hypercore 10.0.0-alpha.9 → 10.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/README.md +83 -22
- package/index.js +583 -212
- package/lib/bitfield.js +109 -41
- package/lib/block-encryption.js +3 -2
- package/lib/block-store.js +6 -4
- package/lib/caps.js +32 -0
- package/lib/core.js +166 -35
- package/lib/errors.js +50 -0
- package/lib/info.js +23 -0
- package/lib/merkle-tree.js +181 -105
- package/lib/messages.js +249 -168
- package/lib/oplog.js +4 -3
- package/lib/remote-bitfield.js +28 -7
- package/lib/replicator.js +1415 -624
- package/lib/streams.js +56 -0
- package/package.json +20 -15
- package/.github/workflows/test-node.yml +0 -23
- package/CHANGELOG.md +0 -37
- package/UPGRADE.md +0 -9
- package/examples/announce.js +0 -19
- package/examples/basic.js +0 -10
- package/examples/http.js +0 -123
- package/examples/lookup.js +0 -20
- package/lib/extensions.js +0 -76
- package/lib/protocol.js +0 -524
- package/lib/random-iterator.js +0 -46
- package/test/basic.js +0 -90
- package/test/bitfield.js +0 -71
- package/test/core.js +0 -290
- package/test/encodings.js +0 -18
- package/test/encryption.js +0 -121
- package/test/extension.js +0 -71
- package/test/helpers/index.js +0 -23
- package/test/merkle-tree.js +0 -518
- package/test/mutex.js +0 -137
- package/test/oplog.js +0 -399
- package/test/preload.js +0 -72
- package/test/replicate.js +0 -372
- package/test/sessions.js +0 -173
- package/test/user-data.js +0 -47
package/lib/protocol.js
DELETED
|
@@ -1,524 +0,0 @@
|
|
|
1
|
-
const { uint, from: fromEncoding } = require('compact-encoding')
|
|
2
|
-
const safetyCatch = require('safety-catch')
|
|
3
|
-
const codecs = require('codecs')
|
|
4
|
-
|
|
5
|
-
const messages = require('./messages')
|
|
6
|
-
|
|
7
|
-
class Extension {
|
|
8
|
-
constructor (protocol, type, name, handlers) {
|
|
9
|
-
this.protocol = protocol
|
|
10
|
-
this.name = name
|
|
11
|
-
this.type = type
|
|
12
|
-
this.peers = new Set()
|
|
13
|
-
this.aliased = !!handlers.aliased
|
|
14
|
-
this.remoteSupports = false
|
|
15
|
-
this.destroyed = false
|
|
16
|
-
|
|
17
|
-
this.onerror = handlers.onerror || noop
|
|
18
|
-
this.onclose = handlers.onclose || noop
|
|
19
|
-
this.onmessage = handlers.onmessage || noop
|
|
20
|
-
this.onremotesupports = handlers.onremotesupports || noop
|
|
21
|
-
|
|
22
|
-
this.encoding = fromEncoding(codecs(handlers.encoding || 'binary'))
|
|
23
|
-
this.announce()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
announce () {
|
|
27
|
-
if (this.destroyed) return
|
|
28
|
-
|
|
29
|
-
this.protocol.send(1, messages.extension, -1, { alias: this.type, name: this.name })
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
send (message) {
|
|
33
|
-
if (this.destroyed) return
|
|
34
|
-
|
|
35
|
-
return this._sendAlias(message, -1)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
_sendAlias (message, alias) {
|
|
39
|
-
if (this.destroyed) return
|
|
40
|
-
|
|
41
|
-
if (this._remoteAliases) {
|
|
42
|
-
return this.protocol.send(this.type, this.encoding, alias, message)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
this.protocol.cork()
|
|
46
|
-
this.announce()
|
|
47
|
-
this.protocol.send(this.type, this.encoding, alias, message)
|
|
48
|
-
this.protocol.uncork()
|
|
49
|
-
|
|
50
|
-
return false
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
_onremotesupports () {
|
|
54
|
-
if (this.destroyed) return
|
|
55
|
-
|
|
56
|
-
this.remoteSupports = true
|
|
57
|
-
this.onremotesupports(this)
|
|
58
|
-
for (const peer of this.peers) {
|
|
59
|
-
peer.onremotesupports(peer)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
_onmessage (state) {
|
|
64
|
-
if (this.destroyed) return
|
|
65
|
-
|
|
66
|
-
if (!this.aliased) {
|
|
67
|
-
this.onmessage(this.encoding.decode(state))
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const alias = uint.decode(state)
|
|
72
|
-
const m = this.encoding.decode(state)
|
|
73
|
-
|
|
74
|
-
for (const peer of this.peers) {
|
|
75
|
-
if (peer.alias === alias) {
|
|
76
|
-
peer.onmessage(m, peer.peer)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
destroy () {
|
|
82
|
-
if (this.destroyed) return
|
|
83
|
-
this.destroyed = true
|
|
84
|
-
this.protocol.unregisterExtension(this.name)
|
|
85
|
-
this.onclose()
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
class CoreExtension {
|
|
90
|
-
constructor (ext, peer, name, handlers) {
|
|
91
|
-
this.extension = ext
|
|
92
|
-
this.peer = peer
|
|
93
|
-
this.name = name
|
|
94
|
-
this.alias = peer.alias
|
|
95
|
-
this.onmessage = handlers.onmessage || noop
|
|
96
|
-
this.onremotesupports = handlers.onremotesupports || noop
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
get remoteSupports () {
|
|
100
|
-
return this.extension.remoteSupports
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
announce () {
|
|
104
|
-
this.extension.announce()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
send (message) {
|
|
108
|
-
return this.extension._sendAlias(message, this.peer.alias)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
destroy () {
|
|
112
|
-
this.peer.extensions.delete(this.name)
|
|
113
|
-
this.extension.peers.delete(this)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
class Peer {
|
|
118
|
-
constructor (protocol, alias, key, discoveryKey, handlers, state) {
|
|
119
|
-
this.protocol = protocol
|
|
120
|
-
this.handlers = handlers
|
|
121
|
-
this.key = key
|
|
122
|
-
this.discoveryKey = discoveryKey
|
|
123
|
-
this.alias = alias
|
|
124
|
-
this.remoteAlias = -1
|
|
125
|
-
this.resend = false
|
|
126
|
-
this.state = state
|
|
127
|
-
this.extensions = new Map()
|
|
128
|
-
this.destroyed = false
|
|
129
|
-
|
|
130
|
-
this._destroyer = this._safeDestroy.bind(this)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
onmessage (type, state) {
|
|
134
|
-
const handlers = this.handlers
|
|
135
|
-
|
|
136
|
-
switch (type) {
|
|
137
|
-
case 4: {
|
|
138
|
-
this._catch(handlers.oninfo(messages.info.decode(state), this))
|
|
139
|
-
break
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
case 5: {
|
|
143
|
-
// options
|
|
144
|
-
break
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
case 6: {
|
|
148
|
-
// want
|
|
149
|
-
break
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
case 7: {
|
|
153
|
-
this._catch(handlers.onhave(messages.have.decode(state), this))
|
|
154
|
-
break
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
case 8: {
|
|
158
|
-
this._catch(handlers.onbitfield(messages.bitfield.decode(state), this))
|
|
159
|
-
break
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
case 9: {
|
|
163
|
-
this._catch(handlers.onrequest(messages.request.decode(state), this))
|
|
164
|
-
break
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
case 10: {
|
|
168
|
-
this._catch(handlers.ondata(messages.data.decode(state), this))
|
|
169
|
-
break
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
state.start = state.end
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
_catch (p) {
|
|
177
|
-
if (isPromise(p)) p.then(noop, this._destroyer)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
registerExtension (name, handlers) {
|
|
181
|
-
if (this.extensions.has(name)) return this.extensions.get(name)
|
|
182
|
-
const ext = this.protocol.registerExtension(name, { aliased: true, encoding: handlers.encoding })
|
|
183
|
-
const coreExt = new CoreExtension(ext, this, name, handlers)
|
|
184
|
-
ext.peers.add(coreExt)
|
|
185
|
-
this.extensions.set(name, coreExt)
|
|
186
|
-
return coreExt
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
cork () {
|
|
190
|
-
this.protocol.cork()
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
uncork () {
|
|
194
|
-
this.protocol.uncork()
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
info (message) {
|
|
198
|
-
return this.protocol.send(4, messages.info, this.alias, message)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
options (message) {
|
|
202
|
-
// TODO
|
|
203
|
-
// this._send(5, messages.info, this.alias, message)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
want (message) {
|
|
207
|
-
// TODO
|
|
208
|
-
// this._send(6, messages.info, this.alias, message)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
have (message) {
|
|
212
|
-
return this.protocol.send(7, messages.have, this.alias, message)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
bitfield (message) {
|
|
216
|
-
return this.protocol.send(8, messages.bitfield, this.alias, message)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
request (message) {
|
|
220
|
-
return this.protocol.send(9, messages.request, this.alias, message)
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
data (message) {
|
|
224
|
-
return this.protocol.send(10, messages.data, this.alias, message)
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
_safeDestroy (err) {
|
|
228
|
-
safetyCatch(err)
|
|
229
|
-
return this.destroy(err)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
destroy (err) {
|
|
233
|
-
this.destroyed = true
|
|
234
|
-
return this.protocol.unregisterPeer(this, err)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
module.exports = class Protocol {
|
|
239
|
-
constructor (noiseStream, handlers = {}) {
|
|
240
|
-
this.noiseStream = noiseStream
|
|
241
|
-
|
|
242
|
-
this.protocolVersion = handlers.protocolVersion || 0
|
|
243
|
-
this.userAgent = handlers.userAgent || ''
|
|
244
|
-
this.remoteUserAgent = ''
|
|
245
|
-
this.handlers = handlers
|
|
246
|
-
|
|
247
|
-
this._firstMessage = true
|
|
248
|
-
this._corks = 1
|
|
249
|
-
this._batch = []
|
|
250
|
-
|
|
251
|
-
this._localAliases = 0
|
|
252
|
-
this._remoteAliases = []
|
|
253
|
-
this._peers = new Map()
|
|
254
|
-
|
|
255
|
-
this._localExtensions = 128
|
|
256
|
-
this._remoteExtensions = []
|
|
257
|
-
this._extensions = new Map()
|
|
258
|
-
|
|
259
|
-
this._destroyer = this._safeDestroy.bind(this)
|
|
260
|
-
this.noiseStream.on('data', this.onmessage.bind(this))
|
|
261
|
-
this.noiseStream.on('end', this.noiseStream.end) // no half open
|
|
262
|
-
this.noiseStream.on('close', () => {
|
|
263
|
-
// TODO: If the stream was destroyed with an error, we probably want to forward it here
|
|
264
|
-
for (const peer of this._peers.values()) {
|
|
265
|
-
peer.destroy(null)
|
|
266
|
-
}
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
this._sendHandshake()
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
_sendHandshake () {
|
|
273
|
-
const m = { protocolVersion: this.protocolVersion, userAgent: this.userAgent }
|
|
274
|
-
const state = { start: 0, end: 0, buffer: null }
|
|
275
|
-
|
|
276
|
-
messages.handshake.preencode(state, m)
|
|
277
|
-
state.buffer = this.noiseStream.alloc(state.end)
|
|
278
|
-
messages.handshake.encode(state, m)
|
|
279
|
-
this.noiseStream.write(state.buffer)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
isRegistered (discoveryKey) {
|
|
283
|
-
return this._peers.has(discoveryKey.toString('hex'))
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
registerPeer (key, discoveryKey, handlers = {}, state = null) {
|
|
287
|
-
const peer = new Peer(this, this._localAliases++, key, discoveryKey, handlers, state)
|
|
288
|
-
this._peers.set(discoveryKey.toString('hex'), peer)
|
|
289
|
-
this._announceCore(peer.alias, key, discoveryKey)
|
|
290
|
-
return peer
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
unregisterPeer (peer, err) {
|
|
294
|
-
this._peers.delete(peer.discoveryKey.toString('hex'))
|
|
295
|
-
|
|
296
|
-
if (peer.remoteAlias > -1) {
|
|
297
|
-
this._remoteAliases[peer.remoteAlias] = null
|
|
298
|
-
peer.remoteAlias = -1
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
peer.handlers.onunregister(peer, err)
|
|
302
|
-
|
|
303
|
-
if (err) this.noiseStream.destroy(err)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
registerExtension (name, handlers) {
|
|
307
|
-
let ext = this._extensions.get(name)
|
|
308
|
-
if (ext) return ext
|
|
309
|
-
ext = new Extension(this, this._localExtensions++, name, handlers)
|
|
310
|
-
this._extensions.set(name, ext)
|
|
311
|
-
return ext
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
unregisterExtension (name) {
|
|
315
|
-
const ext = this._extensions.get(name)
|
|
316
|
-
if (!ext) return
|
|
317
|
-
if (!ext.destroyed) return ext.destroy()
|
|
318
|
-
this._extensions.delete(name)
|
|
319
|
-
this._remoteExtensions[ext.type - 128] = null
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
cork () {
|
|
323
|
-
if (++this._corks === 1) this._batch = []
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
uncork () {
|
|
327
|
-
if (--this._corks > 0) return
|
|
328
|
-
|
|
329
|
-
const batch = this._batch
|
|
330
|
-
this._batch = null
|
|
331
|
-
|
|
332
|
-
if (batch.length === 0) return
|
|
333
|
-
|
|
334
|
-
const state = { start: 0, end: 0, buffer: null }
|
|
335
|
-
const lens = new Array(batch.length)
|
|
336
|
-
|
|
337
|
-
uint.preencode(state, 0)
|
|
338
|
-
for (let i = 0; i < batch.length; i++) {
|
|
339
|
-
const [type, enc, dk, message] = batch[i]
|
|
340
|
-
const start = state.end
|
|
341
|
-
uint.preencode(state, type)
|
|
342
|
-
if (dk > -1) uint.preencode(state, dk)
|
|
343
|
-
enc.preencode(state, message)
|
|
344
|
-
uint.preencode(state, (lens[i] = state.end - start))
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
state.buffer = this.noiseStream.alloc(state.end)
|
|
348
|
-
|
|
349
|
-
uint.encode(state, 0)
|
|
350
|
-
for (let i = 0; i < batch.length; i++) {
|
|
351
|
-
const [type, enc, dk, message] = batch[i]
|
|
352
|
-
uint.encode(state, lens[i])
|
|
353
|
-
uint.encode(state, type)
|
|
354
|
-
if (dk > -1) uint.encode(state, dk)
|
|
355
|
-
enc.encode(state, message)
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
this.noiseStream.write(state.buffer)
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
onmessage (message) {
|
|
362
|
-
try {
|
|
363
|
-
this._decode(message)
|
|
364
|
-
} catch (err) {
|
|
365
|
-
this._safeDestroy(err)
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
_catch (p) {
|
|
370
|
-
if (isPromise(p)) p.then(noop, this._destroyer)
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
_announceCore (alias, key, discoveryKey) {
|
|
374
|
-
this.send(2, messages.core, -1, {
|
|
375
|
-
alias: alias,
|
|
376
|
-
discoveryKey: discoveryKey,
|
|
377
|
-
capability: Buffer.alloc(32) // TODO
|
|
378
|
-
})
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
_decode (buffer) {
|
|
382
|
-
const state = { start: 0, end: buffer.length, buffer }
|
|
383
|
-
|
|
384
|
-
if (this._firstMessage === true) {
|
|
385
|
-
this._firstMessage = false
|
|
386
|
-
const { userAgent } = messages.handshake.decode(state)
|
|
387
|
-
this.remoteUserAgent = userAgent
|
|
388
|
-
this.uncork()
|
|
389
|
-
return
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const type = uint.decode(state)
|
|
393
|
-
|
|
394
|
-
if (type === 0) { // batch
|
|
395
|
-
while (state.start < state.end) {
|
|
396
|
-
const len = uint.decode(state)
|
|
397
|
-
state.end = state.start + len
|
|
398
|
-
const type = uint.decode(state)
|
|
399
|
-
this._decodeMessage(type, state)
|
|
400
|
-
state.end = buffer.length
|
|
401
|
-
}
|
|
402
|
-
} else {
|
|
403
|
-
this._decodeMessage(type, state)
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
_decodeMessage (type, state) {
|
|
408
|
-
switch (type) {
|
|
409
|
-
case 1: return this._onextension(messages.extension.decode(state))
|
|
410
|
-
case 2: return this._oncore(messages.core.decode(state))
|
|
411
|
-
case 3: return this._onunknowncore(messages.unknownCore.decode(state))
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (type < 11) {
|
|
415
|
-
const remoteAlias = uint.decode(state)
|
|
416
|
-
const peer = this._remoteAliases[remoteAlias]
|
|
417
|
-
if (peer) peer.onmessage(type, state)
|
|
418
|
-
} else if (type >= 128) {
|
|
419
|
-
const ext = this._remoteExtensions[type - 128]
|
|
420
|
-
if (ext) ext._onmessage(state)
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
state.start = state.end
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
_onextension (m) {
|
|
427
|
-
const type = m.alias - 128
|
|
428
|
-
const ext = this._extensions.get(m.name)
|
|
429
|
-
|
|
430
|
-
if (type === this._remoteExtensions.length) {
|
|
431
|
-
this._remoteExtensions.push(null)
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (!ext) return
|
|
435
|
-
|
|
436
|
-
if (type < 0 || type >= this._remoteExtensions.length) {
|
|
437
|
-
this.destroy(new Error('Remote alias out of bounds'))
|
|
438
|
-
return
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
this._remoteExtensions[type] = ext
|
|
442
|
-
if (!ext.remoteSupports) ext._onremotesupports()
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
_oncore (m) {
|
|
446
|
-
const hex = m.discoveryKey.toString('hex')
|
|
447
|
-
const peer = this._peers.get(hex)
|
|
448
|
-
|
|
449
|
-
// allow one alloc
|
|
450
|
-
// TODO: if the remote allocs too many "holes", move to slower sparse firendly
|
|
451
|
-
// data structures such as a Map
|
|
452
|
-
if (m.alias === this._remoteAliases.length) this._remoteAliases.push(null)
|
|
453
|
-
|
|
454
|
-
if (peer) {
|
|
455
|
-
// TODO: check cap
|
|
456
|
-
|
|
457
|
-
if (m.alias >= this._remoteAliases.length) {
|
|
458
|
-
this.destroy(new Error('Remote alias out of bounds'))
|
|
459
|
-
return
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
this._remoteAliases[m.alias] = peer
|
|
463
|
-
peer.remoteAlias = m.alias
|
|
464
|
-
if (peer.resend) this._announceCore(peer.alias, peer.key, peer.discoveryKey)
|
|
465
|
-
this._catch(peer.handlers.oncore(m, peer))
|
|
466
|
-
return
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const self = this
|
|
470
|
-
const p = this.handlers.ondiscoverykey ? this.handlers.ondiscoverykey(m.discoveryKey) : undefined
|
|
471
|
-
|
|
472
|
-
if (isPromise(p)) p.then(next, next)
|
|
473
|
-
else next()
|
|
474
|
-
|
|
475
|
-
function next () {
|
|
476
|
-
if (self._peers.has(hex)) return self._oncore(m)
|
|
477
|
-
self.send(3, messages.unknownCore, -1, { discoveryKey: m.discoveryKey })
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
_onunknowncore (m) {
|
|
482
|
-
const peer = this._peers.get(m.discoveryKey.toString('hex'))
|
|
483
|
-
if (!peer) return
|
|
484
|
-
|
|
485
|
-
peer.resend = true
|
|
486
|
-
this._catch(peer.handlers.onunknowncore(m, peer))
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
send (type, enc, dk, message) {
|
|
490
|
-
if (this._corks > 0) {
|
|
491
|
-
this._batch.push([type, enc, dk, message])
|
|
492
|
-
return false
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
const state = { start: 0, end: 0, buffer: null }
|
|
496
|
-
|
|
497
|
-
uint.preencode(state, type)
|
|
498
|
-
if (dk > -1) uint.preencode(state, dk)
|
|
499
|
-
enc.preencode(state, message)
|
|
500
|
-
|
|
501
|
-
state.buffer = this.noiseStream.alloc(state.end)
|
|
502
|
-
|
|
503
|
-
uint.encode(state, type)
|
|
504
|
-
if (dk > -1) uint.encode(state, dk)
|
|
505
|
-
enc.encode(state, message)
|
|
506
|
-
|
|
507
|
-
return this.noiseStream.write(state.buffer)
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
destroy (err) {
|
|
511
|
-
return this.noiseStream.destroy(err)
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
_safeDestroy (err) {
|
|
515
|
-
safetyCatch(err) // check if this was an accidental catch
|
|
516
|
-
this.destroy(err)
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
function noop () {}
|
|
521
|
-
|
|
522
|
-
function isPromise (p) {
|
|
523
|
-
return !!p && typeof p.then === 'function'
|
|
524
|
-
}
|
package/lib/random-iterator.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
module.exports = class RandomIterator {
|
|
2
|
-
constructor (values) {
|
|
3
|
-
this._values = values
|
|
4
|
-
this._next = { value: null, done: false }
|
|
5
|
-
this._start = 0
|
|
6
|
-
this._end = values.length
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
next () {
|
|
10
|
-
if (this._start < this._values.length) {
|
|
11
|
-
if (this._start === this._end) this._end = this._values.length
|
|
12
|
-
|
|
13
|
-
const r = this._start + (Math.random() * (this._end - this._start)) | 0
|
|
14
|
-
const tmp = this._values[r]
|
|
15
|
-
|
|
16
|
-
this._values[r] = this._values[this._start]
|
|
17
|
-
this._next.value = this._values[this._start++] = tmp
|
|
18
|
-
} else {
|
|
19
|
-
this._next.done = true
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return this._next
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
reset () {
|
|
26
|
-
this._start = 0
|
|
27
|
-
this._end = this._values.length
|
|
28
|
-
this._next.done = false
|
|
29
|
-
return this
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
requeue () {
|
|
33
|
-
if (this._start === this._end) {
|
|
34
|
-
this._start--
|
|
35
|
-
} else {
|
|
36
|
-
const top = this._values[--this._end]
|
|
37
|
-
|
|
38
|
-
this._values[this._end] = this._values[--this._start]
|
|
39
|
-
this._values[this._start] = top
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
[Symbol.iterator] () {
|
|
44
|
-
return this
|
|
45
|
-
}
|
|
46
|
-
}
|
package/test/basic.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const test = require('brittle')
|
|
2
|
-
const ram = require('random-access-memory')
|
|
3
|
-
|
|
4
|
-
const Hypercore = require('../')
|
|
5
|
-
const { create } = require('./helpers')
|
|
6
|
-
|
|
7
|
-
test('basic', async function (t) {
|
|
8
|
-
const core = await create()
|
|
9
|
-
let appends = 0
|
|
10
|
-
|
|
11
|
-
t.is(core.length, 0)
|
|
12
|
-
t.is(core.byteLength, 0)
|
|
13
|
-
t.is(core.writable, true)
|
|
14
|
-
t.is(core.readable, true)
|
|
15
|
-
|
|
16
|
-
core.on('append', function () {
|
|
17
|
-
appends++
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
await core.append('hello')
|
|
21
|
-
await core.append('world')
|
|
22
|
-
|
|
23
|
-
t.is(core.length, 2)
|
|
24
|
-
t.is(core.byteLength, 10)
|
|
25
|
-
t.is(appends, 2)
|
|
26
|
-
|
|
27
|
-
t.end()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('session', async function (t) {
|
|
31
|
-
const core = await create()
|
|
32
|
-
|
|
33
|
-
const session = core.session()
|
|
34
|
-
|
|
35
|
-
await session.append('test')
|
|
36
|
-
t.alike(await core.get(0), Buffer.from('test'))
|
|
37
|
-
t.alike(await session.get(0), Buffer.from('test'))
|
|
38
|
-
t.end()
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('close', async function (t) {
|
|
42
|
-
const core = await create()
|
|
43
|
-
await core.append('hello world')
|
|
44
|
-
|
|
45
|
-
await core.close()
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
await core.get(0)
|
|
49
|
-
t.fail('core should be closed')
|
|
50
|
-
} catch {
|
|
51
|
-
t.pass('get threw correctly when core was closed')
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('close multiple', async function (t) {
|
|
56
|
-
const core = await create()
|
|
57
|
-
await core.append('hello world')
|
|
58
|
-
|
|
59
|
-
const ev = t.test('events')
|
|
60
|
-
|
|
61
|
-
ev.plan(4)
|
|
62
|
-
|
|
63
|
-
let i = 0
|
|
64
|
-
|
|
65
|
-
core.on('close', () => ev.is(i++, 0, 'on close'))
|
|
66
|
-
core.close().then(() => ev.is(i++, 1, 'first close'))
|
|
67
|
-
core.close().then(() => ev.is(i++, 2, 'second close'))
|
|
68
|
-
core.close().then(() => ev.is(i++, 3, 'third close'))
|
|
69
|
-
|
|
70
|
-
await ev
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
test('storage options', async function (t) {
|
|
74
|
-
const core = new Hypercore({ storage: ram })
|
|
75
|
-
await core.append('hello')
|
|
76
|
-
t.alike(await core.get(0), Buffer.from('hello'))
|
|
77
|
-
t.end()
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test(
|
|
81
|
-
'allow publicKeys with different byteLength that 32, if opts.crypto were passed',
|
|
82
|
-
function (t) {
|
|
83
|
-
const key = Buffer.alloc(33).fill('a')
|
|
84
|
-
|
|
85
|
-
const core = new Hypercore(ram, key, { crypto: {} })
|
|
86
|
-
|
|
87
|
-
t.is(core.key, key)
|
|
88
|
-
t.pass('creating a core with more than 32 byteLength key did not throw')
|
|
89
|
-
}
|
|
90
|
-
)
|
package/test/bitfield.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
const test = require('brittle')
|
|
2
|
-
const ram = require('random-access-memory')
|
|
3
|
-
const Bitfield = require('../lib/bitfield')
|
|
4
|
-
|
|
5
|
-
test('bitfield - set and get', async function (t) {
|
|
6
|
-
const b = await Bitfield.open(ram())
|
|
7
|
-
|
|
8
|
-
t.absent(b.get(42))
|
|
9
|
-
b.set(42, true)
|
|
10
|
-
t.ok(b.get(42))
|
|
11
|
-
|
|
12
|
-
// bigger offsets
|
|
13
|
-
t.absent(b.get(42000000))
|
|
14
|
-
b.set(42000000, true)
|
|
15
|
-
t.ok(b.get(42000000))
|
|
16
|
-
|
|
17
|
-
b.set(42000000, false)
|
|
18
|
-
t.absent(b.get(42000000))
|
|
19
|
-
|
|
20
|
-
await b.flush()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('bitfield - random set and gets', async function (t) {
|
|
24
|
-
const b = await Bitfield.open(ram())
|
|
25
|
-
const set = new Set()
|
|
26
|
-
|
|
27
|
-
for (let i = 0; i < 200; i++) {
|
|
28
|
-
const idx = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
29
|
-
b.set(idx, true)
|
|
30
|
-
set.add(idx)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (let i = 0; i < 500; i++) {
|
|
34
|
-
const idx = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
35
|
-
const expected = set.has(idx)
|
|
36
|
-
const val = b.get(idx)
|
|
37
|
-
if (val !== expected) {
|
|
38
|
-
t.fail('expected ' + expected + ' but got ' + val + ' at ' + idx)
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
for (const idx of set) {
|
|
44
|
-
const val = b.get(idx)
|
|
45
|
-
if (val !== true) {
|
|
46
|
-
t.fail('expected true but got ' + val + ' at ' + idx)
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
t.pass('all random set and gets pass')
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('bitfield - reload', async function (t) {
|
|
55
|
-
const s = ram()
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
const b = await Bitfield.open(s)
|
|
59
|
-
b.set(142, true)
|
|
60
|
-
b.set(40000, true)
|
|
61
|
-
b.set(1424242424, true)
|
|
62
|
-
await b.flush()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
const b = await Bitfield.open(s)
|
|
67
|
-
t.ok(b.get(142))
|
|
68
|
-
t.ok(b.get(40000))
|
|
69
|
-
t.ok(b.get(1424242424))
|
|
70
|
-
}
|
|
71
|
-
})
|