@dxos/feed-store 2.33.5-dev.ea3876ba → 2.33.5-dev.fee8f5fe
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/dist/src/benchmark.js +22 -26
- package/dist/src/benchmark.js.map +1 -1
- package/dist/src/create-batch-stream.d.ts +1 -1
- package/dist/src/create-batch-stream.d.ts.map +1 -1
- package/dist/src/create-batch-stream.js +14 -14
- package/dist/src/create-batch-stream.js.map +1 -1
- package/dist/src/create-batch-stream.test.js +2 -4
- package/dist/src/create-batch-stream.test.js.map +1 -1
- package/dist/src/feed-descriptor.d.ts +5 -3
- package/dist/src/feed-descriptor.d.ts.map +1 -1
- package/dist/src/feed-descriptor.js +24 -4
- package/dist/src/feed-descriptor.js.map +1 -1
- package/dist/src/feed-descriptor.test.js +10 -10
- package/dist/src/feed-descriptor.test.js.map +1 -1
- package/dist/src/feed-store.d.ts +5 -5
- package/dist/src/feed-store.d.ts.map +1 -1
- package/dist/src/feed-store.js +8 -8
- package/dist/src/feed-store.js.map +1 -1
- package/dist/src/feed-store.test.js +16 -39
- package/dist/src/feed-store.test.js.map +1 -1
- package/dist/src/hypercore-types.d.ts +1 -0
- package/dist/src/hypercore-types.d.ts.map +1 -1
- package/dist/src/index.js +5 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/stream.d.ts +9 -4
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +34 -42
- package/dist/src/stream.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/benchmark.ts +24 -28
- package/src/create-batch-stream.test.ts +2 -4
- package/src/create-batch-stream.ts +15 -15
- package/src/feed-descriptor.test.ts +10 -10
- package/src/feed-descriptor.ts +46 -9
- package/src/feed-store.test.ts +19 -48
- package/src/feed-store.ts +10 -10
- package/src/stream.ts +32 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/feed-store",
|
|
3
|
-
"version": "2.33.5-dev.
|
|
3
|
+
"version": "2.33.5-dev.fee8f5fe",
|
|
4
4
|
"description": "A consistent store for your hypercore feeds.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"dist"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@dxos/async": "2.33.5-dev.
|
|
14
|
-
"@dxos/util": "2.33.5-dev.
|
|
13
|
+
"@dxos/async": "2.33.5-dev.fee8f5fe",
|
|
14
|
+
"@dxos/util": "2.33.5-dev.fee8f5fe",
|
|
15
15
|
"buffer-json-encoding": "^1.0.2",
|
|
16
16
|
"debug": "^4.3.3",
|
|
17
17
|
"end-of-stream": "^1.4.1",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@dxos/benchmark-suite": "^1.0.0-beta.1",
|
|
26
26
|
"@dxos/browser-runner": "^1.0.0-beta.13",
|
|
27
|
-
"@dxos/crypto": "2.33.5-dev.
|
|
28
|
-
"@dxos/eslint-plugin": "~1.0.
|
|
27
|
+
"@dxos/crypto": "2.33.5-dev.fee8f5fe",
|
|
28
|
+
"@dxos/eslint-plugin": "~1.0.33",
|
|
29
29
|
"@dxos/protocols-toolchain": "2.33.4",
|
|
30
|
-
"@dxos/random-access-multi-storage": "2.33.5-dev.
|
|
30
|
+
"@dxos/random-access-multi-storage": "2.33.5-dev.fee8f5fe",
|
|
31
31
|
"@types/debug": "^4.1.7",
|
|
32
32
|
"@types/end-of-stream": "^1.4.0",
|
|
33
33
|
"@types/from2": "~2.3.1",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"eslint": "^7.12.1",
|
|
41
41
|
"hypertrie": "5.1.1",
|
|
42
42
|
"tempy": "~1.0.1",
|
|
43
|
-
"typescript": "^4.
|
|
43
|
+
"typescript": "^4.7.2",
|
|
44
44
|
"wait-for-expect": "^3.0.2"
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
package/src/benchmark.ts
CHANGED
|
@@ -21,44 +21,40 @@ void (async () => {
|
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const fs = new FeedStore(createStorage('.benchmark'), { valueEncoding: 'utf8' });
|
|
24
|
+
const fs = new FeedStore(createStorage('').directory('.benchmark'), { valueEncoding: 'utf8' });
|
|
25
25
|
const suite = new Suite(fs, { maxFeeds, maxMessages });
|
|
26
26
|
|
|
27
|
-
suite.beforeAll(() => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const { feed } = await fs.openReadWriteFeed(PublicKey.from(publicKey), secretKey);
|
|
27
|
+
suite.beforeAll(() => Promise.all(range(maxFeeds).map(async i => {
|
|
28
|
+
const name = `feed/${i}`;
|
|
29
|
+
const { publicKey, secretKey } = createKeyPair();
|
|
30
|
+
const { feed } = await fs.openReadWriteFeed(PublicKey.from(publicKey), secretKey);
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
32
|
+
for (let i = 0; i < maxMessages; i++) {
|
|
33
|
+
await new Promise<void>((resolve, reject) => {
|
|
34
|
+
feed.append(`${name}/${i}`, (err) => {
|
|
35
|
+
if (err) {
|
|
36
|
+
return reject(err);
|
|
37
|
+
}
|
|
38
|
+
resolve();
|
|
41
39
|
});
|
|
42
|
-
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
43
|
+
return feed;
|
|
44
|
+
})));
|
|
47
45
|
|
|
48
46
|
suite.test('getBatch', async () => {
|
|
49
47
|
let count = 0;
|
|
50
48
|
|
|
51
|
-
await Promise.all(Array.from((fs as any)._descriptors.values()).map(({ feed }: any) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
resolve();
|
|
59
|
-
});
|
|
49
|
+
await Promise.all(Array.from((fs as any)._descriptors.values()).map(({ feed }: any) => new Promise<void>((resolve, reject) => {
|
|
50
|
+
feed.getBatch(0, maxMessages, (err: Error, result: any) => {
|
|
51
|
+
count += result.length;
|
|
52
|
+
if (err) {
|
|
53
|
+
return reject(err);
|
|
54
|
+
}
|
|
55
|
+
resolve();
|
|
60
56
|
});
|
|
61
|
-
}));
|
|
57
|
+
})));
|
|
62
58
|
|
|
63
59
|
check(count);
|
|
64
60
|
});
|
|
@@ -13,15 +13,13 @@ import { FeedStore } from './feed-store';
|
|
|
13
13
|
import { HypercoreFeed } from './hypercore-types';
|
|
14
14
|
|
|
15
15
|
const createFeed = async () => {
|
|
16
|
-
const feedStore = new FeedStore(createStorage('', StorageType.RAM), { valueEncoding: 'utf-8' });
|
|
16
|
+
const feedStore = new FeedStore(createStorage('', StorageType.RAM).directory('feed'), { valueEncoding: 'utf-8' });
|
|
17
17
|
const { publicKey, secretKey } = createKeyPair();
|
|
18
18
|
const { feed } = await feedStore.openReadWriteFeed(PublicKey.from(publicKey), secretKey);
|
|
19
19
|
return feed;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
const append = (feed: HypercoreFeed, message: any) =>
|
|
23
|
-
return pify(feed.append.bind(feed))(message);
|
|
24
|
-
};
|
|
22
|
+
const append = (feed: HypercoreFeed, message: any) => pify(feed.append.bind(feed))(message);
|
|
25
23
|
|
|
26
24
|
describe('Batch stream', () => {
|
|
27
25
|
test('Single message', async () => {
|
|
@@ -17,7 +17,7 @@ export interface CreateBatchStreamOptions {
|
|
|
17
17
|
tail?: boolean
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export
|
|
20
|
+
export const createBatchStream = (feed: HypercoreFeed, opts: CreateBatchStreamOptions = {}) => {
|
|
21
21
|
assert(!opts.batch || opts.batch > 0, 'batch must be major or equal to 1');
|
|
22
22
|
|
|
23
23
|
let start = opts.start || 0;
|
|
@@ -34,9 +34,7 @@ export function createBatchStream (feed: HypercoreFeed, opts: CreateBatchStreamO
|
|
|
34
34
|
|
|
35
35
|
let range = feed.download({ start, end, linear: true });
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
function read (size: any, cb?: any) {
|
|
37
|
+
const read = (size: any, cb?: any) => {
|
|
40
38
|
if (!feed.opened) {
|
|
41
39
|
return open(size, cb);
|
|
42
40
|
}
|
|
@@ -103,9 +101,9 @@ export function createBatchStream (feed: HypercoreFeed, opts: CreateBatchStreamO
|
|
|
103
101
|
|
|
104
102
|
cb(null, messages.map(buildMessage));
|
|
105
103
|
});
|
|
106
|
-
}
|
|
104
|
+
};
|
|
107
105
|
|
|
108
|
-
|
|
106
|
+
const buildMessage = (data: object) => {
|
|
109
107
|
const message = {
|
|
110
108
|
key: feed.key,
|
|
111
109
|
seq: seq++,
|
|
@@ -115,26 +113,26 @@ export function createBatchStream (feed: HypercoreFeed, opts: CreateBatchStreamO
|
|
|
115
113
|
};
|
|
116
114
|
|
|
117
115
|
return message;
|
|
118
|
-
}
|
|
116
|
+
};
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
const cleanup = () => {
|
|
121
119
|
if (!range) {
|
|
122
120
|
return;
|
|
123
121
|
}
|
|
124
122
|
feed.undownload(range);
|
|
125
123
|
range = null;
|
|
126
|
-
}
|
|
124
|
+
};
|
|
127
125
|
|
|
128
|
-
|
|
129
|
-
feed.ready(
|
|
126
|
+
const open = (size: any, cb: (err: Error) => void) => {
|
|
127
|
+
feed.ready((err: Error) => {
|
|
130
128
|
if (err) {
|
|
131
129
|
return cb(err);
|
|
132
130
|
}
|
|
133
131
|
read(size, cb);
|
|
134
132
|
});
|
|
135
|
-
}
|
|
133
|
+
};
|
|
136
134
|
|
|
137
|
-
|
|
135
|
+
const setStart = (value: number) => {
|
|
138
136
|
const prevStart = start;
|
|
139
137
|
start = value;
|
|
140
138
|
range.start = start;
|
|
@@ -142,5 +140,7 @@ export function createBatchStream (feed: HypercoreFeed, opts: CreateBatchStreamO
|
|
|
142
140
|
range.iterator.start = start;
|
|
143
141
|
}
|
|
144
142
|
return prevStart;
|
|
145
|
-
}
|
|
146
|
-
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return streamFrom.obj(read).on('end', cleanup).on('close', cleanup);
|
|
146
|
+
};
|
|
@@ -20,7 +20,7 @@ describe('FeedDescriptor', () => {
|
|
|
20
20
|
beforeEach(async () => {
|
|
21
21
|
const { publicKey, secretKey } = createKeyPair();
|
|
22
22
|
fd = new FeedDescriptor({
|
|
23
|
-
|
|
23
|
+
directory: createStorage('', StorageType.RAM).directory('feed'),
|
|
24
24
|
key: PublicKey.from(publicKey),
|
|
25
25
|
secretKey,
|
|
26
26
|
hypercore: defaultHypercore
|
|
@@ -41,7 +41,7 @@ describe('FeedDescriptor', () => {
|
|
|
41
41
|
// When this behaviour was changed, suddenly `protocol-plugin-replicator` tests started hanging forever on network generation.
|
|
42
42
|
const { publicKey } = createKeyPair();
|
|
43
43
|
const key = PublicKey.from(publicKey);
|
|
44
|
-
const fd = new FeedDescriptor({ key,
|
|
44
|
+
const fd = new FeedDescriptor({ key, directory: createStorage('', StorageType.NODE).directory('feed'), hypercore: defaultHypercore });
|
|
45
45
|
expect(fd.key).toEqual(key);
|
|
46
46
|
expect(fd.secretKey).toBeUndefined();
|
|
47
47
|
});
|
|
@@ -50,7 +50,7 @@ describe('FeedDescriptor', () => {
|
|
|
50
50
|
const { publicKey, secretKey } = createKeyPair();
|
|
51
51
|
|
|
52
52
|
const fd = new FeedDescriptor({
|
|
53
|
-
|
|
53
|
+
directory: createStorage('', StorageType.RAM).directory('feed'),
|
|
54
54
|
key: PublicKey.from(publicKey),
|
|
55
55
|
secretKey,
|
|
56
56
|
valueEncoding: 'json',
|
|
@@ -92,7 +92,7 @@ describe('FeedDescriptor', () => {
|
|
|
92
92
|
// If we try to close a feed that is opening should wait for the open result.
|
|
93
93
|
const { publicKey, secretKey } = createKeyPair();
|
|
94
94
|
const fd2 = new FeedDescriptor({
|
|
95
|
-
|
|
95
|
+
directory: createStorage('', StorageType.RAM).directory('feed'),
|
|
96
96
|
key: PublicKey.from(publicKey),
|
|
97
97
|
secretKey,
|
|
98
98
|
hypercore: defaultHypercore
|
|
@@ -108,7 +108,7 @@ describe('FeedDescriptor', () => {
|
|
|
108
108
|
|
|
109
109
|
const { publicKey, secretKey } = createKeyPair();
|
|
110
110
|
const fd = new FeedDescriptor({
|
|
111
|
-
|
|
111
|
+
directory: createStorage(root, StorageType.NODE).directory('feed'),
|
|
112
112
|
key: PublicKey.from(publicKey),
|
|
113
113
|
secretKey,
|
|
114
114
|
valueEncoding: 'utf-8',
|
|
@@ -135,7 +135,7 @@ describe('FeedDescriptor', () => {
|
|
|
135
135
|
test('on open error should unlock the resource', async () => {
|
|
136
136
|
const { publicKey, secretKey } = createKeyPair();
|
|
137
137
|
const fd = new FeedDescriptor({
|
|
138
|
-
|
|
138
|
+
directory: createStorage('', StorageType.RAM).directory('feed'),
|
|
139
139
|
key: PublicKey.from(publicKey),
|
|
140
140
|
secretKey,
|
|
141
141
|
hypercore: () => {
|
|
@@ -149,16 +149,16 @@ describe('FeedDescriptor', () => {
|
|
|
149
149
|
test('on close error should unlock the resource', async () => {
|
|
150
150
|
const { publicKey, secretKey } = createKeyPair();
|
|
151
151
|
const fd = new FeedDescriptor({
|
|
152
|
-
|
|
152
|
+
directory: createStorage('', StorageType.RAM).directory('feed'),
|
|
153
153
|
key: PublicKey.from(publicKey),
|
|
154
154
|
secretKey,
|
|
155
155
|
hypercore: () => ({
|
|
156
156
|
opened: true,
|
|
157
|
-
on () {},
|
|
158
|
-
ready (cb: () => void) {
|
|
157
|
+
on: () => {},
|
|
158
|
+
ready: (cb: () => void) => {
|
|
159
159
|
cb();
|
|
160
160
|
},
|
|
161
|
-
close () {
|
|
161
|
+
close: () => {
|
|
162
162
|
throw new Error('close error');
|
|
163
163
|
}
|
|
164
164
|
} as any)
|
package/src/feed-descriptor.ts
CHANGED
|
@@ -5,20 +5,22 @@
|
|
|
5
5
|
import assert from 'assert';
|
|
6
6
|
import defaultHypercore from 'hypercore';
|
|
7
7
|
import pify from 'pify';
|
|
8
|
+
import { callbackify } from 'util';
|
|
8
9
|
|
|
9
10
|
import { Lock } from '@dxos/async';
|
|
10
11
|
import { PublicKey } from '@dxos/crypto';
|
|
11
|
-
import type {
|
|
12
|
+
import type { Directory } from '@dxos/random-access-multi-storage';
|
|
12
13
|
|
|
13
14
|
import type { HypercoreFeed, Hypercore } from './hypercore-types';
|
|
14
15
|
import type { ValueEncoding } from './types';
|
|
15
16
|
|
|
16
17
|
interface FeedDescriptorOptions {
|
|
17
|
-
|
|
18
|
+
directory: Directory,
|
|
18
19
|
key: PublicKey,
|
|
19
20
|
hypercore: Hypercore,
|
|
20
21
|
secretKey?: Buffer,
|
|
21
22
|
valueEncoding?: ValueEncoding
|
|
23
|
+
disableSigning?: boolean
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/**
|
|
@@ -27,29 +29,32 @@ interface FeedDescriptorOptions {
|
|
|
27
29
|
* Abstract handler for an Hypercore instance.
|
|
28
30
|
*/
|
|
29
31
|
export class FeedDescriptor {
|
|
30
|
-
private readonly
|
|
32
|
+
private readonly _directory: Directory;
|
|
31
33
|
private readonly _key: PublicKey;
|
|
32
34
|
private readonly _secretKey?: Buffer;
|
|
33
35
|
private readonly _valueEncoding?: ValueEncoding;
|
|
34
36
|
private readonly _hypercore: Hypercore;
|
|
35
37
|
private readonly _lock: Lock;
|
|
38
|
+
private readonly _disableSigning: boolean;
|
|
36
39
|
|
|
37
40
|
private _feed: HypercoreFeed | null;
|
|
38
41
|
|
|
39
42
|
constructor (options: FeedDescriptorOptions) {
|
|
40
43
|
const {
|
|
41
|
-
|
|
44
|
+
directory,
|
|
42
45
|
key,
|
|
43
46
|
secretKey,
|
|
44
47
|
valueEncoding,
|
|
45
|
-
hypercore = defaultHypercore
|
|
48
|
+
hypercore = defaultHypercore,
|
|
49
|
+
disableSigning = false
|
|
46
50
|
} = options;
|
|
47
51
|
|
|
48
|
-
this.
|
|
52
|
+
this._directory = directory;
|
|
49
53
|
this._valueEncoding = valueEncoding;
|
|
50
54
|
this._hypercore = hypercore;
|
|
51
55
|
this._key = key;
|
|
52
56
|
this._secretKey = secretKey;
|
|
57
|
+
this._disableSigning = !!disableSigning;
|
|
53
58
|
|
|
54
59
|
this._lock = new Lock();
|
|
55
60
|
|
|
@@ -115,9 +120,19 @@ export class FeedDescriptor {
|
|
|
115
120
|
* Defines the real path where the Hypercore is going
|
|
116
121
|
* to work with the RandomAccessStorage specified.
|
|
117
122
|
*/
|
|
118
|
-
|
|
123
|
+
|
|
124
|
+
private _createStorage (dir = ''): (name: string) => HypercoreFile {
|
|
119
125
|
return (name) => {
|
|
120
|
-
|
|
126
|
+
const file = this._directory.createOrOpen(`${dir}/${name}`);
|
|
127
|
+
// Separation between our internal File API and Hypercore's.
|
|
128
|
+
return {
|
|
129
|
+
read: callbackify(file.read.bind(file)),
|
|
130
|
+
write: callbackify(file.write.bind(file)),
|
|
131
|
+
del: callbackify(file.truncate.bind(file)),
|
|
132
|
+
stat: callbackify(file.stat.bind(file)),
|
|
133
|
+
close: callbackify(file.close.bind(file)),
|
|
134
|
+
destroy: callbackify(file.delete.bind(file))
|
|
135
|
+
} as HypercoreFile;
|
|
121
136
|
};
|
|
122
137
|
}
|
|
123
138
|
|
|
@@ -127,7 +142,8 @@ export class FeedDescriptor {
|
|
|
127
142
|
this._key.asBuffer(),
|
|
128
143
|
{
|
|
129
144
|
secretKey: this._secretKey,
|
|
130
|
-
valueEncoding: this._valueEncoding
|
|
145
|
+
valueEncoding: this._valueEncoding,
|
|
146
|
+
crypto: this._disableSigning ? MOCK_CRYPTO : undefined
|
|
131
147
|
}
|
|
132
148
|
);
|
|
133
149
|
|
|
@@ -141,3 +157,24 @@ export class FeedDescriptor {
|
|
|
141
157
|
}
|
|
142
158
|
|
|
143
159
|
export default FeedDescriptor;
|
|
160
|
+
|
|
161
|
+
const MOCK_CRYPTO = {
|
|
162
|
+
sign: (data: any, secretKey: any, cb: any) => {
|
|
163
|
+
cb(null, Buffer.from(''));
|
|
164
|
+
},
|
|
165
|
+
verify: (signature: any, data: any, key: any, cb: any) => {
|
|
166
|
+
cb(null, true);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* File API that hypercore uses to read/write from storage.
|
|
172
|
+
*/
|
|
173
|
+
interface HypercoreFile {
|
|
174
|
+
read (offset: number, size: number, cb?: (err: Error | null, data?: Buffer) => void): void;
|
|
175
|
+
write (offset: number, data: Buffer, cb?: (err: Error | null) => void): void;
|
|
176
|
+
del (offset: number, size: number, cb?: (err: Error | null) => void): void;
|
|
177
|
+
stat (cb: (err: Error | null, data?: {size: number}) => void): void;
|
|
178
|
+
close (cb?: (err: Error | null) => void): void;
|
|
179
|
+
destroy (cb?: (err: Error | null) => void): void;
|
|
180
|
+
}
|
package/src/feed-store.test.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import assert from 'assert';
|
|
8
8
|
import hypercore from 'hypercore';
|
|
9
|
-
import hypertrie from 'hypertrie';
|
|
10
9
|
import pify from 'pify';
|
|
11
10
|
import tempy from 'tempy';
|
|
12
11
|
|
|
@@ -26,71 +25,43 @@ interface KeyPair {
|
|
|
26
25
|
const feedNames = ['booksFeed', 'usersFeed', 'groupsFeed'];
|
|
27
26
|
|
|
28
27
|
const createFeedStore = (storage: Storage, options = {}) => {
|
|
29
|
-
const feedStore = new FeedStore(storage, options);
|
|
28
|
+
const feedStore = new FeedStore(storage.directory('feed'), options);
|
|
30
29
|
return feedStore;
|
|
31
30
|
};
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
const createDefault = async () => {
|
|
34
33
|
const directory = tempy.directory();
|
|
35
34
|
|
|
36
35
|
return {
|
|
37
36
|
directory,
|
|
38
37
|
feedStore: createFeedStore(createStorage(directory, StorageType.NODE), { valueEncoding: 'utf-8' })
|
|
39
38
|
};
|
|
40
|
-
}
|
|
39
|
+
};
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
)));
|
|
46
|
-
}
|
|
41
|
+
const defaultFeeds = async (feedStore: FeedStore, keys: Record<string, KeyPair>): Promise<Record<string, FeedDescriptor>> => Object.fromEntries(await Promise.all(Object.entries<KeyPair>(keys).map(async ([feed, keyPair]) =>
|
|
42
|
+
[feed, await feedStore.openReadWriteFeed(keyPair.key, keyPair.secretKey)]
|
|
43
|
+
)));
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
return pify(feed.append.bind(feed))(message);
|
|
50
|
-
}
|
|
45
|
+
const append = (feed: HypercoreFeed, message: any) => pify(feed.append.bind(feed))(message);
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
return pify(feed.head.bind(feed))();
|
|
54
|
-
}
|
|
47
|
+
const head = (feed: HypercoreFeed) => pify(feed.head.bind(feed))();
|
|
55
48
|
|
|
56
|
-
const createKeyPairs = () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}));
|
|
61
|
-
};
|
|
49
|
+
const createKeyPairs = () => Object.fromEntries<KeyPair>(feedNames.map(feed => {
|
|
50
|
+
const { publicKey, secretKey } = createKeyPair();
|
|
51
|
+
return [feed, { key: PublicKey.from(publicKey), secretKey }];
|
|
52
|
+
}));
|
|
62
53
|
|
|
63
54
|
describe('FeedStore', () => {
|
|
64
55
|
const keys = createKeyPairs();
|
|
65
56
|
|
|
66
57
|
test('Config default', async () => {
|
|
67
|
-
const feedStore = await createFeedStore(createStorage('
|
|
58
|
+
const feedStore = await createFeedStore(createStorage('', StorageType.RAM));
|
|
68
59
|
expect(feedStore).toBeInstanceOf(FeedStore);
|
|
69
60
|
|
|
70
|
-
const feedStore2 = new FeedStore(createStorage('
|
|
61
|
+
const feedStore2 = new FeedStore(createStorage('', StorageType.RAM).directory('feed'));
|
|
71
62
|
expect(feedStore2).toBeInstanceOf(FeedStore);
|
|
72
63
|
});
|
|
73
64
|
|
|
74
|
-
test('Config default + custom database + custom hypercore', async () => {
|
|
75
|
-
const customHypercore = jest.fn((...args) => {
|
|
76
|
-
return hypercore(args[0], args[1], args[2]);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const storage = createStorage('', StorageType.RAM);
|
|
80
|
-
const database = hypertrie(storage.createOrOpen.bind(storage), { valueEncoding: 'json' });
|
|
81
|
-
database.list = jest.fn((_, cb) => cb(null, []));
|
|
82
|
-
|
|
83
|
-
const feedStore = createFeedStore(createStorage('feed', StorageType.RAM), {
|
|
84
|
-
hypercore: customHypercore
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
expect(feedStore).toBeInstanceOf(FeedStore);
|
|
88
|
-
|
|
89
|
-
await feedStore.openReadOnlyFeed(PublicKey.random());
|
|
90
|
-
|
|
91
|
-
expect(customHypercore.mock.calls.length).toBe(1);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
65
|
test('Create feed', async () => {
|
|
95
66
|
const { feedStore } = await createDefault();
|
|
96
67
|
const { booksFeed: { feed: booksFeed } } = await defaultFeeds(feedStore, keys);
|
|
@@ -161,7 +132,7 @@ describe('FeedStore', () => {
|
|
|
161
132
|
});
|
|
162
133
|
|
|
163
134
|
test('Default codec: binary', async () => {
|
|
164
|
-
const feedStore = createFeedStore(createStorage('
|
|
135
|
+
const feedStore = createFeedStore(createStorage('', StorageType.RAM));
|
|
165
136
|
expect(feedStore).toBeInstanceOf(FeedStore);
|
|
166
137
|
|
|
167
138
|
const { publicKey, secretKey } = createKeyPair();
|
|
@@ -172,14 +143,14 @@ describe('FeedStore', () => {
|
|
|
172
143
|
});
|
|
173
144
|
|
|
174
145
|
test('on close error should unlock the descriptor', async () => {
|
|
175
|
-
const feedStore = createFeedStore(createStorage('
|
|
146
|
+
const feedStore = createFeedStore(createStorage('', StorageType.RAM), {
|
|
176
147
|
hypercore: () => ({
|
|
177
148
|
opened: true,
|
|
178
|
-
ready (cb: () => void) {
|
|
149
|
+
ready: (cb: () => void) => {
|
|
179
150
|
cb();
|
|
180
151
|
},
|
|
181
|
-
on () {},
|
|
182
|
-
close () {
|
|
152
|
+
on: () => {},
|
|
153
|
+
close: () => {
|
|
183
154
|
throw new Error('close error');
|
|
184
155
|
}
|
|
185
156
|
})
|
package/src/feed-store.ts
CHANGED
|
@@ -7,7 +7,7 @@ import defaultHypercore from 'hypercore';
|
|
|
7
7
|
|
|
8
8
|
import { synchronized, Event } from '@dxos/async';
|
|
9
9
|
import { PublicKey } from '@dxos/crypto';
|
|
10
|
-
import {
|
|
10
|
+
import { Directory } from '@dxos/random-access-multi-storage';
|
|
11
11
|
|
|
12
12
|
import FeedDescriptor from './feed-descriptor';
|
|
13
13
|
import type { Hypercore } from './hypercore-types';
|
|
@@ -45,7 +45,7 @@ export interface FeedStoreOptions {
|
|
|
45
45
|
* into a persist repository storage.
|
|
46
46
|
*/
|
|
47
47
|
export class FeedStore {
|
|
48
|
-
private
|
|
48
|
+
private _directory: Directory;
|
|
49
49
|
private _valueEncoding: ValueEncoding | undefined;
|
|
50
50
|
private _hypercore: Hypercore;
|
|
51
51
|
private _descriptors: Map<string, FeedDescriptor>;
|
|
@@ -56,13 +56,13 @@ export class FeedStore {
|
|
|
56
56
|
readonly feedOpenedEvent = new Event<FeedDescriptor>();
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* @param
|
|
59
|
+
* @param directory RandomAccessStorage to use by default by the feeds.
|
|
60
60
|
* @param options Feedstore options.
|
|
61
61
|
*/
|
|
62
|
-
constructor (
|
|
63
|
-
assert(
|
|
62
|
+
constructor (directory: Directory, options: FeedStoreOptions = {}) {
|
|
63
|
+
assert(directory, 'The storage is required.');
|
|
64
64
|
|
|
65
|
-
this.
|
|
65
|
+
this._directory = directory;
|
|
66
66
|
|
|
67
67
|
const {
|
|
68
68
|
valueEncoding,
|
|
@@ -79,7 +79,7 @@ export class FeedStore {
|
|
|
79
79
|
* @type {RandomAccessStorage}
|
|
80
80
|
*/
|
|
81
81
|
get storage () {
|
|
82
|
-
return this.
|
|
82
|
+
return this._directory;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
@synchronized
|
|
@@ -114,7 +114,7 @@ export class FeedStore {
|
|
|
114
114
|
const { key, secretKey } = options;
|
|
115
115
|
|
|
116
116
|
const descriptor = new FeedDescriptor({
|
|
117
|
-
|
|
117
|
+
directory: this._directory,
|
|
118
118
|
key,
|
|
119
119
|
secretKey,
|
|
120
120
|
valueEncoding: this._valueEncoding,
|
|
@@ -133,7 +133,7 @@ export class FeedStore {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
const patchBufferCodec = (encoding: ValueEncoding): ValueEncoding => {
|
|
137
137
|
if (typeof encoding === 'string') {
|
|
138
138
|
return encoding;
|
|
139
139
|
}
|
|
@@ -141,4 +141,4 @@ function patchBufferCodec (encoding: ValueEncoding): ValueEncoding {
|
|
|
141
141
|
encode: (x: any) => Buffer.from(encoding.encode(x)),
|
|
142
142
|
decode: encoding.decode.bind(encoding)
|
|
143
143
|
};
|
|
144
|
-
}
|
|
144
|
+
};
|