-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
selectors.go
96 lines (85 loc) · 2.52 KB
/
selectors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package utils
import (
"bytes"
"context"
"fmt"
"io"
// must be imported to init() raw-codec support
_ "github.com/ipld/go-ipld-prime/codec/raw"
"github.com/ipfs/go-cid"
mdagipld "github.com/ipfs/go-ipld-format"
dagpb "github.com/ipld/go-codec-dagpb"
"github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/traversal"
"github.com/ipld/go-ipld-prime/traversal/selector"
"github.com/ipld/go-ipld-prime/traversal/selector/builder"
)
func TraverseDag(
ctx context.Context,
ds mdagipld.DAGService,
startFrom cid.Cid,
optionalSelector ipld.Node,
visitCallback traversal.AdvVisitFn,
) error {
// If no selector is given - use *.*
// See discusion at https://github.com/ipld/go-ipld-prime/issues/171
if optionalSelector == nil {
ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any)
optionalSelector = ssb.ExploreRecursive(
selector.RecursionLimitNone(),
ssb.ExploreUnion(
ssb.Matcher(),
ssb.ExploreAll(ssb.ExploreRecursiveEdge()),
),
).Node()
}
parsedSelector, err := selector.ParseSelector(optionalSelector)
if err != nil {
return err
}
// not sure what this is for TBH...
linkContext := ipld.LinkContext{Ctx: ctx}
// this is what allows us to understand dagpb
nodePrototypeChooser := dagpb.AddSupportToChooser(
func(ipld.Link, ipld.LinkContext) (ipld.NodePrototype, error) {
return basicnode.Prototype.Any, nil
},
)
// this is how we implement GETs
linkSystem := cidlink.DefaultLinkSystem()
linkSystem.StorageReadOpener = func(_ ipld.LinkContext, lnk ipld.Link) (io.Reader, error) {
if cl, isCid := lnk.(cidlink.Link); !isCid {
return nil, fmt.Errorf("unexpected link type %#v", lnk)
} else {
node, err := ds.Get(context.TODO(), cl.Cid)
if err != nil {
return nil, err
}
return bytes.NewBuffer(node.RawData()), nil
}
}
// this is how we pull the start node out of the DS
startLink := cidlink.Link{Cid: startFrom}
startNodePrototype, err := nodePrototypeChooser(startLink, linkContext)
if err != nil {
return err
}
startNode, err := linkSystem.Load(
linkContext,
startLink,
startNodePrototype,
)
if err != nil {
return err
}
// this is the actual execution, invoking the supplied callback
return traversal.Progress{
Cfg: &traversal.Config{
Ctx: ctx,
LinkSystem: linkSystem,
LinkTargetNodePrototypeChooser: nodePrototypeChooser,
},
}.WalkAdv(startNode, parsedSelector, visitCallback)
}