This repository has been archived by the owner on Feb 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hamtbuilder.go
151 lines (124 loc) · 4.03 KB
/
hamtbuilder.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package hamtcontainer
import (
"github.com/pkg/errors"
"github.com/ipfs/go-cid"
ipld "github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/multiformats/go-multicodec"
"github.com/simplecoincom/go-ipld-adl-hamt-container/storage"
)
var ErrCantUseStorageAndNested = errors.New("Cannot use Storage and FromNested in the same build")
var ErrCantUseParentAndLink = errors.New("Cannot use Parant and Link in the same build")
type Option func(*HAMTBuilder)
type HAMTBuilder struct {
key []byte
storage storage.Storage
link ipld.Link
parentHAMTContainer *HAMTContainer
}
// NewHAMTBuilder create a new HAMTBuilder helper
func NewHAMTBuilder(options ...Option) *HAMTBuilder {
hamtBuilder := &HAMTBuilder{}
for _, opt := range options {
opt(hamtBuilder)
}
return hamtBuilder
}
// WithKey sets the key for the future HAMTContainer
func WithKey(key []byte) Option {
return func(h *HAMTBuilder) {
h.key = key
}
}
// WithStorage sets the storage for the future HAMTContainer
func WithStorage(storage storage.Storage) Option {
return func(h *HAMTBuilder) {
h.storage = storage
}
}
// WithLink sets the link for the future HAMTContainer
func WithLink(link ipld.Link) Option {
return func(h *HAMTBuilder) {
h.link = link
}
}
// WithHAMTContainer sets the parent container to load from the future HAMTContainer
func WithHAMTContainer(hamtContainer *HAMTContainer) Option {
return func(h *HAMTBuilder) {
h.parentHAMTContainer = hamtContainer
}
}
func (hb *HAMTBuilder) parseParamRules() error {
// Should parse params and helps with some rules
// Storage and parent Storage should not be use in the same time
// Because it should get the same storage from the parent
if hb.storage != nil && hb.parentHAMTContainer != nil {
return ErrCantUseStorageAndNested
}
// Not key provided, it cab be just "hamt"
if len(hb.key) == 0 {
hb.key = []byte("hamt")
}
// If storage and parent are nil, we can use the default memory storage
if hb.storage == nil && hb.parentHAMTContainer == nil {
hb.storage = storage.NewMemoryStorage()
}
// If link and parent container
if hb.parentHAMTContainer != nil && hb.link != nil {
return ErrCantUseParentAndLink
}
// If parent isn't nil then we should use it storage
if hb.parentHAMTContainer != nil {
hb.storage = hb.parentHAMTContainer.Storage()
}
return nil
}
// Build creates the HAMT Container based on the params from HAMTBuilder
func (hb HAMTBuilder) Build() (*HAMTContainer, error) {
if err := hb.parseParamRules(); err != nil {
return nil, err
}
newHAMTContainer := &HAMTContainer{
key: hb.key,
kvCache: make(map[string]interface{}),
storage: hb.storage,
}
// Sets the link system
newHAMTContainer.linkSystem = cidlink.DefaultLinkSystem()
newHAMTContainer.linkProto = cidlink.LinkPrototype{Prefix: cid.Prefix{
Version: 1, // Usually '1'.
Codec: uint64(multicodec.DagCbor),
MhType: uint64(multicodec.Sha2_512),
MhLength: 64, // sha2-512 hash has a 64-byte sum.
}}
// Sets the writer and reader interfaces for the link system
newHAMTContainer.linkSystem.StorageWriteOpener = newHAMTContainer.storage.OpenWrite
newHAMTContainer.linkSystem.StorageReadOpener = newHAMTContainer.storage.OpenRead
// If has a parent we should load from it
if hb.parentHAMTContainer != nil {
// If the key doesn't exists we should warn
link, err := hb.parentHAMTContainer.GetAsLink(hb.key)
if err != nil {
return nil, ErrHAMTNoNestedFound
}
// Should load link from parent
if err := newHAMTContainer.LoadLink(link); err != nil {
return nil, ErrHAMTFailedToLoadNested
}
}
// Has a link, try to load
if hb.link != nil {
if err := newHAMTContainer.LoadLink(hb.link); err != nil {
return nil, err
}
}
// If has the parent container and the link we should load the key from it
if hb.parentHAMTContainer != nil || hb.link != nil {
key, err := newHAMTContainer.GetAsBytes([]byte(reservedNameKey))
if err != nil {
return nil, err
}
newHAMTContainer.key = key
}
return newHAMTContainer, nil
}