hypercore 10.0.0-alpha.45 → 10.0.0-alpha.48
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 +2 -1
- package/index.js +39 -9
- package/lib/caps.js +1 -3
- package/lib/replicator.js +51 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,7 +66,8 @@ Note that `tree`, `data`, and `bitfield` are normally heavily sparse files.
|
|
|
66
66
|
valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to binary
|
|
67
67
|
encodeBatch: batch => { ... }, // optionally apply an encoding to complete batches
|
|
68
68
|
keyPair: kp, // optionally pass the public key and secret key as a key pair
|
|
69
|
-
encryptionKey: k // optionally pass an encryption key to enable block encryption
|
|
69
|
+
encryptionKey: k, // optionally pass an encryption key to enable block encryption
|
|
70
|
+
onwait: () => {} // hook that is called if gets are waiting for download
|
|
70
71
|
}
|
|
71
72
|
```
|
|
72
73
|
|
package/index.js
CHANGED
|
@@ -70,6 +70,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
70
70
|
this.sessions = opts._sessions || [this]
|
|
71
71
|
this.auth = opts.auth || null
|
|
72
72
|
this.autoClose = !!opts.autoClose
|
|
73
|
+
this.onwait = opts.onwait || null
|
|
73
74
|
|
|
74
75
|
this.closing = null
|
|
75
76
|
this.opening = this._openSession(key, storage, opts)
|
|
@@ -113,6 +114,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
113
114
|
indent + ' opened: ' + opts.stylize(this.opened, 'boolean') + '\n' +
|
|
114
115
|
indent + ' closed: ' + opts.stylize(this.closed, 'boolean') + '\n' +
|
|
115
116
|
indent + ' snapshotted: ' + opts.stylize(this.snapshotted, 'boolean') + '\n' +
|
|
117
|
+
indent + ' sparse: ' + opts.stylize(this.sparse, 'boolean') + '\n' +
|
|
116
118
|
indent + ' writable: ' + opts.stylize(this.writable, 'boolean') + '\n' +
|
|
117
119
|
indent + ' length: ' + opts.stylize(this.length, 'number') + '\n' +
|
|
118
120
|
indent + ' byteLength: ' + opts.stylize(this.byteLength, 'number') + '\n' +
|
|
@@ -182,9 +184,11 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
182
184
|
throw SESSION_CLOSED('Cannot make sessions on a closing core')
|
|
183
185
|
}
|
|
184
186
|
|
|
187
|
+
const sparse = opts.sparse === false ? false : this.sparse
|
|
185
188
|
const Clz = opts.class || Hypercore
|
|
186
189
|
const s = new Clz(this.storage, this.key, {
|
|
187
190
|
...opts,
|
|
191
|
+
sparse,
|
|
188
192
|
_opening: this.opening,
|
|
189
193
|
_sessions: this.sessions
|
|
190
194
|
})
|
|
@@ -324,14 +328,27 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
324
328
|
}
|
|
325
329
|
}
|
|
326
330
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
331
|
+
_getSnapshot () {
|
|
332
|
+
if (this.sparse) {
|
|
333
|
+
return {
|
|
334
|
+
length: this.core.tree.length,
|
|
335
|
+
byteLength: this.core.tree.byteLength,
|
|
336
|
+
fork: this.core.tree.fork,
|
|
337
|
+
compatLength: this.core.tree.length
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
length: this.core.header.contiguousLength,
|
|
343
|
+
byteLength: 0,
|
|
332
344
|
fork: this.core.tree.fork,
|
|
333
|
-
compatLength: this.core.
|
|
345
|
+
compatLength: this.core.header.contiguousLength
|
|
334
346
|
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
_updateSnapshot () {
|
|
350
|
+
const prev = this._snapshot
|
|
351
|
+
const next = this._snapshot = this._getSnapshot()
|
|
335
352
|
|
|
336
353
|
if (!prev) return true
|
|
337
354
|
return prev.length !== next.length || prev.fork !== next.fork
|
|
@@ -573,10 +590,22 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
573
590
|
const activeRequests = (opts && opts.activeRequests) || this.activeRequests
|
|
574
591
|
const req = this.replicator.addUpgrade(activeRequests)
|
|
575
592
|
|
|
576
|
-
|
|
577
|
-
|
|
593
|
+
let upgraded = await req.promise
|
|
594
|
+
|
|
595
|
+
if (!this.sparse) {
|
|
596
|
+
// Download all available blocks in non-sparse mode
|
|
597
|
+
const start = this.length
|
|
598
|
+
const end = this.core.tree.length
|
|
599
|
+
const contig = this.contiguousLength
|
|
600
|
+
|
|
601
|
+
await this.download({ start, end, ifAvailable: true }).downloaded()
|
|
602
|
+
|
|
603
|
+
if (!upgraded) upgraded = this.contiguousLength !== contig
|
|
604
|
+
}
|
|
578
605
|
|
|
579
|
-
|
|
606
|
+
if (!upgraded) return false
|
|
607
|
+
if (this.snapshotted) return this._updateSnapshot()
|
|
608
|
+
return true
|
|
580
609
|
}
|
|
581
610
|
|
|
582
611
|
async seek (bytes, opts) {
|
|
@@ -634,6 +663,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
634
663
|
} else {
|
|
635
664
|
if (opts && opts.wait === false) return null
|
|
636
665
|
if (opts && opts.onwait) opts.onwait(index)
|
|
666
|
+
else if (this.onwait) this.onwait(index)
|
|
637
667
|
|
|
638
668
|
const activeRequests = (opts && opts.activeRequests) || this.activeRequests
|
|
639
669
|
|
package/lib/caps.js
CHANGED
|
@@ -4,9 +4,7 @@ const b4a = require('b4a')
|
|
|
4
4
|
const c = require('compact-encoding')
|
|
5
5
|
|
|
6
6
|
// TODO: rename this to "crypto" and move everything hashing related etc in here
|
|
7
|
-
// Also lets move the tree stuff from hypercore-crypto here
|
|
8
|
-
// from the hashes there - they are not needed since we lock the indexes in the tree
|
|
9
|
-
// hash and just makes alignment etc harder in other languages
|
|
7
|
+
// Also lets move the tree stuff from hypercore-crypto here
|
|
10
8
|
|
|
11
9
|
const [TREE, REPLICATE_INITIATOR, REPLICATE_RESPONDER] = crypto.namespace('hypercore', 3)
|
|
12
10
|
|
package/lib/replicator.js
CHANGED
|
@@ -102,12 +102,13 @@ class BlockRequest extends Attachable {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
class RangeRequest extends Attachable {
|
|
105
|
-
constructor (ranges, start, end, linear, blocks) {
|
|
105
|
+
constructor (ranges, start, end, linear, ifAvailable, blocks) {
|
|
106
106
|
super()
|
|
107
107
|
|
|
108
108
|
this.start = start
|
|
109
109
|
this.end = end
|
|
110
110
|
this.linear = linear
|
|
111
|
+
this.ifAvailable = ifAvailable
|
|
111
112
|
this.blocks = blocks
|
|
112
113
|
this.ranges = ranges
|
|
113
114
|
|
|
@@ -172,6 +173,10 @@ class InflightTracker {
|
|
|
172
173
|
this._free = []
|
|
173
174
|
}
|
|
174
175
|
|
|
176
|
+
get idle () {
|
|
177
|
+
return this._requests.length === this._free.length
|
|
178
|
+
}
|
|
179
|
+
|
|
175
180
|
* [Symbol.iterator] () {
|
|
176
181
|
for (const req of this._requests) {
|
|
177
182
|
if (req !== null) yield req
|
|
@@ -260,6 +265,7 @@ class Peer {
|
|
|
260
265
|
|
|
261
266
|
this.inflight = 0
|
|
262
267
|
this.maxInflight = DEFAULT_MAX_INFLIGHT
|
|
268
|
+
this.dataProcessing = 0
|
|
263
269
|
|
|
264
270
|
this.canUpgrade = true
|
|
265
271
|
|
|
@@ -515,6 +521,8 @@ class Peer {
|
|
|
515
521
|
|
|
516
522
|
if (reorg === true) return this.replicator._onreorgdata(this, req, data)
|
|
517
523
|
|
|
524
|
+
this.dataProcessing++
|
|
525
|
+
|
|
518
526
|
try {
|
|
519
527
|
if (!matchingRequest(req, data) || !(await this.core.verify(data, this))) {
|
|
520
528
|
this.replicator._onnodata(this, req)
|
|
@@ -523,6 +531,8 @@ class Peer {
|
|
|
523
531
|
} catch (err) {
|
|
524
532
|
this.replicator._onnodata(this, req)
|
|
525
533
|
throw err
|
|
534
|
+
} finally {
|
|
535
|
+
this.dataProcessing--
|
|
526
536
|
}
|
|
527
537
|
|
|
528
538
|
this.replicator._ondata(this, req, data)
|
|
@@ -909,13 +919,21 @@ module.exports = class Replicator {
|
|
|
909
919
|
return ref
|
|
910
920
|
}
|
|
911
921
|
|
|
912
|
-
addRange (session, { start = 0, end = -1, length = toLength(start, end), blocks = null, linear = false } = {}) {
|
|
922
|
+
addRange (session, { start = 0, end = -1, length = toLength(start, end), blocks = null, linear = false, ifAvailable = false } = {}) {
|
|
913
923
|
if (blocks !== null) { // if using blocks, start, end just acts as frames around the blocks array
|
|
914
924
|
start = 0
|
|
915
925
|
end = length = blocks.length
|
|
916
926
|
}
|
|
917
927
|
|
|
918
|
-
const r = new RangeRequest(
|
|
928
|
+
const r = new RangeRequest(
|
|
929
|
+
this._ranges,
|
|
930
|
+
start,
|
|
931
|
+
length === -1 ? -1 : start + length,
|
|
932
|
+
linear,
|
|
933
|
+
ifAvailable,
|
|
934
|
+
blocks
|
|
935
|
+
)
|
|
936
|
+
|
|
919
937
|
const ref = r.attach(session)
|
|
920
938
|
|
|
921
939
|
this._ranges.push(r)
|
|
@@ -1115,6 +1133,14 @@ module.exports = class Replicator {
|
|
|
1115
1133
|
return true
|
|
1116
1134
|
}
|
|
1117
1135
|
|
|
1136
|
+
_resolveRangeRequest (req, index) {
|
|
1137
|
+
const head = this._ranges.pop()
|
|
1138
|
+
|
|
1139
|
+
if (index < this._ranges.length) this._ranges[index] = head
|
|
1140
|
+
|
|
1141
|
+
req.resolve(true)
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1118
1144
|
_clearInflightBlock (tracker, req) {
|
|
1119
1145
|
const isBlock = tracker === this._blocks
|
|
1120
1146
|
const index = isBlock === true ? req.block.index : req.hash.index / 2
|
|
@@ -1168,14 +1194,9 @@ module.exports = class Replicator {
|
|
|
1168
1194
|
while (r.start < r.end && this.core.bitfield.get(mapIndex(r.blocks, r.start)) === true) r.start++
|
|
1169
1195
|
while (r.start < r.end && this.core.bitfield.get(mapIndex(r.blocks, r.end - 1)) === true) r.end--
|
|
1170
1196
|
|
|
1171
|
-
if (r.end
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
else this._ranges.pop()
|
|
1175
|
-
|
|
1176
|
-
i--
|
|
1177
|
-
|
|
1178
|
-
r.resolve(true)
|
|
1197
|
+
if (r.end !== -1 && r.start >= r.end) {
|
|
1198
|
+
this._resolveRangeRequest(r, i--)
|
|
1199
|
+
}
|
|
1179
1200
|
}
|
|
1180
1201
|
|
|
1181
1202
|
for (let i = 0; i < this._seeks.length; i++) {
|
|
@@ -1201,7 +1222,7 @@ module.exports = class Replicator {
|
|
|
1201
1222
|
else s.resolve(res)
|
|
1202
1223
|
}
|
|
1203
1224
|
|
|
1204
|
-
this.updateAll()
|
|
1225
|
+
if (this._inflight.idle) this.updateAll()
|
|
1205
1226
|
|
|
1206
1227
|
// No additional updates scheduled - return
|
|
1207
1228
|
if (--this._updatesPending === 0) return
|
|
@@ -1210,6 +1231,22 @@ module.exports = class Replicator {
|
|
|
1210
1231
|
}
|
|
1211
1232
|
}
|
|
1212
1233
|
|
|
1234
|
+
_maybeResolveIfAvailableRanges () {
|
|
1235
|
+
if (this._ifAvailable > 0 || !this._inflight.idle || !this._ranges.length) return
|
|
1236
|
+
|
|
1237
|
+
for (let i = 0; i < this.peers.length; i++) {
|
|
1238
|
+
if (this.peers[i].dataProcessing > 0) return
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
for (let i = 0; i < this._ranges.length; i++) {
|
|
1242
|
+
const r = this._ranges[i]
|
|
1243
|
+
|
|
1244
|
+
if (r.ifAvailable) {
|
|
1245
|
+
this._resolveRangeRequest(r, i--)
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1213
1250
|
_clearRequest (peer, req) {
|
|
1214
1251
|
if (req.block !== null) {
|
|
1215
1252
|
this._clearInflightBlock(this._blocks, req)
|
|
@@ -1407,6 +1444,7 @@ module.exports = class Replicator {
|
|
|
1407
1444
|
while (this._updatePeerNonPrimary(peer) === true);
|
|
1408
1445
|
|
|
1409
1446
|
this._checkUpgradeIfAvailable()
|
|
1447
|
+
this._maybeResolveIfAvailableRanges()
|
|
1410
1448
|
}
|
|
1411
1449
|
|
|
1412
1450
|
updateAll () {
|
|
@@ -1434,6 +1472,7 @@ module.exports = class Replicator {
|
|
|
1434
1472
|
}
|
|
1435
1473
|
|
|
1436
1474
|
this._checkUpgradeIfAvailable()
|
|
1475
|
+
this._maybeResolveIfAvailableRanges()
|
|
1437
1476
|
}
|
|
1438
1477
|
|
|
1439
1478
|
attachTo (protomux) {
|