Skip to content

Commit

Permalink
Merge pull request #3493 from ipfs/feat/coreapi-refinements
Browse files Browse the repository at this point in the history
Core API refinements and efficiency improvements
  • Loading branch information
whyrusleeping authored Mar 22, 2017
2 parents 21072a5 + ee45b8d commit 7dee31b
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 72 deletions.
73 changes: 67 additions & 6 deletions core/coreapi/coreapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,83 @@ import (

core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
path "github.com/ipfs/go-ipfs/path"
ipfspath "github.com/ipfs/go-ipfs/path"

ipld "gx/ipfs/QmYDscK7dmdo2GZ9aumS8s5auUUAH5mR1jvj5pYhWusfK7/go-ipld-node"
cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
)

func resolve(ctx context.Context, n *core.IpfsNode, p string) (ipld.Node, error) {
pp, err := path.ParsePath(p)
type CoreAPI struct {
node *core.IpfsNode
}

func NewCoreAPI(n *core.IpfsNode) coreiface.CoreAPI {
api := &CoreAPI{n}
return api
}

func (api *CoreAPI) Unixfs() coreiface.UnixfsAPI {
return (*UnixfsAPI)(api)
}

func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (coreiface.Node, error) {
p, err := api.ResolvePath(ctx, p)
if err != nil {
return nil, err
}

node, err := api.node.DAG.Get(ctx, p.Cid())
if err != nil {
return nil, err
}
return node, nil
}

dagnode, err := core.Resolve(ctx, n.Namesys, n.Resolver, pp)
// TODO: store all of ipfspath.Resolver.ResolvePathComponents() in Path
func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.Path, error) {
if p.Resolved() {
return p, nil
}

p2 := ipfspath.FromString(p.String())
node, err := core.Resolve(ctx, api.node.Namesys, api.node.Resolver, p2)
if err == core.ErrNoNamesys {
return nil, coreiface.ErrOffline
} else if err != nil {
return nil, err
}
return dagnode, nil

var root *cid.Cid
if p2.IsJustAKey() {
root = node.Cid()
}

return ResolvedPath(p.String(), node.Cid(), root), nil
}

// Implements coreiface.Path
type path struct {
path ipfspath.Path
cid *cid.Cid
root *cid.Cid
}

func ParsePath(p string) (coreiface.Path, error) {
pp, err := ipfspath.ParsePath(p)
if err != nil {
return nil, err
}
return &path{path: pp}, nil
}

func ParseCid(c *cid.Cid) coreiface.Path {
return &path{path: ipfspath.FromCid(c), cid: c, root: c}
}

func ResolvedPath(p string, c *cid.Cid, r *cid.Cid) coreiface.Path {
return &path{path: ipfspath.FromString(p), cid: c, root: r}
}

func (p *path) String() string { return p.path.String() }
func (p *path) Cid() *cid.Cid { return p.cid }
func (p *path) Root() *cid.Cid { return p.root }
func (p *path) Resolved() bool { return p.cid != nil }
26 changes: 18 additions & 8 deletions core/coreapi/interface/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,33 @@ import (
ipld "gx/ipfs/QmYDscK7dmdo2GZ9aumS8s5auUUAH5mR1jvj5pYhWusfK7/go-ipld-node"
)

// type CoreAPI interface {
// ID() CoreID
// Version() CoreVersion
// }
type Path interface {
String() string
Cid() *cid.Cid
Root() *cid.Cid
Resolved() bool
}

// TODO: should we really copy these?
// if we didn't, godoc would generate nice links straight to go-ipld-node
type Node ipld.Node
type Link ipld.Link

type Reader interface {
io.ReadSeeker
io.Closer
}

type CoreAPI interface {
Unixfs() UnixfsAPI
ResolvePath(context.Context, Path) (Path, error)
ResolveNode(context.Context, Path) (Node, error)
}

type UnixfsAPI interface {
Add(context.Context, io.Reader) (*cid.Cid, error)
Cat(context.Context, string) (Reader, error)
Ls(context.Context, string) ([]*Link, error)
Add(context.Context, io.Reader) (Path, error)
Cat(context.Context, Path) (Reader, error)
Ls(context.Context, Path) ([]*Link, error)
}

