Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add options for record count and timeout for resolving DHT paths #4733

Merged
merged 8 commits into from
Mar 23, 2018
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions core/commands/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -57,11 +58,12 @@ The resolver can recursively resolve:
name := req.Arguments()[0]
resolver := namesys.NewDNSResolver()

depth := 1
if recursive {
depth = namesys.DefaultDepthLimit
ropts := []nsopts.ResolveOpt{}
if !recursive {
ropts = append(ropts, nsopts.Depth(1))
}
output, err := resolver.ResolveN(req.Context(), name, depth)

output, err := resolver.Resolve(req.Context(), name, ropts...)
if err == namesys.ErrResolveFailed {
res.SetError(err, cmdkit.ErrNotFound)
return
Expand Down
21 changes: 16 additions & 5 deletions core/commands/ipns.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"errors"
"io"
"strings"
"time"

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"
Expand Down Expand Up @@ -57,9 +59,10 @@ Resolve the value of a dnslink:
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name."),
cmdkit.BoolOption("nocache", "n", "Do not use cached entries."),
cmdkit.UintOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
cmdkit.UintOption("dht-timeout", "dhtt", "Timeout in seconds for DHT resolution. Pass 0 for no timeout."),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I might be missing something but IPFS commands have a timeout flag (e.g., ipfs --timeout=30s). And we can always set a DHT resolution timeout by setting a timeout on the context. What's the usecase for the additional timeout?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use case is that with --dht-timeout the DHT collects as many values as it can within the timeout, and then returns the best value it has found. The global IPFS command --timeout will simply kill the command:

> ./cmd/ipfs/ipfs name resolve --timeout=5s QmSgxPeqLrnM1ZB1pno3tYMQfqLB4cWXuAQNfSWsk77apK
Error: Post http://127.0.0.1:5001/api/v0/name/resolve?arg=QmSgxPeqLrnM1ZB1pno3tYMQfqLB4cWXuAQNfSWsk77apK&encoding=json&stream-channels=true&timeout=5s: context deadline exceeded
> ./cmd/ipfs/ipfs name resolve --dhtt=5 QmSgxPeqLrnM1ZB1pno3tYMQfqLB4cWXuAQNfSWsk77apK
/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better for the --dht-timeout parameter to take a string though, eg --dht-timeout=5s instead of assuming seconds eg --dht-timeout=5

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. It would be nice to explain that in the help but I can't think of a succinct way of putting it...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dirkmc it will be better for it to parse the time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a commit to parse the time, and changed the parameter description to
Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout
That's the most succinct way I can think of to say it

},
Run: func(req cmds.Request, res cmds.Response) {

n, err := req.InvocContext().GetNode()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
Expand Down Expand Up @@ -107,16 +110,24 @@ Resolve the value of a dnslink:
}

recursive, _, _ := req.Option("recursive").Bool()
depth := 1
if recursive {
depth = namesys.DefaultDepthLimit
rc, rcok, _ := req.Option("dht-record-count").Int()
dhtt, dhttok, _ := req.Option("dht-timeout").Int()
ropts := []nsopts.ResolveOpt{}
if !recursive {
ropts = append(ropts, nsopts.Depth(1))
}
if rcok {
ropts = append(ropts, nsopts.DhtRecordCount(uint(rc)))
}
if dhttok {
ropts = append(ropts, nsopts.DhtTimeout(time.Duration(dhtt)*time.Second))
}

if !strings.HasPrefix(name, "/ipns/") {
name = "/ipns/" + name
}

output, err := resolver.ResolveN(req.Context(), name, depth)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where did the depth arg go?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh nvm, i found it

output, err := resolver.Resolve(req.Context(), name, ropts...)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
Expand Down
15 changes: 14 additions & 1 deletion core/commands/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package commands
import (
"io"
"strings"
"time"

cmds "github.com/ipfs/go-ipfs/commands"
"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"
Expand Down Expand Up @@ -62,6 +64,8 @@ Resolve the value of an IPFS DAG path:
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."),
cmdkit.UintOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
cmdkit.UintOption("dht-timeout", "dhtt", "Timeout in seconds for DHT resolution. Pass 0 for no timeout."),
},
Run: func(req cmds.Request, res cmds.Response) {

Expand All @@ -84,7 +88,16 @@ Resolve the value of an IPFS DAG path:

// the case when ipns is resolved step by step
if strings.HasPrefix(name, "/ipns/") && !recursive {
p, err := n.Namesys.ResolveN(req.Context(), name, 1)
rc, rcok, _ := req.Option("dht-record-count").Int()
dhtt, dhttok, _ := req.Option("dht-timeout").Int()
ropts := []nsopts.ResolveOpt{nsopts.Depth(1)}
if rcok {
ropts = append(ropts, nsopts.DhtRecordCount(uint(rc)))
}
if dhttok {
ropts = append(ropts, nsopts.DhtTimeout(time.Duration(dhtt)*time.Second))
}
p, err := n.Namesys.Resolve(req.Context(), name, ropts...)
// ErrResolveRecursion is fine
if err != nil && err != ns.ErrResolveRecursion {
res.SetError(err, cmdkit.ErrNormal)
Expand Down
13 changes: 7 additions & 6 deletions core/coreapi/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
}

depth := 1
if options.Recursive {
depth = namesys.DefaultDepthLimit
}

if !strings.HasPrefix(name, "/ipns/") {
name = "/ipns/" + name
}

output, err := resolver.ResolveN(ctx, name, depth)
ropts := []nsopts.ResolveOpt{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i prefer writing this as:
var 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
}
Expand Down
7 changes: 2 additions & 5 deletions core/corehttp/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -28,11 +29,7 @@ var emptyDir = "/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"

type mockNamesys map[string]path.Path

func (m mockNamesys) Resolve(ctx context.Context, name string) (value path.Path, err error) {
return m.ResolveN(ctx, name, namesys.DefaultDepthLimit)
}

func (m mockNamesys) ResolveN(ctx context.Context, name string, depth int) (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
Expand Down
8 changes: 5 additions & 3 deletions namesys/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +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) (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, depth int, prefixes ...string) (path.Path, error) {
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)
p, err := r.resolveOnce(ctx, name, options)
if err != nil {
return "", err
}
Expand Down
12 changes: 4 additions & 8 deletions namesys/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -31,13 +32,8 @@ func newDNSResolver() resolver {
}

// Resolve implements Resolver.
func (r *DNSResolver) Resolve(ctx context.Context, name string) (path.Path, error) {
return r.ResolveN(ctx, name, DefaultDepthLimit)
}

// ResolveN implements Resolver.
func (r *DNSResolver) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) {
return resolve(ctx, r, name, depth, "/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 {
Expand All @@ -48,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) (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]

Expand Down
38 changes: 20 additions & 18 deletions namesys/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package namesys
import (
"fmt"
"testing"

opts "github.com/ipfs/go-ipfs/namesys/opts"
)

type mockDNS struct {
Expand Down Expand Up @@ -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)
}
25 changes: 3 additions & 22 deletions namesys/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.")

Expand Down Expand Up @@ -89,17 +79,8 @@ 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 use ResolveN.
Resolve(ctx context.Context, name string) (value path.Path, err error)

// ResolveN performs a recursive lookup, returning the dereferenced
// path. The only difference from Resolve is that the depth limit
// is configurable. You can use DefaultDepthLimit, UnlimitedDepth,
// or a depth limit of your own choosing.
//
// Most users should use Resolve, since the default limit works well
// in most real-world situations.
ResolveN(ctx context.Context, name string, depth int) (value path.Path, err error)
// adjust the limit you can specify it as an option.
Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (value path.Path, err error)
}

// Publisher is an object capable of publishing particular names.
Expand Down
Loading