pin: implement pin/ls with only CoreApi
Michael Muré committed
Dec 5, 2019 at 12:43 UTC
6ef190f5a646b51ea092b7e35479cca26c187d89
4 files changed
+131
-127
core/commands/pin.go
+44
-42
@@ -13,8 +13,6 @@ import (
13
cidenc "github.com/ipfs/go-cidutil/cidenc"
14
cmds "github.com/ipfs/go-ipfs-cmds"
15
offline "github.com/ipfs/go-ipfs-exchange-offline"
16
- pin "github.com/ipfs/go-ipfs-pinner"
17
- ipld "github.com/ipfs/go-ipld-format"
16
dag "github.com/ipfs/go-merkledag"
17
verifcid "github.com/ipfs/go-verifcid"
18
coreiface "github.com/ipfs/interface-go-ipfs-core"
@@ -24,7 +22,6 @@ import (
22
core "github.com/ipfs/go-ipfs/core"
23
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
24
e "github.com/ipfs/go-ipfs/core/commands/e"
27
- coreapi "github.com/ipfs/go-ipfs/core/coreapi"
25
)
26
27
var PinCmd = &cmds.Command{
@@ -320,11 +317,6 @@ Example:
317
cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."),
318
},
319
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
323
- n, err := cmdenv.GetNode(env)
324
- if err != nil {
325
- return err
326
- }
327
-
320
api, err := cmdenv.GetApi(env, req)
321
if err != nil {
322
return err
@@ -352,9 +344,9 @@ Example:
344
}
345
346
if len(req.Arguments) > 0 {
355
- err = pinLsKeys(req, typeStr, n, api, emit)
347
+ err = pinLsKeys(req, typeStr, api, emit)
348
} else {
357
- err = pinLsAll(req, typeStr, n.Pinning, n.DAG, emit)
349
+ err = pinLsAll(req, typeStr, api, emit)
350
}
351
if err != nil {
352
return err
@@ -431,24 +423,30 @@ type PinLsObject struct {
423
Type string `json:",omitempty"`
424
}
425
434
-func pinLsKeys(req *cmds.Request, typeStr string, n *core.IpfsNode, api coreiface.CoreAPI, emit func(value interface{}) error) error {
435
- mode, ok := pin.StringToMode(typeStr)
436
- if !ok {
437
- return fmt.Errorf("invalid pin mode '%s'", typeStr)
438
- }
439
-
426
+func pinLsKeys(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit func(value interface{}) error) error {
427
enc, err := cmdenv.GetCidEncoder(req)
428
if err != nil {
429
return err
430
}
431
432
+ switch typeStr {
433
+ case "all", "direct", "indirect", "recursive":
434
+ default:
435
+ return fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
436
+ }
437
+
438
+ opt, err := options.Pin.IsPinned.Type(typeStr)
439
+ if err != nil {
440
+ panic("unhandled pin type")
441
+ }
442
+
443
for _, p := range req.Arguments {
446
- c, err := api.ResolvePath(req.Context, path.New(p))
444
+ rp, err := api.ResolvePath(req.Context, path.New(p))
445
if err != nil {
446
return err
447
}
448
451
- pinType, pinned, err := n.Pinning.IsPinnedWithType(req.Context, c.Cid(), mode)
449
+ pinType, pinned, err := api.Pin().IsPinned(req.Context, rp, opt)
450
if err != nil {
451
return err
452
}
@@ -466,7 +464,7 @@ func pinLsKeys(req *cmds.Request, typeStr string, n *core.IpfsNode, api coreifac
464
err = emit(&PinLsOutputWrapper{
465
PinLsObject: PinLsObject{
466
Type: pinType,
469
- Cid: enc.Encode(c.Cid()),
467
+ Cid: enc.Encode(rp.Cid()),
468
},
469
})
470
if err != nil {
@@ -477,38 +475,42 @@ func pinLsKeys(req *cmds.Request, typeStr string, n *core.IpfsNode, api coreifac
475
return nil
476
}
477
480
-func pinLsAll(req *cmds.Request, typeStr string, pinning pin.Pinner, dag ipld.DAGService, emit func(value interface{}) error) error {
481
- pinCh, errCh := coreapi.PinLsAll(req.Context, typeStr, pinning, dag)
482
-
478
+func pinLsAll(req *cmds.Request, typeStr string, api coreiface.CoreAPI, emit func(value interface{}) error) error {
479
enc, err := cmdenv.GetCidEncoder(req)
480
if err != nil {
481
return err
482
}
483
488
- ctx := req.Context
489
-loop:
490
- for {
491
- select {
492
- case p, ok := <-pinCh:
493
- if !ok {
494
- break loop
495
- }
496
- if err := emit(&PinLsOutputWrapper{
497
- PinLsObject: PinLsObject{
498
- Type: p.Type(),
499
- Cid: enc.Encode(p.Path().Cid()),
500
- },
501
- }); err != nil {
502
- return err
503
- }
484
+ switch typeStr {
485
+ case "all", "direct", "indirect", "recursive":
486
+ default:
487
+ err = fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
488
+ return err
489
+ }
490
+
491
+ opt, err := options.Pin.Ls.Type(typeStr)
492
+ if err != nil {
493
+ panic("unhandled pin type")
494
+ }
495
+
496
+ pins, err := api.Pin().Ls(req.Context, opt)
497
+ if err != nil {
498
+ return err
499
+ }
500
505
- case <-ctx.Done():
506
- return ctx.Err()
501
+ for p := range pins {
502
+ err = emit(&PinLsOutputWrapper{
503
+ PinLsObject: PinLsObject{
504
+ Type: p.Type(),
505
+ Cid: enc.Encode(p.Path().Cid()),
506
+ },
507
+ })
508
+ if err != nil {
509
+ return err
510
}
511
}
512
510
- err = <-errCh
511
- return err
513
+ return nil
514
}
515
516
const (
core/coreapi/pin.go
+84
-81
@@ -3,11 +3,11 @@ package coreapi
3
import (
4
"context"
5
"fmt"
6
+
7
bserv "github.com/ipfs/go-blockservice"
8
"github.com/ipfs/go-cid"
9
offline "github.com/ipfs/go-ipfs-exchange-offline"
10
pin "github.com/ipfs/go-ipfs-pinner"
10
- ipld "github.com/ipfs/go-ipld-format"
11
"github.com/ipfs/go-merkledag"
12
coreiface "github.com/ipfs/interface-go-ipfs-core"
13
caopts "github.com/ipfs/interface-go-ipfs-core/options"
@@ -41,7 +41,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
41
return api.pinning.Flush(ctx)
42
}
43
44
-func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreiface.Pin, error) {
44
+func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan coreiface.Pin, error) {
45
settings, err := caopts.PinLsOptions(opts...)
46
if err != nil {
47
return nil, err
@@ -53,7 +53,26 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreif
53
return nil, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.Type)
54
}
55
56
- return api.pinLsAll(settings.Type, ctx)
56
+ return api.pinLsAll(settings.Type, ctx), nil
57
+}
58
+
59
+func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) {
60
+ dagNode, err := api.core().ResolveNode(ctx, p)
61
+ if err != nil {
62
+ return "", false, fmt.Errorf("pin: %s", err)
63
+ }
64
+
65
+ settings, err := caopts.PinIsPinnedOptions(opts...)
66
+ if err != nil {
67
+ return "", false, err
68
+ }
69
+
70
+ mode, ok := pin.StringToMode(settings.WithType)
71
+ if !ok {
72
+ return "", false, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.WithType)
73
+ }
74
+
75
+ return api.pinning.IsPinnedWithType(ctx, dagNode.Cid(), mode)
76
}
77
78
// Rm pin rm api
@@ -184,6 +203,7 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
203
type pinInfo struct {
204
pinType string
205
path path.Resolved
206
+ err error
207
}
208
209
func (p *pinInfo) Path() path.Resolved {
@@ -194,123 +214,106 @@ func (p *pinInfo) Type() string {
214
return p.pinType
215
}
216
197
-func (api *PinAPI) pinLsAll(typeStr string, ctx context.Context) ([]coreiface.Pin, error) {
198
- pinCh, errCh := PinLsAll(ctx, typeStr, api.pinning, api.dag)
199
-
200
- var pins []coreiface.Pin
201
-loop:
202
- for {
203
- select {
204
- case p, ok := <-pinCh:
205
- if !ok {
206
- break loop
207
- }
208
- pins = append(pins, p)
209
- case <-ctx.Done():
210
- return nil, ctx.Err()
211
- }
212
- }
213
- err := <-errCh
214
- if err != nil {
215
- return nil, err
216
- }
217
-
218
- return pins, nil
217
+func (p *pinInfo) Err() error {
218
+ return p.err
219
}
220
221
-// PinLsAll is an internal function for returning a list of pins
222
-func PinLsAll(ctx context.Context, typeStr string, pin pin.Pinner, dag ipld.DAGService) (chan coreiface.Pin, chan error) {
223
- ch := make(chan coreiface.Pin, 32)
224
- errCh := make(chan error, 1)
221
+func (api *PinAPI) pinLsAll(typeStr string, ctx context.Context) <-chan coreiface.Pin {
222
+ out := make(chan coreiface.Pin)
223
224
keys := cid.NewSet()
227
- AddToResultKeys := func(keyList []cid.Cid, typeStr string) error {
225
+
226
+ AddToResultKeys := func(keyList []cid.Cid, typeStr string) {
227
for _, c := range keyList {
228
if keys.Visit(c) {
230
- select {
231
- case ch <- &pinInfo{
229
+ out <- &pinInfo{
230
pinType: typeStr,
231
path: path.IpldPath(c),
234
- }:
235
- case <-ctx.Done():
236
- return ctx.Err()
232
}
233
}
234
}
240
- return nil
235
+ }
236
+
237
+ VisitKeys := func(keyList []cid.Cid) {
238
+ for _, c := range keyList {
239
+ keys.Visit(c)
240
+ }
241
}
242
243
go func() {
244
- defer close(ch)
245
- defer close(errCh)
246
- if typeStr == "direct" || typeStr == "all" {
247
- dkeys, err := pin.DirectKeys(ctx)
244
+ defer close(out)
245
+
246
+ if typeStr == "recursive" || typeStr == "all" {
247
+ rkeys, err := api.pinning.RecursiveKeys(ctx)
248
if err != nil {
249
- errCh <- err
250
- return
251
- }
252
- if err := AddToResultKeys(dkeys, "direct"); err != nil {
253
- errCh <- err
249
+ out <- &pinInfo{err: err}
250
return
251
}
252
+ AddToResultKeys(rkeys, "recursive")
253
}
257
- if typeStr == "recursive" || typeStr == "all" {
258
- rkeys, err := pin.RecursiveKeys(ctx)
254
+ if typeStr == "direct" || typeStr == "all" {
255
+ dkeys, err := api.pinning.DirectKeys(ctx)
256
if err != nil {
260
- errCh <- err
261
- return
262
- }
263
- if err := AddToResultKeys(rkeys, "recursive"); err != nil {
264
- errCh <- err
257
+ out <- &pinInfo{err: err}
258
return
259
}
260
+ AddToResultKeys(dkeys, "direct")
261
}
268
- if typeStr == "indirect" || typeStr == "all" {
269
- rkeys, err := pin.RecursiveKeys(ctx)
262
+ if typeStr == "all" {
263
+ set := cid.NewSet()
264
+ rkeys, err := api.pinning.RecursiveKeys(ctx)
265
if err != nil {
271
- errCh <- err
266
+ out <- &pinInfo{err: err}
267
return
268
}
274
-
275
- // If we're only listing indirect pins, we need to
276
- // explicitly mark direct/recursive pins so we don't
277
- // send them.
278
- if typeStr == "indirect" {
279
- dkeys, err := pin.DirectKeys(ctx)
269
+ for _, k := range rkeys {
270
+ err := merkledag.Walk(
271
+ ctx, merkledag.GetLinksWithDAG(api.dag), k,
272
+ set.Visit,
273
+ merkledag.SkipRoot(), merkledag.Concurrent(),
274
+ )
275
if err != nil {
281
- errCh <- err
276
+ out <- &pinInfo{err: err}
277
return
278
}
279
+ }
280
+ AddToResultKeys(set.Keys(), "indirect")
281
+ }
282
+ if typeStr == "indirect" {
283
+ // We need to first visit the direct pins that have priority
284
+ // without emitting them
285
285
- for _, k := range dkeys {
286
- keys.Add(k)
287
- }
288
- for _, k := range rkeys {
289
- keys.Add(k)
290
- }
286
+ dkeys, err := api.pinning.DirectKeys(ctx)
287
+ if err != nil {
288
+ out <- &pinInfo{err: err}
289
+ return
290
}
291
+ VisitKeys(dkeys)
292
293
- indirectKeys := cid.NewSet()
294
- for _, k := range rkeys {
295
- err := merkledag.Walk(ctx, merkledag.GetLinksWithDAG(dag), k, func(c cid.Cid) bool {
296
- r := indirectKeys.Visit(c)
297
- if r {
298
- if err := AddToResultKeys([]cid.Cid{c}, "indirect"); err != nil {
299
- return false
300
- }
301
- }
302
- return r
303
- }, merkledag.SkipRoot(), merkledag.Concurrent())
293
+ rkeys, err := api.pinning.RecursiveKeys(ctx)
294
+ if err != nil {
295
+ out <- &pinInfo{err: err}
296
+ return
297
+ }
298
+ VisitKeys(rkeys)
299
300
+ set := cid.NewSet()
301
+ for _, k := range rkeys {
302
+ err := merkledag.Walk(
303
+ ctx, merkledag.GetLinksWithDAG(api.dag), k,
304
+ set.Visit,
305
+ merkledag.SkipRoot(), merkledag.Concurrent(),
306
+ )
307
if err != nil {
306
- errCh <- err
308
+ out <- &pinInfo{err: err}
309
return
310
}
311
}
312
+ AddToResultKeys(set.Keys(), "indirect")
313
}
314
}()
315
313
- return ch, errCh
316
+ return out
317
}
318
319
func (api *PinAPI) core() coreiface.CoreAPI {
go.mod
+1
-1
@@ -54,7 +54,7 @@ require (
54
github.com/ipfs/go-path v0.0.7
55
github.com/ipfs/go-unixfs v0.2.4
56
github.com/ipfs/go-verifcid v0.0.1
57
- github.com/ipfs/interface-go-ipfs-core v0.2.7
57
+ github.com/ipfs/interface-go-ipfs-core v0.3.0
58
github.com/ipld/go-car v0.1.0
59
github.com/jbenet/go-is-domain v1.0.3
60
github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c
go.sum
+2
-3
@@ -398,8 +398,8 @@ github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo=
398
github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
399
github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E=
400
github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
401
-github.com/ipfs/interface-go-ipfs-core v0.2.7 h1:HCwVmU9Tmba6jdMGxMcPsfwKUBY4y+6bLHp8T+t9hTU=
402
-github.com/ipfs/interface-go-ipfs-core v0.2.7/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=
401
+github.com/ipfs/interface-go-ipfs-core v0.3.0 h1:oZdLLfh256gPGcYPURjivj/lv296GIcr8mUqZUnXOEI=
402
+github.com/ipfs/interface-go-ipfs-core v0.3.0/go.mod h1:Tihp8zxGpUeE3Tokr94L6zWZZdkRQvG5TL6i9MuNE+s=
403
github.com/ipld/go-car v0.1.0 h1:AaIEA5ITRnFA68uMyuIPYGM2XXllxsu8sNjFJP797us=
404
github.com/ipld/go-car v0.1.0/go.mod h1:RCWzaUh2i4mOEkB3W45Vc+9jnS/M6Qay5ooytiBHl3g=
405
github.com/ipld/go-ipld-prime v0.0.2-0.20191108012745-28a82f04c785 h1:fASnkvtR+SmB2y453RxmDD3Uvd4LonVUgFGk9JoDaZs=
@@ -1198,7 +1198,6 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
1198
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
1199
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1200
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1201
-golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1201
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
1202
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1203
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=