hypercore-storage 0.0.40 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +17 -0
- package/index.js +467 -779
- package/lib/block-dependency-stream.js +107 -0
- package/lib/keys.js +242 -0
- package/lib/streams.js +112 -0
- package/lib/tx.js +286 -0
- package/lib/view.js +326 -0
- package/migrations/0/index.js +628 -0
- package/migrations/0/messages.js +1069 -0
- package/package.json +33 -18
- package/spec/hyperschema/index.js +510 -0
- package/lib/dependency-stream.js +0 -111
- package/lib/memory-overlay.js +0 -438
- package/lib/messages.js +0 -190
- package/lib/tip-list.js +0 -93
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const { Readable, getStreamError } = require('streamx')
|
|
2
|
+
const { core } = require('./keys')
|
|
3
|
+
|
|
4
|
+
module.exports = class BlockStream extends Readable {
|
|
5
|
+
constructor (core, db, updates, start, end, reverse) {
|
|
6
|
+
super()
|
|
7
|
+
|
|
8
|
+
this.core = core
|
|
9
|
+
this.db = db
|
|
10
|
+
this.updates = updates
|
|
11
|
+
this.end = end
|
|
12
|
+
this.reverse = reverse === true
|
|
13
|
+
|
|
14
|
+
this._drained = true
|
|
15
|
+
this._consumed = 0
|
|
16
|
+
this._stream = null
|
|
17
|
+
this._oncloseBound = this._onclose.bind(this)
|
|
18
|
+
this._maybeDrainBound = this._maybeDrain.bind(this)
|
|
19
|
+
|
|
20
|
+
this._update()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_update () {
|
|
24
|
+
if (this._consumed > this.core.dependencies.length) return
|
|
25
|
+
|
|
26
|
+
const index = this.reverse ? this.core.dependencies.length - this._consumed : this._consumed
|
|
27
|
+
const offset = index === 0 ? 0 : this.core.dependencies[index - 1].length
|
|
28
|
+
|
|
29
|
+
let end = 0
|
|
30
|
+
let ptr = 0
|
|
31
|
+
|
|
32
|
+
if (this._consumed < this.core.dependencies.length) {
|
|
33
|
+
const dep = this.core.dependencies[this._consumed]
|
|
34
|
+
end = this.end === -1 ? dep.length : Math.min(this.end, dep.length)
|
|
35
|
+
ptr = dep.dataPointer
|
|
36
|
+
} else {
|
|
37
|
+
end = this.end === -1 ? Infinity : this.end
|
|
38
|
+
ptr = this.core.dataPointer
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this._consumed++
|
|
42
|
+
|
|
43
|
+
if (end === offset) return
|
|
44
|
+
|
|
45
|
+
this._makeStream(core.block(ptr, offset), core.block(ptr, end))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_predestroy () {
|
|
49
|
+
if (this._stream !== null) this._stream.destroy()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_read (cb) {
|
|
53
|
+
this._drained = this._onreadable()
|
|
54
|
+
cb(null)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_maybeDrain () {
|
|
58
|
+
if (this._drained === true) return
|
|
59
|
+
this._drained = this._onreadable()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_onreadable () {
|
|
63
|
+
if (this._stream === null) {
|
|
64
|
+
this.push(null)
|
|
65
|
+
return true
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let data = this._stream.read()
|
|
69
|
+
|
|
70
|
+
if (data === null) return false
|
|
71
|
+
|
|
72
|
+
do {
|
|
73
|
+
this.push(data)
|
|
74
|
+
data = this._stream.read()
|
|
75
|
+
} while (data !== null)
|
|
76
|
+
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_onclose () {
|
|
81
|
+
if (this.destroying) return
|
|
82
|
+
|
|
83
|
+
const err = getStreamError(this._stream)
|
|
84
|
+
|
|
85
|
+
if (err !== null) {
|
|
86
|
+
this.destroy(err)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// empty the current stream
|
|
91
|
+
if (this._onreadable() === true) this._drained = true
|
|
92
|
+
|
|
93
|
+
this._stream = this._start = this._end = null
|
|
94
|
+
|
|
95
|
+
this._update()
|
|
96
|
+
this._maybeDrain()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
_makeStream (start, end) {
|
|
100
|
+
this._stream = this.updates.iterator(this.db, start, end, this.reverse)
|
|
101
|
+
this._stream.on('readable', this._maybeDrainBound)
|
|
102
|
+
this._stream.on('error', noop)
|
|
103
|
+
this._stream.on('close', this._oncloseBound)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function noop () {}
|
package/lib/keys.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
const { UINT, STRING } = require('index-encoder')
|
|
2
|
+
const c = require('compact-encoding')
|
|
3
|
+
const b4a = require('b4a')
|
|
4
|
+
|
|
5
|
+
const TL_HEAD = 0
|
|
6
|
+
const TL_CORE_BY_DKEY = 1
|
|
7
|
+
const TL_CORE_BY_ALIAS = 2
|
|
8
|
+
const TL_CORE = 3
|
|
9
|
+
const TL_DATA = 4
|
|
10
|
+
|
|
11
|
+
const TL_END = TL_DATA + 1
|
|
12
|
+
|
|
13
|
+
const CORE_AUTH = 0
|
|
14
|
+
const CORE_SESSIONS = 1
|
|
15
|
+
|
|
16
|
+
const DATA_HEAD = 0
|
|
17
|
+
const DATA_DEPENDENCY = 1
|
|
18
|
+
const DATA_HINTS = 2
|
|
19
|
+
const DATA_BLOCK = 3
|
|
20
|
+
const DATA_TREE = 4
|
|
21
|
+
const DATA_BITFIELD = 5
|
|
22
|
+
const DATA_USER_DATA = 6
|
|
23
|
+
|
|
24
|
+
const slab = { buffer: b4a.allocUnsafe(65536), start: 0, end: 0 }
|
|
25
|
+
|
|
26
|
+
const store = {}
|
|
27
|
+
const core = {}
|
|
28
|
+
|
|
29
|
+
store.clear = function () {
|
|
30
|
+
const state = alloc()
|
|
31
|
+
let start = state.start
|
|
32
|
+
UINT.encode(state, 0)
|
|
33
|
+
const a = state.buffer.subarray(start, state.start)
|
|
34
|
+
start = state.start
|
|
35
|
+
UINT.encode(state, TL_END)
|
|
36
|
+
const b = state.buffer.subarray(start, state.start)
|
|
37
|
+
return [a, b]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
store.head = function () {
|
|
41
|
+
const state = alloc()
|
|
42
|
+
const start = state.start
|
|
43
|
+
UINT.encode(state, TL_HEAD)
|
|
44
|
+
return state.buffer.subarray(start, state.start)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
store.core = function (discoveryKey) {
|
|
48
|
+
const state = alloc()
|
|
49
|
+
const start = state.start
|
|
50
|
+
UINT.encode(state, TL_CORE_BY_DKEY)
|
|
51
|
+
c.fixed32.encode(state, discoveryKey)
|
|
52
|
+
return state.buffer.subarray(start, state.start)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
store.coreStart = function () {
|
|
56
|
+
const state = alloc()
|
|
57
|
+
const start = state.start
|
|
58
|
+
UINT.encode(state, TL_CORE_BY_DKEY)
|
|
59
|
+
return state.buffer.subarray(start, state.start)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
store.coreEnd = function () {
|
|
63
|
+
const state = alloc()
|
|
64
|
+
const start = state.start
|
|
65
|
+
UINT.encode(state, TL_CORE_BY_DKEY + 1)
|
|
66
|
+
return state.buffer.subarray(start, state.start)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
store.coreByAlias = function ({ namespace, name }) {
|
|
70
|
+
const state = alloc()
|
|
71
|
+
const start = state.start
|
|
72
|
+
UINT.encode(state, TL_CORE_BY_ALIAS)
|
|
73
|
+
c.fixed32.encode(state, namespace)
|
|
74
|
+
STRING.encode(state, name)
|
|
75
|
+
return state.buffer.subarray(start, state.start)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
store.coreByAliasStart = function (namespace) {
|
|
79
|
+
const state = alloc()
|
|
80
|
+
const start = state.start
|
|
81
|
+
UINT.encode(state, TL_CORE_BY_ALIAS)
|
|
82
|
+
if (namespace) c.fixed32.encode(state, namespace)
|
|
83
|
+
return state.buffer.subarray(start, state.start)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
store.coreByAliasEnd = function (namespace) {
|
|
87
|
+
const state = alloc()
|
|
88
|
+
const start = state.start
|
|
89
|
+
|
|
90
|
+
if (namespace) {
|
|
91
|
+
UINT.encode(state, TL_CORE_BY_ALIAS)
|
|
92
|
+
c.fixed32.encode(state, namespace)
|
|
93
|
+
state.buffer[state.start++] = 0xff
|
|
94
|
+
} else {
|
|
95
|
+
UINT.encode(state, TL_CORE_BY_ALIAS + 1)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return state.buffer.subarray(start, state.start)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
store.alias = function (buffer) {
|
|
102
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
103
|
+
UINT.decode(state) // ns
|
|
104
|
+
const namespace = c.fixed32.decode(state)
|
|
105
|
+
const name = STRING.decode(state)
|
|
106
|
+
return { namespace, name }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
store.discoveryKey = function (buffer) {
|
|
110
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
111
|
+
UINT.decode(state) // ns
|
|
112
|
+
return c.fixed32.decode(state)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
core.auth = function (ptr) {
|
|
116
|
+
const state = alloc()
|
|
117
|
+
const start = state.start
|
|
118
|
+
UINT.encode(state, TL_CORE)
|
|
119
|
+
UINT.encode(state, ptr)
|
|
120
|
+
UINT.encode(state, CORE_AUTH)
|
|
121
|
+
return state.buffer.subarray(start, state.start)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
core.sessions = function (ptr) {
|
|
125
|
+
const state = alloc()
|
|
126
|
+
const start = state.start
|
|
127
|
+
UINT.encode(state, TL_CORE)
|
|
128
|
+
UINT.encode(state, ptr)
|
|
129
|
+
UINT.encode(state, CORE_SESSIONS)
|
|
130
|
+
return state.buffer.subarray(start, state.start)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
core.head = function (ptr) {
|
|
134
|
+
const state = alloc()
|
|
135
|
+
const start = state.start
|
|
136
|
+
UINT.encode(state, TL_DATA)
|
|
137
|
+
UINT.encode(state, ptr)
|
|
138
|
+
UINT.encode(state, DATA_HEAD)
|
|
139
|
+
return state.buffer.subarray(start, state.start)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
core.dependency = function (ptr) {
|
|
143
|
+
const state = alloc()
|
|
144
|
+
const start = state.start
|
|
145
|
+
UINT.encode(state, TL_DATA)
|
|
146
|
+
UINT.encode(state, ptr)
|
|
147
|
+
UINT.encode(state, DATA_DEPENDENCY)
|
|
148
|
+
return state.buffer.subarray(start, state.start)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
core.hints = function (ptr) {
|
|
152
|
+
const state = alloc()
|
|
153
|
+
const start = state.start
|
|
154
|
+
UINT.encode(state, TL_DATA)
|
|
155
|
+
UINT.encode(state, ptr)
|
|
156
|
+
UINT.encode(state, DATA_HINTS)
|
|
157
|
+
return state.buffer.subarray(start, state.start)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
core.block = function (ptr, index) {
|
|
161
|
+
const state = alloc()
|
|
162
|
+
const start = state.start
|
|
163
|
+
UINT.encode(state, TL_DATA)
|
|
164
|
+
UINT.encode(state, ptr)
|
|
165
|
+
UINT.encode(state, DATA_BLOCK)
|
|
166
|
+
UINT.encode(state, index)
|
|
167
|
+
return state.buffer.subarray(start, state.start)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
core.tree = function (ptr, index) {
|
|
171
|
+
const state = alloc()
|
|
172
|
+
const start = state.start
|
|
173
|
+
UINT.encode(state, TL_DATA)
|
|
174
|
+
UINT.encode(state, ptr)
|
|
175
|
+
UINT.encode(state, DATA_TREE)
|
|
176
|
+
UINT.encode(state, index)
|
|
177
|
+
return state.buffer.subarray(start, state.start)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
core.bitfield = function (ptr, index, type) {
|
|
181
|
+
const state = alloc()
|
|
182
|
+
const start = state.start
|
|
183
|
+
UINT.encode(state, TL_DATA)
|
|
184
|
+
UINT.encode(state, ptr)
|
|
185
|
+
UINT.encode(state, DATA_BITFIELD)
|
|
186
|
+
UINT.encode(state, index)
|
|
187
|
+
UINT.encode(state, type)
|
|
188
|
+
return state.buffer.subarray(start, state.start)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
core.userData = function (ptr, key) {
|
|
192
|
+
const state = alloc()
|
|
193
|
+
const start = state.start
|
|
194
|
+
UINT.encode(state, TL_DATA)
|
|
195
|
+
UINT.encode(state, ptr)
|
|
196
|
+
UINT.encode(state, DATA_USER_DATA)
|
|
197
|
+
STRING.encode(state, key)
|
|
198
|
+
return state.buffer.subarray(start, state.start)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
core.userDataEnd = function (ptr) {
|
|
202
|
+
const state = alloc()
|
|
203
|
+
const start = state.start
|
|
204
|
+
UINT.encode(state, TL_DATA)
|
|
205
|
+
UINT.encode(state, ptr)
|
|
206
|
+
UINT.encode(state, DATA_USER_DATA + 1)
|
|
207
|
+
return state.buffer.subarray(start, state.start)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
core.blockIndex = function (buffer) {
|
|
211
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
212
|
+
UINT.decode(state) // ns
|
|
213
|
+
UINT.decode(state) // ptr
|
|
214
|
+
UINT.decode(state) // type
|
|
215
|
+
return UINT.decode(state)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
core.bitfieldIndexAndType = function (buffer) {
|
|
219
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
220
|
+
UINT.decode(state) // ns
|
|
221
|
+
UINT.decode(state) // ptr
|
|
222
|
+
UINT.decode(state) // type
|
|
223
|
+
return [UINT.decode(state), UINT.decode(state)]
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
core.userDataKey = function (buffer) {
|
|
227
|
+
const state = { buffer, start: 0, end: buffer.byteLength }
|
|
228
|
+
UINT.decode(state) // ns
|
|
229
|
+
UINT.decode(state) // ptr
|
|
230
|
+
UINT.decode(state) // type
|
|
231
|
+
return STRING.decode(state)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
module.exports = { store, core }
|
|
235
|
+
|
|
236
|
+
function alloc () {
|
|
237
|
+
if (slab.buffer.byteLength - slab.start < 4096) {
|
|
238
|
+
slab.buffer = b4a.allocUnsafe(slab.buffer.byteLength)
|
|
239
|
+
slab.start = 0
|
|
240
|
+
}
|
|
241
|
+
return slab
|
|
242
|
+
}
|
package/lib/streams.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const BlockDependencyStream = require('./block-dependency-stream.js')
|
|
2
|
+
const { core, store } = require('./keys.js')
|
|
3
|
+
const schema = require('../spec/hyperschema')
|
|
4
|
+
|
|
5
|
+
const CORESTORE_CORE = schema.getEncoding('@corestore/core')
|
|
6
|
+
const CORE_TREE_NODE = schema.getEncoding('@core/tree-node')
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
createBlockStream,
|
|
10
|
+
createBitfieldStream,
|
|
11
|
+
createUserDataStream,
|
|
12
|
+
createCoreStream,
|
|
13
|
+
createAliasStream,
|
|
14
|
+
createTreeNodeStream
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createCoreStream (db, view) {
|
|
18
|
+
const start = store.coreStart()
|
|
19
|
+
const end = store.coreEnd()
|
|
20
|
+
|
|
21
|
+
const ite = view.iterator(db, start, end, false)
|
|
22
|
+
|
|
23
|
+
ite._readableState.map = mapCore
|
|
24
|
+
return ite
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function createAliasStream (db, view, namespace) {
|
|
28
|
+
const start = store.coreByAliasStart(namespace)
|
|
29
|
+
const end = store.coreByAliasEnd(namespace)
|
|
30
|
+
|
|
31
|
+
const ite = view.iterator(db, start, end, false)
|
|
32
|
+
|
|
33
|
+
ite._readableState.map = mapAlias
|
|
34
|
+
return ite
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createBlockIterator (ptr, db, view, start, end, reverse) {
|
|
38
|
+
if (ptr.dependencies.length > 0) {
|
|
39
|
+
return new BlockDependencyStream(ptr, db, view, start, end, reverse)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const s = core.block(ptr.dataPointer, start)
|
|
43
|
+
const e = core.block(ptr.dataPointer, end === -1 ? Infinity : end)
|
|
44
|
+
return view.iterator(db, s, e, reverse)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createBlockStream (ptr, db, view, { gt = -1, gte = gt + 1, lte = -1, lt = lte === -1 ? -1 : lte + 1, reverse = false } = {}) {
|
|
48
|
+
const ite = createBlockIterator(ptr, db, view, gte, lt, reverse)
|
|
49
|
+
|
|
50
|
+
ite._readableState.map = mapBlock
|
|
51
|
+
return ite
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createBitfieldStream (ptr, db, view, { gt = -1, gte = gt + 1, lte = -1, lt = lte === -1 ? -1 : lte + 1, reverse = false } = {}) {
|
|
55
|
+
const s = core.bitfield(ptr.dataPointer, gte, 0)
|
|
56
|
+
const e = core.bitfield(ptr.dataPointer, lt === -1 ? Infinity : lt, 0)
|
|
57
|
+
const ite = view.iterator(db, s, e, false)
|
|
58
|
+
|
|
59
|
+
ite._readableState.map = mapBitfield
|
|
60
|
+
return ite
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// NOTE: this does not do dependency lookups atm
|
|
64
|
+
function createTreeNodeStream (ptr, db, view, { gt = -1, gte = gt + 1, lte = -1, lt = lte === -1 ? -1 : lte + 1, reverse = false } = {}) {
|
|
65
|
+
const s = core.tree(ptr.dataPointer, gte, 0)
|
|
66
|
+
const e = core.tree(ptr.dataPointer, lt === -1 ? Infinity : lt, 0)
|
|
67
|
+
const ite = view.iterator(db, s, e, false)
|
|
68
|
+
|
|
69
|
+
ite._readableState.map = mapTreeNode
|
|
70
|
+
return ite
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function createUserDataStream (ptr, db, view, { gt = null, gte = '', lte = null, lt = null, reverse = false } = {}) {
|
|
74
|
+
if (gt !== null || lte !== null) throw new Error('gt and lte not yet supported for user data streams')
|
|
75
|
+
|
|
76
|
+
const s = core.userData(ptr.dataPointer, gte)
|
|
77
|
+
const e = lt === null ? core.userDataEnd(ptr.dataPointer) : core.userData(ptr.dataPointer, lt)
|
|
78
|
+
const ite = view.iterator(db, s, e, false)
|
|
79
|
+
|
|
80
|
+
ite._readableState.map = mapUserData
|
|
81
|
+
return ite
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function mapBitfield (data) {
|
|
85
|
+
const [index, type] = core.bitfieldIndexAndType(data.key)
|
|
86
|
+
if (type !== 0) return null // ignore for now
|
|
87
|
+
return { index, page: data.value }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function mapUserData (data) {
|
|
91
|
+
const key = core.userDataKey(data.key)
|
|
92
|
+
return { key, value: data.value }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function mapCore (data) {
|
|
96
|
+
const discoveryKey = store.discoveryKey(data.key)
|
|
97
|
+
const core = CORESTORE_CORE.decode({ start: 0, end: data.value.byteLength, buffer: data.value })
|
|
98
|
+
return { discoveryKey, core }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function mapAlias (data) {
|
|
102
|
+
const alias = store.alias(data.key)
|
|
103
|
+
return { alias, discoveryKey: data.value }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function mapBlock (data) {
|
|
107
|
+
return { index: core.blockIndex(data.key), value: data.value }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function mapTreeNode (data) {
|
|
111
|
+
return CORE_TREE_NODE.decode({ start: 0, end: data.value.byteLength, buffer: data.value })
|
|
112
|
+
}
|