mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-22 19:07:48 +08:00
Merge branch 'master' into docs-release-0.16.0
This commit is contained in:
commit
cf4bf8a1c8
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@ -31,12 +31,12 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
3
.golangci.yml
Normal file
3
.golangci.yml
Normal file
@ -0,0 +1,3 @@
|
||||
linters:
|
||||
enable:
|
||||
- stylecheck
|
||||
@ -1,5 +1,6 @@
|
||||
# Kubo Changelogs
|
||||
|
||||
- [v0.16](docs/changelogs/v0.16.md)
|
||||
- [v0.15](docs/changelogs/v0.15.md)
|
||||
- [v0.14](docs/changelogs/v0.14.md)
|
||||
- [v0.13](docs/changelogs/v0.13.md)
|
||||
|
||||
20
README.md
20
README.md
@ -1,6 +1,3 @@
|
||||
# kubo
|
||||
|
||||
> the oldest IPFS implementation, previously known as "go-ipfs"
|
||||
|
||||

|
||||
|
||||
@ -10,15 +7,18 @@
|
||||
|
||||
## What is Kubo?
|
||||
|
||||
Kubo (go-ipfs) the earliest and most widely used implementation of IPFS.
|
||||
Kubo was the first IPFS implementation and is the most widely used one today. Implementing the *Interplanetary Filesystem* - the Web3 standard and contender to replace https. Thus powered by IPLD's data models and the libp2p for network communication. Kubo is written in Go.
|
||||
|
||||
It includes:
|
||||
- an IPFS daemon server
|
||||
- extensive [command line tooling](https://docs.ipfs.tech/reference/kubo/cli/)
|
||||
- an [HTTP Gateway](https://docs.ipfs.tech/reference/http/gateway/) (`/ipfs/`, `/ipns/`) for serving content to HTTP browsers
|
||||
- an [HTTP RPC API](https://docs.ipfs.tech/reference/kubo/rpc/) (`/api/v0`) for controlling the daemon node
|
||||
Featureset
|
||||
- Runs an IPFS-Node as a network service
|
||||
- [Command Line Interface](https://docs.ipfs.tech/reference/kubo/cli/) to IPFS-Nodes
|
||||
- Local [Web2-to-Web3 HTTP Gateway functionality](https://github.com/ipfs/specs/tree/main/http-gateways#readme)
|
||||
- HTTP RPC API (`/api/v0`) to access and control the daemon
|
||||
- IPFS's internal Webgui can be used to manage the Kubo nodes
|
||||
|
||||
Note: [other implementations exist](https://docs.ipfs.tech/basics/ipfs-implementations/).
|
||||
### Other implementations
|
||||
|
||||
See [List](https://docs.ipfs.tech/basics/ipfs-implementations/)
|
||||
|
||||
## What is IPFS?
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ func addMigrations(ctx context.Context, node *core.IpfsNode, fetcher migrations.
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("Cannot get migrations from unknown fetcher type")
|
||||
return errors.New("cannot get migrations from unknown fetcher type")
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,9 +118,9 @@ func addMigrationPaths(ctx context.Context, node *core.IpfsNode, peerInfo peer.A
|
||||
fmt.Printf("connected to migration peer %q\n", peerInfo)
|
||||
|
||||
if pin {
|
||||
pinApi := ipfs.Pin()
|
||||
pinAPI := ipfs.Pin()
|
||||
for _, ipfsPath := range paths {
|
||||
err := pinApi.Add(ctx, ipfsPath)
|
||||
err := pinAPI.Add(ctx, ipfsPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -59,9 +59,10 @@ const (
|
||||
routingOptionDHTKwd = "dht"
|
||||
routingOptionDHTServerKwd = "dhtserver"
|
||||
routingOptionNoneKwd = "none"
|
||||
routingOptionCustomKwd = "custom"
|
||||
routingOptionDefaultKwd = "default"
|
||||
unencryptTransportKwd = "disable-transport-encryption"
|
||||
unrestrictedApiAccessKwd = "unrestricted-api"
|
||||
unrestrictedAPIAccessKwd = "unrestricted-api"
|
||||
writableKwd = "writable"
|
||||
enablePubSubKwd = "enable-pubsub-experiment"
|
||||
enableIPNSPubSubKwd = "enable-namesys-pubsub"
|
||||
@ -173,7 +174,7 @@ Headers.
|
||||
cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"),
|
||||
cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
|
||||
cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
|
||||
cmds.BoolOption(unrestrictedApiAccessKwd, "Allow API access to unlisted hashes"),
|
||||
cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"),
|
||||
cmds.BoolOption(unencryptTransportKwd, "Disable transport encryption (for debugging protocols)"),
|
||||
cmds.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection"),
|
||||
cmds.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").WithDefault(true),
|
||||
@ -401,7 +402,10 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
|
||||
|
||||
routingOption, _ := req.Options[routingOptionKwd].(string)
|
||||
if routingOption == routingOptionDefaultKwd {
|
||||
routingOption = cfg.Routing.Type.WithDefault(routingOptionDHTKwd)
|
||||
routingOption = cfg.Routing.Type
|
||||
if routingOption == "" {
|
||||
routingOption = routingOptionDHTKwd
|
||||
}
|
||||
}
|
||||
switch routingOption {
|
||||
case routingOptionSupernodeKwd:
|
||||
@ -414,6 +418,14 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
|
||||
ncfg.Routing = libp2p.DHTServerOption
|
||||
case routingOptionNoneKwd:
|
||||
ncfg.Routing = libp2p.NilRouterOption
|
||||
case routingOptionCustomKwd:
|
||||
ncfg.Routing = libp2p.ConstructDelegatedRouting(
|
||||
cfg.Routing.Routers,
|
||||
cfg.Routing.Methods,
|
||||
cfg.Identity.PeerID,
|
||||
cfg.Addresses.Swarm,
|
||||
cfg.Identity.PrivKey,
|
||||
)
|
||||
default:
|
||||
return fmt.Errorf("unrecognized routing option: %s", routingOption)
|
||||
}
|
||||
@ -521,6 +533,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
|
||||
"commit": version.CurrentCommit,
|
||||
}).Set(1)
|
||||
|
||||
// TODO(9285): make metrics more configurable
|
||||
// initialize metrics collector
|
||||
prometheus.MustRegister(&corehttp.IpfsNodeCollector{Node: node})
|
||||
|
||||
@ -641,7 +654,7 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
|
||||
// because this would open up the api to scripting vulnerabilities.
|
||||
// only the webui objects are allowed.
|
||||
// if you know what you're doing, go ahead and pass --unrestricted-api.
|
||||
unrestricted, _ := req.Options[unrestrictedApiAccessKwd].(bool)
|
||||
unrestricted, _ := req.Options[unrestrictedAPIAccessKwd].(bool)
|
||||
gatewayOpt := corehttp.GatewayOption(false, corehttp.WebUIPaths...)
|
||||
if unrestricted {
|
||||
gatewayOpt = corehttp.GatewayOption(true, "/ipfs", "/ipns")
|
||||
|
||||
@ -32,8 +32,9 @@ const (
|
||||
profileOptionName = "profile"
|
||||
)
|
||||
|
||||
// nolint
|
||||
var errRepoExists = errors.New(`ipfs configuration file already exists!
|
||||
Reinitializing would overwrite your keys.
|
||||
Reinitializing would overwrite your keys
|
||||
`)
|
||||
|
||||
var initCmd = &cmds.Command{
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
)
|
||||
|
||||
// This is the CLI root, used for executing commands accessible to CLI clients.
|
||||
// Root is the CLI root, used for executing commands accessible to CLI clients.
|
||||
// Some subcommands (like 'ipfs daemon' or 'ipfs init') are only accessible here,
|
||||
// and can't be called through the HTTP API.
|
||||
var Root = &cmds.Command{
|
||||
|
||||
@ -98,7 +98,7 @@ func TestPinMFSRootNodeError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPinMFSService(t *testing.T) {
|
||||
cfg_invalid_interval := &config.Config{
|
||||
cfgInvalidInterval := &config.Config{
|
||||
Pinning: config.Pinning{
|
||||
RemoteServices: map[string]config.RemotePinningService{
|
||||
"disabled": {
|
||||
@ -119,7 +119,7 @@ func TestPinMFSService(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
cfg_valid_unnamed := &config.Config{
|
||||
cfgValidUnnamed := &config.Config{
|
||||
Pinning: config.Pinning{
|
||||
RemoteServices: map[string]config.RemotePinningService{
|
||||
"valid_unnamed": {
|
||||
@ -134,7 +134,7 @@ func TestPinMFSService(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
cfg_valid_named := &config.Config{
|
||||
cfgValidNamed := &config.Config{
|
||||
Pinning: config.Pinning{
|
||||
RemoteServices: map[string]config.RemotePinningService{
|
||||
"valid_named": {
|
||||
@ -149,9 +149,9 @@ func TestPinMFSService(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
testPinMFSServiceWithError(t, cfg_invalid_interval, "remote pinning service \"invalid_interval\" has invalid MFS.RepinInterval")
|
||||
testPinMFSServiceWithError(t, cfg_valid_unnamed, "error while listing remote pins: empty response from remote pinning service")
|
||||
testPinMFSServiceWithError(t, cfg_valid_named, "error while listing remote pins: empty response from remote pinning service")
|
||||
testPinMFSServiceWithError(t, cfgInvalidInterval, "remote pinning service \"invalid_interval\" has invalid MFS.RepinInterval")
|
||||
testPinMFSServiceWithError(t, cfgValidUnnamed, "error while listing remote pins: empty response from remote pinning service")
|
||||
testPinMFSServiceWithError(t, cfgValidNamed, "error while listing remote pins: empty response from remote pinning service")
|
||||
}
|
||||
|
||||
func testPinMFSServiceWithError(t *testing.T, cfg *config.Config, expectedErrorPrefix string) {
|
||||
|
||||
@ -9,7 +9,7 @@ type DNS struct {
|
||||
// https://en.wikipedia.org/wiki/DNS_over_HTTPS
|
||||
//
|
||||
// Example:
|
||||
// - Custom resolver for ENS: `eth.` → `https://eth.link/dns-query`
|
||||
// - Custom resolver for ENS: `eth.` → `https://dns.eth.limo/dns-query`
|
||||
// - Override the default OS resolver: `.` → `https://doh.applied-privacy.net/query`
|
||||
Resolvers map[string]string
|
||||
// MaxCacheTTL is the maximum duration DNS entries are valid in the cache.
|
||||
|
||||
@ -6,7 +6,7 @@ type Experiments struct {
|
||||
ShardingEnabled bool `json:",omitempty"` // deprecated by autosharding: https://github.com/ipfs/kubo/pull/8527
|
||||
GraphsyncEnabled bool
|
||||
Libp2pStreamMounting bool
|
||||
P2pHttpProxy bool
|
||||
P2pHttpProxy bool //nolint
|
||||
StrategicProviding bool
|
||||
AcceleratedDHTClient bool
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package config
|
||||
|
||||
const DefaultInlineDNSLink = false
|
||||
|
||||
type GatewaySpec struct {
|
||||
// Paths is explicit list of path prefixes that should be handled by
|
||||
// this gateway. Example: `["/ipfs", "/ipns", "/api"]`
|
||||
@ -18,6 +20,11 @@ type GatewaySpec struct {
|
||||
// NoDNSLink configures this gateway to _not_ resolve DNSLink for the FQDN
|
||||
// provided in `Host` HTTP header.
|
||||
NoDNSLink bool
|
||||
|
||||
// InlineDNSLink configures this gateway to always inline DNSLink names
|
||||
// (FQDN) into a single DNS label in order to interop with wildcard TLS certs
|
||||
// and Origin per CID isolation provided by rules like https://publicsuffix.org
|
||||
InlineDNSLink Flag
|
||||
}
|
||||
|
||||
// Gateway contains options for the HTTP gateway server.
|
||||
|
||||
@ -48,7 +48,9 @@ func InitWithIdentity(identity Identity) (*Config, error) {
|
||||
},
|
||||
|
||||
Routing: Routing{
|
||||
Type: NewOptionalString("dht"),
|
||||
Type: "dht",
|
||||
Methods: nil,
|
||||
Routers: nil,
|
||||
},
|
||||
|
||||
// setup the node mount points.
|
||||
|
||||
@ -174,7 +174,7 @@ functionality - performance of content discovery and data
|
||||
fetching may be degraded.
|
||||
`,
|
||||
Transform: func(c *Config) error {
|
||||
c.Routing.Type = NewOptionalString("dhtclient")
|
||||
c.Routing.Type = "dhtclient"
|
||||
c.AutoNAT.ServiceMode = AutoNATServiceDisabled
|
||||
c.Reprovider.Interval = "0"
|
||||
|
||||
|
||||
@ -1,28 +1,101 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Routing defines configuration options for libp2p routing
|
||||
type Routing struct {
|
||||
// Type sets default daemon routing mode.
|
||||
//
|
||||
// Can be one of "dht", "dhtclient", "dhtserver", "none", or unset.
|
||||
Type *OptionalString `json:",omitempty"`
|
||||
// Can be one of "dht", "dhtclient", "dhtserver", "none", or "custom".
|
||||
// When "custom" is set, you can specify a list of Routers.
|
||||
Type string
|
||||
|
||||
Routers map[string]Router
|
||||
Routers Routers
|
||||
|
||||
Methods Methods
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
|
||||
// Currenly only supported Type is "reframe".
|
||||
// Currenly supported Types are "reframe", "dht", "parallel", "sequential".
|
||||
// Reframe type allows to add other resolvers using the Reframe spec:
|
||||
// https://github.com/ipfs/specs/tree/main/reframe
|
||||
// In the future we will support "dht" and other Types here.
|
||||
Type string
|
||||
|
||||
Enabled Flag `json:",omitempty"`
|
||||
Type RouterType
|
||||
|
||||
// Parameters are extra configuration that this router might need.
|
||||
// A common one for reframe router is "Endpoint".
|
||||
Parameters map[string]string
|
||||
Parameters interface{}
|
||||
}
|
||||
|
||||
type Routers map[string]RouterParser
|
||||
type Methods map[MethodName]Method
|
||||
|
||||
func (m Methods) Check() error {
|
||||
|
||||
// Check supported methods
|
||||
for _, mn := range MethodNameList {
|
||||
_, ok := m[mn]
|
||||
if !ok {
|
||||
return fmt.Errorf("method name %q is missing from Routing.Methods config param", mn)
|
||||
}
|
||||
}
|
||||
|
||||
// Check unsupported methods
|
||||
for k := range m {
|
||||
seen := false
|
||||
for _, mn := range MethodNameList {
|
||||
if mn == k {
|
||||
seen = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if seen {
|
||||
continue
|
||||
}
|
||||
|
||||
return fmt.Errorf("method name %q is not a supported method on Routing.Methods config param", k)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RouterParser struct {
|
||||
Router
|
||||
}
|
||||
|
||||
func (r *RouterParser) UnmarshalJSON(b []byte) error {
|
||||
out := Router{}
|
||||
out.Parameters = &json.RawMessage{}
|
||||
if err := json.Unmarshal(b, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
raw := out.Parameters.(*json.RawMessage)
|
||||
|
||||
var p interface{}
|
||||
switch out.Type {
|
||||
case RouterTypeReframe:
|
||||
p = &ReframeRouterParams{}
|
||||
case RouterTypeDHT:
|
||||
p = &DHTRouterParams{}
|
||||
case RouterTypeSequential:
|
||||
p = &ComposableRouterParams{}
|
||||
case RouterTypeParallel:
|
||||
p = &ComposableRouterParams{}
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(*raw, &p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Router.Type = out.Type
|
||||
r.Router.Parameters = p
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type is the routing type.
|
||||
@ -30,15 +103,56 @@ type Router struct {
|
||||
type RouterType string
|
||||
|
||||
const (
|
||||
RouterTypeReframe RouterType = "reframe"
|
||||
RouterTypeReframe RouterType = "reframe"
|
||||
RouterTypeDHT RouterType = "dht"
|
||||
RouterTypeSequential RouterType = "sequential"
|
||||
RouterTypeParallel RouterType = "parallel"
|
||||
)
|
||||
|
||||
type RouterParam string
|
||||
type DHTMode string
|
||||
|
||||
const (
|
||||
// RouterParamEndpoint is the URL where the routing implementation will point to get the information.
|
||||
// Usually used for reframe Routers.
|
||||
RouterParamEndpoint RouterParam = "Endpoint"
|
||||
|
||||
RouterParamPriority RouterParam = "Priority"
|
||||
DHTModeServer DHTMode = "server"
|
||||
DHTModeClient DHTMode = "client"
|
||||
DHTModeAuto DHTMode = "auto"
|
||||
)
|
||||
|
||||
type MethodName string
|
||||
|
||||
const (
|
||||
MethodNameProvide MethodName = "provide"
|
||||
MethodNameFindProviders MethodName = "find-providers"
|
||||
MethodNameFindPeers MethodName = "find-peers"
|
||||
MethodNameGetIPNS MethodName = "get-ipns"
|
||||
MethodNamePutIPNS MethodName = "put-ipns"
|
||||
)
|
||||
|
||||
var MethodNameList = []MethodName{MethodNameProvide, MethodNameFindPeers, MethodNameFindProviders, MethodNameGetIPNS, MethodNamePutIPNS}
|
||||
|
||||
type ReframeRouterParams struct {
|
||||
// Endpoint is the URL where the routing implementation will point to get the information.
|
||||
// Usually used for reframe Routers.
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
type DHTRouterParams struct {
|
||||
Mode DHTMode
|
||||
AcceleratedDHTClient bool `json:",omitempty"`
|
||||
PublicIPNetwork bool
|
||||
}
|
||||
|
||||
type ComposableRouterParams struct {
|
||||
Routers []ConfigRouter
|
||||
Timeout *OptionalDuration `json:",omitempty"`
|
||||
}
|
||||
|
||||
type ConfigRouter struct {
|
||||
RouterName string
|
||||
Timeout Duration
|
||||
IgnoreErrors bool
|
||||
ExecuteAfter *OptionalDuration `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Method struct {
|
||||
RouterName string
|
||||
}
|
||||
|
||||
195
config/routing_test.go
Normal file
195
config/routing_test.go
Normal file
@ -0,0 +1,195 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRouterParameters(t *testing.T) {
|
||||
require := require.New(t)
|
||||
sec := time.Second
|
||||
min := time.Minute
|
||||
r := Routing{
|
||||
Type: "custom",
|
||||
Routers: map[string]RouterParser{
|
||||
"router-dht": {Router{
|
||||
Type: RouterTypeDHT,
|
||||
Parameters: DHTRouterParams{
|
||||
Mode: "auto",
|
||||
AcceleratedDHTClient: true,
|
||||
PublicIPNetwork: false,
|
||||
},
|
||||
}},
|
||||
"router-reframe": {Router{
|
||||
Type: RouterTypeReframe,
|
||||
Parameters: ReframeRouterParams{
|
||||
Endpoint: "reframe-endpoint",
|
||||
},
|
||||
}},
|
||||
"router-parallel": {Router{
|
||||
Type: RouterTypeParallel,
|
||||
Parameters: ComposableRouterParams{
|
||||
Routers: []ConfigRouter{
|
||||
{
|
||||
RouterName: "router-dht",
|
||||
Timeout: Duration{10 * time.Second},
|
||||
IgnoreErrors: true,
|
||||
},
|
||||
{
|
||||
RouterName: "router-reframe",
|
||||
Timeout: Duration{10 * time.Second},
|
||||
IgnoreErrors: false,
|
||||
ExecuteAfter: &OptionalDuration{&sec},
|
||||
},
|
||||
},
|
||||
Timeout: &OptionalDuration{&min},
|
||||
}},
|
||||
},
|
||||
"router-sequential": {Router{
|
||||
Type: RouterTypeSequential,
|
||||
Parameters: ComposableRouterParams{
|
||||
Routers: []ConfigRouter{
|
||||
{
|
||||
RouterName: "router-dht",
|
||||
Timeout: Duration{10 * time.Second},
|
||||
IgnoreErrors: true,
|
||||
},
|
||||
{
|
||||
RouterName: "router-reframe",
|
||||
Timeout: Duration{10 * time.Second},
|
||||
IgnoreErrors: false,
|
||||
},
|
||||
},
|
||||
Timeout: &OptionalDuration{&min},
|
||||
}},
|
||||
},
|
||||
},
|
||||
Methods: Methods{
|
||||
MethodNameFindPeers: {
|
||||
RouterName: "router-reframe",
|
||||
},
|
||||
MethodNameFindProviders: {
|
||||
RouterName: "router-dht",
|
||||
},
|
||||
MethodNameGetIPNS: {
|
||||
RouterName: "router-sequential",
|
||||
},
|
||||
MethodNameProvide: {
|
||||
RouterName: "router-parallel",
|
||||
},
|
||||
MethodNamePutIPNS: {
|
||||
RouterName: "router-parallel",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := json.Marshal(r)
|
||||
require.NoError(err)
|
||||
|
||||
r2 := &Routing{}
|
||||
|
||||
err = json.Unmarshal(out, r2)
|
||||
require.NoError(err)
|
||||
|
||||
require.Equal(5, len(r2.Methods))
|
||||
|
||||
dhtp := r2.Routers["router-dht"].Parameters
|
||||
require.IsType(&DHTRouterParams{}, dhtp)
|
||||
|
||||
rp := r2.Routers["router-reframe"].Parameters
|
||||
require.IsType(&ReframeRouterParams{}, rp)
|
||||
|
||||
sp := r2.Routers["router-sequential"].Parameters
|
||||
require.IsType(&ComposableRouterParams{}, sp)
|
||||
|
||||
pp := r2.Routers["router-parallel"].Parameters
|
||||
require.IsType(&ComposableRouterParams{}, pp)
|
||||
}
|
||||
|
||||
func TestRouterMissingParameters(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
r := Routing{
|
||||
Type: "custom",
|
||||
Routers: map[string]RouterParser{
|
||||
"router-wrong-reframe": {Router{
|
||||
Type: RouterTypeReframe,
|
||||
Parameters: DHTRouterParams{
|
||||
Mode: "auto",
|
||||
AcceleratedDHTClient: true,
|
||||
PublicIPNetwork: false,
|
||||
},
|
||||
}},
|
||||
},
|
||||
Methods: Methods{
|
||||
MethodNameFindPeers: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameFindProviders: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameGetIPNS: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameProvide: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNamePutIPNS: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
out, err := json.Marshal(r)
|
||||
require.NoError(err)
|
||||
|
||||
r2 := &Routing{}
|
||||
|
||||
err = json.Unmarshal(out, r2)
|
||||
require.NoError(err)
|
||||
require.Empty(r2.Routers["router-wrong-reframe"].Parameters.(*ReframeRouterParams).Endpoint)
|
||||
}
|
||||
|
||||
func TestMethods(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
methodsOK := Methods{
|
||||
MethodNameFindPeers: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameFindProviders: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameGetIPNS: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameProvide: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNamePutIPNS: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(methodsOK.Check())
|
||||
|
||||
methodsMissing := Methods{
|
||||
MethodNameFindPeers: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameGetIPNS: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNameProvide: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
MethodNamePutIPNS: {
|
||||
RouterName: "router-wrong-reframe",
|
||||
},
|
||||
}
|
||||
|
||||
require.Error(methodsMissing.Check())
|
||||
}
|
||||
@ -104,6 +104,8 @@ type Transports struct {
|
||||
TCP Flag `json:",omitempty"`
|
||||
Websocket Flag `json:",omitempty"`
|
||||
Relay Flag `json:",omitempty"`
|
||||
// except WebTransport which is experimental and optin.
|
||||
WebTransport Flag `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Security specifies the transports used to encrypt insecure network
|
||||
|
||||
@ -262,6 +262,38 @@ func (d OptionalDuration) String() string {
|
||||
var _ json.Unmarshaler = (*OptionalDuration)(nil)
|
||||
var _ json.Marshaler = (*OptionalDuration)(nil)
|
||||
|
||||
type Duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.String())
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
var v interface{}
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
switch value := v.(type) {
|
||||
case float64:
|
||||
d.Duration = time.Duration(value)
|
||||
return nil
|
||||
case string:
|
||||
var err error
|
||||
d.Duration, err = time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unable to parse duration, expected a duration string or a float, but got %T", v)
|
||||
}
|
||||
}
|
||||
|
||||
var _ json.Unmarshaler = (*Duration)(nil)
|
||||
var _ json.Marshaler = (*Duration)(nil)
|
||||
|
||||
// OptionalInteger represents an integer that has a default value
|
||||
//
|
||||
// When encoded in json, Default is encoded as "null"
|
||||
|
||||
@ -13,6 +13,8 @@ import (
|
||||
"github.com/cheggaaa/pb"
|
||||
cmds "github.com/ipfs/go-ipfs-cmds"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
mfs "github.com/ipfs/go-mfs"
|
||||
coreiface "github.com/ipfs/interface-go-ipfs-core"
|
||||
"github.com/ipfs/interface-go-ipfs-core/options"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
@ -45,6 +47,7 @@ const (
|
||||
hashOptionName = "hash"
|
||||
inlineOptionName = "inline"
|
||||
inlineLimitOptionName = "inline-limit"
|
||||
toFilesOptionName = "to-files"
|
||||
)
|
||||
|
||||
const adderOutChanSize = 8
|
||||
@ -79,6 +82,20 @@ You can now refer to the added file in a gateway, like so:
|
||||
|
||||
/ipfs/QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx/example.jpg
|
||||
|
||||
Files imported with 'ipfs add' are protected from GC (implicit '--pin=true'),
|
||||
but it is up to you to remember the returned CID to get the data back later.
|
||||
|
||||
Passing '--to-files' creates a reference in Files API (MFS), making it easier
|
||||
to find it in the future:
|
||||
|
||||
> ipfs files mkdir -p /myfs/dir
|
||||
> ipfs add example.jpg --to-files /myfs/dir/
|
||||
> ipfs files ls /myfs/dir/
|
||||
example.jpg
|
||||
|
||||
See 'ipfs files --help' to learn more about using MFS
|
||||
for keeping track of added files and directories.
|
||||
|
||||
The chunker option, '-s', specifies the chunking strategy that dictates
|
||||
how to break files into blocks. Blocks with same content can
|
||||
be deduplicated. Different chunking strategies will produce different
|
||||
@ -138,7 +155,6 @@ See 'dag export' and 'dag import' for more information.
|
||||
cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
|
||||
cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
|
||||
cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash").WithDefault("size-262144"),
|
||||
cmds.BoolOption(pinOptionName, "Pin this object when adding.").WithDefault(true),
|
||||
cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes."),
|
||||
cmds.BoolOption(noCopyOptionName, "Add the file using filestore. Implies raw-leaves. (experimental)"),
|
||||
cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"),
|
||||
@ -146,6 +162,8 @@ See 'dag export' and 'dag import' for more information.
|
||||
cmds.StringOption(hashOptionName, "Hash function to use. Implies CIDv1 if not sha2-256. (experimental)").WithDefault("sha2-256"),
|
||||
cmds.BoolOption(inlineOptionName, "Inline small blocks into CIDs. (experimental)"),
|
||||
cmds.IntOption(inlineLimitOptionName, "Maximum block size to inline. (experimental)").WithDefault(32),
|
||||
cmds.BoolOption(pinOptionName, "Pin locally to protect added files from garbage collection.").WithDefault(true),
|
||||
cmds.StringOption(toFilesOptionName, "Add reference to Files API (MFS) at the provided path."),
|
||||
},
|
||||
PreRun: func(req *cmds.Request, env cmds.Environment) error {
|
||||
quiet, _ := req.Options[quietOptionName].(bool)
|
||||
@ -186,10 +204,14 @@ See 'dag export' and 'dag import' for more information.
|
||||
hashFunStr, _ := req.Options[hashOptionName].(string)
|
||||
inline, _ := req.Options[inlineOptionName].(bool)
|
||||
inlineLimit, _ := req.Options[inlineLimitOptionName].(int)
|
||||
toFilesStr, toFilesSet := req.Options[toFilesOptionName].(string)
|
||||
|
||||
hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)]
|
||||
if !ok {
|
||||
return fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr))
|
||||
return fmt.Errorf("unrecognized hash function: %q", strings.ToLower(hashFunStr))
|
||||
}
|
||||
if _, err := mh.GetHasher(hashFunCode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enc, err := cmdenv.GetCidEncoder(req)
|
||||
@ -235,7 +257,12 @@ See 'dag export' and 'dag import' for more information.
|
||||
|
||||
opts = append(opts, nil) // events option placeholder
|
||||
|
||||
ipfsNode, err := cmdenv.GetNode(env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var added int
|
||||
var fileAddedToMFS bool
|
||||
addit := toadd.Entries()
|
||||
for addit.Next() {
|
||||
_, dir := addit.Node().(files.Directory)
|
||||
@ -246,7 +273,65 @@ See 'dag export' and 'dag import' for more information.
|
||||
go func() {
|
||||
var err error
|
||||
defer close(events)
|
||||
_, err = api.Unixfs().Add(req.Context, addit.Node(), opts...)
|
||||
pathAdded, err := api.Unixfs().Add(req.Context, addit.Node(), opts...)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
// creating MFS pointers when optional --to-files is set
|
||||
if toFilesSet {
|
||||
if toFilesStr == "" {
|
||||
toFilesStr = "/"
|
||||
}
|
||||
toFilesDst, err := checkPath(toFilesStr)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("%s: %w", toFilesOptionName, err)
|
||||
return
|
||||
}
|
||||
dstAsDir := toFilesDst[len(toFilesDst)-1] == '/'
|
||||
|
||||
if dstAsDir {
|
||||
mfsNode, err := mfs.Lookup(ipfsNode.FilesRoot, toFilesDst)
|
||||
// confirm dst exists
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("%s: MFS destination directory %q does not exist: %w", toFilesOptionName, toFilesDst, err)
|
||||
return
|
||||
}
|
||||
// confirm dst is a dir
|
||||
if mfsNode.Type() != mfs.TDir {
|
||||
errCh <- fmt.Errorf("%s: MFS destination %q is not a directory", toFilesOptionName, toFilesDst)
|
||||
return
|
||||
}
|
||||
// if MFS destination is a dir, append filename to the dir path
|
||||
toFilesDst += path.Base(addit.Name())
|
||||
}
|
||||
|
||||
// error if we try to overwrite a preexisting file destination
|
||||
if fileAddedToMFS && !dstAsDir {
|
||||
errCh <- fmt.Errorf("%s: MFS destination is a file: only one entry can be copied to %q", toFilesOptionName, toFilesDst)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = mfs.Lookup(ipfsNode.FilesRoot, path.Dir(toFilesDst))
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("%s: MFS destination parent %q %q does not exist: %w", toFilesOptionName, toFilesDst, path.Dir(toFilesDst), err)
|
||||
return
|
||||
}
|
||||
|
||||
var nodeAdded ipld.Node
|
||||
nodeAdded, err = api.Dag().Get(req.Context, pathAdded.Cid())
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
err = mfs.PutNode(ipfsNode.FilesRoot, toFilesDst, nodeAdded)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("%s: cannot put node in path %q: %w", toFilesOptionName, toFilesDst, err)
|
||||
return
|
||||
}
|
||||
fileAddedToMFS = true
|
||||
}
|
||||
errCh <- err
|
||||
}()
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
verifcid "github.com/ipfs/go-verifcid"
|
||||
ipldmulticodec "github.com/ipld/go-ipld-prime/multicodec"
|
||||
mbase "github.com/multiformats/go-multibase"
|
||||
"github.com/multiformats/go-multicodec"
|
||||
mc "github.com/multiformats/go-multicodec"
|
||||
mhash "github.com/multiformats/go-multihash"
|
||||
)
|
||||
@ -71,7 +70,7 @@ The optional format string is a printf style format string:
|
||||
opts.fmtStr = fmtStr
|
||||
|
||||
if codecStr != "" {
|
||||
var codec multicodec.Code
|
||||
var codec mc.Code
|
||||
err := codec.Set(codecStr)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -27,7 +27,7 @@ func GetNode(env interface{}) (*core.IpfsNode, error) {
|
||||
}
|
||||
|
||||
// GetApi extracts CoreAPI instance from the environment.
|
||||
func GetApi(env cmds.Environment, req *cmds.Request) (coreiface.CoreAPI, error) {
|
||||
func GetApi(env cmds.Environment, req *cmds.Request) (coreiface.CoreAPI, error) { //nolint
|
||||
ctx, ok := env.(*commands.Context)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected env to be of type %T, got %T", ctx, env)
|
||||
|
||||
@ -223,7 +223,7 @@ Specification of CAR formats: https://ipld.io/specs/transport/car/
|
||||
// event should have only one of `Root` or `Stats` set, not both
|
||||
if event.Root == nil {
|
||||
if event.Stats == nil {
|
||||
return fmt.Errorf("Unexpected message from DAG import")
|
||||
return fmt.Errorf("unexpected message from DAG import")
|
||||
}
|
||||
stats, _ := req.Options[statsOptionName].(bool)
|
||||
if stats {
|
||||
@ -233,7 +233,7 @@ Specification of CAR formats: https://ipld.io/specs/transport/car/
|
||||
}
|
||||
|
||||
if event.Stats != nil {
|
||||
return fmt.Errorf("Unexpected message from DAG import")
|
||||
return fmt.Errorf("unexpected message from DAG import")
|
||||
}
|
||||
|
||||
enc, err := cmdenv.GetLowLevelCidEncoder(req)
|
||||
|
||||
@ -85,7 +85,7 @@ func finishCLIExport(res cmds.Response, re cmds.ResponseEmitter) error {
|
||||
if !specified {
|
||||
// default based on TTY availability
|
||||
errStat, _ := os.Stderr.Stat()
|
||||
if 0 != (errStat.Mode() & os.ModeCharDevice) {
|
||||
if (errStat.Mode() & os.ModeCharDevice) != 0 {
|
||||
showProgress = true
|
||||
}
|
||||
} else if val.(bool) {
|
||||
|
||||
@ -581,7 +581,7 @@ const (
|
||||
|
||||
var filesReadCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "Read a file in a given MFS.",
|
||||
Tagline: "Read a file from MFS.",
|
||||
ShortDescription: `
|
||||
Read a specified number of bytes from a file at a given offset. By default,
|
||||
it will read the entire file similar to the Unix cat.
|
||||
@ -724,11 +724,16 @@ const (
|
||||
|
||||
var filesWriteCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "Write to a mutable file in a given filesystem.",
|
||||
Tagline: "Append to (modify) a file in MFS.",
|
||||
ShortDescription: `
|
||||
Write data to a file in a given filesystem. This command allows you to specify
|
||||
a beginning offset to write to. The entire length of the input will be
|
||||
written.
|
||||
A low-level MFS command that allows you to append data to a file. If you want
|
||||
to add a file without modifying an existing one, use 'ipfs add --to-files'
|
||||
instead.
|
||||
`,
|
||||
LongDescription: `
|
||||
A low-level MFS command that allows you to append data at the end of a file, or
|
||||
specify a beginning offset within a file to write to. The entire length of the
|
||||
input will be written.
|
||||
|
||||
If the '--create' option is specified, the file will be created if it does not
|
||||
exist. Nonexistent intermediate directories will not be created unless the
|
||||
@ -755,6 +760,22 @@ WARNING:
|
||||
Usage of the '--flush=false' option does not guarantee data durability until
|
||||
the tree has been flushed. This can be accomplished by running 'ipfs files
|
||||
stat' on the file or any of its ancestors.
|
||||
|
||||
WARNING:
|
||||
|
||||
The CID produced by 'files write' will be different from 'ipfs add' because
|
||||
'ipfs file write' creates a trickle-dag optimized for append-only operations
|
||||
See '--trickle' in 'ipfs add --help' for more information.
|
||||
|
||||
If you want to add a file without modifying an existing one,
|
||||
use 'ipfs add' with '--to-files':
|
||||
|
||||
> ipfs files mkdir -p /myfs/dir
|
||||
> ipfs add example.jpg --to-files /myfs/dir/
|
||||
> ipfs files ls /myfs/dir/
|
||||
example.jpg
|
||||
|
||||
See '--to-files' in 'ipfs add --help' for more information.
|
||||
`,
|
||||
},
|
||||
Arguments: []cmds.Argument{
|
||||
@ -1019,7 +1040,7 @@ func updatePath(rt *mfs.Root, pth string, builder cid.Builder) error {
|
||||
|
||||
var filesRmCmd = &cmds.Command{
|
||||
Helptext: cmds.HelpText{
|
||||
Tagline: "Remove a file.",
|
||||
Tagline: "Remove a file from MFS.",
|
||||
ShortDescription: `
|
||||
Remove files or directories.
|
||||
|
||||
|
||||
@ -23,9 +23,9 @@ import (
|
||||
identify "github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
||||
)
|
||||
|
||||
const offlineIdErrorMessage = "'ipfs id' cannot query information on remote peers without a running daemon; if you only want to convert --peerid-base, pass --offline option."
|
||||
const offlineIDErrorMessage = "'ipfs id' cannot query information on remote peers without a running daemon; if you only want to convert --peerid-base, pass --offline option"
|
||||
|
||||
type IdOutput struct {
|
||||
type IdOutput struct { //nolint
|
||||
ID string
|
||||
PublicKey string
|
||||
Addresses []string
|
||||
@ -52,6 +52,7 @@ If no peer is specified, prints out information for local peers.
|
||||
<pver>: Protocol version.
|
||||
<pubkey>: Public key.
|
||||
<addrs>: Addresses (newline delimited).
|
||||
<protocols>: Libp2p Protocol registrations (newline delimited).
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
@ -97,7 +98,7 @@ EXAMPLE:
|
||||
|
||||
offline, _ := req.Options[OfflineOption].(bool)
|
||||
if !offline && !n.IsOnline {
|
||||
return errors.New(offlineIdErrorMessage)
|
||||
return errors.New(offlineIDErrorMessage)
|
||||
}
|
||||
|
||||
if !offline {
|
||||
@ -106,7 +107,7 @@ EXAMPLE:
|
||||
switch err {
|
||||
case nil:
|
||||
case kb.ErrLookupFailure:
|
||||
return errors.New(offlineIdErrorMessage)
|
||||
return errors.New(offlineIDErrorMessage)
|
||||
default:
|
||||
return err
|
||||
}
|
||||
@ -217,7 +218,7 @@ func printSelf(keyEnc ke.KeyEncoder, node *core.IpfsNode) (interface{}, error) {
|
||||
info.Protocols = node.PeerHost.Mux().Protocols()
|
||||
sort.Strings(info.Protocols)
|
||||
}
|
||||
info.ProtocolVersion = identify.LibP2PVersion
|
||||
info.ProtocolVersion = identify.DefaultProtocolVersion
|
||||
info.AgentVersion = version.GetUserAgentVersion()
|
||||
return info, nil
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ publish'.
|
||||
|
||||
type KeyOutput struct {
|
||||
Name string
|
||||
Id string
|
||||
Id string //nolint
|
||||
}
|
||||
|
||||
type KeyOutputList struct {
|
||||
@ -67,7 +67,7 @@ type KeyOutputList struct {
|
||||
type KeyRenameOutput struct {
|
||||
Was string
|
||||
Now string
|
||||
Id string
|
||||
Id string //nolint
|
||||
Overwrite bool
|
||||
}
|
||||
|
||||
|
||||
@ -105,11 +105,11 @@ This command expects multibase inside of a file or via stdin:
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to access file: %w", err)
|
||||
}
|
||||
encoded_data, err := io.ReadAll(file)
|
||||
encodedData, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read file contents: %w", err)
|
||||
}
|
||||
_, data, err := mbase.Decode(string(encoded_data))
|
||||
_, data, err := mbase.Decode(string(encodedData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode multibase: %w", err)
|
||||
}
|
||||
@ -156,11 +156,11 @@ but one can customize used base with -b:
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to access file: %w", err)
|
||||
}
|
||||
encoded_data, err := io.ReadAll(file)
|
||||
encodedData, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read file contents: %w", err)
|
||||
}
|
||||
_, data, err := mbase.Decode(string(encoded_data))
|
||||
_, data, err := mbase.Decode(string(encodedData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode multibase: %w", err)
|
||||
}
|
||||
|
||||
@ -214,27 +214,27 @@ NOTE: a comma-separated notation is supported in CLI for convenience:
|
||||
|
||||
// Block unless --background=true is passed
|
||||
if !req.Options[pinBackgroundOptionName].(bool) {
|
||||
requestId := ps.GetRequestId()
|
||||
requestID := ps.GetRequestId()
|
||||
for {
|
||||
ps, err = c.GetStatusByID(ctx, requestId)
|
||||
ps, err = c.GetStatusByID(ctx, requestID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check pin status for requestid=%q due to error: %v", requestId, err)
|
||||
return fmt.Errorf("failed to check pin status for requestid=%q due to error: %v", requestID, err)
|
||||
}
|
||||
if ps.GetRequestId() != requestId {
|
||||
return fmt.Errorf("failed to check pin status for requestid=%q, remote service sent unexpected requestid=%q", requestId, ps.GetRequestId())
|
||||
if ps.GetRequestId() != requestID {
|
||||
return fmt.Errorf("failed to check pin status for requestid=%q, remote service sent unexpected requestid=%q", requestID, ps.GetRequestId())
|
||||
}
|
||||
s := ps.GetStatus()
|
||||
if s == pinclient.StatusPinned {
|
||||
break
|
||||
}
|
||||
if s == pinclient.StatusFailed {
|
||||
return fmt.Errorf("remote service failed to pin requestid=%q", requestId)
|
||||
return fmt.Errorf("remote service failed to pin requestid=%q", requestID)
|
||||
}
|
||||
tmr := time.NewTimer(time.Second / 2)
|
||||
select {
|
||||
case <-tmr.C:
|
||||
case <-ctx.Done():
|
||||
return fmt.Errorf("waiting for pin interrupted, requestid=%q remains on remote service", requestId)
|
||||
return fmt.Errorf("waiting for pin interrupted, requestid=%q remains on remote service", requestID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -665,8 +665,8 @@ TIP: pass '--enc=json' for more useful JSON output.
|
||||
|
||||
type ServiceDetails struct {
|
||||
Service string
|
||||
ApiEndpoint string
|
||||
Stat *Stat `json:",omitempty"` // present only when --stat not passed
|
||||
ApiEndpoint string //nolint
|
||||
Stat *Stat `json:",omitempty"` // present only when --stat not passed
|
||||
}
|
||||
|
||||
type Stat struct {
|
||||
|
||||
@ -25,7 +25,7 @@ const (
|
||||
DebugOption = "debug"
|
||||
LocalOption = "local" // DEPRECATED: use OfflineOption
|
||||
OfflineOption = "offline"
|
||||
ApiOption = "api"
|
||||
ApiOption = "api" //nolint
|
||||
)
|
||||
|
||||
var Root = &cmds.Command{
|
||||
@ -118,7 +118,6 @@ The CLI will exit with one of the following values:
|
||||
},
|
||||
}
|
||||
|
||||
// commandsDaemonCmd is the "ipfs commands" command for daemon
|
||||
var CommandsDaemonCmd = CommandsCmd(Root)
|
||||
|
||||
var rootSubcommands = map[string]*cmds.Command{
|
||||
|
||||
@ -132,8 +132,8 @@ Example:
|
||||
return err
|
||||
}
|
||||
} else if tfound {
|
||||
protoId := protocol.ID(tstr)
|
||||
stats := nd.Reporter.GetBandwidthForProtocol(protoId)
|
||||
protoID := protocol.ID(tstr)
|
||||
stats := nd.Reporter.GetBandwidthForProtocol(protoID)
|
||||
if err := res.Emit(&stats); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ The output of this command is JSON.
|
||||
}
|
||||
|
||||
if node.ResourceManager == nil {
|
||||
return libp2p.NoResourceMgrError
|
||||
return libp2p.ErrNoResourceMgr
|
||||
}
|
||||
|
||||
if len(req.Arguments) != 1 {
|
||||
@ -394,7 +394,7 @@ Changes made via command line are persisted in the Swarm.ResourceMgr.Limits fiel
|
||||
}
|
||||
|
||||
if node.ResourceManager == nil {
|
||||
return libp2p.NoResourceMgrError
|
||||
return libp2p.ErrNoResourceMgr
|
||||
}
|
||||
|
||||
scope := req.Arguments[0]
|
||||
|
||||
24
core/core.go
24
core/core.go
@ -87,18 +87,18 @@ type IpfsNode struct {
|
||||
RecordValidator record.Validator
|
||||
|
||||
// Online
|
||||
PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
|
||||
Peering *peering.PeeringService `optional:"true"`
|
||||
Filters *ma.Filters `optional:"true"`
|
||||
Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
|
||||
Routing irouting.TieredRouter `optional:"true"` // the routing system. recommend ipfs-dht
|
||||
DNSResolver *madns.Resolver // the DNS resolver
|
||||
Exchange exchange.Interface // the block exchange + strategy (bitswap)
|
||||
Namesys namesys.NameSystem // the name system, resolves paths to hashes
|
||||
Provider provider.System // the value provider system
|
||||
IpnsRepub *ipnsrp.Republisher `optional:"true"`
|
||||
GraphExchange graphsync.GraphExchange `optional:"true"`
|
||||
ResourceManager network.ResourceManager `optional:"true"`
|
||||
PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
|
||||
Peering *peering.PeeringService `optional:"true"`
|
||||
Filters *ma.Filters `optional:"true"`
|
||||
Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
|
||||
Routing irouting.ProvideManyRouter `optional:"true"` // the routing system. recommend ipfs-dht
|
||||
DNSResolver *madns.Resolver // the DNS resolver
|
||||
Exchange exchange.Interface // the block exchange + strategy (bitswap)
|
||||
Namesys namesys.NameSystem // the name system, resolves paths to hashes
|
||||
Provider provider.System // the value provider system
|
||||
IpnsRepub *ipnsrp.Republisher `optional:"true"`
|
||||
GraphExchange graphsync.GraphExchange `optional:"true"`
|
||||
ResourceManager network.ResourceManager `optional:"true"`
|
||||
|
||||
PubSub *pubsub.PubSub `optional:"true"`
|
||||
PSRouter *psrouter.PubsubValueStore `optional:"true"`
|
||||
|
||||
@ -85,18 +85,18 @@ var errNotSupported = errors.New("method not supported")
|
||||
func TestDelegatedRoutingSingle(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
pId1, priv1, err := GeneratePeerID()
|
||||
pID1, priv1, err := GeneratePeerID()
|
||||
require.NoError(err)
|
||||
|
||||
pId2, _, err := GeneratePeerID()
|
||||
pID2, _, err := GeneratePeerID()
|
||||
require.NoError(err)
|
||||
|
||||
theID := path.Join("/ipns", string(pId1))
|
||||
theErrorID := path.Join("/ipns", string(pId2))
|
||||
theID := path.Join("/ipns", string(pID1))
|
||||
theErrorID := path.Join("/ipns", string(pID2))
|
||||
|
||||
d := &delegatedRoutingService{
|
||||
goodPeerID: pId1,
|
||||
badPeerID: pId2,
|
||||
goodPeerID: pID1,
|
||||
badPeerID: pID2,
|
||||
pk1: priv1,
|
||||
}
|
||||
|
||||
@ -117,25 +117,23 @@ func TestDelegatedRoutingSingle(t *testing.T) {
|
||||
err = n.Routing.PutValue(ctx, theID, v)
|
||||
require.NoError(err)
|
||||
|
||||
err = n.Routing.PutValue(ctx, theErrorID, v)
|
||||
require.Error(err)
|
||||
}
|
||||
|
||||
func TestDelegatedRoutingMulti(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
pId1, priv1, err := GeneratePeerID()
|
||||
pID1, priv1, err := GeneratePeerID()
|
||||
require.NoError(err)
|
||||
|
||||
pId2, priv2, err := GeneratePeerID()
|
||||
pID2, priv2, err := GeneratePeerID()
|
||||
require.NoError(err)
|
||||
|
||||
theID1 := path.Join("/ipns", string(pId1))
|
||||
theID2 := path.Join("/ipns", string(pId2))
|
||||
theID1 := path.Join("/ipns", string(pID1))
|
||||
theID2 := path.Join("/ipns", string(pID2))
|
||||
|
||||
d1 := &delegatedRoutingService{
|
||||
goodPeerID: pId1,
|
||||
badPeerID: pId2,
|
||||
goodPeerID: pID1,
|
||||
badPeerID: pID2,
|
||||
pk1: priv1,
|
||||
serviceID: 1,
|
||||
}
|
||||
@ -143,8 +141,8 @@ func TestDelegatedRoutingMulti(t *testing.T) {
|
||||
url1 := StartRoutingServer(t, d1)
|
||||
|
||||
d2 := &delegatedRoutingService{
|
||||
goodPeerID: pId2,
|
||||
badPeerID: pId1,
|
||||
goodPeerID: pID2,
|
||||
badPeerID: pID1,
|
||||
pk1: priv2,
|
||||
serviceID: 2,
|
||||
}
|
||||
@ -164,12 +162,6 @@ func TestDelegatedRoutingMulti(t *testing.T) {
|
||||
require.NoError(err)
|
||||
require.NotNil(v)
|
||||
require.Contains(string(v), "RECORD FROM SERVICE 2")
|
||||
|
||||
err = n.Routing.PutValue(ctx, theID1, v)
|
||||
require.Error(err)
|
||||
|
||||
err = n.Routing.PutValue(ctx, theID2, v)
|
||||
require.Error(err)
|
||||
}
|
||||
|
||||
func StartRoutingServer(t *testing.T, d drs.DelegatedRoutingService) string {
|
||||
@ -187,16 +179,41 @@ func StartRoutingServer(t *testing.T, d drs.DelegatedRoutingService) string {
|
||||
func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode {
|
||||
t.Helper()
|
||||
|
||||
routers := make(map[string]config.Router)
|
||||
routers := make(config.Routers)
|
||||
var routerNames []string
|
||||
for i, ru := range reframeURLs {
|
||||
routers[fmt.Sprintf("reframe-%d", i)] = config.Router{
|
||||
Type: string(config.RouterTypeReframe),
|
||||
Parameters: map[string]string{
|
||||
string(config.RouterParamEndpoint): ru,
|
||||
},
|
||||
}
|
||||
rn := fmt.Sprintf("reframe-%d", i)
|
||||
routerNames = append(routerNames, rn)
|
||||
routers[rn] =
|
||||
config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: ru,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var crs []config.ConfigRouter
|
||||
for _, rn := range routerNames {
|
||||
crs = append(crs, config.ConfigRouter{
|
||||
RouterName: rn,
|
||||
IgnoreErrors: true,
|
||||
Timeout: config.Duration{Duration: time.Minute},
|
||||
})
|
||||
}
|
||||
|
||||
const parallelRouterName = "parallel-router"
|
||||
|
||||
routers[parallelRouterName] = config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeParallel,
|
||||
Parameters: &config.ComposableRouterParams{
|
||||
Routers: crs,
|
||||
},
|
||||
},
|
||||
}
|
||||
cfg := config.Config{
|
||||
Identity: testIdentity,
|
||||
Addresses: config.Addresses{
|
||||
@ -204,8 +221,25 @@ func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode {
|
||||
API: []string{"/ip4/127.0.0.1/tcp/0"},
|
||||
},
|
||||
Routing: config.Routing{
|
||||
Type: config.NewOptionalString("none"),
|
||||
Type: "custom",
|
||||
Routers: routers,
|
||||
Methods: config.Methods{
|
||||
config.MethodNameFindPeers: config.Method{
|
||||
RouterName: parallelRouterName,
|
||||
},
|
||||
config.MethodNameFindProviders: config.Method{
|
||||
RouterName: parallelRouterName,
|
||||
},
|
||||
config.MethodNameGetIPNS: config.Method{
|
||||
RouterName: parallelRouterName,
|
||||
},
|
||||
config.MethodNameProvide: config.Method{
|
||||
RouterName: parallelRouterName,
|
||||
},
|
||||
config.MethodNamePutIPNS: config.Method{
|
||||
RouterName: parallelRouterName,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -214,7 +248,19 @@ func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode {
|
||||
D: syncds.MutexWrap(datastore.NewMapDatastore()),
|
||||
}
|
||||
|
||||
n, err := NewNode(context.Background(), &BuildCfg{Repo: r, Online: true, Routing: libp2p.NilRouterOption})
|
||||
n, err := NewNode(context.Background(),
|
||||
&BuildCfg{
|
||||
Repo: r,
|
||||
Online: true,
|
||||
Routing: libp2p.ConstructDelegatedRouting(
|
||||
cfg.Routing.Routers,
|
||||
cfg.Routing.Methods,
|
||||
cfg.Identity.PeerID,
|
||||
cfg.Addresses.Swarm,
|
||||
cfg.Identity.PrivKey,
|
||||
),
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
return n
|
||||
@ -240,6 +286,10 @@ func (drs *delegatedRoutingService) FindProviders(ctx context.Context, key cid.C
|
||||
return nil, errNotSupported
|
||||
}
|
||||
|
||||
func (drs *delegatedRoutingService) Provide(ctx context.Context, req *client.ProvideRequest) (<-chan client.ProvideAsyncResult, error) {
|
||||
return nil, errNotSupported
|
||||
}
|
||||
|
||||
func (drs *delegatedRoutingService) GetIPNS(ctx context.Context, id []byte) (<-chan client.GetIPNSAsyncResult, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
ch := make(chan client.GetIPNSAsyncResult)
|
||||
|
||||
@ -158,7 +158,7 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e
|
||||
|
||||
n := api.nd
|
||||
|
||||
subApi := &CoreAPI{
|
||||
subAPI := &CoreAPI{
|
||||
nctx: n.Context(),
|
||||
|
||||
identity: n.Identity,
|
||||
@ -190,14 +190,14 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e
|
||||
parentOpts: settings,
|
||||
}
|
||||
|
||||
subApi.checkOnline = func(allowOffline bool) error {
|
||||
subAPI.checkOnline = func(allowOffline bool) error {
|
||||
if !n.IsOnline && !allowOffline {
|
||||
return coreiface.ErrOffline
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
subApi.checkPublishAllowed = func() error {
|
||||
subAPI.checkPublishAllowed = func() error {
|
||||
if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
|
||||
return errors.New("cannot manually publish while IPNS is mounted")
|
||||
}
|
||||
@ -218,39 +218,39 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e
|
||||
return nil, fmt.Errorf("cannot specify negative resolve cache size")
|
||||
}
|
||||
|
||||
subApi.routing = offlineroute.NewOfflineRouter(subApi.repo.Datastore(), subApi.recordValidator)
|
||||
subAPI.routing = offlineroute.NewOfflineRouter(subAPI.repo.Datastore(), subAPI.recordValidator)
|
||||
|
||||
subApi.namesys, err = namesys.NewNameSystem(subApi.routing,
|
||||
namesys.WithDatastore(subApi.repo.Datastore()),
|
||||
namesys.WithDNSResolver(subApi.dnsResolver),
|
||||
subAPI.namesys, err = namesys.NewNameSystem(subAPI.routing,
|
||||
namesys.WithDatastore(subAPI.repo.Datastore()),
|
||||
namesys.WithDNSResolver(subAPI.dnsResolver),
|
||||
namesys.WithCache(cs))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error constructing namesys: %w", err)
|
||||
}
|
||||
|
||||
subApi.provider = provider.NewOfflineProvider()
|
||||
subAPI.provider = provider.NewOfflineProvider()
|
||||
|
||||
subApi.peerstore = nil
|
||||
subApi.peerHost = nil
|
||||
subApi.recordValidator = nil
|
||||
subAPI.peerstore = nil
|
||||
subAPI.peerHost = nil
|
||||
subAPI.recordValidator = nil
|
||||
}
|
||||
|
||||
if settings.Offline || !settings.FetchBlocks {
|
||||
subApi.exchange = offlinexch.Exchange(subApi.blockstore)
|
||||
subApi.blocks = bserv.New(subApi.blockstore, subApi.exchange)
|
||||
subApi.dag = dag.NewDAGService(subApi.blocks)
|
||||
subAPI.exchange = offlinexch.Exchange(subAPI.blockstore)
|
||||
subAPI.blocks = bserv.New(subAPI.blockstore, subAPI.exchange)
|
||||
subAPI.dag = dag.NewDAGService(subAPI.blocks)
|
||||
}
|
||||
|
||||
return subApi, nil
|
||||
return subAPI, nil
|
||||
}
|
||||
|
||||
// getSession returns new api backed by the same node with a read-only session DAG
|
||||
func (api *CoreAPI) getSession(ctx context.Context) *CoreAPI {
|
||||
sesApi := *api
|
||||
sesAPI := *api
|
||||
|
||||
// TODO: We could also apply this to api.blocks, and compose into writable api,
|
||||
// but this requires some changes in blockservice/merkledag
|
||||
sesApi.dag = dag.NewReadOnlyDagService(dag.NewSession(ctx, api.dag))
|
||||
sesAPI.dag = dag.NewReadOnlyDagService(dag.NewSession(ctx, api.dag))
|
||||
|
||||
return &sesApi
|
||||
return &sesAPI
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ func (e *ipnsEntry) Value() path.Path {
|
||||
return e.value
|
||||
}
|
||||
|
||||
type requestContextKey string
|
||||
|
||||
// Publish announces new IPNS name and returns the new IPNS entry.
|
||||
func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) {
|
||||
ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Publish", trace.WithAttributes(attribute.String("path", p.String())))
|
||||
@ -76,7 +78,7 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam
|
||||
|
||||
if options.TTL != nil {
|
||||
// nolint: staticcheck // non-backward compatible change
|
||||
ctx = context.WithValue(ctx, "ipns-publish-ttl", *options.TTL)
|
||||
ctx = context.WithValue(ctx, requestContextKey("ipns-publish-ttl"), *options.TTL)
|
||||
}
|
||||
|
||||
eol := time.Now().Add(options.ValidTime)
|
||||
|
||||
@ -97,7 +97,7 @@ func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopt
|
||||
|
||||
func (api *PubSubAPI) checkNode() (routing.Routing, error) {
|
||||
if api.pubSub == nil {
|
||||
return nil, errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
|
||||
return nil, errors.New("experimental pubsub feature not enabled, run daemon with --enable-pubsub-experiment to use")
|
||||
}
|
||||
|
||||
err := api.checkOnline(false)
|
||||
|
||||
@ -19,7 +19,6 @@ import (
|
||||
bstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
ipld "github.com/ipfs/go-ipld-format"
|
||||
dag "github.com/ipfs/go-merkledag"
|
||||
merkledag "github.com/ipfs/go-merkledag"
|
||||
dagtest "github.com/ipfs/go-merkledag/test"
|
||||
mfs "github.com/ipfs/go-mfs"
|
||||
@ -117,7 +116,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
|
||||
}
|
||||
|
||||
bserv := blockservice.New(addblockstore, exch) // hash security 001
|
||||
dserv := dag.NewDAGService(bserv)
|
||||
dserv := merkledag.NewDAGService(bserv)
|
||||
|
||||
// add a sync call to the DagService
|
||||
// this ensures that data written to the DagService is persisted to the underlying datastore
|
||||
|
||||
@ -77,7 +77,7 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
|
||||
|
||||
AddAccessControlHeaders(headers)
|
||||
|
||||
offlineApi, err := api.WithOptions(options.Api.Offline(true))
|
||||
offlineAPI, err := api.WithOptions(options.Api.Offline(true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -86,7 +86,7 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
|
||||
Headers: headers,
|
||||
Writable: writable,
|
||||
FastDirIndexThreshold: int(cfg.Gateway.FastDirIndexThreshold.WithDefault(100)),
|
||||
}, api, offlineApi)
|
||||
}, api, offlineAPI)
|
||||
|
||||
gateway = otelhttp.NewHandler(gateway, "Gateway.Request")
|
||||
|
||||
@ -146,7 +146,7 @@ func VersionOption() ServeOption {
|
||||
mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Commit: %s\n", version.CurrentCommit)
|
||||
fmt.Fprintf(w, "Client Version: %s\n", version.GetUserAgentVersion())
|
||||
fmt.Fprintf(w, "Protocol Version: %s\n", id.LibP2PVersion)
|
||||
fmt.Fprintf(w, "Protocol Version: %s\n", id.DefaultProtocolVersion)
|
||||
})
|
||||
return mux, nil
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
gopath "path"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -40,7 +39,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
onlyAscii = regexp.MustCompile("[[:^ascii:]]")
|
||||
onlyASCII = regexp.MustCompile("[[:^ascii:]]")
|
||||
noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime
|
||||
)
|
||||
|
||||
@ -69,7 +68,7 @@ type redirectTemplateData struct {
|
||||
type gatewayHandler struct {
|
||||
config GatewayConfig
|
||||
api NodeAPI
|
||||
offlineApi NodeAPI
|
||||
offlineAPI NodeAPI
|
||||
|
||||
// generic metrics
|
||||
firstContentBlockGetMetric *prometheus.HistogramVec
|
||||
@ -215,15 +214,15 @@ func newGatewayHistogramMetric(name string, help string) *prometheus.HistogramVe
|
||||
|
||||
// NewGatewayHandler returns an http.Handler that can act as a gateway to IPFS content
|
||||
// offlineApi is a version of the API that should not make network requests for missing data
|
||||
func NewGatewayHandler(c GatewayConfig, api NodeAPI, offlineApi NodeAPI) http.Handler {
|
||||
return newGatewayHandler(c, api, offlineApi)
|
||||
func NewGatewayHandler(c GatewayConfig, api NodeAPI, offlineAPI NodeAPI) http.Handler {
|
||||
return newGatewayHandler(c, api, offlineAPI)
|
||||
}
|
||||
|
||||
func newGatewayHandler(c GatewayConfig, api NodeAPI, offlineApi NodeAPI) *gatewayHandler {
|
||||
func newGatewayHandler(c GatewayConfig, api NodeAPI, offlineAPI NodeAPI) *gatewayHandler {
|
||||
i := &gatewayHandler{
|
||||
config: c,
|
||||
api: api,
|
||||
offlineApi: offlineApi,
|
||||
offlineAPI: offlineAPI,
|
||||
// Improved Metrics
|
||||
// ----------------------------
|
||||
// Time till the first content block (bar in /ipfs/cid/foo/bar)
|
||||
@ -378,23 +377,6 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
|
||||
// Resolve path to the final DAG node for the ETag
|
||||
resolvedPath, err := i.api.ResolvePath(r.Context(), contentPath)
|
||||
switch err {
|
||||
case nil:
|
||||
case coreiface.ErrOffline:
|
||||
webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusServiceUnavailable)
|
||||
return
|
||||
default:
|
||||
// if Accept is text/html, see if ipfs-404.html is present
|
||||
if i.servePretty404IfPresent(w, r, contentPath) {
|
||||
logger.Debugw("serve pretty 404 if present")
|
||||
return
|
||||
}
|
||||
webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Detect when explicit Accept header or ?format parameter are present
|
||||
responseFormat, formatParams, err := customResponseFormat(r)
|
||||
if err != nil {
|
||||
@ -402,6 +384,11 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
|
||||
return
|
||||
}
|
||||
trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResponseFormat", responseFormat))
|
||||
|
||||
resolvedPath, contentPath, ok := i.handlePathResolution(w, r, responseFormat, contentPath, logger)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String()))
|
||||
|
||||
// Detect when If-None-Match HTTP header allows returning HTTP 304 Not Modified
|
||||
@ -450,36 +437,6 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) servePretty404IfPresent(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) bool {
|
||||
resolved404Path, ctype, err := i.searchUpTreeFor404(r, contentPath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
dr, err := i.api.Unixfs().Get(r.Context(), resolved404Path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer dr.Close()
|
||||
|
||||
f, ok := dr.(files.File)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
size, err := f.Size()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
log.Debugw("using pretty 404 file", "path", contentPath)
|
||||
w.Header().Set("Content-Type", ctype)
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, err = io.CopyN(w, f, size)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
p, err := i.api.Unixfs().Add(r.Context(), files.NewReaderFile(r.Body))
|
||||
if err != nil {
|
||||
@ -726,7 +683,7 @@ func addContentDispositionHeader(w http.ResponseWriter, r *http.Request, content
|
||||
// Set Content-Disposition to arbitrary filename and disposition
|
||||
func setContentDispositionHeader(w http.ResponseWriter, filename string, disposition string) {
|
||||
utf8Name := url.PathEscape(filename)
|
||||
asciiName := url.PathEscape(onlyAscii.ReplaceAllLiteralString(filename, "_"))
|
||||
asciiName := url.PathEscape(onlyASCII.ReplaceAllLiteralString(filename, "_"))
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"; filename*=UTF-8''%s", disposition, asciiName, utf8Name))
|
||||
}
|
||||
|
||||
@ -920,48 +877,6 @@ func customResponseFormat(r *http.Request) (mediaType string, params map[string]
|
||||
return "", nil, nil
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) {
|
||||
filename404, ctype, err := preferred404Filename(r.Header.Values("Accept"))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
pathComponents := strings.Split(contentPath.String(), "/")
|
||||
|
||||
for idx := len(pathComponents); idx >= 3; idx-- {
|
||||
pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...)
|
||||
parsed404Path := ipath.New("/" + pretty404)
|
||||
if parsed404Path.IsValid() != nil {
|
||||
break
|
||||
}
|
||||
resolvedPath, err := i.api.ResolvePath(r.Context(), parsed404Path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
return resolvedPath, ctype, nil
|
||||
}
|
||||
|
||||
return nil, "", fmt.Errorf("no pretty 404 in any parent folder")
|
||||
}
|
||||
|
||||
func preferred404Filename(acceptHeaders []string) (string, string, error) {
|
||||
// If we ever want to offer a 404 file for a different content type
|
||||
// then this function will need to parse q weightings, but for now
|
||||
// the presence of anything matching HTML is enough.
|
||||
for _, acceptHeader := range acceptHeaders {
|
||||
accepted := strings.Split(acceptHeader, ",")
|
||||
for _, spec := range accepted {
|
||||
contentType := strings.SplitN(spec, ";", 1)[0]
|
||||
switch contentType {
|
||||
case "*/*", "text/*", "text/html":
|
||||
return "ipfs-404.html", "text/html", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", "", fmt.Errorf("there is no 404 file for the requested content types")
|
||||
}
|
||||
|
||||
// returns unquoted path with all special characters revealed as \u codes
|
||||
func debugStr(path string) string {
|
||||
q := fmt.Sprintf("%+q", path)
|
||||
@ -971,11 +886,54 @@ func debugStr(path string) string {
|
||||
return q
|
||||
}
|
||||
|
||||
// Resolve the provided contentPath including any special handling related to
|
||||
// the requested responseFormat. Returned ok flag indicates if gateway handler
|
||||
// should continue processing the request.
|
||||
func (i *gatewayHandler) handlePathResolution(w http.ResponseWriter, r *http.Request, responseFormat string, contentPath ipath.Path, logger *zap.SugaredLogger) (resolvedPath ipath.Resolved, newContentPath ipath.Path, ok bool) {
|
||||
// Attempt to resolve the provided path.
|
||||
resolvedPath, err := i.api.ResolvePath(r.Context(), contentPath)
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
return resolvedPath, contentPath, true
|
||||
case coreiface.ErrOffline:
|
||||
webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusServiceUnavailable)
|
||||
return nil, nil, false
|
||||
default:
|
||||
// The path can't be resolved.
|
||||
if isUnixfsResponseFormat(responseFormat) {
|
||||
// If we have origin isolation (subdomain gw, DNSLink website),
|
||||
// and response type is UnixFS (default for website hosting)
|
||||
// check for presence of _redirects file and apply rules defined there.
|
||||
// See: https://github.com/ipfs/specs/pull/290
|
||||
if hasOriginIsolation(r) {
|
||||
resolvedPath, newContentPath, ok, hadMatchingRule := i.serveRedirectsIfPresent(w, r, resolvedPath, contentPath, logger)
|
||||
if hadMatchingRule {
|
||||
logger.Debugw("applied a rule from _redirects file")
|
||||
return resolvedPath, newContentPath, ok
|
||||
}
|
||||
}
|
||||
|
||||
// if Accept is text/html, see if ipfs-404.html is present
|
||||
// This logic isn't documented and will likely be removed at some point.
|
||||
// Any 404 logic in _redirects above will have already run by this time, so it's really an extra fall back
|
||||
if i.serveLegacy404IfPresent(w, r, contentPath) {
|
||||
logger.Debugw("served legacy 404")
|
||||
return nil, nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Note: webError will replace http.StatusBadRequest with StatusNotFound if necessary
|
||||
webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusBadRequest)
|
||||
return nil, nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Detect 'Cache-Control: only-if-cached' in request and return data if it is already in the local datastore.
|
||||
// https://github.com/ipfs/specs/blob/main/http-gateways/PATH_GATEWAY.md#cache-control-request-header
|
||||
func (i *gatewayHandler) handleOnlyIfCached(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) (requestHandled bool) {
|
||||
if r.Header.Get("Cache-Control") == "only-if-cached" {
|
||||
_, err := i.offlineApi.Block().Stat(r.Context(), contentPath)
|
||||
_, err := i.offlineAPI.Block().Stat(r.Context(), contentPath)
|
||||
if err != nil {
|
||||
if r.Method == http.MethodHead {
|
||||
w.WriteHeader(http.StatusPreconditionFailed)
|
||||
|
||||
287
core/corehttp/gateway_handler_unixfs__redirects.go
Normal file
287
core/corehttp/gateway_handler_unixfs__redirects.go
Normal file
@ -0,0 +1,287 @@
|
||||
package corehttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
gopath "path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
files "github.com/ipfs/go-ipfs-files"
|
||||
redirects "github.com/ipfs/go-ipfs-redirects-file"
|
||||
ipath "github.com/ipfs/interface-go-ipfs-core/path"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Resolving a UnixFS path involves determining if the provided `path.Path` exists and returning the `path.Resolved`
|
||||
// corresponding to that path. For UnixFS, path resolution is more involved.
|
||||
//
|
||||
// When a path under requested CID does not exist, Gateway will check if a `_redirects` file exists
|
||||
// underneath the root CID of the path, and apply rules defined there.
|
||||
// See sepcification introduced in: https://github.com/ipfs/specs/pull/290
|
||||
//
|
||||
// Scenario 1:
|
||||
// If a path exists, we always return the `path.Resolved` corresponding to that path, regardless of the existence of a `_redirects` file.
|
||||
//
|
||||
// Scenario 2:
|
||||
// If a path does not exist, usually we should return a `nil` resolution path and an error indicating that the path
|
||||
// doesn't exist. However, a `_redirects` file may exist and contain a redirect rule that redirects that path to a different path.
|
||||
// We need to evaluate the rule and perform the redirect if present.
|
||||
//
|
||||
// Scenario 3:
|
||||
// Another possibility is that the path corresponds to a rewrite rule (i.e. a rule with a status of 200).
|
||||
// In this case, we don't perform a redirect, but do need to return a `path.Resolved` and `path.Path` corresponding to
|
||||
// the rewrite destination path.
|
||||
//
|
||||
// Note that for security reasons, redirect rules are only processed when the request has origin isolation.
|
||||
// See https://github.com/ipfs/specs/pull/290 for more information.
|
||||
func (i *gatewayHandler) serveRedirectsIfPresent(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, logger *zap.SugaredLogger) (newResolvedPath ipath.Resolved, newContentPath ipath.Path, continueProcessing bool, hadMatchingRule bool) {
|
||||
redirectsFile := i.getRedirectsFile(r, contentPath, logger)
|
||||
if redirectsFile != nil {
|
||||
redirectRules, err := i.getRedirectRules(r, redirectsFile)
|
||||
if err != nil {
|
||||
internalWebError(w, err)
|
||||
return nil, nil, false, true
|
||||
}
|
||||
|
||||
redirected, newPath, err := i.handleRedirectsFileRules(w, r, contentPath, redirectRules)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("trouble processing _redirects file at %q: %w", redirectsFile.String(), err)
|
||||
internalWebError(w, err)
|
||||
return nil, nil, false, true
|
||||
}
|
||||
|
||||
if redirected {
|
||||
return nil, nil, false, true
|
||||
}
|
||||
|
||||
// 200 is treated as a rewrite, so update the path and continue
|
||||
if newPath != "" {
|
||||
// Reassign contentPath and resolvedPath since the URL was rewritten
|
||||
contentPath = ipath.New(newPath)
|
||||
resolvedPath, err = i.api.ResolvePath(r.Context(), contentPath)
|
||||
if err != nil {
|
||||
internalWebError(w, err)
|
||||
return nil, nil, false, true
|
||||
}
|
||||
|
||||
return resolvedPath, contentPath, true, true
|
||||
}
|
||||
}
|
||||
// No matching rule, paths remain the same, continue regular processing
|
||||
return resolvedPath, contentPath, true, false
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) handleRedirectsFileRules(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, redirectRules []redirects.Rule) (redirected bool, newContentPath string, err error) {
|
||||
// Attempt to match a rule to the URL path, and perform the corresponding redirect or rewrite
|
||||
pathParts := strings.Split(contentPath.String(), "/")
|
||||
if len(pathParts) > 3 {
|
||||
// All paths should start with /ipfs/cid/, so get the path after that
|
||||
urlPath := "/" + strings.Join(pathParts[3:], "/")
|
||||
rootPath := strings.Join(pathParts[:3], "/")
|
||||
// Trim off the trailing /
|
||||
urlPath = strings.TrimSuffix(urlPath, "/")
|
||||
|
||||
for _, rule := range redirectRules {
|
||||
// Error right away if the rule is invalid
|
||||
if !rule.MatchAndExpandPlaceholders(urlPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
// We have a match!
|
||||
|
||||
// Rewrite
|
||||
if rule.Status == 200 {
|
||||
// Prepend the rootPath
|
||||
toPath := rootPath + rule.To
|
||||
return false, toPath, nil
|
||||
}
|
||||
|
||||
// Or 4xx
|
||||
if rule.Status == 404 || rule.Status == 410 || rule.Status == 451 {
|
||||
toPath := rootPath + rule.To
|
||||
content4xxPath := ipath.New(toPath)
|
||||
err := i.serve4xx(w, r, content4xxPath, rule.Status)
|
||||
return true, toPath, err
|
||||
}
|
||||
|
||||
// Or redirect
|
||||
if rule.Status >= 301 && rule.Status <= 308 {
|
||||
http.Redirect(w, r, rule.To, rule.Status)
|
||||
return true, "", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No redirects matched
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) getRedirectRules(r *http.Request, redirectsFilePath ipath.Resolved) ([]redirects.Rule, error) {
|
||||
// Convert the path into a file node
|
||||
node, err := i.api.Unixfs().Get(r.Context(), redirectsFilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get _redirects: %w", err)
|
||||
}
|
||||
defer node.Close()
|
||||
|
||||
// Convert the node into a file
|
||||
f, ok := node.(files.File)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not parse _redirects: %w", err)
|
||||
}
|
||||
|
||||
// Parse redirect rules from file
|
||||
redirectRules, err := redirects.Parse(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse _redirects: %w", err)
|
||||
}
|
||||
|
||||
return redirectRules, nil
|
||||
}
|
||||
|
||||
// Returns a resolved path to the _redirects file located in the root CID path of the requested path
|
||||
func (i *gatewayHandler) getRedirectsFile(r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) ipath.Resolved {
|
||||
// contentPath is the full ipfs path to the requested resource,
|
||||
// regardless of whether path or subdomain resolution is used.
|
||||
rootPath := getRootPath(contentPath)
|
||||
|
||||
// Check for _redirects file.
|
||||
// Any path resolution failures are ignored and we just assume there's no _redirects file.
|
||||
// Note that ignoring these errors also ensures that the use of the empty CID (bafkqaaa) in tests doesn't fail.
|
||||
path := ipath.Join(rootPath, "_redirects")
|
||||
resolvedPath, err := i.api.ResolvePath(r.Context(), path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return resolvedPath
|
||||
}
|
||||
|
||||
// Returns the root CID Path for the given path
|
||||
func getRootPath(path ipath.Path) ipath.Path {
|
||||
parts := strings.Split(path.String(), "/")
|
||||
return ipath.New(gopath.Join("/", path.Namespace(), parts[2]))
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) serve4xx(w http.ResponseWriter, r *http.Request, content4xxPath ipath.Path, status int) error {
|
||||
resolved4xxPath, err := i.api.ResolvePath(r.Context(), content4xxPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
node, err := i.api.Unixfs().Get(r.Context(), resolved4xxPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer node.Close()
|
||||
|
||||
f, ok := node.(files.File)
|
||||
if !ok {
|
||||
return fmt.Errorf("could not convert node for %d page to file", status)
|
||||
}
|
||||
|
||||
size, err := f.Size()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get size of %d page", status)
|
||||
}
|
||||
|
||||
log.Debugf("using _redirects: custom %d file at %q", status, content4xxPath)
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
|
||||
addCacheControlHeaders(w, r, content4xxPath, resolved4xxPath.Cid())
|
||||
w.WriteHeader(status)
|
||||
_, err = io.CopyN(w, f, size)
|
||||
return err
|
||||
}
|
||||
|
||||
func hasOriginIsolation(r *http.Request) bool {
|
||||
_, gw := r.Context().Value(requestContextKey("gw-hostname")).(string)
|
||||
_, dnslink := r.Context().Value("dnslink-hostname").(string)
|
||||
|
||||
if gw || dnslink {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func isUnixfsResponseFormat(responseFormat string) bool {
|
||||
// The implicit response format is UnixFS
|
||||
return responseFormat == ""
|
||||
}
|
||||
|
||||
// Deprecated: legacy ipfs-404.html files are superseded by _redirects file
|
||||
// This is provided only for backward-compatibility, until websites migrate
|
||||
// to 404s managed via _redirects file (https://github.com/ipfs/specs/pull/290)
|
||||
func (i *gatewayHandler) serveLegacy404IfPresent(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) bool {
|
||||
resolved404Path, ctype, err := i.searchUpTreeFor404(r, contentPath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
dr, err := i.api.Unixfs().Get(r.Context(), resolved404Path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer dr.Close()
|
||||
|
||||
f, ok := dr.(files.File)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
size, err := f.Size()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
log.Debugw("using pretty 404 file", "path", contentPath)
|
||||
w.Header().Set("Content-Type", ctype)
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, err = io.CopyN(w, f, size)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) {
|
||||
filename404, ctype, err := preferred404Filename(r.Header.Values("Accept"))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
pathComponents := strings.Split(contentPath.String(), "/")
|
||||
|
||||
for idx := len(pathComponents); idx >= 3; idx-- {
|
||||
pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...)
|
||||
parsed404Path := ipath.New("/" + pretty404)
|
||||
if parsed404Path.IsValid() != nil {
|
||||
break
|
||||
}
|
||||
resolvedPath, err := i.api.ResolvePath(r.Context(), parsed404Path)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
return resolvedPath, ctype, nil
|
||||
}
|
||||
|
||||
return nil, "", fmt.Errorf("no pretty 404 in any parent folder")
|
||||
}
|
||||
|
||||
func preferred404Filename(acceptHeaders []string) (string, string, error) {
|
||||
// If we ever want to offer a 404 file for a different content type
|
||||
// then this function will need to parse q weightings, but for now
|
||||
// the presence of anything matching HTML is enough.
|
||||
for _, acceptHeader := range acceptHeaders {
|
||||
accepted := strings.Split(acceptHeader, ",")
|
||||
for _, spec := range accepted {
|
||||
contentType := strings.SplitN(spec, ";", 1)[0]
|
||||
switch contentType {
|
||||
case "*/*", "text/*", "text/html":
|
||||
return "ipfs-404.html", "text/html", nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", "", fmt.Errorf("there is no 404 file for the requested content types")
|
||||
}
|
||||
@ -39,10 +39,10 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit
|
||||
webError(w, "failed to parse request path", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
originalUrlPath := requestURI.Path
|
||||
originalURLPath := requestURI.Path
|
||||
|
||||
// Ensure directory paths end with '/'
|
||||
if originalUrlPath[len(originalUrlPath)-1] != '/' {
|
||||
if originalURLPath[len(originalURLPath)-1] != '/' {
|
||||
// don't redirect to trailing slash if it's go get
|
||||
// https://github.com/ipfs/kubo/pull/3963
|
||||
goget := r.URL.Query().Get("go-get") == "1"
|
||||
@ -53,7 +53,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit
|
||||
suffix = suffix + "?" + r.URL.RawQuery
|
||||
}
|
||||
// /ipfs/cid/foo?bar must be redirected to /ipfs/cid/foo/?bar
|
||||
redirectURL := originalUrlPath + suffix
|
||||
redirectURL := originalURLPath + suffix
|
||||
logger.Debugw("directory location moved permanently", "status", http.StatusMovedPermanently)
|
||||
http.Redirect(w, r, redirectURL, http.StatusMovedPermanently)
|
||||
return
|
||||
@ -125,7 +125,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit
|
||||
di := directoryItem{
|
||||
Size: "", // no size because we did not fetch child nodes
|
||||
Name: link.Name,
|
||||
Path: gopath.Join(originalUrlPath, link.Name),
|
||||
Path: gopath.Join(originalURLPath, link.Name),
|
||||
Hash: hash,
|
||||
ShortHash: shortHash(hash),
|
||||
}
|
||||
@ -149,7 +149,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit
|
||||
|
||||
// construct the correct back link
|
||||
// https://github.com/ipfs/kubo/issues/1365
|
||||
var backLink string = originalUrlPath
|
||||
backLink := originalURLPath
|
||||
|
||||
// don't go further up than /ipfs/$hash/
|
||||
pathSplit := path.SplitList(contentPath.String())
|
||||
@ -185,7 +185,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit
|
||||
var gwURL string
|
||||
|
||||
// Get gateway hostname and build gateway URL.
|
||||
if h, ok := r.Context().Value("gw-hostname").(string); ok {
|
||||
if h, ok := r.Context().Value(requestContextKey("gw-hostname")).(string); ok {
|
||||
gwURL = "//" + h
|
||||
} else {
|
||||
gwURL = ""
|
||||
|
||||
@ -117,8 +117,8 @@ func init() {
|
||||
|
||||
// custom template-escaping function to escape a full path, including '#' and '?'
|
||||
urlEscape := func(rawUrl string) string {
|
||||
pathUrl := url.URL{Path: rawUrl}
|
||||
return pathUrl.String()
|
||||
pathURL := url.URL{Path: rawUrl}
|
||||
return pathURL.String()
|
||||
}
|
||||
|
||||
// Directory listing template
|
||||
|
||||
@ -652,7 +652,7 @@ func TestVersion(t *testing.T) {
|
||||
t.Fatalf("response doesn't contain client version:\n%s", s)
|
||||
}
|
||||
|
||||
if !strings.Contains(s, "Protocol Version: "+id.LibP2PVersion) {
|
||||
if !strings.Contains(s, "Protocol Version: "+id.DefaultProtocolVersion) {
|
||||
t.Fatalf("response doesn't contain protocol version:\n%s", s)
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +84,8 @@ func HostnameOption() ServeOption {
|
||||
if gw.UseSubdomains {
|
||||
// Yes, redirect if applicable
|
||||
// Example: dweb.link/ipfs/{cid} → {cid}.ipfs.dweb.link
|
||||
newURL, err := toSubdomainURL(host, r.URL.Path, r, coreAPI)
|
||||
useInlinedDNSLink := gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink)
|
||||
newURL, err := toSubdomainURL(host, r.URL.Path, r, useInlinedDNSLink, coreAPI)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
@ -132,6 +133,9 @@ func HostnameOption() ServeOption {
|
||||
// Assemble original path prefix.
|
||||
pathPrefix := "/" + ns + "/" + rootID
|
||||
|
||||
// Retrieve whether or not we should inline DNSLink.
|
||||
useInlinedDNSLink := gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink)
|
||||
|
||||
// Does this gateway _handle_ subdomains AND this path?
|
||||
if !(gw.UseSubdomains && hasPrefix(pathPrefix, gw.Paths...)) {
|
||||
// If not, resource does not exist, return 404
|
||||
@ -149,7 +153,7 @@ func HostnameOption() ServeOption {
|
||||
}
|
||||
if !strings.HasPrefix(r.Host, dnsCID) {
|
||||
dnsPrefix := "/" + ns + "/" + dnsCID
|
||||
newURL, err := toSubdomainURL(gwHostname, dnsPrefix+r.URL.Path, r, coreAPI)
|
||||
newURL, err := toSubdomainURL(gwHostname, dnsPrefix+r.URL.Path, r, useInlinedDNSLink, coreAPI)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
@ -165,7 +169,7 @@ func HostnameOption() ServeOption {
|
||||
// Do we need to fix multicodec in PeerID represented as CIDv1?
|
||||
if isPeerIDNamespace(ns) {
|
||||
if rootCID.Type() != cid.Libp2pKey {
|
||||
newURL, err := toSubdomainURL(gwHostname, pathPrefix+r.URL.Path, r, coreAPI)
|
||||
newURL, err := toSubdomainURL(gwHostname, pathPrefix+r.URL.Path, r, useInlinedDNSLink, coreAPI)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
@ -221,7 +225,8 @@ func HostnameOption() ServeOption {
|
||||
if !cfg.Gateway.NoDNSLink && isDNSLinkName(r.Context(), coreAPI, host) {
|
||||
// rewrite path and handle as DNSLink
|
||||
r.URL.Path = "/ipns/" + stripPort(host) + r.URL.Path
|
||||
childMux.ServeHTTP(w, withHostnameContext(r, host))
|
||||
ctx := context.WithValue(r.Context(), requestContextKey("dnslink-hostname"), host)
|
||||
childMux.ServeHTTP(w, withHostnameContext(r.WithContext(ctx), host))
|
||||
return
|
||||
}
|
||||
|
||||
@ -242,6 +247,8 @@ type wildcardHost struct {
|
||||
spec *config.GatewaySpec
|
||||
}
|
||||
|
||||
type requestContextKey string
|
||||
|
||||
// Extends request context to include hostname of a canonical gateway root
|
||||
// (subdomain root or dnslink fqdn)
|
||||
func withHostnameContext(r *http.Request, hostname string) *http.Request {
|
||||
@ -250,7 +257,7 @@ func withHostnameContext(r *http.Request, hostname string) *http.Request {
|
||||
// Host header, subdomain gateways have more comples rules (knownSubdomainDetails)
|
||||
// More: https://github.com/ipfs/dir-index-html/issues/42
|
||||
// nolint: staticcheck // non-backward compatible change
|
||||
ctx := context.WithValue(r.Context(), "gw-hostname", hostname)
|
||||
ctx := context.WithValue(r.Context(), requestContextKey("gw-hostname"), hostname)
|
||||
return r.WithContext(ctx)
|
||||
}
|
||||
|
||||
@ -448,7 +455,7 @@ func toDNSLinkFQDN(dnsLabel string) (fqdn string) {
|
||||
}
|
||||
|
||||
// Converts a hostname/path to a subdomain-based URL, if applicable.
|
||||
func toSubdomainURL(hostname, path string, r *http.Request, ipfs iface.CoreAPI) (redirURL string, err error) {
|
||||
func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool, ipfs iface.CoreAPI) (redirURL string, err error) {
|
||||
var scheme, ns, rootID, rest string
|
||||
|
||||
query := r.URL.RawQuery
|
||||
@ -551,7 +558,7 @@ func toSubdomainURL(hostname, path string, r *http.Request, ipfs iface.CoreAPI)
|
||||
// can be loaded from a subdomain gateway with a wildcard TLS cert if
|
||||
// represented as a single DNS label:
|
||||
// https://my-v--long-example-com.ipns.dweb.link
|
||||
if isHTTPS && ns == "ipns" && strings.Contains(rootID, ".") {
|
||||
if (inlineDNSLink || isHTTPS) && ns == "ipns" && strings.Contains(rootID, ".") {
|
||||
if isDNSLinkName(r.Context(), ipfs, rootID) {
|
||||
// my.v-long.example.com → my-v--long-example-com
|
||||
dnsLabel, err := toDNSLinkDNSLabel(rootID)
|
||||
|
||||
@ -36,35 +36,39 @@ func TestToSubdomainURL(t *testing.T) {
|
||||
|
||||
for _, test := range []struct {
|
||||
// in:
|
||||
request *http.Request
|
||||
gwHostname string
|
||||
path string
|
||||
request *http.Request
|
||||
gwHostname string
|
||||
inlineDNSLink bool
|
||||
path string
|
||||
// out:
|
||||
url string
|
||||
err error
|
||||
}{
|
||||
// DNSLink
|
||||
{httpRequest, "localhost", "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost/", nil},
|
||||
{httpRequest, "localhost", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost/", nil},
|
||||
// Hostname with port
|
||||
{httpRequest, "localhost:8080", "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost:8080/", nil},
|
||||
{httpRequest, "localhost:8080", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost:8080/", nil},
|
||||
// CIDv0 → CIDv1base32
|
||||
{httpRequest, "localhost", "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.localhost/", nil},
|
||||
{httpRequest, "localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.localhost/", nil},
|
||||
// CIDv1 with long sha512
|
||||
{httpRequest, "localhost", "/ipfs/bafkrgqe3ohjcjplc6n4f3fwunlj6upltggn7xqujbsvnvyw764srszz4u4rshq6ztos4chl4plgg4ffyyxnayrtdi5oc4xb2332g645433aeg", "", errors.New("CID incompatible with DNS label length limit of 63: kf1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5oj")},
|
||||
{httpRequest, "localhost", false, "/ipfs/bafkrgqe3ohjcjplc6n4f3fwunlj6upltggn7xqujbsvnvyw764srszz4u4rshq6ztos4chl4plgg4ffyyxnayrtdi5oc4xb2332g645433aeg", "", errors.New("CID incompatible with DNS label length limit of 63: kf1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5oj")},
|
||||
// PeerID as CIDv1 needs to have libp2p-key multicodec
|
||||
{httpRequest, "localhost", "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", "http://k2k4r8n0flx3ra0y5dr8fmyvwbzy3eiztmtq6th694k5a3rznayp3e4o.ipns.localhost/", nil},
|
||||
{httpRequest, "localhost", "/ipns/bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "http://k2k4r8l9ja7hkzynavdqup76ou46tnvuaqegbd04a4o1mpbsey0meucb.ipns.localhost/", nil},
|
||||
{httpRequest, "localhost", false, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", "http://k2k4r8n0flx3ra0y5dr8fmyvwbzy3eiztmtq6th694k5a3rznayp3e4o.ipns.localhost/", nil},
|
||||
{httpRequest, "localhost", false, "/ipns/bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "http://k2k4r8l9ja7hkzynavdqup76ou46tnvuaqegbd04a4o1mpbsey0meucb.ipns.localhost/", nil},
|
||||
// PeerID: ed25519+identity multihash → CIDv1Base36
|
||||
{httpRequest, "localhost", "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna.ipns.localhost/", nil},
|
||||
{httpRequest, "sub.localhost", "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.sub.localhost/", nil},
|
||||
{httpRequest, "localhost", false, "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna.ipns.localhost/", nil},
|
||||
{httpRequest, "sub.localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.sub.localhost/", nil},
|
||||
// HTTPS requires DNSLink name to fit in a single DNS label – see "Option C" from https://github.com/ipfs/in-web-browsers/issues/169
|
||||
{httpRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "http://dnslink.long-name.example.com.ipns.dweb.link/", nil},
|
||||
{httpsRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil},
|
||||
{httpsProxiedRequest, "dweb.link", "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil},
|
||||
{httpRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "http://dnslink.long-name.example.com.ipns.dweb.link/", nil},
|
||||
{httpsRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil},
|
||||
{httpsProxiedRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil},
|
||||
// HTTP requests can also be converted to fit into a single DNS label - https://github.com/ipfs/kubo/issues/9243
|
||||
{httpRequest, "localhost", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.localhost/", nil},
|
||||
{httpRequest, "dweb.link", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.dweb.link/", nil},
|
||||
} {
|
||||
url, err := toSubdomainURL(test.gwHostname, test.path, test.request, coreAPI)
|
||||
url, err := toSubdomainURL(test.gwHostname, test.path, test.request, test.inlineDNSLink, coreAPI)
|
||||
if url != test.url || !equalError(err, test.err) {
|
||||
t.Errorf("(%s, %s) returned (%s, %v), expected (%s, %v)", test.gwHostname, test.path, url, err, test.url, test.err)
|
||||
t.Errorf("(%s, %v, %s) returned (%s, %v), expected (%s, %v)", test.gwHostname, test.inlineDNSLink, test.path, url, err, test.url, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,14 +11,14 @@ type badSeeker struct {
|
||||
io.ReadSeeker
|
||||
}
|
||||
|
||||
var badSeekErr = fmt.Errorf("I'm a bad seeker")
|
||||
var errBadSeek = fmt.Errorf("bad seeker")
|
||||
|
||||
func (bs badSeeker) Seek(offset int64, whence int) (int64, error) {
|
||||
off, err := bs.ReadSeeker.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return off, badSeekErr
|
||||
return off, errBadSeek
|
||||
}
|
||||
|
||||
func TestLazySeekerError(t *testing.T) {
|
||||
@ -73,7 +73,7 @@ func TestLazySeekerError(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error, got output %s", string(b))
|
||||
}
|
||||
if err != badSeekErr {
|
||||
if err != errBadSeek {
|
||||
t.Fatalf("expected a bad seek error, got %s", err)
|
||||
}
|
||||
if len(b) != 0 {
|
||||
|
||||
@ -164,7 +164,7 @@ type IpfsNodeCollector struct {
|
||||
Node *core.IpfsNode
|
||||
}
|
||||
|
||||
func (_ IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||
func (IpfsNodeCollector) Describe(ch chan<- *prometheus.Desc) {
|
||||
ch <- peersTotalMetric
|
||||
}
|
||||
|
||||
|
||||
@ -58,11 +58,11 @@ func parseRequest(request *http.Request) (*proxyRequest, error) {
|
||||
|
||||
split := strings.SplitN(path, "/", 5)
|
||||
if len(split) < 5 {
|
||||
return nil, fmt.Errorf("Invalid request path '%s'", path)
|
||||
return nil, fmt.Errorf("invalid request path '%s'", path)
|
||||
}
|
||||
|
||||
if _, err := peer.Decode(split[2]); err != nil {
|
||||
return nil, fmt.Errorf("Invalid request path '%s'", path)
|
||||
return nil, fmt.Errorf("invalid request path '%s'", path)
|
||||
}
|
||||
|
||||
if split[3] == "http" {
|
||||
@ -71,7 +71,7 @@ func parseRequest(request *http.Request) (*proxyRequest, error) {
|
||||
|
||||
split = strings.SplitN(path, "/", 7)
|
||||
if len(split) < 7 || split[3] != "x" || split[5] != "http" {
|
||||
return nil, fmt.Errorf("Invalid request path '%s'", path)
|
||||
return nil, fmt.Errorf("invalid request path '%s'", path)
|
||||
}
|
||||
|
||||
return &proxyRequest{split[2], protocol.ID("/x/" + split[4] + "/http"), split[6]}, nil
|
||||
|
||||
@ -24,5 +24,5 @@ type redirectHandler struct {
|
||||
}
|
||||
|
||||
func (i *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, i.path, 302)
|
||||
http.Redirect(w, r, i.path, http.StatusFound)
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package corehttp
|
||||
// TODO: move to IPNS
|
||||
const WebUIPath = "/ipfs/bafybeiageaoxg6d7npaof6eyzqbwvbubyler7bq44hayik2hvqcggg7d2y" // v2.18.1
|
||||
|
||||
// this is a list of all past webUI paths.
|
||||
// WebUIPaths is a list of all past webUI paths.
|
||||
var WebUIPaths = []string{
|
||||
WebUIPath,
|
||||
"/ipfs/bafybeidb5eryh72zajiokdggzo7yct2d6hhcflncji5im2y5w26uuygdsm",
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"github.com/ipfs/go-bitswap/network"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
exchange "github.com/ipfs/go-ipfs-exchange-interface"
|
||||
config "github.com/ipfs/kubo/config"
|
||||
"github.com/ipfs/kubo/config"
|
||||
irouting "github.com/ipfs/kubo/routing"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"go.uber.org/fx"
|
||||
@ -15,19 +15,24 @@ import (
|
||||
"github.com/ipfs/kubo/core/node/helpers"
|
||||
)
|
||||
|
||||
// Docs: https://github.com/ipfs/kubo/blob/master/docs/config.md#internalbitswap
|
||||
const (
|
||||
// Docs: https://github.com/ipfs/kubo/blob/master/docs/config.md#internalbitswap
|
||||
DefaultEngineBlockstoreWorkerCount = 128
|
||||
DefaultTaskWorkerCount = 8
|
||||
DefaultEngineTaskWorkerCount = 8
|
||||
DefaultMaxOutstandingBytesPerPeer = 1 << 20
|
||||
)
|
||||
|
||||
// OnlineExchange creates new LibP2P backed block exchange (BitSwap)
|
||||
func OnlineExchange(cfg *config.Config, provide bool) interface{} {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt irouting.TieredRouter, bs blockstore.GCBlockstore) exchange.Interface {
|
||||
bitswapNetwork := network.NewFromIpfsHost(host, rt)
|
||||
type bitswapOptionsOut struct {
|
||||
fx.Out
|
||||
|
||||
BitswapOpts []bitswap.Option `group:"bitswap-options,flatten"`
|
||||
}
|
||||
|
||||
// BitswapOptions creates configuration options for Bitswap from the config file
|
||||
// and whether to provide data.
|
||||
func BitswapOptions(cfg *config.Config, provide bool) interface{} {
|
||||
return func() bitswapOptionsOut {
|
||||
var internalBsCfg config.InternalBitswap
|
||||
if cfg.Internal.Bitswap != nil {
|
||||
internalBsCfg = *cfg.Internal.Bitswap
|
||||
@ -40,13 +45,34 @@ func OnlineExchange(cfg *config.Config, provide bool) interface{} {
|
||||
bitswap.EngineTaskWorkerCount(int(internalBsCfg.EngineTaskWorkerCount.WithDefault(DefaultEngineTaskWorkerCount))),
|
||||
bitswap.MaxOutstandingBytesPerPeer(int(internalBsCfg.MaxOutstandingBytesPerPeer.WithDefault(DefaultMaxOutstandingBytesPerPeer))),
|
||||
}
|
||||
exch := bitswap.New(helpers.LifecycleCtx(mctx, lc), bitswapNetwork, bs, opts...)
|
||||
|
||||
return bitswapOptionsOut{BitswapOpts: opts}
|
||||
}
|
||||
}
|
||||
|
||||
type onlineExchangeIn struct {
|
||||
fx.In
|
||||
|
||||
Mctx helpers.MetricsCtx
|
||||
Host host.Host
|
||||
Rt irouting.ProvideManyRouter
|
||||
Bs blockstore.GCBlockstore
|
||||
BitswapOpts []bitswap.Option `group:"bitswap-options"`
|
||||
}
|
||||
|
||||
// OnlineExchange creates new LibP2P backed block exchange (BitSwap).
|
||||
// Additional options to bitswap.New can be provided via the "bitswap-options"
|
||||
// group.
|
||||
func OnlineExchange() interface{} {
|
||||
return func(in onlineExchangeIn, lc fx.Lifecycle) exchange.Interface {
|
||||
bitswapNetwork := network.NewFromIpfsHost(in.Host, in.Rt)
|
||||
|
||||
exch := bitswap.New(helpers.LifecycleCtx(in.Mctx, lc), bitswapNetwork, in.Bs, in.BitswapOpts...)
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(ctx context.Context) error {
|
||||
return exch.Close()
|
||||
},
|
||||
})
|
||||
return exch
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +165,6 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
|
||||
fx.Provide(libp2p.ContentRouting),
|
||||
|
||||
fx.Provide(libp2p.BaseRouting(cfg.Experimental.AcceleratedDHTClient)),
|
||||
fx.Provide(libp2p.DelegatedRouting(cfg.Routing.Routers)),
|
||||
maybeProvide(libp2p.PubsubRouter, bcfg.getOpt("ipnsps")),
|
||||
|
||||
maybeProvide(libp2p.BandwidthCounter, !cfg.Swarm.DisableBandwidthMetrics),
|
||||
@ -289,7 +288,8 @@ func Online(bcfg *BuildCfg, cfg *config.Config) fx.Option {
|
||||
shouldBitswapProvide := !cfg.Experimental.StrategicProviding
|
||||
|
||||
return fx.Options(
|
||||
fx.Provide(OnlineExchange(cfg, shouldBitswapProvide)),
|
||||
fx.Provide(BitswapOptions(cfg, shouldBitswapProvide)),
|
||||
fx.Provide(OnlineExchange()),
|
||||
maybeProvide(Graphsync, cfg.Experimental.GraphsyncEnabled),
|
||||
fx.Provide(DNSResolver),
|
||||
fx.Provide(Namesys(ipnsCacheSize)),
|
||||
|
||||
@ -11,11 +11,10 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
madns "github.com/multiformats/go-multiaddr-dns"
|
||||
|
||||
irouting "github.com/ipfs/kubo/routing"
|
||||
|
||||
"github.com/ipfs/go-namesys"
|
||||
"github.com/ipfs/go-namesys/republisher"
|
||||
"github.com/ipfs/kubo/repo"
|
||||
irouting "github.com/ipfs/kubo/routing"
|
||||
)
|
||||
|
||||
const DefaultIpnsCacheSize = 128
|
||||
@ -29,8 +28,8 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator {
|
||||
}
|
||||
|
||||
// Namesys creates new name system
|
||||
func Namesys(cacheSize int) func(rt irouting.TieredRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
|
||||
return func(rt irouting.TieredRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
|
||||
func Namesys(cacheSize int) func(rt irouting.ProvideManyRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
|
||||
return func(rt irouting.ProvideManyRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
|
||||
opts := []namesys.Option{
|
||||
namesys.WithDatastore(repo.Datastore()),
|
||||
namesys.WithDNSResolver(rslv),
|
||||
|
||||
@ -25,7 +25,6 @@ type Libp2pOpts struct {
|
||||
Opts []libp2p.Option `group:"libp2p"`
|
||||
}
|
||||
|
||||
// Misc options
|
||||
var UserAgent = simpleOpt(libp2p.UserAgent(version.GetUserAgentVersion()))
|
||||
|
||||
func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOpts, err error) {
|
||||
|
||||
@ -28,7 +28,7 @@ import (
|
||||
const NetLimitDefaultFilename = "limit.json"
|
||||
const NetLimitTraceFilename = "rcmgr.json.gz"
|
||||
|
||||
var NoResourceMgrError = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled")
|
||||
var ErrNoResourceMgr = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled")
|
||||
|
||||
func ResourceManager(cfg config.SwarmConfig) interface{} {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) {
|
||||
@ -136,7 +136,7 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) {
|
||||
case scope == "all":
|
||||
rapi, ok := mgr.(rcmgr.ResourceManagerState)
|
||||
if !ok { // NullResourceManager
|
||||
return result, NoResourceMgrError
|
||||
return result, ErrNoResourceMgr
|
||||
}
|
||||
|
||||
stat := rapi.Stat()
|
||||
@ -223,7 +223,7 @@ func NetLimit(mgr network.ResourceManager, scope string) (rcmgr.BaseLimit, error
|
||||
getLimit := func(s network.ResourceScope) error {
|
||||
limiter, ok := s.(rcmgr.ResourceScopeLimiter)
|
||||
if !ok { // NullResourceManager
|
||||
return NoResourceMgrError
|
||||
return ErrNoResourceMgr
|
||||
}
|
||||
limit := limiter.Limit()
|
||||
switch l := limit.(type) {
|
||||
@ -271,7 +271,7 @@ func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limi
|
||||
setLimit := func(s network.ResourceScope) error {
|
||||
limiter, ok := s.(rcmgr.ResourceScopeLimiter)
|
||||
if !ok { // NullResourceManager
|
||||
return NoResourceMgrError
|
||||
return ErrNoResourceMgr
|
||||
}
|
||||
|
||||
limiter.SetLimit(&limit)
|
||||
|
||||
@ -155,7 +155,7 @@ func checkImplicitDefaults() {
|
||||
}
|
||||
|
||||
if !ok {
|
||||
log.Errorf("===> OOF! go-libp2p reduced DefaultServiceLimits\n" +
|
||||
log.Errorf("===> OOF! go-libp2p changed DefaultServiceLimits\n" +
|
||||
"=> See the aboce reduced values for info.\n" +
|
||||
"=> go-libp2p SetDefaultServiceLimits update needs a review:\n" +
|
||||
"Please inspect if changes impact go-ipfs users, and update expectedDefaultServiceLimits in rcmgr_defaults.go to remove this message",
|
||||
@ -376,7 +376,7 @@ const expectedDefaultLimits = `{
|
||||
"ConnsInbound": 1,
|
||||
"ConnsOutbound": 1,
|
||||
"FD": 1,
|
||||
"Memory": 1048576
|
||||
"Memory": 33554432
|
||||
},
|
||||
"ConnLimitIncrease": {
|
||||
"Streams": 0,
|
||||
|
||||
@ -32,6 +32,7 @@ type loggingScope struct {
|
||||
}
|
||||
|
||||
var _ network.ResourceManager = (*loggingResourceManager)(nil)
|
||||
var _ rcmgr.ResourceManagerState = (*loggingResourceManager)(nil)
|
||||
|
||||
func (n *loggingResourceManager) start(ctx context.Context) {
|
||||
logInterval := n.logInterval
|
||||
@ -103,6 +104,40 @@ func (n *loggingResourceManager) Close() error {
|
||||
return n.delegate.Close()
|
||||
}
|
||||
|
||||
func (n *loggingResourceManager) ListServices() []string {
|
||||
rapi, ok := n.delegate.(rcmgr.ResourceManagerState)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return rapi.ListServices()
|
||||
}
|
||||
func (n *loggingResourceManager) ListProtocols() []protocol.ID {
|
||||
rapi, ok := n.delegate.(rcmgr.ResourceManagerState)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return rapi.ListProtocols()
|
||||
}
|
||||
func (n *loggingResourceManager) ListPeers() []peer.ID {
|
||||
rapi, ok := n.delegate.(rcmgr.ResourceManagerState)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return rapi.ListPeers()
|
||||
}
|
||||
|
||||
func (n *loggingResourceManager) Stat() rcmgr.ResourceManagerStat {
|
||||
rapi, ok := n.delegate.(rcmgr.ResourceManagerState)
|
||||
if !ok {
|
||||
return rcmgr.ResourceManagerStat{}
|
||||
}
|
||||
|
||||
return rapi.Stat()
|
||||
}
|
||||
|
||||
func (s *loggingScope) ReserveMemory(size int, prio uint8) error {
|
||||
err := s.delegate.ReserveMemory(size, prio)
|
||||
s.countErrs(err)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package libp2p
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/kubo/config"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
@ -74,17 +76,25 @@ func MaybeAutoRelay(staticRelays []string, cfgPeering config.Peering, enabled bo
|
||||
return fx.Options(
|
||||
// Provide AutoRelay option
|
||||
fx.Provide(func() (opts Libp2pOpts, err error) {
|
||||
opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(autorelay.WithPeerSource(func(numPeers int) <-chan peer.AddrInfo {
|
||||
opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(autorelay.WithPeerSource(func(ctx context.Context, numPeers int) <-chan peer.AddrInfo {
|
||||
// TODO(9257): make this code smarter (have a state and actually try to grow the search outward) instead of a long running task just polling our K cluster.
|
||||
r := make(chan peer.AddrInfo, numPeers)
|
||||
r := make(chan peer.AddrInfo)
|
||||
go func() {
|
||||
defer close(r)
|
||||
for ; numPeers != 0; numPeers-- {
|
||||
v, ok := <-peerChan
|
||||
if !ok {
|
||||
select {
|
||||
case v, ok := <-peerChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case r <- v:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
r <- v
|
||||
}
|
||||
}()
|
||||
return r
|
||||
|
||||
@ -129,39 +129,6 @@ func BaseRouting(experimentalDHTClient bool) interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
type delegatedRouterOut struct {
|
||||
fx.Out
|
||||
|
||||
Routers []Router `group:"routers,flatten"`
|
||||
ContentRouter []routing.ContentRouting `group:"content-routers,flatten"`
|
||||
}
|
||||
|
||||
func DelegatedRouting(routers map[string]config.Router) interface{} {
|
||||
return func() (delegatedRouterOut, error) {
|
||||
out := delegatedRouterOut{}
|
||||
|
||||
for _, v := range routers {
|
||||
if !v.Enabled.WithDefault(true) {
|
||||
continue
|
||||
}
|
||||
|
||||
r, err := irouting.RoutingFromConfig(v)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
out.Routers = append(out.Routers, Router{
|
||||
Routing: r,
|
||||
Priority: irouting.GetPriority(v.Parameters),
|
||||
})
|
||||
|
||||
out.ContentRouter = append(out.ContentRouter, r)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
type p2pOnlineContentRoutingIn struct {
|
||||
fx.In
|
||||
|
||||
@ -195,24 +162,23 @@ type p2pOnlineRoutingIn struct {
|
||||
// Routing will get all routers obtained from different methods
|
||||
// (delegated routers, pub-sub, and so on) and add them all together
|
||||
// using a TieredRouter.
|
||||
func Routing(in p2pOnlineRoutingIn) irouting.TieredRouter {
|
||||
func Routing(in p2pOnlineRoutingIn) irouting.ProvideManyRouter {
|
||||
routers := in.Routers
|
||||
|
||||
sort.SliceStable(routers, func(i, j int) bool {
|
||||
return routers[i].Priority < routers[j].Priority
|
||||
})
|
||||
|
||||
irouters := make([]routing.Routing, len(routers))
|
||||
for i, v := range routers {
|
||||
irouters[i] = v.Routing
|
||||
var cRouters []*routinghelpers.ParallelRouter
|
||||
for _, v := range routers {
|
||||
cRouters = append(cRouters, &routinghelpers.ParallelRouter{
|
||||
Timeout: 5 * time.Minute,
|
||||
IgnoreError: true,
|
||||
Router: v.Routing,
|
||||
})
|
||||
}
|
||||
|
||||
return irouting.Tiered{
|
||||
Tiered: routinghelpers.Tiered{
|
||||
Routers: irouters,
|
||||
Validator: in.Validator,
|
||||
},
|
||||
}
|
||||
return routinghelpers.NewComposableParallel(cRouters)
|
||||
}
|
||||
|
||||
// OfflineRouting provides a special Router to the routers list when we are creating a offline node.
|
||||
|
||||
@ -2,7 +2,10 @@ package libp2p
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/kubo/config"
|
||||
irouting "github.com/ipfs/kubo/routing"
|
||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
dual "github.com/libp2p/go-libp2p-kad-dht/dual"
|
||||
record "github.com/libp2p/go-libp2p-record"
|
||||
@ -46,6 +49,36 @@ func constructDHTRouting(mode dht.ModeOpt) func(
|
||||
}
|
||||
}
|
||||
|
||||
func ConstructDelegatedRouting(routers config.Routers, methods config.Methods, peerID string, addrs []string, privKey string) func(
|
||||
ctx context.Context,
|
||||
host host.Host,
|
||||
dstore datastore.Batching,
|
||||
validator record.Validator,
|
||||
bootstrapPeers ...peer.AddrInfo,
|
||||
) (routing.Routing, error) {
|
||||
return func(
|
||||
ctx context.Context,
|
||||
host host.Host,
|
||||
dstore datastore.Batching,
|
||||
validator record.Validator,
|
||||
bootstrapPeers ...peer.AddrInfo,
|
||||
) (routing.Routing, error) {
|
||||
return irouting.Parse(routers, methods,
|
||||
&irouting.ExtraDHTParams{
|
||||
BootstrapPeers: bootstrapPeers,
|
||||
Host: host,
|
||||
Validator: validator,
|
||||
Datastore: dstore,
|
||||
Context: ctx,
|
||||
},
|
||||
&irouting.ExtraReframeParams{
|
||||
PeerID: peerID,
|
||||
Addrs: addrs,
|
||||
PrivKeyB64: privKey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func constructNilRouting(
|
||||
ctx context.Context,
|
||||
host host.Host,
|
||||
|
||||
@ -6,9 +6,10 @@ import (
|
||||
"github.com/ipfs/kubo/config"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/metrics"
|
||||
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||
quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/websocket"
|
||||
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
|
||||
|
||||
"go.uber.org/fx"
|
||||
)
|
||||
@ -21,7 +22,8 @@ func Transports(tptConfig config.Transports) interface{} {
|
||||
privateNetworkEnabled := pnet.Fprint != nil
|
||||
|
||||
if tptConfig.Network.TCP.WithDefault(true) {
|
||||
opts.Opts = append(opts.Opts, libp2p.Transport(tcp.NewTCPTransport))
|
||||
// TODO(9290): Make WithMetrics configurable
|
||||
opts.Opts = append(opts.Opts, libp2p.Transport(tcp.NewTCPTransport, tcp.WithMetrics()))
|
||||
}
|
||||
|
||||
if tptConfig.Network.Websocket.WithDefault(true) {
|
||||
@ -30,14 +32,22 @@ func Transports(tptConfig config.Transports) interface{} {
|
||||
|
||||
if tptConfig.Network.QUIC.WithDefault(!privateNetworkEnabled) {
|
||||
if privateNetworkEnabled {
|
||||
// QUIC was force enabled while the private network was turned on.
|
||||
// Fail and tell the user.
|
||||
return opts, fmt.Errorf(
|
||||
"The QUIC transport does not support private networks. " +
|
||||
"Please disable Swarm.Transports.Network.QUIC.",
|
||||
"QUIC transport does not support private networks, please disable Swarm.Transports.Network.QUIC",
|
||||
)
|
||||
}
|
||||
opts.Opts = append(opts.Opts, libp2p.Transport(libp2pquic.NewTransport))
|
||||
// TODO(9290): Make WithMetrics configurable
|
||||
opts.Opts = append(opts.Opts, libp2p.Transport(quic.NewTransport, quic.WithMetrics()))
|
||||
}
|
||||
|
||||
// TODO(9292): Remove the false && to allows it enabled by default
|
||||
if tptConfig.Network.WebTransport.WithDefault(false && !privateNetworkEnabled) {
|
||||
if privateNetworkEnabled {
|
||||
return opts, fmt.Errorf(
|
||||
"WebTransport transport does not support private networks, please disable Swarm.Transports.Network.WebTransport",
|
||||
)
|
||||
}
|
||||
opts.Opts = append(opts.Opts, libp2p.Transport(webtransport.New))
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
|
||||
@ -28,13 +28,13 @@ func ProviderQueue(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (*q
|
||||
}
|
||||
|
||||
// SimpleProvider creates new record provider
|
||||
func SimpleProvider(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *q.Queue, rt irouting.TieredRouter) provider.Provider {
|
||||
func SimpleProvider(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *q.Queue, rt irouting.ProvideManyRouter) provider.Provider {
|
||||
return simple.NewProvider(helpers.LifecycleCtx(mctx, lc), queue, rt)
|
||||
}
|
||||
|
||||
// SimpleReprovider creates new reprovider
|
||||
func SimpleReprovider(reproviderInterval time.Duration) interface{} {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt irouting.TieredRouter, keyProvider simple.KeyChanFunc) (provider.Reprovider, error) {
|
||||
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt irouting.ProvideManyRouter, keyProvider simple.KeyChanFunc) (provider.Reprovider, error) {
|
||||
return simple.NewReprovider(helpers.LifecycleCtx(mctx, lc), reproviderInterval, rt, keyProvider), nil
|
||||
}
|
||||
}
|
||||
@ -62,12 +62,7 @@ func SimpleProviderSys(isOnline bool) interface{} {
|
||||
|
||||
// BatchedProviderSys creates new provider system
|
||||
func BatchedProviderSys(isOnline bool, reprovideInterval string) interface{} {
|
||||
return func(lc fx.Lifecycle, cr irouting.TieredRouter, q *q.Queue, keyProvider simple.KeyChanFunc, repo repo.Repo) (provider.System, error) {
|
||||
r := cr.ProvideMany()
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("BatchedProviderSys requires a content router that supports provideMany")
|
||||
}
|
||||
|
||||
return func(lc fx.Lifecycle, cr irouting.ProvideManyRouter, q *q.Queue, keyProvider simple.KeyChanFunc, repo repo.Repo) (provider.System, error) {
|
||||
reprovideIntervalDuration := kReprovideFrequency
|
||||
if reprovideInterval != "" {
|
||||
dur, err := time.ParseDuration(reprovideInterval)
|
||||
@ -78,7 +73,7 @@ func BatchedProviderSys(isOnline bool, reprovideInterval string) interface{} {
|
||||
reprovideIntervalDuration = dur
|
||||
}
|
||||
|
||||
sys, err := batched.New(r, q,
|
||||
sys, err := batched.New(cr, q,
|
||||
batched.ReproviderInterval(reprovideIntervalDuration),
|
||||
batched.Datastore(repo.Datastore()),
|
||||
batched.KeyProvider(keyProvider))
|
||||
|
||||
553
docs/changelogs/v0.16.md
Normal file
553
docs/changelogs/v0.16.md
Normal file
@ -0,0 +1,553 @@
|
||||
# Kubo changelog v0.16
|
||||
|
||||
## v0.16.0
|
||||
|
||||
### Overview
|
||||
|
||||
Below is an outline of all that is in this release, so you get a sense of all that's included.
|
||||
|
||||
- [Kubo changelog v0.16](#kubo-changelog-v016)
|
||||
- [v0.16.0](#v0160)
|
||||
- [Overview](#overview)
|
||||
- [🔦 Highlights](#-highlights)
|
||||
- [🛣️ More configurable delegated routing system](#️-more-configurable-delegated-routing-system)
|
||||
- [🌍 WebTransport new experimental Transport](#-webtransport-new-experimental-transport)
|
||||
- [🗃️ Hardened IPNS record verification](#-hardened-ipns-record-verification)
|
||||
- [🌉 Web Gateways now support _redirects files](#-web-gateways-now-support-_redirects-files)
|
||||
- [😻 Add files to MFS with ipfs add --to-files](#-add-files-to-mfs-with-ipfs-add---to-files)
|
||||
- [Changelog](#changelog)
|
||||
- [Contributors](#contributors)
|
||||
|
||||
|
||||
### 🔦 Highlights
|
||||
|
||||
<!-- TODO -->
|
||||
|
||||
#### 🛣️ More configurable delegated routing system
|
||||
|
||||
Since Kubo v0.14.0 [Reframe protocol](https://github.com/ipfs/specs/tree/main/reframe#readme) has been supported as a new routing system.
|
||||
|
||||
Now, we allow to configure several routers working together, so you can have several `reframe` and `dht` routers making queries. You can use the special `parallel` and `sequential` routers to fill your needs.
|
||||
|
||||
Example configuration usage using the [Filecoin Network Indexer](https://docs.cid.contact/filecoin-network-indexer/overview) and the DHT, making first a query to the indexer, and timing out after 3 seconds.
|
||||
|
||||
```console
|
||||
$ ipfs config Routing.Type --json '"custom"'
|
||||
|
||||
$ ipfs config Routing.Routers.CidContact --json '{
|
||||
"Type": "reframe",
|
||||
"Parameters": {
|
||||
"Endpoint": "https://cid.contact/reframe"
|
||||
}
|
||||
}'
|
||||
|
||||
$ ipfs config Routing.Routers.WanDHT --json '{
|
||||
"Type": "dht",
|
||||
"Parameters": {
|
||||
"Mode": "auto",
|
||||
"PublicIPNetwork": true,
|
||||
"AcceleratedDHTClient": false
|
||||
}
|
||||
}'
|
||||
|
||||
$ ipfs config Routing.Routers.ParallelHelper --json '{
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName" : "CidContact",
|
||||
"IgnoreErrors" : true,
|
||||
"Timeout": "3s"
|
||||
},
|
||||
{
|
||||
"RouterName" : "WanDHT",
|
||||
"IgnoreErrors" : false,
|
||||
"Timeout": "5m",
|
||||
"ExecuteAfter": "2s"
|
||||
}
|
||||
]
|
||||
}
|
||||
}'
|
||||
|
||||
$ ipfs config Routing.Methods --json '{
|
||||
"find-peers": {
|
||||
"RouterName": "ParallelHelper"
|
||||
},
|
||||
"find-providers": {
|
||||
"RouterName": "ParallelHelper"
|
||||
},
|
||||
"get-ipns": {
|
||||
"RouterName": "ParallelHelper"
|
||||
},
|
||||
"provide": {
|
||||
"RouterName": "WanDHT"
|
||||
},
|
||||
"put-ipns": {
|
||||
"RouterName": "ParallelHelper"
|
||||
}
|
||||
}'
|
||||
|
||||
```
|
||||
|
||||
### 🌍 WebTransport new experimental Transport
|
||||
|
||||
A new feature of [`go-libp2p`](https://github.com/libp2p/go-libp2p/releases/tag/v0.23.0) is [WebTransport](https://github.com/libp2p/go-libp2p/issues/1717).
|
||||
|
||||
For now it is **disabled by default** and considered **experimental**.
|
||||
If you find issues running it please [report them to us](https://github.com/ipfs/kubo/issues/new).
|
||||
|
||||
In the future Kubo will listen on WebTransport by default for anyone already listening on QUIC addresses.
|
||||
|
||||
WebTransport is a new transport protocol currently under development by the [IETF](https://datatracker.ietf.org/wg/webtrans/about/) and the [W3C](https://www.w3.org/TR/webtransport/), and [already implemented by Chrome](https://caniuse.com/webtransport).
|
||||
Conceptually, it’s like WebSocket run over QUIC instead of TCP. Most importantly, it allows browsers to establish (secure!) connections to WebTransport servers without the need for CA-signed certificates,
|
||||
thereby enabling any js-libp2p node running in a browser to connect to any kubo node, with zero manual configuration involved.
|
||||
|
||||
The previous alternative is websocket secure, which require installing a reverse proxy and TLS certificates manually.
|
||||
|
||||
#### How to enable WebTransport
|
||||
|
||||
Thoses steps are temporary and wont be needed once we make it enabled by default.
|
||||
|
||||
1. Enable the WebTransport transport:
|
||||
`ipfs config Swarm.Transports.Network.WebTransport --json true`
|
||||
1. Add a listener address for WebTransport to your `Addresses.Swarm` key, for example:
|
||||
```json
|
||||
[
|
||||
"/ip4/0.0.0.0/tcp/4001",
|
||||
"/ip4/0.0.0.0/udp/4001/quic",
|
||||
"/ip4/0.0.0.0/udp/4002/quic/webtransport"
|
||||
]
|
||||
```
|
||||
1. Restart your daemon to apply the config changes.
|
||||
|
||||
### 🗃️ Hardened IPNS record verification
|
||||
|
||||
Records that do not have a valid IPNS V2 signature, or exceed the max size
|
||||
limit, will no longer pass verification, and will be ignored by Kubo when
|
||||
resolving `/ipns/{libp2p-key}` content paths.
|
||||
|
||||
Kubo continues publishing backward-compatible V1+V2 records that can be
|
||||
resolved by V1-only (go-ipfs <0.9.0) clients.
|
||||
|
||||
More details can be found in _Backward Compatibility_, _Record Creation_, and
|
||||
_Record Verification_ sections of the [updated IPNS
|
||||
specification](https://github.com/ipfs/specs/pull/319/files).
|
||||
|
||||
### 🌉 Web Gateways now support `_redirects` files
|
||||
|
||||
This feature enables support for redirects, single-page applications (SPA),
|
||||
custom 404 pages, and moving to IPFS-backed website hosting
|
||||
[without breaking existing HTTP links](https://www.w3.org/Provider/Style/URI).
|
||||
|
||||
It is limited to websites hosted in web contexts with unique
|
||||
[Origins](https://en.wikipedia.org/wiki/Same-origin_policy), such as
|
||||
[subdomain](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#subdomain-gateway) and
|
||||
[DNSLink](https://docs.ipfs.tech/how-to/address-ipfs-on-web/#dnslink-gateway) gateways.
|
||||
Redirect logic is evaluated only if the requested path is not in the DAG.
|
||||
|
||||
See more details and usage examples see
|
||||
[docs.ipfs.tech: _Redirects, custom 404s, and SPA support_](https://docs.ipfs.tech/how-to/websites-on-ipfs/redirects-and-custom-404s/).
|
||||
|
||||
### 😻 Add files to MFS with `ipfs add --to-files`
|
||||
|
||||
Users no longer need to call `ipfs files cp` after `ipfs add` to create a
|
||||
reference in [MFS](https://docs.ipfs.tech/concepts/glossary/#mfs), or deal with
|
||||
low level pins if they do not wish to do so. It is now possible to pass MFS
|
||||
path in an optional `--to-files` to add data directly to MFS, without creating
|
||||
a low level pin.
|
||||
|
||||
Before (Kubo <0.16.0):
|
||||
|
||||
|
||||
```console
|
||||
$ ipfs add cat.jpg
|
||||
QmCID
|
||||
$ ipfs files cp /ipfs/QmCID /mfs-cats/cat.jpg
|
||||
$ ipfs pin rm QmCID # removing low level pin, since MFS is protecting from gc
|
||||
```
|
||||
|
||||
Kubo 0.16.0 collapses the above steps into one:
|
||||
|
||||
```console
|
||||
$ ipfs add --pin=false cat.jpg --to-files /mfs-cats/
|
||||
```
|
||||
|
||||
A recursive add to MFS works too (below line will create `/lots-of-cats/` directory in MFS):
|
||||
|
||||
```console
|
||||
$ ipfs add -r ./lots-of-cats/ --to-files /
|
||||
```
|
||||
|
||||
For more information, see `ipfs add --help` and `ipfs files --help`.
|
||||
|
||||
### Changelog
|
||||
|
||||
<details>
|
||||
<summary>Full Changelog</summary>
|
||||
|
||||
- github.com/ipfs/kubo:
|
||||
- fix: Set default Methods value to nil
|
||||
- docs: document remaining 0.16.0 features
|
||||
- docs: add WebTransport docs ([ipfs/kubo#9308](https://github.com/ipfs/kubo/pull/9308))
|
||||
- chore: bump version to 0.16.0-rc1
|
||||
- fix: ensure hasher is registered when using a hashing function
|
||||
- feat: add webtransport as an optin transport ([ipfs/kubo#9293](https://github.com/ipfs/kubo/pull/9293))
|
||||
- feat(gateway): _redirects file support (#8890) ([ipfs/kubo#8890](https://github.com/ipfs/kubo/pull/8890))
|
||||
- docs: fix typo in changelog-v0.16.0.md
|
||||
- Readme: Rewrite introduction and featureset (#9211) ([ipfs/kubo#9211](https://github.com/ipfs/kubo/pull/9211))
|
||||
- feat: Delegated routing with custom configuration. (#9274) ([ipfs/kubo#9274](https://github.com/ipfs/kubo/pull/9274))
|
||||
- Add <protocols> to `ipfs id -h` options (#9229) ([ipfs/kubo#9229](https://github.com/ipfs/kubo/pull/9229))
|
||||
- chore: bump go-libp2p v0.23.1 ([ipfs/kubo#9285](https://github.com/ipfs/kubo/pull/9285))
|
||||
- feat(cmds/add): --to-files option automates files cp (#8927) ([ipfs/kubo#8927](https://github.com/ipfs/kubo/pull/8927))
|
||||
- docs: fix broken ENS DoH example (#9281) ([ipfs/kubo#9281](https://github.com/ipfs/kubo/pull/9281))
|
||||
- ([ipfs/kubo#9258](https://github.com/ipfs/kubo/pull/9258))
|
||||
- ([ipfs/kubo#9213](https://github.com/ipfs/kubo/pull/9213))
|
||||
- docs: small typo in Dockerfile
|
||||
- feat: ipfs-webui v2.18.1
|
||||
- feat: ipfs-webui v2.18.0 (#9262) ([ipfs/kubo#9262](https://github.com/ipfs/kubo/pull/9262))
|
||||
- bump go-libp2p v0.22.0 & go1.18&go1.19 ([ipfs/kubo#9244](https://github.com/ipfs/kubo/pull/9244))
|
||||
- docs: change windows choco install command to point to go-ipfs
|
||||
- fix: pass the repo directory into the ignored_commit function
|
||||
- docs(cmds): daemon: update DHTClient description
|
||||
- fix(gw): send 200 for empty files
|
||||
- docs(readme): official vs unofficial packages
|
||||
- chore: remove Gateway.PathPrefixes
|
||||
- docs(readme): update Docker section
|
||||
- docs: fix markdown syntax typo in v0.15's changelog
|
||||
- chore: Release v0.15.0 ([ipfs/kubo#9236](https://github.com/ipfs/kubo/pull/9236))
|
||||
- chore: fix undiallable api and gateway files ([ipfs/kubo#9233](https://github.com/ipfs/kubo/pull/9233))
|
||||
- chore: Bump version to 0.16.0-dev
|
||||
- github.com/ipfs/go-bitswap (v0.9.0 -> v0.10.2):
|
||||
- chore: release v0.10.2
|
||||
- fix: create a copy of the protocol slice in network.processSettings
|
||||
- chore: release v0.10.1
|
||||
- fix: incorrect type in the WithTracer polyfill option
|
||||
- chore: fix incorrect log message when a bad option is passed
|
||||
- chore: release v0.10.0
|
||||
- chore: update go-libp2p v0.22.0
|
||||
- github.com/ipfs/go-cid (v0.2.0 -> v0.3.2):
|
||||
- chore: release v0.3.2
|
||||
- Revert "fix: bring back, but deprecate CodecToStr and Codecs"
|
||||
- chore: release v0.2.1
|
||||
- fix: bring back, but deprecate CodecToStr and Codecs
|
||||
- run gofmt -s
|
||||
- bump go.mod to Go 1.18 and run go fix
|
||||
- chore: release v0.3.0
|
||||
- fix: return nil Bytes() if the Cid in undef
|
||||
- Add MustParse ([ipfs/go-cid#139](https://github.com/ipfs/go-cid/pull/139))
|
||||
- github.com/ipfs/go-datastore (v0.5.1 -> v0.6.0):
|
||||
- Release v0.6.0 (#194) ([ipfs/go-datastore#194](https://github.com/ipfs/go-datastore/pull/194))
|
||||
- feat: add Features + datastore scoping
|
||||
- chore: Fix comment typo (#191) ([ipfs/go-datastore#191](https://github.com/ipfs/go-datastore/pull/191))
|
||||
- github.com/ipfs/go-delegated-routing (v0.3.0 -> v0.6.0):
|
||||
- ([ipfs/go-delegated-routing#53](https://github.com/ipfs/go-delegated-routing/pull/53))
|
||||
- ([ipfs/go-delegated-routing#52](https://github.com/ipfs/go-delegated-routing/pull/52))
|
||||
- Release v0.5.2 (#50) ([ipfs/go-delegated-routing#50](https://github.com/ipfs/go-delegated-routing/pull/50))
|
||||
- Fixed serialisation issue with multiadds (#49) ([ipfs/go-delegated-routing#49](https://github.com/ipfs/go-delegated-routing/pull/49))
|
||||
- Upgrade to IPLD `0.18.0`
|
||||
- Release v0.5.0 (#47) ([ipfs/go-delegated-routing#47](https://github.com/ipfs/go-delegated-routing/pull/47))
|
||||
- feat: use GET for FindProviders (#46) ([ipfs/go-delegated-routing#46](https://github.com/ipfs/go-delegated-routing/pull/46))
|
||||
- Update provide to take an array of keys, per spec (#45) ([ipfs/go-delegated-routing#45](https://github.com/ipfs/go-delegated-routing/pull/45))
|
||||
- ([ipfs/go-delegated-routing#44](https://github.com/ipfs/go-delegated-routing/pull/44))
|
||||
- fix: upgrade edelweiss and rerun 'go generate' (#42) ([ipfs/go-delegated-routing#42](https://github.com/ipfs/go-delegated-routing/pull/42))
|
||||
- ci: add check to ensure generated files are up-to-date (#41) ([ipfs/go-delegated-routing#41](https://github.com/ipfs/go-delegated-routing/pull/41))
|
||||
- Add Provide RPC (#37) ([ipfs/go-delegated-routing#37](https://github.com/ipfs/go-delegated-routing/pull/37))
|
||||
- upgrade to go-log/v2 (#34) ([ipfs/go-delegated-routing#34](https://github.com/ipfs/go-delegated-routing/pull/34))
|
||||
- github.com/ipfs/go-ipns (v0.1.2 -> v0.3.0):
|
||||
- fix: require V2 signatures ([ipfs/go-ipns#41](https://github.com/ipfs/go-ipns/pull/41))
|
||||
- update go-libp2p to v0.22.0, release v0.2.0 (#39) ([ipfs/go-ipns#39](https://github.com/ipfs/go-ipns/pull/39))
|
||||
- use peer.IDFromBytes instead of peer.IDFromString (#38) ([ipfs/go-ipns#38](https://github.com/ipfs/go-ipns/pull/38))
|
||||
- sync: update CI config files (#34) ([ipfs/go-ipns#34](https://github.com/ipfs/go-ipns/pull/34))
|
||||
- github.com/ipfs/go-pinning-service-http-client (v0.1.1 -> v0.1.2):
|
||||
- chore: release v0.1.2
|
||||
- fix: send up to nanosecond precision
|
||||
- refactor: cleanup Sprintf for Bearer token
|
||||
- sync: update CI config files ([ipfs/go-pinning-service-http-client#21](https://github.com/ipfs/go-pinning-service-http-client/pull/21))
|
||||
- github.com/ipld/edelweiss (v0.1.4 -> v0.2.0):
|
||||
- Release v0.2.0 (#60) ([ipld/edelweiss#60](https://github.com/ipld/edelweiss/pull/60))
|
||||
- feat: add cachable modifier to methods (#48) ([ipld/edelweiss#48](https://github.com/ipld/edelweiss/pull/48))
|
||||
- adding licenses (#52) ([ipld/edelweiss#52](https://github.com/ipld/edelweiss/pull/52))
|
||||
- sync: update CI config files ([ipld/edelweiss#56](https://github.com/ipld/edelweiss/pull/56))
|
||||
- chore: replace deprecated ioutil with io/os ([ipld/edelweiss#59](https://github.com/ipld/edelweiss/pull/59))
|
||||
- Release v0.1.6
|
||||
- fix: iterate over BlueMap in deterministic order (#57) ([ipld/edelweiss#57](https://github.com/ipld/edelweiss/pull/57))
|
||||
- fix: wrap DAG-JSON serialization error (#55) ([ipld/edelweiss#55](https://github.com/ipld/edelweiss/pull/55))
|
||||
- update examples and harness
|
||||
- upgrade to go-log/v2 (#53) ([ipld/edelweiss#53](https://github.com/ipld/edelweiss/pull/53))
|
||||
- github.com/ipld/go-ipld-prime (v0.17.0 -> v0.18.0):
|
||||
- Prepare v0.18.0
|
||||
- feat(bindnode): add a BindnodeRegistry utility (#437) ([ipld/go-ipld-prime#437](https://github.com/ipld/go-ipld-prime/pull/437))
|
||||
- feat(bindnode): support full uint64 range
|
||||
- chore(bindnode): remove typed functions for options
|
||||
- chore(bindnode): docs and minor tweaks
|
||||
- feat(bindnode): make Any converters work for List and Map values
|
||||
- fix(bindnode): shorten converter option names, minor perf improvements
|
||||
- fix(bindnode): only custom convert AssignNull for Any converter
|
||||
- feat(bindnode): pass Null on to nullable custom converters
|
||||
- chore(bindnode): config helper refactor w/ short-circuit
|
||||
- feat(bindnode): add AddCustomTypeAnyConverter() to handle `Any` fields
|
||||
- feat(bindnode): add AddCustomTypeXConverter() options for most scalar kinds
|
||||
- chore(bindnode): back out of reflection for converters
|
||||
- feat(bindnode): switch to converter functions instead of type
|
||||
- feat(bindnode): allow custom type conversions with options
|
||||
- feat: add release checklist (#442) ([ipld/go-ipld-prime#442](https://github.com/ipld/go-ipld-prime/pull/442))
|
||||
- github.com/libp2p/go-flow-metrics (v0.0.3 -> v0.1.0):
|
||||
- introduce an API to set a mock clock (#20) ([libp2p/go-flow-metrics#20](https://github.com/libp2p/go-flow-metrics/pull/20))
|
||||
- chore: skip slow tests when short testing is specified ([libp2p/go-flow-metrics#16](https://github.com/libp2p/go-flow-metrics/pull/16))
|
||||
- github.com/libp2p/go-libp2p (v0.21.0 -> v0.23.2):
|
||||
- release v0.23.2 (#1781) ([libp2p/go-libp2p#1781](https://github.com/libp2p/go-libp2p/pull/1781))
|
||||
- webtransport: return error before wrapping opened / accepted streams (#1775) ([libp2p/go-libp2p#1775](https://github.com/libp2p/go-libp2p/pull/1775))
|
||||
- release v0.23.1 (#1773) ([libp2p/go-libp2p#1773](https://github.com/libp2p/go-libp2p/pull/1773))
|
||||
- websocket: fix nil pointer in tlsClientConf (#1770) ([libp2p/go-libp2p#1770](https://github.com/libp2p/go-libp2p/pull/1770))
|
||||
- release v0.23.0 (#1764) ([libp2p/go-libp2p#1764](https://github.com/libp2p/go-libp2p/pull/1764))
|
||||
- noise: switch to proto2, use the new NoiseExtensions protobuf ([libp2p/go-libp2p#1762](https://github.com/libp2p/go-libp2p/pull/1762))
|
||||
- webtransport: add custom resolver to add SNI (#1761) ([libp2p/go-libp2p#1761](https://github.com/libp2p/go-libp2p/pull/1761))
|
||||
- swarm: skip dialing WebTransport addresses when we have QUIC addresses (#1756) ([libp2p/go-libp2p#1756](https://github.com/libp2p/go-libp2p/pull/1756))
|
||||
- webtransport: have the server send the certificates (#1757) ([libp2p/go-libp2p#1757](https://github.com/libp2p/go-libp2p/pull/1757))
|
||||
- noise: make it possible for the server to send early data (#1750) ([libp2p/go-libp2p#1750](https://github.com/libp2p/go-libp2p/pull/1750))
|
||||
- swarm: fix selection of transport for dialing (#1653) ([libp2p/go-libp2p#1653](https://github.com/libp2p/go-libp2p/pull/1653))
|
||||
- autorelay: Add a context.Context to WithPeerSource callback (#1736) ([libp2p/go-libp2p#1736](https://github.com/libp2p/go-libp2p/pull/1736))
|
||||
- webtransport: add and check the ?type=noise URL parameter (#1749) ([libp2p/go-libp2p#1749](https://github.com/libp2p/go-libp2p/pull/1749))
|
||||
- webtransport: disable HTTP origin check (#1752) ([libp2p/go-libp2p#1752](https://github.com/libp2p/go-libp2p/pull/1752))
|
||||
- noise: don't fail handshake when early data is received without handler (#1746) ([libp2p/go-libp2p#1746](https://github.com/libp2p/go-libp2p/pull/1746))
|
||||
- Add Resolver interface to transport (#1719) ([libp2p/go-libp2p#1719](https://github.com/libp2p/go-libp2p/pull/1719))
|
||||
- use new /libp2p/go-libp2p/core pkg (#1745) ([libp2p/go-libp2p#1745](https://github.com/libp2p/go-libp2p/pull/1745))
|
||||
- yamux: pass constructors for peer resource scopes to session constructor (#1739) ([libp2p/go-libp2p#1739](https://github.com/libp2p/go-libp2p/pull/1739))
|
||||
- tcp: add an option to enable metrics (disabled by default) (#1734) ([libp2p/go-libp2p#1734](https://github.com/libp2p/go-libp2p/pull/1734))
|
||||
- move go-libp2p-webtransport to p2p/transport/webtransport ([libp2p/go-libp2p#1737](https://github.com/libp2p/go-libp2p/pull/1737))
|
||||
- autorelay: fix race condition in TestBackoff (#1731) ([libp2p/go-libp2p#1731](https://github.com/libp2p/go-libp2p/pull/1731))
|
||||
- rcmgr: increase default connection memory limit to 32 MB (#1740) ([libp2p/go-libp2p#1740](https://github.com/libp2p/go-libp2p/pull/1740))
|
||||
- quic: update quic-go to v0.29.0 (#1723) ([libp2p/go-libp2p#1723](https://github.com/libp2p/go-libp2p/pull/1723))
|
||||
- noise: implement an API to send and receive early data ([libp2p/go-libp2p#1728](https://github.com/libp2p/go-libp2p/pull/1728))
|
||||
- identify: make the protocol version configurable (#1724) ([libp2p/go-libp2p#1724](https://github.com/libp2p/go-libp2p/pull/1724))
|
||||
- Fix threshold calculation (#1722) ([libp2p/go-libp2p#1722](https://github.com/libp2p/go-libp2p/pull/1722))
|
||||
- connmgr: use clock interface (#1720) ([libp2p/go-libp2p#1720](https://github.com/libp2p/go-libp2p/pull/1720))
|
||||
- quic: increase the buffer size used for encoding qlogs (#1715) ([libp2p/go-libp2p#1715](https://github.com/libp2p/go-libp2p/pull/1715))
|
||||
- quic: add a WithMetrics option (#1716) ([libp2p/go-libp2p#1716](https://github.com/libp2p/go-libp2p/pull/1716))
|
||||
- add default listen addresses for QUIC (#1615) ([libp2p/go-libp2p#1615](https://github.com/libp2p/go-libp2p/pull/1615))
|
||||
- feat: inject DNS resolver (#1607) ([libp2p/go-libp2p#1607](https://github.com/libp2p/go-libp2p/pull/1607))
|
||||
- connmgr: prefer peers with no streams when closing connections (#1675) ([libp2p/go-libp2p#1675](https://github.com/libp2p/go-libp2p/pull/1675))
|
||||
- quic: add DisableReuseport option (#1476) ([libp2p/go-libp2p#1476](https://github.com/libp2p/go-libp2p/pull/1476))
|
||||
- release v0.22.0 ([libp2p/go-libp2p#1688](https://github.com/libp2p/go-libp2p/pull/1688))
|
||||
- fix: don't prefer local ports from other addresses when dialing (#1673) ([libp2p/go-libp2p#1673](https://github.com/libp2p/go-libp2p/pull/1673))
|
||||
- crypto: add better support for alternative backends (#1686) ([libp2p/go-libp2p#1686](https://github.com/libp2p/go-libp2p/pull/1686))
|
||||
- crypto/secp256k1: Remove btcsuite intermediary. (#1689) ([libp2p/go-libp2p#1689](https://github.com/libp2p/go-libp2p/pull/1689))
|
||||
- Update resource manager README (#1684) ([libp2p/go-libp2p#1684](https://github.com/libp2p/go-libp2p/pull/1684))
|
||||
- move go-libp2p-core here ([libp2p/go-libp2p#1683](https://github.com/libp2p/go-libp2p/pull/1683))
|
||||
- rcmgr: make scaling changes more intuitive (#1685) ([libp2p/go-libp2p#1685](https://github.com/libp2p/go-libp2p/pull/1685))
|
||||
- move go-eventbus here ([libp2p/go-libp2p#1681](https://github.com/libp2p/go-libp2p/pull/1681))
|
||||
- basichost: remove usage of MultistreamServerMatcher in test (#1680) ([libp2p/go-libp2p#1680](https://github.com/libp2p/go-libp2p/pull/1680))
|
||||
- sync: update CI config files (#1678) ([libp2p/go-libp2p#1678](https://github.com/libp2p/go-libp2p/pull/1678))
|
||||
- move go-libp2p-resource-manager to p2p/host/resource-manager ([libp2p/go-libp2p#1677](https://github.com/libp2p/go-libp2p/pull/1677))
|
||||
- chore: preallocate slices with known final size (#1679) ([libp2p/go-libp2p#1679](https://github.com/libp2p/go-libp2p/pull/1679))
|
||||
- autorelay: fix flaky TestMaxAge (#1676) ([libp2p/go-libp2p#1676](https://github.com/libp2p/go-libp2p/pull/1676))
|
||||
- move go-libp2p-peerstore to p2p/host/peerstore ([libp2p/go-libp2p#1667](https://github.com/libp2p/go-libp2p/pull/1667))
|
||||
- examples: remove ipfs components from echo (#1672) ([libp2p/go-libp2p#1672](https://github.com/libp2p/go-libp2p/pull/1672))
|
||||
- chore: update libp2p to v0.21 in examples (#1674) ([libp2p/go-libp2p#1674](https://github.com/libp2p/go-libp2p/pull/1674))
|
||||
- change the default key type to Ed25519 (#1576) ([libp2p/go-libp2p#1576](https://github.com/libp2p/go-libp2p/pull/1576))
|
||||
- autorelay: poll for new candidates when needed ([libp2p/go-libp2p#1587](https://github.com/libp2p/go-libp2p/pull/1587))
|
||||
- examples: fix unresponsive pubsub chat example (#1652) ([libp2p/go-libp2p#1652](https://github.com/libp2p/go-libp2p/pull/1652))
|
||||
- routed: respect force direct dial context (#1665) ([libp2p/go-libp2p#1665](https://github.com/libp2p/go-libp2p/pull/1665))
|
||||
- pstoremanager: fix flaky TestClose (#1649) ([libp2p/go-libp2p#1649](https://github.com/libp2p/go-libp2p/pull/1649))
|
||||
- Allow adding prologue to noise connections (#1663) ([libp2p/go-libp2p#1663](https://github.com/libp2p/go-libp2p/pull/1663))
|
||||
- connmgr: add nowatchdog go build tag (#1666) ([libp2p/go-libp2p#1666](https://github.com/libp2p/go-libp2p/pull/1666))
|
||||
- mdns: don't discover ourselves (#1661) ([libp2p/go-libp2p#1661](https://github.com/libp2p/go-libp2p/pull/1661))
|
||||
- Support generating custom x509 certificates (#1481) ([libp2p/go-libp2p#1481](https://github.com/libp2p/go-libp2p/pull/1481))
|
||||
- github.com/libp2p/go-libp2p-core (v0.19.1 -> v0.20.1):
|
||||
- chore: release v0.20.1
|
||||
- feat: forward crypto/pb
|
||||
- release v0.20.0
|
||||
- deprecate this repo
|
||||
- stop using the deprecated io/ioutil package (#279) ([libp2p/go-libp2p-core#279](https://github.com/libp2p/go-libp2p-core/pull/279))
|
||||
- use a mock clock in bandwidth tests (#276) ([libp2p/go-libp2p-core#276](https://github.com/libp2p/go-libp2p-core/pull/276))
|
||||
- remove unused MultistreamSemverMatcher (#277) ([libp2p/go-libp2p-core#277](https://github.com/libp2p/go-libp2p-core/pull/277))
|
||||
- remove peer.IDFromString (#274) ([libp2p/go-libp2p-core#274](https://github.com/libp2p/go-libp2p-core/pull/274))
|
||||
- deprecate peer.Encode in favor of peer.ID.String (#275) ([libp2p/go-libp2p-core#275](https://github.com/libp2p/go-libp2p-core/pull/275))
|
||||
- deprecate peer.ID.Pretty (#273) ([libp2p/go-libp2p-core#273](https://github.com/libp2p/go-libp2p-core/pull/273))
|
||||
- github.com/libp2p/go-libp2p-kad-dht (v0.17.0 -> v0.18.0):
|
||||
- update go-libp2p to v0.22.0, release v0.18.0 ([libp2p/go-libp2p-kad-dht#788](https://github.com/libp2p/go-libp2p-kad-dht/pull/788))
|
||||
- sync: update CI config files (#789) ([libp2p/go-libp2p-kad-dht#789](https://github.com/libp2p/go-libp2p-kad-dht/pull/789))
|
||||
- github.com/libp2p/go-libp2p-peerstore (v0.7.1 -> v0.8.0):
|
||||
- release v0.8.0
|
||||
- deprecate this repo
|
||||
- fix flaky TestGCDelay (#206) ([libp2p/go-libp2p-peerstore#206](https://github.com/libp2p/go-libp2p-peerstore/pull/206))
|
||||
- fix flaky EWMA test (#205) ([libp2p/go-libp2p-peerstore#205](https://github.com/libp2p/go-libp2p-peerstore/pull/205))
|
||||
- github.com/libp2p/go-libp2p-record (v0.1.3 -> v0.2.0):
|
||||
- update go-libp2p to v0.22.0, release v0.2.0 ([libp2p/go-libp2p-record#50](https://github.com/libp2p/go-libp2p-record/pull/50))
|
||||
- sync: update CI config files (#47) ([libp2p/go-libp2p-record#47](https://github.com/libp2p/go-libp2p-record/pull/47))
|
||||
- increase RSA key sizes in tests ([libp2p/go-libp2p-record#44](https://github.com/libp2p/go-libp2p-record/pull/44))
|
||||
- cleanup: fix staticcheck failures ([libp2p/go-libp2p-record#43](https://github.com/libp2p/go-libp2p-record/pull/43))
|
||||
- github.com/libp2p/go-libp2p-routing-helpers (v0.2.3 -> v0.4.0):
|
||||
- ([libp2p/go-libp2p-routing-helpers#62](https://github.com/libp2p/go-libp2p-routing-helpers/pull/62))
|
||||
- ([libp2p/go-libp2p-routing-helpers#58](https://github.com/libp2p/go-libp2p-routing-helpers/pull/58))
|
||||
- Update version.json ([libp2p/go-libp2p-routing-helpers#60](https://github.com/libp2p/go-libp2p-routing-helpers/pull/60))
|
||||
- update go-libp2p to v0.22.0 ([libp2p/go-libp2p-routing-helpers#59](https://github.com/libp2p/go-libp2p-routing-helpers/pull/59))
|
||||
- sync: update CI config files (#53) ([libp2p/go-libp2p-routing-helpers#53](https://github.com/libp2p/go-libp2p-routing-helpers/pull/53))
|
||||
- fix staticcheck ([libp2p/go-libp2p-routing-helpers#49](https://github.com/libp2p/go-libp2p-routing-helpers/pull/49))
|
||||
- fix error handling in Parallel.search ([libp2p/go-libp2p-routing-helpers#48](https://github.com/libp2p/go-libp2p-routing-helpers/pull/48))
|
||||
- github.com/libp2p/go-libp2p-testing (v0.11.0 -> v0.12.0):
|
||||
- release v0.12.0 (#67) ([libp2p/go-libp2p-testing#67](https://github.com/libp2p/go-libp2p-testing/pull/67))
|
||||
- chore: update to go-libp2p v0.22.0 (#66) ([libp2p/go-libp2p-testing#66](https://github.com/libp2p/go-libp2p-testing/pull/66))
|
||||
- remove the resource manager mocks (#65) ([libp2p/go-libp2p-testing#65](https://github.com/libp2p/go-libp2p-testing/pull/65))
|
||||
- github.com/libp2p/go-openssl (v0.0.7 -> v0.1.0):
|
||||
- release v0.1.0 (#31) ([libp2p/go-openssl#31](https://github.com/libp2p/go-openssl/pull/31))
|
||||
- Fix build with OpenSSL 3.0 (#25) ([libp2p/go-openssl#25](https://github.com/libp2p/go-openssl/pull/25))
|
||||
- sync: update CI config files ([libp2p/go-openssl#24](https://github.com/libp2p/go-openssl/pull/24))
|
||||
- Add openssl.DialTimeout(network, addr, timeout, ctx, flags) call ([libp2p/go-openssl#26](https://github.com/libp2p/go-openssl/pull/26))
|
||||
- Add Ctx.SetMinProtoVersion and Ctx.SetMaxProtoVersion wrappers ([libp2p/go-openssl#27](https://github.com/libp2p/go-openssl/pull/27))
|
||||
- sync: update CI config files ([libp2p/go-openssl#17](https://github.com/libp2p/go-openssl/pull/17))
|
||||
- fix: unsafe pointer passing ([libp2p/go-openssl#18](https://github.com/libp2p/go-openssl/pull/18))
|
||||
- Update test RSA cert ([libp2p/go-openssl#15](https://github.com/libp2p/go-openssl/pull/15))
|
||||
- Fix tests ([libp2p/go-openssl#16](https://github.com/libp2p/go-openssl/pull/16))
|
||||
- Address `staticcheck` issues ([libp2p/go-openssl#14](https://github.com/libp2p/go-openssl/pull/14))
|
||||
- Enabled PEM files with CRLF line endings to be used (#10) ([libp2p/go-openssl#11](https://github.com/libp2p/go-openssl/pull/11))
|
||||
- github.com/libp2p/zeroconf/v2 (v2.1.1 -> v2.2.0):
|
||||
- Fix windows libp2p (#29) ([libp2p/zeroconf#29](https://github.com/libp2p/zeroconf/pull/29))
|
||||
- Fix compatibility with some IoT devices using avahi 0.8-rc1 (#27) ([libp2p/zeroconf#27](https://github.com/libp2p/zeroconf/pull/27))
|
||||
- Add TTL server option (#23) ([libp2p/zeroconf#23](https://github.com/libp2p/zeroconf/pull/23))
|
||||
- github.com/lucas-clemente/quic-go (v0.28.0 -> v0.29.1):
|
||||
- http3: fix double close of chan when using DontCloseRequestStream
|
||||
- add a logging.NullTracer and logging.NullConnectionTracer ([lucas-clemente/quic-go#3512](https://github.com/lucas-clemente/quic-go/pull/3512))
|
||||
- add support for providing a custom Connection ID generator via Config (#3452) ([lucas-clemente/quic-go#3452](https://github.com/lucas-clemente/quic-go/pull/3452))
|
||||
- fix typo in README
|
||||
- fix datagram support detection (#3511) ([lucas-clemente/quic-go#3511](https://github.com/lucas-clemente/quic-go/pull/3511))
|
||||
- use a single Go routine to send copies of CONNECTION_CLOSE packets ([lucas-clemente/quic-go#3514](https://github.com/lucas-clemente/quic-go/pull/3514))
|
||||
- add YoMo to list of projects in README (#3513) ([lucas-clemente/quic-go#3513](https://github.com/lucas-clemente/quic-go/pull/3513))
|
||||
- http3: fix listening on both QUIC and TCP (#3465) ([lucas-clemente/quic-go#3465](https://github.com/lucas-clemente/quic-go/pull/3465))
|
||||
- Disable anti-amplification limit by address validation token (#3326) ([lucas-clemente/quic-go#3326](https://github.com/lucas-clemente/quic-go/pull/3326))
|
||||
- fix typo in README
|
||||
- implement a new API to let servers control client address verification ([lucas-clemente/quic-go#3501](https://github.com/lucas-clemente/quic-go/pull/3501))
|
||||
- use a generic streams map for incoming streams ([lucas-clemente/quic-go#3489](https://github.com/lucas-clemente/quic-go/pull/3489))
|
||||
- fix unreachable code after log.Fatal in fuzzing corpus generator (#3496) ([lucas-clemente/quic-go#3496](https://github.com/lucas-clemente/quic-go/pull/3496))
|
||||
- use generic Min and Max functions ([lucas-clemente/quic-go#3483](https://github.com/lucas-clemente/quic-go/pull/3483))
|
||||
- add QPACK (RFC 9204) to the list of supported RFCs (#3485) ([lucas-clemente/quic-go#3485](https://github.com/lucas-clemente/quic-go/pull/3485))
|
||||
- add a function to distinguish between long and short header packets (#3498) ([lucas-clemente/quic-go#3498](https://github.com/lucas-clemente/quic-go/pull/3498))
|
||||
- use a generic streams map for outgoing streams (#3488) ([lucas-clemente/quic-go#3488](https://github.com/lucas-clemente/quic-go/pull/3488))
|
||||
- update golangci-lint action to v3, golangci-lint to v1.48.0 (#3499) ([lucas-clemente/quic-go#3499](https://github.com/lucas-clemente/quic-go/pull/3499))
|
||||
- use a generic linked list (#3487) ([lucas-clemente/quic-go#3487](https://github.com/lucas-clemente/quic-go/pull/3487))
|
||||
- drop support for Go 1.16 and 1.17 (#3482) ([lucas-clemente/quic-go#3482](https://github.com/lucas-clemente/quic-go/pull/3482))
|
||||
- optimize FirstOutstanding in the sent packet history (#3467) ([lucas-clemente/quic-go#3467](https://github.com/lucas-clemente/quic-go/pull/3467))
|
||||
- update supported RFCs in README (#3456) ([lucas-clemente/quic-go#3456](https://github.com/lucas-clemente/quic-go/pull/3456))
|
||||
- http3: ignore context after response when using DontCloseRequestStream (#3473) ([lucas-clemente/quic-go#3473](https://github.com/lucas-clemente/quic-go/pull/3473))
|
||||
- github.com/marten-seemann/webtransport-go (null -> v0.1.1):
|
||||
- release v0.1.1 (#31) ([marten-seemann/webtransport-go#31](https://github.com/marten-seemann/webtransport-go/pull/31))
|
||||
- fix double close of chan when using DontCloseRequestStream
|
||||
- github.com/multiformats/go-base32 (v0.0.4 -> v0.1.0):
|
||||
- chore: bump version to 0.1.0
|
||||
- fix: fix staticcheck complaints
|
||||
- run gofmt -s
|
||||
- sync: update CI config files (#5) ([multiformats/go-base32#5](https://github.com/multiformats/go-base32/pull/5))
|
||||
- github.com/multiformats/go-multiaddr (v0.6.0 -> v0.7.0):
|
||||
- Release v0.7.0 ([multiformats/go-multiaddr#183](https://github.com/multiformats/go-multiaddr/pull/183))
|
||||
- use decimal numbers for multicodecs ([multiformats/go-multiaddr#184](https://github.com/multiformats/go-multiaddr/pull/184))
|
||||
- Fix comment on Decapsulate ([multiformats/go-multiaddr#181](https://github.com/multiformats/go-multiaddr/pull/181))
|
||||
- ([multiformats/go-multiaddr#182](https://github.com/multiformats/go-multiaddr/pull/182))
|
||||
- sync: update CI config files (#180) ([multiformats/go-multiaddr#180](https://github.com/multiformats/go-multiaddr/pull/180))
|
||||
- Add webrtc (#179) ([multiformats/go-multiaddr#179](https://github.com/multiformats/go-multiaddr/pull/179))
|
||||
- github.com/multiformats/go-multicodec (v0.5.0 -> v0.6.0):
|
||||
- chore: version bump 0.6.0
|
||||
- fix: replace io/ioutil with io
|
||||
- bump go.mod to Go 1.18 and run go fix
|
||||
|
||||
</details>
|
||||
|
||||
### Contributors
|
||||
|
||||
| Contributor | Commits | Lines ± | Files Changed |
|
||||
|-------------|---------|---------|---------------|
|
||||
| Marten Seemann | 236 | +12637/-24326 | 1152 |
|
||||
| Raúl Kripalani | 118 | +11626/-4136 | 422 |
|
||||
| vyzo | 144 | +10129/-3665 | 230 |
|
||||
| galargh | 9 | +5293/-5298 | 26 |
|
||||
| Marco Munizaga | 83 | +7502/-3080 | 147 |
|
||||
| Antonio Navarro Perez | 33 | +4074/-1240 | 78 |
|
||||
| Steven Allen | 98 | +1974/-1693 | 202 |
|
||||
| Cole Brown | 57 | +2169/-1338 | 95 |
|
||||
| Rod Vagg | 21 | +2588/-768 | 56 |
|
||||
| Gus Eggert | 16 | +2011/-1226 | 36 |
|
||||
| Yusef Napora | 6 | +2738/-187 | 43 |
|
||||
| Raúl Kripalani | 2 | +1000/-889 | 18 |
|
||||
| Łukasz Magiera | 26 | +1312/-500 | 54 |
|
||||
| Will | 2 | +1593/-200 | 18 |
|
||||
| Jorropo | 31 | +924/-712 | 204 |
|
||||
| Juan Batiz-Benet | 2 | +1531/-9 | 21 |
|
||||
| Jeromy | 14 | +691/-468 | 51 |
|
||||
| Petar Maymounkov | 4 | +469/-285 | 25 |
|
||||
| Jeromy Johnson | 24 | +474/-204 | 116 |
|
||||
| Justin Johnson | 1 | +582/-93 | 7 |
|
||||
| Aarsh Shah | 24 | +377/-105 | 34 |
|
||||
| web3-bot | 18 | +246/-228 | 93 |
|
||||
| Masih H. Derkani | 2 | +197/-213 | 21 |
|
||||
| Marcin Rataj | 9 | +211/-176 | 16 |
|
||||
| adam | 4 | +235/-49 | 9 |
|
||||
| Jakub Sztandera | 9 | +203/-73 | 13 |
|
||||
| Guilhem Fanton | 1 | +216/-48 | 5 |
|
||||
| Lucas Molas | 1 | +219/-9 | 3 |
|
||||
| Peter Argue | 1 | +166/-36 | 3 |
|
||||
| Vibhav Pant | 4 | +186/-12 | 7 |
|
||||
| Adrian Lanzafame | 3 | +180/-16 | 5 |
|
||||
| Lars Gierth | 5 | +151/-41 | 25 |
|
||||
| João Oliveirinha | 1 | +124/-38 | 11 |
|
||||
| dignifiedquire | 3 | +122/-33 | 6 |
|
||||
| Chinmay Kousik | 2 | +128/-4 | 7 |
|
||||
| Toby | 1 | +89/-36 | 4 |
|
||||
| Oleg Jukovec | 3 | +111/-14 | 8 |
|
||||
| Whyrusleeping | 2 | +120/-0 | 6 |
|
||||
| KevinZønda | 1 | +81/-20 | 2 |
|
||||
| wzp | 2 | +86/-3 | 2 |
|
||||
| Benedikt Spies | 1 | +75/-12 | 8 |
|
||||
| nisainan | 1 | +33/-43 | 12 |
|
||||
| Tshaka Eric Lekholoane | 1 | +57/-19 | 6 |
|
||||
| cpuchip | 1 | +65/-6 | 2 |
|
||||
| Roman Proskuryakov | 2 | +69/-0 | 2 |
|
||||
| Arceliar | 2 | +36/-28 | 2 |
|
||||
| Maxim Merzhanov | 1 | +29/-24 | 1 |
|
||||
| Richard Ramos | 1 | +51/-0 | 2 |
|
||||
| Dave Collins | 1 | +25/-25 | 4 |
|
||||
| Leo Balduf | 2 | +37/-10 | 3 |
|
||||
| David Aronchick | 1 | +42/-0 | 3 |
|
||||
| Didrik Nordström | 1 | +35/-6 | 1 |
|
||||
| Vasco Santos | 1 | +20/-20 | 7 |
|
||||
| Jesse Bouwman | 1 | +19/-21 | 1 |
|
||||
| Ivan Schasny | 2 | +22/-14 | 4 |
|
||||
| MGMCN | 1 | +9/-24 | 2 |
|
||||
| Brian Meek | 1 | +14/-17 | 4 |
|
||||
| Ian Davis | 3 | +21/-9 | 5 |
|
||||
| Mars Zuo | 1 | +7/-18 | 1 |
|
||||
| RubenKelevra | 1 | +10/-10 | 1 |
|
||||
| mojatter | 1 | +9/-8 | 1 |
|
||||
| Cory Schwartz | 1 | +0/-17 | 1 |
|
||||
| Steve Loeppky | 6 | +7/-6 | 6 |
|
||||
| Matt Joiner | 2 | +10/-3 | 2 |
|
||||
| Winterhuman | 2 | +7/-5 | 2 |
|
||||
| Dmitry Yu Okunev | 1 | +5/-7 | 5 |
|
||||
| corverroos | 1 | +7/-4 | 2 |
|
||||
| Marcel Gregoriadis | 1 | +9/-0 | 1 |
|
||||
| Ignacio Hagopian | 2 | +7/-2 | 2 |
|
||||
| Julien Muret | 1 | +4/-4 | 2 |
|
||||
| Eclésio Junior | 1 | +8/-0 | 1 |
|
||||
| Stephan Eberle | 1 | +4/-3 | 1 |
|
||||
| muXxer | 1 | +3/-3 | 1 |
|
||||
| eth-limo | 1 | +3/-3 | 2 |
|
||||
| Russell Dempsey | 2 | +4/-2 | 2 |
|
||||
| Sergey | 1 | +1/-3 | 1 |
|
||||
| Jun10ng | 2 | +2/-2 | 2 |
|
||||
| Jorik Schellekens | 1 | +2/-2 | 1 |
|
||||
| Eli Wang | 1 | +2/-2 | 1 |
|
||||
| Andreas Linde | 1 | +4/-0 | 1 |
|
||||
| whyrusleeping | 1 | +2/-1 | 1 |
|
||||
| xiabin | 1 | +1/-1 | 1 |
|
||||
| star | 1 | +0/-2 | 1 |
|
||||
| fanweixiao | 1 | +1/-1 | 1 |
|
||||
| dbadoy4874 | 1 | +1/-1 | 1 |
|
||||
| bigs | 1 | +1/-1 | 1 |
|
||||
| Tarun Bansal | 1 | +1/-1 | 1 |
|
||||
| Mikerah | 1 | +1/-1 | 1 |
|
||||
| Mike Goelzer | 1 | +2/-0 | 1 |
|
||||
| Max Inden | 1 | +1/-1 | 1 |
|
||||
| Kevin Mai-Husan Chia | 1 | +1/-1 | 1 |
|
||||
| John B Nelson | 1 | +1/-1 | 1 |
|
||||
| Eli Bailey | 1 | +1/-1 | 1 |
|
||||
| Bryan Stenson | 1 | +1/-1 | 1 |
|
||||
| Alex Stokes | 1 | +1/-1 | 1 |
|
||||
| Abirdcfly | 1 | +1/-1 | 1 |
|
||||
226
docs/config.md
226
docs/config.md
@ -59,6 +59,7 @@ config file at runtime.
|
||||
- [`Gateway.PublicGateways: Paths`](#gatewaypublicgateways-paths)
|
||||
- [`Gateway.PublicGateways: UseSubdomains`](#gatewaypublicgateways-usesubdomains)
|
||||
- [`Gateway.PublicGateways: NoDNSLink`](#gatewaypublicgateways-nodnslink)
|
||||
- [`Gateway.PublicGateways: InlineDNSLink`](#gatewaypublicgateways-inlinednslink)
|
||||
- [Implicit defaults of `Gateway.PublicGateways`](#implicit-defaults-of-gatewaypublicgateways)
|
||||
- [`Gateway` recipes](#gateway-recipes)
|
||||
- [`Identity`](#identity)
|
||||
@ -105,8 +106,8 @@ config file at runtime.
|
||||
- [`Routing`](#routing)
|
||||
- [`Routing.Routers`](#routingrouters)
|
||||
- [`Routing.Routers: Type`](#routingrouters-type)
|
||||
- [`Routing.Routers: Enabled`](#routingrouters-enabled)
|
||||
- [`Routing.Routers: Parameters`](#routingrouters-parameters)
|
||||
- [`Routing: Methods`](#routing-methods)
|
||||
- [`Routing.Type`](#routingtype)
|
||||
- [`Swarm`](#swarm)
|
||||
- [`Swarm.AddrFilters`](#swarmaddrfilters)
|
||||
@ -148,6 +149,8 @@ config file at runtime.
|
||||
- [`Swarm.Transports.Network.Websocket`](#swarmtransportsnetworkwebsocket)
|
||||
- [`Swarm.Transports.Network.QUIC`](#swarmtransportsnetworkquic)
|
||||
- [`Swarm.Transports.Network.Relay`](#swarmtransportsnetworkrelay)
|
||||
- [`Swarm.Transports.Network.WebTransport`](#swarmtransportsnetworkwebtransport)
|
||||
- [How to enable WebTransport](#how-to-enable-webtransport)
|
||||
- [`Swarm.Transports.Security`](#swarmtransportssecurity)
|
||||
- [`Swarm.Transports.Security.TLS`](#swarmtransportssecuritytls)
|
||||
- [`Swarm.Transports.Security.SECIO`](#swarmtransportssecuritysecio)
|
||||
@ -205,7 +208,7 @@ documented in `ipfs config profile --help`.
|
||||
|
||||
Configures the node to use the flatfs datastore. Flatfs is the default datastore.
|
||||
|
||||
This is the most battle-tested and reliable datastore.
|
||||
This is the most battle-tested and reliable datastore.
|
||||
You should use this datastore if:
|
||||
|
||||
- You need a very simple and very reliable datastore, and you trust your
|
||||
@ -223,9 +226,9 @@ documented in `ipfs config profile --help`.
|
||||
|
||||
Configures the node to use the experimental badger datastore. Keep in mind that this **uses an outdated badger 1.x**.
|
||||
|
||||
Use this datastore if some aspects of performance,
|
||||
Use this datastore if some aspects of performance,
|
||||
especially the speed of adding many gigabytes of files, are critical. However, be aware that:
|
||||
|
||||
|
||||
- This datastore will not properly reclaim space when your datastore is
|
||||
smaller than several gigabytes. If you run IPFS with `--enable-gc`, you plan on storing very little data in
|
||||
your IPFS node, and disk usage is more critical than performance, consider using
|
||||
@ -358,6 +361,7 @@ Supported Transports:
|
||||
* tcp/ip{4,6} - `/ipN/.../tcp/...`
|
||||
* websocket - `/ipN/.../tcp/.../ws`
|
||||
* quic - `/ipN/.../udp/.../quic`
|
||||
* webtransport (*experiemental*) - `/ipN/.../udp/.../quic/webtransport` - require using a different port than the QUIC listener for now
|
||||
|
||||
Default:
|
||||
```json
|
||||
@ -764,6 +768,26 @@ Default: `false` (DNSLink lookup enabled by default for every defined hostname)
|
||||
|
||||
Type: `bool`
|
||||
|
||||
#### `Gateway.PublicGateways: InlineDNSLink`
|
||||
|
||||
An optional flag to explicitly configure whether subdomain gateway's redirects
|
||||
(enabled by `UseSubdomains: true`) should always inline a DNSLink name (FQDN)
|
||||
into a single DNS label:
|
||||
|
||||
```
|
||||
//example.com/ipns/example.net → HTTP 301 → //example-net.ipns.example.com
|
||||
```
|
||||
|
||||
DNSLink name inlining allows for HTTPS on public subdomain gateways with single
|
||||
label wildcard TLS certs (also enabled when passing `X-Forwarded-Proto: https`),
|
||||
and provides disjoint Origin per root CID when special rules like
|
||||
https://publicsuffix.org, or a custom localhost logic in browsers like Brave
|
||||
has to be applied.
|
||||
|
||||
Default: `false`
|
||||
|
||||
Type: `flag`
|
||||
|
||||
#### Implicit defaults of `Gateway.PublicGateways`
|
||||
|
||||
Default entries for `localhost` hostname and loopback IPs are always present.
|
||||
@ -804,17 +828,17 @@ Below is a list of the most common public gateway setups.
|
||||
}'
|
||||
```
|
||||
- **Backward-compatible:** this feature enables automatic redirects from content paths to subdomains:
|
||||
|
||||
|
||||
`http://dweb.link/ipfs/{cid}` → `http://{cid}.ipfs.dweb.link`
|
||||
|
||||
|
||||
- **X-Forwarded-Proto:** if you run Kubo behind a reverse proxy that provides TLS, make it add a `X-Forwarded-Proto: https` HTTP header to ensure users are redirected to `https://`, not `http://`. It will also ensure DNSLink names are inlined to fit in a single DNS label, so they work fine with a wildcart TLS cert ([details](https://github.com/ipfs/in-web-browsers/issues/169)). The NGINX directive is `proxy_set_header X-Forwarded-Proto "https";`.:
|
||||
|
||||
|
||||
`http://dweb.link/ipfs/{cid}` → `https://{cid}.ipfs.dweb.link`
|
||||
|
||||
|
||||
`http://dweb.link/ipns/your-dnslink.site.example.com` → `https://your--dnslink-site-example-com.ipfs.dweb.link`
|
||||
|
||||
|
||||
- **X-Forwarded-Host:** we also support `X-Forwarded-Host: example.com` if you want to override subdomain gateway host from the original request:
|
||||
|
||||
|
||||
`http://dweb.link/ipfs/{cid}` → `http://{cid}.ipfs.example.com`
|
||||
|
||||
|
||||
@ -839,7 +863,7 @@ Below is a list of the most common public gateway setups.
|
||||
Disable fetching of remote data (`NoFetch: true`) and resolving DNSLink at unknown hostnames (`NoDNSLink: true`).
|
||||
Then, enable DNSLink gateway only for the specific hostname (for which data
|
||||
is already present on the node), without exposing any content-addressing `Paths`:
|
||||
|
||||
|
||||
```console
|
||||
$ ipfs config --json Gateway.NoFetch true
|
||||
$ ipfs config --json Gateway.NoDNSLink true
|
||||
@ -871,7 +895,7 @@ Type: `string` (base64 encoded)
|
||||
|
||||
This section includes internal knobs for various subsystems to allow advanced users with big or private infrastructures to fine-tune some behaviors without the need to recompile Kubo.
|
||||
|
||||
**Be aware that making informed change here requires in-depth knowledge and most users should leave these untouched. All knobs listed here are subject to breaking changes between versions.**
|
||||
**Be aware that making informed change here requires in-depth knowledge and most users should leave these untouched. All knobs listed here are subject to breaking changes between versions.**
|
||||
|
||||
### `Internal.Bitswap`
|
||||
|
||||
@ -1291,20 +1315,11 @@ It specifies the routing type that will be created.
|
||||
Currently supported types:
|
||||
|
||||
- `reframe` (delegated routing based on the [reframe protocol](https://github.com/ipfs/specs/tree/main/reframe#readme))
|
||||
- <del>`dht`</del> (WIP, custom DHT will be added in a future release)
|
||||
- `dht`
|
||||
- `parallel` and `sequential`: Helpers that can be used to run several routers sequentially or in parallel.
|
||||
|
||||
Type: `string`
|
||||
|
||||
#### `Routing.Routers: Enabled`
|
||||
|
||||
**EXPERIMENTAL: `Routing.Routers` configuration may change in future release**
|
||||
|
||||
Optional flag to disable the specified router without removing it from the configuration file.
|
||||
|
||||
Default: `true`
|
||||
|
||||
Type: `flag` (`null`/missing will apply the default)
|
||||
|
||||
#### `Routing.Routers: Parameters`
|
||||
|
||||
**EXPERIMENTAL: `Routing.Routers` configuration may change in future release**
|
||||
@ -1313,7 +1328,26 @@ Parameters needed to create the specified router. Supported params per router ty
|
||||
|
||||
Reframe:
|
||||
- `Endpoint` (mandatory): URL that will be used to connect to a specified router.
|
||||
- `Priority` (optional): Priority is used when making a routing request. Small numbers represent more important routers. The default priority is 100000.
|
||||
|
||||
DHT:
|
||||
- `"Mode"`: Mode used by the DHT. Possible values: "server", "client", "auto"
|
||||
- `"AcceleratedDHTClient"`: Set to `true` if you want to use the experimentalDHT.
|
||||
- `"PublicIPNetwork"`: Set to `true` to create a `WAN` DHT. Set to `false` to create a `LAN` DHT.
|
||||
|
||||
Parallel:
|
||||
- `Routers`: A list of routers that will be executed in parallel:
|
||||
- `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
|
||||
- `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`). Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
|
||||
- `ExecuteAfter:duration`: Providing this param will delay the execution of that router at the specified time. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`).
|
||||
- `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
|
||||
- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`).
|
||||
|
||||
Sequential:
|
||||
- `Routers`: A list of routers that will be executed in order:
|
||||
- `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
|
||||
- `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
|
||||
- `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
|
||||
- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`.
|
||||
|
||||
**Examples:**
|
||||
|
||||
@ -1334,13 +1368,106 @@ Default: `{}` (use the safe implicit defaults)
|
||||
|
||||
Type: `object[string->string]`
|
||||
|
||||
### `Routing: Methods`
|
||||
|
||||
`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list.
|
||||
|
||||
The value will contain:
|
||||
- `RouterName:string`: Name of the router. It should be one of the previously added to `Routing.Routers` list.
|
||||
|
||||
Type: `object[string->object]`
|
||||
|
||||
**Examples:**
|
||||
|
||||
To use the previously added `CidContact` reframe router on all methods:
|
||||
|
||||
```console
|
||||
$ ipfs config Routing.Methods --json '{
|
||||
"find-peers": {
|
||||
"RouterName": "CidContact"
|
||||
},
|
||||
"find-providers": {
|
||||
"RouterName": "CidContact"
|
||||
},
|
||||
"get-ipns": {
|
||||
"RouterName": "CidContact"
|
||||
},
|
||||
"provide": {
|
||||
"RouterName": "CidContact"
|
||||
},
|
||||
"put-ipns": {
|
||||
"RouterName": "CidContact"
|
||||
}
|
||||
}'
|
||||
```
|
||||
Complete example using 3 Routers, reframe, DHT and parallel.
|
||||
|
||||
```
|
||||
$ ipfs config Routing.Type --json '"custom"'
|
||||
|
||||
$ ipfs config Routing.Routers.CidContact --json '{
|
||||
"Type": "reframe",
|
||||
"Parameters": {
|
||||
"Endpoint": "https://cid.contact/reframe"
|
||||
}
|
||||
}'
|
||||
|
||||
$ ipfs config Routing.Routers.WanDHT --json '{
|
||||
"Type": "dht",
|
||||
"Parameters": {
|
||||
"Mode": "auto",
|
||||
"PublicIPNetwork": true,
|
||||
"AcceleratedDHTClient": false
|
||||
}
|
||||
}'
|
||||
|
||||
$ ipfs config Routing.Routers.ParallelHelper --json '{
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName" : "CidContact",
|
||||
"IgnoreErrors" : true,
|
||||
"Timeout": "3s"
|
||||
},
|
||||
{
|
||||
"RouterName" : "WanDHT",
|
||||
"IgnoreErrors" : false,
|
||||
"Timeout": "5m",
|
||||
"ExecuteAfter": "2s"
|
||||
}
|
||||
]
|
||||
}
|
||||
}'
|
||||
|
||||
ipfs config Routing.Methods --json '{
|
||||
"find-peers": {
|
||||
"RouterName": "ParallelHelper"
|
||||
},
|
||||
"find-providers": {
|
||||
"RouterName": "ParallelHelper"
|
||||
},
|
||||
"get-ipns": {
|
||||
"RouterName": "ParallelHelper"
|
||||
},
|
||||
"provide": {
|
||||
"RouterName": "WanDHT"
|
||||
},
|
||||
"put-ipns": {
|
||||
"RouterName": "ParallelHelper"
|
||||
}
|
||||
}'
|
||||
|
||||
```
|
||||
|
||||
### `Routing.Type`
|
||||
|
||||
There are two core routing options: "none" and "dht" (default).
|
||||
There are three core routing options: "none", "dht" (default) and "custom".
|
||||
|
||||
* If set to "none", your node will use _no_ routing system. You'll have to
|
||||
explicitly connect to peers that have the content you're looking for.
|
||||
* If set to "dht" (or "dhtclient"/"dhtserver"), your node will use the IPFS DHT.
|
||||
* If set to "custom", `Routing.Routers` will be used.
|
||||
|
||||
When the DHT is enabled, it can operate in two modes: client and server.
|
||||
|
||||
@ -1516,7 +1643,7 @@ Type: `optionalInteger`
|
||||
|
||||
#### `Swarm.RelayService.ReservationTTL`
|
||||
|
||||
Duration of a new or refreshed reservation.
|
||||
Duration of a new or refreshed reservation.
|
||||
|
||||
Default: `"1h"`
|
||||
|
||||
@ -1755,7 +1882,7 @@ Configuration section for libp2p _network_ transports. Transports enabled in
|
||||
this section will be used for dialing. However, to receive connections on these
|
||||
transports, multiaddrs for these transports must be added to `Addresses.Swarm`.
|
||||
|
||||
Supported transports are: QUIC, TCP, WS, and Relay.
|
||||
Supported transports are: QUIC, TCP, WS, Relay and WebTransport.
|
||||
|
||||
Each field in this section is a `flag`.
|
||||
|
||||
@ -1831,6 +1958,49 @@ Listen Addresses:
|
||||
* This transport is special. Any node that enables this transport can receive
|
||||
inbound connections on this transport, without specifying a listen address.
|
||||
|
||||
|
||||
#### `Swarm.Transports.Network.WebTransport`
|
||||
|
||||
A new feature of [`go-libp2p`](https://github.com/libp2p/go-libp2p/releases/tag/v0.23.0)
|
||||
is the [WebTransport](https://github.com/libp2p/go-libp2p/issues/1717) transport.
|
||||
|
||||
This is a spiritual descendant of WebSocket but over `HTTP/3`.
|
||||
Since this runs on top of `HTTP/3` it uses `QUIC` under the hood.
|
||||
We expect it to perform worst than `QUIC` because of the extra overhead,
|
||||
this transport is really meant at agents that cannot do `TCP` or `QUIC` (like browsers).
|
||||
|
||||
For now it is **disabled by default** and considered **experimental**.
|
||||
If you find issues running it please [report them to us](https://github.com/ipfs/kubo/issues/new).
|
||||
|
||||
In the future Kubo will listen on WebTransport by default for anyone already listening on QUIC addresses.
|
||||
|
||||
WebTransport is a new transport protocol currently under development by the IETF and the W3C, and already implemented by Chrome.
|
||||
Conceptually, it’s like WebSocket run over QUIC instead of TCP. Most importantly, it allows browsers to establish (secure!) connections to WebTransport servers without the need for CA-signed certificates,
|
||||
thereby enabling any js-libp2p node running in a browser to connect to any kubo node, with zero manual configuration involved.
|
||||
|
||||
The previous alternative is websocket secure, which require installing a reverse proxy and TLS certificates manually.
|
||||
|
||||
Default: Disabled
|
||||
|
||||
Type: `flag`
|
||||
|
||||
|
||||
##### How to enable WebTransport
|
||||
|
||||
Thoses steps are temporary and wont be needed once we make it enabled by default.
|
||||
|
||||
1. Enable the WebTransport transport:
|
||||
`ipfs config Swarm.Transports.Network.WebTransport --json true`
|
||||
1. Add a listener address for WebTransport to your `Addresses.Swarm` key, for example:
|
||||
```json
|
||||
[
|
||||
"/ip4/0.0.0.0/tcp/4001",
|
||||
"/ip4/0.0.0.0/udp/4001/quic",
|
||||
"/ip4/0.0.0.0/udp/4002/quic/webtransport"
|
||||
]
|
||||
```
|
||||
1. Restart your daemon to apply the config changes.
|
||||
|
||||
### `Swarm.Transports.Security`
|
||||
|
||||
Configuration section for libp2p _security_ transports. Transports enabled in
|
||||
@ -1928,7 +2098,7 @@ Example:
|
||||
{
|
||||
"DNS": {
|
||||
"Resolvers": {
|
||||
"eth.": "https://eth.link/dns-query",
|
||||
"eth.": "https://dns.eth.limo/dns-query",
|
||||
"crypto.": "https://resolver.unstoppable.io/dns-query",
|
||||
"libre.": "https://ns1.iriseden.fr/dns-query",
|
||||
".": "https://cloudflare-dns.com/dns-query"
|
||||
|
||||
462
docs/delegated-routing.md
Normal file
462
docs/delegated-routing.md
Normal file
@ -0,0 +1,462 @@
|
||||
# New multi-router configuration system
|
||||
|
||||
- Start Date: 2022-08-15
|
||||
- Related Issues:
|
||||
- https://github.com/ipfs/kubo/issues/9188
|
||||
- https://github.com/ipfs/kubo/issues/9079
|
||||
|
||||
## Summary
|
||||
|
||||
Previously we only used DHT for content routing and content providing. After kubo-0.14.0 release we added support for [delegated routing using Reframe protocol](https://github.com/ipfs/kubo/pull/8997).
|
||||
|
||||
Now we need a better way to add different routers using different protocols like Reframe or DHT, and be able to configure them to cover different use cases.
|
||||
|
||||
## Motivation
|
||||
|
||||
The actual routing implementation is not enough. Some users needs to have more options when configuring the routing system. The new implementations should be able to:
|
||||
|
||||
- [x] Be user-friendly and easy enough to configure, but also versatile
|
||||
- [x] Configurable Router execution order
|
||||
- [x] Delay some of the Router methods execution when they will be executed on parallel
|
||||
- [x] Configure which method of a giving router will be used
|
||||
- [x] Mark some router methods as mandatory to make the execution fails if that method fails
|
||||
|
||||
## Detailed design
|
||||
|
||||
### Configuration file description
|
||||
|
||||
The `Routing` configuration section will contain the following keys:
|
||||
|
||||
#### Type
|
||||
|
||||
`Type` will be still in use to avoid complexity for the user that only wants to use Kubo with the default behavior. We are going to add a new type, `custom`, that will use the new router systems. `none` type will deactivate **all** routers, default dht and delegated ones.
|
||||
|
||||
#### Routers
|
||||
|
||||
`Routers` will be a key-value list of routers that will be available to use. The key is the router name and the value is all the needed configurations for that router. the `Type` will define the routing kind. The main router types will be `reframe` and `dht`, but we will implement two special routers used to execute a set of routers in parallel or sequentially: `parallel` router and `sequential` router.
|
||||
|
||||
Depending on the routing type, it will use different parameters:
|
||||
|
||||
##### Reframe
|
||||
|
||||
Params:
|
||||
|
||||
- `"Endpoint"`: URL endpoint implementing Reframe protocol.
|
||||
|
||||
##### DHT
|
||||
|
||||
Params:
|
||||
- `"Mode"`: Mode used by the DHT. Possible values: "server", "client", "auto"
|
||||
- `"AcceleratedDHTClient"`: Set to `true` if you want to use the experimentalDHT.
|
||||
- `"PublicIPNetwork"`: Set to `true` to create a `WAN` DHT. Set to `false` to create a `LAN` DHT.
|
||||
|
||||
##### Parallel
|
||||
|
||||
Params:
|
||||
- `Routers`: A list of routers that will be executed in parallel:
|
||||
- `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
|
||||
- `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
|
||||
- `ExecuteAfter:duration`: Providing this param will delay the execution of that router at the specified time. It accepts strings compatible with Go `time.ParseDuration(string)`.
|
||||
- `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
|
||||
- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`.
|
||||
##### Sequential
|
||||
|
||||
Params:
|
||||
- `Routers`: A list of routers that will be executed in order:
|
||||
- `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
|
||||
- `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
|
||||
- `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
|
||||
- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`.
|
||||
#### Methods
|
||||
|
||||
`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list. This will make configuration discoverable giving good errors to the user if a method is missing.
|
||||
|
||||
The value will contain:
|
||||
- `RouterName:string`: Name of the router. It should be one of the previously added to `Routers` list.
|
||||
|
||||
#### Configuration file example:
|
||||
|
||||
```json
|
||||
"Routing": {
|
||||
"Type": "custom",
|
||||
"Routers": {
|
||||
"storetheindex": {
|
||||
"Type": "reframe",
|
||||
"Parameters": {
|
||||
"Endpoint": "https://cid.contact/reframe"
|
||||
}
|
||||
},
|
||||
"dht-lan": {
|
||||
"Type": "dht",
|
||||
"Parameters": {
|
||||
"Mode": "server",
|
||||
"PublicIPNetwork": false,
|
||||
"AcceleratedDHTClient": false
|
||||
}
|
||||
},
|
||||
"dht-wan": {
|
||||
"Type": "dht",
|
||||
"Parameters": {
|
||||
"Mode": "auto",
|
||||
"PublicIPNetwork": true,
|
||||
"AcceleratedDHTClient": false
|
||||
}
|
||||
},
|
||||
"find-providers-router": {
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName": "dht-lan",
|
||||
"IgnoreErrors": true
|
||||
},
|
||||
{
|
||||
"RouterName": "dht-wan"
|
||||
},
|
||||
{
|
||||
"RouterName": "storetheindex"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"provide-router": {
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName": "dht-lan",
|
||||
"IgnoreErrors": true
|
||||
},
|
||||
{
|
||||
"RouterName": "dht-wan",
|
||||
"ExecuteAfter": "100ms",
|
||||
"Timeout": "100ms"
|
||||
},
|
||||
{
|
||||
"RouterName": "storetheindex",
|
||||
"ExecuteAfter": "100ms"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"get-ipns-router": {
|
||||
"Type": "sequential",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName": "dht-lan",
|
||||
"IgnoreErrors": true
|
||||
},
|
||||
{
|
||||
"RouterName": "dht-wan",
|
||||
"Timeout": "300ms"
|
||||
},
|
||||
{
|
||||
"RouterName": "storetheindex",
|
||||
"Timeout": "300ms"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"put-ipns-router": {
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName": "dht-lan"
|
||||
},
|
||||
{
|
||||
"RouterName": "dht-wan"
|
||||
},
|
||||
{
|
||||
"RouterName": "storetheindex"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Methods": {
|
||||
"find-providers": {
|
||||
"RouterName": "find-providers-router"
|
||||
},
|
||||
"provide": {
|
||||
"RouterName": "provide-router"
|
||||
},
|
||||
"get-ipns": {
|
||||
"RouterName": "get-ipns-router"
|
||||
},
|
||||
"put-ipns": {
|
||||
"RouterName": "put-ipns-router"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Added YAML for clarity:
|
||||
|
||||
```yaml
|
||||
---
|
||||
Type: custom
|
||||
Routers:
|
||||
storetheindex:
|
||||
Type: reframe
|
||||
Parameters:
|
||||
Endpoint: https://cid.contact/reframe
|
||||
dht-lan:
|
||||
Type: dht
|
||||
Parameters:
|
||||
Mode: server
|
||||
PublicIPNetwork: false
|
||||
AcceleratedDHTClient: false
|
||||
dht-wan:
|
||||
Type: dht
|
||||
Parameters:
|
||||
Mode: auto
|
||||
PublicIPNetwork: true
|
||||
AcceleratedDHTClient: false
|
||||
find-providers-router:
|
||||
Type: parallel
|
||||
Parameters:
|
||||
Routers:
|
||||
- RouterName: dht-lan
|
||||
IgnoreErrors: true
|
||||
- RouterName: dht-wan
|
||||
- RouterName: storetheindex
|
||||
provide-router:
|
||||
Type: parallel
|
||||
Parameters:
|
||||
Routers:
|
||||
- RouterName: dht-lan
|
||||
IgnoreErrors: true
|
||||
- RouterName: dht-wan
|
||||
ExecuteAfter: 100ms
|
||||
Timeout: 100ms
|
||||
- RouterName: storetheindex
|
||||
ExecuteAfter: 100ms
|
||||
get-ipns-router:
|
||||
Type: sequential
|
||||
Parameters:
|
||||
Routers:
|
||||
- RouterName: dht-lan
|
||||
IgnoreErrors: true
|
||||
- RouterName: dht-wan
|
||||
Timeout: 300ms
|
||||
- RouterName: storetheindex
|
||||
Timeout: 300ms
|
||||
put-ipns-router:
|
||||
Type: parallel
|
||||
Parameters:
|
||||
Routers:
|
||||
- RouterName: dht-lan
|
||||
- RouterName: dht-wan
|
||||
- RouterName: storetheindex
|
||||
Methods:
|
||||
find-providers:
|
||||
RouterName: find-providers-router
|
||||
provide:
|
||||
RouterName: provide-router
|
||||
get-ipns:
|
||||
RouterName: get-ipns-router
|
||||
put-ipns:
|
||||
RouterName: put-ipns-router
|
||||
```
|
||||
|
||||
### Error cases
|
||||
- If any of the routers fails, the output will be an error by default.
|
||||
- You can use `IgnoreErrors:true` to ignore errors for a specific router output
|
||||
- To avoid any error at the output, you must ignore all router errors.
|
||||
|
||||
### Implementation Details
|
||||
|
||||
#### Methods
|
||||
|
||||
All routers must implement the `routing.Routing` interface:
|
||||
|
||||
```go=
|
||||
type Routing interface {
|
||||
ContentRouting
|
||||
PeerRouting
|
||||
ValueStore
|
||||
|
||||
Bootstrap(context.Context) error
|
||||
}
|
||||
```
|
||||
|
||||
All methods involved:
|
||||
|
||||
```go=
|
||||
type Routing interface {
|
||||
Provide(context.Context, cid.Cid, bool) error
|
||||
FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo
|
||||
|
||||
FindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||
|
||||
PutValue(context.Context, string, []byte, ...Option) error
|
||||
GetValue(context.Context, string, ...Option) ([]byte, error)
|
||||
SearchValue(context.Context, string, ...Option) (<-chan []byte, error)
|
||||
|
||||
Bootstrap(context.Context) error
|
||||
}
|
||||
```
|
||||
We can configure which methods will be used per routing implementation. Methods names used in the configuration file will be:
|
||||
|
||||
- `Provide`: `"provide"`
|
||||
- `FindProvidersAsync`: `"find-providers"`
|
||||
- `FindPeer`: `"find-peers"`
|
||||
- `PutValue`: `"put-ipns"`
|
||||
- `GetValue`, `SearchValue`: `"get-ipns"`
|
||||
- `Bootstrap`: It will be always executed when needed.
|
||||
|
||||
#### Routers
|
||||
|
||||
We need to implement the `parallel` and `sequential` routers and stop using `routinghelpers.Tiered` router implementation.
|
||||
|
||||
Add cycle detection to avoid to user some headaches.
|
||||
|
||||
Also we need to implement an internal router, that will define the router used per method.
|
||||
|
||||
#### Other considerations
|
||||
|
||||
- We need to refactor how DHT routers are created to be able to use and add any amount of custom DHT routers.
|
||||
- We need to add a new `custom` router type to be able to use the new routing system.
|
||||
- Bitswap WANT broadcasting is not included on this document, but it can be added in next iterations.
|
||||
- This document will live in docs/design-notes for historical reasons and future reference.
|
||||
|
||||
## Test fixtures
|
||||
|
||||
As test fixtures we can add different use cases here and see how the configuration will look like.
|
||||
|
||||
### Mimic previous dual DHT config
|
||||
|
||||
```json
|
||||
"Routing": {
|
||||
"Type": "custom",
|
||||
"Routers": {
|
||||
"dht-lan": {
|
||||
"Type": "dht",
|
||||
"Parameters": {
|
||||
"Mode": "server",
|
||||
"PublicIPNetwork": false
|
||||
}
|
||||
},
|
||||
"dht-wan": {
|
||||
"Type": "dht",
|
||||
"Parameters": {
|
||||
"Mode": "auto",
|
||||
"PublicIPNetwork": true
|
||||
}
|
||||
},
|
||||
"parallel-dht-strict": {
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName": "dht-lan"
|
||||
},
|
||||
{
|
||||
"RouterName": "dht-wan"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parallel-dht": {
|
||||
"Type": "parallel",
|
||||
"Parameters": {
|
||||
"Routers": [
|
||||
{
|
||||
"RouterName": "dht-lan",
|
||||
"IgnoreError": true
|
||||
},
|
||||
{
|
||||
"RouterName": "dht-wan"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Methods": {
|
||||
"provide": {
|
||||
"RouterName": "dht-wan"
|
||||
},
|
||||
"find-providers": {
|
||||
"RouterName": "parallel-dht-strict"
|
||||
},
|
||||
"find-peers": {
|
||||
"RouterName": "parallel-dht-strict"
|
||||
},
|
||||
"get-ipns": {
|
||||
"RouterName": "parallel-dht"
|
||||
},
|
||||
"put-ipns": {
|
||||
"RouterName": "parallel-dht"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Yaml representation for clarity:
|
||||
|
||||
```yaml
|
||||
---
|
||||
Type: custom
|
||||
Routers:
|
||||
dht-lan:
|
||||
Type: dht
|
||||
Parameters:
|
||||
Mode: server
|
||||
PublicIPNetwork: false
|
||||
dht-wan:
|
||||
Type: dht
|
||||
Parameters:
|
||||
Mode: auto
|
||||
PublicIPNetwork: true
|
||||
parallel-dht-strict:
|
||||
Type: parallel
|
||||
Parameters:
|
||||
Routers:
|
||||
- RouterName: dht-lan
|
||||
- RouterName: dht-wan
|
||||
parallel-dht:
|
||||
Type: parallel
|
||||
Parameters:
|
||||
Routers:
|
||||
- RouterName: dht-lan
|
||||
IgnoreError: true
|
||||
- RouterName: dht-wan
|
||||
Methods:
|
||||
provide:
|
||||
RouterName: dht-wan
|
||||
find-providers:
|
||||
RouterName: parallel-dht-strict
|
||||
find-peers:
|
||||
RouterName: parallel-dht-strict
|
||||
get-ipns:
|
||||
RouterName: parallel-dht
|
||||
put-ipns:
|
||||
RouterName: parallel-dht
|
||||
|
||||
```
|
||||
|
||||
### Compatibility
|
||||
|
||||
~~We need to create a config migration using [fs-repo-migrations](https://github.com/ipfs/fs-repo-migrations). We should remove the `Routing.Type` param and add the configuration specified [previously](#Mimic-previous-dual-DHT-config).~~
|
||||
|
||||
We don't need to create any config migration! To avoid to the users the hassle of understanding how the new routing system works, we are gonna keep the old behavior. We will add the Type `custom` to make available the new Routing system.
|
||||
|
||||
### Security
|
||||
|
||||
No new security implications or considerations were found.
|
||||
|
||||
### Alternatives
|
||||
|
||||
I got ideas from all of the following links to create this design document:
|
||||
|
||||
- https://github.com/ipfs/kubo/issues/9079#issuecomment-1211288268
|
||||
- https://github.com/ipfs/kubo/issues/9157
|
||||
- https://github.com/ipfs/kubo/issues/9079#issuecomment-1205000253
|
||||
- https://www.notion.so/pl-strflt/Delegated-Routing-Thoughts-very-very-WIP-0543bc51b1bd4d63a061b0f28e195d38
|
||||
- https://gist.github.com/guseggert/effa027ff4cbadd7f67598efb6704d12
|
||||
|
||||
### Copyright
|
||||
|
||||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
@ -10,8 +10,8 @@ require (
|
||||
github.com/ipfs/go-ipfs-files v0.1.1
|
||||
github.com/ipfs/interface-go-ipfs-core v0.7.0
|
||||
github.com/ipfs/kubo v0.14.0-rc1
|
||||
github.com/libp2p/go-libp2p v0.22.0
|
||||
github.com/multiformats/go-multiaddr v0.6.0
|
||||
github.com/libp2p/go-libp2p v0.23.2
|
||||
github.com/multiformats/go-multiaddr v0.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -28,16 +28,15 @@ require (
|
||||
github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.4.0 // indirect
|
||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||
github.com/cskr/pubsub v1.0.2 // indirect
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/dgraph-io/badger v1.6.2 // indirect
|
||||
github.com/dgraph-io/ristretto v0.0.2 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
|
||||
@ -49,6 +48,7 @@ require (
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
@ -65,10 +65,10 @@ require (
|
||||
github.com/ipfs/go-bitswap v0.10.2 // indirect
|
||||
github.com/ipfs/go-block-format v0.0.3 // indirect
|
||||
github.com/ipfs/go-blockservice v0.4.0 // indirect
|
||||
github.com/ipfs/go-cid v0.3.0 // indirect
|
||||
github.com/ipfs/go-cid v0.3.2 // indirect
|
||||
github.com/ipfs/go-cidutil v0.1.0 // indirect
|
||||
github.com/ipfs/go-datastore v0.5.1 // indirect
|
||||
github.com/ipfs/go-delegated-routing v0.3.0 // indirect
|
||||
github.com/ipfs/go-datastore v0.6.0 // indirect
|
||||
github.com/ipfs/go-delegated-routing v0.6.0 // indirect
|
||||
github.com/ipfs/go-ds-badger v0.3.0 // indirect
|
||||
github.com/ipfs/go-ds-flatfs v0.5.1 // indirect
|
||||
github.com/ipfs/go-ds-leveldb v0.5.0 // indirect
|
||||
@ -94,7 +94,7 @@ require (
|
||||
github.com/ipfs/go-ipld-format v0.4.0 // indirect
|
||||
github.com/ipfs/go-ipld-git v0.1.1 // indirect
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
|
||||
github.com/ipfs/go-ipns v0.2.0 // indirect
|
||||
github.com/ipfs/go-ipns v0.3.0 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/ipfs/go-merkledag v0.6.0 // indirect
|
||||
@ -106,14 +106,14 @@ require (
|
||||
github.com/ipfs/go-unixfs v0.4.0 // indirect
|
||||
github.com/ipfs/go-unixfsnode v1.4.0 // indirect
|
||||
github.com/ipfs/go-verifcid v0.0.2 // indirect
|
||||
github.com/ipld/edelweiss v0.1.4 // indirect
|
||||
github.com/ipld/edelweiss v0.2.0 // indirect
|
||||
github.com/ipld/go-codec-dagpb v1.4.1 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.17.0 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.18.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/jbenet/goprocess v0.1.4 // indirect
|
||||
github.com/klauspost/compress v1.15.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.10 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/koron/go-ssdp v0.0.3 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
@ -127,7 +127,7 @@ require (
|
||||
github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect
|
||||
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.4.0 // indirect
|
||||
github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
|
||||
github.com/libp2p/go-mplex v0.7.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.2.0 // indirect
|
||||
@ -135,14 +135,14 @@ require (
|
||||
github.com/libp2p/go-netroute v0.2.0 // indirect
|
||||
github.com/libp2p/go-openssl v0.1.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.28.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.29.1 // indirect
|
||||
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/marten-seemann/webtransport-go v0.1.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
@ -152,12 +152,12 @@ require (
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.4 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.1.1 // indirect
|
||||
github.com/multiformats/go-multicodec v0.5.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.6.0 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||
github.com/multiformats/go-multistream v0.3.3 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
@ -169,7 +169,7 @@ require (
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
|
||||
github.com/prometheus/client_golang v1.12.1 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
@ -204,13 +204,14 @@ require (
|
||||
go.uber.org/dig v1.14.1 // indirect
|
||||
go.uber.org/fx v1.17.1 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.22.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
|
||||
@ -132,7 +132,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
@ -166,8 +165,9 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=
|
||||
github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
@ -203,8 +203,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
||||
github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
@ -476,8 +477,9 @@ github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqg
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o=
|
||||
github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
|
||||
github.com/ipfs/go-cid v0.3.0 h1:gT6Cbs6YePaBNc7l6v5EXt0xTMup1jGV5EU1N+QLVpY=
|
||||
github.com/ipfs/go-cid v0.3.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
|
||||
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
|
||||
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
|
||||
github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s=
|
||||
github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q=
|
||||
github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA=
|
||||
@ -491,10 +493,11 @@ github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13X
|
||||
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
|
||||
github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs=
|
||||
github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
|
||||
github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ=
|
||||
github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
|
||||
github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE=
|
||||
github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM=
|
||||
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
|
||||
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
|
||||
github.com/ipfs/go-delegated-routing v0.6.0 h1:+M1siyTB2H4mHzEnbWjepQxlmKbapVWdbYLexSDODpg=
|
||||
github.com/ipfs/go-delegated-routing v0.6.0/go.mod h1:FJjhCChfcWK9z6OXo2jwKKJoxq1JlEWG7YTvwaA7UbI=
|
||||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
|
||||
@ -568,6 +571,7 @@ github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY
|
||||
github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
|
||||
github.com/ipfs/go-ipfs-provider v0.7.1 h1:eKToBUAb6ZY8iiA6AYVxzW4G1ep67XUaaEBUIYpxhfw=
|
||||
github.com/ipfs/go-ipfs-provider v0.7.1/go.mod h1:QwdDYRYnC5sYGLlOwVDY/0ZB6T3zcMtu+5+GdGeUuw8=
|
||||
github.com/ipfs/go-ipfs-redirects-file v0.1.1/go.mod h1:tAwRjCV0RjLTjH8DR/AU7VYvfQECg+lpUy2Mdzv7gyk=
|
||||
github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs=
|
||||
github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY=
|
||||
github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY=
|
||||
@ -592,8 +596,9 @@ github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQ
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc=
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg=
|
||||
github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ=
|
||||
github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU=
|
||||
github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
|
||||
github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
|
||||
github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
|
||||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
|
||||
github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
|
||||
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
|
||||
@ -650,8 +655,8 @@ github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0
|
||||
github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js=
|
||||
github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY=
|
||||
github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM=
|
||||
github.com/ipld/edelweiss v0.1.4 h1:g4+C2Ph+8SV2MCJBG3oRtetvxJYAS2WzlNGgsOY95iM=
|
||||
github.com/ipld/edelweiss v0.1.4/go.mod h1:JX1MR06BPcTOF+5xCYDLnylYkXS15iUN0/RXVSiUIQs=
|
||||
github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
|
||||
github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
|
||||
github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
|
||||
github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4=
|
||||
github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI=
|
||||
@ -667,8 +672,9 @@ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHt
|
||||
github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM=
|
||||
github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
|
||||
github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA=
|
||||
github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g=
|
||||
github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs=
|
||||
github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo=
|
||||
github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE=
|
||||
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY=
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
@ -720,13 +726,15 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo=
|
||||
github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
@ -784,8 +792,9 @@ github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m
|
||||
github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4=
|
||||
github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw=
|
||||
github.com/libp2p/go-libp2p v0.20.0/go.mod h1:g0C5Fu+aXXbCXkusCzLycuBowEih3ElmDqtbo61Em7k=
|
||||
github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw=
|
||||
github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4=
|
||||
github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE=
|
||||
github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw=
|
||||
@ -939,8 +948,9 @@ github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvN
|
||||
github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y=
|
||||
github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ=
|
||||
github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.4.0 h1:b7y4aixQ7AwbqYfcOQ6wTw8DQvuRZeTAA0Od3YYN5yc=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.4.0/go.mod h1:dYEAgkVhqho3/YKxfOEGdFMIcWfAFNlZX8iAIihYA2E=
|
||||
github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0=
|
||||
github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
|
||||
@ -1110,8 +1120,9 @@ github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDY
|
||||
github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo=
|
||||
github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo=
|
||||
github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4=
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q=
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
|
||||
github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q=
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
|
||||
@ -1123,25 +1134,25 @@ github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2
|
||||
github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||
github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||
github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
|
||||
github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
|
||||
github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0=
|
||||
github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
@ -1152,6 +1163,8 @@ github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
|
||||
github.com/marten-seemann/webtransport-go v0.1.1 h1:TnyKp3pEXcDooTaNn4s9dYpMJ7kMnTp7k5h+SgYP/mc=
|
||||
github.com/marten-seemann/webtransport-go v0.1.1/go.mod h1:kBEh5+RSvOA4troP1vyOVBWK4MIMzDICXVrvCPrYcrM=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@ -1216,8 +1229,9 @@ github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE=
|
||||
github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM=
|
||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
|
||||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
|
||||
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
|
||||
@ -1234,8 +1248,9 @@ github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9x
|
||||
github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc=
|
||||
github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM=
|
||||
github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug=
|
||||
github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg=
|
||||
github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM=
|
||||
github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc=
|
||||
github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs=
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||
github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=
|
||||
@ -1262,8 +1277,9 @@ github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaI
|
||||
github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
|
||||
github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
|
||||
github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
|
||||
github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
|
||||
github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues=
|
||||
github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE=
|
||||
github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
|
||||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
|
||||
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
@ -1274,6 +1290,7 @@ github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj
|
||||
github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg=
|
||||
github.com/multiformats/go-multihash v0.0.16/go.mod h1:zhfEIgVnB/rPMfxgFw15ZmGoNaKyNUIE4IWHG/kC+Ag=
|
||||
github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84=
|
||||
github.com/multiformats/go-multihash v0.2.0/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
|
||||
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
|
||||
@ -1378,8 +1395,9 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
|
||||
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@ -1518,9 +1536,11 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
||||
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
@ -1659,8 +1679,9 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
|
||||
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
@ -1715,8 +1736,9 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc=
|
||||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E=
|
||||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4=
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -1741,8 +1763,7 @@ golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hM
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -1810,8 +1831,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 h1:KafLifaRFIuSJ5C+7CyFJOF9haxKNC1CEIDk8GX6X0k=
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -1932,8 +1954,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -2009,7 +2032,7 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -2159,6 +2182,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -116,12 +116,12 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *mountWra
|
||||
}
|
||||
}
|
||||
|
||||
coreApi, err := coreapi.NewCoreAPI(node)
|
||||
coreAPI, err := coreapi.NewCoreAPI(node)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fs, err := NewFileSystem(node.Context(), coreApi, "", "")
|
||||
fs, err := NewFileSystem(node.Context(), coreAPI, "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -147,25 +147,25 @@ func CreateRoot(ctx context.Context, ipfs iface.CoreAPI, keys map[string]iface.K
|
||||
}
|
||||
|
||||
// Attr returns file attributes.
|
||||
func (*Root) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||
func (r *Root) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||
log.Debug("Root Attr")
|
||||
a.Mode = os.ModeDir | 0111 // -rw+x
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lookup performs a lookup under this node.
|
||||
func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
func (r *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
switch name {
|
||||
case "mach_kernel", ".hidden", "._.":
|
||||
// Just quiet some log noise on OS X.
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
|
||||
if lnk, ok := s.LocalLinks[name]; ok {
|
||||
if lnk, ok := r.LocalLinks[name]; ok {
|
||||
return lnk, nil
|
||||
}
|
||||
|
||||
nd, ok := s.LocalDirs[name]
|
||||
nd, ok := r.LocalDirs[name]
|
||||
if ok {
|
||||
switch nd := nd.(type) {
|
||||
case *Directory:
|
||||
@ -179,7 +179,7 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
|
||||
// other links go through ipns resolution and are symlinked into the ipfs mountpoint
|
||||
ipnsName := "/ipns/" + name
|
||||
resolved, err := s.Ipfs.Name().Resolve(ctx, ipnsName)
|
||||
resolved, err := r.Ipfs.Name().Resolve(ctx, ipnsName)
|
||||
if err != nil {
|
||||
log.Warnf("ipns: namesys resolve error: %s", err)
|
||||
return nil, fuse.ENOENT
|
||||
@ -189,7 +189,7 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
return nil, errors.New("invalid path from ipns record")
|
||||
}
|
||||
|
||||
return &Link{s.IpfsRoot + "/" + strings.TrimPrefix(resolved.String(), "/ipfs/")}, nil
|
||||
return &Link{r.IpfsRoot + "/" + strings.TrimPrefix(resolved.String(), "/ipfs/")}, nil
|
||||
}
|
||||
|
||||
func (r *Root) Close() error {
|
||||
@ -270,8 +270,8 @@ func (fi *FileNode) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||
}
|
||||
|
||||
// Lookup performs a lookup under this node.
|
||||
func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
child, err := s.dir.Child(name)
|
||||
func (d *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
child, err := d.dir.Child(name)
|
||||
if err != nil {
|
||||
// todo: make this error more versatile.
|
||||
return nil, fuse.ENOENT
|
||||
@ -290,8 +290,8 @@ func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
}
|
||||
|
||||
// ReadDirAll reads the link structure as directory entries
|
||||
func (dir *Directory) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
listing, err := dir.dir.List(ctx)
|
||||
func (d *Directory) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
listing, err := d.dir.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -401,8 +401,8 @@ func (fi *File) Forget() {
|
||||
}
|
||||
}
|
||||
|
||||
func (dir *Directory) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
|
||||
child, err := dir.dir.Mkdir(req.Name)
|
||||
func (d *Directory) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
|
||||
child, err := d.dir.Mkdir(req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -451,15 +451,15 @@ func (fi *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
|
||||
return fi.fi.Close()
|
||||
}
|
||||
|
||||
func (dir *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
|
||||
func (d *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
|
||||
// New 'empty' file
|
||||
nd := dag.NodeWithData(ft.FilePBData(nil, 0))
|
||||
err := dir.dir.AddChild(req.Name, nd)
|
||||
err := d.dir.AddChild(req.Name, nd)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
child, err := dir.dir.Child(req.Name)
|
||||
child, err := d.dir.Child(req.Name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -483,8 +483,8 @@ func (dir *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp
|
||||
return nodechild, &File{fi: fd}, nil
|
||||
}
|
||||
|
||||
func (dir *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
||||
err := dir.dir.Unlink(req.Name)
|
||||
func (d *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
||||
err := d.dir.Unlink(req.Name)
|
||||
if err != nil {
|
||||
return fuse.ENOENT
|
||||
}
|
||||
@ -492,13 +492,13 @@ func (dir *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error
|
||||
}
|
||||
|
||||
// Rename implements NodeRenamer
|
||||
func (dir *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
|
||||
cur, err := dir.dir.Child(req.OldName)
|
||||
func (d *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
|
||||
cur, err := d.dir.Child(req.OldName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dir.dir.Unlink(req.OldName)
|
||||
err = d.dir.Unlink(req.OldName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ import (
|
||||
|
||||
// Mount mounts ipns at a given location, and returns a mount.Mount instance.
|
||||
func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (mount.Mount, error) {
|
||||
coreApi, err := coreapi.NewCoreAPI(ipfs)
|
||||
coreAPI, err := coreapi.NewCoreAPI(ipfs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -22,12 +22,12 @@ func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (mount.Mount, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allow_other := cfg.Mounts.FuseAllowOther
|
||||
allowOther := cfg.Mounts.FuseAllowOther
|
||||
|
||||
fsys, err := NewFileSystem(ipfs.Context(), coreApi, ipfsmp, ipnsmp)
|
||||
fsys, err := NewFileSystem(ipfs.Context(), coreAPI, ipfsmp, ipnsmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mount.NewMount(ipfs.Process, fsys, ipnsmp, allow_other)
|
||||
return mount.NewMount(ipfs.Process, fsys, ipnsmp, allowOther)
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ type mount struct {
|
||||
|
||||
// Mount mounts a fuse fs.FS at a given location, and returns a Mount instance.
|
||||
// parent is a ContextGroup to bind the mount's ContextGroup to.
|
||||
func NewMount(p goprocess.Process, fsys fs.FS, mountpoint string, allow_other bool) (Mount, error) {
|
||||
func NewMount(p goprocess.Process, fsys fs.FS, mountpoint string, allowOther bool) (Mount, error) {
|
||||
var conn *fuse.Conn
|
||||
var err error
|
||||
|
||||
@ -39,7 +39,7 @@ func NewMount(p goprocess.Process, fsys fs.FS, mountpoint string, allow_other bo
|
||||
fuse.AsyncRead(),
|
||||
}
|
||||
|
||||
if allow_other {
|
||||
if allowOther {
|
||||
mountOpts = append(mountOpts, fuse.AllowOther())
|
||||
}
|
||||
conn, err = fuse.Mount(mountpoint, mountOpts...)
|
||||
|
||||
@ -15,7 +15,7 @@ func Mount(ipfs *core.IpfsNode, mountpoint string) (mount.Mount, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allow_other := cfg.Mounts.FuseAllowOther
|
||||
allowOther := cfg.Mounts.FuseAllowOther
|
||||
fsys := NewFileSystem(ipfs)
|
||||
return mount.NewMount(ipfs.Process, fsys, mountpoint, allow_other)
|
||||
return mount.NewMount(ipfs.Process, fsys, mountpoint, allowOther)
|
||||
}
|
||||
|
||||
@ -180,11 +180,11 @@ func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
case os.ErrNotExist, mdag.ErrLinkNotFound:
|
||||
// todo: make this error more versatile.
|
||||
return nil, fuse.ENOENT
|
||||
case nil:
|
||||
// noop
|
||||
default:
|
||||
log.Errorf("fuse lookup %q: %s", name, err)
|
||||
return nil, fuse.EIO
|
||||
case nil:
|
||||
// noop
|
||||
}
|
||||
|
||||
nd, err := s.Ipfs.DAG.Get(ctx, link.Cid)
|
||||
|
||||
2
gc/gc.go
2
gc/gc.go
@ -167,7 +167,7 @@ func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots
|
||||
verboseCidError := func(err error) error {
|
||||
if strings.Contains(err.Error(), verifcid.ErrBelowMinimumHashLength.Error()) ||
|
||||
strings.Contains(err.Error(), verifcid.ErrPossiblyInsecureHashFunction.Error()) {
|
||||
err = fmt.Errorf("\"%s\"\nPlease run 'ipfs pin verify'"+
|
||||
err = fmt.Errorf("\"%s\"\nPlease run 'ipfs pin verify'"+ //nolint
|
||||
" to list insecure hashes. If you want to read them,"+
|
||||
" please downgrade your go-ipfs to 0.4.13\n", err)
|
||||
log.Error(err)
|
||||
|
||||
52
go.mod
52
go.mod
@ -8,7 +8,7 @@ require (
|
||||
github.com/ceramicnetwork/go-dag-jose v0.1.0
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/cheggaaa/pb v1.0.29
|
||||
github.com/coreos/go-systemd/v22 v22.3.2
|
||||
github.com/coreos/go-systemd/v22 v22.4.0
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302
|
||||
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5
|
||||
@ -18,9 +18,9 @@ require (
|
||||
github.com/ipfs/go-bitswap v0.10.2
|
||||
github.com/ipfs/go-block-format v0.0.3
|
||||
github.com/ipfs/go-blockservice v0.4.0
|
||||
github.com/ipfs/go-cid v0.3.0
|
||||
github.com/ipfs/go-cid v0.3.2
|
||||
github.com/ipfs/go-cidutil v0.1.0
|
||||
github.com/ipfs/go-datastore v0.5.1
|
||||
github.com/ipfs/go-datastore v0.6.0
|
||||
github.com/ipfs/go-detect-race v0.0.1
|
||||
github.com/ipfs/go-ds-badger v0.3.0
|
||||
github.com/ipfs/go-ds-flatfs v0.5.1
|
||||
@ -46,7 +46,7 @@ require (
|
||||
github.com/ipfs/go-ipld-format v0.4.0
|
||||
github.com/ipfs/go-ipld-git v0.1.1
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1
|
||||
github.com/ipfs/go-ipns v0.2.0
|
||||
github.com/ipfs/go-ipns v0.3.0
|
||||
github.com/ipfs/go-log v1.0.5
|
||||
github.com/ipfs/go-merkledag v0.6.0
|
||||
github.com/ipfs/go-metrics-interface v0.0.1
|
||||
@ -63,12 +63,12 @@ require (
|
||||
github.com/ipld/go-car v0.4.0
|
||||
github.com/ipld/go-car/v2 v2.4.0
|
||||
github.com/ipld/go-codec-dagpb v1.4.1
|
||||
github.com/ipld/go-ipld-prime v0.17.0
|
||||
github.com/ipld/go-ipld-prime v0.18.0
|
||||
github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0
|
||||
github.com/jbenet/goprocess v0.1.4
|
||||
github.com/libp2p/go-doh-resolver v0.4.0
|
||||
github.com/libp2p/go-libp2p v0.22.0
|
||||
github.com/libp2p/go-libp2p v0.23.2
|
||||
github.com/libp2p/go-libp2p-core v0.20.1 // indirect
|
||||
github.com/libp2p/go-libp2p-http v0.2.1
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.18.0
|
||||
@ -77,19 +77,19 @@ require (
|
||||
github.com/libp2p/go-libp2p-pubsub v0.6.1
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.5.0
|
||||
github.com/libp2p/go-libp2p-record v0.2.0
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.4.0
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0
|
||||
github.com/libp2p/go-socket-activation v0.1.0
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/multiformats/go-multiaddr v0.6.0
|
||||
github.com/multiformats/go-multiaddr v0.7.0
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1
|
||||
github.com/multiformats/go-multibase v0.1.1
|
||||
github.com/multiformats/go-multicodec v0.5.0
|
||||
github.com/multiformats/go-multicodec v0.6.0
|
||||
github.com/multiformats/go-multihash v0.2.1
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
@ -108,15 +108,16 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.7.0
|
||||
go.uber.org/dig v1.14.1
|
||||
go.uber.org/fx v1.17.1
|
||||
go.uber.org/zap v1.22.0
|
||||
go.uber.org/zap v1.23.0
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/benbjohnson/clock v1.3.0
|
||||
github.com/ipfs/go-delegated-routing v0.3.0
|
||||
github.com/ipfs/go-delegated-routing v0.6.0
|
||||
github.com/ipfs/go-ipfs-redirects-file v0.1.1
|
||||
github.com/ipfs/go-log/v2 v2.5.1
|
||||
)
|
||||
|
||||
@ -129,7 +130,6 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||
github.com/cskr/pubsub v1.0.2 // indirect
|
||||
@ -138,7 +138,7 @@ require (
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/dgraph-io/badger v1.6.2 // indirect
|
||||
github.com/dgraph-io/ristretto v0.0.2 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
@ -151,6 +151,7 @@ require (
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
@ -167,10 +168,10 @@ require (
|
||||
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
|
||||
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
|
||||
github.com/ipfs/go-peertaskqueue v0.7.1 // indirect
|
||||
github.com/ipld/edelweiss v0.1.4 // indirect
|
||||
github.com/ipld/edelweiss v0.2.0 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/klauspost/compress v1.15.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.10 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
|
||||
github.com/koron/go-ssdp v0.0.3 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
@ -186,14 +187,14 @@ require (
|
||||
github.com/libp2p/go-netroute v0.2.0 // indirect
|
||||
github.com/libp2p/go-openssl v0.1.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.28.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.29.1 // indirect
|
||||
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/marten-seemann/webtransport-go v0.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
@ -204,7 +205,7 @@ require (
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.4 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multistream v0.3.3 // indirect
|
||||
@ -227,6 +228,7 @@ require (
|
||||
github.com/tidwall/gjson v1.14.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
|
||||
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
|
||||
@ -239,9 +241,9 @@ require (
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 // indirect
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
|
||||
98
go.sum
98
go.sum
@ -130,7 +130,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo=
|
||||
github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30=
|
||||
@ -163,8 +162,8 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=
|
||||
github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
@ -198,8 +197,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
||||
github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
@ -472,8 +472,8 @@ github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67Fexh
|
||||
github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
|
||||
github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o=
|
||||
github.com/ipfs/go-cid v0.3.0 h1:gT6Cbs6YePaBNc7l6v5EXt0xTMup1jGV5EU1N+QLVpY=
|
||||
github.com/ipfs/go-cid v0.3.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
|
||||
github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
|
||||
github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
|
||||
github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s=
|
||||
github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q=
|
||||
github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA=
|
||||
@ -487,10 +487,10 @@ github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13X
|
||||
github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
|
||||
github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs=
|
||||
github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
|
||||
github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ=
|
||||
github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
|
||||
github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE=
|
||||
github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM=
|
||||
github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
|
||||
github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
|
||||
github.com/ipfs/go-delegated-routing v0.6.0 h1:+M1siyTB2H4mHzEnbWjepQxlmKbapVWdbYLexSDODpg=
|
||||
github.com/ipfs/go-delegated-routing v0.6.0/go.mod h1:FJjhCChfcWK9z6OXo2jwKKJoxq1JlEWG7YTvwaA7UbI=
|
||||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
|
||||
@ -565,6 +565,8 @@ github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY
|
||||
github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
|
||||
github.com/ipfs/go-ipfs-provider v0.7.1 h1:eKToBUAb6ZY8iiA6AYVxzW4G1ep67XUaaEBUIYpxhfw=
|
||||
github.com/ipfs/go-ipfs-provider v0.7.1/go.mod h1:QwdDYRYnC5sYGLlOwVDY/0ZB6T3zcMtu+5+GdGeUuw8=
|
||||
github.com/ipfs/go-ipfs-redirects-file v0.1.1 h1:Io++k0Vf/wK+tfnhEh63Yte1oQK5VGT2hIEYpD0Rzx8=
|
||||
github.com/ipfs/go-ipfs-redirects-file v0.1.1/go.mod h1:tAwRjCV0RjLTjH8DR/AU7VYvfQECg+lpUy2Mdzv7gyk=
|
||||
github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs=
|
||||
github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY=
|
||||
github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY=
|
||||
@ -589,8 +591,8 @@ github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQ
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc=
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg=
|
||||
github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ=
|
||||
github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU=
|
||||
github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
|
||||
github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
|
||||
github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
|
||||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
|
||||
github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
|
||||
github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
|
||||
@ -649,8 +651,8 @@ github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPm
|
||||
github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY=
|
||||
github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4=
|
||||
github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM=
|
||||
github.com/ipld/edelweiss v0.1.4 h1:g4+C2Ph+8SV2MCJBG3oRtetvxJYAS2WzlNGgsOY95iM=
|
||||
github.com/ipld/edelweiss v0.1.4/go.mod h1:JX1MR06BPcTOF+5xCYDLnylYkXS15iUN0/RXVSiUIQs=
|
||||
github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
|
||||
github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
|
||||
github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
|
||||
github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4=
|
||||
github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI=
|
||||
@ -666,8 +668,8 @@ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHt
|
||||
github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM=
|
||||
github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
|
||||
github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA=
|
||||
github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g=
|
||||
github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs=
|
||||
github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo=
|
||||
github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE=
|
||||
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ=
|
||||
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY=
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
@ -720,13 +722,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo=
|
||||
github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
|
||||
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
@ -783,8 +785,8 @@ github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2
|
||||
github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM=
|
||||
github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4=
|
||||
github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw=
|
||||
github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw=
|
||||
github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4=
|
||||
github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE=
|
||||
github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw=
|
||||
@ -936,8 +938,9 @@ github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3qu
|
||||
github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
|
||||
github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y=
|
||||
github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.4.0 h1:b7y4aixQ7AwbqYfcOQ6wTw8DQvuRZeTAA0Od3YYN5yc=
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.4.0/go.mod h1:dYEAgkVhqho3/YKxfOEGdFMIcWfAFNlZX8iAIihYA2E=
|
||||
github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0=
|
||||
github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
|
||||
@ -1104,8 +1107,8 @@ github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZj
|
||||
github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs=
|
||||
github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo=
|
||||
github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo=
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q=
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
|
||||
github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q=
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
|
||||
@ -1116,33 +1119,31 @@ github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0
|
||||
github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
|
||||
github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
|
||||
github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
|
||||
github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
|
||||
github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0=
|
||||
github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
|
||||
github.com/marten-seemann/webtransport-go v0.1.1 h1:TnyKp3pEXcDooTaNn4s9dYpMJ7kMnTp7k5h+SgYP/mc=
|
||||
github.com/marten-seemann/webtransport-go v0.1.1/go.mod h1:kBEh5+RSvOA4troP1vyOVBWK4MIMzDICXVrvCPrYcrM=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@ -1210,8 +1211,8 @@ github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE=
|
||||
github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM=
|
||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
|
||||
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
|
||||
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
|
||||
@ -1228,8 +1229,8 @@ github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9x
|
||||
github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc=
|
||||
github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM=
|
||||
github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug=
|
||||
github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg=
|
||||
github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM=
|
||||
github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc=
|
||||
github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs=
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||
github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=
|
||||
@ -1255,8 +1256,8 @@ github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErh
|
||||
github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ=
|
||||
github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
|
||||
github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
|
||||
github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
|
||||
github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues=
|
||||
github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE=
|
||||
github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
|
||||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
|
||||
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
@ -1370,8 +1371,9 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
|
||||
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||
github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@ -1512,9 +1514,12 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
||||
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ=
|
||||
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
@ -1651,8 +1656,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
|
||||
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||
@ -1705,8 +1710,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc=
|
||||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5 h1:rxKZ2gOnYxjfmakvUUqh9Gyb6KXfrj7JWTxORTYqb0E=
|
||||
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4=
|
||||
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@ -1793,8 +1798,8 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
|
||||
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 h1:KafLifaRFIuSJ5C+7CyFJOF9haxKNC1CEIDk8GX6X0k=
|
||||
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -1909,8 +1914,9 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
|
||||
@ -35,7 +35,7 @@ const LockFile = "repo.lock"
|
||||
|
||||
var log = logging.Logger("fsrepo")
|
||||
|
||||
// version number that we are currently expecting to see
|
||||
// RepoVersion is the version number that we are currently expecting to see
|
||||
var RepoVersion = 12
|
||||
|
||||
var migrationInstructions = `See https://github.com/ipfs/fs-repo-migrations/blob/master/run.md
|
||||
@ -383,7 +383,7 @@ func (r *FSRepo) SetAPIAddr(addr ma.Multiaddr) error {
|
||||
}
|
||||
// Remove the temp file when rename return error
|
||||
if err1 := os.Remove(filepath.Join(r.path, "."+apiFile+".tmp")); err1 != nil {
|
||||
return fmt.Errorf("File Rename error: %s, File remove error: %s", err.Error(),
|
||||
return fmt.Errorf("file Rename error: %s, file remove error: %s", err.Error(),
|
||||
err1.Error())
|
||||
}
|
||||
return err
|
||||
@ -422,7 +422,7 @@ func (r *FSRepo) SetGatewayAddr(addr net.Addr) error {
|
||||
}
|
||||
// Remove the temp file when rename return error
|
||||
if err1 := os.Remove(tmpPath); err1 != nil {
|
||||
return fmt.Errorf("File Rename error: %w, File remove error: %s", err, err1.Error())
|
||||
return fmt.Errorf("file Rename error: %w, file remove error: %s", err, err1.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ const (
|
||||
)
|
||||
|
||||
// HttpFetcher fetches files over HTTP
|
||||
type HttpFetcher struct {
|
||||
type HttpFetcher struct { //nolint
|
||||
distPath string
|
||||
gateway string
|
||||
limit int64
|
||||
@ -30,7 +30,7 @@ var _ Fetcher = (*HttpFetcher)(nil)
|
||||
// Specifying "" for distPath sets the default IPNS path.
|
||||
// Specifying "" for gateway sets the default.
|
||||
// Specifying 0 for fetchLimit sets the default, -1 means no limit.
|
||||
func NewHttpFetcher(distPath, gateway, userAgent string, fetchLimit int64) *HttpFetcher {
|
||||
func NewHttpFetcher(distPath, gateway, userAgent string, fetchLimit int64) *HttpFetcher { //nolint
|
||||
f := &HttpFetcher{
|
||||
distPath: LatestIpfsDist,
|
||||
gateway: defaultGatewayURL,
|
||||
|
||||
@ -28,7 +28,7 @@ const (
|
||||
// Default maximum download size
|
||||
defaultFetchLimit = 1024 * 1024 * 512
|
||||
|
||||
tempNodeTcpAddr = "/ip4/127.0.0.1/tcp/0"
|
||||
tempNodeTCPAddr = "/ip4/127.0.0.1/tcp/0"
|
||||
)
|
||||
|
||||
type IpfsFetcher struct {
|
||||
@ -188,12 +188,12 @@ func initTempNode(ctx context.Context, bootstrap []string, peers []peer.AddrInfo
|
||||
}
|
||||
|
||||
// configure the temporary node
|
||||
cfg.Routing.Type = config.NewOptionalString("dhtclient")
|
||||
cfg.Routing.Type = "dhtclient"
|
||||
|
||||
// Disable listening for inbound connections
|
||||
cfg.Addresses.Gateway = []string{}
|
||||
cfg.Addresses.API = []string{}
|
||||
cfg.Addresses.Swarm = []string{tempNodeTcpAddr}
|
||||
cfg.Addresses.Swarm = []string{tempNodeTCPAddr}
|
||||
|
||||
if len(bootstrap) != 0 {
|
||||
cfg.Bootstrap = bootstrap
|
||||
|
||||
@ -166,6 +166,8 @@ func GetMigrationFetcher(downloadSources []string, distPath string, newIpfsFetch
|
||||
if newIpfsFetcher != nil {
|
||||
fetchers = append(fetchers, newIpfsFetcher(distPath))
|
||||
}
|
||||
case "":
|
||||
// Ignore empty string
|
||||
default:
|
||||
u, err := url.Parse(src)
|
||||
if err != nil {
|
||||
@ -179,8 +181,6 @@ func GetMigrationFetcher(downloadSources []string, distPath string, newIpfsFetch
|
||||
return nil, errors.New("bad gateway address: url scheme must be http or https")
|
||||
}
|
||||
fetchers = append(fetchers, &RetryFetcher{NewHttpFetcher(distPath, u.String(), httpUserAgent, 0), numTriesPerHTTP})
|
||||
case "":
|
||||
// Ignore empty string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrApiNotRunning = errors.New("api not running")
|
||||
ErrApiNotRunning = errors.New("api not running") //nolint
|
||||
)
|
||||
|
||||
// Repo represents all persistent data of a given ipfs node.
|
||||
|
||||
74
routing/composer.go
Normal file
74
routing/composer.go
Normal file
@ -0,0 +1,74 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/ipfs/go-cid"
|
||||
routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
"github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
var _ routinghelpers.ProvideManyRouter = &Composer{}
|
||||
var _ routing.Routing = &Composer{}
|
||||
|
||||
type Composer struct {
|
||||
GetValueRouter routing.Routing
|
||||
PutValueRouter routing.Routing
|
||||
FindPeersRouter routing.Routing
|
||||
FindProvidersRouter routing.Routing
|
||||
ProvideRouter routing.Routing
|
||||
}
|
||||
|
||||
func (c *Composer) Provide(ctx context.Context, cid cid.Cid, provide bool) error {
|
||||
return c.ProvideRouter.Provide(ctx, cid, provide)
|
||||
}
|
||||
|
||||
func (c *Composer) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
|
||||
pmr, ok := c.ProvideRouter.(routinghelpers.ProvideManyRouter)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return pmr.ProvideMany(ctx, keys)
|
||||
}
|
||||
|
||||
func (c *Composer) Ready() bool {
|
||||
pmr, ok := c.ProvideRouter.(routinghelpers.ProvideManyRouter)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
return pmr.Ready()
|
||||
}
|
||||
|
||||
func (c *Composer) FindProvidersAsync(ctx context.Context, cid cid.Cid, count int) <-chan peer.AddrInfo {
|
||||
return c.FindProvidersRouter.FindProvidersAsync(ctx, cid, count)
|
||||
}
|
||||
|
||||
func (c *Composer) FindPeer(ctx context.Context, pid peer.ID) (peer.AddrInfo, error) {
|
||||
return c.FindPeersRouter.FindPeer(ctx, pid)
|
||||
}
|
||||
|
||||
func (c *Composer) PutValue(ctx context.Context, key string, val []byte, opts ...routing.Option) error {
|
||||
return c.PutValueRouter.PutValue(ctx, key, val, opts...)
|
||||
}
|
||||
|
||||
func (c *Composer) GetValue(ctx context.Context, key string, opts ...routing.Option) ([]byte, error) {
|
||||
return c.GetValueRouter.GetValue(ctx, key, opts...)
|
||||
}
|
||||
|
||||
func (c *Composer) SearchValue(ctx context.Context, key string, opts ...routing.Option) (<-chan []byte, error) {
|
||||
return c.GetValueRouter.SearchValue(ctx, key, opts...)
|
||||
}
|
||||
|
||||
func (c *Composer) Bootstrap(ctx context.Context) error {
|
||||
errfp := c.FindPeersRouter.Bootstrap(ctx)
|
||||
errfps := c.FindProvidersRouter.Bootstrap(ctx)
|
||||
errgv := c.GetValueRouter.Bootstrap(ctx)
|
||||
errpv := c.PutValueRouter.Bootstrap(ctx)
|
||||
errp := c.ProvideRouter.Bootstrap(ctx)
|
||||
return multierror.Append(errfp, errfps, errgv, errpv, errp)
|
||||
}
|
||||
@ -1,93 +1,315 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
drc "github.com/ipfs/go-delegated-routing/client"
|
||||
drp "github.com/ipfs/go-delegated-routing/gen/proto"
|
||||
logging "github.com/ipfs/go-log"
|
||||
"github.com/ipfs/kubo/config"
|
||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
"github.com/libp2p/go-libp2p-kad-dht/dual"
|
||||
"github.com/libp2p/go-libp2p-kad-dht/fullrt"
|
||||
record "github.com/libp2p/go-libp2p-record"
|
||||
routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
|
||||
ic "github.com/libp2p/go-libp2p/core/crypto"
|
||||
host "github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
"github.com/multiformats/go-multicodec"
|
||||
)
|
||||
|
||||
type TieredRouter interface {
|
||||
routing.Routing
|
||||
ProvideMany() ProvideMany
|
||||
}
|
||||
var log = logging.Logger("routing/delegated")
|
||||
|
||||
var _ TieredRouter = &Tiered{}
|
||||
func Parse(routers config.Routers, methods config.Methods, extraDHT *ExtraDHTParams, extraReframe *ExtraReframeParams) (routing.Routing, error) {
|
||||
if err := methods.Check(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Tiered is a routing Tiered implementation providing some extra methods to fill
|
||||
// some special use cases when initializing the client.
|
||||
type Tiered struct {
|
||||
routinghelpers.Tiered
|
||||
}
|
||||
createdRouters := make(map[string]routing.Routing)
|
||||
finalRouter := &Composer{}
|
||||
|
||||
// ProvideMany returns a ProvideMany implementation including all Routers that
|
||||
// implements ProvideMany
|
||||
func (ds Tiered) ProvideMany() ProvideMany {
|
||||
var pms []ProvideMany
|
||||
for _, r := range ds.Tiered.Routers {
|
||||
pm, ok := r.(ProvideMany)
|
||||
if !ok {
|
||||
continue
|
||||
// Create all needed routers from method names
|
||||
for mn, m := range methods {
|
||||
router, err := parse(make(map[string]bool), createdRouters, m.RouterName, routers, extraDHT, extraReframe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pms = append(pms, pm)
|
||||
|
||||
switch mn {
|
||||
case config.MethodNamePutIPNS:
|
||||
finalRouter.PutValueRouter = router
|
||||
case config.MethodNameGetIPNS:
|
||||
finalRouter.GetValueRouter = router
|
||||
case config.MethodNameFindPeers:
|
||||
finalRouter.FindPeersRouter = router
|
||||
case config.MethodNameFindProviders:
|
||||
finalRouter.FindProvidersRouter = router
|
||||
case config.MethodNameProvide:
|
||||
finalRouter.ProvideRouter = router
|
||||
}
|
||||
|
||||
log.Info("using method ", mn, " with router ", m.RouterName)
|
||||
}
|
||||
|
||||
if len(pms) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ProvideManyWrapper{pms: pms}
|
||||
return finalRouter, nil
|
||||
}
|
||||
|
||||
const defaultPriority = 100000
|
||||
|
||||
// GetPriority extract priority from config params.
|
||||
// Small numbers represent more important routers.
|
||||
func GetPriority(params map[string]string) int {
|
||||
param := params[string(config.RouterParamPriority)]
|
||||
if param == "" {
|
||||
return defaultPriority
|
||||
func parse(visited map[string]bool,
|
||||
createdRouters map[string]routing.Routing,
|
||||
routerName string,
|
||||
routersCfg config.Routers,
|
||||
extraDHT *ExtraDHTParams,
|
||||
extraReframe *ExtraReframeParams,
|
||||
) (routing.Routing, error) {
|
||||
// check if we already created it
|
||||
r, ok := createdRouters[routerName]
|
||||
if ok {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
p, err := strconv.Atoi(param)
|
||||
if err != nil {
|
||||
return defaultPriority
|
||||
// check if we are in a dep loop
|
||||
if visited[routerName] {
|
||||
return nil, fmt.Errorf("dependency loop creating router with name %q", routerName)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
// set node as visited
|
||||
visited[routerName] = true
|
||||
|
||||
// RoutingFromConfig creates a Routing instance from the specified configuration.
|
||||
func RoutingFromConfig(c config.Router) (routing.Routing, error) {
|
||||
switch {
|
||||
case c.Type == string(config.RouterTypeReframe):
|
||||
return reframeRoutingFromConfig(c)
|
||||
default:
|
||||
return nil, &RouterTypeNotFoundError{c.Type}
|
||||
}
|
||||
}
|
||||
|
||||
func reframeRoutingFromConfig(conf config.Router) (routing.Routing, error) {
|
||||
var dr drp.DelegatedRouting_Client
|
||||
|
||||
param := string(config.RouterParamEndpoint)
|
||||
addr, ok := conf.Parameters[param]
|
||||
cfg, ok := routersCfg[routerName]
|
||||
if !ok {
|
||||
return nil, NewParamNeededErr(param, conf.Type)
|
||||
return nil, fmt.Errorf("config for router with name %q not found", routerName)
|
||||
}
|
||||
|
||||
var router routing.Routing
|
||||
var err error
|
||||
switch cfg.Type {
|
||||
case config.RouterTypeReframe:
|
||||
router, err = reframeRoutingFromConfig(cfg.Router, extraReframe)
|
||||
case config.RouterTypeDHT:
|
||||
router, err = dhtRoutingFromConfig(cfg.Router, extraDHT)
|
||||
case config.RouterTypeParallel:
|
||||
crp := cfg.Parameters.(*config.ComposableRouterParams)
|
||||
var pr []*routinghelpers.ParallelRouter
|
||||
for _, cr := range crp.Routers {
|
||||
ri, err := parse(visited, createdRouters, cr.RouterName, routersCfg, extraDHT, extraReframe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pr = append(pr, &routinghelpers.ParallelRouter{
|
||||
Router: ri,
|
||||
IgnoreError: cr.IgnoreErrors,
|
||||
Timeout: cr.Timeout.Duration,
|
||||
ExecuteAfter: cr.ExecuteAfter.WithDefault(0),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
router = routinghelpers.NewComposableParallel(pr)
|
||||
case config.RouterTypeSequential:
|
||||
crp := cfg.Parameters.(*config.ComposableRouterParams)
|
||||
var sr []*routinghelpers.SequentialRouter
|
||||
for _, cr := range crp.Routers {
|
||||
ri, err := parse(visited, createdRouters, cr.RouterName, routersCfg, extraDHT, extraReframe)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sr = append(sr, &routinghelpers.SequentialRouter{
|
||||
Router: ri,
|
||||
IgnoreError: cr.IgnoreErrors,
|
||||
Timeout: cr.Timeout.Duration,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
router = routinghelpers.NewComposableSequential(sr)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown router type %q", cfg.Type)
|
||||
}
|
||||
|
||||
dr, err := drp.New_DelegatedRouting_Client(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := drc.NewClient(dr)
|
||||
createdRouters[routerName] = router
|
||||
|
||||
log.Info("created router ", routerName, " with params ", cfg.Parameters)
|
||||
|
||||
return router, nil
|
||||
}
|
||||
|
||||
type ExtraReframeParams struct {
|
||||
PeerID string
|
||||
Addrs []string
|
||||
PrivKeyB64 string
|
||||
}
|
||||
|
||||
func reframeRoutingFromConfig(conf config.Router, extraReframe *ExtraReframeParams) (routing.Routing, error) {
|
||||
var dr drp.DelegatedRouting_Client
|
||||
|
||||
params := conf.Parameters.(*config.ReframeRouterParams)
|
||||
|
||||
if params.Endpoint == "" {
|
||||
return nil, NewParamNeededErr("Endpoint", conf.Type)
|
||||
}
|
||||
|
||||
// Increase per-host connection pool since we are making lots of concurrent requests.
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
transport.MaxIdleConns = 500
|
||||
transport.MaxIdleConnsPerHost = 100
|
||||
|
||||
delegateHTTPClient := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
dr, err := drp.New_DelegatedRouting_Client(params.Endpoint,
|
||||
drp.DelegatedRouting_Client_WithHTTPClient(delegateHTTPClient),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var c *drc.Client
|
||||
|
||||
// this path is for tests only
|
||||
if extraReframe == nil {
|
||||
c, err = drc.NewClient(dr, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
prov, err := createProvider(extraReframe.PeerID, extraReframe.Addrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := decodePrivKey(extraReframe.PrivKeyB64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err = drc.NewClient(dr, prov, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
crc := drc.NewContentRoutingClient(c)
|
||||
return &reframeRoutingWrapper{
|
||||
Client: c,
|
||||
ContentRoutingClient: crc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodePrivKey(keyB64 string) (ic.PrivKey, error) {
|
||||
pk, err := base64.StdEncoding.DecodeString(keyB64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ic.UnmarshalPrivateKey(pk)
|
||||
}
|
||||
|
||||
func createProvider(peerID string, addrs []string) (*drc.Provider, error) {
|
||||
pID, err := peer.Decode(peerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mas []ma.Multiaddr
|
||||
for _, a := range addrs {
|
||||
m, err := ma.NewMultiaddr(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mas = append(mas, m)
|
||||
}
|
||||
|
||||
return &drc.Provider{
|
||||
Peer: peer.AddrInfo{
|
||||
ID: pID,
|
||||
Addrs: mas,
|
||||
},
|
||||
ProviderProto: []drc.TransferProtocol{
|
||||
{Codec: multicodec.TransportBitswap},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ExtraDHTParams struct {
|
||||
BootstrapPeers []peer.AddrInfo
|
||||
Host host.Host
|
||||
Validator record.Validator
|
||||
Datastore datastore.Batching
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
func dhtRoutingFromConfig(conf config.Router, extra *ExtraDHTParams) (routing.Routing, error) {
|
||||
params, ok := conf.Parameters.(*config.DHTRouterParams)
|
||||
if !ok {
|
||||
return nil, errors.New("incorrect params for DHT router")
|
||||
}
|
||||
|
||||
if params.AcceleratedDHTClient {
|
||||
return createFullRT(extra)
|
||||
}
|
||||
|
||||
var mode dht.ModeOpt
|
||||
switch params.Mode {
|
||||
case config.DHTModeAuto:
|
||||
mode = dht.ModeAuto
|
||||
case config.DHTModeClient:
|
||||
mode = dht.ModeClient
|
||||
case config.DHTModeServer:
|
||||
mode = dht.ModeServer
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid DHT mode: %q", params.Mode)
|
||||
}
|
||||
|
||||
return createDHT(extra, params.PublicIPNetwork, mode)
|
||||
}
|
||||
|
||||
func createDHT(params *ExtraDHTParams, public bool, mode dht.ModeOpt) (routing.Routing, error) {
|
||||
var opts []dht.Option
|
||||
|
||||
if public {
|
||||
opts = append(opts, dht.QueryFilter(dht.PublicQueryFilter),
|
||||
dht.RoutingTableFilter(dht.PublicRoutingTableFilter),
|
||||
dht.RoutingTablePeerDiversityFilter(dht.NewRTPeerDiversityFilter(params.Host, 2, 3)))
|
||||
} else {
|
||||
opts = append(opts, dht.ProtocolExtension(dual.LanExtension),
|
||||
dht.QueryFilter(dht.PrivateQueryFilter),
|
||||
dht.RoutingTableFilter(dht.PrivateRoutingTableFilter))
|
||||
}
|
||||
|
||||
opts = append(opts,
|
||||
dht.Concurrency(10),
|
||||
dht.Mode(mode),
|
||||
dht.Datastore(params.Datastore),
|
||||
dht.Validator(params.Validator),
|
||||
dht.BootstrapPeers(params.BootstrapPeers...))
|
||||
|
||||
return dht.New(
|
||||
params.Context, params.Host, opts...,
|
||||
)
|
||||
}
|
||||
|
||||
func createFullRT(params *ExtraDHTParams) (routing.Routing, error) {
|
||||
return fullrt.NewFullRT(params.Host,
|
||||
dht.DefaultPrefix,
|
||||
fullrt.DHTOption(
|
||||
dht.Validator(params.Validator),
|
||||
dht.Datastore(params.Datastore),
|
||||
dht.BootstrapPeers(params.BootstrapPeers...),
|
||||
dht.BucketSize(20),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,121 +1,239 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/kubo/config"
|
||||
routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
"github.com/multiformats/go-multihash"
|
||||
crypto "github.com/libp2p/go-libp2p/core/crypto"
|
||||
peer "github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPriority(t *testing.T) {
|
||||
require := require.New(t)
|
||||
params := make(map[string]string)
|
||||
p := GetPriority(params)
|
||||
|
||||
require.Equal(defaultPriority, p)
|
||||
|
||||
params[string(config.RouterParamPriority)] = "101"
|
||||
|
||||
p = GetPriority(params)
|
||||
|
||||
require.Equal(101, p)
|
||||
|
||||
params[string(config.RouterParamPriority)] = "NAN"
|
||||
|
||||
p = GetPriority(params)
|
||||
|
||||
require.Equal(defaultPriority, p)
|
||||
}
|
||||
|
||||
func TestRoutingFromConfig(t *testing.T) {
|
||||
func TestReframeRoutingFromConfig(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
r, err := RoutingFromConfig(config.Router{
|
||||
Type: "unknown",
|
||||
})
|
||||
|
||||
require.Nil(r)
|
||||
require.EqualError(err, "router type unknown is not supported")
|
||||
|
||||
r, err = RoutingFromConfig(config.Router{
|
||||
Type: string(config.RouterTypeReframe),
|
||||
Parameters: make(map[string]string),
|
||||
})
|
||||
r, err := reframeRoutingFromConfig(config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{},
|
||||
}, nil)
|
||||
|
||||
require.Nil(r)
|
||||
require.EqualError(err, "configuration param 'Endpoint' is needed for reframe delegated routing types")
|
||||
|
||||
r, err = RoutingFromConfig(config.Router{
|
||||
Type: string(config.RouterTypeReframe),
|
||||
Parameters: map[string]string{
|
||||
string(config.RouterParamEndpoint): "test",
|
||||
r, err = reframeRoutingFromConfig(config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: "test",
|
||||
},
|
||||
}, nil)
|
||||
|
||||
require.NoError(err)
|
||||
require.NotNil(r)
|
||||
|
||||
priv, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048)
|
||||
require.NoError(err)
|
||||
|
||||
id, err := peer.IDFromPublicKey(pub)
|
||||
require.NoError(err)
|
||||
|
||||
privM, err := crypto.MarshalPrivateKey(priv)
|
||||
require.NoError(err)
|
||||
|
||||
r, err = reframeRoutingFromConfig(config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: "test",
|
||||
},
|
||||
}, &ExtraReframeParams{
|
||||
PeerID: id.String(),
|
||||
Addrs: []string{"/ip4/0.0.0.0/tcp/4001"},
|
||||
PrivKeyB64: base64.StdEncoding.EncodeToString(privM),
|
||||
})
|
||||
|
||||
require.NotNil(r)
|
||||
require.NoError(err)
|
||||
}
|
||||
|
||||
func TestTieredRouter(t *testing.T) {
|
||||
func TestParser(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
tr := &Tiered{
|
||||
Tiered: routinghelpers.Tiered{
|
||||
Routers: []routing.Routing{routinghelpers.Null{}},
|
||||
router, err := Parse(config.Routers{
|
||||
"r1": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: "testEndpoint",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
"r2": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeSequential,
|
||||
Parameters: &config.ComposableRouterParams{
|
||||
Routers: []config.ConfigRouter{
|
||||
{
|
||||
RouterName: "r1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, config.Methods{
|
||||
config.MethodNameFindPeers: config.Method{
|
||||
RouterName: "r1",
|
||||
},
|
||||
config.MethodNameFindProviders: config.Method{
|
||||
RouterName: "r1",
|
||||
},
|
||||
config.MethodNameGetIPNS: config.Method{
|
||||
RouterName: "r1",
|
||||
},
|
||||
config.MethodNamePutIPNS: config.Method{
|
||||
RouterName: "r2",
|
||||
},
|
||||
config.MethodNameProvide: config.Method{
|
||||
RouterName: "r2",
|
||||
},
|
||||
}, &ExtraDHTParams{}, nil)
|
||||
|
||||
pm := tr.ProvideMany()
|
||||
require.Nil(pm)
|
||||
require.NoError(err)
|
||||
|
||||
tr.Tiered.Routers = append(tr.Tiered.Routers, &dummyRouter{})
|
||||
comp, ok := router.(*Composer)
|
||||
require.True(ok)
|
||||
|
||||
pm = tr.ProvideMany()
|
||||
require.NotNil(pm)
|
||||
require.Equal(comp.FindPeersRouter, comp.FindProvidersRouter)
|
||||
require.Equal(comp.ProvideRouter, comp.PutValueRouter)
|
||||
}
|
||||
|
||||
type dummyRouter struct {
|
||||
}
|
||||
func TestParserRecursive(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
func (dr *dummyRouter) Provide(context.Context, cid.Cid, bool) error {
|
||||
panic("not implemented")
|
||||
router, err := Parse(config.Routers{
|
||||
"reframe1": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: "testEndpoint1",
|
||||
},
|
||||
},
|
||||
},
|
||||
"reframe2": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: "testEndpoint2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"reframe3": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeReframe,
|
||||
Parameters: &config.ReframeRouterParams{
|
||||
Endpoint: "testEndpoint3",
|
||||
},
|
||||
},
|
||||
},
|
||||
"composable1": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeSequential,
|
||||
Parameters: &config.ComposableRouterParams{
|
||||
Routers: []config.ConfigRouter{
|
||||
{
|
||||
RouterName: "reframe1",
|
||||
},
|
||||
{
|
||||
RouterName: "reframe2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"composable2": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeParallel,
|
||||
Parameters: &config.ComposableRouterParams{
|
||||
Routers: []config.ConfigRouter{
|
||||
{
|
||||
RouterName: "composable1",
|
||||
},
|
||||
{
|
||||
RouterName: "reframe3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, config.Methods{
|
||||
config.MethodNameFindPeers: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNameFindProviders: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNameGetIPNS: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNamePutIPNS: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNameProvide: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
}, &ExtraDHTParams{}, nil)
|
||||
|
||||
require.NoError(err)
|
||||
|
||||
_, ok := router.(*Composer)
|
||||
require.True(ok)
|
||||
|
||||
}
|
||||
|
||||
func (dr *dummyRouter) FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo {
|
||||
panic("not implemented")
|
||||
}
|
||||
func TestParserRecursiveLoop(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
func (dr *dummyRouter) FindPeer(context.Context, peer.ID) (peer.AddrInfo, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
_, err := Parse(config.Routers{
|
||||
"composable1": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeSequential,
|
||||
Parameters: &config.ComposableRouterParams{
|
||||
Routers: []config.ConfigRouter{
|
||||
{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"composable2": config.RouterParser{
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeParallel,
|
||||
Parameters: &config.ComposableRouterParams{
|
||||
Routers: []config.ConfigRouter{
|
||||
{
|
||||
RouterName: "composable1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, config.Methods{
|
||||
config.MethodNameFindPeers: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNameFindProviders: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNameGetIPNS: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNamePutIPNS: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
config.MethodNameProvide: config.Method{
|
||||
RouterName: "composable2",
|
||||
},
|
||||
}, &ExtraDHTParams{}, nil)
|
||||
|
||||
func (dr *dummyRouter) PutValue(context.Context, string, []byte, ...routing.Option) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (dr *dummyRouter) GetValue(context.Context, string, ...routing.Option) ([]byte, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (dr *dummyRouter) SearchValue(context.Context, string, ...routing.Option) (<-chan []byte, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (dr *dummyRouter) Bootstrap(context.Context) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (dr *dummyRouter) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (dr *dummyRouter) Ready() bool {
|
||||
panic("not implemented")
|
||||
require.ErrorContains(err, "dependency loop creating router with name \"composable2\"")
|
||||
}
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
package routing
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ipfs/kubo/config"
|
||||
)
|
||||
|
||||
type ParamNeededError struct {
|
||||
ParamName string
|
||||
RouterType string
|
||||
RouterType config.RouterType
|
||||
}
|
||||
|
||||
func NewParamNeededErr(param, routing string) error {
|
||||
func NewParamNeededErr(param string, routing config.RouterType) error {
|
||||
return &ParamNeededError{
|
||||
ParamName: param,
|
||||
RouterType: routing,
|
||||
@ -17,11 +21,3 @@ func NewParamNeededErr(param, routing string) error {
|
||||
func (e *ParamNeededError) Error() string {
|
||||
return fmt.Sprintf("configuration param '%v' is needed for %v delegated routing types", e.ParamName, e.RouterType)
|
||||
}
|
||||
|
||||
type RouterTypeNotFoundError struct {
|
||||
RouterType string
|
||||
}
|
||||
|
||||
func (e *RouterTypeNotFoundError) Error() string {
|
||||
return fmt.Sprintf("router type %v is not supported", e.RouterType)
|
||||
}
|
||||
|
||||
@ -5,13 +5,13 @@ import (
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
drc "github.com/ipfs/go-delegated-routing/client"
|
||||
routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
var _ routing.Routing = &reframeRoutingWrapper{}
|
||||
var _ routinghelpers.ProvideManyRouter = &reframeRoutingWrapper{}
|
||||
|
||||
// reframeRoutingWrapper is a wrapper needed to construct the routing.Routing interface from
|
||||
// delegated-routing library.
|
||||
@ -20,6 +20,10 @@ type reframeRoutingWrapper struct {
|
||||
*drc.ContentRoutingClient
|
||||
}
|
||||
|
||||
func (c *reframeRoutingWrapper) Provide(ctx context.Context, id cid.Cid, announce bool) error {
|
||||
return c.ContentRoutingClient.Provide(ctx, id, announce)
|
||||
}
|
||||
|
||||
func (c *reframeRoutingWrapper) FindProvidersAsync(ctx context.Context, cid cid.Cid, count int) <-chan peer.AddrInfo {
|
||||
return c.ContentRoutingClient.FindProvidersAsync(ctx, cid, count)
|
||||
}
|
||||
@ -32,35 +36,7 @@ func (c *reframeRoutingWrapper) FindPeer(ctx context.Context, id peer.ID) (peer.
|
||||
return peer.AddrInfo{}, routing.ErrNotSupported
|
||||
}
|
||||
|
||||
type ProvideMany interface {
|
||||
ProvideMany(ctx context.Context, keys []multihash.Multihash) error
|
||||
Ready() bool
|
||||
}
|
||||
|
||||
var _ ProvideMany = &ProvideManyWrapper{}
|
||||
|
||||
type ProvideManyWrapper struct {
|
||||
pms []ProvideMany
|
||||
}
|
||||
|
||||
func (pmw *ProvideManyWrapper) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
|
||||
var g errgroup.Group
|
||||
for _, pm := range pmw.pms {
|
||||
pm := pm
|
||||
g.Go(func() error {
|
||||
return pm.ProvideMany(ctx, keys)
|
||||
})
|
||||
}
|
||||
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// Ready is ready if all providers are ready
|
||||
func (pmw *ProvideManyWrapper) Ready() bool {
|
||||
out := true
|
||||
for _, pm := range pmw.pms {
|
||||
out = out && pm.Ready()
|
||||
}
|
||||
|
||||
return out
|
||||
type ProvideManyRouter interface {
|
||||
routinghelpers.ProvideManyRouter
|
||||
routing.Routing
|
||||
}
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
func TestProvideManyWrapper_ProvideMany(t *testing.T) {
|
||||
type fields struct {
|
||||
pms []ProvideMany
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantErr bool
|
||||
ready bool
|
||||
}{
|
||||
{
|
||||
name: "one provider",
|
||||
fields: fields{
|
||||
pms: []ProvideMany{
|
||||
newDummyProvideMany(true, false),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
ready: true,
|
||||
},
|
||||
{
|
||||
name: "two providers, no errors and ready",
|
||||
fields: fields{
|
||||
pms: []ProvideMany{
|
||||
newDummyProvideMany(true, false),
|
||||
newDummyProvideMany(true, false),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
ready: true,
|
||||
},
|
||||
{
|
||||
name: "two providers, no ready, no error",
|
||||
fields: fields{
|
||||
pms: []ProvideMany{
|
||||
newDummyProvideMany(true, false),
|
||||
newDummyProvideMany(false, false),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
ready: false,
|
||||
},
|
||||
{
|
||||
name: "two providers, no ready, and one erroing",
|
||||
fields: fields{
|
||||
pms: []ProvideMany{
|
||||
newDummyProvideMany(true, false),
|
||||
newDummyProvideMany(false, true),
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
ready: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pmw := &ProvideManyWrapper{
|
||||
pms: tt.fields.pms,
|
||||
}
|
||||
if err := pmw.ProvideMany(context.Background(), nil); (err != nil) != tt.wantErr {
|
||||
t.Errorf("ProvideManyWrapper.ProvideMany() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if ready := pmw.Ready(); ready != tt.ready {
|
||||
t.Errorf("ProvideManyWrapper.Ready() unexpected output = %v, want %v", ready, tt.ready)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newDummyProvideMany(ready, failProviding bool) *dummyProvideMany {
|
||||
return &dummyProvideMany{
|
||||
ready: ready,
|
||||
failProviding: failProviding,
|
||||
}
|
||||
}
|
||||
|
||||
type dummyProvideMany struct {
|
||||
ready, failProviding bool
|
||||
}
|
||||
|
||||
func (dpm *dummyProvideMany) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
|
||||
if dpm.failProviding {
|
||||
return errors.New("error providing many")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (dpm *dummyProvideMany) Ready() bool {
|
||||
return dpm.ready
|
||||
}
|
||||
@ -122,12 +122,12 @@ func DirectAddCat(data []byte, conf testutil.LatencyConfig) error {
|
||||
}
|
||||
defer catter.Close()
|
||||
|
||||
adderApi, err := coreapi.NewCoreAPI(adder)
|
||||
adderAPI, err := coreapi.NewCoreAPI(adder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
catterApi, err := coreapi.NewCoreAPI(catter)
|
||||
catterAPI, err := coreapi.NewCoreAPI(catter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -147,12 +147,12 @@ func DirectAddCat(data []byte, conf testutil.LatencyConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
added, err := adderApi.Unixfs().Add(ctx, files.NewBytesFile(data))
|
||||
added, err := adderAPI.Unixfs().Add(ctx, files.NewBytesFile(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
readerCatted, err := catterApi.Unixfs().Get(ctx, added)
|
||||
readerCatted, err := catterAPI.Unixfs().Get(ctx, added)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -65,12 +65,12 @@ func benchCat(b *testing.B, data []byte, conf testutil.LatencyConfig) error {
|
||||
}
|
||||
defer catter.Close()
|
||||
|
||||
adderApi, err := coreapi.NewCoreAPI(adder)
|
||||
adderAPI, err := coreapi.NewCoreAPI(adder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
catterApi, err := coreapi.NewCoreAPI(catter)
|
||||
catterAPI, err := coreapi.NewCoreAPI(catter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -90,13 +90,13 @@ func benchCat(b *testing.B, data []byte, conf testutil.LatencyConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
added, err := adderApi.Unixfs().Add(ctx, files.NewBytesFile(data))
|
||||
added, err := adderAPI.Unixfs().Add(ctx, files.NewBytesFile(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
readerCatted, err := catterApi.Unixfs().Get(ctx, added)
|
||||
readerCatted, err := catterAPI.Unixfs().Get(ctx, added)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -93,12 +93,12 @@ func RunThreeLeggedCat(data []byte, conf testutil.LatencyConfig) error {
|
||||
}
|
||||
defer catter.Close()
|
||||
|
||||
adderApi, err := coreapi.NewCoreAPI(adder)
|
||||
adderAPI, err := coreapi.NewCoreAPI(adder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
catterApi, err := coreapi.NewCoreAPI(catter)
|
||||
catterAPI, err := coreapi.NewCoreAPI(catter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -117,12 +117,12 @@ func RunThreeLeggedCat(data []byte, conf testutil.LatencyConfig) error {
|
||||
return err
|
||||
}
|
||||
|
||||
added, err := adderApi.Unixfs().Add(ctx, files.NewBytesFile(data))
|
||||
added, err := adderAPI.Unixfs().Add(ctx, files.NewBytesFile(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
readerCatted, err := catterApi.Unixfs().Get(ctx, added)
|
||||
readerCatted, err := catterAPI.Unixfs().Get(ctx, added)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -362,6 +362,113 @@ test_add_cat_file() {
|
||||
rm mountdir/same-file/hello.txt &&
|
||||
rmdir mountdir/same-file
|
||||
'
|
||||
|
||||
## --to-files with single source
|
||||
|
||||
test_expect_success "ipfs add --to-files /mfspath succeeds" '
|
||||
mkdir -p mountdir && echo "Hello MFS!" > mountdir/mfs.txt &&
|
||||
ipfs add mountdir/mfs.txt --to-files /ipfs-add-to-files >actual
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add --to-files output looks good" '
|
||||
HASH_MFS="QmVT8bL3sGBA2TwvX8JPhrv5CYZL8LLLfW7mxkUjPZsgBr" &&
|
||||
echo "added $HASH_MFS mfs.txt" >expected &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success "ipfs files read succeeds" '
|
||||
ipfs files read /ipfs-add-to-files >actual &&
|
||||
ipfs files rm /ipfs-add-to-files
|
||||
'
|
||||
|
||||
test_expect_success "ipfs cat output looks good" '
|
||||
echo "Hello MFS!" >expected &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add --to-files requires argument" '
|
||||
test_expect_code 1 ipfs add mountdir/mfs.txt --to-files >actual 2>&1 &&
|
||||
test_should_contain "Error: missing argument for option \"to-files\"" actual
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add --to-files / (MFS root) works" '
|
||||
echo "Hello MFS!" >expected &&
|
||||
ipfs add mountdir/mfs.txt --to-files / &&
|
||||
ipfs files read /mfs.txt >actual &&
|
||||
test_cmp expected actual &&
|
||||
ipfs files rm /mfs.txt &&
|
||||
rm mountdir/mfs.txt
|
||||
'
|
||||
|
||||
## --to-files with multiple sources
|
||||
|
||||
test_expect_success "ipfs add file1 file2 --to-files /mfspath0 (without trailing slash) fails" '
|
||||
mkdir -p test &&
|
||||
echo "file1" > test/mfs1.txt &&
|
||||
echo "file2" > test/mfs2.txt &&
|
||||
test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfspath0 >actual 2>&1 &&
|
||||
test_should_contain "MFS destination is a file: only one entry can be copied to \"/mfspath0\"" actual &&
|
||||
ipfs files rm -r --force /mfspath0
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add file1 file2 --to-files /mfsfile1 (without trailing slash + with preexisting file) fails" '
|
||||
echo test | ipfs files write --create /mfsfile1 &&
|
||||
test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfsfile1 >actual 2>&1 &&
|
||||
test_should_contain "Error: to-files: cannot put node in path \"/mfsfile1\"" actual &&
|
||||
ipfs files rm -r --force /mfsfile1
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add file1 file2 --to-files /mfsdir1 (without trailing slash + with preexisting dir) fails" '
|
||||
ipfs files mkdir -p /mfsdir1 &&
|
||||
test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfsdir1 >actual 2>&1 &&
|
||||
test_should_contain "Error: to-files: cannot put node in path \"/mfsdir1\"" actual &&
|
||||
ipfs files rm -r --force /mfsdir1
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add file1 file2 --to-files /mfsdir2/ (with trailing slash) succeeds" '
|
||||
ipfs files mkdir -p /mfsdir2 &&
|
||||
test_expect_code 0 ipfs add --cid-version 1 test/mfs1.txt test/mfs2.txt --to-files /mfsdir2/ > actual 2>&1 &&
|
||||
test_should_contain "added bafkreihm3rktn5z33luic3youqdsn326toaq3ekesmdvsa53sbrd3f5r3a mfs1.txt" actual &&
|
||||
test_should_contain "added bafkreidh5zkhr2vnwa2luwmuj24xo6l3jhfgvkgtk5cyp43oxs7owzpxby mfs2.txt" actual &&
|
||||
test_should_not_contain "Error" actual &&
|
||||
ipfs files ls /mfsdir2/ > lsout &&
|
||||
test_should_contain "mfs1.txt" lsout &&
|
||||
test_should_contain "mfs2.txt" lsout &&
|
||||
ipfs files rm -r --force /mfsdir2
|
||||
'
|
||||
|
||||
test_expect_success "ipfs add file1 file2 --to-files /mfsfile2/ (with trailing slash + with preexisting file) fails" '
|
||||
echo test | ipfs files write --create /mfsfile2 &&
|
||||
test_expect_code 1 ipfs add test/mfs1.txt test/mfs2.txt --to-files /mfsfile2/ >actual 2>&1 &&
|
||||
test_should_contain "Error: to-files: MFS destination \"/mfsfile2/\" is not a directory" actual &&
|
||||
ipfs files rm -r --force /mfsfile2
|
||||
'
|
||||
|
||||
## --to-files with recursive dir
|
||||
|
||||
# test MFS destination without trailing slash
|
||||
test_expect_success "ipfs add with --to-files /mfs/subdir3 fails because /mfs/subdir3 exists" '
|
||||
ipfs files mkdir -p /mfs/subdir3 &&
|
||||
test_expect_code 1 ipfs add -r test --to-files /mfs/subdir3 >actual 2>&1 &&
|
||||
test_should_contain "cannot put node in path \"/mfs/subdir3\": directory already has entry by that name" actual &&
|
||||
ipfs files rm -r --force /mfs
|
||||
'
|
||||
|
||||
# test recursive import of a dir into MFS subdirectory
|
||||
test_expect_success "ipfs add -r dir --to-files /mfs/subdir4/ succeeds (because of trailing slash)" '
|
||||
ipfs files mkdir -p /mfs/subdir4 &&
|
||||
ipfs add --cid-version 1 -r test --to-files /mfs/subdir4/ >actual 2>&1 &&
|
||||
test_should_contain "added bafkreihm3rktn5z33luic3youqdsn326toaq3ekesmdvsa53sbrd3f5r3a test/mfs1.txt" actual &&
|
||||
test_should_contain "added bafkreidh5zkhr2vnwa2luwmuj24xo6l3jhfgvkgtk5cyp43oxs7owzpxby test/mfs2.txt" actual &&
|
||||
test_should_contain "added bafybeic7xwqwovt4g4bax6d3udp6222i63vj2rblpbim7uy2uw4a5gahha test" actual &&
|
||||
test_should_not_contain "Error" actual
|
||||
ipfs files ls /mfs/subdir4/ > lsout &&
|
||||
test_should_contain "test" lsout &&
|
||||
test_should_not_contain "mfs1.txt" lsout &&
|
||||
test_should_not_contain "mfs2.txt" lsout &&
|
||||
ipfs files rm -r --force /mfs
|
||||
'
|
||||
|
||||
}
|
||||
|
||||
test_add_cat_5MB() {
|
||||
|
||||
@ -27,7 +27,7 @@ test_expect_success "test ping other" '
|
||||
|
||||
test_expect_success "test ping unreachable peer" '
|
||||
printf "Looking up peer %s\n" "$BAD_PEER" > bad_ping_exp &&
|
||||
printf "Error: peer lookup failed: routing: not found\n" >> bad_ping_exp &&
|
||||
printf "PING QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJx.\nPing error: routing: not found\nError: ping failed\n" >> bad_ping_exp &&
|
||||
! ipfsi 0 ping -n2 -- "$BAD_PEER" > bad_ping_actual 2>&1 &&
|
||||
test_cmp bad_ping_exp bad_ping_actual
|
||||
'
|
||||
|
||||
@ -93,6 +93,10 @@ EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_failure "'ipfs add' with an unregistered hash and wrapped leaves fails without crashing" '
|
||||
ipfs add --hash poseidon-bls12_381-a2-fc1 --raw-leaves=false -r mountdir/planets
|
||||
'
|
||||
|
||||
}
|
||||
|
||||
# should work offline
|
||||
|
||||
BIN
test/sharness/t0109-gateway-web-_redirects-data/redirects.car
Normal file
BIN
test/sharness/t0109-gateway-web-_redirects-data/redirects.car
Normal file
Binary file not shown.
239
test/sharness/t0109-gateway-web-_redirects.sh
Executable file
239
test/sharness/t0109-gateway-web-_redirects.sh
Executable file
@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
test_description="Test HTTP Gateway _redirects support"
|
||||
|
||||
. lib/test-lib.sh
|
||||
|
||||
test_init_ipfs
|
||||
test_launch_ipfs_daemon
|
||||
|
||||
## ============================================================================
|
||||
## Test _redirects file support
|
||||
## ============================================================================
|
||||
|
||||
# Import test case
|
||||
# Run `ipfs cat /ipfs/$REDIRECTS_DIR_CID/_redirects` to see sample _redirects file
|
||||
test_expect_success "Add the _redirects file test directory" '
|
||||
ipfs dag import ../t0109-gateway-web-_redirects-data/redirects.car
|
||||
'
|
||||
CAR_ROOT_CID=QmQyqMY5vUBSbSxyitJqthgwZunCQjDVtNd8ggVCxzuPQ4
|
||||
|
||||
REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples | cut -d "/" -f3)
|
||||
REDIRECTS_DIR_HOSTNAME="${REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/redirect-one redirects with default of 301, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/redirect-one" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /one.html" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/301-redirect-one redirects with 301, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/301-redirect-one" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /one.html" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/302-redirect-two redirects with 302, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/302-redirect-two" > response &&
|
||||
test_should_contain "302 Found" response &&
|
||||
test_should_contain "Location: /two.html" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/200-index returns 200, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/200-index" > response &&
|
||||
test_should_contain "my index" response &&
|
||||
test_should_contain "200 OK" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/posts/:year/:month/:day/:title redirects with 301 and placeholders, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/posts/2022/01/01/hello-world" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /articles/2022/01/01/hello-world" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/splat/one.html redirects with 301 and splat placeholder, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/splat/one.html" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /redirected-splat/one.html" response
|
||||
'
|
||||
|
||||
# ensure custom 4xx works and has the same cache headers as regular /ipfs/ path
|
||||
CUSTOM_4XX_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples/404.html | cut -d "/" -f3)
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/not-found/has-no-redirects-entry returns custom 404, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/not-found/has-no-redirects-entry" > response &&
|
||||
test_should_contain "404 Not Found" response &&
|
||||
test_should_contain "Cache-Control: public, max-age=29030400, immutable" response &&
|
||||
test_should_contain "Etag: \"$CUSTOM_4XX_CID\"" response &&
|
||||
test_should_contain "my 404" response
|
||||
'
|
||||
|
||||
CUSTOM_4XX_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples/410.html | cut -d "/" -f3)
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/gone/has-no-redirects-entry returns custom 410, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/gone/has-no-redirects-entry" > response &&
|
||||
test_should_contain "410 Gone" response &&
|
||||
test_should_contain "Cache-Control: public, max-age=29030400, immutable" response &&
|
||||
test_should_contain "Etag: \"$CUSTOM_4XX_CID\"" response &&
|
||||
test_should_contain "my 410" response
|
||||
'
|
||||
|
||||
CUSTOM_4XX_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples/451.html | cut -d "/" -f3)
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/unavail/has-no-redirects-entry returns custom 451, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/unavail/has-no-redirects-entry" > response &&
|
||||
test_should_contain "451 Unavailable For Legal Reasons" response &&
|
||||
test_should_contain "Cache-Control: public, max-age=29030400, immutable" response &&
|
||||
test_should_contain "Etag: \"$CUSTOM_4XX_CID\"" response &&
|
||||
test_should_contain "my 451" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $REDIRECTS_DIR_HOSTNAME/catch-all returns 200, per _redirects file" '
|
||||
curl -sD - --resolve $REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$REDIRECTS_DIR_HOSTNAME/catch-all" > response &&
|
||||
test_should_contain "200 OK" response &&
|
||||
test_should_contain "my index" response
|
||||
'
|
||||
|
||||
# This test ensures _redirects is supported only on Web Gateways that use Host header (DNSLink, Subdomain)
|
||||
test_expect_success "request for http://127.0.0.1:$GWAY_PORT/ipfs/$REDIRECTS_DIR_CID/301-redirect-one returns generic 404 (no custom 404 from _redirects since no origin isolation)" '
|
||||
curl -sD - "http://127.0.0.1:$GWAY_PORT/ipfs/$REDIRECTS_DIR_CID/301-redirect-one" > response &&
|
||||
test_should_contain "404 Not Found" response &&
|
||||
test_should_not_contain "my 404" response
|
||||
'
|
||||
|
||||
# With CRLF line terminator
|
||||
NEWLINE_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/newlines | cut -d "/" -f3)
|
||||
NEWLINE_REDIRECTS_DIR_HOSTNAME="${NEWLINE_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
|
||||
test_expect_success "newline: _redirects has CRLF line terminators" '
|
||||
ipfs cat /ipfs/$NEWLINE_REDIRECTS_DIR_CID/_redirects | file - > response &&
|
||||
test_should_contain "with CRLF line terminators" response
|
||||
'
|
||||
|
||||
test_expect_success "newline: request for $NEWLINE_REDIRECTS_DIR_HOSTNAME/redirect-one redirects with default of 301, per _redirects file" '
|
||||
curl -sD - --resolve $NEWLINE_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$NEWLINE_REDIRECTS_DIR_HOSTNAME/redirect-one" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /one.html" response
|
||||
'
|
||||
|
||||
# Good codes
|
||||
GOOD_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/good-codes | cut -d "/" -f3)
|
||||
GOOD_REDIRECTS_DIR_HOSTNAME="${GOOD_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
|
||||
test_expect_success "good codes: request for $GOOD_REDIRECTS_DIR_HOSTNAME/redirect-one redirects with default of 301, per _redirects file" '
|
||||
curl -sD - --resolve $GOOD_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$GOOD_REDIRECTS_DIR_HOSTNAME/a301" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /b301" response
|
||||
'
|
||||
|
||||
# Bad codes
|
||||
BAD_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/bad-codes | cut -d "/" -f3)
|
||||
BAD_REDIRECTS_DIR_HOSTNAME="${BAD_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
|
||||
# if accessing a path that doesn't exist, read _redirects and fail parsing, and return error
|
||||
test_expect_success "bad codes: request for $BAD_REDIRECTS_DIR_HOSTNAME/not-found returns error about bad code" '
|
||||
curl -sD - --resolve $BAD_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$BAD_REDIRECTS_DIR_HOSTNAME/not-found" > response &&
|
||||
test_should_contain "500" response &&
|
||||
test_should_contain "status code 999 is not supported" response
|
||||
'
|
||||
|
||||
# if accessing a path that does exist, don't read _redirects and therefore don't fail parsing
|
||||
test_expect_success "bad codes: request for $BAD_REDIRECTS_DIR_HOSTNAME/found.html doesn't return error about bad code" '
|
||||
curl -sD - --resolve $BAD_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$BAD_REDIRECTS_DIR_HOSTNAME/found.html" > response &&
|
||||
test_should_contain "200" response &&
|
||||
test_should_contain "my found" response &&
|
||||
test_should_not_contain "unsupported redirect status" response
|
||||
'
|
||||
|
||||
# Invalid file, containing "hello"
|
||||
INVALID_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/invalid | cut -d "/" -f3)
|
||||
INVALID_REDIRECTS_DIR_HOSTNAME="${INVALID_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
|
||||
# if accessing a path that doesn't exist, read _redirects and fail parsing, and return error
|
||||
test_expect_success "invalid file: request for $INVALID_REDIRECTS_DIR_HOSTNAME/not-found returns error about invalid redirects file" '
|
||||
curl -sD - --resolve $INVALID_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$INVALID_REDIRECTS_DIR_HOSTNAME/not-found" > response &&
|
||||
test_should_contain "500" response &&
|
||||
test_should_contain "could not parse _redirects:" response
|
||||
'
|
||||
|
||||
# Invalid file, containing forced redirect
|
||||
INVALID_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/forced | cut -d "/" -f3)
|
||||
INVALID_REDIRECTS_DIR_HOSTNAME="${INVALID_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
|
||||
# if accessing a path that doesn't exist, read _redirects and fail parsing, and return error
|
||||
test_expect_success "invalid file: request for $INVALID_REDIRECTS_DIR_HOSTNAME/not-found returns error about invalid redirects file" '
|
||||
curl -sD - --resolve $INVALID_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$INVALID_REDIRECTS_DIR_HOSTNAME/not-found" > response &&
|
||||
test_should_contain "500" response &&
|
||||
test_should_contain "could not parse _redirects:" response &&
|
||||
test_should_contain "forced redirects (or \"shadowing\") are not supported" response
|
||||
'
|
||||
|
||||
# if accessing a path that doesn't exist and _redirects file is too large, return error
|
||||
TOO_LARGE_REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/too-large | cut -d "/" -f3)
|
||||
TOO_LARGE_REDIRECTS_DIR_HOSTNAME="${TOO_LARGE_REDIRECTS_DIR_CID}.ipfs.localhost:$GWAY_PORT"
|
||||
test_expect_success "invalid file: request for $TOO_LARGE_REDIRECTS_DIR_HOSTNAME/not-found returns error about too large redirects file" '
|
||||
curl -sD - --resolve $TOO_LARGE_REDIRECTS_DIR_HOSTNAME:127.0.0.1 "http://$TOO_LARGE_REDIRECTS_DIR_HOSTNAME/not-found" > response &&
|
||||
test_should_contain "500" response &&
|
||||
test_should_contain "could not parse _redirects:" response &&
|
||||
test_should_contain "redirects file size cannot exceed" response
|
||||
'
|
||||
|
||||
test_kill_ipfs_daemon
|
||||
|
||||
# disable wildcard DNSLink gateway
|
||||
# and enable it on specific DNSLink hostname
|
||||
ipfs config --json Gateway.NoDNSLink true && \
|
||||
ipfs config --json Gateway.PublicGateways '{
|
||||
"dnslink-enabled-on-fqdn.example.org": {
|
||||
"NoDNSLink": false,
|
||||
"UseSubdomains": false,
|
||||
"Paths": ["/ipfs"]
|
||||
},
|
||||
"dnslink-disabled-on-fqdn.example.com": {
|
||||
"NoDNSLink": true,
|
||||
"UseSubdomains": false,
|
||||
"Paths": []
|
||||
}
|
||||
}' || exit 1
|
||||
|
||||
# DNSLink test requires a daemon in online mode with precached /ipns/ mapping
|
||||
# REDIRECTS_DIR_CID=$(ipfs resolve -r /ipfs/$CAR_ROOT_CID/examples | cut -d "/" -f3)
|
||||
DNSLINK_FQDN="dnslink-enabled-on-fqdn.example.org"
|
||||
NO_DNSLINK_FQDN="dnslink-disabled-on-fqdn.example.com"
|
||||
export IPFS_NS_MAP="$DNSLINK_FQDN:/ipfs/$REDIRECTS_DIR_CID"
|
||||
|
||||
# restart daemon to apply config changes
|
||||
test_launch_ipfs_daemon
|
||||
|
||||
# make sure test setup is valid (fail if CoreAPI is unable to resolve)
|
||||
test_expect_success "spoofed DNSLink record resolves in cli" "
|
||||
ipfs resolve /ipns/$DNSLINK_FQDN > result &&
|
||||
test_should_contain \"$REDIRECTS_DIR_CID\" result &&
|
||||
ipfs cat /ipns/$DNSLINK_FQDN/_redirects > result &&
|
||||
test_should_contain \"index.html\" result
|
||||
"
|
||||
|
||||
test_expect_success "request for $DNSLINK_FQDN/redirect-one redirects with default of 301, per _redirects file" '
|
||||
curl -sD - --resolve $DNSLINK_FQDN:$GWAY_PORT:127.0.0.1 "http://$DNSLINK_FQDN:$GWAY_PORT/redirect-one" > response &&
|
||||
test_should_contain "301 Moved Permanently" response &&
|
||||
test_should_contain "Location: /one.html" response
|
||||
'
|
||||
|
||||
# ensure custom 404 works and has the same cache headers as regular /ipns/ paths
|
||||
test_expect_success "request for $DNSLINK_FQDN/en/has-no-redirects-entry returns custom 404, per _redirects file" '
|
||||
curl -sD - --resolve $DNSLINK_FQDN:$GWAY_PORT:127.0.0.1 "http://$DNSLINK_FQDN:$GWAY_PORT/not-found/has-no-redirects-entry" > response &&
|
||||
test_should_contain "404 Not Found" response &&
|
||||
test_should_contain "Etag: \"Qmd9GD7Bauh6N2ZLfNnYS3b7QVAijbud83b8GE8LPMNBBP\"" response &&
|
||||
test_should_not_contain "Cache-Control: public, max-age=29030400, immutable" response &&
|
||||
test_should_not_contain "immutable" response &&
|
||||
test_should_contain "Date: " response &&
|
||||
test_should_contain "my 404" response
|
||||
'
|
||||
|
||||
test_expect_success "request for $NO_DNSLINK_FQDN/redirect-one does not redirect, since DNSLink is disabled" '
|
||||
curl -sD - --resolve $NO_DNSLINK_FQDN:$GWAY_PORT:127.0.0.1 "http://$NO_DNSLINK_FQDN:$GWAY_PORT/redirect-one" > response &&
|
||||
test_should_not_contain "one.html" response &&
|
||||
test_should_not_contain "301 Moved Permanently" response &&
|
||||
test_should_not_contain "Location:" response
|
||||
'
|
||||
|
||||
test_kill_ipfs_daemon
|
||||
|
||||
test_done
|
||||
@ -323,6 +323,38 @@ test_localhost_gateway_response_should_contain \
|
||||
"http://api.localhost:$GWAY_PORT/api/v0/refs?arg=$DIR_CID&r=true" \
|
||||
"Ref"
|
||||
|
||||
## ============================================================================
|
||||
## Test DNSLink inlining on HTTP gateways
|
||||
## ============================================================================
|
||||
|
||||
# set explicit subdomain gateway config for the hostname
|
||||
ipfs config --json Gateway.PublicGateways '{
|
||||
"localhost": {
|
||||
"UseSubdomains": true,
|
||||
"InlineDNSLink": true,
|
||||
"Paths": ["/ipfs", "/ipns", "/api"]
|
||||
},
|
||||
"example.com": {
|
||||
"UseSubdomains": true,
|
||||
"InlineDNSLink": true,
|
||||
"Paths": ["/ipfs", "/ipns", "/api"]
|
||||
}
|
||||
}' || exit 1
|
||||
# restart daemon to apply config changes
|
||||
test_kill_ipfs_daemon
|
||||
test_launch_ipfs_daemon_without_network
|
||||
|
||||
test_localhost_gateway_response_should_contain \
|
||||
"request for localhost/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \
|
||||
"http://localhost:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \
|
||||
"Location: http://en-wikipedia--on--ipfs-org.ipns.localhost:$GWAY_PORT/wiki"
|
||||
|
||||
test_hostname_gateway_response_should_contain \
|
||||
"request for example.com/ipns/{fqdn} redirects to DNSLink in subdomain with DNS inlining" \
|
||||
"example.com" \
|
||||
"http://127.0.0.1:$GWAY_PORT/ipns/en.wikipedia-on-ipfs.org/wiki" \
|
||||
"Location: http://en-wikipedia--on--ipfs-org.ipns.example.com/wiki"
|
||||
|
||||
## ============================================================================
|
||||
## Test subdomain-based requests with a custom hostname config
|
||||
## (origin per content root at http://*.example.com)
|
||||
|
||||
@ -159,10 +159,6 @@ flatfs_datastore_sync_latency_seconds_bucket
|
||||
flatfs_datastore_sync_latency_seconds_count
|
||||
flatfs_datastore_sync_latency_seconds_sum
|
||||
flatfs_datastore_sync_total
|
||||
go_cgo_go_to_c_calls_calls_total
|
||||
go_gc_cycles_automatic_gc_cycles_total
|
||||
go_gc_cycles_forced_gc_cycles_total
|
||||
go_gc_cycles_total_gc_cycles_total
|
||||
go_gc_duration_seconds
|
||||
go_gc_duration_seconds
|
||||
go_gc_duration_seconds
|
||||
@ -170,77 +166,12 @@ go_gc_duration_seconds
|
||||
go_gc_duration_seconds
|
||||
go_gc_duration_seconds_count
|
||||
go_gc_duration_seconds_sum
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_bucket
|
||||
go_gc_heap_allocs_by_size_bytes_total_count
|
||||
go_gc_heap_allocs_by_size_bytes_total_sum
|
||||
go_gc_heap_allocs_bytes_total
|
||||
go_gc_heap_allocs_objects_total
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_bucket
|
||||
go_gc_heap_frees_by_size_bytes_total_count
|
||||
go_gc_heap_frees_by_size_bytes_total_sum
|
||||
go_gc_heap_frees_bytes_total
|
||||
go_gc_heap_frees_objects_total
|
||||
go_gc_heap_goal_bytes
|
||||
go_gc_heap_objects_objects
|
||||
go_gc_heap_tiny_allocs_objects_total
|
||||
go_gc_limiter_last_enabled_gc_cycle
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_bucket
|
||||
go_gc_pauses_seconds_total_count
|
||||
go_gc_pauses_seconds_total_sum
|
||||
go_gc_stack_starting_size_bytes
|
||||
go_goroutines
|
||||
go_info
|
||||
go_memory_classes_heap_free_bytes
|
||||
go_memory_classes_heap_objects_bytes
|
||||
go_memory_classes_heap_released_bytes
|
||||
go_memory_classes_heap_stacks_bytes
|
||||
go_memory_classes_heap_unused_bytes
|
||||
go_memory_classes_metadata_mcache_free_bytes
|
||||
go_memory_classes_metadata_mcache_inuse_bytes
|
||||
go_memory_classes_metadata_mspan_free_bytes
|
||||
go_memory_classes_metadata_mspan_inuse_bytes
|
||||
go_memory_classes_metadata_other_bytes
|
||||
go_memory_classes_os_stacks_bytes
|
||||
go_memory_classes_other_bytes
|
||||
go_memory_classes_profiling_buckets_bytes
|
||||
go_memory_classes_total_bytes
|
||||
go_memstats_alloc_bytes
|
||||
go_memstats_alloc_bytes_total
|
||||
go_memstats_buck_hash_sys_bytes
|
||||
go_memstats_frees_total
|
||||
go_memstats_gc_cpu_fraction
|
||||
go_memstats_gc_sys_bytes
|
||||
go_memstats_heap_alloc_bytes
|
||||
go_memstats_heap_idle_bytes
|
||||
@ -260,21 +191,6 @@ go_memstats_other_sys_bytes
|
||||
go_memstats_stack_inuse_bytes
|
||||
go_memstats_stack_sys_bytes
|
||||
go_memstats_sys_bytes
|
||||
go_sched_gomaxprocs_threads
|
||||
go_sched_goroutines_goroutines
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_bucket
|
||||
go_sched_latencies_seconds_count
|
||||
go_sched_latencies_seconds_sum
|
||||
go_threads
|
||||
ipfs_bitswap_active_block_tasks
|
||||
ipfs_bitswap_active_tasks
|
||||
|
||||
@ -55,6 +55,10 @@ test_expect_success 'ResourceMgr enabled: swarm limit' '
|
||||
jq -e .StreamsOutbound < json
|
||||
'
|
||||
|
||||
test_expect_success 'connected: swarm stats all working properly' '
|
||||
test_expect_code 0 ipfs swarm stats all
|
||||
'
|
||||
|
||||
# every scope has the same fields, so we only inspect System
|
||||
test_expect_success 'ResourceMgr enabled: swarm stats' '
|
||||
ipfs swarm stats all --enc=json | tee json &&
|
||||
|
||||
49
test/sharness/t0191-webtransport-ping.sh
Executable file
49
test/sharness/t0191-webtransport-ping.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
test_description="Test ping over WebTransport command"
|
||||
|
||||
. lib/test-lib.sh
|
||||
|
||||
test_init_ipfs
|
||||
|
||||
# start iptb + wait for peering
|
||||
test_expect_success 'init iptb' '
|
||||
iptb testbed create -type localipfs -count 2 -init
|
||||
'
|
||||
|
||||
addr1='"[\"/ip4/127.0.0.1/udp/0/quic/webtransport\"]"'
|
||||
addr2='"[\"/ip4/127.0.0.1/udp/0/quic/webtransport\"]"'
|
||||
test_expect_success "add WebTransport swarm addresses" '
|
||||
ipfsi 0 config --json Addresses.Swarm '$addr1' &&
|
||||
ipfsi 0 config --json Swarm.Transports.Network.WebTransport true &&
|
||||
ipfsi 1 config --json Addresses.Swarm '$addr2' &&
|
||||
ipfsi 1 config --json Swarm.Transports.Network.WebTransport true
|
||||
'
|
||||
|
||||
startup_cluster 2
|
||||
|
||||
test_expect_success 'peer ids' '
|
||||
PEERID_0=$(iptb attr get 0 id) &&
|
||||
PEERID_1=$(iptb attr get 1 id)
|
||||
'
|
||||
|
||||
test_expect_success "test ping other" '
|
||||
ipfsi 0 ping -n2 -- "$PEERID_1" &&
|
||||
ipfsi 1 ping -n2 -- "$PEERID_0"
|
||||
'
|
||||
|
||||
test_expect_success "test ping self" '
|
||||
test_must_fail ipfsi 0 ping -n2 -- "$PEERID_0" &&
|
||||
test_must_fail ipfsi 1 ping -n2 -- "$PEERID_1"
|
||||
'
|
||||
|
||||
test_expect_success "test ping 0" '
|
||||
test_must_fail ipfsi 0 ping -n0 -- "$PEERID_1" &&
|
||||
test_must_fail ipfsi 1 ping -n0 -- "$PEERID_0"
|
||||
'
|
||||
|
||||
test_expect_success 'stop iptb' '
|
||||
iptb stop
|
||||
'
|
||||
|
||||
test_done
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user