1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-20 19:19:06 +08:00

Merge pull request #5484 from ipfs/fix/resolve-hamt

resolve: use unixfs ResolveOnce
This commit is contained in:
Steven Allen
2018-09-19 18:41:44 +00:00
committed by GitHub
7 changed files with 80 additions and 80 deletions

View File

@ -2,18 +2,21 @@ package commands
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"strings" "strings"
"time" "time"
cmds "github.com/ipfs/go-ipfs/commands" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/core"
e "github.com/ipfs/go-ipfs/core/commands/e" e "github.com/ipfs/go-ipfs/core/commands/e"
ncmd "github.com/ipfs/go-ipfs/core/commands/name" ncmd "github.com/ipfs/go-ipfs/core/commands/name"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
ns "github.com/ipfs/go-ipfs/namesys" ns "github.com/ipfs/go-ipfs/namesys"
nsopts "github.com/ipfs/go-ipfs/namesys/opts" nsopts "github.com/ipfs/go-ipfs/namesys/opts"
path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path" path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
"gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit" "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
) )
@ -62,12 +65,17 @@ Resolve the value of an IPFS DAG path:
}, },
Options: []cmdkit.Option{ Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."), 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.IntOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."), cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
}, },
Run: func(req cmds.Request, res cmds.Response) { Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
n, err := req.InvocContext().GetNode() n, err := cmdenv.GetNode(env)
if err != nil { if err != nil {
res.SetError(err, cmdkit.ErrNormal) res.SetError(err, cmdkit.ErrNormal)
return return
@ -81,16 +89,19 @@ Resolve the value of an IPFS DAG path:
} }
} }
name := req.Arguments()[0] name := req.Arguments[0]
recursive, _, _ := req.Option("recursive").Bool() recursive, _ := req.Options["recursive"].(bool)
// the case when ipns is resolved step by step // the case when ipns is resolved step by step
if strings.HasPrefix(name, "/ipns/") && !recursive { if strings.HasPrefix(name, "/ipns/") && !recursive {
rc, rcok, _ := req.Option("dht-record-count").Int() rc, rcok := req.Options["dht-record-count"].(uint)
dhtt, dhttok, _ := req.Option("dht-timeout").String() dhtt, dhttok := req.Options["dht-timeout"].(string)
ropts := []nsopts.ResolveOpt{nsopts.Depth(1)} ropts := []options.NameResolveOption{
options.Name.ResolveOption(nsopts.Depth(1)),
}
if rcok { if rcok {
ropts = append(ropts, nsopts.DhtRecordCount(uint(rc))) ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
} }
if dhttok { if dhttok {
d, err := time.ParseDuration(dhtt) d, err := time.ParseDuration(dhtt)
@ -102,48 +113,45 @@ Resolve the value of an IPFS DAG path:
res.SetError(errors.New("DHT timeout value must be >= 0"), cmdkit.ErrNormal) res.SetError(errors.New("DHT timeout value must be >= 0"), cmdkit.ErrNormal)
return return
} }
ropts = append(ropts, nsopts.DhtTimeout(d)) ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
} }
p, err := n.Namesys.Resolve(req.Context(), name, ropts...) p, err := api.Name().Resolve(req.Context, name, ropts...)
// ErrResolveRecursion is fine // ErrResolveRecursion is fine
if err != nil && err != ns.ErrResolveRecursion { if err != nil && err != ns.ErrResolveRecursion {
res.SetError(err, cmdkit.ErrNormal) res.SetError(err, cmdkit.ErrNormal)
return return
} }
res.SetOutput(&ncmd.ResolvedPath{Path: p}) cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path(p.String())})
return return
} }
// else, ipfs path or ipns with recursive flag // else, ipfs path or ipns with recursive flag
p, err := path.ParsePath(name) p, err := coreiface.ParsePath(name)
if err != nil { if err != nil {
res.SetError(err, cmdkit.ErrNormal) res.SetError(err, cmdkit.ErrNormal)
return return
} }
node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, p) rp, err := api.ResolvePath(req.Context, p)
if err != nil { if err != nil {
res.SetError(err, cmdkit.ErrNormal) res.SetError(err, cmdkit.ErrNormal)
return return
} }
c := node.Cid() c := rp.Cid()
res.SetOutput(&ncmd.ResolvedPath{Path: path.FromCid(c)}) cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.FromCid(c)})
}, },
Marshalers: cmds.MarshalerMap{ Encoders: cmds.EncoderMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) { cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
output, ok := v.(*ncmd.ResolvedPath) output, ok := v.(*ncmd.ResolvedPath)
if !ok { if !ok {
return nil, e.TypeErr(output, v) return e.TypeErr(output, v)
} }
return strings.NewReader(output.Path.String() + "\n"), nil
}, fmt.Fprintln(w, output.Path.String())
return nil
}),
}, },
Type: ncmd.ResolvedPath{}, Type: ncmd.ResolvedPath{},
} }

