hypercore 9.11.0 → 10.0.0-alpha.10
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/.github/workflows/test-node.yml +3 -4
- package/README.md +123 -409
- package/__snapshots__/test/storage.js.snapshot.cjs +15 -0
- package/examples/announce.js +19 -0
- package/examples/basic.js +10 -0
- package/examples/http.js +123 -0
- package/examples/lookup.js +20 -0
- package/index.js +362 -1597
- package/lib/bitfield.js +113 -285
- package/lib/block-encryption.js +68 -0
- package/lib/block-store.js +58 -0
- package/lib/core.js +468 -0
- package/lib/extensions.js +76 -0
- package/lib/merkle-tree.js +1110 -0
- package/lib/messages.js +571 -0
- package/lib/mutex.js +39 -0
- package/lib/oplog.js +224 -0
- package/lib/protocol.js +525 -0
- package/lib/random-iterator.js +46 -0
- package/lib/remote-bitfield.js +24 -0
- package/lib/replicator.js +857 -0
- package/package.json +44 -45
- package/test/basic.js +59 -471
- package/test/bitfield.js +48 -133
- package/test/core.js +290 -0
- package/test/encodings.js +18 -0
- package/test/encryption.js +123 -0
- package/test/extension.js +71 -0
- package/test/helpers/index.js +23 -0
- package/test/merkle-tree.js +518 -0
- package/test/mutex.js +137 -0
- package/test/oplog.js +399 -0
- package/test/preload.js +72 -0
- package/test/replicate.js +227 -824
- package/test/sessions.js +173 -0
- package/test/storage.js +31 -0
- package/test/user-data.js +47 -0
- package/bench/all.sh +0 -65
- package/bench/copy-64kb-blocks.js +0 -51
- package/bench/helpers/read-throttled.js +0 -27
- package/bench/helpers/read.js +0 -47
- package/bench/helpers/write.js +0 -29
- package/bench/read-16kb-blocks-proof-throttled.js +0 -1
- package/bench/read-16kb-blocks-proof.js +0 -1
- package/bench/read-16kb-blocks-throttled.js +0 -1
- package/bench/read-16kb-blocks.js +0 -1
- package/bench/read-512b-blocks.js +0 -1
- package/bench/read-64kb-blocks-linear-batch.js +0 -18
- package/bench/read-64kb-blocks-linear.js +0 -18
- package/bench/read-64kb-blocks-proof.js +0 -1
- package/bench/read-64kb-blocks.js +0 -1
- package/bench/replicate-16kb-blocks.js +0 -19
- package/bench/replicate-64kb-blocks.js +0 -19
- package/bench/write-16kb-blocks.js +0 -1
- package/bench/write-512b-blocks.js +0 -1
- package/bench/write-64kb-blocks-static.js +0 -1
- package/bench/write-64kb-blocks.js +0 -1
- package/example.js +0 -23
- package/lib/cache.js +0 -26
- package/lib/crypto.js +0 -5
- package/lib/replicate.js +0 -829
- package/lib/safe-buffer-equals.js +0 -6
- package/lib/storage.js +0 -421
- package/lib/tree-index.js +0 -183
- package/test/ack.js +0 -306
- package/test/audit.js +0 -36
- package/test/cache.js +0 -93
- package/test/compat.js +0 -209
- package/test/copy.js +0 -377
- package/test/default-storage.js +0 -51
- package/test/extensions.js +0 -137
- package/test/get.js +0 -64
- package/test/head.js +0 -65
- package/test/helpers/create-tracking-ram.js +0 -27
- package/test/helpers/create.js +0 -6
- package/test/helpers/replicate.js +0 -4
- package/test/seek.js +0 -234
- package/test/selections.js +0 -95
- package/test/set-uploading-downloading.js +0 -91
- package/test/stats.js +0 -77
- package/test/streams.js +0 -162
- package/test/timeouts.js +0 -22
- package/test/tree-index.js +0 -841
- package/test/update.js +0 -156
- package/test/value-encoding.js +0 -52
package/README.md
CHANGED
|
@@ -1,68 +1,40 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Hypercore 10
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
NOTE: This is the _ALPHA_ version of the upcoming [Hypercore](https://github.com/hypercore-protocol/hypercore) 10 protocol upgrade.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Features all the power of Hypercore combined with
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
To learn more about how hypercore works on a technical level read the [Dat paper](https://github.com/datprotocol/whitepaper/blob/master/dat-paper.pdf).
|
|
14
|
-
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
* **Sparse replication.** Only download the data you are interested in.
|
|
18
|
-
* **Realtime.** Get the latest updates to the log fast and securely.
|
|
19
|
-
* **Performant.** Uses a simple flat file structure to maximize I/O performance.
|
|
20
|
-
* **Secure.** Uses signed merkle trees to verify log integrity in real time.
|
|
21
|
-
* **Browser support.** Simply pick a storage provider (like [random-access-memory](https://github.com/random-access-storage/random-access-memory)) that works in the browser
|
|
7
|
+
* Multiwriter support
|
|
8
|
+
* Fork recovery
|
|
9
|
+
* Promises
|
|
10
|
+
* Simplications and performance/scaling improvements
|
|
11
|
+
* Internal oplog design
|
|
22
12
|
|
|
23
|
-
|
|
13
|
+
## Install
|
|
24
14
|
|
|
25
|
-
|
|
15
|
+
Install from NPM using the next tag
|
|
26
16
|
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
var feed = hypercore('./my-first-dataset', {valueEncoding: 'utf-8'})
|
|
30
|
-
|
|
31
|
-
feed.append('hello')
|
|
32
|
-
feed.append('world', function (err) {
|
|
33
|
-
if (err) throw err
|
|
34
|
-
feed.get(0, console.log) // prints hello
|
|
35
|
-
feed.get(1, console.log) // prints world
|
|
36
|
-
})
|
|
17
|
+
```sh
|
|
18
|
+
npm install hypercore@next
|
|
37
19
|
```
|
|
38
20
|
|
|
39
|
-
To get find other modules that help with building data structures, P2P networks etc on top of Hypercore see the [companion modules](#Companion-modules) list at the bottom of this page.
|
|
40
|
-
|
|
41
|
-
## Terminology
|
|
42
|
-
|
|
43
|
-
- **feed**. This is what hypercores are: a data feed. Feeds are permanent data structures that can be shared on the dat network.
|
|
44
|
-
- **stream**. Streams are a tool in the code for reading or writing data. Streams are temporary and almost always returned by functions.
|
|
45
|
-
- **pipe**. Streams tend to either be readable (giving data) or writable (receiving data). If you connect a readable to a writable, that's called piping.
|
|
46
|
-
- **replication stream**. A stream returned by the `replicate()` function which can be piped to a peer. It is used to sync the peers' hypercore feeds.
|
|
47
|
-
- **swarming**. Swarming describes adding yourself to the network, finding peers, and sharing data with them. Piping a replication feed describes sharing the data with one peer.
|
|
48
|
-
|
|
49
21
|
## API
|
|
50
22
|
|
|
51
|
-
#### `
|
|
23
|
+
#### `const core = new Hypercore(storage, [key], [options])`
|
|
52
24
|
|
|
53
|
-
|
|
25
|
+
Make a new Hypercore instance.
|
|
54
26
|
|
|
55
|
-
`storage` should be set to a directory where you want to store the data and
|
|
27
|
+
`storage` should be set to a directory where you want to store the data and core metadata.
|
|
56
28
|
|
|
57
29
|
``` js
|
|
58
|
-
|
|
30
|
+
const core = new Hypercore('./directory') // store data in ./directory
|
|
59
31
|
```
|
|
60
32
|
|
|
61
|
-
Alternatively you can pass a function instead that is called with every filename
|
|
33
|
+
Alternatively you can pass a function instead that is called with every filename Hypercore needs to function and return your own [abstract-random-access](https://github.com/random-access-storage/abstract-random-access) instance that is used to store the data.
|
|
62
34
|
|
|
63
35
|
``` js
|
|
64
|
-
|
|
65
|
-
|
|
36
|
+
const ram = require('random-access-memory')
|
|
37
|
+
const core = new Hypercore((filename) => {
|
|
66
38
|
// filename will be one of: data, bitfield, tree, signatures, key, secret_key
|
|
67
39
|
// the data file will contain all your data concatenated.
|
|
68
40
|
|
|
@@ -71,58 +43,42 @@ var feed = hypercore(function (filename) {
|
|
|
71
43
|
})
|
|
72
44
|
```
|
|
73
45
|
|
|
74
|
-
Per default
|
|
46
|
+
Per default Hypercore uses [random-access-file](https://github.com/random-access-storage/random-access-file). This is also useful if you want to store specific files in other directories.
|
|
75
47
|
|
|
76
|
-
|
|
48
|
+
Hypercore will produce the following files:
|
|
49
|
+
|
|
50
|
+
* `oplog` - The internal truncating journal/oplog that tracks mutations, the public key and other metadata.
|
|
51
|
+
* `tree` - The Merkle Tree file.
|
|
52
|
+
* `bitfield` - The bitfield of which data blocks this core has.
|
|
53
|
+
* `data` - The raw data of each block.
|
|
54
|
+
|
|
55
|
+
Note that `tree`, `data`, and `bitfield` are normally heavily sparse files.
|
|
56
|
+
|
|
57
|
+
`key` can be set to a Hypercore public key. If you do not set this the public key will be loaded from storage. If no key exists a new key pair will be generated.
|
|
77
58
|
|
|
78
59
|
`options` include:
|
|
79
60
|
|
|
80
61
|
``` js
|
|
81
62
|
{
|
|
82
|
-
createIfMissing: true, // create a new
|
|
83
|
-
overwrite: false, // overwrite any old
|
|
63
|
+
createIfMissing: true, // create a new Hypercore key pair if none was present in storage
|
|
64
|
+
overwrite: false, // overwrite any old Hypercore that might already exist
|
|
84
65
|
valueEncoding: 'json' | 'utf-8' | 'binary', // defaults to binary
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
secretKey: buffer, // optionally pass the corresponding secret key yourself
|
|
88
|
-
storeSecretKey: true, // if false, will not save the secret key
|
|
89
|
-
storageCacheSize: 65536, // the # of entries to keep in the storage system's LRU cache (false or 0 to disable)
|
|
90
|
-
onwrite: (index, data, peer, cb) // optional hook called before data is written after being verified
|
|
91
|
-
// (remember to call cb() at the end of your handler)
|
|
92
|
-
stats: true // collect network-related statistics,
|
|
93
|
-
// Optionally use custom cryptography for signatures
|
|
94
|
-
crypto: {
|
|
95
|
-
sign (data, secretKey, cb(err, signature)),
|
|
96
|
-
verify (signature, data, key, cb(err, valid))
|
|
97
|
-
}
|
|
98
|
-
noiseKeyPair: { publicKey, secretKey } // set a static key pair to use for Noise authentication when replicating
|
|
66
|
+
keyPair: kp, // optionally pass the public key and secret key as a key pair
|
|
67
|
+
encryptionKey: k // optionally pass an encryption key to enable block encryption
|
|
99
68
|
}
|
|
100
69
|
```
|
|
101
70
|
|
|
102
|
-
You can also set valueEncoding to any [abstract-encoding](https://github.com/mafintosh/abstract-encoding) instance.
|
|
103
|
-
|
|
104
|
-
__Note:__ The `[key]` and `secretKey` are _Node.js_ buffer instances, not browser-based ArrayBuffer instances. When creating hypercores in browser, if you pass an ArrayBuffer instance, you will get an error similar to `key must be at least 16, was given undefined`. Instead, create a Node.js Buffer instance using [Feross‘s](https://github.com/feross) [buffer](https://github.com/feross/buffer) module (`npm install buffer`). e.g.,
|
|
105
|
-
|
|
106
|
-
```javascript
|
|
107
|
-
const storage = someRandomAccessStorage
|
|
108
|
-
const myPublicKey = someUint8Array
|
|
109
|
-
|
|
110
|
-
const Buffer = require('buffer').Buffer
|
|
111
|
-
const hypercorePublicKeyBuffer = Buffer.from(myPublicKey.buffer)
|
|
112
|
-
|
|
113
|
-
const hypercore = hypercore(storage, hypercorePublicKeyBuffer)
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
#### `feed.append(data, [callback])`
|
|
71
|
+
You can also set valueEncoding to any [abstract-encoding](https://github.com/mafintosh/abstract-encoding) or [compact-encoding](https://github.com/compact-encoding) instance.
|
|
117
72
|
|
|
118
|
-
|
|
73
|
+
#### `const seq = await core.append(block)`
|
|
119
74
|
|
|
120
|
-
|
|
75
|
+
Append a block of data (or an array of blocks) to the core.
|
|
76
|
+
Returns the seq the first block was stored at.
|
|
121
77
|
|
|
122
|
-
#### `const
|
|
78
|
+
#### `const block = await core.get(index, [options])`
|
|
123
79
|
|
|
124
80
|
Get a block of data.
|
|
125
|
-
If the data is not available locally this method will prioritize and wait for the data to be downloaded
|
|
81
|
+
If the data is not available locally this method will prioritize and wait for the data to be downloaded.
|
|
126
82
|
|
|
127
83
|
Options include
|
|
128
84
|
|
|
@@ -131,419 +87,177 @@ Options include
|
|
|
131
87
|
wait: true, // wait for index to be downloaded
|
|
132
88
|
onwait: () => {}, // hook that is called if the get is waiting for download
|
|
133
89
|
timeout: 0, // wait at max some milliseconds (0 means no timeout)
|
|
134
|
-
valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the
|
|
90
|
+
valueEncoding: 'json' | 'utf-8' | 'binary' // defaults to the core's valueEncoding
|
|
135
91
|
}
|
|
136
92
|
```
|
|
137
93
|
|
|
138
|
-
|
|
94
|
+
#### `await core.truncate(newLength, [forkId])`
|
|
139
95
|
|
|
140
|
-
|
|
96
|
+
Truncate the core to a smaller length.
|
|
141
97
|
|
|
142
|
-
|
|
98
|
+
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.
|
|
99
|
+
Note that the fork id should be monotonely incrementing.
|
|
143
100
|
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
wait: sameAsAbove,
|
|
147
|
-
timeout: sameAsAbove,
|
|
148
|
-
valueEncoding: sameAsAbove
|
|
149
|
-
}
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
#### `feed.cancel(getId)`
|
|
101
|
+
#### `const range = core.download([range])`
|
|
153
102
|
|
|
154
|
-
|
|
103
|
+
Download a range of data.
|
|
155
104
|
|
|
156
|
-
|
|
105
|
+
You can await when the range has been fully downloaded by doing:
|
|
157
106
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
Accepts the same `options` as `feed.get()`.
|
|
162
|
-
|
|
163
|
-
#### `const id = feed.download([range], [callback])`
|
|
107
|
+
```js
|
|
108
|
+
await range.downloaded()
|
|
109
|
+
```
|
|
164
110
|
|
|
165
|
-
Download a range of data. Callback is called when all data has been downloaded.
|
|
166
111
|
A range can have the following properties:
|
|
167
112
|
|
|
168
113
|
``` js
|
|
169
114
|
{
|
|
170
115
|
start: startIndex,
|
|
171
116
|
end: nonInclusiveEndIndex,
|
|
117
|
+
blocks: [index1, index2, ...],
|
|
172
118
|
linear: false // download range linearly and not randomly
|
|
173
119
|
}
|
|
174
120
|
```
|
|
175
121
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
If you have not enabled sparse mode (`sparse: true` in the feed constructor) then the entire
|
|
179
|
-
feed will be marked for download when the feed is created.
|
|
180
|
-
|
|
181
|
-
If you have an array of blocks you want to get downloaded you also also pass that
|
|
122
|
+
To download the full core continously (often referred to as non sparse mode) do
|
|
182
123
|
|
|
183
124
|
``` js
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
125
|
+
// Note that this will never be consider downloaded as the range
|
|
126
|
+
// will keep waiting for new blocks to be appended.
|
|
127
|
+
core.download({ start: 0, end: -1 })
|
|
187
128
|
```
|
|
188
129
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
Cancel a previous download request.
|
|
192
|
-
|
|
193
|
-
#### `feed.signature([index], callback)`
|
|
130
|
+
To downloaded a discrete range of blocks pass a list of indices.
|
|
194
131
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
Callback is called with `(err, signature)`.
|
|
198
|
-
The signature has the following properties:
|
|
199
|
-
``` js
|
|
200
|
-
{
|
|
201
|
-
index: lastSignedBlock,
|
|
202
|
-
signature: Buffer
|
|
203
|
-
}
|
|
132
|
+
```js
|
|
133
|
+
core.download({ blocks: [4, 9, 7] });
|
|
204
134
|
```
|
|
205
135
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
Verify a signature is correct for the data up to index, which must be the last signed
|
|
209
|
-
block associated with the signature.
|
|
210
|
-
|
|
211
|
-
Callback is called with `(err, success)` where success is true only if the signature is
|
|
212
|
-
correct.
|
|
213
|
-
|
|
214
|
-
#### `feed.rootHashes(index, callback)`
|
|
215
|
-
|
|
216
|
-
Retrieve the root *hashes* for given `index`.
|
|
136
|
+
To cancel downloading a range simply destroy the range instance.
|
|
217
137
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
index: location in the merkle tree of this root,
|
|
222
|
-
size: total bytes in children of this root,
|
|
223
|
-
hash: hash of the children of this root (32-byte buffer)
|
|
224
|
-
}
|
|
138
|
+
``` js
|
|
139
|
+
// will stop downloading now
|
|
140
|
+
range.destroy()
|
|
225
141
|
```
|
|
226
142
|
|
|
227
|
-
|
|
228
|
-
#### `var number = feed.downloaded([start], [end])`
|
|
229
|
-
|
|
230
|
-
Returns total number of downloaded blocks within range.
|
|
231
|
-
If `end` is not specified it will default to the total number of blocks.
|
|
232
|
-
If `start` is not specified it will default to 0.
|
|
233
|
-
|
|
234
|
-
#### `var bool = feed.has(index)`
|
|
235
|
-
|
|
236
|
-
Return true if a data block is available locally.
|
|
237
|
-
False otherwise.
|
|
238
|
-
|
|
239
|
-
#### `var bool = feed.has(start, end)`
|
|
240
|
-
Return true if all data blocks within a range are available locally.
|
|
241
|
-
False otherwise.
|
|
242
|
-
|
|
243
|
-
#### `feed.clear(start, [end], [callback])`
|
|
244
|
-
|
|
245
|
-
Clear a range of data from the local cache.
|
|
246
|
-
Will clear the data from the bitfield and make a call to the underlying storage provider to delete the byte range the range occupies.
|
|
247
|
-
|
|
248
|
-
`end` defaults to `start + 1`.
|
|
249
|
-
|
|
250
|
-
#### `feed.seek(byteOffset, callback)`
|
|
143
|
+
#### `const [index, relativeOffset] = await core.seek(byteOffset)`
|
|
251
144
|
|
|
252
145
|
Seek to a byte offset.
|
|
253
146
|
|
|
254
|
-
|
|
147
|
+
Returns `(index, relativeOffset)`, where `index` is the data block the byteOffset is contained in and `relativeOffset` is
|
|
255
148
|
the relative byte offset in the data block.
|
|
256
149
|
|
|
257
|
-
#### `
|
|
258
|
-
|
|
259
|
-
Wait for the feed to contain at least `minLength` elements.
|
|
260
|
-
If you do not provide `minLength` it will be set to current length + 1.
|
|
261
|
-
|
|
262
|
-
Does not download any data from peers except for a proof of the new feed length.
|
|
150
|
+
#### `const updated = await core.update()`
|
|
263
151
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
feed.update(function () {
|
|
267
|
-
console.log('length has increased', feed.length)
|
|
268
|
-
})
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
Per default update will wait until a peer arrives and the update can be performed.
|
|
272
|
-
If you only wanna check if any of the current peers you are connected to can
|
|
273
|
-
update you (and return an error otherwise if you use the `ifAvailable` option)
|
|
152
|
+
Wait for the core to try and find a signed update to it's length.
|
|
153
|
+
Does not download any data from peers except for a proof of the new core length.
|
|
274
154
|
|
|
275
155
|
``` js
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
})
|
|
156
|
+
const updated = await core.update()
|
|
157
|
+
console.log('core was updated?', updated, 'length is', core.length)
|
|
279
158
|
```
|
|
280
159
|
|
|
281
|
-
#### `
|
|
160
|
+
#### `await core.close()`
|
|
282
161
|
|
|
283
|
-
|
|
162
|
+
Fully close this core.
|
|
284
163
|
|
|
285
|
-
#### `
|
|
164
|
+
#### `core.on('close')`
|
|
286
165
|
|
|
287
|
-
|
|
166
|
+
Emitted when then core has been fully closed.
|
|
288
167
|
|
|
289
|
-
#### `
|
|
168
|
+
#### `await core.ready()`
|
|
290
169
|
|
|
291
|
-
|
|
170
|
+
Wait for the core to fully open.
|
|
292
171
|
|
|
293
|
-
|
|
172
|
+
After this has called `core.length` and other properties have been set.
|
|
294
173
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
start: 0, // read from this index
|
|
298
|
-
end: feed.length, // read until this index
|
|
299
|
-
snapshot: true, // if set to false it will update `end` to `feed.length` on every read
|
|
300
|
-
tail: false, // sets `start` to `feed.length`
|
|
301
|
-
live: false, // set to true to keep reading forever
|
|
302
|
-
timeout: 0, // timeout for each data event (0 means no timeout)
|
|
303
|
-
wait: true, // wait for data to be downloaded
|
|
304
|
-
batch: 1 // amount of messages to read in batch, increasing it (e.g. 100) can improve the performance reading
|
|
305
|
-
}
|
|
306
|
-
```
|
|
174
|
+
In general you do NOT need to wait for `ready`, unless checking a synchronous property,
|
|
175
|
+
as all internals await this themself.
|
|
307
176
|
|
|
308
|
-
#### `
|
|
177
|
+
#### `core.on('ready')`
|
|
309
178
|
|
|
310
|
-
|
|
311
|
-
Options include:
|
|
179
|
+
Emitted after the core has initially opened all it's internal state.
|
|
312
180
|
|
|
313
|
-
|
|
314
|
-
{
|
|
315
|
-
maxBlockSize: Infinity // set this to auto chunk individual blocks if they are larger than this number
|
|
316
|
-
}
|
|
317
|
-
```
|
|
181
|
+
#### `core.writable`
|
|
318
182
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
Create a replication stream. You should pipe this to another hypercore instance.
|
|
322
|
-
|
|
323
|
-
The `isInitiator` argument is a boolean indicating whether you are the iniatior of the connection (ie the client)
|
|
324
|
-
or if you are the passive part (ie the server).
|
|
325
|
-
|
|
326
|
-
If you are using a P2P swarm like [Hyperswarm](https://github.com/hyperswarm/hyperswarm) you can know this by checking if the swarm connection is a client socket or server socket. In Hyperswarm you can check that using [client property on the peer details object](https://github.com/hyperswarm/hyperswarm#swarmonconnection-socket-details--)
|
|
327
|
-
|
|
328
|
-
If you want to multiplex the replication over an existing hypercore replication stream you can pass
|
|
329
|
-
another stream instance instead of the `isInitiator` boolean.
|
|
330
|
-
|
|
331
|
-
``` js
|
|
332
|
-
// assuming we have two feeds, localFeed + remoteFeed, sharing the same key
|
|
333
|
-
// on a server
|
|
334
|
-
var net = require('net')
|
|
335
|
-
var server = net.createServer(function (socket) {
|
|
336
|
-
socket.pipe(remoteFeed.replicate(false)).pipe(socket)
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
// on a client
|
|
340
|
-
var socket = net.connect(...)
|
|
341
|
-
socket.pipe(localFeed.replicate(true)).pipe(socket)
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
Options include:
|
|
345
|
-
|
|
346
|
-
``` js
|
|
347
|
-
{
|
|
348
|
-
live: false, // keep replicating after all remote data has been downloaded?
|
|
349
|
-
ack: false, // set to true to get explicit acknowledgement when a peer has written a block
|
|
350
|
-
download: true, // download data from peers?
|
|
351
|
-
upload: true, // upload data to peers?
|
|
352
|
-
encrypted: true, // encrypt the data sent using the hypercore key pair
|
|
353
|
-
noise: true, // set to false to disable the NOISE handshake completely, and also disable the capability verification. works only together with encrypted = false.
|
|
354
|
-
keyPair: { publicKey, secretKey }, // use this keypair for Noise authentication
|
|
355
|
-
onauthenticate (remotePublicKey, done) // hook that can be used to authenticate the remote peer.
|
|
356
|
-
// calling done with an error will disallow the peer from connecting to you.
|
|
357
|
-
onfeedauthenticate (feed, remotePublicKey, done) // hook similar to onauthenticate but called per feed to replicate over a stream of feeds.
|
|
358
|
-
// calling done with an error will disallow the peer from syncing this particular feed, but the
|
|
359
|
-
// stream will stay open.
|
|
360
|
-
}
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
When `ack` is `true`, you can listen on the replication `stream` for an `ack`
|
|
364
|
-
event:
|
|
365
|
-
|
|
366
|
-
``` js
|
|
367
|
-
var stream = feed.replicate({ ack: true })
|
|
368
|
-
stream.on('ack', function (ack) {
|
|
369
|
-
console.log(ack.start, ack.length)
|
|
370
|
-
})
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
#### `feed.close([callback])`
|
|
374
|
-
|
|
375
|
-
Fully close this feed.
|
|
376
|
-
|
|
377
|
-
Calls the callback with `(err)` when all storage has been closed.
|
|
378
|
-
|
|
379
|
-
#### `feed.destroyStorage([callback])`
|
|
380
|
-
|
|
381
|
-
Destroys all stored data and fully closes this feed.
|
|
382
|
-
|
|
383
|
-
Calls the callback with `(err)` when all storage has been deleted and closed.
|
|
384
|
-
|
|
385
|
-
#### `feed.audit([callback])`
|
|
386
|
-
|
|
387
|
-
Audit all data in the feed. Will check that all current data stored
|
|
388
|
-
matches the hashes in the merkle tree and clear the bitfield if not.
|
|
389
|
-
|
|
390
|
-
When done a report is passed to the callback that looks like this:
|
|
391
|
-
|
|
392
|
-
```js
|
|
393
|
-
{
|
|
394
|
-
valid: 10, // how many data blocks matches the hashes
|
|
395
|
-
invalid: 0, // how many did not
|
|
396
|
-
}
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
If a block does not match the hash it is cleared from the data bitfield.
|
|
400
|
-
|
|
401
|
-
#### `feed.writable`
|
|
402
|
-
|
|
403
|
-
Can we append to this feed?
|
|
183
|
+
Can we append to this core?
|
|
404
184
|
|
|
405
185
|
Populated after `ready` has been emitted. Will be `false` before the event.
|
|
406
186
|
|
|
407
|
-
#### `
|
|
187
|
+
#### `core.readable`
|
|
408
188
|
|
|
409
|
-
Can we read from this
|
|
189
|
+
Can we read from this core? After closing the core this will be false.
|
|
410
190
|
|
|
411
191
|
Populated after `ready` has been emitted. Will be `false` before the event.
|
|
412
192
|
|
|
413
|
-
#### `
|
|
193
|
+
#### `core.key`
|
|
414
194
|
|
|
415
|
-
Buffer containing the public key identifying this
|
|
195
|
+
Buffer containing the public key identifying this core.
|
|
416
196
|
|
|
417
197
|
Populated after `ready` has been emitted. Will be `null` before the event.
|
|
418
198
|
|
|
419
|
-
#### `
|
|
199
|
+
#### `core.discoveryKey`
|
|
420
200
|
|
|
421
|
-
Buffer containing a key derived from the
|
|
422
|
-
In contrast to `
|
|
201
|
+
Buffer containing a key derived from the core's public key.
|
|
202
|
+
In contrast to `core.key` this key does not allow you to verify the data but can be used to announce or look for peers that are sharing the same core, without leaking the core key.
|
|
423
203
|
|
|
424
204
|
Populated after `ready` has been emitted. Will be `null` before the event.
|
|
425
205
|
|
|
426
|
-
#### `
|
|
206
|
+
#### `core.encryptionKey`
|
|
427
207
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
208
|
+
Buffer containing the optional block encryption key of this core. Will be `null` unless block encryption is enabled.
|
|
431
209
|
|
|
432
|
-
#### `
|
|
210
|
+
#### `core.length`
|
|
433
211
|
|
|
434
|
-
How
|
|
212
|
+
How many blocks of data are available on this core?
|
|
435
213
|
|
|
436
214
|
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
437
215
|
|
|
438
|
-
#### `
|
|
216
|
+
#### `core.byteLength`
|
|
439
217
|
|
|
440
|
-
|
|
218
|
+
How much data is available on this core in bytes?
|
|
441
219
|
|
|
442
|
-
|
|
443
|
-
```js
|
|
444
|
-
{
|
|
445
|
-
totals: {
|
|
446
|
-
uploadedBytes: 100,
|
|
447
|
-
uploadedBlocks: 1,
|
|
448
|
-
downloadedBytes: 0,
|
|
449
|
-
downloadedBlocks: 0
|
|
450
|
-
},
|
|
451
|
-
peers: [
|
|
452
|
-
{
|
|
453
|
-
uploadedBytes: 100,
|
|
454
|
-
uploadedBlocks: 1,
|
|
455
|
-
downloadedBytes: 0,
|
|
456
|
-
downloadedBlocks: 0
|
|
457
|
-
},
|
|
458
|
-
...
|
|
459
|
-
]
|
|
460
|
-
}
|
|
461
|
-
```
|
|
220
|
+
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
462
221
|
|
|
463
|
-
|
|
222
|
+
#### `core.fork`
|
|
464
223
|
|
|
465
|
-
|
|
224
|
+
What is the current fork id of this core?
|
|
466
225
|
|
|
467
|
-
|
|
226
|
+
Populated after `ready` has been emitted. Will be `0` before the event.
|
|
468
227
|
|
|
469
|
-
#### `
|
|
228
|
+
#### `core.padding`
|
|
470
229
|
|
|
471
|
-
|
|
230
|
+
How much padding is applied to each block of this core? Will be `0` unless block encryption is enabled.
|
|
472
231
|
|
|
473
|
-
#### `
|
|
232
|
+
#### `const stream = core.replicate(isInitiatorOrReplicationStream)`
|
|
474
233
|
|
|
475
|
-
|
|
234
|
+
Create a replication stream. You should pipe this to another Hypercore instance.
|
|
476
235
|
|
|
477
|
-
|
|
236
|
+
The `isInitiator` argument is a boolean indicating whether you are the iniatior of the connection (ie the client)
|
|
237
|
+
or if you are the passive part (ie the server).
|
|
478
238
|
|
|
479
|
-
|
|
239
|
+
If you are using a P2P swarm like [Hyperswarm](https://github.com/hyperswarm/hyperswarm) you can know this by checking if the swarm connection is a client socket or server socket. In Hyperswarm you can check that using the [client property on the peer details object](https://github.com/hyperswarm/hyperswarm#swarmonconnection-socket-details--)
|
|
480
240
|
|
|
481
|
-
|
|
241
|
+
If you want to multiplex the replication over an existing Hypercore replication stream you can pass
|
|
242
|
+
another stream instance instead of the `isInitiator` boolean.
|
|
482
243
|
|
|
483
|
-
|
|
244
|
+
``` js
|
|
245
|
+
// assuming we have two cores, localCore + remoteCore, sharing the same key
|
|
246
|
+
// on a server
|
|
247
|
+
const net = require('net')
|
|
248
|
+
const server = net.createServer(function (socket) {
|
|
249
|
+
socket.pipe(remoteCore.replicate(false)).pipe(socket)
|
|
250
|
+
})
|
|
484
251
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
onmessage (message, peer) {
|
|
489
|
-
// called when a message is received from a peer
|
|
490
|
-
// will be decoded using the encoding you provide
|
|
491
|
-
},
|
|
492
|
-
onerror (err) {
|
|
493
|
-
// called in case of an decoding error
|
|
494
|
-
}
|
|
495
|
-
}
|
|
252
|
+
// on a client
|
|
253
|
+
const socket = net.connect(...)
|
|
254
|
+
socket.pipe(localCore.replicate(true)).pipe(socket)
|
|
496
255
|
```
|
|
497
256
|
|
|
498
|
-
#### `
|
|
499
|
-
|
|
500
|
-
Send an extension message to a specific peer.
|
|
501
|
-
|
|
502
|
-
#### `ext.broadcast(message)`
|
|
503
|
-
|
|
504
|
-
Send a message to every peer you are connected to.
|
|
505
|
-
|
|
506
|
-
#### `peer.publicKey`
|
|
507
|
-
|
|
508
|
-
Get the public key buffer for this peer. Useful for identifying a peer in the swarm.
|
|
509
|
-
|
|
510
|
-
#### `feed.on('ready')`
|
|
511
|
-
|
|
512
|
-
Emitted when the feed is ready and all properties have been populated.
|
|
513
|
-
|
|
514
|
-
#### `feed.on('error', err)`
|
|
515
|
-
|
|
516
|
-
Emitted when the feed experiences a critical error.
|
|
517
|
-
|
|
518
|
-
#### `feed.on('download', index, data)`
|
|
519
|
-
|
|
520
|
-
Emitted when a data block has been downloaded.
|
|
521
|
-
|
|
522
|
-
#### `feed.on('upload', index, data)`
|
|
523
|
-
|
|
524
|
-
Emitted when a data block is going to be uploaded.
|
|
525
|
-
|
|
526
|
-
#### `feed.on('append')`
|
|
527
|
-
|
|
528
|
-
Emitted when the feed has been appended to (i.e. has a new length / byteLength).
|
|
529
|
-
|
|
530
|
-
#### `feed.on('sync')`
|
|
531
|
-
|
|
532
|
-
Emitted every time ALL data from `0` to `feed.length` has been downloaded.
|
|
533
|
-
|
|
534
|
-
#### `feed.on('close')`
|
|
535
|
-
|
|
536
|
-
Emitted when the feed has been fully closed
|
|
537
|
-
|
|
538
|
-
## Companion modules
|
|
539
|
-
|
|
540
|
-
Hypercore works really well with a series of other modules. This in a non-exhaustive list of some of those:
|
|
257
|
+
#### `core.on('append')`
|
|
541
258
|
|
|
542
|
-
|
|
543
|
-
* [Hyperswarm replicator](https://github.com/hyperswarm/replicator) - Wanna share a single Hypercore without any hastle over a network?
|
|
544
|
-
* [Hyperdrive](https://github.com/hypercore-protocol/hyperdrive) - Filesystem abstraction built on Hypercores
|
|
545
|
-
* [Hypertrie](https://github.com/hypercore-protocol/hypertrie) - Scalable key/value store built on Hypercores
|
|
259
|
+
Emitted when the core has been appended to (i.e. has a new length / byteLength), either locally or remotely.
|
|
546
260
|
|
|
547
|
-
|
|
261
|
+
#### `core.on('truncate')`
|
|
548
262
|
|
|
549
|
-
|
|
263
|
+
Emitted when the core has been truncated, either locally or remotely.
|