// type ObjectAPI interface {
Expand All @@ -50,5 +61,4 @@ type UnixfsAPI interface {
// }

var ErrIsDir = errors.New("object is a directory")
var ErrIsNonDag = errors.New("not a merkledag object")
var ErrOffline = errors.New("can't resolve, ipfs node is offline")
30 changes: 15 additions & 15 deletions core/coreapi/unixfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,29 @@ import (
"context"
"io"

core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
uio "github.com/ipfs/go-ipfs/unixfs/io"

cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
)

type UnixfsAPI struct {
node *core.IpfsNode
}

func NewUnixfsAPI(n *core.IpfsNode) coreiface.UnixfsAPI {
api := &UnixfsAPI{n}
return api
}
type UnixfsAPI CoreAPI

func (api *UnixfsAPI) Add(ctx context.Context, r io.Reader) (*cid.Cid, error) {
func (api *UnixfsAPI) Add(ctx context.Context, r io.Reader) (coreiface.Path, error) {
k, err := coreunix.AddWithContext(ctx, api.node, r)
if err != nil {
return nil, err
}
return cid.Decode(k)
c, err := cid.Decode(k)
if err != nil {
return nil, err
}
return ParseCid(c), nil
}

func (api *UnixfsAPI) Cat(ctx context.Context, p string) (coreiface.Reader, error) {
dagnode, err := resolve(ctx, api.node, p)
func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) {
dagnode, err := api.core().ResolveNode(ctx, p)
if err != nil {
return nil, err
}
Expand All @@ -44,8 +40,8 @@ func (api *UnixfsAPI) Cat(ctx context.Context, p string) (coreiface.Reader, erro
return r, nil
}

func (api *UnixfsAPI) Ls(ctx context.Context, p string) ([]*coreiface.Link, error) {
dagnode, err := resolve(ctx, api.node, p)
func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path) ([]*coreiface.Link, error) {
dagnode, err := api.core().ResolveNode(ctx, p)
if err != nil {
return nil, err
}
Expand All @@ -57,3 +53,7 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p string) ([]*coreiface.Link, erro
}
return links, nil
}

func (api *UnixfsAPI) core() coreiface.CoreAPI {
return (*CoreAPI)(api)
}
60 changes: 33 additions & 27 deletions core/coreapi/unixfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import (
)

// `echo -n 'hello, world!' | ipfs add`
var hello = "QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk"
var hello = coreapi.ResolvedPath("/ipfs/QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk", nil, nil)
var helloStr = "hello, world!"

// `ipfs object new unixfs-dir`
var emptyUnixfsDir = "QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"
var emptyDir = coreapi.ResolvedPath("/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn", nil, nil)

// `echo -n | ipfs add`
var emptyUnixfsFile = "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH"
var emptyFile = coreapi.ResolvedPath("/ipfs/QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH", nil, nil)

func makeAPI(ctx context.Context) (*core.IpfsNode, coreiface.UnixfsAPI, error) {
r := &repo.Mock{
Expand All @@ -41,7 +41,7 @@ func makeAPI(ctx context.Context) (*core.IpfsNode, coreiface.UnixfsAPI, error) {
if err != nil {
return nil, nil, err
}
api := coreapi.NewUnixfsAPI(node)
api := coreapi.NewCoreAPI(node).Unixfs()
return node, api, nil
}

Expand All @@ -53,13 +53,13 @@ func TestAdd(t *testing.T) {
}

str := strings.NewReader(helloStr)
c, err := api.Add(ctx, str)
p, err := api.Add(ctx, str)
if err != nil {
t.Error(err)
}

if c.String() != hello {
t.Fatalf("expected CID %s, got: %s", hello, c)
if p.String() != hello.String() {
t.Fatalf("expected path %s, got: %s", hello, p)
}

r, err := api.Cat(ctx, hello)
Expand All @@ -85,13 +85,13 @@ func TestAddEmptyFile(t *testing.T) {
}

str := strings.NewReader("")
c, err := api.Add(ctx, str)
p, err := api.Add(ctx, str)
if err != nil {
t.Error(err)
}

if c.String() != emptyUnixfsFile {
t.Fatalf("expected CID %s, got: %s", hello, c)
if p.String() != emptyFile.String() {
t.Fatalf("expected path %s, got: %s", hello, p)
}
}

Expand All @@ -103,16 +103,17 @@ func TestCatBasic(t *testing.T) {
}

hr := strings.NewReader(helloStr)
k, err := coreunix.Add(node, hr)
p, err := coreunix.Add(node, hr)
if err != nil {
t.Fatal(err)
}
p = "/ipfs/" + p

if k != hello {
t.Fatalf("expected CID %s, got: %s", hello, k)
if p != hello.String() {
t.Fatalf("expected CID %s, got: %s", hello, p)
}

r, err := api.Cat(ctx, k)
r, err := api.Cat(ctx, hello)
if err != nil {
t.Fatal(err)
}
Expand All @@ -139,7 +140,7 @@ func TestCatEmptyFile(t *testing.T) {
t.Fatal(err)
}

r, err := api.Cat(ctx, emptyUnixfsFile)
r, err := api.Cat(ctx, emptyFile)
if err != nil {
t.Fatal(err)
}
Expand All @@ -165,8 +166,13 @@ func TestCatDir(t *testing.T) {
if err != nil {
t.Error(err)
}
p := coreapi.ParseCid(c)

if p.String() != emptyDir.String() {
t.Fatalf("expected path %s, got: %s", emptyDir, p)
}

_, err = api.Cat(ctx, c.String())
_, err = api.Cat(ctx, emptyDir)
if err != coreiface.ErrIsDir {
t.Fatalf("expected ErrIsDir, got: %s", err)
}
Expand All @@ -184,7 +190,7 @@ func TestCatNonUnixfs(t *testing.T) {
t.Error(err)
}

_, err = api.Cat(ctx, c.String())
_, err = api.Cat(ctx, coreapi.ParseCid(c))
if !strings.Contains(err.Error(), "proto: required field") {
t.Fatalf("expected protobuf error, got: %s", err)
}
Expand All @@ -197,7 +203,7 @@ func TestCatOffline(t *testing.T) {
t.Error(err)
}

_, err = api.Cat(ctx, "/ipns/Qmfoobar")
_, err = api.Cat(ctx, coreapi.ResolvedPath("/ipns/Qmfoobar", nil, nil))
if err != coreiface.ErrOffline {
t.Fatalf("expected ErrOffline, got: %", err)
}
Expand All @@ -211,17 +217,17 @@ func TestLs(t *testing.T) {
}

r := strings.NewReader("content-of-file")
p, _, err := coreunix.AddWrapped(node, r, "name-of-file")
k, _, err := coreunix.AddWrapped(node, r, "name-of-file")
if err != nil {
t.Error(err)
}
parts := strings.Split(p, "/")
parts := strings.Split(k, "/")
if len(parts) != 2 {
t.Errorf("unexpected path:", p)
t.Errorf("unexpected path:", k)
}
k := parts[0]
p := coreapi.ResolvedPath("/ipfs/"+parts[0], nil, nil)

links, err := api.Ls(ctx, k)
links, err := api.Ls(ctx, p)
if err != nil {
t.Error(err)
}
Expand All @@ -236,7 +242,7 @@ func TestLs(t *testing.T) {
t.Fatalf("expected name = name-of-file, got %s", links[0].Name)
}
if links[0].Cid.String() != "QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr" {
t.Fatalf("expected cid = QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr, got %s", links[0].Cid.String())
t.Fatalf("expected cid = QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr, got %s", links[0].Cid)
}
}

Expand All @@ -247,12 +253,12 @@ func TestLsEmptyDir(t *testing.T) {
t.Error(err)
}

c, err := node.DAG.Add(unixfs.EmptyDirNode())
_, err = node.DAG.Add(unixfs.EmptyDirNode())
if err != nil {
t.Error(err)
}

links, err := api.Ls(ctx, c.String())
links, err := api.Ls(ctx, emptyDir)
if err != nil {
t.Error(err)
}
Expand All @@ -275,7 +281,7 @@ func TestLsNonUnixfs(t *testing.T) {
t.Error(err)
}

links, err := api.Ls(ctx, c.String())
links, err := api.Ls(ctx, coreapi.ParseCid(c))
if err != nil {
t.Error(err)
}
Expand Down
2 changes: 1 addition & 1 deletion core/corehttp/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
Headers: cfg.Gateway.HTTPHeaders,
Writable: writable,
PathPrefixes: cfg.Gateway.PathPrefixes,
}, coreapi.NewUnixfsAPI(n))
}, coreapi.NewCoreAPI(n))

for _, p := range paths {
mux.Handle(p+"/", gateway)
Expand Down
Loading

0 comments on commit 7dee31b

Please sign in to comment.