@cryptotaxi247 / kubo / commits / 6ef190f5a

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=