hypercore 10.0.0-alpha.3 → 10.0.0-alpha.32

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/lib/protocol.js DELETED
@@ -1,522 +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
-
129
- this._destroyer = this._safeDestroy.bind(this)
130
- }
131
-
132
- onmessage (type, state) {
133
- const handlers = this.handlers
134
-
135
- switch (type) {
136
- case 4: {
137
- this._catch(handlers.oninfo(messages.info.decode(state), this))
138
- break
139
- }
140
-
141
- case 5: {
142
- // options
143
- break
144
- }
145
-
146
- case 6: {
147
- // want
148
- break
149
- }
150
-
151
- case 7: {
152
- this._catch(handlers.onhave(messages.have.decode(state), this))
153
- break
154
- }
155
-
156
- case 8: {
157
- this._catch(handlers.onbitfield(messages.bitfield.decode(state), this))
158
- break
159
- }
160
-
161
- case 9: {
162
- this._catch(handlers.onrequest(messages.request.decode(state), this))
163
- break
164
- }
165
-
166
- case 10: {
167
- this._catch(handlers.ondata(messages.data.decode(state), this))
168
- break
169
- }
170
- }
171
-
172
- state.start = state.end
173
- }
174
-
175
- _catch (p) {
176
- if (isPromise(p)) p.then(noop, this._destroyer)
177
- }
178
-
179
- registerExtension (name, handlers) {
180
- if (this.extensions.has(name)) return this.extensions.get(name)
181
- const ext = this.protocol.registerExtension(name, { aliased: true, encoding: handlers.encoding })
182
- const coreExt = new CoreExtension(ext, this, name, handlers)
183
- ext.peers.add(coreExt)
184
- this.extensions.set(name, coreExt)
185
- return coreExt
186
- }
187
-
188
- cork () {
189
- this.protocol.cork()
190
- }
191
-
192
- uncork () {
193
- this.protocol.uncork()
194
- }
195
-
196
- info (message) {
197
- return this.protocol.send(4, messages.info, this.alias, message)
198
- }
199
-
200
- options (message) {
201
- // TODO
202
- // this._send(5, messages.info, this.alias, message)
203
- }
204
-
205
- want (message) {
206
- // TODO
207
- // this._send(6, messages.info, this.alias, message)
208
- }
209
-
210
- have (message) {
211
- return this.protocol.send(7, messages.have, this.alias, message)
212
- }
213
-
214
- bitfield (message) {
215
- return this.protocol.send(8, messages.bitfield, this.alias, message)
216
- }
217
-
218
- request (message) {
219
- return this.protocol.send(9, messages.request, this.alias, message)
220
- }
221
-
222
- data (message) {
223
- return this.protocol.send(10, messages.data, this.alias, message)
224
- }
225
-
226
- _safeDestroy (err) {
227
- safetyCatch(err)
228
- return this.destroy(err)
229
- }
230
-
231
- destroy (err) {
232
- return this.protocol.unregisterPeer(this, err)
233
- }
234
- }
235
-
236
- module.exports = class Protocol {
237
- constructor (noiseStream, handlers = {}) {
238
- this.noiseStream = noiseStream
239
-
240
- this.protocolVersion = handlers.protocolVersion || 0
241
- this.userAgent = handlers.userAgent || ''
242
- this.remoteUserAgent = ''
243
- this.handlers = handlers
244
-
245
- this._firstMessage = true
246
- this._corks = 1
247
- this._batch = []
248
-
249
- this._localAliases = 0
250
- this._remoteAliases = []
251
- this._peers = new Map()
252
-
253
- this._localExtensions = 128
254
- this._remoteExtensions = []
255
- this._extensions = new Map()
256
-
257
- this._destroyer = this._safeDestroy.bind(this)
258
- this.noiseStream.on('data', this.onmessage.bind(this))
259
- this.noiseStream.on('end', this.noiseStream.end) // no half open
260
- this.noiseStream.on('close', () => {
261
- // TODO: If the stream was destroyed with an error, we probably want to forward it here
262
- for (const peer of this._peers.values()) {
263
- peer.destroy(null)
264
- }
265
- })
266
-
267
- this._sendHandshake()
268
- }
269
-
270
- _sendHandshake () {
271
- const m = { protocolVersion: this.protocolVersion, userAgent: this.userAgent }
272
- const state = { start: 0, end: 0, buffer: null }
273
-
274
- messages.handshake.preencode(state, m)
275
- state.buffer = this.noiseStream.alloc(state.end)
276
- messages.handshake.encode(state, m)
277
- this.noiseStream.write(state.buffer)
278
- }
279
-
280
- isRegistered (discoveryKey) {
281
- return this._peers.has(discoveryKey.toString('hex'))
282
- }
283
-
284
- registerPeer (key, discoveryKey, handlers = {}, state = null) {
285
- const peer = new Peer(this, this._localAliases++, key, discoveryKey, handlers, state)
286
- this._peers.set(discoveryKey.toString('hex'), peer)
287
- this._announceCore(peer.alias, key, discoveryKey)
288
- return peer
289
- }
290
-
291
- unregisterPeer (peer, err) {
292
- this._peers.delete(peer.discoveryKey.toString('hex'))
293
-
294
- if (peer.remoteAlias > -1) {
295
- this._remoteAliases[peer.remoteAlias] = null
296
- peer.remoteAlias = -1
297
- }
298
-
299
- peer.handlers.onunregister(this, err)
300
-
301
- if (err) this.noiseStream.destroy(err)
302
- }
303
-
304
- registerExtension (name, handlers) {
305
- let ext = this._extensions.get(name)
306
- if (ext) return ext
307
- ext = new Extension(this, this._localExtensions++, name, handlers)
308
- this._extensions.set(name, ext)
309
- return ext
310
- }
311
-
312
- unregisterExtension (name) {
313
- const ext = this._extensions.get(name)
314
- if (!ext) return
315
- if (!ext.destroyed) return ext.destroy()
316
- this._extensions.delete(name)
317
- this._remoteExtensions[ext.type - 128] = null
318
- }
319
-
320
- cork () {
321
- if (++this._corks === 1) this._batch = []
322
- }
323
-
324
- uncork () {
325
- if (--this._corks > 0) return
326
-
327
- const batch = this._batch
328
- this._batch = null
329
-
330
- if (batch.length === 0) return
331
-
332
- const state = { start: 0, end: 0, buffer: null }
333
- const lens = new Array(batch.length)
334
-
335
- uint.preencode(state, 0)
336
- for (let i = 0; i < batch.length; i++) {
337
- const [type, enc, dk, message] = batch[i]
338
- const start = state.end
339
- uint.preencode(state, type)
340
- if (dk > -1) uint.preencode(state, dk)
341
- enc.preencode(state, message)
342
- uint.preencode(state, (lens[i] = state.end - start))
343
- }
344
-
345
- state.buffer = this.noiseStream.alloc(state.end)
346
-
347
- uint.encode(state, 0)
348
- for (let i = 0; i < batch.length; i++) {
349
- const [type, enc, dk, message] = batch[i]
350
- uint.encode(state, lens[i])
351
- uint.encode(state, type)
352
- if (dk > -1) uint.encode(state, dk)
353
- enc.encode(state, message)
354
- }
355
-
356
- this.noiseStream.write(state.buffer)
357
- }
358
-
359
- onmessage (message) {
360
- try {
361
- this._decode(message)
362
- } catch (err) {
363
- this._safeDestroy(err)
364
- }
365
- }
366
-
367
- _catch (p) {
368
- if (isPromise(p)) p.then(noop, this._destroyer)
369
- }
370
-
371
- _announceCore (alias, key, discoveryKey) {
372
- this.send(2, messages.core, -1, {
373
- alias: alias,
374
- discoveryKey: discoveryKey,
375
- capability: Buffer.alloc(32) // TODO
376
- })
377
- }
378
-
379
- _decode (buffer) {
380
- const state = { start: 0, end: buffer.length, buffer }
381
-
382
- if (this._firstMessage === true) {
383
- this._firstMessage = false
384
- const { userAgent } = messages.handshake.decode(state)
385
- this.remoteUserAgent = userAgent
386
- this.uncork()
387
- return
388
- }
389
-
390
- const type = uint.decode(state)
391
-
392
- if (type === 0) { // batch
393
- while (state.start < state.end) {
394
- const len = uint.decode(state)
395
- state.end = state.start + len
396
- const type = uint.decode(state)
397
- this._decodeMessage(type, state)
398
- state.end = buffer.length
399
- }
400
- } else {
401
- this._decodeMessage(type, state)
402
- }
403
- }
404
-
405
- _decodeMessage (type, state) {
406
- switch (type) {
407
- case 1: return this._onextension(messages.extension.decode(state))
408
- case 2: return this._oncore(messages.core.decode(state))
409
- case 3: return this._onunknowncore(messages.unknownCore.decode(state))
410
- }
411
-
412
- if (type < 11) {
413
- const remoteAlias = uint.decode(state)
414
- const peer = this._remoteAliases[remoteAlias]
415
- if (peer) peer.onmessage(type, state)
416
- } else if (type >= 128) {
417
- const ext = this._remoteExtensions[type - 128]
418
- if (ext) ext._onmessage(state)
419
- }
420
-
421
- state.start = state.end
422
- }
423
-
424
- _onextension (m) {
425
- const type = m.alias - 128
426
- const ext = this._extensions.get(m.name)
427
-
428
- if (type === this._remoteExtensions.length) {
429
- this._remoteExtensions.push(null)
430
- }
431
-
432
- if (!ext) return
433
-
434
- if (type < 0 || type >= this._remoteExtensions.length) {
435
- this.destroy(new Error('Remote alias out of bounds'))
436
- return
437
- }
438
-
439
- this._remoteExtensions[type] = ext
440
- if (!ext.remoteSupports) ext._onremotesupports()
441
- }
442
-
443
- _oncore (m) {
444
- const hex = m.discoveryKey.toString('hex')
445
- const peer = this._peers.get(hex)
446
-
447
- // allow one alloc
448
- // TODO: if the remote allocs too many "holes", move to slower sparse firendly
449
- // data structures such as a Map
450
- if (m.alias === this._remoteAliases.length) this._remoteAliases.push(null)
451
-
452
- if (peer) {
453
- // TODO: check cap
454
-
455
- if (m.alias >= this._remoteAliases.length) {
456
- this.destroy(new Error('Remote alias out of bounds'))
457
- return
458
- }
459
-
460
- this._remoteAliases[m.alias] = peer
461
- peer.remoteAlias = m.alias
462
- if (peer.resend) this._announceCore(peer.alias, peer.key, peer.discoveryKey)
463
- this._catch(peer.handlers.oncore(m, peer))
464
- return
465
- }
466
-
467
- const self = this
468
- const p = this.handlers.ondiscoverykey ? this.handlers.ondiscoverykey(m.discoveryKey) : undefined
469
-
470
- if (isPromise(p)) p.then(next, next)
471
- else next()
472
-
473
- function next () {
474
- if (self._peers.has(hex)) return self._oncore(m)
475
- self.send(3, messages.unknownCore, -1, { discoveryKey: m.discoveryKey })
476
- }
477
- }
478
-
479
- _onunknowncore (m) {
480
- const peer = this._peers.get(m.discoveryKey.toString('hex'))
481
- if (!peer) return
482
-
483
- peer.resend = true
484
- this._catch(peer.handlers.onunknowncore(m, peer))
485
- }
486
-
487
- send (type, enc, dk, message) {
488
- if (this._corks > 0) {
489
- this._batch.push([type, enc, dk, message])
490
- return false
491
- }
492
-
493
- const state = { start: 0, end: 0, buffer: null }
494
-
495
- uint.preencode(state, type)
496
- if (dk > -1) uint.preencode(state, dk)
497
- enc.preencode(state, message)
498
-
499
- state.buffer = this.noiseStream.alloc(state.end)
500
-
501
- uint.encode(state, type)
502
- if (dk > -1) uint.encode(state, dk)
503
- enc.encode(state, message)
504
-
505
- return this.noiseStream.write(state.buffer)
506
- }
507
-
508
- destroy (err) {
509
- return this.noiseStream.destroy(err)
510
- }
511
-
512
- _safeDestroy (err) {
513
- safetyCatch(err) // check if this was an accidental catch
514
- this.destroy(err)
515
- }
516
- }
517
-
518
- function noop () {}
519
-
520
- function isPromise (p) {
521
- return !!p && typeof p.then === 'function'
522
- }
@@ -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,78 +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
- })
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
- })