-
Notifications
You must be signed in to change notification settings - Fork 2
/
manifest.go
91 lines (74 loc) · 2.09 KB
/
manifest.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
package manifest
import (
"context"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-ipld-format"
)
// Manifest is a DAG of only block names and links (no content)
// node identifiers are stored in a slice "nodes", all other slices reference
// cids by index positions
type Manifest struct {
Nodes []string `json:"nodes"`
Links [][2]int `json:"links"`
Sizes []uint64 `json:"sizes"`
}
// Node is a subset of the ipld format.Node interface
type Node interface {
// pulled from blocks.Block format
Cid() *cid.Cid
// Links is a helper function that returns all links within this object
Links() []*format.Link
// Size returns the size in bytes of the serialized object
Size() (uint64, error)
}
// NewManifest generates a manifest from an ipld node
func NewManifest(ctx context.Context, ng format.NodeGetter, node Node) (*Manifest, error) {
ms := &mstate{
ctx: ctx,
ng: ng,
cids: map[string]int{},
m: &Manifest{},
}
if _, err := ms.addNode(node); err != nil {
return nil, err
}
return ms.m, nil
}
// mstate is a state machine for generating a manifest
type mstate struct {
ctx context.Context
ng format.NodeGetter
idx int
cids map[string]int // lookup table of already-added cids
m *Manifest
}
// addNode places a node in the manifest & state machine, recursively adding linked nodes
// addNode returns early if this node is already added to the manifest
func (ms *mstate) addNode(node Node) (int, error) {
id := node.Cid().String()
if idx, ok := ms.cids[id]; ok {
return idx, nil
}
// add the node
idx := ms.idx
ms.idx++
ms.cids[id] = idx
ms.m.Nodes = append(ms.m.Nodes, id)
// ignore size errors b/c uint64 has no way to represent
// errored size state as an int (-1), hopefully implementations default to 0
// when erroring :/
size, _ := node.Size()
ms.m.Sizes = append(ms.m.Sizes, size)
for _, link := range node.Links() {
linkNode, err := link.GetNode(ms.ctx, ms.ng)
if err != nil {
return -1, err
}
nodeIdx, err := ms.addNode(linkNode)
if err != nil {
return -1, err
}
ms.m.Links = append(ms.m.Links, [2]int{idx, nodeIdx})
}
return idx, nil
}