From e8f79c88036362d99d2b06e3fa7fae974090cd6f Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Wed, 28 Feb 2018 16:57:24 -0500 Subject: [PATCH] Use variadic options License: MIT Signed-off-by: Dirk McCormick --- core/commands/dns.go | 8 ++-- core/commands/ipns.go | 11 ++--- core/commands/resolve.go | 10 ++--- core/coreapi/name.go | 13 +++--- core/corehttp/gateway_test.go | 3 +- core/corehttp/ipns_hostname.go | 3 +- core/pathresolver.go | 2 +- fuse/ipns/ipns_unix.go | 2 +- namesys/base.go | 9 ++-- namesys/dns.go | 7 ++-- namesys/dns_test.go | 38 +++++++++-------- namesys/interface.go | 14 +------ namesys/ipns_validate_test.go | 11 ++--- namesys/namesys.go | 15 +++---- namesys/namesys_test.go | 17 ++++---- namesys/opts.go | 29 ------------- namesys/opts/opts.go | 68 +++++++++++++++++++++++++++++++ namesys/proquint.go | 7 ++-- namesys/pubsub.go | 7 ++-- namesys/pubsub_test.go | 4 +- namesys/republisher/repub_test.go | 4 +- namesys/resolve_test.go | 4 +- namesys/routing.go | 17 ++++---- 23 files changed, 172 insertions(+), 131 deletions(-) delete mode 100644 namesys/opts.go create mode 100644 namesys/opts/opts.go diff --git a/core/commands/dns.go b/core/commands/dns.go index 3eec2898b..5ab03093a 100644 --- a/core/commands/dns.go +++ b/core/commands/dns.go @@ -7,6 +7,7 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" e "github.com/ipfs/go-ipfs/core/commands/e" namesys "github.com/ipfs/go-ipfs/namesys" + nsopts "github.com/ipfs/go-ipfs/namesys/opts" "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" ) @@ -57,11 +58,12 @@ The resolver can recursively resolve: name := req.Arguments()[0] resolver := namesys.NewDNSResolver() - opts := namesys.DefaultResolveOpts() + ropts := []nsopts.ResolveOpt{} if !recursive { - opts.Depth = 1 + ropts = append(ropts, nsopts.Depth(1)) } - output, err := resolver.Resolve(req.Context(), name, opts) + + output, err := resolver.Resolve(req.Context(), name, ropts...) if err == namesys.ErrResolveFailed { res.SetError(err, cmdkit.ErrNotFound) return diff --git a/core/commands/ipns.go b/core/commands/ipns.go index 70166e967..b84486f2a 100644 --- a/core/commands/ipns.go +++ b/core/commands/ipns.go @@ -9,6 +9,7 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" e "github.com/ipfs/go-ipfs/core/commands/e" namesys "github.com/ipfs/go-ipfs/namesys" + nsopts "github.com/ipfs/go-ipfs/namesys/opts" offline "gx/ipfs/QmZRcGYvxdauCd7hHnMYLYqcZRaDjv24c7eUNyJojAcdBb/go-ipfs-routing/offline" "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" @@ -111,22 +112,22 @@ Resolve the value of a dnslink: recursive, _, _ := req.Option("recursive").Bool() rc, rcok, _ := req.Option("dht-record-count").Int() dhtt, dhttok, _ := req.Option("dht-timeout").Int() - opts := namesys.DefaultResolveOpts() + ropts := []nsopts.ResolveOpt{} if !recursive { - opts.Depth = 1 + ropts = append(ropts, nsopts.Depth(1)) } if rcok { - opts.DhtRecordCount = uint(rc) + ropts = append(ropts, nsopts.DhtRecordCount(uint(rc))) } if dhttok { - opts.DhtTimeout = time.Duration(dhtt) * time.Second + ropts = append(ropts, nsopts.DhtTimeout(time.Duration(dhtt)*time.Second)) } if !strings.HasPrefix(name, "/ipns/") { name = "/ipns/" + name } - output, err := resolver.Resolve(req.Context(), name, opts) + output, err := resolver.Resolve(req.Context(), name, ropts...) if err != nil { res.SetError(err, cmdkit.ErrNormal) return diff --git a/core/commands/resolve.go b/core/commands/resolve.go index f1ce604af..aa282342e 100644 --- a/core/commands/resolve.go +++ b/core/commands/resolve.go @@ -9,6 +9,7 @@ import ( "github.com/ipfs/go-ipfs/core" e "github.com/ipfs/go-ipfs/core/commands/e" ns "github.com/ipfs/go-ipfs/namesys" + nsopts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit" @@ -89,15 +90,14 @@ Resolve the value of an IPFS DAG path: if strings.HasPrefix(name, "/ipns/") && !recursive { rc, rcok, _ := req.Option("dht-record-count").Int() dhtt, dhttok, _ := req.Option("dht-timeout").Int() - opts := ns.DefaultResolveOpts() - opts.Depth = 1 + ropts := []nsopts.ResolveOpt{nsopts.Depth(1)} if rcok { - opts.DhtRecordCount = uint(rc) + ropts = append(ropts, nsopts.DhtRecordCount(uint(rc))) } if dhttok { - opts.DhtTimeout = time.Duration(dhtt) * time.Second + ropts = append(ropts, nsopts.DhtTimeout(time.Duration(dhtt)*time.Second)) } - p, err := n.Namesys.Resolve(req.Context(), name, opts) + p, err := n.Namesys.Resolve(req.Context(), name, ropts...) // ErrResolveRecursion is fine if err != nil && err != ns.ErrResolveRecursion { res.SetError(err, cmdkit.ErrNormal) diff --git a/core/coreapi/name.go b/core/coreapi/name.go index 4ca7df0a3..817fb000a 100644 --- a/core/coreapi/name.go +++ b/core/coreapi/name.go @@ -12,6 +12,7 @@ import ( caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options" keystore "github.com/ipfs/go-ipfs/keystore" namesys "github.com/ipfs/go-ipfs/namesys" + nsopts "github.com/ipfs/go-ipfs/namesys/opts" ipath "github.com/ipfs/go-ipfs/path" offline "gx/ipfs/QmZRcGYvxdauCd7hHnMYLYqcZRaDjv24c7eUNyJojAcdBb/go-ipfs-routing/offline" @@ -117,16 +118,16 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam resolver = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), 0) } - ropts := namesys.DefaultResolveOpts() - if !options.Recursive { - ropts.Depth = 1 - } - if !strings.HasPrefix(name, "/ipns/") { name = "/ipns/" + name } - output, err := resolver.Resolve(ctx, name, ropts) + ropts := []nsopts.ResolveOpt{} + if !options.Recursive { + ropts = append(ropts, nsopts.Depth(1)) + } + + output, err := resolver.Resolve(ctx, name, ropts...) if err != nil { return nil, err } diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index e5d328ded..d91bb7cff 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -14,6 +14,7 @@ import ( coreunix "github.com/ipfs/go-ipfs/core/coreunix" dag "github.com/ipfs/go-ipfs/merkledag" namesys "github.com/ipfs/go-ipfs/namesys" + nsopts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" repo "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" @@ -28,7 +29,7 @@ var emptyDir = "/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn" type mockNamesys map[string]path.Path -func (m mockNamesys) Resolve(ctx context.Context, name string, opts *namesys.ResolveOpts) (value path.Path, err error) { +func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) { p, ok := m[name] if !ok { return "", namesys.ErrResolveFailed diff --git a/core/corehttp/ipns_hostname.go b/core/corehttp/ipns_hostname.go index a8e534ece..6a36bd8c4 100644 --- a/core/corehttp/ipns_hostname.go +++ b/core/corehttp/ipns_hostname.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/ipfs/go-ipfs/core" - namesys "github.com/ipfs/go-ipfs/namesys" isd "gx/ipfs/QmZmmuAXgX73UQmX1jRKjTGmjzq24Jinqkq8vzkBtno4uX/go-is-domain" ) @@ -25,7 +24,7 @@ func IPNSHostnameOption() ServeOption { host := strings.SplitN(r.Host, ":", 2)[0] if len(host) > 0 && isd.IsDomain(host) { name := "/ipns/" + host - if _, err := n.Namesys.Resolve(ctx, name, namesys.DefaultResolveOpts()); err == nil { + if _, err := n.Namesys.Resolve(ctx, name); err == nil { r.Header["X-Ipns-Original-Path"] = []string{r.URL.Path} r.URL.Path = name + r.URL.Path } diff --git a/core/pathresolver.go b/core/pathresolver.go index 46c14cb24..2e873509a 100644 --- a/core/pathresolver.go +++ b/core/pathresolver.go @@ -48,7 +48,7 @@ func Resolve(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver, return nil, err } - respath, err := nsys.Resolve(ctx, resolvable.String(), namesys.DefaultResolveOpts()) + respath, err := nsys.Resolve(ctx, resolvable.String()) if err != nil { evt.Append(logging.LoggableMap{"error": err.Error()}) return nil, err diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index 65cd93d9b..6b1836731 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -203,7 +203,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 - resolved, err := s.Ipfs.Namesys.Resolve(s.Ipfs.Context(), name, namesys.DefaultResolveOpts()) + resolved, err := s.Ipfs.Namesys.Resolve(s.Ipfs.Context(), name) if err != nil { log.Warningf("ipns: namesys resolve error: %s", err) return nil, fuse.ENOENT diff --git a/namesys/base.go b/namesys/base.go index 574de9b7a..a301a5a61 100644 --- a/namesys/base.go +++ b/namesys/base.go @@ -5,19 +5,20 @@ import ( context "context" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" ) type resolver interface { // resolveOnce looks up a name once (without recursion). - resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (value path.Path, err error) + resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (value path.Path, err error) } // resolve is a helper for implementing Resolver.ResolveN using resolveOnce. -func resolve(ctx context.Context, r resolver, name string, opts *ResolveOpts, prefixes ...string) (path.Path, error) { - depth := opts.Depth +func resolve(ctx context.Context, r resolver, name string, options *opts.ResolveOpts, prefixes ...string) (path.Path, error) { + depth := options.Depth for { - p, err := r.resolveOnce(ctx, name, opts) + p, err := r.resolveOnce(ctx, name, options) if err != nil { return "", err } diff --git a/namesys/dns.go b/namesys/dns.go index c58f0ea24..6d74e5221 100644 --- a/namesys/dns.go +++ b/namesys/dns.go @@ -6,6 +6,7 @@ import ( "net" "strings" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" isd "gx/ipfs/QmZmmuAXgX73UQmX1jRKjTGmjzq24Jinqkq8vzkBtno4uX/go-is-domain" ) @@ -31,8 +32,8 @@ func newDNSResolver() resolver { } // Resolve implements Resolver. -func (r *DNSResolver) Resolve(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { - return resolve(ctx, r, name, opts, "/ipns/") +func (r *DNSResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) { + return resolve(ctx, r, name, opts.ProcessOpts(options), "/ipns/") } type lookupRes struct { @@ -43,7 +44,7 @@ type lookupRes struct { // resolveOnce implements resolver. // TXT records for a given domain name should contain a b58 // encoded multihash. -func (r *DNSResolver) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (r *DNSResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) { segments := strings.SplitN(name, "/", 2) domain := segments[0] diff --git a/namesys/dns_test.go b/namesys/dns_test.go index 9b11845ac..1a3110c9b 100644 --- a/namesys/dns_test.go +++ b/namesys/dns_test.go @@ -3,6 +3,8 @@ package namesys import ( "fmt" "testing" + + opts "github.com/ipfs/go-ipfs/namesys/opts" ) type mockDNS struct { @@ -128,33 +130,33 @@ func newMockDNS() *mockDNS { func TestDNSResolution(t *testing.T) { mock := newMockDNS() r := &DNSResolver{lookupTXT: mock.lookupTXT} - testResolution(t, r, "multihash.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) - testResolution(t, r, "ipfs.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) - testResolution(t, r, "dipfs.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) - testResolution(t, r, "dns1.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "multihash.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "ipfs.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "dipfs.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "dns1.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) testResolution(t, r, "dns1.example.com", 1, "/ipns/ipfs.example.com", ErrResolveRecursion) - testResolution(t, r, "dns2.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "dns2.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) testResolution(t, r, "dns2.example.com", 1, "/ipns/dns1.example.com", ErrResolveRecursion) testResolution(t, r, "dns2.example.com", 2, "/ipns/ipfs.example.com", ErrResolveRecursion) - testResolution(t, r, "multi.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "multi.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) testResolution(t, r, "multi.example.com", 1, "/ipns/dns1.example.com", ErrResolveRecursion) testResolution(t, r, "multi.example.com", 2, "/ipns/ipfs.example.com", ErrResolveRecursion) - testResolution(t, r, "equals.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/=equals", nil) + testResolution(t, r, "equals.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/=equals", nil) testResolution(t, r, "loop1.example.com", 1, "/ipns/loop2.example.com", ErrResolveRecursion) testResolution(t, r, "loop1.example.com", 2, "/ipns/loop1.example.com", ErrResolveRecursion) testResolution(t, r, "loop1.example.com", 3, "/ipns/loop2.example.com", ErrResolveRecursion) - testResolution(t, r, "loop1.example.com", DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion) + testResolution(t, r, "loop1.example.com", opts.DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion) testResolution(t, r, "dloop1.example.com", 1, "/ipns/loop2.example.com", ErrResolveRecursion) testResolution(t, r, "dloop1.example.com", 2, "/ipns/loop1.example.com", ErrResolveRecursion) testResolution(t, r, "dloop1.example.com", 3, "/ipns/loop2.example.com", ErrResolveRecursion) - testResolution(t, r, "dloop1.example.com", DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion) - testResolution(t, r, "bad.example.com", DefaultDepthLimit, "", ErrResolveFailed) - testResolution(t, r, "withsegment.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment", nil) - testResolution(t, r, "withrecsegment.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub", nil) - testResolution(t, r, "withsegment.example.com/test1", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/test1", nil) - testResolution(t, r, "withrecsegment.example.com/test2", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test2", nil) - testResolution(t, r, "withrecsegment.example.com/test3/", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test3/", nil) - testResolution(t, r, "withtrailingrec.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/", nil) - testResolution(t, r, "double.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) - testResolution(t, r, "conflict.example.com", DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjE", nil) + testResolution(t, r, "dloop1.example.com", opts.DefaultDepthLimit, "/ipns/loop1.example.com", ErrResolveRecursion) + testResolution(t, r, "bad.example.com", opts.DefaultDepthLimit, "", ErrResolveFailed) + testResolution(t, r, "withsegment.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment", nil) + testResolution(t, r, "withrecsegment.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub", nil) + testResolution(t, r, "withsegment.example.com/test1", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/test1", nil) + testResolution(t, r, "withrecsegment.example.com/test2", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test2", nil) + testResolution(t, r, "withrecsegment.example.com/test3/", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/subsub/test3/", nil) + testResolution(t, r, "withtrailingrec.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD/sub/segment/", nil) + testResolution(t, r, "double.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", nil) + testResolution(t, r, "conflict.example.com", opts.DefaultDepthLimit, "/ipfs/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjE", nil) } diff --git a/namesys/interface.go b/namesys/interface.go index 8ad84e57f..db2aa0a22 100644 --- a/namesys/interface.go +++ b/namesys/interface.go @@ -35,21 +35,11 @@ import ( context "context" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) -const ( - // DefaultDepthLimit is the default depth limit used by Resolve. - DefaultDepthLimit = 32 - - // UnlimitedDepth allows infinite recursion in ResolveN. You - // probably don't want to use this, but it's here if you absolutely - // trust resolution to eventually complete and can't put an upper - // limit on how many steps it will take. - UnlimitedDepth = 0 -) - // ErrResolveFailed signals an error when attempting to resolve. var ErrResolveFailed = errors.New("Could not resolve name.") @@ -90,7 +80,7 @@ type Resolver interface { // There is a default depth-limit to avoid infinite recursion. Most // users will be fine with this default limit, but if you need to // adjust the limit you can specify it as an option. - Resolve(ctx context.Context, name string, opts *ResolveOpts) (value path.Path, err error) + Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (value path.Path, err error) } // Publisher is an object capable of publishing particular names. diff --git a/namesys/ipns_validate_test.go b/namesys/ipns_validate_test.go index 7e3c285bc..9e72b9fe5 100644 --- a/namesys/ipns_validate_test.go +++ b/namesys/ipns_validate_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" u "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util" @@ -115,7 +116,7 @@ func TestResolverValidation(t *testing.T) { } // Resolve entry - resp, err := resolver.resolveOnce(ctx, id.Pretty(), DefaultResolveOpts()) + resp, err := resolver.resolveOnce(ctx, id.Pretty(), opts.DefaultResolveOpts()) if err != nil { t.Fatal(err) } @@ -136,7 +137,7 @@ func TestResolverValidation(t *testing.T) { } // Record should fail validation because entry is expired - _, err = resolver.resolveOnce(ctx, id.Pretty(), DefaultResolveOpts()) + _, err = resolver.resolveOnce(ctx, id.Pretty(), opts.DefaultResolveOpts()) if err == nil { t.Fatal("ValidateIpnsRecord should have returned error") } @@ -158,7 +159,7 @@ func TestResolverValidation(t *testing.T) { // Record should fail validation because public key defined by // ipns path doesn't match record signature - _, err = resolver.resolveOnce(ctx, id2.Pretty(), DefaultResolveOpts()) + _, err = resolver.resolveOnce(ctx, id2.Pretty(), opts.DefaultResolveOpts()) if err == nil { t.Fatal("ValidateIpnsRecord should have failed signature verification") } @@ -176,7 +177,7 @@ func TestResolverValidation(t *testing.T) { // Record should fail validation because public key is not available // in peer store or on network - _, err = resolver.resolveOnce(ctx, id3.Pretty(), DefaultResolveOpts()) + _, err = resolver.resolveOnce(ctx, id3.Pretty(), opts.DefaultResolveOpts()) if err == nil { t.Fatal("ValidateIpnsRecord should have failed because public key was not found") } @@ -191,7 +192,7 @@ func TestResolverValidation(t *testing.T) { // public key is available in the peer store by looking it up in // the DHT, which causes the DHT to fetch it and cache it in the // peer store - _, err = resolver.resolveOnce(ctx, id3.Pretty(), DefaultResolveOpts()) + _, err = resolver.resolveOnce(ctx, id3.Pretty(), opts.DefaultResolveOpts()) if err != nil { t.Fatal(err) } diff --git a/namesys/namesys.go b/namesys/namesys.go index 0a9cb5283..e47d433a3 100644 --- a/namesys/namesys.go +++ b/namesys/namesys.go @@ -7,6 +7,7 @@ import ( "sync" "time" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" p2phost "gx/ipfs/QmNmJZL7FQySMtE2BQuLMuZg2EB2CLEunJJUSVSc9YnnbV/go-libp2p-host" @@ -67,7 +68,7 @@ func AddPubsubNameSystem(ctx context.Context, ns NameSystem, host p2phost.Host, const DefaultResolverCacheTTL = time.Minute // Resolve implements Resolver. -func (ns *mpns) Resolve(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (ns *mpns) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) { if strings.HasPrefix(name, "/ipfs/") { return path.ParsePath(name) } @@ -76,11 +77,11 @@ func (ns *mpns) Resolve(ctx context.Context, name string, opts *ResolveOpts) (pa return path.ParsePath("/ipfs/" + name) } - return resolve(ctx, ns, name, opts, "/ipns/") + return resolve(ctx, ns, name, opts.ProcessOpts(options), "/ipns/") } // resolveOnce implements resolver. -func (ns *mpns) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (ns *mpns) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) { if !strings.HasPrefix(name, "/ipns/") { name = "/ipns/" + name } @@ -109,7 +110,7 @@ func (ns *mpns) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) if err == nil { res, ok := ns.resolvers["pubsub"] if ok { - p, err := res.resolveOnce(ctx, key, opts) + p, err := res.resolveOnce(ctx, key, options) if err == nil { return makePath(p) } @@ -117,7 +118,7 @@ func (ns *mpns) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) res, ok = ns.resolvers["dht"] if ok { - p, err := res.resolveOnce(ctx, key, opts) + p, err := res.resolveOnce(ctx, key, options) if err == nil { return makePath(p) } @@ -129,7 +130,7 @@ func (ns *mpns) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) if isd.IsDomain(key) { res, ok := ns.resolvers["dns"] if ok { - p, err := res.resolveOnce(ctx, key, opts) + p, err := res.resolveOnce(ctx, key, options) if err == nil { return makePath(p) } @@ -140,7 +141,7 @@ func (ns *mpns) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) res, ok := ns.resolvers["proquint"] if ok { - p, err := res.resolveOnce(ctx, key, opts) + p, err := res.resolveOnce(ctx, key, options) if err == nil { return makePath(p) } diff --git a/namesys/namesys_test.go b/namesys/namesys_test.go index 59d544fd8..7cc4b780c 100644 --- a/namesys/namesys_test.go +++ b/namesys/namesys_test.go @@ -6,6 +6,7 @@ import ( context "context" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" "github.com/ipfs/go-ipfs/unixfs" @@ -20,9 +21,7 @@ type mockResolver struct { } func testResolution(t *testing.T, resolver Resolver, name string, depth uint, expected string, expError error) { - opts := DefaultResolveOpts() - opts.Depth = depth - p, err := resolver.Resolve(context.Background(), name, opts) + p, err := resolver.Resolve(context.Background(), name, opts.Depth(depth)) if err != expError { t.Fatal(fmt.Errorf( "Expected %s with a depth of %d to have a '%s' error, but got '%s'", @@ -35,7 +34,7 @@ func testResolution(t *testing.T, resolver Resolver, name string, depth uint, ex } } -func (r *mockResolver) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (r *mockResolver) resolveOnce(ctx context.Context, name string, opts *opts.ResolveOpts) (path.Path, error) { return path.ParsePath(r.entries[name]) } @@ -65,14 +64,14 @@ func TestNamesysResolution(t *testing.T) { }, } - testResolution(t, r, "Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) - testResolution(t, r, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) - testResolution(t, r, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) + testResolution(t, r, "Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) + testResolution(t, r, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) + testResolution(t, r, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) testResolution(t, r, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", 1, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", ErrResolveRecursion) - testResolution(t, r, "/ipns/ipfs.io", DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) + testResolution(t, r, "/ipns/ipfs.io", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) testResolution(t, r, "/ipns/ipfs.io", 1, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", ErrResolveRecursion) testResolution(t, r, "/ipns/ipfs.io", 2, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", ErrResolveRecursion) - testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) + testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil) testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", 1, "/ipns/ipfs.io", ErrResolveRecursion) testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", 2, "/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", ErrResolveRecursion) testResolution(t, r, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", 3, "/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy", ErrResolveRecursion) diff --git a/namesys/opts.go b/namesys/opts.go deleted file mode 100644 index 2807eecef..000000000 --- a/namesys/opts.go +++ /dev/null @@ -1,29 +0,0 @@ -package namesys - -import ( - "time" -) - -// ResolveOpts specifies options for resolving an IPNS path -type ResolveOpts struct { - // Recursion depth limit - Depth uint - // The number of IPNS records to retrieve from the DHT - // (the best record is selected from this set) - DhtRecordCount uint - // The amount of time to wait for DHT records to be fetched - // and verified. A zero value indicates that there is no explicit - // timeout (although there is an implicit timeout due to dial - // timeouts within the DHT) - DhtTimeout time.Duration -} - -// DefaultResolveOpts returns the default options for resolving -// an IPNS path -func DefaultResolveOpts() *ResolveOpts { - return &ResolveOpts{ - Depth: DefaultDepthLimit, - DhtRecordCount: 16, - DhtTimeout: time.Minute, - } -} diff --git a/namesys/opts/opts.go b/namesys/opts/opts.go new file mode 100644 index 000000000..ff7b44c51 --- /dev/null +++ b/namesys/opts/opts.go @@ -0,0 +1,68 @@ +package namesys_opts + +import ( + "time" +) + +const ( + // DefaultDepthLimit is the default depth limit used by Resolve. + DefaultDepthLimit = 32 + + // UnlimitedDepth allows infinite recursion in Resolve. You + // probably don't want to use this, but it's here if you absolutely + // trust resolution to eventually complete and can't put an upper + // limit on how many steps it will take. + UnlimitedDepth = 0 +) + +// ResolveOpts specifies options for resolving an IPNS path +type ResolveOpts struct { + // Recursion depth limit + Depth uint + // The number of IPNS records to retrieve from the DHT + // (the best record is selected from this set) + DhtRecordCount uint + // The amount of time to wait for DHT records to be fetched + // and verified. A zero value indicates that there is no explicit + // timeout (although there is an implicit timeout due to dial + // timeouts within the DHT) + DhtTimeout time.Duration +} + +// DefaultResolveOpts returns the default options for resolving +// an IPNS path +func DefaultResolveOpts() *ResolveOpts { + return &ResolveOpts{ + Depth: DefaultDepthLimit, + DhtRecordCount: 16, + DhtTimeout: time.Minute, + } +} + +type ResolveOpt func(*ResolveOpts) + +func Depth(depth uint) ResolveOpt { + return func(o *ResolveOpts) { + o.Depth = depth + } +} + +func DhtRecordCount(count uint) ResolveOpt { + return func(o *ResolveOpts) { + o.DhtRecordCount = count + } +} + +func DhtTimeout(timeout time.Duration) ResolveOpt { + return func(o *ResolveOpts) { + o.DhtTimeout = timeout + } +} + +func ProcessOpts(opts []ResolveOpt) *ResolveOpts { + rsopts := DefaultResolveOpts() + for _, option := range opts { + option(rsopts) + } + return rsopts +} diff --git a/namesys/proquint.go b/namesys/proquint.go index 48cb4013d..2c61c98d3 100644 --- a/namesys/proquint.go +++ b/namesys/proquint.go @@ -5,6 +5,7 @@ import ( context "context" + opts "github.com/ipfs/go-ipfs/namesys/opts" path "github.com/ipfs/go-ipfs/path" proquint "gx/ipfs/QmYnf27kzqR2cxt6LFZdrAFJuQd6785fTkBvMuEj9EeRxM/proquint" ) @@ -12,12 +13,12 @@ import ( type ProquintResolver struct{} // Resolve implements Resolver. -func (r *ProquintResolver) Resolve(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { - return resolve(ctx, r, name, opts, "/ipns/") +func (r *ProquintResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) { + return resolve(ctx, r, name, opts.ProcessOpts(options), "/ipns/") } // resolveOnce implements resolver. Decodes the proquint string. -func (r *ProquintResolver) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (r *ProquintResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) { ok, err := proquint.IsProquint(name) if err != nil || !ok { return "", errors.New("not a valid proquint string") diff --git a/namesys/pubsub.go b/namesys/pubsub.go index 856d0ff70..abbf8f0cc 100644 --- a/namesys/pubsub.go +++ b/namesys/pubsub.go @@ -8,6 +8,7 @@ import ( "sync" "time" + opts "github.com/ipfs/go-ipfs/namesys/opts" pb "github.com/ipfs/go-ipfs/namesys/pb" path "github.com/ipfs/go-ipfs/path" @@ -185,11 +186,11 @@ func (p *PubsubPublisher) publishRecord(ctx context.Context, k ci.PrivKey, value } // Resolve resolves a name through pubsub and default depth limit -func (r *PubsubResolver) Resolve(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { - return resolve(ctx, r, name, opts, "/ipns/") +func (r *PubsubResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) { + return resolve(ctx, r, name, opts.ProcessOpts(options), "/ipns/") } -func (r *PubsubResolver) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (r *PubsubResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) { log.Debugf("PubsubResolve: resolve '%s'", name) // retrieve the public key once (for verifying messages) diff --git a/namesys/pubsub_test.go b/namesys/pubsub_test.go index 1d9873ccd..e2cf15b5d 100644 --- a/namesys/pubsub_test.go +++ b/namesys/pubsub_test.go @@ -180,14 +180,14 @@ func TestPubsubPublishSubscribe(t *testing.T) { } func checkResolveNotFound(ctx context.Context, t *testing.T, i int, resolver Resolver, name string) { - _, err := resolver.Resolve(ctx, name, DefaultResolveOpts()) + _, err := resolver.Resolve(ctx, name) if err != ErrResolveFailed { t.Fatalf("[resolver %d] unexpected error: %s", i, err.Error()) } } func checkResolve(ctx context.Context, t *testing.T, i int, resolver Resolver, name string, val path.Path) { - xval, err := resolver.Resolve(ctx, name, DefaultResolveOpts()) + xval, err := resolver.Resolve(ctx, name) if err != nil { t.Fatalf("[resolver %d] resolve failed: %s", i, err.Error()) } diff --git a/namesys/republisher/repub_test.go b/namesys/republisher/repub_test.go index 3b20a9a53..580b708de 100644 --- a/namesys/republisher/repub_test.go +++ b/namesys/republisher/repub_test.go @@ -98,7 +98,7 @@ func verifyResolution(nodes []*core.IpfsNode, key string, exp path.Path) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() for _, n := range nodes { - val, err := n.Namesys.Resolve(ctx, key, namesys.DefaultResolveOpts()) + val, err := n.Namesys.Resolve(ctx, key) if err != nil { return err } @@ -114,7 +114,7 @@ func verifyResolutionFails(nodes []*core.IpfsNode, key string) error { ctx, cancel := context.WithCancel(context.Background()) defer cancel() for _, n := range nodes { - _, err := n.Namesys.Resolve(ctx, key, namesys.DefaultResolveOpts()) + _, err := n.Namesys.Resolve(ctx, key) if err == nil { return errors.New("expected resolution to fail") } diff --git a/namesys/resolve_test.go b/namesys/resolve_test.go index 28e9c80bb..a55d5a4d4 100644 --- a/namesys/resolve_test.go +++ b/namesys/resolve_test.go @@ -40,7 +40,7 @@ func TestRoutingResolve(t *testing.T) { t.Fatal(err) } - res, err := resolver.Resolve(context.Background(), pid.Pretty(), DefaultResolveOpts()) + res, err := resolver.Resolve(context.Background(), pid.Pretty()) if err != nil { t.Fatal(err) } @@ -125,7 +125,7 @@ func TestPrexistingRecord(t *testing.T) { } func verifyCanResolve(r Resolver, name string, exp path.Path) error { - res, err := r.Resolve(context.Background(), name, DefaultResolveOpts()) + res, err := r.Resolve(context.Background(), name) if err != nil { return err } diff --git a/namesys/routing.go b/namesys/routing.go index ca87292d7..29b26cdbd 100644 --- a/namesys/routing.go +++ b/namesys/routing.go @@ -5,6 +5,7 @@ import ( "strings" "time" + opts "github.com/ipfs/go-ipfs/namesys/opts" pb "github.com/ipfs/go-ipfs/namesys/pb" path "github.com/ipfs/go-ipfs/path" @@ -104,23 +105,23 @@ func NewRoutingResolver(route routing.ValueStore, cachesize int) *routingResolve } // Resolve implements Resolver. -func (r *routingResolver) Resolve(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { - return resolve(ctx, r, name, opts, "/ipns/") +func (r *routingResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) { + return resolve(ctx, r, name, opts.ProcessOpts(options), "/ipns/") } // resolveOnce implements resolver. Uses the IPFS routing system to // resolve SFS-like names. -func (r *routingResolver) resolveOnce(ctx context.Context, name string, opts *ResolveOpts) (path.Path, error) { +func (r *routingResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) { log.Debugf("RoutingResolver resolving %s", name) cached, ok := r.cacheGet(name) if ok { return cached, nil } - if opts.DhtTimeout != 0 { + if options.DhtTimeout != 0 { // Resolution must complete within the timeout var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, opts.DhtTimeout) + ctx, cancel = context.WithTimeout(ctx, options.DhtTimeout) defer cancel() } @@ -153,7 +154,7 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string, opts *Re // Note that the DHT will call the ipns validator when retrieving // the value, which in turn verifies the ipns record signature _, ipnsKey := IpnsKeysForID(pid) - val, err := r.getValue(ctx, ipnsKey, opts) + val, err := r.getValue(ctx, ipnsKey, options) if err != nil { log.Debugf("RoutingResolver: dht get for name %s failed: %s", name, err) return "", err @@ -186,9 +187,9 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string, opts *Re } } -func (r *routingResolver) getValue(ctx context.Context, ipnsKey string, opts *ResolveOpts) ([]byte, error) { +func (r *routingResolver) getValue(ctx context.Context, ipnsKey string, options *opts.ResolveOpts) ([]byte, error) { // Get specified number of values from the DHT - vals, err := r.routing.GetValues(ctx, ipnsKey, int(opts.DhtRecordCount)) + vals, err := r.routing.GetValues(ctx, ipnsKey, int(options.DhtRecordCount)) if err != nil { return nil, err }