@dxos/echo-pipeline 0.1.41 → 0.1.45-next.45667d4
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/lib/browser/{chunk-4YAT2XJW.mjs → chunk-2NGLSBL4.mjs} +1128 -1017
- package/dist/lib/browser/chunk-2NGLSBL4.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1 -3
- package/dist/lib/browser/index.mjs.map +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +72 -48
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node/index.cjs +1048 -938
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +735 -540
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/types/src/dbhost/database-host.d.ts +2 -4
- package/dist/types/src/dbhost/database-host.d.ts.map +1 -1
- package/dist/types/src/dbhost/snapshot-store.d.ts +2 -0
- package/dist/types/src/dbhost/snapshot-store.d.ts.map +1 -1
- package/dist/types/src/metadata/metadata-store.d.ts +3 -2
- package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
- package/dist/types/src/pipeline/pipeline.d.ts +27 -11
- package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/types/src/pipeline/timeframe-clock.d.ts +1 -0
- package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
- package/dist/types/src/space/auth.d.ts +4 -4
- package/dist/types/src/space/auth.d.ts.map +1 -1
- package/dist/types/src/space/control-pipeline.d.ts +2 -4
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/data-pipeline.d.ts +19 -10
- package/dist/types/src/space/data-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/index.d.ts +0 -1
- package/dist/types/src/space/index.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +14 -14
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space-protocol.d.ts +2 -2
- package/dist/types/src/space/space-protocol.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +20 -7
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/database-test-rig.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent-builder.d.ts +15 -5
- package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
- package/package.json +30 -30
- package/src/common/feeds.ts +2 -2
- package/src/dbhost/data-service-host.ts +10 -10
- package/src/dbhost/data-service.ts +1 -1
- package/src/dbhost/database-host.ts +1 -9
- package/src/dbhost/snapshot-store.test.ts +2 -2
- package/src/dbhost/snapshot-store.ts +16 -1
- package/src/metadata/metadata-store.ts +14 -16
- package/src/pipeline/message-selector.ts +1 -1
- package/src/pipeline/pipeline.test.ts +68 -44
- package/src/pipeline/pipeline.ts +118 -35
- package/src/pipeline/timeframe-clock.ts +8 -2
- package/src/space/auth.ts +6 -6
- package/src/space/control-pipeline.test.ts +19 -20
- package/src/space/control-pipeline.ts +3 -5
- package/src/space/data-pipeline.ts +131 -69
- package/src/space/index.ts +0 -1
- package/src/space/replication.browser.test.ts +8 -8
- package/src/space/space-manager.browser.test.ts +3 -3
- package/src/space/space-manager.ts +25 -20
- package/src/space/space-protocol.browser.test.ts +1 -1
- package/src/space/space-protocol.test.ts +6 -6
- package/src/space/space-protocol.ts +7 -7
- package/src/space/space.test.ts +137 -48
- package/src/space/space.ts +82 -40
- package/src/testing/database-test-rig.ts +25 -24
- package/src/testing/test-agent-builder.ts +88 -49
- package/src/testing/test-feed-builder.ts +1 -1
- package/src/testing/util.ts +15 -15
- package/src/tests/database-unit.test.ts +4 -4
- package/src/tests/database.test.ts +1 -1
- package/dist/lib/browser/chunk-4YAT2XJW.mjs.map +0 -7
- package/dist/types/src/space/genesis.d.ts +0 -5
- package/dist/types/src/space/genesis.d.ts.map +0 -1
- package/src/space/genesis.ts +0 -69
package/src/pipeline/pipeline.ts
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
|
-
import { sleep, synchronized, Trigger } from '@dxos/async';
|
|
7
|
+
import { Event, sleep, synchronized, Trigger } from '@dxos/async';
|
|
8
8
|
import { Context, rejectOnDispose } from '@dxos/context';
|
|
9
|
+
import { failUndefined } from '@dxos/debug';
|
|
9
10
|
import { FeedSetIterator, FeedWrapper, FeedWriter } from '@dxos/feed-store';
|
|
10
11
|
import { PublicKey } from '@dxos/keys';
|
|
11
12
|
import { log } from '@dxos/log';
|
|
12
13
|
import { FeedMessageBlock } from '@dxos/protocols';
|
|
13
14
|
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
14
15
|
import { Timeframe } from '@dxos/timeframe';
|
|
16
|
+
import { ComplexMap } from '@dxos/util';
|
|
15
17
|
|
|
16
18
|
import { createMappedFeedWriter } from '../common';
|
|
17
19
|
import { createMessageSelector } from './message-selector';
|
|
@@ -37,6 +39,8 @@ export class PipelineState {
|
|
|
37
39
|
// TODO(dmaretskyi): Remove?.
|
|
38
40
|
public readonly timeframeUpdate = this._timeframeClock.update;
|
|
39
41
|
|
|
42
|
+
public readonly stalled = new Event();
|
|
43
|
+
|
|
40
44
|
/**
|
|
41
45
|
* Target timeframe we are waiting to reach.
|
|
42
46
|
*/
|
|
@@ -46,7 +50,7 @@ export class PipelineState {
|
|
|
46
50
|
|
|
47
51
|
// prettier-ignore
|
|
48
52
|
constructor(
|
|
49
|
-
private
|
|
53
|
+
private _feeds: ComplexMap<PublicKey, FeedWrapper<FeedMessage>>,
|
|
50
54
|
private _timeframeClock: TimeframeClock
|
|
51
55
|
) { }
|
|
52
56
|
|
|
@@ -57,12 +61,12 @@ export class PipelineState {
|
|
|
57
61
|
// TODO(dmaretskyi): Rename `totalTimeframe`? or `lastTimeframe`.
|
|
58
62
|
get endTimeframe() {
|
|
59
63
|
return mapFeedIndexesToTimeframe(
|
|
60
|
-
this.
|
|
64
|
+
Array.from(this._feeds.values())
|
|
61
65
|
.filter((feed) => feed.length > 0)
|
|
62
66
|
.map((feed) => ({
|
|
63
67
|
feedKey: feed.key,
|
|
64
|
-
index: feed.length - 1
|
|
65
|
-
}))
|
|
68
|
+
index: feed.length - 1,
|
|
69
|
+
})),
|
|
66
70
|
);
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -79,7 +83,7 @@ export class PipelineState {
|
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
get feeds() {
|
|
82
|
-
return this.
|
|
86
|
+
return Array.from(this._feeds.values());
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
async waitUntilTimeframe(target: Timeframe) {
|
|
@@ -100,19 +104,19 @@ export class PipelineState {
|
|
|
100
104
|
async waitUntilReachedTargetTimeframe({
|
|
101
105
|
ctx = new Context(),
|
|
102
106
|
timeout,
|
|
103
|
-
breakOnStall = true
|
|
107
|
+
breakOnStall = true,
|
|
104
108
|
}: WaitUntilReachedTargetParams = {}) {
|
|
105
109
|
log('waitUntilReachedTargetTimeframe', {
|
|
106
110
|
timeout,
|
|
107
111
|
current: this.timeframe,
|
|
108
|
-
target: this.targetTimeframe
|
|
112
|
+
target: this.targetTimeframe,
|
|
109
113
|
});
|
|
110
114
|
|
|
111
115
|
this._reachedTargetPromise ??= Promise.race([
|
|
112
116
|
this._timeframeClock.update.waitForCondition(() => {
|
|
113
117
|
return Timeframe.dependencies(this.targetTimeframe, this.timeframe).isEmpty();
|
|
114
118
|
}),
|
|
115
|
-
...(breakOnStall ? [this.
|
|
119
|
+
...(breakOnStall ? [this.stalled.discardParameter().waitForCount(1)] : []),
|
|
116
120
|
]);
|
|
117
121
|
|
|
118
122
|
let done = false;
|
|
@@ -132,9 +136,9 @@ export class PipelineState {
|
|
|
132
136
|
timeout,
|
|
133
137
|
current: this.timeframe,
|
|
134
138
|
target: this.targetTimeframe,
|
|
135
|
-
dependencies: Timeframe.dependencies(this.targetTimeframe, this.timeframe)
|
|
139
|
+
dependencies: Timeframe.dependencies(this.targetTimeframe, this.timeframe),
|
|
136
140
|
});
|
|
137
|
-
})
|
|
141
|
+
}),
|
|
138
142
|
]);
|
|
139
143
|
} else {
|
|
140
144
|
return this._reachedTargetPromise;
|
|
@@ -180,33 +184,31 @@ export interface PipelineAccessor {
|
|
|
180
184
|
* 5. Wait for the writable feed to be added.
|
|
181
185
|
*/
|
|
182
186
|
export class Pipeline implements PipelineAccessor {
|
|
183
|
-
private readonly _timeframeClock = new TimeframeClock(
|
|
187
|
+
private readonly _timeframeClock = new TimeframeClock(new Timeframe());
|
|
188
|
+
|
|
189
|
+
private readonly _feeds = new ComplexMap<PublicKey, FeedWrapper<FeedMessage>>(PublicKey.hash);
|
|
184
190
|
|
|
185
191
|
// Inbound feed stream.
|
|
186
|
-
private
|
|
187
|
-
start: startAfter(this._initialTimeframe),
|
|
188
|
-
stallTimeout: 1000
|
|
189
|
-
});
|
|
192
|
+
private _feedSetIterator?: FeedSetIterator<FeedMessage>;
|
|
190
193
|
|
|
191
194
|
// External state accessor.
|
|
192
|
-
private readonly _state: PipelineState = new PipelineState(this.
|
|
195
|
+
private readonly _state: PipelineState = new PipelineState(this._feeds, this._timeframeClock);
|
|
193
196
|
|
|
194
197
|
// Waits for the message consumer to process the message and yield control back to the pipeline.
|
|
195
198
|
private readonly _processingTrigger = new Trigger().wake();
|
|
196
199
|
|
|
197
|
-
|
|
198
|
-
|
|
200
|
+
private readonly _pauseTrigger = new Trigger().wake();
|
|
201
|
+
|
|
202
|
+
private _isStopping = false;
|
|
203
|
+
|
|
204
|
+
private _isStarted = false;
|
|
199
205
|
|
|
200
206
|
private _isOpen = false;
|
|
201
207
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
this._feedSetIterator.stalled.on((iterator) => {
|
|
207
|
-
log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`);
|
|
208
|
-
});
|
|
209
|
-
}
|
|
208
|
+
private _isPaused = false;
|
|
209
|
+
|
|
210
|
+
// Outbound feed writer.
|
|
211
|
+
private _writer: FeedWriter<FeedMessage.Payload> | undefined;
|
|
210
212
|
|
|
211
213
|
get state() {
|
|
212
214
|
return this._state;
|
|
@@ -218,17 +220,20 @@ export class Pipeline implements PipelineAccessor {
|
|
|
218
220
|
}
|
|
219
221
|
|
|
220
222
|
getFeeds(): FeedWrapper<FeedMessage>[] {
|
|
221
|
-
return this._feedSetIterator
|
|
223
|
+
return this._feedSetIterator!.feeds;
|
|
222
224
|
}
|
|
223
225
|
|
|
224
226
|
// NOTE: This cannot be synchronized with `stop` because stop waits for the mutation processing to complete,
|
|
225
227
|
// which might be opening feeds during the mutation processing, which w
|
|
226
228
|
async addFeed(feed: FeedWrapper<FeedMessage>) {
|
|
227
|
-
|
|
229
|
+
this._feeds.set(feed.key, feed);
|
|
230
|
+
if (this._feedSetIterator) {
|
|
231
|
+
await this._feedSetIterator.addFeed(feed);
|
|
232
|
+
}
|
|
228
233
|
}
|
|
229
234
|
|
|
230
235
|
hasFeed(feedKey: PublicKey) {
|
|
231
|
-
return this.
|
|
236
|
+
return this._feeds.has(feedKey);
|
|
232
237
|
}
|
|
233
238
|
|
|
234
239
|
setWriteFeed(feed: FeedWrapper<FeedMessage>) {
|
|
@@ -238,25 +243,69 @@ export class Pipeline implements PipelineAccessor {
|
|
|
238
243
|
this._writer = createMappedFeedWriter<FeedMessage.Payload, FeedMessage>(
|
|
239
244
|
(payload: FeedMessage.Payload) => ({
|
|
240
245
|
timeframe: this._timeframeClock.timeframe,
|
|
241
|
-
payload
|
|
246
|
+
payload,
|
|
242
247
|
}),
|
|
243
|
-
feed.createFeedWriter()
|
|
248
|
+
feed.createFeedWriter(),
|
|
244
249
|
);
|
|
245
250
|
}
|
|
246
251
|
|
|
247
252
|
@synchronized
|
|
248
253
|
async start() {
|
|
249
254
|
log('starting...', {});
|
|
250
|
-
await this.
|
|
255
|
+
await this._initIterator();
|
|
256
|
+
await this._feedSetIterator!.open();
|
|
251
257
|
log('started');
|
|
258
|
+
this._isStarted = true;
|
|
252
259
|
}
|
|
253
260
|
|
|
254
261
|
@synchronized
|
|
255
262
|
async stop() {
|
|
256
263
|
log('stopping...', {});
|
|
257
|
-
|
|
264
|
+
this._isStopping = true;
|
|
265
|
+
await this._feedSetIterator?.close();
|
|
258
266
|
await this._processingTrigger.wait(); // Wait for the in-flight message to be processed.
|
|
259
267
|
log('stopped');
|
|
268
|
+
this._isStarted = false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @param timeframe Timeframe of already processed messages. The pipeline will start processing messages AFTER this timeframe.
|
|
273
|
+
*/
|
|
274
|
+
@synchronized
|
|
275
|
+
async setCursor(timeframe: Timeframe) {
|
|
276
|
+
assert(!this._isStarted || this._isPaused, 'Invalid state.');
|
|
277
|
+
|
|
278
|
+
this._timeframeClock.setTimeframe(timeframe);
|
|
279
|
+
|
|
280
|
+
if (this._feedSetIterator) {
|
|
281
|
+
await this._feedSetIterator.close();
|
|
282
|
+
await this._initIterator();
|
|
283
|
+
await this._feedSetIterator.open();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Calling pause while processing will cause a deadlock.
|
|
289
|
+
*/
|
|
290
|
+
@synchronized
|
|
291
|
+
async pause() {
|
|
292
|
+
assert(this._isStarted, 'Pipeline is not open.');
|
|
293
|
+
if (this._isPaused) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this._pauseTrigger.reset();
|
|
298
|
+
await this._processingTrigger.wait();
|
|
299
|
+
this._isPaused = true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
@synchronized
|
|
303
|
+
async unpause() {
|
|
304
|
+
assert(this._isStarted, 'Pipeline is not open.');
|
|
305
|
+
assert(this._isPaused, 'Pipeline is not paused.');
|
|
306
|
+
|
|
307
|
+
this._pauseTrigger.wake();
|
|
308
|
+
this._isPaused = false;
|
|
260
309
|
}
|
|
261
310
|
|
|
262
311
|
/**
|
|
@@ -267,7 +316,26 @@ export class Pipeline implements PipelineAccessor {
|
|
|
267
316
|
assert(!this._isOpen, 'Pipeline is already being consumed.');
|
|
268
317
|
this._isOpen = true;
|
|
269
318
|
|
|
270
|
-
|
|
319
|
+
assert(this._feedSetIterator, 'Iterator not initialized.');
|
|
320
|
+
let lastFeedSetIterator = this._feedSetIterator;
|
|
321
|
+
let iterable = lastFeedSetIterator[Symbol.asyncIterator]();
|
|
322
|
+
|
|
323
|
+
while (!this._isStopping) {
|
|
324
|
+
await this._pauseTrigger.wait();
|
|
325
|
+
|
|
326
|
+
// Iterator might have been changed while we were waiting for the processing to complete.
|
|
327
|
+
if (lastFeedSetIterator !== this._feedSetIterator) {
|
|
328
|
+
assert(this._feedSetIterator, 'Iterator not initialized.');
|
|
329
|
+
lastFeedSetIterator = this._feedSetIterator;
|
|
330
|
+
iterable = lastFeedSetIterator[Symbol.asyncIterator]();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const { done, value } = await iterable.next();
|
|
334
|
+
if (done) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const block = value ?? failUndefined();
|
|
271
339
|
this._processingTrigger.reset();
|
|
272
340
|
this._timeframeClock.updatePendingTimeframe(PublicKey.from(block.feedKey), block.seq);
|
|
273
341
|
yield block;
|
|
@@ -279,4 +347,19 @@ export class Pipeline implements PipelineAccessor {
|
|
|
279
347
|
// TODO(burdon): Test re-entrant?
|
|
280
348
|
this._isOpen = false;
|
|
281
349
|
}
|
|
350
|
+
|
|
351
|
+
private async _initIterator() {
|
|
352
|
+
this._feedSetIterator = new FeedSetIterator<FeedMessage>(createMessageSelector(this._timeframeClock), {
|
|
353
|
+
start: startAfter(this._timeframeClock.timeframe),
|
|
354
|
+
stallTimeout: 1000,
|
|
355
|
+
});
|
|
356
|
+
this._feedSetIterator.stalled.on((iterator) => {
|
|
357
|
+
log.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`);
|
|
358
|
+
this._state.stalled.emit();
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
for (const feed of this._feeds.values()) {
|
|
362
|
+
await this._feedSetIterator.addFeed(feed);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
282
365
|
}
|
|
@@ -48,6 +48,12 @@ export class TimeframeClock {
|
|
|
48
48
|
return this._pendingTimeframe;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
setTimeframe(timeframe: Timeframe) {
|
|
52
|
+
this._timeframe = timeframe;
|
|
53
|
+
this._pendingTimeframe = timeframe;
|
|
54
|
+
this.update.emit(this._timeframe);
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
updatePendingTimeframe(key: PublicKey, seq: number) {
|
|
52
58
|
this._pendingTimeframe = Timeframe.merge(this._pendingTimeframe, new Timeframe([[key, seq]]));
|
|
53
59
|
}
|
|
@@ -64,12 +70,12 @@ export class TimeframeClock {
|
|
|
64
70
|
|
|
65
71
|
@timed(5_000)
|
|
66
72
|
async waitUntilReached(target: Timeframe) {
|
|
67
|
-
log
|
|
73
|
+
log('waitUntilReached', { target, current: this._timeframe });
|
|
68
74
|
await this.update.waitForCondition(() => {
|
|
69
75
|
log('check if reached', {
|
|
70
76
|
target,
|
|
71
77
|
current: this._timeframe,
|
|
72
|
-
deps: Timeframe.dependencies(target, this._timeframe)
|
|
78
|
+
deps: Timeframe.dependencies(target, this._timeframe),
|
|
73
79
|
});
|
|
74
80
|
|
|
75
81
|
return Timeframe.dependencies(target, this._timeframe).isEmpty();
|
package/src/space/auth.ts
CHANGED
|
@@ -27,18 +27,18 @@ export class AuthExtension extends RpcExtension<Services, Services> {
|
|
|
27
27
|
private readonly _ctx = new Context({
|
|
28
28
|
onError: (err) => {
|
|
29
29
|
log.catch(err);
|
|
30
|
-
}
|
|
30
|
+
},
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
constructor(private readonly _authParams: AuthExtensionParams) {
|
|
34
34
|
super({
|
|
35
35
|
requested: {
|
|
36
|
-
AuthService: schema.getService('dxos.mesh.teleport.auth.AuthService')
|
|
36
|
+
AuthService: schema.getService('dxos.mesh.teleport.auth.AuthService'),
|
|
37
37
|
},
|
|
38
38
|
exposed: {
|
|
39
|
-
AuthService: schema.getService('dxos.mesh.teleport.auth.AuthService')
|
|
39
|
+
AuthService: schema.getService('dxos.mesh.teleport.auth.AuthService'),
|
|
40
40
|
},
|
|
41
|
-
timeout: 60 * 1000 // Long timeout because auth can wait for sync in certain cases.
|
|
41
|
+
timeout: 60 * 1000, // Long timeout because auth can wait for sync in certain cases.
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -56,8 +56,8 @@ export class AuthExtension extends RpcExtension<Services, Services> {
|
|
|
56
56
|
log.error('failed to generate auth credentials', err);
|
|
57
57
|
throw new Error('auth rejected');
|
|
58
58
|
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -30,9 +30,9 @@ describe('space/control-pipeline', () => {
|
|
|
30
30
|
root: createStorage({ type: StorageType.RAM }).createDirectory(),
|
|
31
31
|
signer: keyring,
|
|
32
32
|
hypercore: {
|
|
33
|
-
valueEncoding
|
|
34
|
-
}
|
|
35
|
-
})
|
|
33
|
+
valueEncoding,
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
const createFeed = async () => {
|
|
@@ -45,8 +45,7 @@ describe('space/control-pipeline', () => {
|
|
|
45
45
|
const controlPipeline = new ControlPipeline({
|
|
46
46
|
spaceKey,
|
|
47
47
|
genesisFeed,
|
|
48
|
-
|
|
49
|
-
feedProvider: (key) => feedStore.openFeed(key)
|
|
48
|
+
feedProvider: (key) => feedStore.openFeed(key),
|
|
50
49
|
});
|
|
51
50
|
|
|
52
51
|
const admittedFeeds: PublicKey[] = [];
|
|
@@ -72,8 +71,8 @@ describe('space/control-pipeline', () => {
|
|
|
72
71
|
for (const credential of credentials) {
|
|
73
72
|
await controlPipeline.pipeline.writer?.write({
|
|
74
73
|
credential: {
|
|
75
|
-
credential
|
|
76
|
-
}
|
|
74
|
+
credential,
|
|
75
|
+
},
|
|
77
76
|
});
|
|
78
77
|
}
|
|
79
78
|
|
|
@@ -95,10 +94,10 @@ describe('space/control-pipeline', () => {
|
|
|
95
94
|
spaceKey,
|
|
96
95
|
identityKey,
|
|
97
96
|
deviceKey,
|
|
98
|
-
designation: AdmittedFeed.Designation.CONTROL
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
}
|
|
97
|
+
designation: AdmittedFeed.Designation.CONTROL,
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
},
|
|
102
101
|
});
|
|
103
102
|
|
|
104
103
|
await controlPipeline.pipeline.state.waitUntilTimeframe(controlPipeline.pipeline.state.endTimeframe);
|
|
@@ -119,10 +118,10 @@ describe('space/control-pipeline', () => {
|
|
|
119
118
|
spaceKey,
|
|
120
119
|
identityKey,
|
|
121
120
|
deviceKey,
|
|
122
|
-
designation: AdmittedFeed.Designation.DATA
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
}
|
|
121
|
+
designation: AdmittedFeed.Designation.DATA,
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
},
|
|
126
125
|
});
|
|
127
126
|
|
|
128
127
|
const end = controlPipeline.pipeline.state.endTimeframe;
|
|
@@ -147,12 +146,12 @@ describe('space/control-pipeline', () => {
|
|
|
147
146
|
spaceKey,
|
|
148
147
|
identityKey,
|
|
149
148
|
deviceKey,
|
|
150
|
-
designation: AdmittedFeed.Designation.DATA
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
}
|
|
149
|
+
designation: AdmittedFeed.Designation.DATA,
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
},
|
|
154
153
|
},
|
|
155
|
-
timeframe: new Timeframe()
|
|
154
|
+
timeframe: new Timeframe(),
|
|
156
155
|
});
|
|
157
156
|
|
|
158
157
|
await controlPipeline.pipeline.state.waitUntilTimeframe(controlPipeline.pipeline.state.endTimeframe);
|
|
@@ -8,7 +8,6 @@ import { PublicKey } from '@dxos/keys';
|
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
9
|
import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
|
|
10
10
|
import { AdmittedFeed, Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
11
|
-
import { Timeframe } from '@dxos/timeframe';
|
|
12
11
|
import { AsyncCallback, Callback } from '@dxos/util';
|
|
13
12
|
|
|
14
13
|
import { Pipeline, PipelineAccessor } from '../pipeline';
|
|
@@ -17,7 +16,6 @@ export type ControlPipelineParams = {
|
|
|
17
16
|
spaceKey: PublicKey;
|
|
18
17
|
genesisFeed: FeedWrapper<FeedMessage>;
|
|
19
18
|
feedProvider: (feedKey: PublicKey) => Promise<FeedWrapper<FeedMessage>>;
|
|
20
|
-
initialTimeframe?: Timeframe;
|
|
21
19
|
};
|
|
22
20
|
|
|
23
21
|
/**
|
|
@@ -31,8 +29,8 @@ export class ControlPipeline {
|
|
|
31
29
|
public readonly onMemberAdmitted: Callback<AsyncCallback<MemberInfo>>;
|
|
32
30
|
public readonly onCredentialProcessed: Callback<AsyncCallback<Credential>>;
|
|
33
31
|
|
|
34
|
-
constructor({ spaceKey, genesisFeed, feedProvider
|
|
35
|
-
this._pipeline = new Pipeline(
|
|
32
|
+
constructor({ spaceKey, genesisFeed, feedProvider }: ControlPipelineParams) {
|
|
33
|
+
this._pipeline = new Pipeline();
|
|
36
34
|
void this._pipeline.addFeed(genesisFeed); // TODO(burdon): Require async open/close?
|
|
37
35
|
|
|
38
36
|
this._spaceStateMachine = new SpaceStateMachine(spaceKey);
|
|
@@ -79,7 +77,7 @@ export class ControlPipeline {
|
|
|
79
77
|
if (msg.data.payload.credential) {
|
|
80
78
|
const result = await this._spaceStateMachine.process(
|
|
81
79
|
msg.data.payload.credential.credential,
|
|
82
|
-
PublicKey.from(msg.feedKey)
|
|
80
|
+
PublicKey.from(msg.feedKey),
|
|
83
81
|
);
|
|
84
82
|
if (!result) {
|
|
85
83
|
log.warn('processing failed', { msg });
|