@dxos/hypercore 0.1.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/LICENSE +21 -0
- package/README.md +4 -0
- package/dist/src/crypto.d.ts +13 -0
- package/dist/src/crypto.d.ts.map +1 -0
- package/dist/src/crypto.js +45 -0
- package/dist/src/crypto.js.map +1 -0
- package/dist/src/defaults.d.ts +18 -0
- package/dist/src/defaults.d.ts.map +1 -0
- package/dist/src/defaults.js +44 -0
- package/dist/src/defaults.js.map +1 -0
- package/dist/src/hypercore-factory.d.ts +23 -0
- package/dist/src/hypercore-factory.d.ts.map +1 -0
- package/dist/src/hypercore-factory.js +44 -0
- package/dist/src/hypercore-factory.js.map +1 -0
- package/dist/src/hypercore-factory.test.d.ts +2 -0
- package/dist/src/hypercore-factory.test.d.ts.map +1 -0
- package/dist/src/hypercore-factory.test.js +46 -0
- package/dist/src/hypercore-factory.test.js.map +1 -0
- package/dist/src/hypercore-protocol.test.d.ts +2 -0
- package/dist/src/hypercore-protocol.test.d.ts.map +1 -0
- package/dist/src/hypercore-protocol.test.js +191 -0
- package/dist/src/hypercore-protocol.test.js.map +1 -0
- package/dist/src/hypercore.test.d.ts +2 -0
- package/dist/src/hypercore.test.d.ts.map +1 -0
- package/dist/src/hypercore.test.js +79 -0
- package/dist/src/hypercore.test.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +24 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/iterator.d.ts +26 -0
- package/dist/src/iterator.d.ts.map +1 -0
- package/dist/src/iterator.js +37 -0
- package/dist/src/iterator.js.map +1 -0
- package/dist/src/iterator.test.d.ts +2 -0
- package/dist/src/iterator.test.d.ts.map +1 -0
- package/dist/src/iterator.test.js +61 -0
- package/dist/src/iterator.test.js.map +1 -0
- package/dist/src/multiplexer.d.ts +21 -0
- package/dist/src/multiplexer.d.ts.map +1 -0
- package/dist/src/multiplexer.js +103 -0
- package/dist/src/multiplexer.js.map +1 -0
- package/dist/src/multiplexer.test.d.ts +2 -0
- package/dist/src/multiplexer.test.d.ts.map +1 -0
- package/dist/src/multiplexer.test.js +142 -0
- package/dist/src/multiplexer.test.js.map +1 -0
- package/dist/src/replicate.test.d.ts +2 -0
- package/dist/src/replicate.test.d.ts.map +1 -0
- package/dist/src/replicate.test.js +197 -0
- package/dist/src/replicate.test.js.map +1 -0
- package/dist/src/streams.test.d.ts +2 -0
- package/dist/src/streams.test.d.ts.map +1 -0
- package/dist/src/streams.test.js +65 -0
- package/dist/src/streams.test.js.map +1 -0
- package/dist/src/testing.d.ts +11 -0
- package/dist/src/testing.d.ts.map +1 -0
- package/dist/src/testing.js +36 -0
- package/dist/src/testing.js.map +1 -0
- package/package.json +50 -0
- package/src/crypto.ts +46 -0
- package/src/defaults.ts +46 -0
- package/src/hypercore-factory.test.ts +53 -0
- package/src/hypercore-factory.ts +44 -0
- package/src/hypercore-protocol.test.ts +236 -0
- package/src/hypercore.test.ts +98 -0
- package/src/index.ts +8 -0
- package/src/iterator.test.ts +66 -0
- package/src/iterator.ts +35 -0
- package/src/multiplexer.test.ts +172 -0
- package/src/multiplexer.ts +122 -0
- package/src/replicate.test.ts +241 -0
- package/src/streams.test.ts +75 -0
- package/src/testing.ts +40 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2019 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const chai_1 = require("chai");
|
|
10
|
+
const faker_1 = __importDefault(require("faker"));
|
|
11
|
+
const async_1 = require("@dxos/async");
|
|
12
|
+
const crypto_1 = require("@dxos/crypto");
|
|
13
|
+
const log_1 = require("@dxos/log");
|
|
14
|
+
const hypercore_factory_1 = require("./hypercore-factory");
|
|
15
|
+
const iterator_1 = require("./iterator");
|
|
16
|
+
const testing_1 = require("./testing");
|
|
17
|
+
const noop = () => { };
|
|
18
|
+
describe('Replication', function () {
|
|
19
|
+
const factory1 = new hypercore_factory_1.HypercoreFactory();
|
|
20
|
+
const factory2 = new hypercore_factory_1.HypercoreFactory();
|
|
21
|
+
it('replicates feeds', async function () {
|
|
22
|
+
const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
|
|
23
|
+
const core1 = factory1.createFeed(publicKey, { secretKey });
|
|
24
|
+
const core2 = factory2.createFeed(publicKey);
|
|
25
|
+
// Open.
|
|
26
|
+
{
|
|
27
|
+
const [ready, done] = (0, async_1.latch)({ count: 2 });
|
|
28
|
+
core1.open(done);
|
|
29
|
+
core2.open(done);
|
|
30
|
+
await ready();
|
|
31
|
+
}
|
|
32
|
+
const numBlocks = 10;
|
|
33
|
+
// Sync.
|
|
34
|
+
{
|
|
35
|
+
const stream1 = core1.replicate(true);
|
|
36
|
+
const stream2 = core2.replicate(false);
|
|
37
|
+
const [streamsClosed, onClose] = (0, async_1.latch)({ count: 2 });
|
|
38
|
+
stream1.pipe(stream2, onClose).pipe(stream1, onClose);
|
|
39
|
+
(0, chai_1.expect)(core1.stats.peers).to.have.lengthOf(1);
|
|
40
|
+
(0, chai_1.expect)(core2.stats.peers).to.have.lengthOf(1);
|
|
41
|
+
// Wait for complete sync.
|
|
42
|
+
core2.on('sync', () => {
|
|
43
|
+
stream1.end();
|
|
44
|
+
stream2.end();
|
|
45
|
+
});
|
|
46
|
+
// Write.
|
|
47
|
+
for (let i = 0; i < numBlocks; i++) {
|
|
48
|
+
core1.append(`test-${i}`, noop);
|
|
49
|
+
}
|
|
50
|
+
await streamsClosed();
|
|
51
|
+
}
|
|
52
|
+
// Close.
|
|
53
|
+
{
|
|
54
|
+
const [closed, close] = (0, async_1.latch)({ count: 2 });
|
|
55
|
+
core1.close(close);
|
|
56
|
+
core1.close(close);
|
|
57
|
+
await closed();
|
|
58
|
+
}
|
|
59
|
+
(0, chai_1.expect)(core1.stats.totals.uploadedBlocks).to.eq(numBlocks);
|
|
60
|
+
(0, chai_1.expect)(core2.stats.totals.downloadedBlocks).to.eq(numBlocks);
|
|
61
|
+
});
|
|
62
|
+
it('replicates feeds in batches', async function () {
|
|
63
|
+
const numBlocks = 100;
|
|
64
|
+
// Replicating feeds must have the same public key.
|
|
65
|
+
const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
|
|
66
|
+
const core1 = factory1.createFeed(publicKey, { secretKey });
|
|
67
|
+
const core2 = factory2.createFeed(publicKey);
|
|
68
|
+
// Open.
|
|
69
|
+
{
|
|
70
|
+
const [ready, done] = (0, async_1.latch)({ count: 2 });
|
|
71
|
+
core1.open(done);
|
|
72
|
+
core2.open(done);
|
|
73
|
+
await ready();
|
|
74
|
+
}
|
|
75
|
+
const stream1 = core1.replicate(true);
|
|
76
|
+
const stream2 = core2.replicate(false);
|
|
77
|
+
// Start replication.
|
|
78
|
+
// NOTE: Replication won't start unless the public keys on both sides are the same.
|
|
79
|
+
const [streamsClosed, onClose] = (0, async_1.latch)({ count: 2 });
|
|
80
|
+
stream1.pipe(stream2, onClose).pipe(stream1, onClose);
|
|
81
|
+
(0, chai_1.expect)(core1.stats.peers).to.have.lengthOf(1);
|
|
82
|
+
(0, chai_1.expect)(core2.stats.peers).to.have.lengthOf(1);
|
|
83
|
+
// Replicate messages.
|
|
84
|
+
{
|
|
85
|
+
// Wait until all uploaded.
|
|
86
|
+
const [waitForDownloaded, incDownload] = (0, async_1.latch)({ count: numBlocks });
|
|
87
|
+
// Monitor uploads.
|
|
88
|
+
let uploaded = 0;
|
|
89
|
+
core1.on('upload', () => {
|
|
90
|
+
uploaded++;
|
|
91
|
+
(0, log_1.log)('up', { uploaded, length: core1.length }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 111 });
|
|
92
|
+
});
|
|
93
|
+
// Monitor downloads.
|
|
94
|
+
let downloaded = 0;
|
|
95
|
+
core2.on('download', (seq, data) => {
|
|
96
|
+
downloaded++;
|
|
97
|
+
const { id } = JSON.parse(data.toString());
|
|
98
|
+
(0, chai_1.expect)(id).to.eq(seq);
|
|
99
|
+
(0, log_1.log)('down', { downloaded, length: core2.length }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 120 });
|
|
100
|
+
(0, chai_1.expect)(downloaded).to.be.lessThanOrEqual(uploaded);
|
|
101
|
+
incDownload();
|
|
102
|
+
});
|
|
103
|
+
// Monitor sync points (multiple since delayed writes).
|
|
104
|
+
const sync = { started: 0, complete: 0 };
|
|
105
|
+
core2.on('sync', () => {
|
|
106
|
+
(0, log_1.log)('sync', { events: ++sync.started }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 128 });
|
|
107
|
+
core2.download();
|
|
108
|
+
});
|
|
109
|
+
// Write batch of messages with delay.
|
|
110
|
+
(0, testing_1.batch)((next, i, remaining) => {
|
|
111
|
+
const size = faker_1.default.datatype.number({
|
|
112
|
+
min: 1,
|
|
113
|
+
max: Math.min(10, remaining)
|
|
114
|
+
});
|
|
115
|
+
for (let j = 0; j < size; j++) {
|
|
116
|
+
core1.append(JSON.stringify((0, testing_1.createDataItem)(i + j)), noop);
|
|
117
|
+
}
|
|
118
|
+
// Random delay.
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
next(size);
|
|
121
|
+
}, faker_1.default.datatype.number({ min: 0, max: 100 }));
|
|
122
|
+
}, numBlocks);
|
|
123
|
+
// Done.
|
|
124
|
+
await waitForDownloaded();
|
|
125
|
+
(0, chai_1.expect)(uploaded).to.eq(downloaded);
|
|
126
|
+
}
|
|
127
|
+
// Close streams.
|
|
128
|
+
{
|
|
129
|
+
stream1.end();
|
|
130
|
+
stream2.end();
|
|
131
|
+
await streamsClosed();
|
|
132
|
+
(0, chai_1.expect)(stream1.destroyed).to.be.true;
|
|
133
|
+
(0, chai_1.expect)(stream2.destroyed).to.be.true;
|
|
134
|
+
}
|
|
135
|
+
// Close feeds.
|
|
136
|
+
{
|
|
137
|
+
await core1.close();
|
|
138
|
+
await core2.close();
|
|
139
|
+
(0, chai_1.expect)(core1.writable).to.be.false;
|
|
140
|
+
(0, chai_1.expect)(core1.stats.totals.uploadedBlocks).to.eq(numBlocks);
|
|
141
|
+
(0, chai_1.expect)(core2.stats.totals.downloadedBlocks).to.eq(numBlocks);
|
|
142
|
+
}
|
|
143
|
+
}).timeout(5000);
|
|
144
|
+
it('replicates feeds with read stream', async function () {
|
|
145
|
+
const numBlocks = 10;
|
|
146
|
+
const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
|
|
147
|
+
const core1 = factory1.createFeed(publicKey, { secretKey });
|
|
148
|
+
const core2 = factory2.createFeed(publicKey);
|
|
149
|
+
// Open.
|
|
150
|
+
{
|
|
151
|
+
const [ready, done] = (0, async_1.latch)({ count: 2 });
|
|
152
|
+
core1.open(done);
|
|
153
|
+
core2.open(done);
|
|
154
|
+
await ready();
|
|
155
|
+
}
|
|
156
|
+
(0, chai_1.expect)(core1.opened).to.be.true;
|
|
157
|
+
(0, chai_1.expect)(core2.opened).to.be.true;
|
|
158
|
+
const stream1 = core1.replicate(true, { live: true });
|
|
159
|
+
const stream2 = core2.replicate(false, { live: true });
|
|
160
|
+
const [done, onClose] = (0, async_1.latch)({ count: 2 });
|
|
161
|
+
// Start replication.
|
|
162
|
+
{
|
|
163
|
+
stream1.pipe(stream2, onClose).pipe(stream1, onClose);
|
|
164
|
+
(0, chai_1.expect)(core1.stats.peers).to.have.lengthOf(1);
|
|
165
|
+
(0, chai_1.expect)(core2.stats.peers).to.have.lengthOf(1);
|
|
166
|
+
let sync = 0;
|
|
167
|
+
core2.on('sync', () => {
|
|
168
|
+
(0, log_1.log)('sync', { events: ++sync }, { file: "packages/common/hypercore/src/replicate.test.ts", line: 206 });
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// Writer.
|
|
172
|
+
{
|
|
173
|
+
setTimeout(async () => {
|
|
174
|
+
for (const _ of Array.from(Array(numBlocks))) {
|
|
175
|
+
const block = {
|
|
176
|
+
text: faker_1.default.lorem.sentence()
|
|
177
|
+
};
|
|
178
|
+
core1.append(JSON.stringify(block), noop);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// Reader.
|
|
183
|
+
{
|
|
184
|
+
const [done, inc] = (0, async_1.latch)({ count: numBlocks });
|
|
185
|
+
setTimeout(async () => {
|
|
186
|
+
for await (const _ of (0, iterator_1.createReadable)(core2.createReadStream({ live: true }))) {
|
|
187
|
+
inc();
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
await done();
|
|
191
|
+
stream1.end();
|
|
192
|
+
stream2.end();
|
|
193
|
+
}
|
|
194
|
+
await done();
|
|
195
|
+
}).timeout(5000);
|
|
196
|
+
});
|
|
197
|
+
//# sourceMappingURL=replicate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replicate.test.js","sourceRoot":"","sources":["../../src/replicate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streams.test.d.ts","sourceRoot":"","sources":["../../src/streams.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2019 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const node_util_1 = __importDefault(require("node:util"));
|
|
10
|
+
const streamx_1 = require("streamx");
|
|
11
|
+
const async_1 = require("@dxos/async");
|
|
12
|
+
const crypto_1 = require("@dxos/crypto");
|
|
13
|
+
const log_1 = require("@dxos/log");
|
|
14
|
+
const hypercore_factory_1 = require("./hypercore-factory");
|
|
15
|
+
describe('Streams', function () {
|
|
16
|
+
it('reads from stream', async function () {
|
|
17
|
+
const factory = new hypercore_factory_1.HypercoreFactory();
|
|
18
|
+
const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
|
|
19
|
+
const core = factory.createFeed(publicKey, { secretKey });
|
|
20
|
+
const numBlocks = 10;
|
|
21
|
+
const [closed, setClosed] = (0, async_1.latch)();
|
|
22
|
+
const [processed, incProcessed] = (0, async_1.latch)({ count: numBlocks });
|
|
23
|
+
const stream = core.createReadStream({ live: true });
|
|
24
|
+
const consumer = stream.pipe(new streamx_1.Writable({
|
|
25
|
+
write: (data, next) => {
|
|
26
|
+
(0, log_1.log)('received', { data: String(data) }, { file: "packages/common/hypercore/src/streams.test.ts", line: 28 });
|
|
27
|
+
incProcessed();
|
|
28
|
+
next();
|
|
29
|
+
}
|
|
30
|
+
}));
|
|
31
|
+
{
|
|
32
|
+
const append = node_util_1.default.promisify(core.append.bind(core));
|
|
33
|
+
for (const i of Array.from(Array(numBlocks)).keys()) {
|
|
34
|
+
await append(`message-${i}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
await processed();
|
|
38
|
+
{
|
|
39
|
+
consumer.once('close', () => {
|
|
40
|
+
(0, log_1.log)('closed', {}, { file: "packages/common/hypercore/src/streams.test.ts", line: 46 });
|
|
41
|
+
setClosed();
|
|
42
|
+
});
|
|
43
|
+
consumer.destroy();
|
|
44
|
+
await closed();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
it('feed closed while stream is open', async function () {
|
|
48
|
+
const factory = new hypercore_factory_1.HypercoreFactory();
|
|
49
|
+
const { publicKey, secretKey } = (0, crypto_1.createKeyPair)();
|
|
50
|
+
const core = factory.createFeed(publicKey, { secretKey });
|
|
51
|
+
const [closed, setClosed] = (0, async_1.latch)({ count: 1 });
|
|
52
|
+
{
|
|
53
|
+
const stream = core.createReadStream({ live: true });
|
|
54
|
+
stream.once('close', () => {
|
|
55
|
+
(0, log_1.log)('closed', {}, { file: "packages/common/hypercore/src/streams.test.ts", line: 64 });
|
|
56
|
+
setClosed();
|
|
57
|
+
});
|
|
58
|
+
stream.destroy();
|
|
59
|
+
}
|
|
60
|
+
await closed();
|
|
61
|
+
const close = node_util_1.default.promisify(core.close.bind(core));
|
|
62
|
+
await close();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=streams.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streams.test.js","sourceRoot":"","sources":["../../src/streams.test.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;AAEF,0DAA6B;AAC7B,qCAAmC;AAEnC,uCAAoC;AACpC,yCAA6C;AAC7C,mCAAgC;AAEhC,2DAAuD;AAEvD,QAAQ,CAAC,SAAS,EAAE;IAClB,EAAE,CAAC,mBAAmB,EAAE,KAAK;QAC3B,MAAM,OAAO,GAAG,IAAI,oCAAgB,EAAU,CAAC;QAC/C,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAA,sBAAa,GAAE,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAE1D,MAAM,SAAS,GAAG,EAAE,CAAC;QACrB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,aAAK,GAAE,CAAC;QACpC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,IAAA,aAAK,EAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAa,MAAM,CAAC,IAAI,CACpC,IAAI,kBAAQ,CAAC;YACX,KAAK,EAAE,CAAC,IAAS,EAAE,IAAgB,EAAE,EAAE;gBACrC,IAAA,SAAG,EAAC,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,sEAAC,CAAC;gBACxC,YAAY,EAAE,CAAC;gBACf,IAAI,EAAE,CAAC;YACT,CAAC;SACF,CAAC,CACH,CAAC;QAEF;YACE,MAAM,MAAM,GAAG,mBAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YACtD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE;gBACnD,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;aAC9B;SACF;QAED,MAAM,SAAS,EAAE,CAAC;QAElB;YACE,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC1B,IAAA,SAAG,EAAC,QAAQ,0EAAC,CAAC;gBACd,SAAS,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,QAAQ,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,MAAM,EAAE,CAAC;SAChB;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK;QAC1C,MAAM,OAAO,GAAG,IAAI,oCAAgB,EAAU,CAAC;QAC/C,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAA,sBAAa,GAAE,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,aAAK,EAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAChD;YACE,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;gBACxB,IAAA,SAAG,EAAC,QAAQ,0EAAC,CAAC;gBACd,SAAS,EAAE,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,OAAO,EAAE,CAAC;SAClB;QACD,MAAM,MAAM,EAAE,CAAC;QAEf,MAAM,KAAK,GAAG,mBAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,MAAM,KAAK,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const noop: () => void;
|
|
2
|
+
export declare const py: (obj: any, fn: Function) => Function;
|
|
3
|
+
export declare type TestDataItem = {
|
|
4
|
+
id: number;
|
|
5
|
+
text: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const createDataItem: (n: number) => TestDataItem;
|
|
8
|
+
declare type BatchCallback = (next: (num: number) => void, index: number, remaining: number) => void;
|
|
9
|
+
export declare const batch: (cb: BatchCallback, total: number) => void;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/testing.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,IAAI,YAAW,CAAC;AAE7B,eAAO,MAAM,EAAE,QAAS,GAAG,MAAM,QAAQ,aAAiC,CAAC;AAG3E,oBAAY,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,eAAO,MAAM,cAAc,MAAO,MAAM,KAAG,YAGzC,CAAC;AAEH,aAAK,aAAa,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;AAG7F,eAAO,MAAM,KAAK,OAAQ,aAAa,SAAS,MAAM,SAiBrD,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Copyright 2019 DXOS.org
|
|
4
|
+
//
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.batch = exports.createDataItem = exports.py = exports.noop = void 0;
|
|
10
|
+
const faker_1 = __importDefault(require("faker"));
|
|
11
|
+
const node_util_1 = __importDefault(require("node:util"));
|
|
12
|
+
const noop = () => { };
|
|
13
|
+
exports.noop = noop;
|
|
14
|
+
const py = (obj, fn) => node_util_1.default.promisify(fn.bind(obj));
|
|
15
|
+
exports.py = py;
|
|
16
|
+
const createDataItem = (n) => ({
|
|
17
|
+
id: n,
|
|
18
|
+
text: faker_1.default.lorem.sentence()
|
|
19
|
+
});
|
|
20
|
+
exports.createDataItem = createDataItem;
|
|
21
|
+
// TODO(burdon): Factor out.
|
|
22
|
+
const batch = (cb, total) => {
|
|
23
|
+
let i = 0;
|
|
24
|
+
const f = () => {
|
|
25
|
+
const remaining = total - i;
|
|
26
|
+
cb((num = 1) => {
|
|
27
|
+
i += num;
|
|
28
|
+
if (i < total) {
|
|
29
|
+
f();
|
|
30
|
+
}
|
|
31
|
+
}, i, remaining);
|
|
32
|
+
};
|
|
33
|
+
f();
|
|
34
|
+
};
|
|
35
|
+
exports.batch = batch;
|
|
36
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/testing.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0BAA0B;AAC1B,EAAE;;;;;;AAEF,kDAA0B;AAC1B,0DAA6B;AAEtB,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;AAAhB,QAAA,IAAI,QAAY;AAEtB,MAAM,EAAE,GAAG,CAAC,GAAQ,EAAE,EAAY,EAAE,EAAE,CAAC,mBAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAA9D,QAAA,EAAE,MAA4D;AAKpE,MAAM,cAAc,GAAG,CAAC,CAAS,EAAgB,EAAE,CAAC,CAAC;IAC1D,EAAE,EAAE,CAAC;IACL,IAAI,EAAE,eAAK,CAAC,KAAK,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAHU,QAAA,cAAc,kBAGxB;AAIH,4BAA4B;AACrB,MAAM,KAAK,GAAG,CAAC,EAAiB,EAAE,KAAa,EAAE,EAAE;IACxD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,CAAC,GAAG,GAAG,EAAE;QACb,MAAM,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;QAC5B,EAAE,CACA,CAAC,GAAG,GAAG,CAAC,EAAE,EAAE;YACV,CAAC,IAAI,GAAG,CAAC;YACT,IAAI,CAAC,GAAG,KAAK,EAAE;gBACb,CAAC,EAAE,CAAC;aACL;QACH,CAAC,EACD,CAAC,EACD,SAAS,CACV,CAAC;IACJ,CAAC,CAAC;IAEF,CAAC,EAAE,CAAC;AACN,CAAC,CAAC;AAjBW,QAAA,KAAK,SAiBhB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dxos/hypercore",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Hypercore wrapper and utils.",
|
|
5
|
+
"homepage": "https://dxos.org",
|
|
6
|
+
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "DXOS.org",
|
|
9
|
+
"main": "./dist/src/index.js",
|
|
10
|
+
"browser": {
|
|
11
|
+
"node:assert": "assert",
|
|
12
|
+
"node:util": "util"
|
|
13
|
+
},
|
|
14
|
+
"types": "./dist/src/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@dxos/async": "0.1.0",
|
|
21
|
+
"@dxos/codec-protobuf": "0.1.0",
|
|
22
|
+
"@dxos/crypto": "0.1.0",
|
|
23
|
+
"@dxos/debug": "0.1.0",
|
|
24
|
+
"@dxos/keys": "0.1.0",
|
|
25
|
+
"@dxos/random-access-storage": "0.1.0",
|
|
26
|
+
"assert": "^2.0.0",
|
|
27
|
+
"hypercore": "^9.12.0",
|
|
28
|
+
"hypercore-protocol": "^8.0.7",
|
|
29
|
+
"readable-stream": "^3.6.0",
|
|
30
|
+
"streamx": "^2.12.5",
|
|
31
|
+
"util": "^0.12.4"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@dxos/log": "0.1.0",
|
|
35
|
+
"@dxos/util": "0.1.0",
|
|
36
|
+
"@types/debug": "^4.1.7",
|
|
37
|
+
"@types/faker": "^5.5.9",
|
|
38
|
+
"@types/randombytes": "^2.0.0",
|
|
39
|
+
"@types/readable-stream": "^2.3.9",
|
|
40
|
+
"debug": "^4.3.3",
|
|
41
|
+
"faker": "^5.5.3",
|
|
42
|
+
"random-access-memory": "^4.1.0"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"check": "true"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/src/crypto.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import assert from 'assert';
|
|
6
|
+
import { AbstractValueEncoding, Crypto } from 'hypercore';
|
|
7
|
+
import { callbackify } from 'node:util';
|
|
8
|
+
|
|
9
|
+
import { Codec } from '@dxos/codec-protobuf';
|
|
10
|
+
import { Signer, verifySignature } from '@dxos/crypto';
|
|
11
|
+
import { PublicKey } from '@dxos/keys';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create encoding (e.g., from protobuf codec).
|
|
15
|
+
*/
|
|
16
|
+
export const createCodecEncoding = <T>(codec: Codec<T>): AbstractValueEncoding<T> => ({
|
|
17
|
+
encode: (obj: T) => Buffer.from(codec.encode(obj)),
|
|
18
|
+
decode: (buffer: Buffer) => codec.decode(buffer)
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a custom hypercore crypto signer.
|
|
23
|
+
*/
|
|
24
|
+
// TODO(burdon): Create test without adding deps.
|
|
25
|
+
export const createCrypto = (signer: Signer, publicKey: PublicKey): Crypto => {
|
|
26
|
+
assert(signer);
|
|
27
|
+
assert(publicKey);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
sign: (message, secretKey, cb) => {
|
|
31
|
+
callbackify(signer.sign.bind(signer!))(publicKey, message, (err, result) => {
|
|
32
|
+
if (err) {
|
|
33
|
+
cb(err, null);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
cb(null, Buffer.from(result));
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
verify: async (message, signature, key, cb) => {
|
|
42
|
+
// NOTE: Uses the public key passed into function.
|
|
43
|
+
callbackify(verifySignature)(publicKey, message, signature, cb);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
package/src/defaults.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { HypercoreOptions, ReadStreamOptions, ReplicationOptions, WriteStreamOptions } from 'hypercore';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-feed--hypercorestorage-key-options
|
|
9
|
+
*/
|
|
10
|
+
export const defaultFeedOptions: HypercoreOptions = {
|
|
11
|
+
createIfMissing: true,
|
|
12
|
+
valueEncoding: 'binary'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-stream--feedcreatereadstreamoptions
|
|
17
|
+
*/
|
|
18
|
+
export const defaultReadStreamOptions: ReadStreamOptions = {
|
|
19
|
+
start: 0,
|
|
20
|
+
end: Infinity,
|
|
21
|
+
snapshot: true,
|
|
22
|
+
tail: false,
|
|
23
|
+
live: false,
|
|
24
|
+
timeout: 0,
|
|
25
|
+
wait: true,
|
|
26
|
+
batch: 1
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-stream--feedcreatewritestreamopts
|
|
31
|
+
*/
|
|
32
|
+
export const defaultWriteStreamOptions: WriteStreamOptions = {
|
|
33
|
+
maxBlockSize: Infinity
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* https://github.com/hypercore-protocol/hypercore/tree/v9.12.0#var-stream--feedreplicateisinitiator-options
|
|
38
|
+
*/
|
|
39
|
+
export const defaultReplicateOptions: ReplicationOptions = {
|
|
40
|
+
live: false,
|
|
41
|
+
ack: false,
|
|
42
|
+
download: true,
|
|
43
|
+
upload: true,
|
|
44
|
+
encrypted: true,
|
|
45
|
+
noise: true
|
|
46
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2019 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
import faker from 'faker';
|
|
7
|
+
|
|
8
|
+
import { createKeyPair } from '@dxos/crypto';
|
|
9
|
+
|
|
10
|
+
import { HypercoreFactory } from './hypercore-factory';
|
|
11
|
+
import { createDataItem, py } from './testing';
|
|
12
|
+
|
|
13
|
+
describe('HypercoreFactory', function () {
|
|
14
|
+
it('appends to, and read from, multiple feeds', async function () {
|
|
15
|
+
const factory = new HypercoreFactory();
|
|
16
|
+
|
|
17
|
+
const numFeeds = 10;
|
|
18
|
+
const numBlocks = 100;
|
|
19
|
+
|
|
20
|
+
// Create feeds.
|
|
21
|
+
const feeds = await Promise.all(
|
|
22
|
+
Array.from({ length: numFeeds }).map(async () => {
|
|
23
|
+
const { publicKey, secretKey } = createKeyPair();
|
|
24
|
+
return await factory.openFeed(publicKey, { secretKey });
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Write data.
|
|
29
|
+
{
|
|
30
|
+
const data = Array.from({ length: numBlocks }).map((_, i) => createDataItem(i));
|
|
31
|
+
for await (const datum of data) {
|
|
32
|
+
const feed = faker.random.arrayElement(feeds);
|
|
33
|
+
await py(feed, feed.append)(Buffer.from(JSON.stringify(datum)));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Test.
|
|
38
|
+
{
|
|
39
|
+
const total = feeds.reduce((result, feed) => result + feed.length, 0);
|
|
40
|
+
expect(total).to.eq(numBlocks);
|
|
41
|
+
|
|
42
|
+
const feed = faker.random.arrayElement(feeds);
|
|
43
|
+
const block1 = await py(feed, feed.head)();
|
|
44
|
+
const block2 = await py(feed, feed.get)(feed.length - 1);
|
|
45
|
+
expect(block1.toString()).to.eq(block2.toString());
|
|
46
|
+
|
|
47
|
+
const blocks = await py(feed, feed.getBatch)(0, feed.length);
|
|
48
|
+
expect(blocks.length).to.eq(feed.length);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await Promise.all(feeds.map((feed) => feed.close()));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import assert from 'assert';
|
|
6
|
+
import hypercore from 'hypercore';
|
|
7
|
+
import type { Hypercore, HypercoreOptions } from 'hypercore';
|
|
8
|
+
|
|
9
|
+
import { createStorage, Directory, StorageType } from '@dxos/random-access-storage';
|
|
10
|
+
|
|
11
|
+
import { py } from './testing';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates feeds with default properties.
|
|
15
|
+
*/
|
|
16
|
+
export class HypercoreFactory<T> {
|
|
17
|
+
// prettier-ignore
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly _root: Directory = createStorage({ type: StorageType.RAM }).createDirectory(),
|
|
20
|
+
private readonly _options?: HypercoreOptions
|
|
21
|
+
) {
|
|
22
|
+
assert(this._root);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a feed using a storage factory prefixed with the feed's key.
|
|
27
|
+
* NOTE: We have to use our `random-access-storage` implementation since the native ones
|
|
28
|
+
* do not behave uniformly across platforms.
|
|
29
|
+
*/
|
|
30
|
+
createFeed(publicKey: Buffer, options?: HypercoreOptions): Hypercore<T> {
|
|
31
|
+
const directory = this._root.createDirectory(publicKey.toString());
|
|
32
|
+
const storage = (filename: string) => directory.getOrCreateFile(filename).native;
|
|
33
|
+
return hypercore(storage, publicKey, Object.assign({}, this._options, options));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Creates and opens a feed.
|
|
38
|
+
*/
|
|
39
|
+
async openFeed(publicKey: Buffer, options?: HypercoreOptions): Promise<Hypercore<T>> {
|
|
40
|
+
const feed = this.createFeed(publicKey, options);
|
|
41
|
+
await py(feed, feed.open)(); // TODO(burdon): Sometimes strange bug if done inside function.
|
|
42
|
+
return feed;
|
|
43
|
+
}
|
|
44
|
+
}
|