hypercore 9.12.0 → 10.0.0-alpha.11

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.
Files changed (86) hide show
  1. package/.github/workflows/test-node.yml +3 -4
  2. package/README.md +131 -404
  3. package/__snapshots__/test/storage.js.snapshot.cjs +15 -0
  4. package/examples/announce.js +19 -0
  5. package/examples/basic.js +10 -0
  6. package/examples/http.js +123 -0
  7. package/examples/lookup.js +20 -0
  8. package/index.js +365 -1600
  9. package/lib/bitfield.js +113 -285
  10. package/lib/block-encryption.js +68 -0
  11. package/lib/block-store.js +58 -0
  12. package/lib/core.js +468 -0
  13. package/lib/extensions.js +76 -0
  14. package/lib/merkle-tree.js +1110 -0
  15. package/lib/messages.js +571 -0
  16. package/lib/mutex.js +39 -0
  17. package/lib/oplog.js +224 -0
  18. package/lib/protocol.js +525 -0
  19. package/lib/random-iterator.js +46 -0
  20. package/lib/remote-bitfield.js +24 -0
  21. package/lib/replicator.js +857 -0
  22. package/lib/streams.js +39 -0
  23. package/package.json +44 -45
  24. package/test/basic.js +59 -471
  25. package/test/bitfield.js +48 -133
  26. package/test/core.js +290 -0
  27. package/test/encodings.js +18 -0
  28. package/test/encryption.js +123 -0
  29. package/test/extension.js +71 -0
  30. package/test/helpers/index.js +23 -0
  31. package/test/merkle-tree.js +518 -0
  32. package/test/mutex.js +137 -0
  33. package/test/oplog.js +399 -0
  34. package/test/preload.js +72 -0
  35. package/test/replicate.js +227 -824
  36. package/test/sessions.js +173 -0
  37. package/test/storage.js +31 -0
  38. package/test/streams.js +39 -146
  39. package/test/user-data.js +47 -0
  40. package/bench/all.sh +0 -65
  41. package/bench/copy-64kb-blocks.js +0 -51
  42. package/bench/helpers/read-throttled.js +0 -27
  43. package/bench/helpers/read.js +0 -47
  44. package/bench/helpers/write.js +0 -29
  45. package/bench/read-16kb-blocks-proof-throttled.js +0 -1
  46. package/bench/read-16kb-blocks-proof.js +0 -1
  47. package/bench/read-16kb-blocks-throttled.js +0 -1
  48. package/bench/read-16kb-blocks.js +0 -1
  49. package/bench/read-512b-blocks.js +0 -1
  50. package/bench/read-64kb-blocks-linear-batch.js +0 -18
  51. package/bench/read-64kb-blocks-linear.js +0 -18
  52. package/bench/read-64kb-blocks-proof.js +0 -1
  53. package/bench/read-64kb-blocks.js +0 -1
  54. package/bench/replicate-16kb-blocks.js +0 -19
  55. package/bench/replicate-64kb-blocks.js +0 -19
  56. package/bench/write-16kb-blocks.js +0 -1
  57. package/bench/write-512b-blocks.js +0 -1
  58. package/bench/write-64kb-blocks-static.js +0 -1
  59. package/bench/write-64kb-blocks.js +0 -1
  60. package/example.js +0 -23
  61. package/lib/cache.js +0 -26
  62. package/lib/crypto.js +0 -5
  63. package/lib/replicate.js +0 -829
  64. package/lib/safe-buffer-equals.js +0 -6
  65. package/lib/storage.js +0 -421
  66. package/lib/tree-index.js +0 -183
  67. package/test/ack.js +0 -306
  68. package/test/audit.js +0 -36
  69. package/test/cache.js +0 -93
  70. package/test/compat.js +0 -209
  71. package/test/copy.js +0 -377
  72. package/test/default-storage.js +0 -51
  73. package/test/extensions.js +0 -137
  74. package/test/get.js +0 -64
  75. package/test/head.js +0 -65
  76. package/test/helpers/create-tracking-ram.js +0 -27
  77. package/test/helpers/create.js +0 -6
  78. package/test/helpers/replicate.js +0 -4
  79. package/test/seek.js +0 -234
  80. package/test/selections.js +0 -95
  81. package/test/set-uploading-downloading.js +0 -91
  82. package/test/stats.js +0 -77
  83. package/test/timeouts.js +0 -22
  84. package/test/tree-index.js +0 -841
  85. package/test/update.js +0 -156
  86. package/test/value-encoding.js +0 -52
