master
go 161 lines 3.42 KB
Raw
1 package coreapi
2
3 import (
4 "bytes"
5 "context"
6 "errors"
7 "io"
8
9 "github.com/ipfs/boxo/path"
10 pin "github.com/ipfs/boxo/pinning/pinner"
11 blocks "github.com/ipfs/go-block-format"
12 cid "github.com/ipfs/go-cid"
13 coreiface "github.com/ipfs/kubo/core/coreiface"
14 caopts "github.com/ipfs/kubo/core/coreiface/options"
15 "go.opentelemetry.io/otel/attribute"
16 "go.opentelemetry.io/otel/trace"
17
18 util "github.com/ipfs/kubo/blocks/blockstoreutil"
19 "github.com/ipfs/kubo/tracing"
20 )
21
22 type BlockAPI CoreAPI
23
24 type BlockStat struct {
25 path path.ImmutablePath
26 size int
27 }
28
29 func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.BlockStat, error) {
30 ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Put")
31 defer span.End()
32
33 settings, err := caopts.BlockPutOptions(opts...)
34 if err != nil {
35 return nil, err
36 }
37
38 data, err := io.ReadAll(src)
39 if err != nil {
40 return nil, err
41 }
42
43 bcid, err := settings.CidPrefix.Sum(data)
44 if err != nil {
45 return nil, err
46 }
47
48 b, err := blocks.NewBlockWithCid(data, bcid)
49 if err != nil {
50 return nil, err
51 }
52
53 if settings.Pin {
54 defer api.blockstore.PinLock(ctx).Unlock(ctx)
55 }
56
57 err = api.blocks.AddBlock(ctx, b)
58 if err != nil {
59 return nil, err
60 }
61
62 if settings.Pin {
63 if err = api.pinning.PinWithMode(ctx, b.Cid(), pin.Recursive, ""); err != nil {
64 return nil, err
65 }
66 if err := api.pinning.Flush(ctx); err != nil {
67 return nil, err
68 }
69 }
70
71 return &BlockStat{path: path.FromCid(b.Cid()), size: len(data)}, nil
72 }
73
74 func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) {
75 ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Get", trace.WithAttributes(attribute.String("path", p.String())))
76 defer span.End()
77 rp, _, err := api.core().ResolvePath(ctx, p)
78 if err != nil {
79 return nil, err
80 }
81
82 b, err := api.blocks.GetBlock(ctx, rp.RootCid())
83 if err != nil {
84 return nil, err
85 }
86
87 return bytes.NewReader(b.RawData()), nil
88 }
89
90 func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRmOption) error {
91 ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String())))
92 defer span.End()
93
94 rp, _, err := api.core().ResolvePath(ctx, p)
95 if err != nil {
96 return err
97 }
98
99 settings, err := caopts.BlockRmOptions(opts...)
100 if err != nil {
101 return err
102 }
103 cids := []cid.Cid{rp.RootCid()}
104 o := util.RmBlocksOpts{Force: settings.Force}
105
106 out, err := util.RmBlocks(ctx, api.blockstore, api.pinning, cids, o)
107 if err != nil {
108 return err
109 }
110
111 select {
112 case res, ok := <-out:
113 if !ok {
114 return nil
115 }
116
117 remBlock, ok := res.(*util.RemovedBlock)
118 if !ok {
119 return errors.New("got unexpected output from util.RmBlocks")
120 }
121
122 if remBlock.Error != nil {
123 return remBlock.Error
124 }
125 return nil
126 case <-ctx.Done():
127 return ctx.Err()
128 }
129 }
130
131 func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (coreiface.BlockStat, error) {
132 ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Stat", trace.WithAttributes(attribute.String("path", p.String())))
133 defer span.End()
134
135 rp, _, err := api.core().ResolvePath(ctx, p)
136 if err != nil {
137 return nil, err
138 }
139
140 b, err := api.blocks.GetBlock(ctx, rp.RootCid())
141 if err != nil {
142 return nil, err
143 }
144
145 return &BlockStat{
146 path: path.FromCid(b.Cid()),
147 size: len(b.RawData()),
148 }, nil
149 }
150
151 func (bs *BlockStat) Size() int {
152 return bs.size
153 }
154
155 func (bs *BlockStat) Path() path.ImmutablePath {
156 return bs.path
157 }
158
159 func (api *BlockAPI) core() coreiface.CoreAPI {
160 return (*CoreAPI)(api)
161 }