hypercore 11.14.1 → 11.15.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 +249 -22
- package/index.js +10 -5
- package/lib/replicator.js +32 -14
- package/lib/session-state.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,11 +23,6 @@ Version 10 is not compatible with earlier versions (9 and earlier), but is consi
|
|
|
23
23
|
npm install hypercore
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
> [!NOTE]
|
|
27
|
-
> This readme reflects Hypercore 11, our latest major version that is backed by RocksDB for storage and atomicity.
|
|
28
|
-
> Whilst we are fully validating that, the npm dist-tag for latest is set to latest version of Hypercore 10, the previous major, to avoid too much disruption.
|
|
29
|
-
> It will be updated to 11 in a few weeks.
|
|
30
|
-
|
|
31
26
|
## API
|
|
32
27
|
|
|
33
28
|
#### `const core = new Hypercore(storage, [key], [options])`
|
|
@@ -50,6 +45,7 @@ Alternatively you can pass a [Hypercore Storage](https://github.com/holepunchto/
|
|
|
50
45
|
{
|
|
51
46
|
createIfMissing: true, // create a new Hypercore key pair if none was present in storage
|
|
52
47
|
overwrite: false, // overwrite any old Hypercore that might already exist
|
|
48
|
+
force: false, // Advanced option. Will force overwrite even if the header's key & the passed key don't match
|
|
53
49
|
valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to binary
|
|
54
50
|
encodeBatch: batch => { ... }, // optionally apply an encoding to complete batches
|
|
55
51
|
keyPair: kp, // optionally pass the public key and secret key as a key pair
|
|
@@ -59,9 +55,14 @@ Alternatively you can pass a [Hypercore Storage](https://github.com/holepunchto/
|
|
|
59
55
|
writable: true, // disable appends and truncates
|
|
60
56
|
inflightRange: null, // Advanced option. Set to [minInflight, maxInflight] to change the min and max inflight blocks per peer when downloading.
|
|
61
57
|
ongc: (session) => { ... }, // A callback called when the session is garbage collected
|
|
58
|
+
onseq: (index, core) => { ... }, // A callback called when core.get(index) is called.
|
|
62
59
|
notDownloadingLinger: 20000, // How many milliseconds to wait after downloading finishes keeping the connection open. Defaults to a random number between 20-40s
|
|
63
60
|
allowFork: true, // Enables updating core when it forks
|
|
64
|
-
userData: { foo: 'bar' }, // An object to assign to the local User
|
|
61
|
+
userData: { foo: 'bar' }, // An object to assign to the local User Data storage
|
|
62
|
+
manifest: undefined, // Advanced option. Set the manifest when creating the hypercore. See Manifest section for more info
|
|
63
|
+
preload: undefined, // Advanced option. A promise that returns constructor options overrides before the core is opened
|
|
64
|
+
storage: undefined, // An alternative to passing storage as a dedicated argument
|
|
65
|
+
key: null, // An alternative to passing key as a dedicated argument
|
|
65
66
|
}
|
|
66
67
|
```
|
|
67
68
|
|
|
@@ -79,7 +80,36 @@ Keys are always strings and values can be strings or buffers.
|
|
|
79
80
|
|
|
80
81
|
See [`core.setUserData(key, value)`](#await-coresetuserdatakey-value) and [`core.getUserData(key)`](#const-value--await-coregetuserdatakey) for updating User Data.
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
##### Manifest
|
|
84
|
+
|
|
85
|
+
The manifest is metadata about authenticating a hypercore including things like the signers (only one by default) and the prologue. Manifest has the following structure:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
{
|
|
89
|
+
version: 1, // Version of the manifest format
|
|
90
|
+
hash: 'blake2b', // Only Blake2b is supported currently
|
|
91
|
+
allowPatch: false, // Whether the hypercore can be "patched" to change the signers
|
|
92
|
+
quorum: (signers.length / 2) + 1, // How many signers needed to verify a block
|
|
93
|
+
signers, // Array of signers for the core
|
|
94
|
+
prologue: null, // The tree hash and length of the core
|
|
95
|
+
linked: null, // Array of associated core keys. Only supported in versions >= 2
|
|
96
|
+
userData: null // Arbitrary buffer for User Data integral to the core. Only supported in versions >= 2
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The `linked` property in the manifest is used to reference other hypercores that are associated with the current core. For example in `autobase` the encryption view is loaded from the `linked` property in the system view core. Note, as with everything in the manifest, changing the `linked` property changes the core's `key`.
|
|
101
|
+
|
|
102
|
+
Signers are an array of objects with the following structure:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
{
|
|
106
|
+
signature: 'ed25519', // The signature method
|
|
107
|
+
namespace: caps.DEFAULT_NAMESPACE, // A cryptographic namespace for the signature
|
|
108
|
+
publicKey: Buffer // Signer's public key
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### `const { length, byteLength } = await core.append(block, options = {})`
|
|
83
113
|
|
|
84
114
|
Append a block of data (or an array of blocks) to the core.
|
|
85
115
|
Returns the new length and byte length of the core.
|
|
@@ -92,6 +122,17 @@ await core.append(Buffer.from('I am a block of data'))
|
|
|
92
122
|
await core.append([Buffer.from('batch block 1'), Buffer.from('batch block 2')])
|
|
93
123
|
```
|
|
94
124
|
|
|
125
|
+
`options` include:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
{
|
|
129
|
+
writable: false // Enabled ignores writable check. Does not override whether core is writable.
|
|
130
|
+
maxLength: undefined // The maximum resulting length of the core after appending
|
|
131
|
+
keyPair: core.keyPair // KeyPair used to sign the block(s)
|
|
132
|
+
signature: null // Set signature for block(s)
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
95
136
|
#### `const block = await core.get(index, [options])`
|
|
96
137
|
|
|
97
138
|
Get a block of data.
|
|
@@ -115,8 +156,10 @@ const blockLocal = await core.get(44, { wait: false })
|
|
|
115
156
|
wait: true, // wait for block to be downloaded
|
|
116
157
|
onwait: () => {}, // hook that is called if the get is waiting for download
|
|
117
158
|
timeout: 0, // wait at max some milliseconds (0 means no timeout)
|
|
159
|
+
activeRequests: undefined, // Advanced option. Pass BlockRequest for replicating the block
|
|
118
160
|
valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to the core's valueEncoding
|
|
119
|
-
decrypt: true // automatically decrypts the block if encrypted
|
|
161
|
+
decrypt: true, // automatically decrypts the block if encrypted
|
|
162
|
+
raw: false, // Return block without decoding
|
|
120
163
|
}
|
|
121
164
|
```
|
|
122
165
|
|
|
@@ -138,7 +181,9 @@ console.log('core was updated?', updated, 'length is', core.length)
|
|
|
138
181
|
|
|
139
182
|
``` js
|
|
140
183
|
{
|
|
141
|
-
wait: false
|
|
184
|
+
wait: false,
|
|
185
|
+
activeRequests: undefined, // Advanced option. Pass requests for replicating blocks
|
|
186
|
+
force: false, // Force an update even if core is writable.
|
|
142
187
|
}
|
|
143
188
|
```
|
|
144
189
|
|
|
@@ -162,7 +207,8 @@ const third = await core.seek(5) // returns [2, 1]
|
|
|
162
207
|
``` js
|
|
163
208
|
{
|
|
164
209
|
wait: true, // wait for data to be downloaded
|
|
165
|
-
timeout: 0 // wait at max some milliseconds (0 means no timeout)
|
|
210
|
+
timeout: 0, // wait at max some milliseconds (0 means no timeout)
|
|
211
|
+
activeRequests: undefined // Advanced option. Pass requests for replicating blocks
|
|
166
212
|
}
|
|
167
213
|
```
|
|
168
214
|
|
|
@@ -191,7 +237,9 @@ for await (const data of fullStream) {
|
|
|
191
237
|
{
|
|
192
238
|
start: 0,
|
|
193
239
|
end: core.length,
|
|
194
|
-
|
|
240
|
+
wait: core.wait, // Whether to wait for updates from peers
|
|
241
|
+
timeout: core.timeout, // How long to wait for updates from peers
|
|
242
|
+
live: false, // Wait for next block keeping stream open / live
|
|
195
243
|
snapshot: true // auto set end to core.length on open or update it on every read
|
|
196
244
|
}
|
|
197
245
|
```
|
|
@@ -220,12 +268,31 @@ partialStream.pipe(process.stdout)
|
|
|
220
268
|
|
|
221
269
|
``` js
|
|
222
270
|
{
|
|
223
|
-
byteOffset: 0,
|
|
224
|
-
byteLength: core.byteLength - options.byteOffset,
|
|
225
|
-
prefetch: 32
|
|
271
|
+
byteOffset: 0, // Offset where to start from
|
|
272
|
+
byteLength: core.byteLength - options.byteOffset, // How many bytes to read
|
|
273
|
+
prefetch: 32 // How many bytes to download at a time
|
|
226
274
|
}
|
|
227
275
|
```
|
|
228
276
|
|
|
277
|
+
#### `const stream = core.createWriteStream()`
|
|
278
|
+
|
|
279
|
+
Make a write stream to append chunks as blocks.
|
|
280
|
+
|
|
281
|
+
``` js
|
|
282
|
+
const ws = core.createWriteStream()
|
|
283
|
+
|
|
284
|
+
// Listen for stream finishing
|
|
285
|
+
const done = new Promise(resolve => ws.on('finish', resolve))
|
|
286
|
+
|
|
287
|
+
for (const data of ['hello', 'world']) ws.write(data)
|
|
288
|
+
ws.end()
|
|
289
|
+
|
|
290
|
+
await done
|
|
291
|
+
|
|
292
|
+
console.log(await core.get(core.length - 2)) // 'hello'
|
|
293
|
+
console.log(await core.get(core.length - 1)) // 'world'
|
|
294
|
+
```
|
|
295
|
+
|
|
229
296
|
#### `const cleared = await core.clear(start, [end], [options])`
|
|
230
297
|
|
|
231
298
|
Clear stored blocks between `start` and `end`, reclaiming storage when possible.
|
|
@@ -244,17 +311,55 @@ The core will also gossip to peers it is connected to, that is no longer has the
|
|
|
244
311
|
}
|
|
245
312
|
```
|
|
246
313
|
|
|
247
|
-
#### `await core.truncate(newLength, [
|
|
314
|
+
#### `await core.truncate(newLength, [options])`
|
|
248
315
|
|
|
249
316
|
Truncate the core to a smaller length.
|
|
250
317
|
|
|
251
|
-
Per default this will update the fork id of the core to `+ 1`, but you can set the fork id you prefer with the option
|
|
318
|
+
Per default this will update the fork id of the core to `+ 1`, but you can set the fork id you prefer with the option `fork`.
|
|
252
319
|
Note that the fork id should be monotonely incrementing.
|
|
253
320
|
|
|
321
|
+
`options` include:
|
|
322
|
+
```js
|
|
323
|
+
{
|
|
324
|
+
fork: core.fork + 1, // The new fork id after truncating
|
|
325
|
+
keyPair: core.keyPair, // Key pair used for signing the truncation
|
|
326
|
+
signature: null, // Set signature for truncation
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
If `options` is a number, it will be used as the `fork` id.
|
|
331
|
+
|
|
254
332
|
#### `const hash = await core.treeHash([length])`
|
|
255
333
|
|
|
256
334
|
Get the Merkle Tree hash of the core at a given length, defaulting to the current length of the core.
|
|
257
335
|
|
|
336
|
+
#### `const proof = await core.proof(opts)`
|
|
337
|
+
|
|
338
|
+
Generate a proof (a `TreeProof` instance) for the request `opts`.
|
|
339
|
+
|
|
340
|
+
`opts` include:
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
{
|
|
344
|
+
block: { index, nodes }, // Block request
|
|
345
|
+
hash: { index, nodes }, // Hash Request
|
|
346
|
+
seek: { bytes, padding }, // Seek Request
|
|
347
|
+
upgrade: { start, length } // Upgrade request
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Note that you cannot seek & provide a block / hash request when upgrading.
|
|
352
|
+
|
|
353
|
+
#### `const batch = await core.verifyFullyRemote(proof)`
|
|
354
|
+
|
|
355
|
+
Return the merkle tree batch from the proof. Will throw if the proof cannot be verified.
|
|
356
|
+
|
|
357
|
+
Note that you cannot seek & provide a block / hash request when upgrading.
|
|
358
|
+
|
|
359
|
+
#### `const buffer = await core.signable([length], [fork])`
|
|
360
|
+
|
|
361
|
+
Return a buffer which encodes the core's `key`, tree hash (`core.treeHash()`), `length`, & `fork`. If the `length` & `fork` arguments are not provided, the current values for the core are used by default.
|
|
362
|
+
|
|
258
363
|
#### `const range = core.download([range])`
|
|
259
364
|
|
|
260
365
|
Download a range of data.
|
|
@@ -272,7 +377,8 @@ A range can have the following properties:
|
|
|
272
377
|
start: startIndex,
|
|
273
378
|
end: nonInclusiveEndIndex,
|
|
274
379
|
blocks: [index1, index2, ...],
|
|
275
|
-
linear: false // download range linearly and not randomly
|
|
380
|
+
linear: false, // download range linearly and not randomly
|
|
381
|
+
activeRequests: undefined // Advanced option. Pass requests for replicating blocks
|
|
276
382
|
}
|
|
277
383
|
```
|
|
278
384
|
|
|
@@ -297,6 +403,31 @@ To cancel downloading a range simply destroy the range instance.
|
|
|
297
403
|
range.destroy()
|
|
298
404
|
```
|
|
299
405
|
|
|
406
|
+
#### `const ext = core.registerExtension(name, handlers = {})`
|
|
407
|
+
|
|
408
|
+
Register a custom protocol extension. This is a legacy implementation and is no longer recommended. Creating a [`Protomux`](https://github.com/holepunchto/protomux) protocol is recommended instead.
|
|
409
|
+
|
|
410
|
+
`handlers` include:
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
{
|
|
414
|
+
encoding: 'json' | 'utf-8' | 'binary', // Compact encoding to use for messages. Defaults to buffer
|
|
415
|
+
onmessage: (message, peer) => { ... } // Callback for when a message for the extension is receive
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
##### ext.send(message, peer)
|
|
420
|
+
|
|
421
|
+
Sends the `message` to a specific `peer`.
|
|
422
|
+
|
|
423
|
+
##### ext.broadcast(message)
|
|
424
|
+
|
|
425
|
+
Sends the `message` to all peers.
|
|
426
|
+
|
|
427
|
+
##### ext.destroy()
|
|
428
|
+
|
|
429
|
+
Unregister and remove extension from the hypercore.
|
|
430
|
+
|
|
300
431
|
#### `const session = core.session([options])`
|
|
301
432
|
|
|
302
433
|
Creates a new Hypercore instance that shares the same underlying core.
|
|
@@ -342,9 +473,20 @@ Attempt to apply blocks from the session to the `core`. `core` must be a default
|
|
|
342
473
|
|
|
343
474
|
Returns `null` if committing failed.
|
|
344
475
|
|
|
476
|
+
`opts` includes:
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
{
|
|
480
|
+
length: session.length, // the core's length after committing the blocks
|
|
481
|
+
treeLength: core.length, // The expected length of the core's merkle tree prior to commit
|
|
482
|
+
keyPair: core.keyPair, // The keypair to use when committing
|
|
483
|
+
signature: undefined, // The signature for the blocks being committed
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
345
487
|
#### `const snapshot = core.snapshot([options])`
|
|
346
488
|
|
|
347
|
-
Same as
|
|
489
|
+
Same as [`core.session(options)`](#const-session--coresessionoptions), but backed by a storage snapshot so will not truncate nor append.
|
|
348
490
|
|
|
349
491
|
#### `const info = await core.info([options])`
|
|
350
492
|
|
|
@@ -378,9 +520,9 @@ Info {
|
|
|
378
520
|
}
|
|
379
521
|
```
|
|
380
522
|
|
|
381
|
-
#### `await core.close()`
|
|
523
|
+
#### `await core.close([{ error }])`
|
|
382
524
|
|
|
383
|
-
Fully close this core.
|
|
525
|
+
Fully close this core. Passing an error via `{ error }` is optional and all pending replicator requests will be rejected with the error.
|
|
384
526
|
|
|
385
527
|
#### `core.on('close')`
|
|
386
528
|
|
|
@@ -401,7 +543,7 @@ Emitted after the core has initially opened all its internal state.
|
|
|
401
543
|
|
|
402
544
|
#### `core.writable`
|
|
403
545
|
|
|
404
|
-
Can we append to this core?
|
|
546
|
+
Can we append to or truncate this core?
|
|
405
547
|
|
|
406
548
|
Populated after `ready` has been emitted. Will be `false` before the event.
|
|
407
549
|
|
|
@@ -464,6 +606,36 @@ Populated after `ready` has been emitted. Will be `0` before the event.
|
|
|
464
606
|
|
|
465
607
|
How much padding is applied to each block of this core? Will be `0` unless block encryption is enabled.
|
|
466
608
|
|
|
609
|
+
#### `core.peers`
|
|
610
|
+
|
|
611
|
+
Array of current peers the core is replicating with.
|
|
612
|
+
|
|
613
|
+
#### `await core.setEncryption(encryption)`
|
|
614
|
+
|
|
615
|
+
Set the encryption, which should satisfy the [HypercoreEncryption](https://github.com/holepunchto/hypercore-encryption) interface.
|
|
616
|
+
|
|
617
|
+
#### `await core.setEncryptionKey(key, [opts])`
|
|
618
|
+
|
|
619
|
+
Set the encryption key.
|
|
620
|
+
|
|
621
|
+
`opts` includes:
|
|
622
|
+
|
|
623
|
+
```
|
|
624
|
+
{
|
|
625
|
+
block: false, // Whether the key is for block encryption
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
#### `core.setKeyPair(keyPair)`
|
|
630
|
+
|
|
631
|
+
Update the core's `keyPair`. Advanced as the `keyPair` is used throughout Hypercore, e.g. verifying blocks, identifying the core, etc.
|
|
632
|
+
|
|
633
|
+
#### `core.setActive(active)`
|
|
634
|
+
|
|
635
|
+
Set the core to be active or not. A core is considered 'active' if it should linger to download blocks from peers.
|
|
636
|
+
|
|
637
|
+
When calling `core.setActive(true)` make sure to later call `core.setActive(false)` to mark it as inactive otherwise the core's activity tracking will be inaccurate and keep replication channels open.
|
|
638
|
+
|
|
467
639
|
#### `await core.setUserData(key, value)`
|
|
468
640
|
|
|
469
641
|
Set a key in the User Data key-value store.
|
|
@@ -476,7 +648,7 @@ Return the value for a key in the User Data key-value store.
|
|
|
476
648
|
|
|
477
649
|
`key` is a string.
|
|
478
650
|
|
|
479
|
-
#### `const stream = core.replicate(isInitiatorOrReplicationStream)`
|
|
651
|
+
#### `const stream = core.replicate(isInitiatorOrReplicationStream, opts = {})`
|
|
480
652
|
|
|
481
653
|
Create a replication stream. You should pipe this to another Hypercore instance.
|
|
482
654
|
|
|
@@ -501,6 +673,8 @@ const socket = net.connect(...)
|
|
|
501
673
|
socket.pipe(localCore.replicate(true)).pipe(socket)
|
|
502
674
|
```
|
|
503
675
|
|
|
676
|
+
`opts` are same as [`Hypercore.createProtocolStream()`](#const-stream--hypercorecreateprotocolstreamisinitiator-opts--).
|
|
677
|
+
|
|
504
678
|
#### `const done = core.findingPeers()`
|
|
505
679
|
|
|
506
680
|
Create a hook that tells Hypercore you are finding peers for this core in the background. Call `done` when your current discovery iteration is done.
|
|
@@ -531,3 +705,56 @@ Emitted when a block is uploaded to a peer.
|
|
|
531
705
|
#### `core.on('download', index, byteLength, peer)`
|
|
532
706
|
|
|
533
707
|
Emitted when a block is downloaded from a peer.
|
|
708
|
+
|
|
709
|
+
#### `Hypercore.MAX_SUGGESTED_BLOCK_SIZE`
|
|
710
|
+
|
|
711
|
+
The constant for max size (15MB) for blocks appended to Hypercore. This max ensures blocks are replicated smoothly.
|
|
712
|
+
|
|
713
|
+
#### `const key = Hypercore.key(manifest, options = {})`
|
|
714
|
+
|
|
715
|
+
Returns the key for a given manifest.
|
|
716
|
+
|
|
717
|
+
`options` include:
|
|
718
|
+
|
|
719
|
+
```
|
|
720
|
+
{
|
|
721
|
+
compat: false, // Whether the manifest has a single singer whose public key is the key
|
|
722
|
+
version, // Manifest version if the manifest argument is the public key of a single singer
|
|
723
|
+
namespace // The signer namespace if the manifest argument is the public key of a single singer
|
|
724
|
+
}
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
#### `const dKey = Hypercore.discoveryKey(key)`
|
|
728
|
+
|
|
729
|
+
Returns the discovery key for the provided `key`.
|
|
730
|
+
|
|
731
|
+
#### `const bkey = Hypercore.blockEncryptionKey(key, encryptionKey)`
|
|
732
|
+
|
|
733
|
+
Returns a block encryption key derived from the `key` and `encryptionKey`.
|
|
734
|
+
|
|
735
|
+
#### `const mux = Hypercore.getProtocolMuxer(stream)`
|
|
736
|
+
|
|
737
|
+
Returns a protomux instance from the provided `stream` Hypercore protocol stream.
|
|
738
|
+
|
|
739
|
+
#### `const core = Hypercore.createCore(storage, opts)`
|
|
740
|
+
|
|
741
|
+
Returns the internal core using the `storage` and `opts` without creating a full Hypercore instance.
|
|
742
|
+
|
|
743
|
+
#### `const stream = Hypercore.createProtocolStream(isInitiator, opts = {})`
|
|
744
|
+
|
|
745
|
+
Create an encrypted noise stream with a protomux instance attached used for Hypercore's replication protocol.
|
|
746
|
+
|
|
747
|
+
`isInitiator` can be a framed stream, a protomux or a boolean for whether the stream should be the initiator in the noise handshake.
|
|
748
|
+
|
|
749
|
+
`opts` can include:
|
|
750
|
+
|
|
751
|
+
```
|
|
752
|
+
{
|
|
753
|
+
keepAlive: true, // Whether to keep the stream alive
|
|
754
|
+
ondiscoverykey: () => {}, // A handler for when a discovery key is set over the stream for corestore management
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
#### `const storage = Hypercore.defaultStorage(storage, opts = {})`
|
|
759
|
+
|
|
760
|
+
Returns a default hypercore storage. The `storage` argument can be a path where to create the `hypercore-storage` instance or an existing `hypercore-storage` instance. If an existing instance, it is immediately returned.
|
package/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const Info = require('./lib/info')
|
|
|
15
15
|
const Download = require('./lib/download')
|
|
16
16
|
const DefaultEncryption = require('./lib/default-encryption')
|
|
17
17
|
const caps = require('./lib/caps')
|
|
18
|
+
const Replicator = require('./lib/replicator')
|
|
18
19
|
const { manifestHash, createManifest } = require('./lib/verifier')
|
|
19
20
|
const { ReadStream, WriteStream, ByteStream } = require('./lib/streams')
|
|
20
21
|
const { MerkleTree } = require('./lib/merkle-tree')
|
|
@@ -203,6 +204,10 @@ class Hypercore extends EventEmitter {
|
|
|
203
204
|
return new CoreStorage(directory, opts)
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
static clearRequests (session, err) {
|
|
208
|
+
return Replicator.clearRequests(session, err)
|
|
209
|
+
}
|
|
210
|
+
|
|
206
211
|
snapshot (opts) {
|
|
207
212
|
return this.session({ ...opts, snapshot: true })
|
|
208
213
|
}
|
|
@@ -241,10 +246,10 @@ class Hypercore extends EventEmitter {
|
|
|
241
246
|
async setEncryptionKey (key, opts) {
|
|
242
247
|
if (!this.opened) await this.opening
|
|
243
248
|
const encryption = this._getEncryptionProvider({ key, block: !!(opts && opts.block) })
|
|
244
|
-
return this.setEncryption(encryption
|
|
249
|
+
return this.setEncryption(encryption)
|
|
245
250
|
}
|
|
246
251
|
|
|
247
|
-
async setEncryption (encryption
|
|
252
|
+
async setEncryption (encryption) {
|
|
248
253
|
if (!this.opened) await this.opening
|
|
249
254
|
|
|
250
255
|
if (encryption === null) {
|
|
@@ -516,7 +521,7 @@ class Hypercore extends EventEmitter {
|
|
|
516
521
|
replicate (isInitiator, opts = {}) {
|
|
517
522
|
// Only limitation here is that ondiscoverykey doesn't work atm when passing a muxer directly,
|
|
518
523
|
// because it doesn't really make a lot of sense.
|
|
519
|
-
if (Protomux.isProtomux(isInitiator)) return this._attachToMuxer(isInitiator
|
|
524
|
+
if (Protomux.isProtomux(isInitiator)) return this._attachToMuxer(isInitiator)
|
|
520
525
|
|
|
521
526
|
// if same stream is passed twice, ignore the 2nd one before we make sessions etc
|
|
522
527
|
if (isStream(isInitiator) && this._isAttached(isInitiator)) return isInitiator
|
|
@@ -883,8 +888,8 @@ class Hypercore extends EventEmitter {
|
|
|
883
888
|
return new ReadStream(this, opts)
|
|
884
889
|
}
|
|
885
890
|
|
|
886
|
-
createWriteStream (
|
|
887
|
-
return new WriteStream(this
|
|
891
|
+
createWriteStream () {
|
|
892
|
+
return new WriteStream(this)
|
|
888
893
|
}
|
|
889
894
|
|
|
890
895
|
createByteStream (opts) {
|
package/lib/replicator.js
CHANGED
|
@@ -57,7 +57,8 @@ const PRIORITY = {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
class Attachable {
|
|
60
|
-
constructor () {
|
|
60
|
+
constructor (replicator) {
|
|
61
|
+
this.replicator = replicator
|
|
61
62
|
this.resolved = false
|
|
62
63
|
this.processing = false
|
|
63
64
|
this.refs = []
|
|
@@ -147,8 +148,8 @@ class Attachable {
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
class BlockRequest extends Attachable {
|
|
150
|
-
constructor (tracker, index, priority) {
|
|
151
|
-
super()
|
|
151
|
+
constructor (replicator, tracker, index, priority) {
|
|
152
|
+
super(replicator)
|
|
152
153
|
|
|
153
154
|
this.index = index
|
|
154
155
|
this.priority = priority
|
|
@@ -171,8 +172,8 @@ class BlockRequest extends Attachable {
|
|
|
171
172
|
}
|
|
172
173
|
|
|
173
174
|
class RangeRequest extends Attachable {
|
|
174
|
-
constructor (ranges, start, end, linear, ifAvailable, blocks) {
|
|
175
|
-
super()
|
|
175
|
+
constructor (replicator, ranges, start, end, linear, ifAvailable, blocks) {
|
|
176
|
+
super(replicator)
|
|
176
177
|
|
|
177
178
|
this.start = start
|
|
178
179
|
this.end = end
|
|
@@ -200,12 +201,11 @@ class RangeRequest extends Attachable {
|
|
|
200
201
|
|
|
201
202
|
class UpgradeRequest extends Attachable {
|
|
202
203
|
constructor (replicator, fork, length) {
|
|
203
|
-
super()
|
|
204
|
+
super(replicator)
|
|
204
205
|
|
|
205
206
|
this.fork = fork
|
|
206
207
|
this.length = length
|
|
207
208
|
this.inflight = []
|
|
208
|
-
this.replicator = replicator
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
_unref () {
|
|
@@ -219,8 +219,8 @@ class UpgradeRequest extends Attachable {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
class SeekRequest extends Attachable {
|
|
222
|
-
constructor (seeks, seeker) {
|
|
223
|
-
super()
|
|
222
|
+
constructor (replicator, seeks, seeker) {
|
|
223
|
+
super(replicator)
|
|
224
224
|
|
|
225
225
|
this.seeker = seeker
|
|
226
226
|
this.inflight = []
|
|
@@ -278,7 +278,8 @@ class InflightTracker {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
class BlockTracker {
|
|
281
|
-
constructor () {
|
|
281
|
+
constructor (replicator) {
|
|
282
|
+
this._replicator = replicator
|
|
282
283
|
this._map = new Map()
|
|
283
284
|
}
|
|
284
285
|
|
|
@@ -302,7 +303,7 @@ class BlockTracker {
|
|
|
302
303
|
let b = this._map.get(index)
|
|
303
304
|
if (b) return b
|
|
304
305
|
|
|
305
|
-
b = new BlockRequest(this, index, priority)
|
|
306
|
+
b = new BlockRequest(this._replicator, this, index, priority)
|
|
306
307
|
this._map.set(index, b)
|
|
307
308
|
|
|
308
309
|
return b
|
|
@@ -1534,8 +1535,8 @@ module.exports = class Replicator {
|
|
|
1534
1535
|
|
|
1535
1536
|
this._attached = new Set()
|
|
1536
1537
|
this._inflight = new InflightTracker()
|
|
1537
|
-
this._blocks = new BlockTracker()
|
|
1538
|
-
this._hashes = new BlockTracker()
|
|
1538
|
+
this._blocks = new BlockTracker(this)
|
|
1539
|
+
this._hashes = new BlockTracker(this)
|
|
1539
1540
|
|
|
1540
1541
|
this._queued = []
|
|
1541
1542
|
|
|
@@ -1697,7 +1698,7 @@ module.exports = class Replicator {
|
|
|
1697
1698
|
}
|
|
1698
1699
|
|
|
1699
1700
|
addSeek (session, seeker) {
|
|
1700
|
-
const s = new SeekRequest(this._seeks, seeker)
|
|
1701
|
+
const s = new SeekRequest(this, this._seeks, seeker)
|
|
1701
1702
|
const ref = s.attach(session)
|
|
1702
1703
|
|
|
1703
1704
|
this._seeks.push(s)
|
|
@@ -1713,6 +1714,7 @@ module.exports = class Replicator {
|
|
|
1713
1714
|
}
|
|
1714
1715
|
|
|
1715
1716
|
const r = new RangeRequest(
|
|
1717
|
+
this,
|
|
1716
1718
|
this._ranges,
|
|
1717
1719
|
start,
|
|
1718
1720
|
length === -1 ? -1 : start + length,
|
|
@@ -1743,6 +1745,22 @@ module.exports = class Replicator {
|
|
|
1743
1745
|
ref.context.detach(ref, null)
|
|
1744
1746
|
}
|
|
1745
1747
|
|
|
1748
|
+
static clearRequests (session, err) {
|
|
1749
|
+
if (session.length === 0) return
|
|
1750
|
+
|
|
1751
|
+
const updated = new Set()
|
|
1752
|
+
|
|
1753
|
+
while (session.length > 0) {
|
|
1754
|
+
const ref = session[session.length - 1]
|
|
1755
|
+
ref.context.detach(ref, err)
|
|
1756
|
+
updated.add(ref.context.replicator)
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
for (const replicator of updated) {
|
|
1760
|
+
replicator.updateAll()
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1746
1764
|
clearRequests (session, err = null) {
|
|
1747
1765
|
let cleared = false
|
|
1748
1766
|
while (session.length > 0) {
|
package/lib/session-state.js
CHANGED
|
@@ -832,7 +832,7 @@ module.exports = class SessionState {
|
|
|
832
832
|
return { tree, flushed }
|
|
833
833
|
}
|
|
834
834
|
|
|
835
|
-
async commit (state, { signature, keyPair, length = state.length, treeLength = -1
|
|
835
|
+
async commit (state, { signature, keyPair, length = state.length, treeLength = -1 } = {}) {
|
|
836
836
|
assert(this.isDefault() || (this.parent && this.parent.isDefault()), 'Can only commit into default state')
|
|
837
837
|
|
|
838
838
|
let srcLocked = false
|