diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go index 7f4d3d26a0f..5c0326b51e8 100644 --- a/core/coreapi/coreapi.go +++ b/core/coreapi/coreapi.go @@ -26,7 +26,7 @@ func (api *CoreAPI) Unixfs() coreiface.UnixfsAPI { } func (api *CoreAPI) Dag() coreiface.DagAPI { - return (*dagAPI)(api) + return &DagAPI{api, nil} } func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (coreiface.Node, error) { diff --git a/core/coreapi/dag.go b/core/coreapi/dag.go index 83d0c78ce6e..de796bd4dc9 100644 --- a/core/coreapi/dag.go +++ b/core/coreapi/dag.go @@ -8,30 +8,29 @@ import ( 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" - mh "gx/ipfs/QmYeKnKpubCMRiq3PGZcTREErthbb5Q9cXsCoSkD9bjEBd/go-multihash" cid "gx/ipfs/QmeSrf6pzut73u6zLQkRFQ3ygt3k6XFT2kjdYP8Tnkwwyg/go-cid" ) -type dagAPI CoreAPI +type DagAPI struct { + *CoreAPI + *caopts.DagOptions +} -func (api *dagAPI) Put(ctx context.Context, src io.Reader, inputEnc string, format *cid.Prefix) ([]coreiface.Node, error) { - if format == nil { - format = &cid.Prefix{ - Version: 1, - Codec: cid.DagCBOR, - MhType: mh.SHA2_256, - MhLength: mh.DefaultLengths[mh.SHA2_256], - } +func (api *DagAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.DagPutOption) ([]coreiface.Node, error) { + settings, err := caopts.DagPutOptions(opts...) + if err != nil { + return nil, err } - codec, ok := cid.CodecToStr[format.Codec] + codec, ok := cid.CodecToStr[settings.Codec] if !ok { - return nil, fmt.Errorf("invalid codec %d", format.Codec) + return nil, fmt.Errorf("invalid codec %d", settings.Codec) } - nds, err := coredag.ParseInputs(inputEnc, codec, src, format.MhType, format.MhLength) + nds, err := coredag.ParseInputs(settings.InputEnc, codec, src, settings.MhType, settings.MhLength) if err != nil { return nil, err } @@ -51,16 +50,21 @@ func (api *dagAPI) Put(ctx context.Context, src io.Reader, inputEnc string, form return out, nil } -func (api *dagAPI) Get(ctx context.Context, path coreiface.Path) (coreiface.Node, error) { +func (api *DagAPI) Get(ctx context.Context, path coreiface.Path) (coreiface.Node, error) { return api.core().ResolveNode(ctx, path) } -func (api *dagAPI) Tree(ctx context.Context, p coreiface.Path, depth int) ([]coreiface.Path, error) { +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("", depth) + paths := n.Tree("", settings.Depth) out := make([]coreiface.Path, len(paths)) for n, p2 := range paths { out[n], err = ParsePath(gopath.Join(p.String(), p2)) @@ -72,6 +76,6 @@ func (api *dagAPI) Tree(ctx context.Context, p coreiface.Path, depth int) ([]cor return out, nil } -func (api *dagAPI) core() coreiface.CoreAPI { - return (*CoreAPI)(api) +func (api *DagAPI) core() coreiface.CoreAPI { + return api.CoreAPI } diff --git a/core/coreapi/dag_test.go b/core/coreapi/dag_test.go index ee2d8ee22c8..b528afbaa15 100644 --- a/core/coreapi/dag_test.go +++ b/core/coreapi/dag_test.go @@ -7,6 +7,8 @@ import ( "testing" coreapi "github.com/ipfs/go-ipfs/core/coreapi" + + mh "gx/ipfs/QmYeKnKpubCMRiq3PGZcTREErthbb5Q9cXsCoSkD9bjEBd/go-multihash" ) var ( @@ -26,7 +28,7 @@ func TestPut(t *testing.T) { t.Error(err) } - res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`), "json", nil) + res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`)) if err != nil { t.Error(err) } @@ -36,6 +38,23 @@ func TestPut(t *testing.T) { } } +func TestPutWithHash(t *testing.T) { + ctx := context.Background() + _, api, err := makeAPI(ctx) + if err != nil { + t.Error(err) + } + + res, err := api.Dag().Put(ctx, strings.NewReader(`"Hello"`), api.Dag().WithHash(mh.ID, -1)) + if err != nil { + t.Error(err) + } + + if res[0].Cid().String() != "z5hRLNd2sv4z1c" { + t.Errorf("got wrong cid: %s", res[0].Cid().String()) + } +} + func TestPath(t *testing.T) { ctx := context.Background() _, api, err := makeAPI(ctx) @@ -43,12 +62,12 @@ func TestPath(t *testing.T) { t.Error(err) } - sub, err := api.Dag().Put(ctx, strings.NewReader(`"foo"`), "json", nil) + sub, err := api.Dag().Put(ctx, strings.NewReader(`"foo"`)) if err != nil { t.Error(err) } - res, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+sub[0].Cid().String()+`"}}`), "json", nil) + res, err := api.Dag().Put(ctx, strings.NewReader(`{"lnk": {"/": "`+sub[0].Cid().String()+`"}}`)) if err != nil { t.Error(err) } @@ -75,7 +94,7 @@ func TestTree(t *testing.T) { t.Error(err) } - res, err := api.Dag().Put(ctx, strings.NewReader(`{"a": 123, "b": "foo", "c": {"d": 321, "e": 111}}`), "json", nil) + res, err := api.Dag().Put(ctx, strings.NewReader(`{"a": 123, "b": "foo", "c": {"d": 321, "e": 111}}`)) if err != nil { t.Error(err) } diff --git a/core/coreapi/interface/interface.go b/core/coreapi/interface/interface.go index ecccc1c6438..f43700e9cb7 100644 --- a/core/coreapi/interface/interface.go +++ b/core/coreapi/interface/interface.go @@ -7,6 +7,8 @@ import ( "errors" "io" + options "github.com/ipfs/go-ipfs/core/coreapi/interface/options" + ipld "gx/ipfs/QmNwUEK7QbwSqyKBu3mMtToo8SUc6wQJ7gdZq4gGGJqfnf/go-ipld-format" cid "gx/ipfs/QmeSrf6pzut73u6zLQkRFQ3ygt3k6XFT2kjdYP8Tnkwwyg/go-cid" ) @@ -60,14 +62,31 @@ type UnixfsAPI interface { type DagAPI interface { // Put inserts data using specified format and input encoding. // If format is not specified (nil), default dag-cbor/sha256 is used - Put(ctx context.Context, src io.Reader, inputEnc string, format *cid.Prefix) ([]Node, error) //TODO: make format optional + Put(ctx context.Context, src io.Reader, opts ...options.DagPutOption) ([]Node, error) + + // WithInputEnc is an option for Put which specifies the input encoding of the + // data. Default is "json", most formats/codecs support "raw" + WithInputEnc(enc string) options.DagPutOption + + // WithCodec is an option for Put which specifies the multicodec to use to + // serialize the object. Default is cid.DagCBOR (0x71) + WithCodec(codec uint64) options.DagPutOption + + // WithHash is an option for 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 + WithHash(mhType uint64, mhLen int) options.DagPutOption // Get attempts to resolve and get the node specified by the path Get(ctx context.Context, path Path) (Node, error) // Tree returns list of paths within a node specified by the path. - // To get all paths in a tree, set depth to -1 - Tree(ctx context.Context, path Path, depth int) ([]Path, error) + Tree(ctx context.Context, path Path, opts ...options.DagTreeOption) ([]Path, error) + + // WithDepth is an option for Tree which specifies maximum depth of the + // returned tree. Default is -1 (no depth limit) + WithDepth(depth int) options.DagTreeOption } // type ObjectAPI interface { diff --git a/core/coreapi/interface/options/dag.go b/core/coreapi/interface/options/dag.go new file mode 100644 index 00000000000..7850c4bc3a8 --- /dev/null +++ b/core/coreapi/interface/options/dag.go @@ -0,0 +1,83 @@ +package options + +import ( + "math" + + cid "gx/ipfs/QmeSrf6pzut73u6zLQkRFQ3ygt3k6XFT2kjdYP8Tnkwwyg/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 DagOptions struct{} + +func (api *DagOptions) WithInputEnc(enc string) DagPutOption { + return func(settings *DagPutSettings) error { + settings.InputEnc = enc + return nil + } +} + +func (api *DagOptions) WithCodec(codec uint64) DagPutOption { + return func(settings *DagPutSettings) error { + settings.Codec = codec + return nil + } +} + +func (api *DagOptions) WithHash(mhType uint64, mhLen int) DagPutOption { + return func(settings *DagPutSettings) error { + settings.MhType = mhType + settings.MhLength = mhLen + return nil + } +} + +func (api *DagOptions) WithDepth(depth int) DagTreeOption { + return func(settings *DagTreeSettings) error { + settings.Depth = depth + return nil + } +}