1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-18 09:17:49 +08:00

coreapi: path remainders

License: MIT
Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
Łukasz Magiera
2018-04-03 14:49:33 +02:00
parent 7ee6194352
commit 9b288560a4
5 changed files with 150 additions and 27 deletions

View File

@ -29,13 +29,14 @@ type Path interface {
// ResolvedPath is a resolved Path
type ResolvedPath interface {
// Cid returns cid referred to by path
// Cid returns the CID referred to by path
Cid() *cid.Cid
// Root returns cid of root path
// Root returns the CID of root path
Root() *cid.Cid
//TODO: Path remainder
// Remainder returns unresolved part of the path
Remainder() string
Path
}

View File

@ -1,7 +1,9 @@
package coreapi
import (
"context"
context "context"
gopath "path"
strings "strings"
core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
@ -24,16 +26,27 @@ type resolvedPath struct {
path
cid *cid.Cid
root *cid.Cid
remainder string
}
// IpfsPath parses the path from `c`, reruns the parsed path.
func (api *CoreAPI) IpfsPath(c *cid.Cid) coreiface.ResolvedPath {
return &resolvedPath{path: path{ipfspath.Path("/ipfs/" + c.String())}, cid: c, root: c}
return &resolvedPath{
path: path{ipfspath.Path("/ipfs/" + c.String())},
cid: c,
root: c,
remainder: "",
}
}
// IpldPath parses the path from `c`, reruns the parsed path.
func (api *CoreAPI) IpldPath(c *cid.Cid) coreiface.ResolvedPath {
return &resolvedPath{path: path{ipfspath.Path("/ipld/" + c.String())}, cid: c, root: c}
return &resolvedPath{
path: path{ipfspath.Path("/ipld/" + c.String())},
cid: c,
root: c,
remainder: "",
}
}
// ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the
@ -66,25 +79,40 @@ func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSyste
return p.(coreiface.ResolvedPath), nil
}
r := &resolver.Resolver{
DAG: ng,
ResolveOnce: uio.ResolveUnixfsOnce,
}
p2 := ipfspath.FromString(p.String())
node, err := core.Resolve(ctx, nsys, r, p2)
ipath := p.(*path).path
ipath, err := core.ResolveIPNS(ctx, nsys, ipath)
if err == core.ErrNoNamesys {
return nil, coreiface.ErrOffline
} else if err != nil {
return nil, err
}
resolveOnce := uio.ResolveUnixfsOnce
if strings.HasPrefix(ipath.String(), "/ipld") {
resolveOnce = resolver.ResolveSingle
}
r := &resolver.Resolver{
DAG: ng,
ResolveOnce: resolveOnce,
}
node, rest, err := r.ResolveToLastNode(ctx, ipath)
if err != nil {
return nil, err
}
var root *cid.Cid
if p2.IsJustAKey() {
if ipath.IsJustAKey() {
root = node.Cid()
}
return &resolvedPath{path: path{p2}, cid: node.Cid(), root: root}, nil
return &resolvedPath{
path: path{ipath},
cid: node.Cid(),
root: root,
remainder: gopath.Join(rest...),
}, nil
}
// ParsePath parses path `p` using ipfspath parser, returns the parsed path.
@ -120,3 +148,7 @@ func (p *resolvedPath) Cid() *cid.Cid {
func (p *resolvedPath) Root() *cid.Cid {
return p.root
}
func (p *resolvedPath) Remainder() string {
return p.remainder
}

View File

@ -32,3 +32,84 @@ func TestMutablePath(t *testing.T) {
t.Error("expected /ipld path to be immutable")
}
}
func TestPathRemainder(t *testing.T) {
ctx := context.Background()
_, api, err := makeAPI(ctx)
if err != nil {
t.Fatal(err)
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
if err != nil {
t.Fatal(err)
}
p1, err := api.ParsePath(obj.String() + "/foo/bar")
if err != nil {
t.Error(err)
}
rp1, err := api.ResolvePath(ctx, p1)
if err != nil {
t.Fatal(err)
}
if rp1.Remainder() != "foo/bar" {
t.Error("expected to get path remainder")
}
}
func TestEmptyPathRemainder(t *testing.T) {
ctx := context.Background()
_, api, err := makeAPI(ctx)
if err != nil {
t.Fatal(err)
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
if err != nil {
t.Fatal(err)
}
if obj.Remainder() != "" {
t.Error("expected the resolved path to not have a remainder")
}
p1, err := api.ParsePath(obj.String())
if err != nil {
t.Error(err)
}
rp1, err := api.ResolvePath(ctx, p1)
if err != nil {
t.Fatal(err)
}
if rp1.Remainder() != "" {
t.Error("expected the resolved path to not have a remainder")
}
}
func TestInvalidPathRemainder(t *testing.T) {
ctx := context.Background()
_, api, err := makeAPI(ctx)
if err != nil {
t.Fatal(err)
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
if err != nil {
t.Fatal(err)
}
p1, err := api.ParsePath(obj.String() + "/bar/baz")
if err != nil {
t.Error(err)
}
_, err = api.ResolvePath(ctx, p1)
if err == nil || err.Error() != "no such link found" {
t.Fatalf("unexpected error: %s", err)
}
}

View File

@ -19,10 +19,8 @@ import (
var ErrNoNamesys = errors.New(
"core/resolve: no Namesys on IpfsNode - can't resolve ipns entry")
// Resolve resolves the given path by parsing out protocol-specific
// entries (e.g. /ipns/<node-key>) and then going through the /ipfs/
// entries and returning the final node.
func Resolve(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver, p path.Path) (ipld.Node, error) {
// ResolveIPNS resolves /ipns paths
func ResolveIPNS(ctx context.Context, nsys namesys.NameSystem, p path.Path) (path.Path, error) {
if strings.HasPrefix(p.String(), "/ipns/") {
evt := log.EventBegin(ctx, "resolveIpnsPath")
defer evt.Done()
@ -31,36 +29,47 @@ func Resolve(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver,
// TODO(cryptix): we should be able to query the local cache for the path
if nsys == nil {
evt.Append(logging.LoggableMap{"error": ErrNoNamesys.Error()})
return nil, ErrNoNamesys
return "", ErrNoNamesys
}
seg := p.Segments()
if len(seg) < 2 || seg[1] == "" { // just "/<protocol/>" without further segments
evt.Append(logging.LoggableMap{"error": path.ErrNoComponents.Error()})
return nil, path.ErrNoComponents
return "", path.ErrNoComponents
}
extensions := seg[2:]
resolvable, err := path.FromSegments("/", seg[0], seg[1])
if err != nil {
evt.Append(logging.LoggableMap{"error": err.Error()})
return nil, err
return "", err
}
respath, err := nsys.Resolve(ctx, resolvable.String())
if err != nil {
evt.Append(logging.LoggableMap{"error": err.Error()})
return nil, err
return "", err
}
segments := append(respath.Segments(), extensions...)
p, err = path.FromSegments("/", segments...)
if err != nil {
evt.Append(logging.LoggableMap{"error": err.Error()})
return nil, err
return "", err
}
}
return p, nil
}
// Resolve resolves the given path by parsing out protocol-specific
// entries (e.g. /ipns/<node-key>) and then going through the /ipfs/
// entries and returning the final node.
func Resolve(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver, p path.Path) (ipld.Node, error) {
p, err := ResolveIPNS(ctx, nsys, p)
if err != nil {
return nil, err
}
// ok, we have an IPFS path now (or what we'll treat as one)
return r.ResolvePath(ctx, p)

View File

@ -161,7 +161,7 @@ func SplitList(pth string) []string {
// must be a Multihash) and return it separately.
func SplitAbsPath(fpath Path) (*cid.Cid, []string, error) {
parts := fpath.Segments()
if parts[0] == "ipfs" {
if parts[0] == "ipfs" || parts[0] == "ipld" {
parts = parts[1:]
}