This repository was archived by the owner on Jun 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathfetcher.go
129 lines (109 loc) · 4.17 KB
/
fetcher.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package bsfetcher
import (
"bytes"
"context"
"fmt"
"io"
"github.com/ipfs/go-blockservice"
"github.com/ipfs/go-fetcher"
"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/schema"
"github.com/ipld/go-ipld-prime/traversal"
"github.com/ipld/go-ipld-prime/traversal/selector"
)
type fetcherSession struct {
linkSystem ipld.LinkSystem
protoChooser traversal.LinkTargetNodePrototypeChooser
}
// FetcherConfig defines a configuration object from which Fetcher instances are constructed
type FetcherConfig struct {
blockService blockservice.BlockService
NodeReifier ipld.NodeReifier
PrototypeChooser traversal.LinkTargetNodePrototypeChooser
}
// NewFetcherConfig creates a FetchConfig from which session may be created and nodes retrieved.
func NewFetcherConfig(blockService blockservice.BlockService) FetcherConfig {
return FetcherConfig{
blockService: blockService,
PrototypeChooser: DefaultPrototypeChooser,
}
}
// NewSession creates a session from which nodes may be retrieved.
// The session ends when the provided context is canceled.
func (fc FetcherConfig) NewSession(ctx context.Context) fetcher.Fetcher {
ls := cidlink.DefaultLinkSystem()
// while we may be loading blocks remotely, they are already hash verified by the time they load
// into ipld-prime
ls.TrustedStorage = true
ls.StorageReadOpener = blockOpener(ctx, blockservice.NewSession(ctx, fc.blockService))
ls.NodeReifier = fc.NodeReifier
protoChooser := fc.PrototypeChooser
return &fetcherSession{linkSystem: ls, protoChooser: protoChooser}
}
// interface check
var _ fetcher.Factory = FetcherConfig{}
// BlockOfType fetches a node graph of the provided type corresponding to single block by link.
func (f *fetcherSession) BlockOfType(ctx context.Context, link ipld.Link, ptype ipld.NodePrototype) (ipld.Node, error) {
return f.linkSystem.Load(ipld.LinkContext{}, link, ptype)
}
func (f *fetcherSession) nodeMatching(ctx context.Context, initialProgress traversal.Progress, node ipld.Node, match ipld.Node, cb fetcher.FetchCallback) error {
matchSelector, err := selector.ParseSelector(match)
if err != nil {
return err
}
return initialProgress.WalkMatching(node, matchSelector, func(prog traversal.Progress, n ipld.Node) error {
return cb(fetcher.FetchResult{
Node: n,
Path: prog.Path,
LastBlockPath: prog.LastBlock.Path,
LastBlockLink: prog.LastBlock.Link,
})
})
}
func (f *fetcherSession) blankProgress(ctx context.Context) traversal.Progress {
return traversal.Progress{
Cfg: &traversal.Config{
LinkSystem: f.linkSystem,
LinkTargetNodePrototypeChooser: f.protoChooser,
},
}
}
func (f *fetcherSession) NodeMatching(ctx context.Context, node ipld.Node, match ipld.Node, cb fetcher.FetchCallback) error {
return f.nodeMatching(ctx, f.blankProgress(ctx), node, match, cb)
}
func (f *fetcherSession) BlockMatchingOfType(ctx context.Context, root ipld.Link, match ipld.Node,
ptype ipld.NodePrototype, cb fetcher.FetchCallback) error {
// retrieve first node
node, err := f.BlockOfType(ctx, root, ptype)
if err != nil {
return err
}
progress := f.blankProgress(ctx)
progress.LastBlock.Link = root
return f.nodeMatching(ctx, progress, node, match, cb)
}
func (f *fetcherSession) PrototypeFromLink(lnk ipld.Link) (ipld.NodePrototype, error) {
return f.protoChooser(lnk, ipld.LinkContext{})
}
// DefaultPrototypeChooser supports DagPB nodes and choosing the prototype from the link.
var DefaultPrototypeChooser = func(lnk ipld.Link, lnkCtx ipld.LinkContext) (ipld.NodePrototype, error) {
if tlnkNd, ok := lnkCtx.LinkNode.(schema.TypedLinkNode); ok {
return tlnkNd.LinkTargetNodePrototype(), nil
}
return basicnode.Prototype.Any, nil
}
func blockOpener(ctx context.Context, bs *blockservice.Session) ipld.BlockReadOpener {
return func(_ ipld.LinkContext, lnk ipld.Link) (io.Reader, error) {
cidLink, ok := lnk.(cidlink.Link)
if !ok {
return nil, fmt.Errorf("invalid link type for loading: %v", lnk)
}
blk, err := bs.GetBlock(ctx, cidLink.Cid)
if err != nil {
return nil, err
}
return bytes.NewReader(blk.RawData()), nil
}
}