coreapi: replace coreiface.DagAPI with ipld.DAGService

License: MIT
Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
Łukasz Magiera 2019-01-12 15:41:19 +01:00
parent b36037a3a5
commit eb23c90031
9 changed files with 109 additions and 328 deletions

View File

@ -96,8 +96,8 @@ func (api *CoreAPI) Block() coreiface.BlockAPI {
}
// Dag returns the DagAPI interface implementation backed by the go-ipfs node
func (api *CoreAPI) Dag() coreiface.DagAPI {
return (*DagAPI)(api)
func (api *CoreAPI) Dag() ipld.DAGService {
return api.dag
}
// Name returns the NameAPI interface implementation backed by the go-ipfs node

View File

@ -1,132 +0,0 @@
package coreapi
import (
"context"
"fmt"
"io"
"sync"
gopath "path"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
coredag "github.com/ipfs/go-ipfs/core/coredag"
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
)
type DagAPI CoreAPI
type dagBatch struct {
api *DagAPI
toPut []ipld.Node
lk sync.Mutex
}
// Put inserts data using specified format and input encoding. Unless used with
// `WithCodes` or `WithHash`, the defaults "dag-cbor" and "sha256" are used.
// Returns the path of the inserted data.
func (api *DagAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.DagPutOption) (coreiface.ResolvedPath, error) {
nd, err := getNode(src, opts...)
if err != nil {
return nil, err
}
err = api.dag.Add(ctx, nd)
if err != nil {
return nil, err
}
return coreiface.IpldPath(nd.Cid()), nil
}
// Get resolves `path` using Unixfs resolver, returns the resolved Node.
func (api *DagAPI) Get(ctx context.Context, path coreiface.Path) (ipld.Node, error) {
return api.core().ResolveNode(ctx, path)
}
// Tree returns list of paths within a node specified by the path `p`.
func (api *DagAPI) Tree(ctx context.Context, p coreiface.Path, opts ...caopts.DagTreeOption) ([]coreiface.Path, error) {
settings, err := caopts.DagTreeOptions(opts...)
if err != nil {
return nil, err
}
n, err := api.Get(ctx, p)
if err != nil {
return nil, err
}
paths := n.Tree("", settings.Depth)
out := make([]coreiface.Path, len(paths))
for n, p2 := range paths {
out[n], err = coreiface.ParsePath(gopath.Join(p.String(), p2))
if err != nil {
return nil, err
}
}
return out, nil
}
// Batch creates new DagBatch
func (api *DagAPI) Batch(ctx context.Context) coreiface.DagBatch {
return &dagBatch{api: api}
}
// Put inserts data using specified format and input encoding. Unless used with
// `WithCodes` or `WithHash`, the defaults "dag-cbor" and "sha256" are used.
// Returns the path of the inserted data.
func (b *dagBatch) Put(ctx context.Context, src io.Reader, opts ...caopts.DagPutOption) (coreiface.ResolvedPath, error) {
nd, err := getNode(src, opts...)
if err != nil {
return nil, err
}
b.lk.Lock()
b.toPut = append(b.toPut, nd)
b.lk.Unlock()
return coreiface.IpldPath(nd.Cid()), nil
}
// Commit commits nodes to the datastore and announces them to the network
func (b *dagBatch) Commit(ctx context.Context) error {
b.lk.Lock()
defer b.lk.Unlock()
defer func() {
b.toPut = nil
}()
return b.api.dag.AddMany(ctx, b.toPut)
}
func getNode(src io.Reader, opts ...caopts.DagPutOption) (ipld.Node, error) {
settings, err := caopts.DagPutOptions(opts...)
if err != nil {
return nil, err
}
codec, ok := cid.CodecToStr[settings.Codec]
if !ok {
return nil, fmt.Errorf("invalid codec %d", settings.Codec)
}
nds, err := coredag.ParseInputs(settings.InputEnc, codec, src, settings.MhType, settings.MhLength)
if err != nil {
return nil, err
}
if len(nds) == 0 {
return nil, fmt.Errorf("no node returned from ParseInputs")
}
if len(nds) != 1 {
return nil, fmt.Errorf("got more that one node from ParseInputs")
}
return nds[0], nil
}
func (api *DagAPI) core() coreiface.CoreAPI {
return (*CoreAPI)(api)
}

View File

@ -19,7 +19,7 @@ type CoreAPI interface {
Block() BlockAPI
// Dag returns an implementation of Dag API
Dag() DagAPI
Dag() ipld.DAGService
// Name returns an implementation of Name API
Name() NameAPI

View File

@ -1,41 +0,0 @@
package iface
import (
"context"
"io"
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
)
// DagOps groups operations that can be batched together
type DagOps interface {
// Put inserts data using specified format and input encoding.
// Unless used with WithCodec or WithHash, the defaults "dag-cbor" and
// "sha256" are used.
Put(ctx context.Context, src io.Reader, opts ...options.DagPutOption) (ResolvedPath, error)
}
// DagBatch is the batching version of DagAPI. All implementations of DagBatch
// should be threadsafe
type DagBatch interface {
DagOps
// Commit commits nodes to the datastore and announces them to the network
Commit(ctx context.Context) error
}
// DagAPI specifies the interface to IPLD
type DagAPI interface {
DagOps
// Get attempts to resolve and get the node specified by the path
Get(ctx context.Context, path Path) (ipld.Node, error)
// Tree returns list of paths within a node specified by the path.
Tree(ctx context.Context, path Path, opts ...options.DagTreeOption) ([]Path, error)
// Batch creates new DagBatch
Batch(ctx context.Context) DagBatch
}

View File

@ -1,95 +0,0 @@
package options
import (
"math"
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
)
type DagPutSettings struct {
InputEnc string
Codec uint64
MhType uint64
MhLength int
}
type DagTreeSettings struct {
Depth int
}
type DagPutOption func(*DagPutSettings) error
type DagTreeOption func(*DagTreeSettings) error
func DagPutOptions(opts ...DagPutOption) (*DagPutSettings, error) {
options := &DagPutSettings{
InputEnc: "json",
Codec: cid.DagCBOR,
MhType: math.MaxUint64,
MhLength: -1,
}
for _, opt := range opts {
err := opt(options)
if err != nil {
return nil, err
}
}
return options, nil
}
func DagTreeOptions(opts ...DagTreeOption) (*DagTreeSettings, error) {
options := &DagTreeSettings{
Depth: -1,
}
for _, opt := range opts {
err := opt(options)
if err != nil {
return nil, err
}
}
return options, nil
}
type dagOpts struct{}
var Dag dagOpts
// InputEnc is an option for Dag.Put which specifies the input encoding of the
// data. Default is "json", most formats/codecs support "raw"
func (dagOpts) InputEnc(enc string) DagPutOption {
return func(settings *DagPutSettings) error {
settings.InputEnc = enc
return nil
}
}
// Codec is an option for Dag.Put which specifies the multicodec to use to
// serialize the object. Default is cid.DagCBOR (0x71)
func (dagOpts) Codec(codec uint64) DagPutOption {
return func(settings *DagPutSettings) error {
settings.Codec = codec
return nil
}
}
// Hash is an option for Dag.Put which specifies the multihash settings to use
// when hashing the object. Default is based on the codec used
// (mh.SHA2_256 (0x12) for DagCBOR). If mhLen is set to -1, default length for
// the hash will be used
func (dagOpts) Hash(mhType uint64, mhLen int) DagPutOption {
return func(settings *DagPutSettings) error {
settings.MhType = mhType
settings.MhLength = mhLen
return nil
}
}
// Depth is an option for Dag.Tree which specifies maximum depth of the
// returned tree. Default is -1 (no depth limit)
func (dagOpts) Depth(depth int) DagTreeOption {
return func(settings *DagTreeSettings) error {
settings.Depth = depth
return nil
}
}

View File

@ -2,12 +2,13 @@ package tests
import (
"context"
"math"
"path"
"strings"
"testing"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
coredag "github.com/ipfs/go-ipfs/core/coredag"
mh "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"
)
@ -45,13 +46,18 @@ func (tp *provider) TestPut(t *testing.T) {
t.Error(err)
}
res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`"Hello"`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
err = api.Dag().Add(ctx, nds[0])
if err != nil {
t.Fatal(err)
}
if res.Cid().String() != "zdpuAqckYF3ToF3gcJNxPZXmnmGuXd3gxHCXhq81HGxBejEvv" {
t.Errorf("got wrong cid: %s", res.Cid().String())
if nds[0].Cid().String() != "zdpuAqckYF3ToF3gcJNxPZXmnmGuXd3gxHCXhq81HGxBejEvv" {
t.Errorf("got wrong cid: %s", nds[0].Cid().String())
}
}
@ -63,13 +69,18 @@ func (tp *provider) TestPutWithHash(t *testing.T) {
t.Error(err)
}
res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`), opt.Dag.Hash(mh.ID, -1))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`"Hello"`), mh.ID, -1)
if err != nil {
t.Error(err)
}
err = api.Dag().Add(ctx, nds[0])
if err != nil {
t.Fatal(err)
}
if res.Cid().String() != "z5hRLNd2sv4z1c" {
t.Errorf("got wrong cid: %s", res.Cid().String())
if nds[0].Cid().String() != "z5hRLNd2sv4z1c" {
t.Errorf("got wrong cid: %s", nds[0].Cid().String())
}
}
@ -81,28 +92,43 @@ func (tp *provider) TestDagPath(t *testing.T) {
t.Error(err)
}
sub, err := api.Dag().Put(ctx, strings.NewReader(`"foo"`))
if err != nil {
t.Fatal(err)
}
res, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+sub.Cid().String()+`"}}`))
if err != nil {
t.Fatal(err)
}
p, err := coreiface.ParsePath(path.Join(res.Cid().String(), "lnk"))
snds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`"foo"`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
nd, err := api.Dag().Get(ctx, p)
err = api.Dag().Add(ctx, snds[0])
if err != nil {
t.Fatal(err)
}
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"lnk": {"/": "`+snds[0].Cid().String()+`"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
if nd.Cid().String() != sub.Cid().String() {
t.Errorf("got unexpected cid %s, expected %s", nd.Cid().String(), sub.Cid().String())
err = api.Dag().Add(ctx, nds[0])
if err != nil {
t.Fatal(err)
}
p, err := coreiface.ParsePath(path.Join(nds[0].Cid().String(), "lnk"))
if err != nil {
t.Error(err)
}
rp, err := api.ResolvePath(ctx, p)
if err != nil {
t.Error(err)
}
nd, err := api.Dag().Get(ctx, rp.Cid())
if err != nil {
t.Error(err)
}
if nd.Cid().String() != snds[0].Cid().String() {
t.Errorf("got unexpected cid %s, expected %s", nd.Cid().String(), snds[0].Cid().String())
}
}
@ -114,12 +140,17 @@ func (tp *provider) TestTree(t *testing.T) {
t.Error(err)
}
c, err := api.Dag().Put(ctx, strings.NewReader(`{"a": 123, "b": "foo", "c": {"d": 321, "e": 111}}`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"a": 123, "b": "foo", "c": {"d": 321, "e": 111}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
err = api.Dag().Add(ctx, nds[0])
if err != nil {
t.Fatal(err)
}
res, err := api.Dag().Get(ctx, c)
res, err := api.Dag().Get(ctx, nds[0].Cid())
if err != nil {
t.Error(err)
}
@ -144,27 +175,25 @@ func (tp *provider) TestBatch(t *testing.T) {
t.Error(err)
}
batch := api.Dag().Batch(ctx)
c, err := batch.Put(ctx, strings.NewReader(`"Hello"`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`"Hello"`), math.MaxUint64, -1)
if err != nil {
t.Fatal(err)
t.Error(err)
}
if c.Cid().String() != "zdpuAqckYF3ToF3gcJNxPZXmnmGuXd3gxHCXhq81HGxBejEvv" {
t.Errorf("got wrong cid: %s", c.Cid().String())
if nds[0].Cid().String() != "zdpuAqckYF3ToF3gcJNxPZXmnmGuXd3gxHCXhq81HGxBejEvv" {
t.Errorf("got wrong cid: %s", nds[0].Cid().String())
}
_, err = api.Dag().Get(ctx, c)
_, err = api.Dag().Get(ctx, nds[0].Cid())
if err == nil || err.Error() != "merkledag: not found" {
t.Error(err)
}
if err := batch.Commit(ctx); err != nil {
if err := api.Dag().AddMany(ctx, nds); err != nil {
t.Error(err)
}
_, err = api.Dag().Get(ctx, c)
_, err = api.Dag().Get(ctx, nds[0].Cid())
if err != nil {
t.Error(err)
}

View File

@ -2,11 +2,13 @@ package tests
import (
"context"
"math"
"strings"
"testing"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
"github.com/ipfs/go-ipfs/core/coredag"
)
func (tp *provider) TestPath(t *testing.T) {
@ -62,12 +64,16 @@ func (tp *provider) TestPathRemainder(t *testing.T) {
t.Fatal(".Dag not implemented")
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"foo": {"bar": "baz"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
if err := api.Dag().AddMany(ctx, nds); err != nil {
t.Fatal(err)
}
p1, err := coreiface.ParsePath(obj.String() + "/foo/bar")
p1, err := coreiface.ParsePath(nds[0].String() + "/foo/bar")
if err != nil {
t.Error(err)
}
@ -94,16 +100,16 @@ func (tp *provider) TestEmptyPathRemainder(t *testing.T) {
t.Fatal(".Dag not implemented")
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"foo": {"bar": "baz"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
if err := api.Dag().AddMany(ctx, nds); err != nil {
t.Fatal(err)
}
if obj.Remainder() != "" {
t.Error("expected the resolved path to not have a remainder")
}
p1, err := coreiface.ParsePath(obj.String())
p1, err := coreiface.ParsePath(nds[0].Cid().String())
if err != nil {
t.Error(err)
}
@ -130,12 +136,16 @@ func (tp *provider) TestInvalidPathRemainder(t *testing.T) {
t.Fatal(".Dag not implemented")
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"bar": "baz"}}`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"foo": {"bar": "baz"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
if err := api.Dag().AddMany(ctx, nds); err != nil {
t.Fatal(err)
}
p1, err := coreiface.ParsePath(obj.String() + "/bar/baz")
p1, err := coreiface.ParsePath("/ipld/" + nds[0].Cid().String() + "/bar/baz")
if err != nil {
t.Error(err)
}
@ -167,12 +177,16 @@ func (tp *provider) TestPathRoot(t *testing.T) {
t.Fatal(".Dag not implemented")
}
obj, err := api.Dag().Put(ctx, strings.NewReader(`{"foo": {"/": "`+blk.Path().Cid().String()+`"}}`))
nds, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"foo": {"/": "`+blk.Path().Cid().String()+`"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
if err := api.Dag().AddMany(ctx, nds); err != nil {
t.Fatal(err)
}
p1, err := coreiface.ParsePath(obj.String() + "/foo")
p1, err := coreiface.ParsePath("/ipld/" + nds[0].Cid().String() + "/foo")
if err != nil {
t.Error(err)
}
@ -182,7 +196,7 @@ func (tp *provider) TestPathRoot(t *testing.T) {
t.Fatal(err)
}
if rp.Root().String() != obj.Cid().String() {
if rp.Root().String() != nds[0].Cid().String() {
t.Error("unexpected path root")
}

View File

@ -2,11 +2,13 @@ package tests
import (
"context"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
"math"
"strings"
"testing"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
"github.com/ipfs/go-ipfs/core/coredag"
)
func (tp *provider) TestPin(t *testing.T) {
@ -109,22 +111,26 @@ func (tp *provider) TestPinRecursive(t *testing.T) {
t.Error(err)
}
p2, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+p0.Cid().String()+`"}}`))
nd2, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"lnk": {"/": "`+p0.Cid().String()+`"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
p3, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+p1.Cid().String()+`"}}`))
nd3, err := coredag.ParseInputs("json", "dag-cbor", strings.NewReader(`{"lnk": {"/": "`+p1.Cid().String()+`"}}`), math.MaxUint64, -1)
if err != nil {
t.Error(err)
}
err = api.Pin().Add(ctx, p2)
if err := api.Dag().AddMany(ctx, append(nd2, nd3...)); err != nil {
t.Fatal(err)
}
err = api.Pin().Add(ctx, iface.IpldPath(nd2[0].Cid()))
if err != nil {
t.Error(err)
}
err = api.Pin().Add(ctx, p3, opt.Pin.Recursive(false))
err = api.Pin().Add(ctx, iface.IpldPath(nd3[0].Cid()), opt.Pin.Recursive(false))
if err != nil {
t.Error(err)
}
@ -147,8 +153,8 @@ func (tp *provider) TestPinRecursive(t *testing.T) {
t.Errorf("unexpected pin list len: %d", len(list))
}
if list[0].Path().String() != p3.String() {
t.Error("unexpected path")
if list[0].Path().String() != iface.IpldPath(nd3[0].Cid()).String() {
t.Errorf("unexpected path, %s != %s", list[0].Path().String(), iface.IpfsPath(nd2[0].Cid()).String())
}
list, err = api.Pin().Ls(ctx, opt.Pin.Type.Recursive())
@ -160,8 +166,8 @@ func (tp *provider) TestPinRecursive(t *testing.T) {
t.Errorf("unexpected pin list len: %d", len(list))
}
if list[0].Path().String() != p2.String() {
t.Error("unexpected path")
if list[0].Path().String() != iface.IpldPath(nd2[0].Cid()).String() {
t.Errorf("unexpected path, %s != %s", list[0].Path().String(), iface.IpldPath(nd3[0].Cid()).String())
}
list, err = api.Pin().Ls(ctx, opt.Pin.Type.Indirect())

View File

@ -633,7 +633,7 @@ func (tp *provider) TestGetDir(t *testing.T) {
t.Error(err)
}
edir := unixfs.EmptyDirNode()
_, err = api.Dag().Put(ctx, bytes.NewReader(edir.RawData()), options.Dag.Codec(cid.DagProtobuf), options.Dag.InputEnc("raw"))
err = api.Dag().Add(ctx, edir)
if err != nil {
t.Error(err)
}
@ -667,7 +667,7 @@ func (tp *provider) TestGetNonUnixfs(t *testing.T) {
}
nd := new(mdag.ProtoNode)
_, err = api.Dag().Put(ctx, bytes.NewReader(nd.RawData()), options.Dag.Codec(nd.CidBuilder().GetCodec()), options.Dag.InputEnc("raw"))
err = api.Dag().Add(ctx, nd)
if err != nil {
t.Error(err)
}
@ -801,7 +801,7 @@ func (tp *provider) TestLsNonUnixfs(t *testing.T) {
t.Fatal(err)
}
_, err = api.Dag().Put(ctx, bytes.NewReader(nd.RawData()), options.Dag.Codec(cid.DagCBOR), options.Dag.InputEnc("raw"))
err = api.Dag().Add(ctx, nd)
if err != nil {
t.Error(err)
}