master
go 134 lines 2.86 KB
Raw
1 package rpc
2
3 import (
4 "bytes"
5 "context"
6 "fmt"
7 "io"
8
9 "github.com/ipfs/boxo/path"
10 "github.com/ipfs/go-cid"
11 iface "github.com/ipfs/kubo/core/coreiface"
12 caopts "github.com/ipfs/kubo/core/coreiface/options"
13 mc "github.com/multiformats/go-multicodec"
14 mh "github.com/multiformats/go-multihash"
15 )
16
17 type BlockAPI HttpApi
18
19 type blockStat struct {
20 Key string
21 BSize int `json:"Size"`
22
23 cid cid.Cid
24 }
25
26 func (s *blockStat) Size() int {
27 return s.BSize
28 }
29
30 func (s *blockStat) Path() path.ImmutablePath {
31 return path.FromCid(s.cid)
32 }
33
34 func (api *BlockAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.BlockPutOption) (iface.BlockStat, error) {
35 options, err := caopts.BlockPutOptions(opts...)
36 px := options.CidPrefix
37 if err != nil {
38 return nil, err
39 }
40
41 mht, ok := mh.Codes[px.MhType]
42 if !ok {
43 return nil, fmt.Errorf("unknowm mhType %d", px.MhType)
44 }
45
46 var cidOptKey, cidOptVal string
47 switch {
48 case px.Version == 0 && px.Codec == cid.DagProtobuf:
49 // ensure legacy --format=v0 passes as BlockPutOption still works
50 cidOptKey = "format"
51 cidOptVal = "v0"
52 default:
53 // pass codec as string
54 cidOptKey = "cid-codec"
55 cidOptVal = mc.Code(px.Codec).String()
56 }
57
58 req := api.core().Request("block/put").
59 Option("mhtype", mht).
60 Option("mhlen", px.MhLength).
61 Option(cidOptKey, cidOptVal).
62 Option("pin", options.Pin).
63 FileBody(r)
64
65 var out blockStat
66 if err := req.Exec(ctx, &out); err != nil {
67 return nil, err
68 }
69 out.cid, err = cid.Parse(out.Key)
70 if err != nil {
71 return nil, err
72 }
73
74 return &out, nil
75 }
76
77 func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) {
78 resp, err := api.core().Request("block/get", p.String()).Send(ctx)
79 if err != nil {
80 return nil, err
81 }
82 if resp.Error != nil {
83 return nil, parseErrNotFoundWithFallbackToError(resp.Error)
84 }
85
86 // TODO: make get return ReadCloser to avoid copying
87 defer resp.Close()
88 b := new(bytes.Buffer)
89 if _, err := io.Copy(b, resp.Output); err != nil {
90 return nil, err
91 }
92
93 return b, nil
94 }
95
96 func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRmOption) error {
97 options, err := caopts.BlockRmOptions(opts...)
98 if err != nil {
99 return err
100 }
101
102 removedBlock := struct {
103 Hash string `json:",omitempty"`
104 Error string `json:",omitempty"`
105 }{}
106
107 req := api.core().Request("block/rm").
108 Option("force", options.Force).
109 Arguments(p.String())
110
111 if err := req.Exec(ctx, &removedBlock); err != nil {
112 return err
113 }
114
115 return parseErrNotFoundWithFallbackToMSG(removedBlock.Error)
116 }
117
118 func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (iface.BlockStat, error) {
119 var out blockStat
120 err := api.core().Request("block/stat", p.String()).Exec(ctx, &out)
121 if err != nil {
122 return nil, parseErrNotFoundWithFallbackToError(err)
123 }
124 out.cid, err = cid.Parse(out.Key)
125 if err != nil {
126 return nil, err
127 }
128
129 return &out, nil
130 }
131
132 func (api *BlockAPI) core() *HttpApi {
133 return (*HttpApi)(api)
134 }