View File

@ -135,7 +135,7 @@ var rootSubcommands = map[string]*cmds.Command{
"ping": lgc.NewCommand(PingCmd), "ping": lgc.NewCommand(PingCmd),
"p2p": lgc.NewCommand(P2PCmd), "p2p": lgc.NewCommand(P2PCmd),
"refs": lgc.NewCommand(RefsCmd), "refs": lgc.NewCommand(RefsCmd),
"resolve": lgc.NewCommand(ResolveCmd), "resolve": ResolveCmd,
"swarm": lgc.NewCommand(SwarmCmd), "swarm": lgc.NewCommand(SwarmCmd),
"tar": lgc.NewCommand(TarCmd), "tar": lgc.NewCommand(TarCmd),
"file": lgc.NewCommand(unixfs.UnixFSCmd), "file": lgc.NewCommand(unixfs.UnixFSCmd),
@ -183,7 +183,7 @@ var rootROSubcommands = map[string]*cmds.Command{
"resolve": dag.DagResolveCmd, "resolve": dag.DagResolveCmd,
}, },
}), }),
"resolve": lgc.NewCommand(ResolveCmd), "resolve": ResolveCmd,
"version": lgc.NewCommand(VersionCmd), "version": lgc.NewCommand(VersionCmd),
} }

View File