package/lib/replicate.js DELETED
@@ -1,829 +0,0 @@
1
- var Protocol = require('hypercore-protocol')
2
- var timeout = require('timeout-refresh')
3
- var bitfield = require('fast-bitfield')
4
- var set = require('unordered-set')
5
- var rle = require('bitfield-rle').align(4)
6
- var treeIndex = require('./tree-index')
7
-
8
- var EMPTY = new Uint8Array(1024)
9
-
10
- module.exports = replicate
11
-
12
- function replicate (feed, initiator, opts) {
13
- feed.ifAvailable.wait()
14
- var stream = Protocol.isProtocolStream(initiator) ? initiator : opts.stream
15
-
16
- if (!stream) {
17
- if (!opts.keyPair) opts.keyPair = feed.noiseKeyPair
18
- stream = new Protocol(initiator, opts)
19
- }
20
-
21
- if (feed.opened) onready(null)
22
- else feed.ready(onready)
23
-
24
- return stream
25
-
26
- function onready (err) {
27
- feed.ifAvailable.continue()
28
-
29
- if (err) return stream.destroy(err)
30
- if (stream.destroyed) return
31
- if (stream.opened(feed.key)) return
32
-
33
- if (opts.noise !== false && opts.onfeedauthenticate) {
34
- if (!stream.remotePublicKey) {
35
- feed.ifAvailable.wait()
36
- stream.setMaxListeners(0)
37
- stream.on('close', onhandshake)
38
- stream.on('handshake', onhandshake)
39
- return
40
- }
41
- feedauthenticate()
42
- return
43
- }
44
- replicatePeer()
45
- }
46
-
47
- function onhandshake () {
48
- feed.ifAvailable.continue()
49
- stream.off('close', onhandshake)
50
- stream.off('handshake', onhandshake)
51
- feedauthenticate()
52
- }
53
-
54
- function feedauthenticate () {
55
- if (stream.destroyed) return
56
- if (stream.opened(feed.key)) return
57
- feed.ifAvailable.wait()
58
- opts.onfeedauthenticate(feed, stream.remotePublicKey, function (err) {
59
- feed.ifAvailable.continue()
60
- if (stream.destroyed) return
61
- if (stream.opened(feed.key)) return
62
- if (err) {
63
- stream.close(feed.discoveryKey)
64
- return
65
- }
66
- replicatePeer()
67
- })
68
- }
69
-
70
- function replicatePeer () {
71
- if (opts.noise !== false) {
72
- if (stream.remoteOpened(feed.key) && !stream.remoteVerified(feed.key)) {
73
- stream.close(feed.discoveryKey)
74
- return
75
- }
76
- }
77
-
78
- var peer = new Peer(feed, opts)
79
-
80
- peer.feed = feed
81
- peer.stream = stream.open(feed.key, peer)
82
-
83
- stream.setMaxListeners(0)
84
- peer.ready()
85
- feed.emit('replicating', stream)
86
- }
87
- }
88
-
89
- function Peer (feed, opts) {
90
- if (opts.extensions) throw new Error('Per peer extensions is not supported. Use feed.registerExtension instead')
91
-
92
- this.feed = feed
93
- this.stream = null // set by replicate just after creation
94
- this.wants = bitfield()
95
- this.remoteBitfield = bitfield()
96
- this.remoteLength = 0
97
- this.remoteWant = false
98
- this.remoteTree = null
99
- this.remoteAck = false
100
- this.remoteOpened = false
101
- this.live = !!opts.live
102
- this.sparse = feed.sparse
103
- this.ack = !!opts.ack
104
-
105
- this.remoteDownloading = true
106
- this.remoteUploading = true
107
- this.remoteExtensions = feed.extensions.remote()
108
- this.downloading = typeof opts.download === 'boolean' ? opts.download : feed.downloading
109
- this.uploading = typeof opts.upload === 'boolean' ? opts.upload : feed.uploading
110
-
111
- this.updated = false
112
-
113
- this.maxRequests = opts.maxRequests || feed.maxRequests || 16
114
- this.urgentRequests = this.maxRequests + 16
115
- this.inflightRequests = []
116
- this.inflightWants = 0
117
-
118
- this._index = -1
119
- this._lastBytes = 0
120
- this._first = true
121
- this._closed = false
122
- this._destroyed = false
123
- this._defaultDownloading = this.downloading
124
- this._iterator = this.remoteBitfield.iterator()
125
- this._requestTimeout = null
126
-
127
- this.stats = !opts.stats ? null : {
128
- uploadedBytes: 0,
129
- uploadedBlocks: 0,
130
- downloadedBytes: 0,
131
- downloadedBlocks: 0
132
- }
133
- }
134
-
135
- Object.defineProperty(Peer.prototype, 'remoteAddress', {
136
- enumerable: true,
137
- get: function () {
138
- return this.stream.stream.remoteAddress
139
- }
140
- })
141
-
142
- Object.defineProperty(Peer.prototype, 'remoteType', {
143
- enumerable: true,
144
- get: function () {
145
- return this.stream.stream.remoteType
146
- }
147
- })
148
-
149
- Object.defineProperty(Peer.prototype, 'remotePublicKey', {
150
- enumerable: true,
151
- get: function () {
152
- return this.stream.state.remotePublicKey
153
- }
154
- })
155
-
156
- Peer.prototype.onwant = function (want) {
157
- if (!this.uploading) return
158
- // We only reploy to multipla of 8192 in terms of offsets and lengths for want messages
159
- // since this is much easier for the bitfield, in terms of paging.
160
- if ((want.start & 8191) || (want.length & 8191)) return
161
- if (!this.remoteWant && this.feed.length && this.feed.bitfield.get(this.feed.length - 1)) {
162
- // Eagerly send the length of the feed to the otherside
163
- // TODO: only send this if the remote is not wanting a region
164
- // where this is contained in
165
- this.stream.have({ start: this.feed.length - 1 })
166
- }
167
- this.remoteWant = true
168
- var rle = this.feed.bitfield.compress(want.start, want.length)
169
- this.stream.have({ start: want.start, length: want.length, bitfield: rle })
170
- }
171
-
172
- Peer.prototype.ondata = function (data) {
173
- var self = this
174
-
175
- // Ignore unrequested messages unless we allow push
176
- // TODO: would be better to check if the byte range was requested instead, but this works fine
177
- var allowPush = this.feed.allowPush || !data.value
178
- if (!allowPush && !this.feed._reserved.get(data.index)) {
179
- // If we do not have this block, send back unhave message for this index,
180
- // to let the remote know we rejected it.
181
- // TODO: we might want to have some "unwanted push" threshold to punish spammers
182
- if (!self.feed.bitfield.get(data.index)) self.unhave({ start: data.index })
183
- self._clear(data.index, !data.value)
184
- return
185
- }
186
-
187
- this.feed._putBuffer(data.index, data.value, data, this, function (err) {
188
- if (err) return self.destroy(err)
189
- if (data.value) self.remoteBitfield.set(data.index, false)
190
- if (self.remoteAck) {
191
- // Send acknowledgement.
192
- // In the future this could batch several ACKs at once
193
- self.stream.have({ start: data.index, length: 1, ack: true })
194
- }
195
- if (self.stats && data.value) {
196
- self.stats.downloadedBlocks += 1
197
- self.stats.downloadedBytes += data.value.length
198
- }
199
- self._clear(data.index, !data.value)
200
- })
201
- }
202
-
203
- Peer.prototype._clear = function (index, hash) {
204
- // TODO: optimize me (no splice and do not run through all ...)
205
- for (var i = 0; i < this.inflightRequests.length; i++) {
206
- if (this.inflightRequests[i].index === index) {
207
- if (this._requestTimeout !== null) this._requestTimeout.refresh()
208
- this.inflightRequests.splice(i, 1)
209
- i--
210
- }
211
- }
212
-
213
- this.feed._reserved.set(index, false)
214
- // TODO: only update all if we have overlapping selections
215
- this.feed._updatePeers()
216
-
217
- if (this.inflightRequests.length === 0 && this._requestTimeout !== null) {
218
- this._requestTimeout.destroy()
219
- this._requestTimeout = null
220
- }
221
- }
222
-
223
- Peer.prototype.onrequest = function (request) {
224
- if (!this.uploading) return
225
- if (request.bytes) return this._onbytes(request)
226
-
227
- // lazily instantiate the remote tree
228
- if (!this.remoteTree) this.remoteTree = treeIndex()
229
-
230
- var self = this
231
- var opts = { digest: request.nodes, hash: request.hash, tree: this.remoteTree }
232
-
233
- this.feed.proof(request.index, opts, onproof)
234
-
235
- function onproof (err, proof) {
236
- if (err) return self.destroy(err)
237
- if (request.hash) onvalue(null, null)
238
- else if (self.feed.bitfield.get(request.index)) self.feed._getBuffer(request.index, onvalue)
239
-
240
- function onvalue (err, value) {
241
- if (!self.uploading) return
242
- if (err) return self.destroy(err)
243
-
244
- if (value) {
245
- if (self.stats) {
246
- self.stats.uploadedBlocks += 1
247
- self.stats.uploadedBytes += value.length
248
- self.feed._stats.uploadedBlocks += 1
249
- self.feed._stats.uploadedBytes += value.length
250
- }
251
- self.feed.emit('upload', request.index, value, self)
252
- }
253
-
254
- // TODO: prob not needed with new bitfield
255
- if (request.index + 1 > self.remoteLength) {
256
- self.remoteLength = request.index + 1
257
- self._updateEnd()
258
- }
259
-
260
- self.stream.data({
261
- index: request.index,
262
- value: value,
263
- nodes: proof.nodes,
264
- signature: proof.signature
265
- })
266
- }
267
- }
268
- }
269
-
270
- Peer.prototype._updateOptions = function () {
271
- if (this.ack || this.feed.extensions.length) {
272
- this.stream.options({
273
- ack: this.ack,
274
- extensions: this.feed.extensions.names()
275
- })
276
- }
277
- }
278
-
279
- Peer.prototype.setDownloading = function (downloading) {
280
- if (downloading === this.downloading) return
281
- this.downloading = downloading
282
- this.stream.status({
283
- downloading,
284
- uploading: this.uploading
285
- })
286
- this.update()
287
- }
288
-
289
- Peer.prototype.setUploading = function (uploading) {
290
- if (uploading === this.uploading) return
291
- this.uploading = uploading
292
- this.stream.status({
293
- downloading: this.downloading,
294
- uploading
295
- })
296
- this.update()
297
- }
298
-
299
- Peer.prototype._onbytes = function (request) {
300
- var self = this
301
-
302
- this.feed.seek(request.bytes, { wait: false }, function (err, index) {
303
- if (err) {
304
- request.bytes = 0
305
- self.onrequest(request)
306
- return
307
- }
308
-
309
- // quick'n'dirty filter for parallel bytes requests
310
- // it does not matter that this doesn't catch ALL parallel requests - just a bandwidth optimization
311
- if (self._lastBytes === request.bytes) return
312
- self._lastBytes = request.bytes
313
-
314
- request.bytes = 0
315
- request.index = index
316
- request.nodes = 0
317
-
318
- self.onrequest(request)
319
- })
320
- }
321
-
322
- Peer.prototype._onrequesttimeout = function () {
323
- this._requestTimeout = null
324
- if (!this.inflightRequests.length) return
325
-
326
- var first = this.inflightRequests[0]
327
-
328
- if (first.hash ? this.feed.tree.get(2 * first.index) : this.feed.bitfield.get(first.index)) {
329
- // prob a bytes response
330
- this.inflightRequests.shift()
331
- this.feed._reserved.set(first.index, false)
332
-
333
- if (this.stream.stream.timeout) {
334
- this._requestTimeout = timeout(this.stream.stream.timeout.ms, this._onrequesttimeout, this)
335
- }
336
- return
337
- }
338
-
339
- this.destroy(new Error('Request timeout'))
340
- }
341
-
342
- Peer.prototype.onhave = function (have) {
343
- this.feed.emit('peer-ack', this, have)
344
-
345
- if (this.ack && have.ack && !have.bitfield && this.feed.bitfield.get(have.start)) {
346
- this.stream.stream.emit('ack', have)
347
- return
348
- }
349
-
350
- var updated = this._first
351
- if (this._first) this._first = false
352
-
353
- // In this impl, we only sent WANTs for 1024 * 1024 length ranges
354
- // so if we get a HAVE for that it is a reply to a WANT.
355
- if (have.length === 1024 * 1024 && this.inflightWants > 0) {
356
- this.feed.ifAvailable.continue()
357
- this.inflightWants--
358
- }
359
-
360
- if (have.bitfield) { // TODO: handle start !== 0
361
- if (have.length === 0 || have.length === 1) { // length === 1 is for backwards compat
362
- this.wants = null // we are in backwards compat mode where we subscribe everything
363
- }
364
- var buf = rle.decode(have.bitfield)
365
- var bits = buf.length * 8
366
- remoteAndNotLocal(this.feed.bitfield, buf, this.remoteBitfield.littleEndian, have.start)
367
- this.remoteBitfield.fill(buf, have.start)
368
- if (bits > this.remoteLength) {
369
- this.remoteLength = this.remoteBitfield.last() + 1
370
- updated = true
371
- }
372
- } else {
373
- // TODO: if len > something simply copy a 0b1111... buffer to the bitfield
374
-
375
- var start = have.start
376
- var len = have.length || 1
377
-
378
- while (len--) this.remoteBitfield.set(start, !this.feed.bitfield.get(start++))
379
- if (start > this.remoteLength) {
380
- this.remoteLength = start
381
- updated = true
382
- }
383
- }
384
-
385
- if (updated) {
386
- this.updated = true
387
- this.feed.emit('remote-update', this)
388
- }
389
-
390
- this._updateEnd()
391
- this.update()
392
- }
393
-
394
- Peer.prototype._updateEnd = function () {
395
- if (this.live || this.feed.sparse || !this.feed._selections.length) return
396
-
397
- var sel = this.feed._selections[0]
398
- var remoteLength = this.feed.length || -1
399
-
400
- for (var i = 0; i < this.feed.peers.length; i++) {
401
- if (this.feed.peers[i].remoteLength > remoteLength) {
402
- remoteLength = this.feed.peers[i].remoteLength
403
- }
404
- }
405
-
406
- sel.end = remoteLength
407
- }
408
-
409
- Peer.prototype.onextension = function (id, message) {
410
- this.remoteExtensions.onmessage(id, message, this)
411
- }
412
-
413
- Peer.prototype.onstatus = function (info) {
414
- this.remoteUploading = info.uploading
415
- this.remoteDownloading = info.downloading
416
-
417
- if (!info.uploading) {
418
- while (this.inflightRequests.length) {
419
- const data = this.inflightRequests[0]
420
- this._clear(data.index, !data.value)
421
- }
422
- for (var i = 0; i < this.inflightWants; i++) {
423
- this.feed.ifAvailable.continue()
424
- }
425
- this.inflightWants = 0
426
- this.wants = bitfield()
427
- }
428
- this.update()
429
- if (info.downloading || this.live) return
430
- if (this.feed._selections.length && this.downloading) return
431
- this._autoEnd()
432
- }
433
-
434
- Peer.prototype._autoEnd = function () {
435
- if (this.uploading && this.remoteDownloading) return
436
- if ((this.sparse || this.live) && (this.remoteUploading || this.downloading)) return
437
- this.end()
438
- }
439
-
440
- Peer.prototype.onunhave = function (unhave) {
441
- var start = unhave.start
442
- var len = unhave.length || 1
443
-
444
- if (start === 0 && len >= this.remoteLength) {
445
- this.remoteLength = 0
446
- this.remoteBitfield = bitfield()
447
- return
448
- }
449
-
450
- while (len--) this.remoteBitfield.set(start++, false)
451
- }
452
-
453
- Peer.prototype.onunwant =
454
- Peer.prototype.oncancel = function () {
455
- // TODO: impl all of me
456
- }
457
-
458
- Peer.prototype.onclose = function () {
459
- this._close()
460
- }
461
-
462
- Peer.prototype.have = function (have) { // called by feed
463
- if (this.stream && this.remoteWant) this.stream.have(have)
464
- var start = have.start
465
- var len = have.length
466
- while (len--) this.remoteBitfield.set(start++, false)
467
- }
468
-
469
- Peer.prototype.unhave = function (unhave) { // called by feed
470
- if (this.stream && this.remoteWant) this.stream.unhave(unhave)
471
- }
472
-
473
- Peer.prototype.haveBytes = function (bytes) { // called by feed
474
- for (var i = 0; i < this.inflightRequests.length; i++) {
475
- if (this.inflightRequests[i].bytes === bytes) {
476
- this.feed._reserved.set(this.inflightRequests[i].index, false)
477
- this.inflightRequests.splice(i, 1)
478
- i--
479
- }
480
- }
481
-
482
- this.update()
483
-
484
- if (this.inflightRequests.length === 0 && this._requestTimeout !== null) {
485
- this._requestTimeout.destroy()
486
- this._requestTimeout = null
487
- }
488
- }
489
-
490
- Peer.prototype.update = function () {
491
- // do nothing
492
- while (this._update()) {}
493
- this._sendWantsMaybe()
494
- }
495
-
496
- Peer.prototype._update = function () {
497
- // should return true if mutated false if not
498
- if (!this.downloading || !this.remoteUploading) return false
499
- var selections = this.feed._selections
500
- var waiting = this.feed._waiting
501
- var wlen = waiting.length
502
- var slen = selections.length
503
- var inflight = this.inflightRequests.length
504
- var offset = 0
505
- var i = 0
506
-
507
- // TODO: less duplicate code here
508
- // TODO: re-add priority levels
509
-
510
- while (inflight < this.urgentRequests) {
511
- offset = Math.floor(Math.random() * waiting.length)
512
-
513
- for (i = 0; i < waiting.length; i++) {
514
- var w = waiting[offset++]
515
- if (offset === waiting.length) offset = 0
516
-
517
- this._downloadWaiting(w)
518
- if (waiting.length !== wlen) return true // mutated
519
- if (this.inflightRequests.length >= this.urgentRequests) return false
520
- }
521
- if (inflight === this.inflightRequests.length) break
522
- inflight = this.inflightRequests.length
523
- }
524
-
525
- while (inflight < this.maxRequests) {
526
- offset = Math.floor(Math.random() * selections.length)
527
-
528
- for (i = 0; i < selections.length; i++) {
529
- var s = selections[offset++]
530
- if (offset === selections.length) offset = 0
531
-
532
- if (!s.iterator) s.iterator = this.feed.bitfield.iterator(s.start, s.end)
533
- if (s.blocks) this._downloadBlocks(s)
534
- else this._downloadRange(s)
535
- if (selections.length !== slen) return true // mutated
536
- if (this.inflightRequests.length >= this.maxRequests) return false
537
- }
538
-
539
- if (inflight === this.inflightRequests.length) return false
540
- inflight = this.inflightRequests.length
541
- }
542
-
543
- return false
544
- }
545
-
546
- Peer.prototype.onopen = function () {
547
- this.feed.ifAvailable.continue()
548
- this.remoteOpened = true
549
-
550
- this._updateOptions()
551
-
552
- if (!this.uploading || !this.downloading) {
553
- this.stream.status({
554
- uploading: this.uploading,
555
- downloading: this.downloading
556
- })
557
- }
558
-
559
- this._sendWants()
560
- this.feed.emit('peer-open', this)
561
- }
562
-
563
- Peer.prototype.onoptions = function (options) {
564
- this.remoteAck = options.ack
565
- this.remoteExtensions.update(options.extensions)
566
- }
567
-
568
- Peer.prototype.ready = function () {
569
- this.feed.ifAvailable.wait() // continued by onopen or close
570
- set.add(this.feed.peers, this)
571
- this.feed.emit('peer-add', this)
572
- if (this.stream.remoteOpened) this.onopen()
573
- }
574
-
575
- Peer.prototype.end = function () {
576
- if (!this.downloading && !this.remoteDownloading && !this.live) {
577
- if (!this._defaultDownloading) {
578
- this.stream.status({ downloading: false, uploading: false })
579
- }
580
- this._close()
581
- return
582
- }
583
- if (!this._closed) {
584
- this._closed = true
585
- this.downloading = false
586
- this.stream.status({ downloading: false, uploading: true })
587
- } else {
588
- if (!this.live) this._close()
589
- }
590
- }
591
-
592
- Peer.prototype._close = function () {
593
- if (!this._destroyed) {
594
- this._destroyed = true
595
- this.stream.close()
596
- }
597
- if (this._index === -1) return
598
- set.remove(this.feed.peers, this)
599
- this._index = -1
600
- for (var i = 0; i < this.inflightRequests.length; i++) {
601
- this.feed._reserved.set(this.inflightRequests[i].index, false)
602
- }
603
- if (this._requestTimeout !== null) {
604
- this._requestTimeout.destroy()
605
- this._requestTimeout = null
606
- }
607
- this._updateEnd()
608
- this.remoteWant = false
609
- this.feed._updatePeers()
610
- this.feed.emit('peer-remove', this)
611
- for (i = 0; i < this.inflightWants; i++) {
612
- this.feed.ifAvailable.continue()
613
- }
614
- if (!this.remoteOpened) {
615
- this.feed.ifAvailable.continue()
616
- }
617
- }
618
-
619
- Peer.prototype.destroy = function (err) {
620
- if (this._index === -1 || this._destroyed) return
621
- this.stream.destroy(err)
622
- this._destroyed = true
623
- this._close()
624
- }
625
-
626
- Peer.prototype._sendWantsMaybe = function () {
627
- if (this.inflightRequests.length < this.urgentRequests) this._sendWants()
628
- }
629
-
630
- Peer.prototype._sendWants = function () {
631
- if (!this.wants || !this.downloading || !this.remoteOpened || !this.remoteUploading) return
632
- if (this.inflightWants >= 16) return
633
-
634
- var i
635
-
636
- for (i = 0; i < this.feed._waiting.length; i++) {
637
- var w = this.feed._waiting[i]
638
- if (w.index === -1) this._sendWantRange(w)
639
- else this._sendWant(w.index)
640
- if (this.inflightWants >= 16) return
641
- }
642
-
643
- for (i = 0; i < this.feed._selections.length; i++) {
644
- var s = this.feed._selections[i]
645
- this._sendWantRange(s)
646
- if (this.inflightWants >= 16) return
647
- }
648
-
649
- // always sub to the first range for now, usually what you want
650
- this._sendWant(0)
651
- }
652
-
653
- Peer.prototype._sendWantRange = function (s) {
654
- if (s.blocks) {
655
- if (!s.selected) s.selected = new WeakSet()
656
- if (s.selected.has(this)) return
657
- s.selected.add(this)
658
- for (const block of s.blocks) {
659
- this._sendWant(block)
660
- }
661
- return
662
- }
663
-
664
- var want = s.start ? 1024 * 1024 * Math.floor(s.start / 1024 / 1024) : 0
665
-
666
- while (true) {
667
- if (want >= this.remoteLength) return
668
- if (s.end !== -1 && want >= s.end) return
669
-
670
- if (this._sendWant(want)) return
671
-
672
- // check if region is already selected - if so try next one
673
- if (!this.wants.get(Math.floor(want / 1024 / 1024))) return
674
- want += 1024 * 1024
675
- }
676
- }
677
-
678
- Peer.prototype._sendWant = function (index) {
679
- var len = 1024 * 1024
680
- var j = Math.floor(index / len)
681
- if (this.wants.get(j)) return false
682
- this.wants.set(j, true)
683
- this.inflightWants++
684
- this.feed.ifAvailable.wait()
685
- this.stream.want({ start: j * len, length: len })
686
- return true
687
- }
688
-
689
- Peer.prototype._downloadWaiting = function (wait) {
690
- if (!wait.bytes) {
691
- if (!this.remoteBitfield.get(wait.index) || !this.feed._reserved.set(wait.index, true)) {
692
- if (!wait.update || this.feed._reserved.get(wait.index)) return
693
- const i = this._iterator.seek(wait.index).next(true)
694
- if (i === -1 || !this.feed._reserved.set(i, true)) return
695
- wait.index = i
696
- }
697
- this._request(wait.index, 0, wait.hash === true)
698
- return
699
- }
700
-
701
- this._downloadRange(wait)
702
- }
703
-
704
- Peer.prototype._downloadBlocks = function (range) {
705
- while (range.blocksDownloaded < range.blocks.length) {
706
- const blk = range.blocks[range.blocksDownloaded]
707
- if (!this.feed.bitfield.get(blk)) break
708
- range.blocksDownloaded++
709
- }
710
-
711
- if (range.blocksDownloaded >= range.blocks.length) {
712
- set.remove(this.feed._selections, range)
713
- range.callback(null)
714
- return
715
- }
716
-
717
- for (var i = range.blocksDownloaded; i < range.blocks.length; i++) {
718
- const blk = range.blocks[i]
719
- if (this.remoteBitfield.get(blk) && this.feed._reserved.set(blk, true)) {
720
- range.requested++
721
- this._request(blk, 0, false)
722
- return
723
- }
724
- }
725
- }
726
-
727
- Peer.prototype._downloadRange = function (range) {
728
- if (!range.iterator) range.iterator = this.feed.bitfield.iterator(range.start, range.end)
729
-
730
- var reserved = this.feed._reserved
731
- var ite = this._iterator
732
- var wantedEnd = Math.min(range.end === -1 ? this.remoteLength : range.end, this.remoteLength)
733
-
734
- var i = range.linear ? ite.seek(range.start).next(true) : nextRandom(ite, range.start, wantedEnd)
735
- var start = i
736
-
737
- if (i === -1 || i >= wantedEnd) {
738
- if (!range.bytes && range.end > -1 && this.feed.length >= range.end && range.iterator.seek(0).next() === -1) {
739
- set.remove(this.feed._selections, range)
740
- range.callback(null)
741
- if (!this.live && !this.sparse && !this.feed._selections.length) this.end()
742
- }
743
- return
744
- }
745
-
746
- while ((range.hash && this.feed.tree.get(2 * i)) || !reserved.set(i, true)) {
747
- i = ite.next(true)
748
-
749
- if (i > -1 && i < wantedEnd) {
750
- // check this index
751
- continue
752
- }
753
-
754
- if (!range.linear && start !== 0) {
755
- // retry from the beginning since we are iterating randomly and started !== 0
756
- i = ite.seek(range.start).next(true)
757
- start = 0
758
- if (i > -1 && i < wantedEnd) continue
759
- }
760
-
761
- // we have checked all indexes.
762
- // if we are looking for hashes we should check if we have all now (first check only checks blocks)
763
- if (range.hash) {
764
- // quick'n'dirty check if have all hashes - can be optimized be checking only tree roots
765
- // but we don't really request long ranges of hashes so yolo
766
- for (var j = range.start; j < wantedEnd; j++) {
767
- if (!this.feed.tree.get(2 * j)) return
768
- }
769
- if (!range.bytes) {
770
- set.remove(this.feed._selections, range)
771
- range.callback(null)
772
- }
773
- }
774
-
775
- // exit the update loop - nothing to do
776
- return
777
- }
778
-
779
- range.requested++
780
- this._request(i, range.bytes || 0, range.hash)
781
- }
782
-
783
- Peer.prototype._request = function (index, bytes, hash) {
784
- var request = {
785
- bytes: bytes,
786
- index: index,
787
- hash: hash,
788
- nodes: this.feed.digest(index)
789
- }
790
-
791
- if (this._requestTimeout === null && this.stream.stream.timeout) {
792
- this._requestTimeout = timeout(this.stream.stream.timeout.ms, this._onrequesttimeout, this)
793
- }
794
- this.inflightRequests.push(request)
795
- this.stream.request(request)
796
- }
797
-
798
- Peer.prototype.extension = function (id, message) {
799
- this.stream.extension(id, message)
800
- }
801
-
802
- function createView (page) {
803
- var buf = page ? page.buffer : EMPTY
804
- return new DataView(buf.buffer, buf.byteOffset, 1024)
805
- }
806
-
807
- function remoteAndNotLocal (local, buf, le, start) {
808
- var remote = new DataView(buf.buffer, buf.byteOffset)
809
- var len = Math.floor(buf.length / 4)
810
- var arr = new Uint32Array(buf.buffer, buf.byteOffset, len)
811
- var p = start / 8192 // 8192 is bits per bitfield page
812
- var l = 0
813
- var page = createView(local.pages.get(p++, true))
814
-
815
- for (var i = 0; i < len; i++) {
816
- arr[i] = remote.getUint32(4 * i, !le) & ~page.getUint32(4 * (l++), !le)
817
-
818
- if (l === 256) {
819
- page = createView(local.pages.get(p++, true))
820
- l = 0
821
- }
822
- }
823
- }
824
-
825
- function nextRandom (ite, start, end) {
826
- var len = end - start
827
- var i = ite.seek(Math.floor(Math.random() * len) + start).next(true)
828
- return i === -1 || i >= end ? ite.seek(start).next(true) : i
829
- }