hypercore 10.0.0-alpha.2 → 10.0.0-alpha.23
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 +34 -2
- package/index.js +268 -127
- package/lib/bitfield.js +3 -2
- package/lib/block-encryption.js +68 -0
- package/lib/block-store.js +3 -1
- package/lib/core.js +6 -3
- package/lib/merkle-tree.js +62 -35
- package/lib/oplog.js +4 -3
- package/lib/protocol.js +69 -8
- package/lib/replicator.js +62 -16
- package/lib/streams.js +56 -0
- package/package.json +14 -7
- package/.github/workflows/test-node.yml +0 -24
- package/UPGRADE.md +0 -9
- package/examples/announce.js +0 -19
- package/examples/basic.js +0 -10
- package/examples/http.js +0 -123
- package/examples/lookup.js +0 -20
- package/test/basic.js +0 -78
- package/test/bitfield.js +0 -71
- package/test/core.js +0 -290
- package/test/encodings.js +0 -18
- package/test/extension.js +0 -71
- package/test/helpers/index.js +0 -23
- package/test/merkle-tree.js +0 -518
- package/test/mutex.js +0 -137
- package/test/oplog.js +0 -399
- package/test/preload.js +0 -72
- package/test/replicate.js +0 -296
- package/test/sessions.js +0 -173
- package/test/user-data.js +0 -47
package/lib/replicator.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const Protocol = require('./protocol')
|
|
2
2
|
const RemoteBitfield = require('./remote-bitfield')
|
|
3
3
|
const RandomIterator = require('random-array-iterator')
|
|
4
|
+
const b4a = require('b4a')
|
|
4
5
|
|
|
5
6
|
const PKG = require('../package.json')
|
|
6
7
|
const USER_AGENT = PKG.name + '/' + PKG.version + '@nodejs'
|
|
@@ -25,11 +26,12 @@ class InvertedPromise {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
class Request {
|
|
28
|
-
constructor (index, seek) {
|
|
29
|
+
constructor (index, seek, nodes) {
|
|
29
30
|
this.peer = null
|
|
30
31
|
this.index = index
|
|
31
32
|
this.seek = seek
|
|
32
33
|
this.value = seek === 0
|
|
34
|
+
this.nodes = nodes
|
|
33
35
|
this.promises = []
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -119,9 +121,10 @@ class Seek {
|
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
class Range {
|
|
122
|
-
constructor (start, end, linear) {
|
|
124
|
+
constructor (start, end, filter, linear) {
|
|
123
125
|
this.start = start
|
|
124
126
|
this.end = end
|
|
127
|
+
this.filter = filter
|
|
125
128
|
this.linear = !!linear
|
|
126
129
|
this.promise = null
|
|
127
130
|
this.done = false
|
|
@@ -144,7 +147,7 @@ class Range {
|
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
for (; this._start < this.end; this._start++) {
|
|
147
|
-
if (!bitfield.get(this._start)) return false
|
|
150
|
+
if (this.filter(this._start) && !bitfield.get(this._start)) return false
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
return true
|
|
@@ -278,7 +281,9 @@ class RequestPool {
|
|
|
278
281
|
|
|
279
282
|
_updateSeek (peer, seek) {
|
|
280
283
|
if (seek.request) return false
|
|
281
|
-
|
|
284
|
+
// We have to snapshot the nodes here now, due to the caching of the request...
|
|
285
|
+
const nodes = log2(seek.seeker.end - seek.seeker.start)
|
|
286
|
+
seek.request = this._requestRange(peer, seek.seeker.start, seek.seeker.end, seek.seeker.bytes, nodes)
|
|
282
287
|
return seek.request !== null
|
|
283
288
|
}
|
|
284
289
|
|
|
@@ -296,10 +301,13 @@ class RequestPool {
|
|
|
296
301
|
const end = range.end === -1 ? peer.state.length : range.end
|
|
297
302
|
if (end <= range._start) return false
|
|
298
303
|
|
|
299
|
-
if (range.linear) return !!this._requestRange(peer, range._start, end, 0)
|
|
304
|
+
if (range.linear) return !!this._requestRange(peer, range._start, end, 0, 0, range.filter)
|
|
300
305
|
|
|
301
306
|
const r = range._start + Math.floor(Math.random() * (end - range._start))
|
|
302
|
-
return !!(
|
|
307
|
+
return !!(
|
|
308
|
+
this._requestRange(peer, r, end, 0, 0, range.filter) ||
|
|
309
|
+
this._requestRange(peer, range._start, r, 0, 0, range.filter)
|
|
310
|
+
)
|
|
303
311
|
}
|
|
304
312
|
|
|
305
313
|
_updateUpgrade (peer) {
|
|
@@ -328,7 +336,7 @@ class RequestPool {
|
|
|
328
336
|
this.pendingUpgrade = null
|
|
329
337
|
}
|
|
330
338
|
|
|
331
|
-
_requestRange (peer, start, end, seek) {
|
|
339
|
+
_requestRange (peer, start, end, seek, nodes, filter = tautology) {
|
|
332
340
|
const remote = peer.state.bitfield
|
|
333
341
|
const local = this.core.bitfield
|
|
334
342
|
|
|
@@ -336,12 +344,12 @@ class RequestPool {
|
|
|
336
344
|
if (end === -1) end = peer.state.length
|
|
337
345
|
|
|
338
346
|
for (let i = start; i < end; i++) {
|
|
339
|
-
if (!remote.get(i) || local.get(i)) continue
|
|
347
|
+
if (!filter(i) || !remote.get(i) || local.get(i)) continue
|
|
340
348
|
// TODO: if this was a NO_VALUE request, retry if no blocks can be found elsewhere
|
|
341
349
|
if (this.requests.has(i)) continue
|
|
342
350
|
|
|
343
351
|
// TODO: if seeking and i >= core.length, let that takes precendance in the upgrade req
|
|
344
|
-
const req = new Request(i, i < this.core.tree.length ? seek : 0)
|
|
352
|
+
const req = new Request(i, i < this.core.tree.length ? seek : 0, nodes)
|
|
345
353
|
this.requests.set(i, req)
|
|
346
354
|
this.send(peer, req)
|
|
347
355
|
return req
|
|
@@ -390,16 +398,28 @@ class RequestPool {
|
|
|
390
398
|
|
|
391
399
|
if (data.block.index < this.core.tree.length || this.core.truncating > 0) {
|
|
392
400
|
try {
|
|
393
|
-
data.block.nodes = await this.core.tree.nodes(data.block.index * 2)
|
|
401
|
+
data.block.nodes = Math.max(req.nodes, await this.core.tree.nodes(data.block.index * 2))
|
|
394
402
|
} catch (err) {
|
|
395
403
|
console.error('TODO handle me:', err.stack)
|
|
396
404
|
}
|
|
397
405
|
}
|
|
398
406
|
|
|
407
|
+
if (peer.destroyed) {
|
|
408
|
+
req.peer = null
|
|
409
|
+
this.pending.push(req)
|
|
410
|
+
if (upgrading) {
|
|
411
|
+
this.upgrading.resolve()
|
|
412
|
+
this.upgrading = null
|
|
413
|
+
}
|
|
414
|
+
this.replicator.updateAll()
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
|
|
399
418
|
if (fork !== this.core.tree.fork || paused(peer, this.core.tree.fork) || this.core.truncating > 0) {
|
|
400
419
|
if (peer.state.inflight > 0) peer.state.inflight--
|
|
401
420
|
if (req.promises.length) { // someone is eagerly waiting for this request
|
|
402
421
|
req.peer = null // resend on some other peer
|
|
422
|
+
this.pending.push(req)
|
|
403
423
|
} else { // otherwise delete the request
|
|
404
424
|
this.requests.delete(req.index)
|
|
405
425
|
}
|
|
@@ -594,7 +614,7 @@ class RequestPool {
|
|
|
594
614
|
return e.createPromise()
|
|
595
615
|
}
|
|
596
616
|
|
|
597
|
-
const r = new Request(index, 0)
|
|
617
|
+
const r = new Request(index, 0, 0)
|
|
598
618
|
|
|
599
619
|
this.requests.set(index, r)
|
|
600
620
|
this.pending.push(r)
|
|
@@ -613,8 +633,9 @@ module.exports = class Replicator {
|
|
|
613
633
|
this.onupdate = onupdate
|
|
614
634
|
}
|
|
615
635
|
|
|
616
|
-
static createProtocol (noiseStream) {
|
|
636
|
+
static createProtocol (noiseStream, opts) {
|
|
617
637
|
return new Protocol(noiseStream, {
|
|
638
|
+
...opts,
|
|
618
639
|
protocolVersion: 0,
|
|
619
640
|
userAgent: USER_AGENT
|
|
620
641
|
})
|
|
@@ -662,8 +683,18 @@ module.exports = class Replicator {
|
|
|
662
683
|
return promise
|
|
663
684
|
}
|
|
664
685
|
|
|
665
|
-
static createRange (start, end, linear) {
|
|
666
|
-
|
|
686
|
+
static createRange (start, end, filter, linear) {
|
|
687
|
+
// createRange(start, end)
|
|
688
|
+
if (filter === undefined) {
|
|
689
|
+
filter = tautology
|
|
690
|
+
|
|
691
|
+
// createRange(start, end, linear)
|
|
692
|
+
} else if (typeof filter === 'boolean') {
|
|
693
|
+
linear = filter
|
|
694
|
+
filter = tautology
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return new Range(start, end, filter, linear)
|
|
667
698
|
}
|
|
668
699
|
|
|
669
700
|
addRange (range) {
|
|
@@ -750,8 +781,8 @@ module.exports = class Replicator {
|
|
|
750
781
|
|
|
751
782
|
onbitfield ({ start, bitfield }, peer) {
|
|
752
783
|
if (bitfield.length < 1024) {
|
|
753
|
-
const buf =
|
|
754
|
-
const bigger =
|
|
784
|
+
const buf = b4a.from(bitfield.buffer, bitfield.byteOffset, bitfield.byteLength)
|
|
785
|
+
const bigger = b4a.concat([buf, b4a.alloc(4096 - buf.length)])
|
|
755
786
|
bitfield = new Uint32Array(bigger.buffer, bigger.byteOffset, 1024)
|
|
756
787
|
}
|
|
757
788
|
peer.state.bitfield.pages.set(start, bitfield)
|
|
@@ -810,3 +841,18 @@ function pages (core) {
|
|
|
810
841
|
}
|
|
811
842
|
|
|
812
843
|
function noop () {}
|
|
844
|
+
|
|
845
|
+
function tautology () {
|
|
846
|
+
return true
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function log2 (n) {
|
|
850
|
+
let res = 1
|
|
851
|
+
|
|
852
|
+
while (n > 2) {
|
|
853
|
+
n /= 2
|
|
854
|
+
res++
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
return res
|
|
858
|
+
}
|
package/lib/streams.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const { Writable, Readable } = require('streamx')
|
|
2
|
+
|
|
3
|
+
class ReadStream extends Readable {
|
|
4
|
+
constructor (core, opts = {}) {
|
|
5
|
+
super()
|
|
6
|
+
|
|
7
|
+
this.core = core
|
|
8
|
+
this.start = opts.start || 0
|
|
9
|
+
this.end = typeof opts.end === 'number' ? opts.end : -1
|
|
10
|
+
this.snapshot = !opts.live && opts.snapshot !== false
|
|
11
|
+
this.live = !!opts.live
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_open (cb) {
|
|
15
|
+
this._openP().then(cb, cb)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_read (cb) {
|
|
19
|
+
this._readP().then(cb, cb)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async _openP () {
|
|
23
|
+
if (this.end === -1) await this.core.update()
|
|
24
|
+
else await this.core.ready()
|
|
25
|
+
if (this.snapshot && this.end === -1) this.end = this.core.length
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async _readP () {
|
|
29
|
+
const end = this.live ? -1 : (this.end === -1 ? this.core.length : this.end)
|
|
30
|
+
if (end >= 0 && this.start >= end) {
|
|
31
|
+
this.push(null)
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.push(await this.core.get(this.start++))
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.ReadStream = ReadStream
|
|
40
|
+
|
|
41
|
+
class WriteStream extends Writable {
|
|
42
|
+
constructor (core) {
|
|
43
|
+
super()
|
|
44
|
+
this.core = core
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_writev (batch, cb) {
|
|
48
|
+
this._writevP(batch).then(cb, cb)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async _writevP (batch) {
|
|
52
|
+
await this.core.append(batch)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.WriteStream = WriteStream
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "10.0.0-alpha.
|
|
3
|
+
"version": "10.0.0-alpha.23",
|
|
4
4
|
"description": "Hypercore 10",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,22 +27,29 @@
|
|
|
27
27
|
"url": "https://github.com/hypercore-protocol/hypercore/issues"
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/hypercore-protocol/hypercore#readme",
|
|
30
|
+
"files": [
|
|
31
|
+
"index.js",
|
|
32
|
+
"lib/**.js"
|
|
33
|
+
],
|
|
30
34
|
"dependencies": {
|
|
31
35
|
"@hyperswarm/secret-stream": "^5.0.0",
|
|
36
|
+
"b4a": "^1.1.0",
|
|
32
37
|
"big-sparse-array": "^1.0.2",
|
|
33
|
-
"codecs": "^
|
|
34
|
-
"compact-encoding": "^2.
|
|
38
|
+
"codecs": "^3.0.0",
|
|
39
|
+
"compact-encoding": "^2.5.0",
|
|
35
40
|
"crc32-universal": "^1.0.1",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
41
|
+
"events": "^3.3.0",
|
|
42
|
+
"flat-tree": "^1.9.0",
|
|
43
|
+
"hypercore-crypto": "^3.1.0",
|
|
38
44
|
"is-options": "^1.0.1",
|
|
39
45
|
"random-access-file": "^2.1.4",
|
|
40
46
|
"random-array-iterator": "^1.0.0",
|
|
41
47
|
"safety-catch": "^1.0.1",
|
|
42
|
-
"
|
|
48
|
+
"sodium-universal": "^3.0.4",
|
|
49
|
+
"xache": "^1.0.0"
|
|
43
50
|
},
|
|
44
51
|
"devDependencies": {
|
|
45
|
-
"brittle": "^
|
|
52
|
+
"brittle": "^2.0.0",
|
|
46
53
|
"hyperswarm": "next",
|
|
47
54
|
"random-access-memory": "^3.1.2",
|
|
48
55
|
"standard": "^16.0.3",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
name: Build Status
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- master
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- master
|
|
10
|
-
jobs:
|
|
11
|
-
build:
|
|
12
|
-
strategy:
|
|
13
|
-
matrix:
|
|
14
|
-
node-version: [14.x]
|
|
15
|
-
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
16
|
-
runs-on: ${{ matrix.os }}
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@v2
|
|
19
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
|
20
|
-
uses: actions/setup-node@v2
|
|
21
|
-
with:
|
|
22
|
-
node-version: ${{ matrix.node-version }}
|
|
23
|
-
- run: npm install
|
|
24
|
-
- run: npm test
|
package/UPGRADE.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Upgrade Notes
|
|
2
|
-
|
|
3
|
-
Notes for downstream developers who are upgrading their modules to new, breaking versions of hypercore.
|
|
4
|
-
|
|
5
|
-
## 9.0.0
|
|
6
|
-
|
|
7
|
-
- The format of signatures [has been changed](https://github.com/mafintosh/hypercore/issues/260). This is backwards-compatible (v9 can read v8 signatures), but forward-incompatible (v8 cannot read v9 signatures). If a v8 peer replicates with a v9 peer, it will emit a "REMOTE SIGNTURE INVALID" error on the replication stream.
|
|
8
|
-
- The encryption ([NOISE](https://github.com/emilbayes/noise-protocol)) handshake has been changed in an backwards- and forwards-incompatible way. v8 peers can not handshake with v9 peers, and vice-versa. A NOISE-related error is emitted on the replication stream.
|
|
9
|
-
- There is no way (yet) to detect whether a peer is running an incompatible version of hypercore at the replication level. One workaround for downstream developers is to include their own application-level handshake before piping to the replication stream, to communicate a "app protocol version" (maybe "v8" and "v9") and abort the connection if the peer is running an incompatible version.
|
package/examples/announce.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
const Hypercore = require('../')
|
|
2
|
-
const Hyperswarm = require('hyperswarm')
|
|
3
|
-
|
|
4
|
-
const core = new Hypercore('./source')
|
|
5
|
-
|
|
6
|
-
start()
|
|
7
|
-
|
|
8
|
-
async function start () {
|
|
9
|
-
await core.ready()
|
|
10
|
-
while (core.length < 1000) {
|
|
11
|
-
await core.append('block #' + core.length)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const swarm = new Hyperswarm()
|
|
15
|
-
swarm.on('connection', socket => core.replicate(socket))
|
|
16
|
-
swarm.join(core.discoveryKey, { server: true, client: false })
|
|
17
|
-
|
|
18
|
-
console.log('Core:', core.key.toString('hex'))
|
|
19
|
-
}
|
package/examples/basic.js
DELETED
package/examples/http.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
const Hypercore = require('../')
|
|
2
|
-
const streamx = require('streamx')
|
|
3
|
-
const replicator = require('@hyperswarm/replicator')
|
|
4
|
-
|
|
5
|
-
const core = new Hypercore('/tmp/movie')
|
|
6
|
-
|
|
7
|
-
if (process.argv[2] === 'bench') bench()
|
|
8
|
-
else if (process.argv[2]) importData()
|
|
9
|
-
else start()
|
|
10
|
-
|
|
11
|
-
class ByteStream extends streamx.Readable {
|
|
12
|
-
constructor (core, byteOffset, byteLength) {
|
|
13
|
-
super()
|
|
14
|
-
|
|
15
|
-
this.core = core
|
|
16
|
-
this.byteOffset = byteOffset
|
|
17
|
-
this.byteLength = byteLength
|
|
18
|
-
this.index = 0
|
|
19
|
-
this.range = null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async _read (cb) {
|
|
23
|
-
let data = null
|
|
24
|
-
|
|
25
|
-
if (!this.byteLength) {
|
|
26
|
-
this.push(null)
|
|
27
|
-
return cb(null)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (this.byteOffset > 0) {
|
|
31
|
-
const [block, byteOffset] = await core.seek(this.byteOffset)
|
|
32
|
-
this.byteOffset = 0
|
|
33
|
-
this.index = block + 1
|
|
34
|
-
this._select(this.index)
|
|
35
|
-
data = (await core.get(block)).slice(byteOffset)
|
|
36
|
-
} else {
|
|
37
|
-
this._select(this.index + 1)
|
|
38
|
-
data = await core.get(this.index++)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (data.length >= this.byteLength) {
|
|
42
|
-
data = data.slice(0, this.byteLength)
|
|
43
|
-
this.push(data)
|
|
44
|
-
this.push(null)
|
|
45
|
-
} else {
|
|
46
|
-
this.push(data)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
this.byteLength -= data.length
|
|
50
|
-
|
|
51
|
-
cb(null)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
_select (index) {
|
|
55
|
-
if (this.range !== null) this.range.destroy(null)
|
|
56
|
-
this.range = this.core.download({ start: index, end: index + 32, linear: true })
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
_destroy (cb) {
|
|
60
|
-
if (this.range) this.range.destroy(null)
|
|
61
|
-
cb(null)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async function bench () {
|
|
66
|
-
await core.ready()
|
|
67
|
-
|
|
68
|
-
console.time()
|
|
69
|
-
for (let i = 0; i < core.length; i++) {
|
|
70
|
-
await core.get(i)
|
|
71
|
-
}
|
|
72
|
-
console.timeEnd()
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function start () {
|
|
76
|
-
const http = require('http')
|
|
77
|
-
const parse = require('range-parser')
|
|
78
|
-
|
|
79
|
-
await core.ready()
|
|
80
|
-
|
|
81
|
-
core.on('download', (index) => console.log('Downloaded block #' + index))
|
|
82
|
-
core.download({ start: 0, end: 1 })
|
|
83
|
-
|
|
84
|
-
// hack until we update the replicator
|
|
85
|
-
core.ready = (cb) => cb(null)
|
|
86
|
-
|
|
87
|
-
replicator(core, {
|
|
88
|
-
discoveryKey: require('crypto').createHash('sha256').update('http').digest(),
|
|
89
|
-
announce: true,
|
|
90
|
-
lookup: true
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
http.createServer(function (req, res) {
|
|
94
|
-
res.setHeader('Content-Type', 'video/x-matroska')
|
|
95
|
-
res.setHeader('Accept-Ranges', 'bytes')
|
|
96
|
-
|
|
97
|
-
let s
|
|
98
|
-
|
|
99
|
-
if (req.headers.range) {
|
|
100
|
-
const range = parse(core.byteLength, req.headers.range)[0]
|
|
101
|
-
const byteLength = range.end - range.start + 1
|
|
102
|
-
res.statusCode = 206
|
|
103
|
-
res.setHeader('Content-Range', 'bytes ' + range.start + '-' + range.end + '/' + core.byteLength)
|
|
104
|
-
s = new ByteStream(core, range.start, byteLength)
|
|
105
|
-
} else {
|
|
106
|
-
s = new ByteStream(core, 0, core.byteLength)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
res.setHeader('Content-Length', s.byteLength)
|
|
110
|
-
s.pipe(res, () => {})
|
|
111
|
-
}).listen(10101)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async function importData () {
|
|
115
|
-
const fs = require('fs')
|
|
116
|
-
const rs = fs.createReadStream(process.argv[2])
|
|
117
|
-
|
|
118
|
-
for await (const data of rs) {
|
|
119
|
-
await core.append(data)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log('done!', core)
|
|
123
|
-
}
|
package/examples/lookup.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const Hypercore = require('../')
|
|
2
|
-
const Hyperswarm = require('hyperswarm')
|
|
3
|
-
|
|
4
|
-
const core = new Hypercore('./clone', process.argv[2])
|
|
5
|
-
|
|
6
|
-
start()
|
|
7
|
-
|
|
8
|
-
async function start () {
|
|
9
|
-
await core.ready()
|
|
10
|
-
|
|
11
|
-
const swarm = new Hyperswarm()
|
|
12
|
-
swarm.on('connection', socket => core.replicate(socket))
|
|
13
|
-
swarm.join(core.discoveryKey, { server: false, client: true })
|
|
14
|
-
|
|
15
|
-
console.log((await core.get(42)).toString())
|
|
16
|
-
console.log((await core.get(142)).toString())
|
|
17
|
-
console.log((await core.get(511)).toString())
|
|
18
|
-
console.log((await core.get(512)).toString())
|
|
19
|
-
console.log((await core.get(513)).toString())
|
|
20
|
-
}
|
package/test/basic.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
const test = require('brittle')
|
|
2
|
-
const ram = require('random-access-memory')
|
|
3
|
-
|
|
4
|
-
const Hypercore = require('../')
|
|
5
|
-
const { create } = require('./helpers')
|
|
6
|
-
|
|
7
|
-
test('basic', async function (t) {
|
|
8
|
-
const core = await create()
|
|
9
|
-
let appends = 0
|
|
10
|
-
|
|
11
|
-
t.is(core.length, 0)
|
|
12
|
-
t.is(core.byteLength, 0)
|
|
13
|
-
t.is(core.writable, true)
|
|
14
|
-
t.is(core.readable, true)
|
|
15
|
-
|
|
16
|
-
core.on('append', function () {
|
|
17
|
-
appends++
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
await core.append('hello')
|
|
21
|
-
await core.append('world')
|
|
22
|
-
|
|
23
|
-
t.is(core.length, 2)
|
|
24
|
-
t.is(core.byteLength, 10)
|
|
25
|
-
t.is(appends, 2)
|
|
26
|
-
|
|
27
|
-
t.end()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('session', async function (t) {
|
|
31
|
-
const core = await create()
|
|
32
|
-
|
|
33
|
-
const session = core.session()
|
|
34
|
-
|
|
35
|
-
await session.append('test')
|
|
36
|
-
t.alike(await core.get(0), Buffer.from('test'))
|
|
37
|
-
t.alike(await session.get(0), Buffer.from('test'))
|
|
38
|
-
t.end()
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('close', async function (t) {
|
|
42
|
-
const core = await create()
|
|
43
|
-
await core.append('hello world')
|
|
44
|
-
|
|
45
|
-
await core.close()
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
await core.get(0)
|
|
49
|
-
t.fail('core should be closed')
|
|
50
|
-
} catch {
|
|
51
|
-
t.pass('get threw correctly when core was closed')
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('close multiple', async function (t) {
|
|
56
|
-
const core = await create()
|
|
57
|
-
await core.append('hello world')
|
|
58
|
-
|
|
59
|
-
const ev = t.test('events')
|
|
60
|
-
|
|
61
|
-
ev.plan(4)
|
|
62
|
-
|
|
63
|
-
let i = 0
|
|
64
|
-
|
|
65
|
-
core.on('close', () => ev.is(i++, 0, 'on close'))
|
|
66
|
-
core.close().then(() => ev.is(i++, 1, 'first close'))
|
|
67
|
-
core.close().then(() => ev.is(i++, 2, 'second close'))
|
|
68
|
-
core.close().then(() => ev.is(i++, 3, 'third close'))
|
|
69
|
-
|
|
70
|
-
await ev
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
test('storage options', async function (t) {
|
|
74
|
-
const core = new Hypercore({ storage: ram })
|
|
75
|
-
await core.append('hello')
|
|
76
|
-
t.alike(await core.get(0), Buffer.from('hello'))
|
|
77
|
-
t.end()
|
|
78
|
-
})
|
package/test/bitfield.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
const test = require('brittle')
|
|
2
|
-
const ram = require('random-access-memory')
|
|
3
|
-
const Bitfield = require('../lib/bitfield')
|
|
4
|
-
|
|
5
|
-
test('bitfield - set and get', async function (t) {
|
|
6
|
-
const b = await Bitfield.open(ram())
|
|
7
|
-
|
|
8
|
-
t.absent(b.get(42))
|
|
9
|
-
b.set(42, true)
|
|
10
|
-
t.ok(b.get(42))
|
|
11
|
-
|
|
12
|
-
// bigger offsets
|
|
13
|
-
t.absent(b.get(42000000))
|
|
14
|
-
b.set(42000000, true)
|
|
15
|
-
t.ok(b.get(42000000))
|
|
16
|
-
|
|
17
|
-
b.set(42000000, false)
|
|
18
|
-
t.absent(b.get(42000000))
|
|
19
|
-
|
|
20
|
-
await b.flush()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('bitfield - random set and gets', async function (t) {
|
|
24
|
-
const b = await Bitfield.open(ram())
|
|
25
|
-
const set = new Set()
|
|
26
|
-
|
|
27
|
-
for (let i = 0; i < 200; i++) {
|
|
28
|
-
const idx = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
29
|
-
b.set(idx, true)
|
|
30
|
-
set.add(idx)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (let i = 0; i < 500; i++) {
|
|
34
|
-
const idx = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)
|
|
35
|
-
const expected = set.has(idx)
|
|
36
|
-
const val = b.get(idx)
|
|
37
|
-
if (val !== expected) {
|
|
38
|
-
t.fail('expected ' + expected + ' but got ' + val + ' at ' + idx)
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
for (const idx of set) {
|
|
44
|
-
const val = b.get(idx)
|
|
45
|
-
if (val !== true) {
|
|
46
|
-
t.fail('expected true but got ' + val + ' at ' + idx)
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
t.pass('all random set and gets pass')
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('bitfield - reload', async function (t) {
|
|
55
|
-
const s = ram()
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
const b = await Bitfield.open(s)
|
|
59
|
-
b.set(142, true)
|
|
60
|
-
b.set(40000, true)
|
|
61
|
-
b.set(1424242424, true)
|
|
62
|
-
await b.flush()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
const b = await Bitfield.open(s)
|
|
67
|
-
t.ok(b.get(142))
|
|
68
|
-
t.ok(b.get(40000))
|
|
69
|
-
t.ok(b.get(1424242424))
|
|
70
|
-
}
|
|
71
|
-
})
|