-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4548 from ipfs/feat/coreapi/block
coreapi: Block API
- Loading branch information
Showing
5 changed files
with
422 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
package coreapi | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
|
||
util "github.com/ipfs/go-ipfs/blocks/blockstore/util" | ||
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" | ||
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options" | ||
|
||
mh "gx/ipfs/QmZyZDi491cCNTLfAhwcaDii2Kg4pwKRkhqQzURGDvY6ua/go-multihash" | ||
cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid" | ||
blocks "gx/ipfs/Qmej7nf81hi2x2tvjRBF3mcp74sQyuDH4VMYDGd1YtXjb2/go-block-format" | ||
) | ||
|
||
type BlockAPI struct { | ||
*CoreAPI | ||
*caopts.BlockOptions | ||
} | ||
|
||
type BlockStat struct { | ||
path coreiface.Path | ||
size int | ||
} | ||
|
||
func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.Path, error) { | ||
settings, err := caopts.BlockPutOptions(opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
data, err := ioutil.ReadAll(src) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var pref cid.Prefix | ||
pref.Version = 1 | ||
|
||
formatval, ok := cid.Codecs[settings.Codec] | ||
if !ok { | ||
return nil, fmt.Errorf("unrecognized format: %s", settings.Codec) | ||
} | ||
if settings.Codec == "v0" && settings.MhType == mh.SHA2_256 { | ||
pref.Version = 0 | ||
} | ||
pref.Codec = formatval | ||
|
||
pref.MhType = settings.MhType | ||
pref.MhLength = settings.MhLength | ||
|
||
bcid, err := pref.Sum(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
b, err := blocks.NewBlockWithCid(data, bcid) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
err = api.node.Blocks.AddBlock(b) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return ParseCid(b.Cid()), nil | ||
} | ||
|
||
func (api *BlockAPI) Get(ctx context.Context, p coreiface.Path) (io.Reader, error) { | ||
b, err := api.node.Blocks.GetBlock(ctx, p.Cid()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return bytes.NewReader(b.RawData()), nil | ||
} | ||
|
||
func (api *BlockAPI) Rm(ctx context.Context, p coreiface.Path, opts ...caopts.BlockRmOption) error { | ||
settings, err := caopts.BlockRmOptions(opts...) | ||
if err != nil { | ||
return err | ||
} | ||
cids := []*cid.Cid{p.Cid()} | ||
o := util.RmBlocksOpts{Force: settings.Force} | ||
|
||
out, err := util.RmBlocks(api.node.Blockstore, api.node.Pinning, cids, o) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
select { | ||
case res, ok := <-out: | ||
if !ok { | ||
return nil | ||
} | ||
|
||
remBlock, ok := res.(*util.RemovedBlock) | ||
if !ok { | ||
return errors.New("got unexpected output from util.RmBlocks") | ||
} | ||
|
||
if remBlock.Error != "" { | ||
return errors.New(remBlock.Error) | ||
} | ||
return nil | ||
case <-ctx.Done(): | ||
return ctx.Err() | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (api *BlockAPI) Stat(ctx context.Context, p coreiface.Path) (coreiface.BlockStat, error) { | ||
b, err := api.node.Blocks.GetBlock(ctx, p.Cid()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &BlockStat{ | ||
path: ParseCid(b.Cid()), | ||
size: len(b.RawData()), | ||
}, nil | ||
} | ||
|
||
func (bs *BlockStat) Size() int { | ||
return bs.size | ||
} | ||
|
||
func (bs *BlockStat) Path() coreiface.Path { | ||
return bs.path | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package coreapi_test | ||
|
||
import ( | ||
"context" | ||
"io/ioutil" | ||
"strings" | ||
"testing" | ||
|
||
mh "gx/ipfs/QmZyZDi491cCNTLfAhwcaDii2Kg4pwKRkhqQzURGDvY6ua/go-multihash" | ||
) | ||
|
||
func TestBlockPut(t *testing.T) { | ||
ctx := context.Background() | ||
_, api, err := makeAPI(ctx) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
res, err := api.Block().Put(ctx, strings.NewReader(`Hello`)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if res.Cid().String() != "QmPyo15ynbVrSTVdJL9th7JysHaAbXt9dM9tXk1bMHbRtk" { | ||
t.Errorf("got wrong cid: %s", res.Cid().String()) | ||
} | ||
} | ||
|
||
func TestBlockPutFormat(t *testing.T) { | ||
ctx := context.Background() | ||
_, api, err := makeAPI(ctx) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
res, err := api.Block().Put(ctx, strings.NewReader(`Hello`), api.Block().WithFormat("cbor")) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if res.Cid().String() != "zdpuAn4amuLWo8Widi5v6VQpuo2dnpnwbVE3oB6qqs7mDSeoa" { | ||
t.Errorf("got wrong cid: %s", res.Cid().String()) | ||
} | ||
} | ||
|
||
func TestBlockPutHash(t *testing.T) { | ||
ctx := context.Background() | ||
_, api, err := makeAPI(ctx) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
res, err := api.Block().Put(ctx, strings.NewReader(`Hello`), api.Block().WithHash(mh.KECCAK_512, -1)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if res.Cid().String() != "zBurKB9YZkcDf6xa53WBE8CFX4ydVqAyf9KPXBFZt5stJzEstaS8Hukkhu4gwpMtc1xHNDbzP7sPtQKyWsP3C8fbhkmrZ" { | ||
t.Errorf("got wrong cid: %s", res.Cid().String()) | ||
} | ||
} | ||
|
||
func TestBlockGet(t *testing.T) { | ||
ctx := context.Background() | ||
_, api, err := makeAPI(ctx) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
res, err := api.Block().Put(ctx, strings.NewReader(`Hello`), api.Block().WithHash(mh.KECCAK_512, -1)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
r, err := api.Block().Get(ctx, res) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
d, err := ioutil.ReadAll(r) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if string(d) != "Hello" { | ||
t.Error("didn't get correct data back") | ||
} | ||
} | ||
|
||
func TestBlockRm(t *testing.T) { | ||
ctx := context.Background() | ||
_, api, err := makeAPI(ctx) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
res, err := api.Block().Put(ctx, strings.NewReader(`Hello`)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
r, err := api.Block().Get(ctx, res) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
d, err := ioutil.ReadAll(r) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if string(d) != "Hello" { | ||
t.Error("didn't get correct data back") | ||
} | ||
|
||
err = api.Block().Rm(ctx, res) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
_, err = api.Block().Get(ctx, res) | ||
if err == nil { | ||
t.Error("expected err to exist") | ||
} | ||
if err.Error() != "blockservice: key not found" { | ||
t.Errorf("unexpected error; %s", err.Error()) | ||
} | ||
|
||
err = api.Block().Rm(ctx, res) | ||
if err == nil { | ||
t.Error("expected err to exist") | ||
} | ||
if err.Error() != "blockstore: block not found" { | ||
t.Errorf("unexpected error; %s", err.Error()) | ||
} | ||
|
||
err = api.Block().Rm(ctx, res, api.Block().WithForce(true)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
|
||
func TestBlockStat(t *testing.T) { | ||
ctx := context.Background() | ||
_, api, err := makeAPI(ctx) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
res, err := api.Block().Put(ctx, strings.NewReader(`Hello`)) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
stat, err := api.Block().Stat(ctx, res) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if stat.Path().String() != res.String() { | ||
t.Error("paths don't match") | ||
} | ||
|
||
if stat.Size() != len("Hello") { | ||
t.Error("length doesn't match") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.