hypercore 10.0.0-alpha.8 → 10.1.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/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
- }
@@ -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
- })