Use variadic options

License: MIT
Signed-off-by: Dirk McCormick <dirkmdev@gmail.com>
This commit is contained in:
Dirk McCormick 2018-02-28 16:57:24 -05:00
parent 5096025df2
commit e8f79c8803
23 changed files with 172 additions and 131 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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]

View File

@ -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)
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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,
}
}

68
namesys/opts/opts.go Normal file
View File

@ -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
}

View File

@ -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")

View File

@ -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)

View File

@ -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())
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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
}