@ -2,6 +2,8 @@ package options
import ( import (
"time" "time"
ropts "github.com/ipfs/go-ipfs/namesys/opts"
) )
const ( const (
@ -14,9 +16,10 @@ type NamePublishSettings struct {
} }
type NameResolveSettings struct { type NameResolveSettings struct {
Recursive bool Local bool
Local bool Cache bool
Cache bool
ResolveOpts []ropts.ResolveOpt
} }
type NamePublishOption func(*NamePublishSettings) error type NamePublishOption func(*NamePublishSettings) error
@ -40,9 +43,8 @@ func NamePublishOptions(opts ...NamePublishOption) (*NamePublishSettings, error)
func NameResolveOptions(opts ...NameResolveOption) (*NameResolveSettings, error) { func NameResolveOptions(opts ...NameResolveOption) (*NameResolveSettings, error) {
options := &NameResolveSettings{ options := &NameResolveSettings{
Recursive: false, Local: false,
Local: false, Cache: true,
Cache: true,
} }
for _, opt := range opts { for _, opt := range opts {
@ -80,15 +82,6 @@ func (nameOpts) Key(key string) NamePublishOption {
} }
} }
// Recursive is an option for Name.Resolve which specifies whether to perform a
// recursive lookup. Default value is false
func (nameOpts) Recursive(recursive bool) NameResolveOption {
return func(settings *NameResolveSettings) error {
settings.Recursive = recursive
return nil
}
}
// Local is an option for Name.Resolve which specifies if the lookup should be // Local is an option for Name.Resolve which specifies if the lookup should be
// offline. Default value is false // offline. Default value is false
func (nameOpts) Local(local bool) NameResolveOption { func (nameOpts) Local(local bool) NameResolveOption {
@ -106,3 +99,11 @@ func (nameOpts) Cache(cache bool) NameResolveOption {
return nil return nil
} }
} }
//
func (nameOpts) ResolveOption(opt ropts.ResolveOpt) NameResolveOption {
return func(settings *NameResolveSettings) error {
settings.ResolveOpts = append(settings.ResolveOpts, opt)
return nil
}
}

View File

@ -7,17 +7,16 @@ import (
"strings" "strings"
"time" "time"
core "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options" caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
keystore "github.com/ipfs/go-ipfs/keystore" "github.com/ipfs/go-ipfs/keystore"
namesys "github.com/ipfs/go-ipfs/namesys" "github.com/ipfs/go-ipfs/namesys"
nsopts "github.com/ipfs/go-ipfs/namesys/opts"
ipath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path" ipath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
crypto "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto" "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
peer "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer" "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer"
offline "gx/ipfs/QmSNe4MWVxZWk6UxxW2z2EKofFo4GdFzud1vfn1iVby3mj/go-ipfs-routing/offline" "gx/ipfs/QmSNe4MWVxZWk6UxxW2z2EKofFo4GdFzud1vfn1iVby3mj/go-ipfs-routing/offline"
) )
type NameAPI CoreAPI type NameAPI CoreAPI
@ -119,12 +118,7 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam
name = "/ipns/" + name name = "/ipns/" + name
} }
var ropts []nsopts.ResolveOpt output, err := resolver.Resolve(ctx, name, options.ResolveOpts...)
if !options.Recursive {
ropts = append(ropts, nsopts.Depth(1))
}
output, err := resolver.Resolve(ctx, name, ropts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,53 +1,44 @@
package coreapi package coreapi
import ( import (
context "context" "context"
fmt "fmt" "fmt"
gopath "path" gopath "path"
core "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
namesys "github.com/ipfs/go-ipfs/namesys"
uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io" uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io"
ipfspath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path" ipfspath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path"
resolver "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver" "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid" "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format" ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
) )
// ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the // ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the
// resolved Node. // resolved Node.
func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (ipld.Node, error) { func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (ipld.Node, error) {
return resolveNode(ctx, api.node.DAG, api.node.Namesys, p) rp, err := api.ResolvePath(ctx, p)
}
// ResolvePath resolves the path `p` using Unixfs resolver, returns the
// resolved path.
func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.ResolvedPath, error) {
return resolvePath(ctx, api.node.DAG, api.node.Namesys, p)
}
func resolveNode(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSystem, p coreiface.Path) (ipld.Node, error) {
rp, err := resolvePath(ctx, ng, nsys, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
node, err := ng.Get(ctx, rp.Cid()) node, err := api.node.DAG.Get(ctx, rp.Cid())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return node, nil return node, nil
} }
func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSystem, p coreiface.Path) (coreiface.ResolvedPath, error) { // ResolvePath resolves the path `p` using Unixfs resolver, returns the
// resolved path.
func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.ResolvedPath, error) {
if _, ok := p.(coreiface.ResolvedPath); ok { if _, ok := p.(coreiface.ResolvedPath); ok {
return p.(coreiface.ResolvedPath), nil return p.(coreiface.ResolvedPath), nil
} }
ipath := ipfspath.Path(p.String()) ipath := ipfspath.Path(p.String())
ipath, err := core.ResolveIPNS(ctx, nsys, ipath) ipath, err := core.ResolveIPNS(ctx, api.node.Namesys, ipath)
if err == core.ErrNoNamesys { if err == core.ErrNoNamesys {
return nil, coreiface.ErrOffline return nil, coreiface.ErrOffline
} else if err != nil { } else if err != nil {
@ -66,7 +57,7 @@ func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSyste
} }
r := &resolver.Resolver{ r := &resolver.Resolver{
DAG: ng, DAG: api.node.DAG,
ResolveOnce: resolveOnce, ResolveOnce: resolveOnce,
} }

View File

@ -32,7 +32,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, r io.Reader) (coreiface.ResolvedP
func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) { func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) {
dget := api.node.DAG // TODO: use a session here once routing perf issues are resolved dget := api.node.DAG // TODO: use a session here once routing perf issues are resolved
dagnode, err := resolveNode(ctx, dget, api.node.Namesys, p) dagnode, err := api.core().ResolveNode(ctx, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -84,6 +84,12 @@ test_expect_success "gateway can resolve sharded dirs" '
test_cmp expected actual test_cmp expected actual
' '
test_expect_success "'ipfs resolve' can resolve sharded dirs" '
echo /ipfs/QmZ3RfWk1u5LEGYLHA633B5TNJy3Du27K6Fny9wcxpowGS > expected &&
ipfs resolve "/ipfs/$SHARDED/file100" > actual &&
test_cmp expected actual
'
test_kill_ipfs_daemon test_kill_ipfs_daemon
test_add_large_dir_v1() { test_add_large_dir_v1() {