hypercore-storage 0.0.21
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/index.js +742 -0
- package/lib/dependency-stream.js +111 -0
- package/lib/messages.js +190 -0
- package/package.json +30 -0
package/index.js
ADDED
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
const RocksDB = require('rocksdb-native')
|
|
2
|
+
const c = require('compact-encoding')
|
|
3
|
+
const { UINT } = require('index-encoder')
|
|
4
|
+
const RW = require('read-write-mutexify')
|
|
5
|
+
const b4a = require('b4a')
|
|
6
|
+
const flat = require('flat-tree')
|
|
7
|
+
const assert = require('nanoassert')
|
|
8
|
+
const m = require('./lib/messages')
|
|
9
|
+
const DependencyStream = require('./lib/dependency-stream')
|
|
10
|
+
|
|
11
|
+
const INF = b4a.from([0xff])
|
|
12
|
+
|
|
13
|
+
// <TL_INFO> = { version, free, total }
|
|
14
|
+
// <TL_LOCAL_SEED> = seed
|
|
15
|
+
// <TL_CORE_INFO><discovery-key-32-bytes> = { version, owner, core, data }
|
|
16
|
+
|
|
17
|
+
// <core><CORE_MANIFEST> = { key, manifest? }
|
|
18
|
+
// <core><CORE_LOCAL_SEED> = seed
|
|
19
|
+
// <core><CORE_ENCRYPTION_KEY> = encryptionKey // should come later, not important initially
|
|
20
|
+
// <core><CORE_HEAD><data> = { fork, length, byteLength, signature }
|
|
21
|
+
// <core><CORE_BATCHES><name> = <data>
|
|
22
|
+
|
|
23
|
+
// <data><CORE_INFO> = { version }
|
|
24
|
+
// <data><CORE_UPDATES> = { contiguousLength, blocks }
|
|
25
|
+
// <data><CORE_DEPENDENCY = { data, length, roots }
|
|
26
|
+
// <data><CORE_HINTS> = { reorg } // should come later, not important initially
|
|
27
|
+
// <data><CORE_TREE><index> = { index, size, hash }
|
|
28
|
+
// <data><CORE_BITFIELD><index> = <4kb buffer>
|
|
29
|
+
// <data><CORE_BLOCKS><index> = <buffer>
|
|
30
|
+
// <data><CORE_USER_DATA><key> = <value>
|
|
31
|
+
|
|
32
|
+
// top level prefixes
|
|
33
|
+
const TL = {
|
|
34
|
+
STORAGE_INFO: 0,
|
|
35
|
+
LOCAL_SEED: 1,
|
|
36
|
+
DKEYS: 2,
|
|
37
|
+
CORE: 3,
|
|
38
|
+
DATA: 4,
|
|
39
|
+
DEFAULT_KEY: 5
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// core prefixes
|
|
43
|
+
const CORE = {
|
|
44
|
+
MANIFEST: 0,
|
|
45
|
+
LOCAL_SEED: 1,
|
|
46
|
+
ENCRYPTION_KEY: 2,
|
|
47
|
+
HEAD: 3,
|
|
48
|
+
BATCHES: 4
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// data prefixes
|
|
52
|
+
const DATA = {
|
|
53
|
+
INFO: 0,
|
|
54
|
+
UPDATES: 1,
|
|
55
|
+
DEPENDENCY: 2,
|
|
56
|
+
HINTS: 3,
|
|
57
|
+
TREE: 4,
|
|
58
|
+
BITFIELD: 5,
|
|
59
|
+
BLOCK: 6,
|
|
60
|
+
USER_DATA: 7
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const SLAB = {
|
|
64
|
+
start: 0,
|
|
65
|
+
end: 65536,
|
|
66
|
+
buffer: b4a.allocUnsafe(65536)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// PREFIX + BATCH + TYPE + INDEX
|
|
70
|
+
|
|
71
|
+
class WriteBatch {
|
|
72
|
+
constructor (storage, write) {
|
|
73
|
+
this.storage = storage
|
|
74
|
+
this.write = write
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setCoreHead (head) {
|
|
78
|
+
this.write.tryPut(encodeCoreIndex(this.storage.corePointer, CORE.HEAD, this.storage.dataPointer), c.encode(m.CoreHead, head))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setCoreAuth ({ key, manifest }) {
|
|
82
|
+
this.write.tryPut(encodeCoreIndex(this.storage.corePointer, CORE.MANIFEST), c.encode(m.CoreAuth, { key, manifest }))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setBatchPointer (name, pointer) {
|
|
86
|
+
this.write.tryPut(encodeBatch(this.storage.corePointer, CORE.BATCHES, name), encode(m.DataPointer, pointer))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setDataDependency ({ data, length }) {
|
|
90
|
+
this.write.tryPut(encodeDataIndex(this.storage.dataPointer, DATA.DEPENDENCY), encode(m.DataDependency, { data, length }))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setLocalKeyPair (keyPair) {
|
|
94
|
+
this.write.tryPut(encodeCoreIndex(this.storage.corePointer, CORE.LOCAL_SEED), encode(m.KeyPair, keyPair))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
setEncryptionKey (encryptionKey) {
|
|
98
|
+
this.write.tryPut(encodeCoreIndex(this.storage.corePointer, CORE.ENCRYPTION_KEY), encryptionKey)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setDataInfo (info) {
|
|
102
|
+
if (info.version !== 0) throw new Error('Version > 0 is not supported')
|
|
103
|
+
this.write.tryPut(encodeDataIndex(this.storage.dataPointer, DATA.INFO), encode(m.DataInfo, info))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
setUserData (key, value) {
|
|
107
|
+
this.write.tryPut(encodeUserDataIndex(this.storage.dataPointer, DATA.USER_DATA, key), value)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
putBlock (index, data) {
|
|
111
|
+
this.write.tryPut(encodeDataIndex(this.storage.dataPointer, DATA.BLOCK, index), data)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
deleteBlock (index) {
|
|
115
|
+
this.write.tryDelete(encodeDataIndex(this.storage.dataPointer, DATA.BLOCK, index))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
deleteBlockRange (start, end) {
|
|
119
|
+
return this._deleteRange(DATA.BLOCK, start, end)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
putTreeNode (node) {
|
|
123
|
+
this.write.tryPut(encodeDataIndex(this.storage.dataPointer, DATA.TREE, node.index), encode(m.TreeNode, node))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
deleteTreeNode (index) {
|
|
127
|
+
this.write.tryDelete(encodeDataIndex(this.storage.dataPointer, DATA.TREE, index))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
deleteTreeNodeRange (start, end) {
|
|
131
|
+
return this._deleteRange(DATA.TREE, start, end)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
putBitfieldPage (index, page) {
|
|
135
|
+
this.write.tryPut(encodeDataIndex(this.storage.dataPointer, DATA.BITFIELD, index), page)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
deleteBitfieldPage (index) {
|
|
139
|
+
this.write.tryDelete(encodeDataIndex(this.storage.dataPointer, DATA.BITFIELD, index))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
deleteBitfieldPageRange (start, end) {
|
|
143
|
+
return this._deleteRange(DATA.BITFIELD, start, end)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
_deleteRange (type, start, end) {
|
|
147
|
+
const s = encodeDataIndex(this.storage.dataPointer, type, start)
|
|
148
|
+
const e = encodeDataIndex(this.storage.dataPointer, type, end === -1 ? Infinity : end)
|
|
149
|
+
|
|
150
|
+
return this.write.deleteRange(s, e)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
destroy () {
|
|
154
|
+
this.write.destroy()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
flush () {
|
|
158
|
+
return this.write.flush()
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
class ReadBatch {
|
|
163
|
+
constructor (storage, read) {
|
|
164
|
+
this.storage = storage
|
|
165
|
+
this.read = read
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async getCoreHead () {
|
|
169
|
+
return this._get(encodeCoreIndex(this.storage.corePointer, CORE.HEAD, this.storage.dataPointer), m.CoreHead)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async getCoreAuth () {
|
|
173
|
+
return this._get(encodeCoreIndex(this.storage.corePointer, CORE.MANIFEST), m.CoreAuth)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async getLocalKeyPair () {
|
|
177
|
+
return this._get(encodeCoreIndex(this.storage.corePointer, CORE.LOCAL_SEED), m.KeyPair)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async getEncryptionKey () {
|
|
181
|
+
return this._get(encodeCoreIndex(this.storage.corePointer, CORE.ENCRYPTION_KEY), null)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
getDataInfo (info) {
|
|
185
|
+
return this._get(encodeDataIndex(this.storage.dataPointer, DATA.INFO), m.DataInfo)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
getUserData (key) {
|
|
189
|
+
return this._get(encodeUserDataIndex(this.storage.dataPointer, DATA.USER_DATA, key), null)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async hasBlock (index) {
|
|
193
|
+
return this._has(encodeDataIndex(this.storage.dataPointer, DATA.BLOCK, index))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async getBlock (index, error) {
|
|
197
|
+
const dependency = findBlockDependency(this.storage.dependencies, index)
|
|
198
|
+
const dataPointer = dependency !== null ? dependency : this.storage.dataPointer
|
|
199
|
+
|
|
200
|
+
const key = encodeDataIndex(dataPointer, DATA.BLOCK, index)
|
|
201
|
+
const block = await this._get(key, null)
|
|
202
|
+
|
|
203
|
+
if (block === null && error === true) {
|
|
204
|
+
throw new Error('Node not found: ' + index)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return block
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async hasTreeNode (index) {
|
|
211
|
+
return this._has(encodeDataIndex(this.storage.dataPointer, DATA.TREE, index))
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async getTreeNode (index, error) {
|
|
215
|
+
const dependency = findTreeDependency(this.storage.dependencies, index)
|
|
216
|
+
const dataPointer = dependency !== null ? dependency : this.storage.dataPointer
|
|
217
|
+
|
|
218
|
+
const key = encodeDataIndex(dataPointer, DATA.TREE, index)
|
|
219
|
+
const node = await this._get(key, m.TreeNode)
|
|
220
|
+
|
|
221
|
+
if (node === null && error === true) {
|
|
222
|
+
throw new Error('Node not found: ' + index)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return node
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async getBitfieldPage (index) {
|
|
229
|
+
const key = encodeDataIndex(this.storage.dataPointer, DATA.BITFIELD, index)
|
|
230
|
+
return this._get(key, null)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async _has (key) {
|
|
234
|
+
return (await this.read.get(key)) !== null
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async _get (key, enc) {
|
|
238
|
+
const buffer = await this.read.get(key)
|
|
239
|
+
if (buffer === null) return null
|
|
240
|
+
|
|
241
|
+
if (enc) return c.decode(enc, buffer)
|
|
242
|
+
|
|
243
|
+
return buffer
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
destroy () {
|
|
247
|
+
this.read.destroy()
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
flush () {
|
|
251
|
+
return this.read.flush()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
tryFlush () {
|
|
255
|
+
this.read.tryFlush()
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = class CoreStorage {
|
|
260
|
+
constructor (dir, { autoClose = true } = {}) {
|
|
261
|
+
this.db = new RocksDB(dir)
|
|
262
|
+
this.mutex = new RW()
|
|
263
|
+
this.autoClose = !!autoClose
|
|
264
|
+
|
|
265
|
+
this.sessions = 0
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// just a helper to make tests easier
|
|
269
|
+
static async clear (dir) {
|
|
270
|
+
const s = new this(dir)
|
|
271
|
+
await s.clear()
|
|
272
|
+
return s
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async setLocalSeed (seed, overwrite) {
|
|
276
|
+
if (!overwrite) {
|
|
277
|
+
const existing = await getLocalSeed(this.db)
|
|
278
|
+
if (existing) return b4a.equals(existing, seed)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
await this.mutex.write.lock()
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
const b = this.db.write()
|
|
285
|
+
b.tryPut(b4a.from([TL.LOCAL_SEED]), seed)
|
|
286
|
+
await b.flush()
|
|
287
|
+
|
|
288
|
+
return true
|
|
289
|
+
} finally {
|
|
290
|
+
this.mutex.write.unlock()
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
getLocalSeed () {
|
|
295
|
+
return getLocalSeed(this.db)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
info () {
|
|
299
|
+
return getStorageInfo(this.db)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
list () {
|
|
303
|
+
const s = this.db.iterator({
|
|
304
|
+
gt: b4a.from([TL.DKEYS]),
|
|
305
|
+
lt: b4a.from([TL.DKEYS + 1])
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
s._readableState.map = mapOnlyDiscoveryKey
|
|
309
|
+
return s
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async idle () {
|
|
313
|
+
if (this.isIdle()) return
|
|
314
|
+
|
|
315
|
+
do {
|
|
316
|
+
await new Promise(setImmediate)
|
|
317
|
+
await this.db.idle()
|
|
318
|
+
await new Promise(setImmediate)
|
|
319
|
+
} while (!this.isIdle())
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
isIdle () {
|
|
323
|
+
return this.db.isIdle()
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
ready () {
|
|
327
|
+
return this.db.ready()
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
close () {
|
|
331
|
+
return this.db.close()
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async clear () {
|
|
335
|
+
const b = this.db.write()
|
|
336
|
+
b.tryDeleteRange(b4a.from([TL.STORAGE_INFO]), INF)
|
|
337
|
+
await b.flush()
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async has (discoveryKey) {
|
|
341
|
+
return !!(await this.db.get(encodeDiscoveryKey(discoveryKey)))
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async resume (discoveryKey) {
|
|
345
|
+
if (!discoveryKey) {
|
|
346
|
+
discoveryKey = await getDefaultKey(this.db)
|
|
347
|
+
if (!discoveryKey) return null
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const val = await this.db.get(encodeDiscoveryKey(discoveryKey))
|
|
351
|
+
if (val === null) return null
|
|
352
|
+
|
|
353
|
+
const { core, data } = c.decode(m.CorePointer, val)
|
|
354
|
+
|
|
355
|
+
return new HypercoreStorage(this, discoveryKey, core, data, null)
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async create ({ key, manifest, keyPair, encryptionKey, discoveryKey }) {
|
|
359
|
+
await this.mutex.write.lock()
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
const existing = await this.resume(discoveryKey)
|
|
363
|
+
|
|
364
|
+
if (existing) {
|
|
365
|
+
// todo: verify key/manifest etc.
|
|
366
|
+
return existing
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (!key) throw new Error('No key was provided')
|
|
370
|
+
|
|
371
|
+
let info = await getStorageInfo(this.db)
|
|
372
|
+
|
|
373
|
+
const write = this.db.write()
|
|
374
|
+
|
|
375
|
+
if (!info) {
|
|
376
|
+
write.tryPut(b4a.from([TL.DEFAULT_KEY]), discoveryKey)
|
|
377
|
+
info = { free: 0, total: 0 }
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const core = info.total++
|
|
381
|
+
const data = info.free++
|
|
382
|
+
|
|
383
|
+
write.tryPut(encodeDiscoveryKey(discoveryKey), encode(m.CorePointer, { core, data }))
|
|
384
|
+
write.tryPut(b4a.from([TL.STORAGE_INFO]), encode(m.StorageInfo, info))
|
|
385
|
+
|
|
386
|
+
const storage = new HypercoreStorage(this, discoveryKey, core, data, null)
|
|
387
|
+
const batch = new WriteBatch(storage, write)
|
|
388
|
+
|
|
389
|
+
initialiseCoreInfo(batch, { key, manifest, keyPair, encryptionKey })
|
|
390
|
+
initialiseCoreData(batch)
|
|
391
|
+
|
|
392
|
+
await batch.flush()
|
|
393
|
+
return storage
|
|
394
|
+
} finally {
|
|
395
|
+
this.mutex.write.unlock()
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
_onclose () {
|
|
400
|
+
if (--this.sessions > 0 || !this.autoClose) return Promise.resolve()
|
|
401
|
+
return this.close()
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
class HypercoreStorage {
|
|
406
|
+
constructor (root, discoveryKey, core, data, snapshot) {
|
|
407
|
+
this.root = root
|
|
408
|
+
this.db = root.db
|
|
409
|
+
this.dbSnapshot = snapshot
|
|
410
|
+
this.mutex = root.mutex
|
|
411
|
+
|
|
412
|
+
this.root.sessions++
|
|
413
|
+
|
|
414
|
+
this.discoveryKey = discoveryKey
|
|
415
|
+
|
|
416
|
+
this.dependencies = []
|
|
417
|
+
|
|
418
|
+
// pointers
|
|
419
|
+
this.corePointer = core
|
|
420
|
+
this.dataPointer = data
|
|
421
|
+
|
|
422
|
+
this.closed = false
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
get snapshotted () {
|
|
426
|
+
return this.dbSnapshot !== null
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async registerBatch (name, length, overwrite) {
|
|
430
|
+
// todo: make sure opened
|
|
431
|
+
const existing = await this.db.get(encodeBatch(this.corePointer, CORE.BATCHES, name))
|
|
432
|
+
const storage = new HypercoreStorage(this.root, this.discoveryKey, this.corePointer, this.dataPointer, null)
|
|
433
|
+
|
|
434
|
+
if (existing && !overwrite) {
|
|
435
|
+
const dataPointer = c.decode(m.DataPointer, existing)
|
|
436
|
+
storage.dataPointer = dataPointer
|
|
437
|
+
storage.dependencies = await addDependencies(this.db, storage.dataPointer, length)
|
|
438
|
+
return storage
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
await this.mutex.write.lock()
|
|
442
|
+
|
|
443
|
+
try {
|
|
444
|
+
const info = await getStorageInfo(this.db)
|
|
445
|
+
|
|
446
|
+
const write = this.db.write()
|
|
447
|
+
|
|
448
|
+
storage.dataPointer = info.free++
|
|
449
|
+
|
|
450
|
+
write.tryPut(b4a.from([TL.STORAGE_INFO]), encode(m.StorageInfo, info))
|
|
451
|
+
|
|
452
|
+
const batch = new WriteBatch(storage, write)
|
|
453
|
+
|
|
454
|
+
initialiseCoreData(batch)
|
|
455
|
+
|
|
456
|
+
batch.setDataDependency({ data: this.dataPointer, length })
|
|
457
|
+
batch.setBatchPointer(name, storage.dataPointer)
|
|
458
|
+
|
|
459
|
+
await write.flush()
|
|
460
|
+
|
|
461
|
+
storage.dependencies = await addDependencies(this.db, storage.dataPointer, length)
|
|
462
|
+
return storage
|
|
463
|
+
} finally {
|
|
464
|
+
this.mutex.write.unlock()
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
snapshot () {
|
|
469
|
+
assert(this.closed === false)
|
|
470
|
+
return new HypercoreStorage(this.root, this.discoveryKey, this.corePointer, this.dataPointer, this.db.snapshot())
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
createReadBatch (opts) {
|
|
474
|
+
assert(this.closed === false)
|
|
475
|
+
|
|
476
|
+
const snapshot = this.dbSnapshot
|
|
477
|
+
return new ReadBatch(this, this.db.read({ snapshot }))
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
createWriteBatch () {
|
|
481
|
+
assert(this.closed === false)
|
|
482
|
+
|
|
483
|
+
return new WriteBatch(this, this.db.write())
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
createBlockStream (opts = {}) {
|
|
487
|
+
assert(this.closed === false)
|
|
488
|
+
return createStream(this, createBlockStream, opts)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
createUserDataStream (opts = {}) {
|
|
492
|
+
assert(this.closed === false)
|
|
493
|
+
|
|
494
|
+
const r = encodeIndexRange(this.dataPointer, DATA.USER_DATA, this.dbSnapshot, opts)
|
|
495
|
+
const s = this.db.iterator(r)
|
|
496
|
+
s._readableState.map = mapStreamUserData
|
|
497
|
+
return s
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
createTreeNodeStream (opts = {}) {
|
|
501
|
+
assert(this.closed === false)
|
|
502
|
+
|
|
503
|
+
const r = encodeIndexRange(this.dataPointer, DATA.TREE, this.dbSnapshot, opts)
|
|
504
|
+
const s = this.db.iterator(r)
|
|
505
|
+
s._readableState.map = mapStreamTreeNode
|
|
506
|
+
return s
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
createBitfieldPageStream (opts = {}) {
|
|
510
|
+
assert(this.closed === false)
|
|
511
|
+
|
|
512
|
+
const r = encodeIndexRange(this.dataPointer, DATA.BITFIELD, this.dbSnapshot, opts)
|
|
513
|
+
const s = this.db.iterator(r)
|
|
514
|
+
s._readableState.map = mapStreamBitfieldPage
|
|
515
|
+
return s
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async peakLastTreeNode () {
|
|
519
|
+
assert(this.closed === false)
|
|
520
|
+
|
|
521
|
+
const last = await this.db.peek(encodeIndexRange(this.dataPointer, DATA.TREE, this.dbSnapshot, { reverse: true }))
|
|
522
|
+
if (last === null) return null
|
|
523
|
+
return c.decode(m.TreeNode, last.value)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async peakLastBitfieldPage () {
|
|
527
|
+
assert(this.closed === false)
|
|
528
|
+
|
|
529
|
+
const last = await this.db.peek(encodeIndexRange(this.dataPointer, DATA.BITFIELD, this.dbSnapshot, { reverse: true }))
|
|
530
|
+
if (last === null) return null
|
|
531
|
+
return mapStreamBitfieldPage(last)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
close () {
|
|
535
|
+
if (this.closed) return Promise.resolve()
|
|
536
|
+
this.closed = true
|
|
537
|
+
|
|
538
|
+
if (this.dbSnapshot) this.dbSnapshot.destroy()
|
|
539
|
+
this.dbSnapshot = null
|
|
540
|
+
|
|
541
|
+
return this.root._onclose()
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function createStream (storage, createStreamType, opts) {
|
|
546
|
+
return storage.dependencies.length === 0
|
|
547
|
+
? createStreamType(storage.db, storage.dbSnapshot, storage.dataPointer, opts)
|
|
548
|
+
: new DependencyStream(storage, createStreamType, opts)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function createBlockStream (db, snap, data, opts) {
|
|
552
|
+
const r = encodeIndexRange(data, DATA.BLOCK, snap, opts)
|
|
553
|
+
const s = db.iterator(r)
|
|
554
|
+
s._readableState.map = mapStreamBlock
|
|
555
|
+
return s
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function mapStreamUserData (data) {
|
|
559
|
+
const state = { start: 0, end: data.key.byteLength, buffer: data.key }
|
|
560
|
+
|
|
561
|
+
UINT.decode(state) // TL.DATA
|
|
562
|
+
UINT.decode(state) // pointer
|
|
563
|
+
UINT.decode(state) // DATA.USER_DATA
|
|
564
|
+
|
|
565
|
+
const key = c.string.decode(state)
|
|
566
|
+
|
|
567
|
+
return { key, value: data.value }
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function mapStreamTreeNode (data) {
|
|
571
|
+
return c.decode(m.TreeNode, data.value)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function mapStreamBitfieldPage (data) {
|
|
575
|
+
const state = { start: 0, end: data.key.byteLength, buffer: data.key }
|
|
576
|
+
|
|
577
|
+
UINT.decode(state) // TL.DATA
|
|
578
|
+
UINT.decode(state) // pointer
|
|
579
|
+
UINT.decode(state) // DATA.BITFIELD
|
|
580
|
+
|
|
581
|
+
const index = UINT.decode(state)
|
|
582
|
+
|
|
583
|
+
return { index, page: data.value }
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function mapStreamBlock (data) {
|
|
587
|
+
const state = { start: 0, end: data.key.byteLength, buffer: data.key }
|
|
588
|
+
|
|
589
|
+
UINT.decode(state) // TL.DATA
|
|
590
|
+
UINT.decode(state) // pointer
|
|
591
|
+
UINT.decode(state) // DATA.BITFIELD
|
|
592
|
+
|
|
593
|
+
const index = UINT.decode(state)
|
|
594
|
+
return { index, value: data.value }
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function mapOnlyDiscoveryKey (data) {
|
|
598
|
+
return data.key.subarray(1)
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
async function getDefaultKey (db) {
|
|
602
|
+
return db.get(b4a.from([TL.DEFAULT_KEY]))
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async function getLocalSeed (db) {
|
|
606
|
+
return db.get(b4a.from([TL.LOCAL_SEED]))
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
async function getStorageInfo (db) {
|
|
610
|
+
const value = await db.get(b4a.from([TL.STORAGE_INFO]))
|
|
611
|
+
if (value === null) return null
|
|
612
|
+
return c.decode(m.StorageInfo, value)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function ensureSlab (size) {
|
|
616
|
+
if (SLAB.buffer.byteLength - SLAB.start < size) {
|
|
617
|
+
SLAB.buffer = b4a.allocUnsafe(SLAB.end)
|
|
618
|
+
SLAB.start = 0
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return SLAB
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function encodeIndexRange (pointer, type, snapshot, opts) {
|
|
625
|
+
const bounded = { snapshot, gt: null, gte: null, lte: null, lt: null, reverse: !!opts.reverse, limit: toLimit(opts.limit) }
|
|
626
|
+
|
|
627
|
+
if (opts.gt || opts.gt === 0) bounded.gt = encodeDataIndex(pointer, type, opts.gt)
|
|
628
|
+
else if (opts.gte) bounded.gte = encodeDataIndex(pointer, type, opts.gte)
|
|
629
|
+
else bounded.gte = encodeDataIndex(pointer, type, 0)
|
|
630
|
+
|
|
631
|
+
if (opts.lt || opts.lt === 0) bounded.lt = encodeDataIndex(pointer, type, opts.lt)
|
|
632
|
+
else if (opts.lte) bounded.lte = encodeDataIndex(pointer, type, opts.lte)
|
|
633
|
+
else bounded.lte = encodeDataIndex(pointer, type, Infinity) // infinity
|
|
634
|
+
|
|
635
|
+
return bounded
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function toLimit (n) {
|
|
639
|
+
return n === 0 ? 0 : (n || Infinity)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function encode (encoding, value) {
|
|
643
|
+
const state = ensureSlab(128)
|
|
644
|
+
const start = state.start
|
|
645
|
+
encoding.encode(state, value)
|
|
646
|
+
|
|
647
|
+
assert(state.start <= state.end)
|
|
648
|
+
|
|
649
|
+
return state.buffer.subarray(start, state.start)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function encodeBatch (pointer, type, name) {
|
|
653
|
+
const end = 128 + name.length
|
|
654
|
+
const state = { start: 0, end, buffer: b4a.allocUnsafe(end) }
|
|
655
|
+
const start = state.start
|
|
656
|
+
UINT.encode(state, TL.CORE)
|
|
657
|
+
UINT.encode(state, pointer)
|
|
658
|
+
UINT.encode(state, type)
|
|
659
|
+
c.string.encode(state, name)
|
|
660
|
+
|
|
661
|
+
return state.buffer.subarray(start, state.start)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function encodeCoreIndex (pointer, type, index) {
|
|
665
|
+
const state = ensureSlab(128)
|
|
666
|
+
const start = state.start
|
|
667
|
+
UINT.encode(state, TL.CORE)
|
|
668
|
+
UINT.encode(state, pointer)
|
|
669
|
+
UINT.encode(state, type)
|
|
670
|
+
if (index !== undefined) UINT.encode(state, index)
|
|
671
|
+
|
|
672
|
+
return state.buffer.subarray(start, state.start)
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function encodeDataIndex (pointer, type, index) {
|
|
676
|
+
const state = ensureSlab(128)
|
|
677
|
+
const start = state.start
|
|
678
|
+
UINT.encode(state, TL.DATA)
|
|
679
|
+
UINT.encode(state, pointer)
|
|
680
|
+
UINT.encode(state, type)
|
|
681
|
+
if (index !== undefined) UINT.encode(state, index)
|
|
682
|
+
|
|
683
|
+
return state.buffer.subarray(start, state.start)
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
function encodeUserDataIndex (pointer, type, key) {
|
|
687
|
+
const end = 128 + key.length
|
|
688
|
+
const state = { start: 0, end, buffer: b4a.allocUnsafe(end) }
|
|
689
|
+
const start = state.start
|
|
690
|
+
UINT.encode(state, TL.DATA)
|
|
691
|
+
UINT.encode(state, pointer)
|
|
692
|
+
UINT.encode(state, type)
|
|
693
|
+
c.string.encode(state, key)
|
|
694
|
+
|
|
695
|
+
return state.buffer.subarray(start, state.start)
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
function encodeDiscoveryKey (discoveryKey) {
|
|
699
|
+
const state = ensureSlab(128)
|
|
700
|
+
const start = state.start
|
|
701
|
+
UINT.encode(state, TL.DKEYS)
|
|
702
|
+
c.fixed32.encode(state, discoveryKey)
|
|
703
|
+
return state.buffer.subarray(start, state.start)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
async function addDependencies (db, dataPointer, treeLength) {
|
|
707
|
+
const dependencies = []
|
|
708
|
+
|
|
709
|
+
let dep = await db.get(encodeDataIndex(dataPointer, DATA.DEPENDENCY))
|
|
710
|
+
while (dep) {
|
|
711
|
+
const { data, length } = c.decode(m.DataDependency, dep)
|
|
712
|
+
if (length <= treeLength) dependencies.push({ data, length })
|
|
713
|
+
|
|
714
|
+
dep = await db.get(encodeDataIndex(data, DATA.DEPENDENCY))
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return dependencies
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function findBlockDependency (dependencies, index) {
|
|
721
|
+
for (const { data, length } of dependencies) {
|
|
722
|
+
if (index < length) return data
|
|
723
|
+
}
|
|
724
|
+
return null
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function findTreeDependency (dependencies, index) {
|
|
728
|
+
for (const { data, length } of dependencies) {
|
|
729
|
+
if (flat.rightSpan(index) <= (length - 1) * 2) return data
|
|
730
|
+
}
|
|
731
|
+
return null
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
function initialiseCoreInfo (db, { key, manifest, keyPair, encryptionKey }) {
|
|
735
|
+
db.setCoreAuth({ key, manifest })
|
|
736
|
+
if (keyPair) db.setLocalKeyPair(keyPair)
|
|
737
|
+
if (encryptionKey) db.setEncryptionKey(encryptionKey)
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function initialiseCoreData (db) {
|
|
741
|
+
db.setDataInfo({ version: 0 })
|
|
742
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const { Readable, isEnded, getStreamError } = require('streamx')
|
|
2
|
+
|
|
3
|
+
module.exports = class DependencyStream extends Readable {
|
|
4
|
+
constructor (storage, createStream, opts = {}) {
|
|
5
|
+
super()
|
|
6
|
+
|
|
7
|
+
this.storage = storage
|
|
8
|
+
this.createStream = createStream
|
|
9
|
+
|
|
10
|
+
let max = 0
|
|
11
|
+
|
|
12
|
+
const reverse = !!opts.reverse
|
|
13
|
+
const limit = opts.limit === 0 ? 0 : (opts.limit || Infinity)
|
|
14
|
+
const gte = typeof opts.gte === 'number' ? opts.gte : typeof opts.gt === 'number' ? opts.gt + 1 : 0
|
|
15
|
+
const lt = typeof opts.lt === 'number' ? opts.lt : typeof opts.lte === 'number' ? opts.lte + 1 : Infinity
|
|
16
|
+
|
|
17
|
+
const streams = []
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < storage.dependencies.length; i++) {
|
|
20
|
+
const min = max
|
|
21
|
+
max += storage.dependencies[i].length
|
|
22
|
+
|
|
23
|
+
streams.push({
|
|
24
|
+
data: storage.dependencies[i].data,
|
|
25
|
+
gte: Math.max(gte, min),
|
|
26
|
+
lt: Math.min(lt, max)
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
streams.push({
|
|
31
|
+
data: storage.dataPointer,
|
|
32
|
+
gte: Math.max(gte, max),
|
|
33
|
+
lt
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
this._streams = reverse ? streams.reverse() : streams
|
|
37
|
+
this._reverse = reverse
|
|
38
|
+
this._limit = limit
|
|
39
|
+
this._next = 0
|
|
40
|
+
this._active = null
|
|
41
|
+
this._pendingDestroy = null
|
|
42
|
+
this._ondataBound = this._ondata.bind(this)
|
|
43
|
+
this._oncloseBound = this._onclose.bind(this)
|
|
44
|
+
|
|
45
|
+
this._nextStream()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_read (cb) {
|
|
49
|
+
this._active.resume()
|
|
50
|
+
cb(null)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_predestroy () {
|
|
54
|
+
if (this._active) this._active.destroy()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_destroy (cb) {
|
|
58
|
+
if (this._active === null) cb(null)
|
|
59
|
+
else this._pendingDestroy = cb
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_ondata (data) {
|
|
63
|
+
if (this._limit > 0) this._limit--
|
|
64
|
+
if (this.push(data) === false) this._active.pause()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_onclose () {
|
|
68
|
+
if (!isEnded(this._active)) {
|
|
69
|
+
const error = getStreamError(this._active)
|
|
70
|
+
this._active = null
|
|
71
|
+
this.destroy(error)
|
|
72
|
+
this._continueDestroy(error)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (this._next >= this._streams.length || this._limit === 0) {
|
|
77
|
+
this._active = null
|
|
78
|
+
this.push(null)
|
|
79
|
+
this._continueDestroy(null)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this._nextStream()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_continueDestroy (err) {
|
|
87
|
+
if (this._pendingDestroy === null) return
|
|
88
|
+
const cb = this._pendingDestroy
|
|
89
|
+
this._pendingDestroy = null
|
|
90
|
+
cb(err)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_nextStream () {
|
|
94
|
+
const { data, gte, lt } = this._streams[this._next++]
|
|
95
|
+
|
|
96
|
+
const stream = this.createStream(this.storage.db, this.storage.dbSnapshot, data, {
|
|
97
|
+
reverse: this._reverse,
|
|
98
|
+
limit: this._limit,
|
|
99
|
+
gte,
|
|
100
|
+
lt
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
this._active = stream
|
|
104
|
+
|
|
105
|
+
stream.on('data', this._ondataBound)
|
|
106
|
+
stream.on('error', noop) // handled in onclose
|
|
107
|
+
stream.on('close', this._oncloseBound)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function noop () {}
|
package/lib/messages.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const c = require('compact-encoding')
|
|
2
|
+
|
|
3
|
+
exports.DataPointer = c.uint
|
|
4
|
+
|
|
5
|
+
exports.KeyPair = {
|
|
6
|
+
preencode (state, m) {
|
|
7
|
+
c.uint.preencode(state, m.secretKey ? 1 : 0)
|
|
8
|
+
c.fixed32.preencode(state, m.publicKey)
|
|
9
|
+
if (m.secretKey) c.fixed64.preencode(state, m.secretKey)
|
|
10
|
+
},
|
|
11
|
+
encode (state, m) {
|
|
12
|
+
c.uint.encode(state, m.secretKey ? 1 : 0)
|
|
13
|
+
c.fixed32.encode(state, m.publicKey)
|
|
14
|
+
if (m.secretKey) c.fixed64.encode(state, m.secretKey)
|
|
15
|
+
},
|
|
16
|
+
decode (state) {
|
|
17
|
+
const flags = c.uint.decode(state)
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
publicKey: c.fixed32.decode(state),
|
|
21
|
+
secretKey: flags & 1 ? c.fixed64.decode(state) : null
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.StorageInfo = {
|
|
27
|
+
preencode (state, m) {
|
|
28
|
+
c.uint.preencode(state, m.version)
|
|
29
|
+
c.uint.preencode(state, 0) // flags, reserved
|
|
30
|
+
c.uint.preencode(state, m.free)
|
|
31
|
+
c.uint.preencode(state, m.total)
|
|
32
|
+
},
|
|
33
|
+
encode (state, m) {
|
|
34
|
+
c.uint.encode(state, m.version)
|
|
35
|
+
c.uint.encode(state, 0) // flags, reserved
|
|
36
|
+
c.uint.encode(state, m.free)
|
|
37
|
+
c.uint.encode(state, m.total)
|
|
38
|
+
},
|
|
39
|
+
decode (state, m) {
|
|
40
|
+
const v = c.uint.decode(state)
|
|
41
|
+
if (v !== 0) throw new Error('Invalid version: ' + v)
|
|
42
|
+
|
|
43
|
+
c.uint.decode(state) // flags, ignore
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
free: c.uint.decode(state),
|
|
47
|
+
total: c.uint.decode(state)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
exports.CorePointer = {
|
|
53
|
+
preencode (state, m) {
|
|
54
|
+
c.uint.preencode(state, m.core)
|
|
55
|
+
c.uint.preencode(state, m.data)
|
|
56
|
+
},
|
|
57
|
+
encode (state, m) {
|
|
58
|
+
c.uint.encode(state, m.core)
|
|
59
|
+
c.uint.encode(state, m.data)
|
|
60
|
+
},
|
|
61
|
+
decode (state) {
|
|
62
|
+
return {
|
|
63
|
+
core: c.uint.decode(state),
|
|
64
|
+
data: c.uint.decode(state)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.CoreHead = {
|
|
70
|
+
preencode (state, m) {
|
|
71
|
+
c.uint.preencode(state, m.fork)
|
|
72
|
+
c.uint.preencode(state, m.length)
|
|
73
|
+
c.fixed32.preencode(state, m.rootHash)
|
|
74
|
+
c.buffer.preencode(state, m.signature)
|
|
75
|
+
},
|
|
76
|
+
encode (state, m) {
|
|
77
|
+
c.uint.encode(state, m.fork)
|
|
78
|
+
c.uint.encode(state, m.length)
|
|
79
|
+
c.fixed32.encode(state, m.rootHash)
|
|
80
|
+
c.buffer.encode(state, m.signature)
|
|
81
|
+
},
|
|
82
|
+
decode (state) {
|
|
83
|
+
return {
|
|
84
|
+
fork: c.uint.decode(state),
|
|
85
|
+
length: c.uint.decode(state),
|
|
86
|
+
rootHash: c.fixed32.decode(state),
|
|
87
|
+
signature: c.buffer.decode(state)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
exports.TreeNode = {
|
|
93
|
+
preencode (state, m) {
|
|
94
|
+
c.uint.preencode(state, m.index)
|
|
95
|
+
c.uint.preencode(state, m.size)
|
|
96
|
+
c.fixed32.preencode(state, m.hash)
|
|
97
|
+
},
|
|
98
|
+
encode (state, m) {
|
|
99
|
+
c.uint.encode(state, m.index)
|
|
100
|
+
c.uint.encode(state, m.size)
|
|
101
|
+
c.fixed32.encode(state, m.hash)
|
|
102
|
+
},
|
|
103
|
+
decode (state) {
|
|
104
|
+
return {
|
|
105
|
+
index: c.uint.decode(state),
|
|
106
|
+
size: c.uint.decode(state),
|
|
107
|
+
hash: c.fixed32.decode(state)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
exports.CoreAuth = {
|
|
113
|
+
preencode (state, m) {
|
|
114
|
+
c.uint.preencode(state, m.manifest ? 1 : 0)
|
|
115
|
+
c.fixed32.preencode(state, m.key)
|
|
116
|
+
if (m.manifest) c.buffer.preencode(state, m.manifest)
|
|
117
|
+
},
|
|
118
|
+
encode (state, m) {
|
|
119
|
+
c.uint.encode(state, m.manifest ? 1 : 0)
|
|
120
|
+
c.fixed32.encode(state, m.key)
|
|
121
|
+
if (m.manifest) c.buffer.encode(state, m.manifest)
|
|
122
|
+
},
|
|
123
|
+
decode (state) {
|
|
124
|
+
const flags = c.uint.decode(state)
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
key: c.fixed32.decode(state),
|
|
128
|
+
manifest: flags & 1 ? c.buffer.decode(state) : null
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
exports.DataDependency = {
|
|
134
|
+
preencode (state, m) {
|
|
135
|
+
c.uint.preencode(state, m.data)
|
|
136
|
+
c.uint.preencode(state, m.length)
|
|
137
|
+
},
|
|
138
|
+
encode (state, m) {
|
|
139
|
+
c.uint.encode(state, m.data)
|
|
140
|
+
c.uint.encode(state, m.length)
|
|
141
|
+
},
|
|
142
|
+
decode (state) {
|
|
143
|
+
return {
|
|
144
|
+
data: c.uint.decode(state),
|
|
145
|
+
length: c.uint.decode(state)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
exports.CoreSeed = {
|
|
151
|
+
preencode (state, m) {
|
|
152
|
+
c.fixed32.preencode(state, m.seed)
|
|
153
|
+
},
|
|
154
|
+
encode (state, m) {
|
|
155
|
+
c.fixed32.encode(state, m.seed)
|
|
156
|
+
},
|
|
157
|
+
decode (state) {
|
|
158
|
+
return {
|
|
159
|
+
seed: c.fixed32.decode(state)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
exports.CoreEncryptionKey = {
|
|
165
|
+
preencode (state, m) {
|
|
166
|
+
c.fixed32.preencode(state, m.encryptionKey)
|
|
167
|
+
},
|
|
168
|
+
encode (state, m) {
|
|
169
|
+
c.fixed32.encode(state, m.encryptionKey)
|
|
170
|
+
},
|
|
171
|
+
decode (state) {
|
|
172
|
+
return {
|
|
173
|
+
encryptionKey: c.fixed32.decode(state)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
exports.DataInfo = {
|
|
179
|
+
preencode (state, m) {
|
|
180
|
+
c.uint.preencode(state, m.version)
|
|
181
|
+
},
|
|
182
|
+
encode (state, m) {
|
|
183
|
+
c.uint.encode(state, m.version)
|
|
184
|
+
},
|
|
185
|
+
decode (state) {
|
|
186
|
+
return {
|
|
187
|
+
version: c.uint.decode(state)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hypercore-storage",
|
|
3
|
+
"version": "0.0.21",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"files": [
|
|
6
|
+
"index.js",
|
|
7
|
+
"lib/*.js"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "standard && brittle test/*.js"
|
|
11
|
+
},
|
|
12
|
+
"author": "Holepunch",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"description": "RocksDB storage driver for Hypercore",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"b4a": "^1.6.6",
|
|
17
|
+
"compact-encoding": "^2.15.0",
|
|
18
|
+
"flat-tree": "^1.10.0",
|
|
19
|
+
"index-encoder": "^3.0.1",
|
|
20
|
+
"nanoassert": "^2.0.0",
|
|
21
|
+
"read-write-mutexify": "^2.1.0",
|
|
22
|
+
"rocksdb-native": "^2.2.0",
|
|
23
|
+
"streamx": "^2.20.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"brittle": "^3.5.2",
|
|
27
|
+
"standard": "^17.1.0",
|
|
28
|
+
"test-tmp": "^1.2.1"
|
|
29
|
+
}
|
|
30
|
+
}
|