@dxos/echo-pipeline 0.6.2 → 0.6.3-main.0308ae2
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-UJQ5VS5V.mjs → chunk-6MJEONOX.mjs} +2569 -1066
- package/dist/lib/browser/chunk-6MJEONOX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +12 -1049
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +224 -2
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/{chunk-RH6TDRML.cjs → chunk-PT5LWMPA.cjs} +3185 -1710
- package/dist/lib/node/chunk-PT5LWMPA.cjs.map +7 -0
- package/dist/lib/node/index.cjs +37 -1056
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +238 -13
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/types/src/automerge/automerge-host.d.ts +29 -2
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/collection-synchronizer.d.ts +61 -0
- package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -0
- package/dist/types/src/automerge/collection-synchronizer.test.d.ts +2 -0
- package/dist/types/src/automerge/collection-synchronizer.test.d.ts.map +1 -0
- package/dist/types/src/automerge/echo-network-adapter.d.ts +9 -2
- package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-replicator.d.ts +7 -0
- package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/heads-store.d.ts +1 -1
- package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
- package/dist/types/src/automerge/index.d.ts +2 -0
- package/dist/types/src/automerge/index.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +3 -1
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts +2 -2
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/network-protocol.d.ts +31 -0
- package/dist/types/src/automerge/network-protocol.d.ts.map +1 -0
- package/dist/types/src/automerge/space-collection.d.ts +4 -0
- package/dist/types/src/automerge/space-collection.d.ts.map +1 -0
- package/dist/types/src/db-host/data-service.d.ts +2 -1
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-synchronizer.d.ts +1 -1
- package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-replicator.d.ts +46 -0
- package/dist/types/src/testing/test-replicator.d.ts.map +1 -0
- package/package.json +33 -33
- package/src/automerge/automerge-host.test.ts +76 -14
- package/src/automerge/automerge-host.ts +219 -32
- package/src/automerge/automerge-repo.test.ts +2 -1
- package/src/automerge/collection-synchronizer.test.ts +91 -0
- package/src/automerge/collection-synchronizer.ts +204 -0
- package/src/automerge/echo-network-adapter.test.ts +5 -1
- package/src/automerge/echo-network-adapter.ts +69 -4
- package/src/automerge/echo-replicator.ts +9 -0
- package/src/automerge/heads-store.ts +6 -9
- package/src/automerge/index.ts +2 -0
- package/src/automerge/mesh-echo-replicator-connection.ts +6 -1
- package/src/automerge/mesh-echo-replicator.ts +28 -7
- package/src/automerge/network-protocol.ts +45 -0
- package/src/automerge/space-collection.ts +14 -0
- package/src/db-host/data-service.ts +26 -12
- package/src/db-host/documents-synchronizer.ts +17 -5
- package/src/metadata/metadata-store.ts +1 -1
- package/src/testing/index.ts +1 -0
- package/src/testing/test-replicator.ts +194 -0
- package/dist/lib/browser/chunk-UJQ5VS5V.mjs.map +0 -7
- package/dist/lib/node/chunk-RH6TDRML.cjs.map +0 -7
|
@@ -137,14 +137,39 @@ var DocumentsSynchronizer = class extends Resource {
|
|
|
137
137
|
this._pendingUpdates = /* @__PURE__ */ new Set();
|
|
138
138
|
this._sendUpdatesJob = void 0;
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
addDocuments(documentIds, retryCounter = 0) {
|
|
141
|
+
if (retryCounter > 3) {
|
|
142
|
+
log.warn("Failed to load document, retry limit reached", {
|
|
143
|
+
documentIds
|
|
144
|
+
}, {
|
|
145
|
+
F: __dxlog_file2,
|
|
146
|
+
L: 49,
|
|
147
|
+
S: this,
|
|
148
|
+
C: (f, a) => f(...a)
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
141
152
|
for (const documentId of documentIds) {
|
|
142
153
|
const doc = this._params.repo.find(documentId);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
154
|
+
doc.whenReady().then(() => {
|
|
155
|
+
this._startSync(doc);
|
|
156
|
+
this._pendingUpdates.add(doc.documentId);
|
|
157
|
+
this._sendUpdatesJob.trigger();
|
|
158
|
+
}).catch((error) => {
|
|
159
|
+
log.warn("Failed to load document, wraparound", {
|
|
160
|
+
documentId,
|
|
161
|
+
error
|
|
162
|
+
}, {
|
|
163
|
+
F: __dxlog_file2,
|
|
164
|
+
L: 63,
|
|
165
|
+
S: this,
|
|
166
|
+
C: (f, a) => f(...a)
|
|
167
|
+
});
|
|
168
|
+
this.addDocuments([
|
|
169
|
+
documentId
|
|
170
|
+
], retryCounter + 1);
|
|
171
|
+
});
|
|
146
172
|
}
|
|
147
|
-
this._sendUpdatesJob.trigger();
|
|
148
173
|
}
|
|
149
174
|
removeDocuments(documentIds) {
|
|
150
175
|
for (const documentId of documentIds) {
|
|
@@ -179,7 +204,7 @@ var DocumentsSynchronizer = class extends Resource {
|
|
|
179
204
|
documentId: doc.documentId
|
|
180
205
|
}, {
|
|
181
206
|
F: __dxlog_file2,
|
|
182
|
-
L:
|
|
207
|
+
L: 102,
|
|
183
208
|
S: this,
|
|
184
209
|
C: (f, a) => f(...a)
|
|
185
210
|
});
|
|
@@ -222,7 +247,7 @@ var DocumentsSynchronizer = class extends Resource {
|
|
|
222
247
|
const syncState = this._syncStates.get(documentId);
|
|
223
248
|
invariant2(syncState, "Sync state for document not found", {
|
|
224
249
|
F: __dxlog_file2,
|
|
225
|
-
L:
|
|
250
|
+
L: 143,
|
|
226
251
|
S: this,
|
|
227
252
|
A: [
|
|
228
253
|
"syncState",
|
|
@@ -244,7 +269,7 @@ var DocumentsSynchronizer = class extends Resource {
|
|
|
244
269
|
const syncState = this._syncStates.get(documentId);
|
|
245
270
|
invariant2(syncState, "Sync state for document not found", {
|
|
246
271
|
F: __dxlog_file2,
|
|
247
|
-
L:
|
|
272
|
+
L: 158,
|
|
248
273
|
S: this,
|
|
249
274
|
A: [
|
|
250
275
|
"syncState",
|
|
@@ -262,111 +287,276 @@ var DocumentsSynchronizer = class extends Resource {
|
|
|
262
287
|
}
|
|
263
288
|
};
|
|
264
289
|
|
|
265
|
-
// packages/core/echo/echo-pipeline/src/
|
|
266
|
-
import {
|
|
267
|
-
import {
|
|
268
|
-
import {
|
|
269
|
-
|
|
270
|
-
var
|
|
290
|
+
// packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts
|
|
291
|
+
import { asyncReturn, Event, scheduleTask, scheduleTaskInterval } from "@dxos/async";
|
|
292
|
+
import { next as am } from "@dxos/automerge/automerge";
|
|
293
|
+
import { Resource as Resource2 } from "@dxos/context";
|
|
294
|
+
import { defaultMap } from "@dxos/util";
|
|
295
|
+
var MIN_QUERY_INTERVAL = 5e3;
|
|
296
|
+
var POLL_INTERVAL = 3e4;
|
|
297
|
+
var CollectionSynchronizer = class extends Resource2 {
|
|
271
298
|
constructor(params) {
|
|
299
|
+
super();
|
|
272
300
|
/**
|
|
273
|
-
*
|
|
274
|
-
* subscriptionId -> DocumentsSynchronizer
|
|
301
|
+
* CollectionId -> State.
|
|
275
302
|
*/
|
|
276
|
-
this.
|
|
277
|
-
this.
|
|
278
|
-
this.
|
|
303
|
+
this._perCollectionStates = /* @__PURE__ */ new Map();
|
|
304
|
+
this._connectedPeers = /* @__PURE__ */ new Set();
|
|
305
|
+
this.remoteStateUpdated = new Event();
|
|
306
|
+
this._sendCollectionState = params.sendCollectionState;
|
|
307
|
+
this._queryCollectionState = params.queryCollectionState;
|
|
308
|
+
this._shouldSyncCollection = params.shouldSyncCollection;
|
|
279
309
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
310
|
+
async _open(ctx) {
|
|
311
|
+
scheduleTaskInterval(this._ctx, async () => {
|
|
312
|
+
for (const collectionId of this._perCollectionStates.keys()) {
|
|
313
|
+
this.refreshCollection(collectionId);
|
|
314
|
+
await asyncReturn();
|
|
315
|
+
}
|
|
316
|
+
}, POLL_INTERVAL);
|
|
317
|
+
}
|
|
318
|
+
getRegisteredCollectionIds() {
|
|
319
|
+
return [
|
|
320
|
+
...this._perCollectionStates.keys()
|
|
321
|
+
];
|
|
322
|
+
}
|
|
323
|
+
getLocalCollectionState(collectionId) {
|
|
324
|
+
return this._getPerCollectionState(collectionId).localState;
|
|
325
|
+
}
|
|
326
|
+
setLocalCollectionState(collectionId, state) {
|
|
327
|
+
this._getPerCollectionState(collectionId).localState = state;
|
|
328
|
+
queueMicrotask(async () => {
|
|
329
|
+
if (!this._ctx.disposed) {
|
|
330
|
+
this._refreshInterestedPeers(collectionId);
|
|
331
|
+
this.refreshCollection(collectionId);
|
|
332
|
+
}
|
|
296
333
|
});
|
|
297
334
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
335
|
+
getRemoteCollectionStates(collectionId) {
|
|
336
|
+
return this._getPerCollectionState(collectionId).remoteStates;
|
|
337
|
+
}
|
|
338
|
+
refreshCollection(collectionId) {
|
|
339
|
+
let scheduleAnotherRefresh = false;
|
|
340
|
+
const state = this._getPerCollectionState(collectionId);
|
|
341
|
+
for (const peerId of this._connectedPeers) {
|
|
342
|
+
if (state.interestedPeers.has(peerId)) {
|
|
343
|
+
const lastQueried = state.lastQueried.get(peerId) ?? 0;
|
|
344
|
+
if (Date.now() - lastQueried > MIN_QUERY_INTERVAL) {
|
|
345
|
+
state.lastQueried.set(peerId, Date.now());
|
|
346
|
+
this._queryCollectionState(collectionId, peerId);
|
|
347
|
+
} else {
|
|
348
|
+
scheduleAnotherRefresh = true;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (scheduleAnotherRefresh) {
|
|
353
|
+
scheduleTask(this._ctx, () => this.refreshCollection(collectionId), MIN_QUERY_INTERVAL);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Callback when a connection to a peer is established.
|
|
358
|
+
*/
|
|
359
|
+
onConnectionOpen(peerId) {
|
|
360
|
+
this._connectedPeers.add(peerId);
|
|
361
|
+
queueMicrotask(async () => {
|
|
362
|
+
if (this._ctx.disposed) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
for (const [collectionId, state] of this._perCollectionStates.entries()) {
|
|
366
|
+
if (this._shouldSyncCollection(collectionId, peerId)) {
|
|
367
|
+
state.interestedPeers.add(peerId);
|
|
368
|
+
state.lastQueried.set(peerId, Date.now());
|
|
369
|
+
this._queryCollectionState(collectionId, peerId);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
308
372
|
});
|
|
309
|
-
|
|
310
|
-
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Callback when a connection to a peer is closed.
|
|
376
|
+
*/
|
|
377
|
+
onConnectionClosed(peerId) {
|
|
378
|
+
this._connectedPeers.delete(peerId);
|
|
379
|
+
for (const perCollectionState of this._perCollectionStates.values()) {
|
|
380
|
+
perCollectionState.remoteStates.delete(peerId);
|
|
311
381
|
}
|
|
312
|
-
|
|
313
|
-
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Callback when a peer queries the state of a collection.
|
|
385
|
+
*/
|
|
386
|
+
onCollectionStateQueried(collectionId, peerId) {
|
|
387
|
+
const perCollectionState = this._getPerCollectionState(collectionId);
|
|
388
|
+
if (perCollectionState.localState) {
|
|
389
|
+
this._sendCollectionState(collectionId, peerId, perCollectionState.localState);
|
|
314
390
|
}
|
|
315
391
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
392
|
+
/**
|
|
393
|
+
* Callback when a peer sends the state of a collection.
|
|
394
|
+
*/
|
|
395
|
+
onRemoteStateReceived(collectionId, peerId, state) {
|
|
396
|
+
const perCollectionState = this._getPerCollectionState(collectionId);
|
|
397
|
+
perCollectionState.remoteStates.set(peerId, state);
|
|
398
|
+
this.remoteStateUpdated.emit({
|
|
399
|
+
peerId,
|
|
400
|
+
collectionId
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
_getPerCollectionState(collectionId) {
|
|
404
|
+
return defaultMap(this._perCollectionStates, collectionId, () => ({
|
|
405
|
+
localState: void 0,
|
|
406
|
+
remoteStates: /* @__PURE__ */ new Map(),
|
|
407
|
+
interestedPeers: /* @__PURE__ */ new Set(),
|
|
408
|
+
lastQueried: /* @__PURE__ */ new Map()
|
|
409
|
+
}));
|
|
410
|
+
}
|
|
411
|
+
_refreshInterestedPeers(collectionId) {
|
|
412
|
+
for (const peerId of this._connectedPeers) {
|
|
413
|
+
if (this._shouldSyncCollection(collectionId, peerId)) {
|
|
414
|
+
this._getPerCollectionState(collectionId).interestedPeers.add(peerId);
|
|
415
|
+
} else {
|
|
416
|
+
this._getPerCollectionState(collectionId).interestedPeers.delete(peerId);
|
|
417
|
+
}
|
|
319
418
|
}
|
|
320
|
-
const synchronizer = this._subscriptions.get(request.subscriptionId);
|
|
321
|
-
invariant3(synchronizer, "Subscription not found", {
|
|
322
|
-
F: __dxlog_file3,
|
|
323
|
-
L: 84,
|
|
324
|
-
S: this,
|
|
325
|
-
A: [
|
|
326
|
-
"synchronizer",
|
|
327
|
-
"'Subscription not found'"
|
|
328
|
-
]
|
|
329
|
-
});
|
|
330
|
-
synchronizer.update(request.updates);
|
|
331
419
|
}
|
|
332
|
-
|
|
333
|
-
|
|
420
|
+
};
|
|
421
|
+
var diffCollectionState = (local, remote) => {
|
|
422
|
+
const allDocuments = /* @__PURE__ */ new Set([
|
|
423
|
+
...Object.keys(local.documents),
|
|
424
|
+
...Object.keys(remote.documents)
|
|
425
|
+
]);
|
|
426
|
+
const different = [];
|
|
427
|
+
for (const documentId of allDocuments) {
|
|
428
|
+
if (!local.documents[documentId] || !remote.documents[documentId] || !am.equals(local.documents[documentId], remote.documents[documentId])) {
|
|
429
|
+
different.push(documentId);
|
|
430
|
+
}
|
|
334
431
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
432
|
+
return {
|
|
433
|
+
different
|
|
434
|
+
};
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// packages/core/echo/echo-pipeline/src/automerge/leveldb-storage-adapter.ts
|
|
438
|
+
import { LifecycleState, Resource as Resource3 } from "@dxos/context";
|
|
439
|
+
var LevelDBStorageAdapter = class extends Resource3 {
|
|
440
|
+
constructor(_params) {
|
|
441
|
+
super();
|
|
442
|
+
this._params = _params;
|
|
443
|
+
}
|
|
444
|
+
async load(keyArray) {
|
|
445
|
+
try {
|
|
446
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
447
|
+
return void 0;
|
|
346
448
|
}
|
|
347
|
-
|
|
449
|
+
return await this._params.db.get(keyArray, {
|
|
450
|
+
...encodingOptions
|
|
451
|
+
});
|
|
452
|
+
} catch (err) {
|
|
453
|
+
if (isLevelDbNotFoundError(err)) {
|
|
454
|
+
return void 0;
|
|
455
|
+
}
|
|
456
|
+
throw err;
|
|
457
|
+
}
|
|
348
458
|
}
|
|
349
|
-
async
|
|
350
|
-
|
|
459
|
+
async save(keyArray, binary) {
|
|
460
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
461
|
+
return void 0;
|
|
462
|
+
}
|
|
463
|
+
const batch = this._params.db.batch();
|
|
464
|
+
await this._params.callbacks?.beforeSave?.({
|
|
465
|
+
path: keyArray,
|
|
466
|
+
batch
|
|
467
|
+
});
|
|
468
|
+
batch.put(keyArray, Buffer.from(binary), {
|
|
469
|
+
...encodingOptions
|
|
470
|
+
});
|
|
471
|
+
await batch.write();
|
|
472
|
+
await this._params.callbacks?.afterSave?.(keyArray);
|
|
351
473
|
}
|
|
352
|
-
async
|
|
353
|
-
|
|
474
|
+
async remove(keyArray) {
|
|
475
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
476
|
+
return void 0;
|
|
477
|
+
}
|
|
478
|
+
await this._params.db.del(keyArray, {
|
|
479
|
+
...encodingOptions
|
|
480
|
+
});
|
|
354
481
|
}
|
|
355
|
-
async
|
|
356
|
-
|
|
482
|
+
async loadRange(keyPrefix) {
|
|
483
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
484
|
+
return [];
|
|
485
|
+
}
|
|
486
|
+
const result = [];
|
|
487
|
+
for await (const [key, value] of this._params.db.iterator({
|
|
488
|
+
gte: keyPrefix,
|
|
489
|
+
lte: [
|
|
490
|
+
...keyPrefix,
|
|
491
|
+
"\uFFFF"
|
|
492
|
+
],
|
|
493
|
+
...encodingOptions
|
|
494
|
+
})) {
|
|
495
|
+
result.push({
|
|
496
|
+
key,
|
|
497
|
+
data: value
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
return result;
|
|
501
|
+
}
|
|
502
|
+
async removeRange(keyPrefix) {
|
|
503
|
+
if (this._lifecycleState !== LifecycleState.OPEN) {
|
|
504
|
+
return void 0;
|
|
505
|
+
}
|
|
506
|
+
const batch = this._params.db.batch();
|
|
507
|
+
for await (const [key] of this._params.db.iterator({
|
|
508
|
+
gte: keyPrefix,
|
|
509
|
+
lte: [
|
|
510
|
+
...keyPrefix,
|
|
511
|
+
"\uFFFF"
|
|
512
|
+
],
|
|
513
|
+
...encodingOptions
|
|
514
|
+
})) {
|
|
515
|
+
batch.del(key, {
|
|
516
|
+
...encodingOptions
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
await batch.write();
|
|
357
520
|
}
|
|
358
521
|
};
|
|
522
|
+
var keyEncoder = {
|
|
523
|
+
encode: (key) => Buffer.from(key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-")),
|
|
524
|
+
decode: (key) => Buffer.from(key).toString().split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%")),
|
|
525
|
+
format: "buffer"
|
|
526
|
+
};
|
|
527
|
+
var encodingOptions = {
|
|
528
|
+
keyEncoding: keyEncoder,
|
|
529
|
+
valueEncoding: "buffer"
|
|
530
|
+
};
|
|
531
|
+
var isLevelDbNotFoundError = (err) => err.code === "LEVEL_NOT_FOUND";
|
|
359
532
|
|
|
360
|
-
// packages/core/echo/echo-pipeline/src/
|
|
361
|
-
import
|
|
362
|
-
import {
|
|
363
|
-
import {
|
|
533
|
+
// packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
|
|
534
|
+
import { Event as Event2, asyncTimeout } from "@dxos/async";
|
|
535
|
+
import { next as automerge, getBackend, getHeads, isAutomerge, equals as headsEquals, save } from "@dxos/automerge/automerge";
|
|
536
|
+
import { Repo } from "@dxos/automerge/automerge-repo";
|
|
537
|
+
import { Context, Resource as Resource4, cancelWithContext as cancelWithContext2 } from "@dxos/context";
|
|
364
538
|
import { invariant as invariant4 } from "@dxos/invariant";
|
|
365
539
|
import { PublicKey as PublicKey2 } from "@dxos/keys";
|
|
366
540
|
import { log as log3 } from "@dxos/log";
|
|
367
|
-
import {
|
|
368
|
-
import {
|
|
369
|
-
import {
|
|
541
|
+
import { objectPointerCodec } from "@dxos/protocols";
|
|
542
|
+
import { trace } from "@dxos/tracing";
|
|
543
|
+
import { mapValues } from "@dxos/util";
|
|
544
|
+
|
|
545
|
+
// packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
|
|
546
|
+
import { synchronized, Trigger } from "@dxos/async";
|
|
547
|
+
import { NetworkAdapter } from "@dxos/automerge/automerge-repo";
|
|
548
|
+
import { LifecycleState as LifecycleState2 } from "@dxos/context";
|
|
549
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
550
|
+
import { log as log2 } from "@dxos/log";
|
|
551
|
+
import { nonNullable } from "@dxos/util";
|
|
552
|
+
|
|
553
|
+
// packages/core/echo/echo-pipeline/src/automerge/network-protocol.ts
|
|
554
|
+
var MESSAGE_TYPE_COLLECTION_QUERY = "collection-query";
|
|
555
|
+
var isCollectionQueryMessage = (message) => message.type === MESSAGE_TYPE_COLLECTION_QUERY;
|
|
556
|
+
var MESSAGE_TYPE_COLLECTION_STATE = "collection-state";
|
|
557
|
+
var isCollectionStateMessage = (message) => message.type === MESSAGE_TYPE_COLLECTION_STATE;
|
|
558
|
+
|
|
559
|
+
// packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
|
|
370
560
|
function _ts_decorate(decorators, target, key, desc) {
|
|
371
561
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
372
562
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
@@ -377,334 +567,348 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
377
567
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
378
568
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
379
569
|
}
|
|
380
|
-
var
|
|
381
|
-
var
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
this.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
570
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts";
|
|
571
|
+
var EchoNetworkAdapter = class extends NetworkAdapter {
|
|
572
|
+
constructor(_params) {
|
|
573
|
+
super();
|
|
574
|
+
this._params = _params;
|
|
575
|
+
this._replicators = /* @__PURE__ */ new Set();
|
|
576
|
+
this._connections = /* @__PURE__ */ new Map();
|
|
577
|
+
this._lifecycleState = LifecycleState2.CLOSED;
|
|
578
|
+
this._connected = new Trigger();
|
|
579
|
+
}
|
|
580
|
+
connect(peerId, peerMetadata) {
|
|
581
|
+
this.peerId = peerId;
|
|
582
|
+
this.peerMetadata = peerMetadata;
|
|
583
|
+
this._connected.wake();
|
|
584
|
+
}
|
|
585
|
+
send(message) {
|
|
586
|
+
const connectionEntry = this._connections.get(message.targetId);
|
|
587
|
+
if (!connectionEntry) {
|
|
588
|
+
throw new Error("Connection not found.");
|
|
589
|
+
}
|
|
590
|
+
connectionEntry.writer.write(message).catch((err) => {
|
|
591
|
+
if (connectionEntry.isOpen) {
|
|
592
|
+
log2.catch(err, void 0, {
|
|
593
|
+
F: __dxlog_file3,
|
|
594
|
+
L: 63,
|
|
595
|
+
S: this,
|
|
596
|
+
C: (f, a) => f(...a)
|
|
597
|
+
});
|
|
598
|
+
}
|
|
400
599
|
});
|
|
401
|
-
this._directory = directory;
|
|
402
|
-
}
|
|
403
|
-
get metadata() {
|
|
404
|
-
return this._metadata;
|
|
405
|
-
}
|
|
406
|
-
get version() {
|
|
407
|
-
return this._metadata.version ?? 0;
|
|
408
600
|
}
|
|
409
|
-
|
|
410
|
-
* Returns a list of currently saved spaces. The list and objects in it can be modified addSpace and
|
|
411
|
-
* addSpaceFeed functions.
|
|
412
|
-
*/
|
|
413
|
-
get spaces() {
|
|
414
|
-
return this._metadata.spaces ?? [];
|
|
601
|
+
disconnect() {
|
|
415
602
|
}
|
|
416
|
-
async
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
if (fileLength < 8) {
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
const dataSize = fromBytesInt32(await file.read(0, 4));
|
|
423
|
-
const checksum = fromBytesInt32(await file.read(4, 4));
|
|
424
|
-
log3("loaded", {
|
|
425
|
-
size: dataSize,
|
|
426
|
-
checksum,
|
|
427
|
-
name: file.filename
|
|
428
|
-
}, {
|
|
429
|
-
F: __dxlog_file4,
|
|
430
|
-
L: 89,
|
|
431
|
-
S: this,
|
|
432
|
-
C: (f, a) => f(...a)
|
|
433
|
-
});
|
|
434
|
-
if (fileLength < dataSize + 8) {
|
|
435
|
-
throw new DataCorruptionError("Metadata size is smaller than expected.", {
|
|
436
|
-
fileLength,
|
|
437
|
-
dataSize
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
const data = await file.read(8, dataSize);
|
|
441
|
-
const calculatedChecksum = CRC32.buf(data);
|
|
442
|
-
if (calculatedChecksum !== checksum) {
|
|
443
|
-
throw new DataCorruptionError("Metadata checksum is invalid.");
|
|
444
|
-
}
|
|
445
|
-
return codec2.decode(data);
|
|
446
|
-
} finally {
|
|
447
|
-
await file.close();
|
|
603
|
+
async open() {
|
|
604
|
+
if (this._lifecycleState === LifecycleState2.OPEN) {
|
|
605
|
+
return;
|
|
448
606
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
async _writeFile(file, codec2, data) {
|
|
454
|
-
const encoded = arrayToBuffer(codec2.encode(data));
|
|
455
|
-
const checksum = CRC32.buf(encoded);
|
|
456
|
-
const result = Buffer.alloc(8 + encoded.length);
|
|
457
|
-
result.writeInt32LE(encoded.length, 0);
|
|
458
|
-
result.writeInt32LE(checksum, 4);
|
|
459
|
-
encoded.copy(result, 8);
|
|
460
|
-
await file.write(0, result);
|
|
461
|
-
log3("saved", {
|
|
462
|
-
size: encoded.length,
|
|
463
|
-
checksum
|
|
464
|
-
}, {
|
|
465
|
-
F: __dxlog_file4,
|
|
466
|
-
L: 124,
|
|
607
|
+
this._lifecycleState = LifecycleState2.OPEN;
|
|
608
|
+
log2("emit ready", void 0, {
|
|
609
|
+
F: __dxlog_file3,
|
|
610
|
+
L: 79,
|
|
467
611
|
S: this,
|
|
468
612
|
C: (f, a) => f(...a)
|
|
469
613
|
});
|
|
614
|
+
this.emit("ready", {
|
|
615
|
+
network: this
|
|
616
|
+
});
|
|
470
617
|
}
|
|
471
618
|
async close() {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
await this._metadataFile?.close();
|
|
475
|
-
this._metadataFile = void 0;
|
|
476
|
-
this._metadata = emptyEchoMetadata();
|
|
477
|
-
this._spaceLargeMetadata.clear();
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Loads metadata from persistent storage.
|
|
481
|
-
*/
|
|
482
|
-
async load() {
|
|
483
|
-
if (!this._metadataFile || this._metadataFile.closed) {
|
|
484
|
-
this._metadataFile = this._directory.getOrCreateFile("EchoMetadata");
|
|
619
|
+
if (this._lifecycleState === LifecycleState2.CLOSED) {
|
|
620
|
+
return this;
|
|
485
621
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (metadata) {
|
|
489
|
-
this._metadata = metadata;
|
|
490
|
-
}
|
|
491
|
-
this._metadata.spaces?.forEach((space) => {
|
|
492
|
-
space.state ??= SpaceState.ACTIVE;
|
|
493
|
-
});
|
|
494
|
-
} catch (err) {
|
|
495
|
-
log3.error("failed to load metadata", {
|
|
496
|
-
err
|
|
497
|
-
}, {
|
|
498
|
-
F: __dxlog_file4,
|
|
499
|
-
L: 156,
|
|
500
|
-
S: this,
|
|
501
|
-
C: (f, a) => f(...a)
|
|
502
|
-
});
|
|
503
|
-
this._metadata = emptyEchoMetadata();
|
|
622
|
+
for (const replicator of this._replicators) {
|
|
623
|
+
await replicator.disconnect();
|
|
504
624
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
...this._metadata.spaces?.map((space) => space.key) ?? []
|
|
508
|
-
].filter(isNotNullOrUndefined), async (key) => {
|
|
509
|
-
try {
|
|
510
|
-
await this._loadSpaceLargeMetadata(key);
|
|
511
|
-
} catch (err) {
|
|
512
|
-
log3.error("failed to load space large metadata", {
|
|
513
|
-
err
|
|
514
|
-
}, {
|
|
515
|
-
F: __dxlog_file4,
|
|
516
|
-
L: 168,
|
|
517
|
-
S: this,
|
|
518
|
-
C: (f, a) => f(...a)
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
});
|
|
522
|
-
scheduleTaskInterval(this._invitationCleanupCtx, async () => {
|
|
523
|
-
for (const invitation of this._metadata.invitations ?? []) {
|
|
524
|
-
if (hasInvitationExpired(invitation) || isLegacyInvitationFormat(invitation)) {
|
|
525
|
-
await this.removeInvitation(invitation.invitationId);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}, EXPIRED_INVITATION_CLEANUP_INTERVAL);
|
|
625
|
+
this._replicators.clear();
|
|
626
|
+
this._lifecycleState = LifecycleState2.CLOSED;
|
|
529
627
|
}
|
|
530
|
-
async
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
created: this._metadata.created ?? /* @__PURE__ */ new Date(),
|
|
535
|
-
updated: /* @__PURE__ */ new Date()
|
|
536
|
-
};
|
|
537
|
-
this.update.emit(data);
|
|
538
|
-
const file = this._directory.getOrCreateFile("EchoMetadata");
|
|
539
|
-
await this._writeFile(file, EchoMetadata, data);
|
|
628
|
+
async whenConnected() {
|
|
629
|
+
await this._connected.wait({
|
|
630
|
+
timeout: 1e4
|
|
631
|
+
});
|
|
540
632
|
}
|
|
541
|
-
async
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
633
|
+
async addReplicator(replicator) {
|
|
634
|
+
invariant3(this._lifecycleState === LifecycleState2.OPEN, void 0, {
|
|
635
|
+
F: __dxlog_file3,
|
|
636
|
+
L: 105,
|
|
637
|
+
S: this,
|
|
638
|
+
A: [
|
|
639
|
+
"this._lifecycleState === LifecycleState.OPEN",
|
|
640
|
+
""
|
|
641
|
+
]
|
|
642
|
+
});
|
|
643
|
+
invariant3(this.peerId, void 0, {
|
|
644
|
+
F: __dxlog_file3,
|
|
645
|
+
L: 106,
|
|
646
|
+
S: this,
|
|
647
|
+
A: [
|
|
648
|
+
"this.peerId",
|
|
649
|
+
""
|
|
650
|
+
]
|
|
651
|
+
});
|
|
652
|
+
invariant3(!this._replicators.has(replicator), void 0, {
|
|
653
|
+
F: __dxlog_file3,
|
|
654
|
+
L: 107,
|
|
655
|
+
S: this,
|
|
656
|
+
A: [
|
|
657
|
+
"!this._replicators.has(replicator)",
|
|
658
|
+
""
|
|
659
|
+
]
|
|
660
|
+
});
|
|
661
|
+
this._replicators.add(replicator);
|
|
662
|
+
await replicator.connect({
|
|
663
|
+
peerId: this.peerId,
|
|
664
|
+
onConnectionOpen: this._onConnectionOpen.bind(this),
|
|
665
|
+
onConnectionClosed: this._onConnectionClosed.bind(this),
|
|
666
|
+
onConnectionAuthScopeChanged: this._onConnectionAuthScopeChanged.bind(this),
|
|
667
|
+
getContainingSpaceForDocument: this._params.getContainingSpaceForDocument
|
|
668
|
+
});
|
|
558
669
|
}
|
|
559
|
-
async
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
670
|
+
async removeReplicator(replicator) {
|
|
671
|
+
invariant3(this._lifecycleState === LifecycleState2.OPEN, void 0, {
|
|
672
|
+
F: __dxlog_file3,
|
|
673
|
+
L: 121,
|
|
674
|
+
S: this,
|
|
675
|
+
A: [
|
|
676
|
+
"this._lifecycleState === LifecycleState.OPEN",
|
|
677
|
+
""
|
|
678
|
+
]
|
|
679
|
+
});
|
|
680
|
+
invariant3(this._replicators.has(replicator), void 0, {
|
|
681
|
+
F: __dxlog_file3,
|
|
682
|
+
L: 122,
|
|
683
|
+
S: this,
|
|
684
|
+
A: [
|
|
685
|
+
"this._replicators.has(replicator)",
|
|
686
|
+
""
|
|
687
|
+
]
|
|
688
|
+
});
|
|
689
|
+
await replicator.disconnect();
|
|
690
|
+
this._replicators.delete(replicator);
|
|
563
691
|
}
|
|
564
|
-
async
|
|
565
|
-
|
|
692
|
+
async shouldAdvertise(peerId, params) {
|
|
693
|
+
const connection = this._connections.get(peerId);
|
|
694
|
+
if (!connection) {
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
return connection.connection.shouldAdvertise(params);
|
|
566
698
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
699
|
+
shouldSyncCollection(peerId, params) {
|
|
700
|
+
const connection = this._connections.get(peerId);
|
|
701
|
+
if (!connection) {
|
|
702
|
+
return false;
|
|
570
703
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
704
|
+
return connection.connection.shouldSyncCollection(params);
|
|
705
|
+
}
|
|
706
|
+
queryCollectionState(collectionId, targetId) {
|
|
707
|
+
const message = {
|
|
708
|
+
type: "collection-query",
|
|
709
|
+
senderId: this.peerId,
|
|
710
|
+
targetId,
|
|
711
|
+
collectionId
|
|
712
|
+
};
|
|
713
|
+
this.send(message);
|
|
714
|
+
}
|
|
715
|
+
sendCollectionState(collectionId, targetId, state) {
|
|
716
|
+
const message = {
|
|
717
|
+
type: "collection-state",
|
|
718
|
+
senderId: this.peerId,
|
|
719
|
+
targetId,
|
|
720
|
+
collectionId,
|
|
721
|
+
state
|
|
722
|
+
};
|
|
723
|
+
this.send(message);
|
|
724
|
+
}
|
|
725
|
+
// TODO(dmaretskyi): Remove.
|
|
726
|
+
getPeersInterestedInCollection(collectionId) {
|
|
727
|
+
return Array.from(this._connections.values()).map((connection) => {
|
|
728
|
+
return connection.connection.shouldSyncCollection({
|
|
729
|
+
collectionId
|
|
730
|
+
}) ? connection.connection.peerId : null;
|
|
731
|
+
}).filter(nonNullable);
|
|
732
|
+
}
|
|
733
|
+
_onConnectionOpen(connection) {
|
|
734
|
+
log2("Connection opened", {
|
|
735
|
+
peerId: connection.peerId
|
|
736
|
+
}, {
|
|
737
|
+
F: __dxlog_file3,
|
|
738
|
+
L: 178,
|
|
739
|
+
S: this,
|
|
740
|
+
C: (f, a) => f(...a)
|
|
741
|
+
});
|
|
742
|
+
invariant3(!this._connections.has(connection.peerId), void 0, {
|
|
743
|
+
F: __dxlog_file3,
|
|
744
|
+
L: 179,
|
|
575
745
|
S: this,
|
|
576
746
|
A: [
|
|
577
|
-
"
|
|
578
|
-
"
|
|
747
|
+
"!this._connections.has(connection.peerId as PeerId)",
|
|
748
|
+
""
|
|
579
749
|
]
|
|
580
750
|
});
|
|
581
|
-
|
|
751
|
+
const reader = connection.readable.getReader();
|
|
752
|
+
const writer = connection.writable.getWriter();
|
|
753
|
+
const connectionEntry = {
|
|
754
|
+
connection,
|
|
755
|
+
reader,
|
|
756
|
+
writer,
|
|
757
|
+
isOpen: true
|
|
758
|
+
};
|
|
759
|
+
this._connections.set(connection.peerId, connectionEntry);
|
|
760
|
+
queueMicrotask(async () => {
|
|
761
|
+
try {
|
|
762
|
+
while (true) {
|
|
763
|
+
const { done, value } = await reader.read();
|
|
764
|
+
if (done) {
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
767
|
+
this._onMessage(value);
|
|
768
|
+
}
|
|
769
|
+
} catch (err) {
|
|
770
|
+
if (connectionEntry.isOpen) {
|
|
771
|
+
log2.catch(err, void 0, {
|
|
772
|
+
F: __dxlog_file3,
|
|
773
|
+
L: 198,
|
|
774
|
+
S: this,
|
|
775
|
+
C: (f, a) => f(...a)
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
log2("emit peer-candidate", {
|
|
781
|
+
peerId: connection.peerId
|
|
782
|
+
}, {
|
|
783
|
+
F: __dxlog_file3,
|
|
784
|
+
L: 203,
|
|
785
|
+
S: this,
|
|
786
|
+
C: (f, a) => f(...a)
|
|
787
|
+
});
|
|
788
|
+
this._emitPeerCandidate(connection);
|
|
582
789
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
790
|
+
_onMessage(message) {
|
|
791
|
+
if (isCollectionQueryMessage(message)) {
|
|
792
|
+
this._params.onCollectionStateQueried(message.collectionId, message.senderId);
|
|
793
|
+
} else if (isCollectionStateMessage(message)) {
|
|
794
|
+
this._params.onCollectionStateReceived(message.collectionId, message.senderId, message.state);
|
|
795
|
+
} else {
|
|
796
|
+
this.emit("message", message);
|
|
587
797
|
}
|
|
588
|
-
entry = emptyLargeSpaceMetadata();
|
|
589
|
-
this._spaceLargeMetadata.set(key, entry);
|
|
590
|
-
return entry;
|
|
591
798
|
}
|
|
592
799
|
/**
|
|
593
|
-
*
|
|
800
|
+
* Trigger doc-synchronizer shared documents set recalculation. Happens on peer-candidate.
|
|
801
|
+
* TODO(y): replace with a proper API call when sharePolicy update becomes supported by automerge-repo
|
|
594
802
|
*/
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
803
|
+
_onConnectionAuthScopeChanged(connection) {
|
|
804
|
+
log2("Connection auth scope changed", {
|
|
805
|
+
peerId: connection.peerId
|
|
806
|
+
}, {
|
|
807
|
+
F: __dxlog_file3,
|
|
808
|
+
L: 222,
|
|
599
809
|
S: this,
|
|
600
810
|
C: (f, a) => f(...a)
|
|
601
811
|
});
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
return this._metadata.identity;
|
|
607
|
-
}
|
|
608
|
-
async setIdentityRecord(record) {
|
|
609
|
-
invariant4(!this._metadata.identity, "Cannot overwrite existing identity in metadata", {
|
|
610
|
-
F: __dxlog_file4,
|
|
611
|
-
L: 261,
|
|
812
|
+
const entry = this._connections.get(connection.peerId);
|
|
813
|
+
invariant3(entry, void 0, {
|
|
814
|
+
F: __dxlog_file3,
|
|
815
|
+
L: 224,
|
|
612
816
|
S: this,
|
|
613
817
|
A: [
|
|
614
|
-
"
|
|
615
|
-
"
|
|
818
|
+
"entry",
|
|
819
|
+
""
|
|
616
820
|
]
|
|
617
821
|
});
|
|
618
|
-
this.
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
getInvitations() {
|
|
623
|
-
return this._metadata.invitations ?? [];
|
|
624
|
-
}
|
|
625
|
-
async addInvitation(invitation) {
|
|
626
|
-
if (this._metadata.invitations?.find((i) => i.invitationId === invitation.invitationId)) {
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
(this._metadata.invitations ??= []).push(invitation);
|
|
630
|
-
await this._save();
|
|
631
|
-
await this.flush();
|
|
632
|
-
}
|
|
633
|
-
async removeInvitation(invitationId) {
|
|
634
|
-
this._metadata.invitations = (this._metadata.invitations ?? []).filter((i) => i.invitationId !== invitationId);
|
|
635
|
-
await this._save();
|
|
636
|
-
await this.flush();
|
|
822
|
+
this.emit("peer-disconnected", {
|
|
823
|
+
peerId: connection.peerId
|
|
824
|
+
});
|
|
825
|
+
this._emitPeerCandidate(connection);
|
|
637
826
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
827
|
+
_onConnectionClosed(connection) {
|
|
828
|
+
log2("Connection closed", {
|
|
829
|
+
peerId: connection.peerId
|
|
830
|
+
}, {
|
|
831
|
+
F: __dxlog_file3,
|
|
832
|
+
L: 230,
|
|
833
|
+
S: this,
|
|
834
|
+
C: (f, a) => f(...a)
|
|
835
|
+
});
|
|
836
|
+
const entry = this._connections.get(connection.peerId);
|
|
837
|
+
invariant3(entry, void 0, {
|
|
838
|
+
F: __dxlog_file3,
|
|
839
|
+
L: 232,
|
|
642
840
|
S: this,
|
|
643
841
|
A: [
|
|
644
|
-
"
|
|
645
|
-
"
|
|
842
|
+
"entry",
|
|
843
|
+
""
|
|
646
844
|
]
|
|
647
845
|
});
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
async setWritableFeedKeys(spaceKey, controlFeedKey, dataFeedKey) {
|
|
666
|
-
const space = this._getSpace(spaceKey);
|
|
667
|
-
space.controlFeedKey = controlFeedKey;
|
|
668
|
-
space.dataFeedKey = dataFeedKey;
|
|
669
|
-
await this._save();
|
|
670
|
-
await this.flush();
|
|
671
|
-
}
|
|
672
|
-
async setSpaceState(spaceKey, state) {
|
|
673
|
-
this._getSpace(spaceKey).state = state;
|
|
674
|
-
await this._save();
|
|
675
|
-
await this.flush();
|
|
676
|
-
}
|
|
677
|
-
getSpaceControlPipelineSnapshot(spaceKey) {
|
|
678
|
-
return this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot;
|
|
846
|
+
entry.isOpen = false;
|
|
847
|
+
this.emit("peer-disconnected", {
|
|
848
|
+
peerId: connection.peerId
|
|
849
|
+
});
|
|
850
|
+
void entry.reader.cancel().catch((err) => log2.catch(err, void 0, {
|
|
851
|
+
F: __dxlog_file3,
|
|
852
|
+
L: 237,
|
|
853
|
+
S: this,
|
|
854
|
+
C: (f, a) => f(...a)
|
|
855
|
+
}));
|
|
856
|
+
void entry.writer.abort().catch((err) => log2.catch(err, void 0, {
|
|
857
|
+
F: __dxlog_file3,
|
|
858
|
+
L: 238,
|
|
859
|
+
S: this,
|
|
860
|
+
C: (f, a) => f(...a)
|
|
861
|
+
}));
|
|
862
|
+
this._connections.delete(connection.peerId);
|
|
679
863
|
}
|
|
680
|
-
|
|
681
|
-
this.
|
|
682
|
-
|
|
683
|
-
|
|
864
|
+
_emitPeerCandidate(connection) {
|
|
865
|
+
this.emit("peer-candidate", {
|
|
866
|
+
peerId: connection.peerId,
|
|
867
|
+
peerMetadata: createEchoPeerMetadata()
|
|
868
|
+
});
|
|
684
869
|
}
|
|
685
870
|
};
|
|
686
871
|
_ts_decorate([
|
|
687
872
|
synchronized
|
|
688
|
-
],
|
|
873
|
+
], EchoNetworkAdapter.prototype, "open", null);
|
|
689
874
|
_ts_decorate([
|
|
690
875
|
synchronized
|
|
691
|
-
],
|
|
876
|
+
], EchoNetworkAdapter.prototype, "close", null);
|
|
692
877
|
_ts_decorate([
|
|
693
878
|
synchronized
|
|
694
|
-
],
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
879
|
+
], EchoNetworkAdapter.prototype, "addReplicator", null);
|
|
880
|
+
_ts_decorate([
|
|
881
|
+
synchronized
|
|
882
|
+
], EchoNetworkAdapter.prototype, "removeReplicator", null);
|
|
883
|
+
var createEchoPeerMetadata = () => ({
|
|
884
|
+
// TODO(dmaretskyi): Refactor this.
|
|
885
|
+
dxos_peerSource: "EchoNetworkAdapter"
|
|
886
|
+
});
|
|
887
|
+
var isEchoPeerMetadata = (metadata) => metadata?.dxos_peerSource === "EchoNetworkAdapter";
|
|
888
|
+
|
|
889
|
+
// packages/core/echo/echo-pipeline/src/automerge/heads-store.ts
|
|
890
|
+
import { headsEncoding } from "@dxos/indexing";
|
|
891
|
+
var HeadsStore = class {
|
|
892
|
+
constructor({ db }) {
|
|
893
|
+
this._db = db;
|
|
894
|
+
}
|
|
895
|
+
setHeads(documentId, heads, batch) {
|
|
896
|
+
batch.put(documentId, heads, {
|
|
897
|
+
sublevel: this._db,
|
|
898
|
+
keyEncoding: "utf8",
|
|
899
|
+
valueEncoding: headsEncoding
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
// TODO(dmaretskyi): Make batched.
|
|
903
|
+
async getHeads(documentIds) {
|
|
904
|
+
return this._db.getMany(documentIds, {
|
|
905
|
+
keyEncoding: "utf8",
|
|
906
|
+
valueEncoding: headsEncoding
|
|
907
|
+
});
|
|
908
|
+
}
|
|
701
909
|
};
|
|
702
910
|
|
|
703
|
-
// packages/core/echo/echo-pipeline/src/
|
|
704
|
-
import { Event as Event2 } from "@dxos/async";
|
|
705
|
-
import { timed } from "@dxos/debug";
|
|
706
|
-
import { log as log4 } from "@dxos/log";
|
|
707
|
-
import { Timeframe } from "@dxos/timeframe";
|
|
911
|
+
// packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
|
|
708
912
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
709
913
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
710
914
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
@@ -715,238 +919,845 @@ function _ts_decorate2(decorators, target, key, desc) {
|
|
|
715
919
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
716
920
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
717
921
|
}
|
|
718
|
-
var
|
|
719
|
-
var
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
this.
|
|
734
|
-
|
|
735
|
-
|
|
922
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
|
|
923
|
+
var AutomergeHost = class extends Resource4 {
|
|
924
|
+
constructor({ db, indexMetadataStore }) {
|
|
925
|
+
super();
|
|
926
|
+
this._echoNetworkAdapter = new EchoNetworkAdapter({
|
|
927
|
+
getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this),
|
|
928
|
+
onCollectionStateQueried: this._onCollectionStateQueried.bind(this),
|
|
929
|
+
onCollectionStateReceived: this._onCollectionStateReceived.bind(this)
|
|
930
|
+
});
|
|
931
|
+
this._collectionSynchronizer = new CollectionSynchronizer({
|
|
932
|
+
queryCollectionState: this._queryCollectionState.bind(this),
|
|
933
|
+
sendCollectionState: this._sendCollectionState.bind(this),
|
|
934
|
+
shouldSyncCollection: this._shouldSyncCollection.bind(this)
|
|
935
|
+
});
|
|
936
|
+
this._db = db;
|
|
937
|
+
this._storage = new LevelDBStorageAdapter({
|
|
938
|
+
db: db.sublevel("automerge"),
|
|
939
|
+
callbacks: {
|
|
940
|
+
beforeSave: async (params) => this._beforeSave(params),
|
|
941
|
+
afterSave: async (key) => this._afterSave(key)
|
|
942
|
+
}
|
|
943
|
+
});
|
|
944
|
+
this._headsStore = new HeadsStore({
|
|
945
|
+
db: db.sublevel("heads")
|
|
946
|
+
});
|
|
947
|
+
this._indexMetadataStore = indexMetadataStore;
|
|
736
948
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
949
|
+
async _open() {
|
|
950
|
+
this._peerId = `host-${PublicKey2.random().toHex()}`;
|
|
951
|
+
await this._storage.open?.();
|
|
952
|
+
this._repo = new Repo({
|
|
953
|
+
peerId: this._peerId,
|
|
954
|
+
sharePolicy: this._sharePolicy.bind(this),
|
|
955
|
+
storage: this._storage,
|
|
956
|
+
network: [
|
|
957
|
+
// Upstream swarm.
|
|
958
|
+
this._echoNetworkAdapter
|
|
959
|
+
]
|
|
960
|
+
});
|
|
961
|
+
Event2.wrap(this._echoNetworkAdapter, "peer-candidate").on(this._ctx, (e) => this._onPeerConnected(e.peerId));
|
|
962
|
+
Event2.wrap(this._echoNetworkAdapter, "peer-disconnected").on(this._ctx, (e) => this._onPeerDisconnected(e.peerId));
|
|
963
|
+
this._collectionSynchronizer.remoteStateUpdated.on(this._ctx, ({ collectionId, peerId }) => {
|
|
964
|
+
this._onRemoteCollectionStateUpdated(collectionId, peerId);
|
|
965
|
+
});
|
|
966
|
+
await this._echoNetworkAdapter.open();
|
|
967
|
+
await this._collectionSynchronizer.open();
|
|
968
|
+
await this._echoNetworkAdapter.open();
|
|
969
|
+
await this._echoNetworkAdapter.whenConnected();
|
|
970
|
+
}
|
|
971
|
+
async _close() {
|
|
972
|
+
await this._collectionSynchronizer.close();
|
|
973
|
+
await this._storage.close?.();
|
|
974
|
+
await this._echoNetworkAdapter.close();
|
|
975
|
+
await this._ctx.dispose();
|
|
742
976
|
}
|
|
743
977
|
/**
|
|
744
|
-
*
|
|
745
|
-
* Will be equal to `timeframe` after the processing is complete.
|
|
978
|
+
* @deprecated To be abstracted away.
|
|
746
979
|
*/
|
|
747
|
-
get
|
|
748
|
-
return this.
|
|
980
|
+
get repo() {
|
|
981
|
+
return this._repo;
|
|
749
982
|
}
|
|
750
|
-
|
|
751
|
-
this.
|
|
752
|
-
this._pendingTimeframe = timeframe;
|
|
753
|
-
this.update.emit(this._timeframe);
|
|
983
|
+
get peerId() {
|
|
984
|
+
return this._peerId;
|
|
754
985
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
[
|
|
758
|
-
key,
|
|
759
|
-
seq
|
|
760
|
-
]
|
|
761
|
-
]));
|
|
986
|
+
get loadedDocsCount() {
|
|
987
|
+
return Object.keys(this._repo.handles).length;
|
|
762
988
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
this.update.emit(this._timeframe);
|
|
989
|
+
async addReplicator(replicator) {
|
|
990
|
+
await this._echoNetworkAdapter.addReplicator(replicator);
|
|
766
991
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
return !gaps.isEmpty();
|
|
992
|
+
async removeReplicator(replicator) {
|
|
993
|
+
await this._echoNetworkAdapter.removeReplicator(replicator);
|
|
770
994
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
995
|
+
/**
|
|
996
|
+
* Loads the document handle from the repo and waits for it to be ready.
|
|
997
|
+
*/
|
|
998
|
+
async loadDoc(ctx, documentId, opts) {
|
|
999
|
+
let handle;
|
|
1000
|
+
if (typeof documentId === "string") {
|
|
1001
|
+
handle = this._repo.handles[documentId];
|
|
1002
|
+
}
|
|
1003
|
+
if (!handle) {
|
|
1004
|
+
handle = this._repo.find(documentId);
|
|
1005
|
+
}
|
|
1006
|
+
if (!handle.isReady()) {
|
|
1007
|
+
if (!opts?.timeout) {
|
|
1008
|
+
await cancelWithContext2(ctx, handle.whenReady());
|
|
1009
|
+
} else {
|
|
1010
|
+
await cancelWithContext2(ctx, asyncTimeout(handle.whenReady(), opts.timeout));
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return handle;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Create new persisted document.
|
|
1017
|
+
*/
|
|
1018
|
+
createDoc(initialValue, opts) {
|
|
1019
|
+
if (opts?.preserveHistory) {
|
|
1020
|
+
if (!isAutomerge(initialValue)) {
|
|
1021
|
+
throw new TypeError("Initial value must be an Automerge document");
|
|
1022
|
+
}
|
|
1023
|
+
return this._repo.import(save(initialValue));
|
|
1024
|
+
} else {
|
|
1025
|
+
return this._repo.create(initialValue);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
async waitUntilHeadsReplicated(heads) {
|
|
1029
|
+
const entries = heads.entries;
|
|
1030
|
+
if (!entries?.length) {
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
const documentIds = entries.map((entry) => entry.documentId);
|
|
1034
|
+
const documentHeads = await this.getHeads(documentIds);
|
|
1035
|
+
const headsToWait = entries.filter((entry, index) => {
|
|
1036
|
+
const targetHeads = entry.heads;
|
|
1037
|
+
if (!targetHeads || targetHeads.length === 0) {
|
|
1038
|
+
return false;
|
|
1039
|
+
}
|
|
1040
|
+
const currentHeads = documentHeads[index];
|
|
1041
|
+
return !(currentHeads !== null && headsEquals(currentHeads, targetHeads));
|
|
780
1042
|
});
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
1043
|
+
if (headsToWait.length > 0) {
|
|
1044
|
+
await Promise.all(headsToWait.map(async (entry, index) => {
|
|
1045
|
+
const handle = await this.loadDoc(Context.default(void 0, {
|
|
1046
|
+
F: __dxlog_file4,
|
|
1047
|
+
L: 223
|
|
1048
|
+
}), entry.documentId);
|
|
1049
|
+
await waitForHeads(handle, entry.heads);
|
|
1050
|
+
}));
|
|
1051
|
+
}
|
|
1052
|
+
await this._repo.flush(documentIds.filter((documentId) => !!this._repo.handles[documentId]));
|
|
1053
|
+
}
|
|
1054
|
+
async reIndexHeads(documentIds) {
|
|
1055
|
+
for (const documentId of documentIds) {
|
|
1056
|
+
log3.info("re-indexing heads for document", {
|
|
1057
|
+
documentId
|
|
786
1058
|
}, {
|
|
787
|
-
F:
|
|
788
|
-
L:
|
|
1059
|
+
F: __dxlog_file4,
|
|
1060
|
+
L: 235,
|
|
789
1061
|
S: this,
|
|
790
1062
|
C: (f, a) => f(...a)
|
|
791
1063
|
});
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
var createMessageSelector = (timeframeClock) => {
|
|
816
|
-
return (messages) => {
|
|
817
|
-
for (let i = 0; i < messages.length; i++) {
|
|
818
|
-
const { data: { timeframe } } = messages[i];
|
|
819
|
-
invariant5(timeframe, void 0, {
|
|
820
|
-
F: __dxlog_file6,
|
|
821
|
-
L: 25,
|
|
822
|
-
S: void 0,
|
|
1064
|
+
const handle = this._repo.find(documentId);
|
|
1065
|
+
await handle.whenReady([
|
|
1066
|
+
"ready",
|
|
1067
|
+
"requesting"
|
|
1068
|
+
]);
|
|
1069
|
+
if (handle.inState([
|
|
1070
|
+
"requesting"
|
|
1071
|
+
])) {
|
|
1072
|
+
log3.warn("document is not available locally, skipping", {
|
|
1073
|
+
documentId
|
|
1074
|
+
}, {
|
|
1075
|
+
F: __dxlog_file4,
|
|
1076
|
+
L: 239,
|
|
1077
|
+
S: this,
|
|
1078
|
+
C: (f, a) => f(...a)
|
|
1079
|
+
});
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
const doc = handle.docSync();
|
|
1083
|
+
invariant4(doc, void 0, {
|
|
1084
|
+
F: __dxlog_file4,
|
|
1085
|
+
L: 244,
|
|
1086
|
+
S: this,
|
|
823
1087
|
A: [
|
|
824
|
-
"
|
|
1088
|
+
"doc",
|
|
825
1089
|
""
|
|
826
1090
|
]
|
|
827
1091
|
});
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1092
|
+
const heads = getHeads(doc);
|
|
1093
|
+
const batch = this._db.batch();
|
|
1094
|
+
this._headsStore.setHeads(documentId, heads, batch);
|
|
1095
|
+
await batch.write();
|
|
831
1096
|
}
|
|
832
|
-
|
|
833
|
-
F:
|
|
834
|
-
L:
|
|
835
|
-
S:
|
|
1097
|
+
log3.info("done re-indexing heads", void 0, {
|
|
1098
|
+
F: __dxlog_file4,
|
|
1099
|
+
L: 251,
|
|
1100
|
+
S: this,
|
|
836
1101
|
C: (f, a) => f(...a)
|
|
837
1102
|
});
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
//
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1103
|
+
}
|
|
1104
|
+
// TODO(dmaretskyi): Share based on HALO permissions and space affinity.
|
|
1105
|
+
// Hosts, running in the worker, don't share documents unless requested by other peers.
|
|
1106
|
+
// NOTE: If both peers return sharePolicy=false the replication will not happen
|
|
1107
|
+
// https://github.com/automerge/automerge-repo/pull/292
|
|
1108
|
+
async _sharePolicy(peerId, documentId) {
|
|
1109
|
+
if (peerId.startsWith("client-")) {
|
|
1110
|
+
return false;
|
|
1111
|
+
}
|
|
1112
|
+
if (!documentId) {
|
|
1113
|
+
return false;
|
|
1114
|
+
}
|
|
1115
|
+
const peerMetadata = this.repo.peerMetadataByPeerId[peerId];
|
|
1116
|
+
if (isEchoPeerMetadata(peerMetadata)) {
|
|
1117
|
+
return this._echoNetworkAdapter.shouldAdvertise(peerId, {
|
|
1118
|
+
documentId
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
return false;
|
|
1122
|
+
}
|
|
1123
|
+
async _beforeSave({ path, batch }) {
|
|
1124
|
+
const handle = this._repo.handles[path[0]];
|
|
1125
|
+
if (!handle) {
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
const doc = handle.docSync();
|
|
1129
|
+
if (!doc) {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
const heads = getHeads(doc);
|
|
1133
|
+
this._headsStore.setHeads(handle.documentId, heads, batch);
|
|
1134
|
+
const spaceKey = getSpaceKeyFromDoc(doc) ?? void 0;
|
|
1135
|
+
const objectIds = Object.keys(doc.objects ?? {});
|
|
1136
|
+
const encodedIds = objectIds.map((objectId) => objectPointerCodec.encode({
|
|
1137
|
+
documentId: handle.documentId,
|
|
1138
|
+
objectId,
|
|
1139
|
+
spaceKey
|
|
1140
|
+
}));
|
|
1141
|
+
const idToLastHash = new Map(encodedIds.map((id) => [
|
|
1142
|
+
id,
|
|
1143
|
+
heads
|
|
1144
|
+
]));
|
|
1145
|
+
this._indexMetadataStore.markDirty(idToLastHash, batch);
|
|
1146
|
+
}
|
|
1147
|
+
_shouldSyncCollection(collectionId, peerId) {
|
|
1148
|
+
const peerMetadata = this._repo.peerMetadataByPeerId[peerId];
|
|
1149
|
+
if (isEchoPeerMetadata(peerMetadata)) {
|
|
1150
|
+
return this._echoNetworkAdapter.shouldSyncCollection(peerId, {
|
|
1151
|
+
collectionId
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
return false;
|
|
865
1155
|
}
|
|
866
1156
|
/**
|
|
867
|
-
*
|
|
868
|
-
* NOTE: This might never be reached if the mutation dependencies
|
|
1157
|
+
* Called by AutomergeStorageAdapter after levelDB batch commit.
|
|
869
1158
|
*/
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1159
|
+
async _afterSave(path) {
|
|
1160
|
+
this._indexMetadataStore.notifyMarkedDirty();
|
|
1161
|
+
const documentId = path[0];
|
|
1162
|
+
const document = this._repo.handles[documentId]?.docSync();
|
|
1163
|
+
if (document) {
|
|
1164
|
+
const heads = getHeads(document);
|
|
1165
|
+
this._onHeadsChanged(documentId, heads);
|
|
1166
|
+
}
|
|
876
1167
|
}
|
|
877
|
-
|
|
878
|
-
return this.
|
|
1168
|
+
_automergeDocs() {
|
|
1169
|
+
return mapValues(this._repo.handles, (handle) => ({
|
|
1170
|
+
state: handle.state,
|
|
1171
|
+
hasDoc: !!handle.docSync(),
|
|
1172
|
+
heads: handle.docSync() ? automerge.getHeads(handle.docSync()) : null,
|
|
1173
|
+
data: handle.docSync() && mapValues(handle.docSync(), (value, key) => {
|
|
1174
|
+
try {
|
|
1175
|
+
switch (key) {
|
|
1176
|
+
case "access":
|
|
1177
|
+
case "links":
|
|
1178
|
+
return value;
|
|
1179
|
+
case "objects":
|
|
1180
|
+
return Object.keys(value);
|
|
1181
|
+
default:
|
|
1182
|
+
return `${value}`;
|
|
1183
|
+
}
|
|
1184
|
+
} catch (err) {
|
|
1185
|
+
return `${err}`;
|
|
1186
|
+
}
|
|
1187
|
+
})
|
|
1188
|
+
}));
|
|
879
1189
|
}
|
|
880
|
-
|
|
881
|
-
return this.
|
|
1190
|
+
_automergePeers() {
|
|
1191
|
+
return this._repo.peers;
|
|
882
1192
|
}
|
|
883
|
-
|
|
884
|
-
|
|
1193
|
+
async _getContainingSpaceForDocument(documentId) {
|
|
1194
|
+
const doc = this._repo.handles[documentId]?.docSync();
|
|
1195
|
+
if (!doc) {
|
|
1196
|
+
return null;
|
|
1197
|
+
}
|
|
1198
|
+
const spaceKeyHex = getSpaceKeyFromDoc(doc);
|
|
1199
|
+
if (!spaceKeyHex) {
|
|
1200
|
+
return null;
|
|
1201
|
+
}
|
|
1202
|
+
return PublicKey2.from(spaceKeyHex);
|
|
885
1203
|
}
|
|
886
|
-
|
|
887
|
-
|
|
1204
|
+
/**
|
|
1205
|
+
* Flush documents to disk.
|
|
1206
|
+
*/
|
|
1207
|
+
async flush({ documentIds } = {}) {
|
|
1208
|
+
await this._repo.flush(documentIds);
|
|
888
1209
|
}
|
|
889
|
-
|
|
890
|
-
|
|
1210
|
+
async getHeads(documentIds) {
|
|
1211
|
+
const result = [];
|
|
1212
|
+
const storeRequestIds = [];
|
|
1213
|
+
const storeResultIndices = [];
|
|
1214
|
+
for (const documentId of documentIds) {
|
|
1215
|
+
const doc = this._repo.handles[documentId]?.docSync();
|
|
1216
|
+
if (doc) {
|
|
1217
|
+
result.push(getHeads(doc));
|
|
1218
|
+
} else {
|
|
1219
|
+
storeRequestIds.push(documentId);
|
|
1220
|
+
storeResultIndices.push(result.length);
|
|
1221
|
+
result.push(void 0);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (storeRequestIds.length > 0) {
|
|
1225
|
+
const storedHeads = await this._headsStore.getHeads(storeRequestIds);
|
|
1226
|
+
for (let i = 0; i < storedHeads.length; i++) {
|
|
1227
|
+
result[storeResultIndices[i]] = storedHeads[i];
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
return result;
|
|
891
1231
|
}
|
|
892
|
-
|
|
893
|
-
|
|
1232
|
+
//
|
|
1233
|
+
// Collection sync.
|
|
1234
|
+
//
|
|
1235
|
+
getLocalCollectionState(collectionId) {
|
|
1236
|
+
return this._collectionSynchronizer.getLocalCollectionState(collectionId);
|
|
894
1237
|
}
|
|
895
|
-
|
|
896
|
-
|
|
1238
|
+
getRemoteCollectionStates(collectionId) {
|
|
1239
|
+
return this._collectionSynchronizer.getRemoteCollectionStates(collectionId);
|
|
897
1240
|
}
|
|
898
|
-
|
|
899
|
-
this.
|
|
1241
|
+
refreshCollection(collectionId) {
|
|
1242
|
+
this._collectionSynchronizer.refreshCollection(collectionId);
|
|
1243
|
+
}
|
|
1244
|
+
async getCollectionSyncState(collectionId) {
|
|
1245
|
+
const result = {
|
|
1246
|
+
peers: []
|
|
1247
|
+
};
|
|
1248
|
+
const localState = this.getLocalCollectionState(collectionId);
|
|
1249
|
+
const remoteState = this.getRemoteCollectionStates(collectionId);
|
|
1250
|
+
if (!localState) {
|
|
1251
|
+
return result;
|
|
1252
|
+
}
|
|
1253
|
+
for (const [peerId, state] of remoteState) {
|
|
1254
|
+
const diff = diffCollectionState(localState, state);
|
|
1255
|
+
result.peers.push({
|
|
1256
|
+
peerId,
|
|
1257
|
+
differentDocuments: diff.different.length
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
return result;
|
|
900
1261
|
}
|
|
901
1262
|
/**
|
|
902
|
-
*
|
|
903
|
-
*
|
|
904
|
-
* This function will resolve immediately if the pipeline is stalled.
|
|
905
|
-
*
|
|
906
|
-
* @param timeout Timeout in milliseconds to specify the maximum wait time.
|
|
1263
|
+
* Update the local collection state based on the locally stored document heads.
|
|
907
1264
|
*/
|
|
908
|
-
async
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1265
|
+
async updateLocalCollectionState(collectionId, documentIds) {
|
|
1266
|
+
const heads = await this.getHeads(documentIds);
|
|
1267
|
+
const documents = Object.fromEntries(heads.map((heads2, index) => [
|
|
1268
|
+
documentIds[index],
|
|
1269
|
+
heads2 ?? []
|
|
1270
|
+
]));
|
|
1271
|
+
this._collectionSynchronizer.setLocalCollectionState(collectionId, {
|
|
1272
|
+
documents
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
_onCollectionStateQueried(collectionId, peerId) {
|
|
1276
|
+
this._collectionSynchronizer.onCollectionStateQueried(collectionId, peerId);
|
|
1277
|
+
}
|
|
1278
|
+
_onCollectionStateReceived(collectionId, peerId, state) {
|
|
1279
|
+
this._collectionSynchronizer.onRemoteStateReceived(collectionId, peerId, decodeCollectionState(state));
|
|
1280
|
+
}
|
|
1281
|
+
_queryCollectionState(collectionId, peerId) {
|
|
1282
|
+
this._echoNetworkAdapter.queryCollectionState(collectionId, peerId);
|
|
1283
|
+
}
|
|
1284
|
+
_sendCollectionState(collectionId, peerId, state) {
|
|
1285
|
+
this._echoNetworkAdapter.sendCollectionState(collectionId, peerId, encodeCollectionState(state));
|
|
1286
|
+
}
|
|
1287
|
+
_onPeerConnected(peerId) {
|
|
1288
|
+
this._collectionSynchronizer.onConnectionOpen(peerId);
|
|
1289
|
+
}
|
|
1290
|
+
_onPeerDisconnected(peerId) {
|
|
1291
|
+
this._collectionSynchronizer.onConnectionClosed(peerId);
|
|
1292
|
+
}
|
|
1293
|
+
_onRemoteCollectionStateUpdated(collectionId, peerId) {
|
|
1294
|
+
const localState = this._collectionSynchronizer.getLocalCollectionState(collectionId);
|
|
1295
|
+
const remoteState = this._collectionSynchronizer.getRemoteCollectionStates(collectionId).get(peerId);
|
|
1296
|
+
if (!localState || !remoteState) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
const { different } = diffCollectionState(localState, remoteState);
|
|
1300
|
+
if (different.length === 0) {
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
log3.info("replication documents after collection sync", {
|
|
1304
|
+
count: different.length
|
|
916
1305
|
}, {
|
|
917
|
-
F:
|
|
918
|
-
L:
|
|
1306
|
+
F: __dxlog_file4,
|
|
1307
|
+
L: 486,
|
|
919
1308
|
S: this,
|
|
920
1309
|
C: (f, a) => f(...a)
|
|
921
1310
|
});
|
|
922
|
-
|
|
923
|
-
this.
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1311
|
+
for (const documentId of different) {
|
|
1312
|
+
this._repo.find(documentId);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
_onHeadsChanged(documentId, heads) {
|
|
1316
|
+
for (const collectionId of this._collectionSynchronizer.getRegisteredCollectionIds()) {
|
|
1317
|
+
const state = this._collectionSynchronizer.getLocalCollectionState(collectionId);
|
|
1318
|
+
if (state?.documents[documentId]) {
|
|
1319
|
+
const newState = structuredClone(state);
|
|
1320
|
+
newState.documents[documentId] = heads;
|
|
1321
|
+
this._collectionSynchronizer.setLocalCollectionState(collectionId, newState);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
_ts_decorate2([
|
|
1327
|
+
trace.info()
|
|
1328
|
+
], AutomergeHost.prototype, "_peerId", void 0);
|
|
1329
|
+
_ts_decorate2([
|
|
1330
|
+
trace.info({
|
|
1331
|
+
depth: null
|
|
1332
|
+
})
|
|
1333
|
+
], AutomergeHost.prototype, "_automergeDocs", null);
|
|
1334
|
+
_ts_decorate2([
|
|
1335
|
+
trace.info({
|
|
1336
|
+
depth: null
|
|
1337
|
+
})
|
|
1338
|
+
], AutomergeHost.prototype, "_automergePeers", null);
|
|
1339
|
+
_ts_decorate2([
|
|
1340
|
+
trace.span({
|
|
1341
|
+
showInBrowserTimeline: true
|
|
1342
|
+
})
|
|
1343
|
+
], AutomergeHost.prototype, "flush", null);
|
|
1344
|
+
AutomergeHost = _ts_decorate2([
|
|
1345
|
+
trace.resource()
|
|
1346
|
+
], AutomergeHost);
|
|
1347
|
+
var getSpaceKeyFromDoc = (doc) => {
|
|
1348
|
+
const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
|
|
1349
|
+
if (rawSpaceKey == null) {
|
|
1350
|
+
return null;
|
|
1351
|
+
}
|
|
1352
|
+
return String(rawSpaceKey);
|
|
1353
|
+
};
|
|
1354
|
+
var waitForHeads = async (handle, heads) => {
|
|
1355
|
+
const unavailableHeads = new Set(heads);
|
|
1356
|
+
await handle.whenReady();
|
|
1357
|
+
await Event2.wrap(handle, "change").waitForCondition(() => {
|
|
1358
|
+
for (const changeHash of unavailableHeads.values()) {
|
|
1359
|
+
if (changeIsPresentInDoc(handle.docSync(), changeHash)) {
|
|
1360
|
+
unavailableHeads.delete(changeHash);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
return unavailableHeads.size === 0;
|
|
1364
|
+
});
|
|
1365
|
+
};
|
|
1366
|
+
var changeIsPresentInDoc = (doc, changeHash) => {
|
|
1367
|
+
return !!getBackend(doc).getChangeByHash(changeHash);
|
|
1368
|
+
};
|
|
1369
|
+
var decodeCollectionState = (state) => {
|
|
1370
|
+
invariant4(typeof state === "object" && state !== null, "Invalid state", {
|
|
1371
|
+
F: __dxlog_file4,
|
|
1372
|
+
L: 539,
|
|
1373
|
+
S: void 0,
|
|
1374
|
+
A: [
|
|
1375
|
+
"typeof state === 'object' && state !== null",
|
|
1376
|
+
"'Invalid state'"
|
|
1377
|
+
]
|
|
1378
|
+
});
|
|
1379
|
+
return state;
|
|
1380
|
+
};
|
|
1381
|
+
var encodeCollectionState = (state) => {
|
|
1382
|
+
return state;
|
|
1383
|
+
};
|
|
1384
|
+
|
|
1385
|
+
// packages/core/echo/echo-pipeline/src/automerge/space-collection.ts
|
|
1386
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
1387
|
+
import { SpaceId } from "@dxos/keys";
|
|
1388
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/space-collection.ts";
|
|
1389
|
+
var deriveCollectionIdFromSpaceId = (spaceId) => `space:${spaceId}`;
|
|
1390
|
+
var getSpaceIdFromCollectionId = (collectionId) => {
|
|
1391
|
+
const spaceId = collectionId.replace(/^space:/, "");
|
|
1392
|
+
invariant5(SpaceId.isValid(spaceId), void 0, {
|
|
1393
|
+
F: __dxlog_file5,
|
|
1394
|
+
L: 12,
|
|
1395
|
+
S: void 0,
|
|
1396
|
+
A: [
|
|
1397
|
+
"SpaceId.isValid(spaceId)",
|
|
1398
|
+
""
|
|
1399
|
+
]
|
|
1400
|
+
});
|
|
1401
|
+
return spaceId;
|
|
1402
|
+
};
|
|
1403
|
+
|
|
1404
|
+
// packages/core/echo/echo-pipeline/src/space/auth.ts
|
|
1405
|
+
import { runInContext, scheduleTask as scheduleTask2 } from "@dxos/async";
|
|
1406
|
+
import { Context as Context2 } from "@dxos/context";
|
|
1407
|
+
import { randomBytes } from "@dxos/crypto";
|
|
1408
|
+
import { invariant as invariant6 } from "@dxos/invariant";
|
|
1409
|
+
import { log as log4 } from "@dxos/log";
|
|
1410
|
+
import { schema as schema4 } from "@dxos/protocols";
|
|
1411
|
+
import { RpcExtension } from "@dxos/teleport";
|
|
1412
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/auth.ts";
|
|
1413
|
+
var AuthExtension = class extends RpcExtension {
|
|
1414
|
+
constructor(_authParams) {
|
|
1415
|
+
super({
|
|
1416
|
+
requested: {
|
|
1417
|
+
AuthService: schema4.getService("dxos.mesh.teleport.auth.AuthService")
|
|
1418
|
+
},
|
|
1419
|
+
exposed: {
|
|
1420
|
+
AuthService: schema4.getService("dxos.mesh.teleport.auth.AuthService")
|
|
1421
|
+
},
|
|
1422
|
+
timeout: 60 * 1e3
|
|
1423
|
+
});
|
|
1424
|
+
this._authParams = _authParams;
|
|
1425
|
+
this._ctx = new Context2({
|
|
1426
|
+
onError: (err) => {
|
|
1427
|
+
log4.catch(err, void 0, {
|
|
1428
|
+
F: __dxlog_file6,
|
|
1429
|
+
L: 28,
|
|
1430
|
+
S: this,
|
|
1431
|
+
C: (f, a) => f(...a)
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
}, {
|
|
1435
|
+
F: __dxlog_file6,
|
|
1436
|
+
L: 26
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
async getHandlers() {
|
|
1440
|
+
return {
|
|
1441
|
+
AuthService: {
|
|
1442
|
+
authenticate: async ({ challenge }) => {
|
|
1443
|
+
try {
|
|
1444
|
+
const credential = await this._authParams.provider(challenge);
|
|
1445
|
+
if (!credential) {
|
|
1446
|
+
throw new Error("auth rejected");
|
|
1447
|
+
}
|
|
1448
|
+
return {
|
|
1449
|
+
credential
|
|
1450
|
+
};
|
|
1451
|
+
} catch (err) {
|
|
1452
|
+
log4.error("failed to generate auth credentials", err, {
|
|
1453
|
+
F: __dxlog_file6,
|
|
1454
|
+
L: 55,
|
|
1455
|
+
S: this,
|
|
1456
|
+
C: (f, a) => f(...a)
|
|
1457
|
+
});
|
|
1458
|
+
throw new Error("auth rejected");
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
async onOpen(context) {
|
|
1465
|
+
await super.onOpen(context);
|
|
1466
|
+
scheduleTask2(this._ctx, async () => {
|
|
1467
|
+
try {
|
|
1468
|
+
const challenge = randomBytes(32);
|
|
1469
|
+
const { credential } = await this.rpc.AuthService.authenticate({
|
|
1470
|
+
challenge
|
|
1471
|
+
});
|
|
1472
|
+
invariant6(credential?.length > 0, "invalid credential", {
|
|
1473
|
+
F: __dxlog_file6,
|
|
1474
|
+
L: 69,
|
|
1475
|
+
S: this,
|
|
1476
|
+
A: [
|
|
1477
|
+
"credential?.length > 0",
|
|
1478
|
+
"'invalid credential'"
|
|
1479
|
+
]
|
|
1480
|
+
});
|
|
1481
|
+
const success = await this._authParams.verifier(challenge, credential);
|
|
1482
|
+
invariant6(success, "credential not verified", {
|
|
1483
|
+
F: __dxlog_file6,
|
|
1484
|
+
L: 71,
|
|
1485
|
+
S: this,
|
|
1486
|
+
A: [
|
|
1487
|
+
"success",
|
|
1488
|
+
"'credential not verified'"
|
|
1489
|
+
]
|
|
1490
|
+
});
|
|
1491
|
+
runInContext(this._ctx, () => this._authParams.onAuthSuccess());
|
|
1492
|
+
} catch (err) {
|
|
1493
|
+
log4("auth failed", err, {
|
|
1494
|
+
F: __dxlog_file6,
|
|
1495
|
+
L: 74,
|
|
1496
|
+
S: this,
|
|
1497
|
+
C: (f, a) => f(...a)
|
|
1498
|
+
});
|
|
1499
|
+
this.close();
|
|
1500
|
+
this._authParams.onAuthFailure();
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
async onClose() {
|
|
1505
|
+
await this._ctx.dispose();
|
|
1506
|
+
await super.onClose();
|
|
1507
|
+
}
|
|
1508
|
+
async onAbort() {
|
|
1509
|
+
await this._ctx.dispose();
|
|
1510
|
+
await super.onAbort();
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
|
|
1514
|
+
// packages/core/echo/echo-pipeline/src/pipeline/timeframe-clock.ts
|
|
1515
|
+
import { Event as Event3 } from "@dxos/async";
|
|
1516
|
+
import { timed } from "@dxos/debug";
|
|
1517
|
+
import { log as log5 } from "@dxos/log";
|
|
1518
|
+
import { Timeframe } from "@dxos/timeframe";
|
|
1519
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
1520
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1521
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
1522
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1523
|
+
else
|
|
1524
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
1525
|
+
if (d = decorators[i])
|
|
1526
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1527
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1528
|
+
}
|
|
1529
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/pipeline/timeframe-clock.ts";
|
|
1530
|
+
var mapTimeframeToFeedIndexes = (timeframe) => timeframe.frames().map(([feedKey, index]) => ({
|
|
1531
|
+
feedKey,
|
|
1532
|
+
index
|
|
1533
|
+
}));
|
|
1534
|
+
var mapFeedIndexesToTimeframe = (indexes) => new Timeframe(indexes.map(({ feedKey, index }) => [
|
|
1535
|
+
feedKey,
|
|
1536
|
+
index
|
|
1537
|
+
]));
|
|
1538
|
+
var startAfter = (timeframe) => timeframe.frames().map(([feedKey, index]) => ({
|
|
1539
|
+
feedKey,
|
|
1540
|
+
index: index + 1
|
|
1541
|
+
}));
|
|
1542
|
+
var TimeframeClock = class {
|
|
1543
|
+
constructor(_timeframe = new Timeframe()) {
|
|
1544
|
+
this._timeframe = _timeframe;
|
|
1545
|
+
this.update = new Event3();
|
|
1546
|
+
this._pendingTimeframe = _timeframe;
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Timeframe that was processed by ECHO.
|
|
1550
|
+
*/
|
|
1551
|
+
get timeframe() {
|
|
1552
|
+
return this._timeframe;
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Timeframe that is currently being processed by ECHO.
|
|
1556
|
+
* Will be equal to `timeframe` after the processing is complete.
|
|
1557
|
+
*/
|
|
1558
|
+
get pendingTimeframe() {
|
|
1559
|
+
return this._pendingTimeframe;
|
|
1560
|
+
}
|
|
1561
|
+
setTimeframe(timeframe) {
|
|
1562
|
+
this._timeframe = timeframe;
|
|
1563
|
+
this._pendingTimeframe = timeframe;
|
|
1564
|
+
this.update.emit(this._timeframe);
|
|
1565
|
+
}
|
|
1566
|
+
updatePendingTimeframe(key, seq) {
|
|
1567
|
+
this._pendingTimeframe = Timeframe.merge(this._pendingTimeframe, new Timeframe([
|
|
1568
|
+
[
|
|
1569
|
+
key,
|
|
1570
|
+
seq
|
|
1571
|
+
]
|
|
1572
|
+
]));
|
|
1573
|
+
}
|
|
1574
|
+
updateTimeframe() {
|
|
1575
|
+
this._timeframe = this._pendingTimeframe;
|
|
1576
|
+
this.update.emit(this._timeframe);
|
|
1577
|
+
}
|
|
1578
|
+
hasGaps(timeframe) {
|
|
1579
|
+
const gaps = Timeframe.dependencies(timeframe, this._timeframe);
|
|
1580
|
+
return !gaps.isEmpty();
|
|
1581
|
+
}
|
|
1582
|
+
async waitUntilReached(target) {
|
|
1583
|
+
log5("waitUntilReached", {
|
|
1584
|
+
target,
|
|
1585
|
+
current: this._timeframe
|
|
1586
|
+
}, {
|
|
1587
|
+
F: __dxlog_file7,
|
|
1588
|
+
L: 70,
|
|
1589
|
+
S: this,
|
|
1590
|
+
C: (f, a) => f(...a)
|
|
1591
|
+
});
|
|
1592
|
+
await this.update.waitForCondition(() => {
|
|
1593
|
+
log5("check if reached", {
|
|
1594
|
+
target,
|
|
1595
|
+
current: this._timeframe,
|
|
1596
|
+
deps: Timeframe.dependencies(target, this._timeframe)
|
|
1597
|
+
}, {
|
|
1598
|
+
F: __dxlog_file7,
|
|
1599
|
+
L: 72,
|
|
1600
|
+
S: this,
|
|
1601
|
+
C: (f, a) => f(...a)
|
|
1602
|
+
});
|
|
1603
|
+
return Timeframe.dependencies(target, this._timeframe).isEmpty();
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
_ts_decorate3([
|
|
1608
|
+
timed(5e3)
|
|
1609
|
+
], TimeframeClock.prototype, "waitUntilReached", null);
|
|
1610
|
+
|
|
1611
|
+
// packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
|
|
1612
|
+
import { Event as Event4, sleepWithContext, synchronized as synchronized2, Trigger as Trigger2 } from "@dxos/async";
|
|
1613
|
+
import { Context as Context3, rejectOnDispose } from "@dxos/context";
|
|
1614
|
+
import { failUndefined } from "@dxos/debug";
|
|
1615
|
+
import { FeedSetIterator } from "@dxos/feed-store";
|
|
1616
|
+
import { invariant as invariant8 } from "@dxos/invariant";
|
|
1617
|
+
import { PublicKey as PublicKey3 } from "@dxos/keys";
|
|
1618
|
+
import { log as log7 } from "@dxos/log";
|
|
1619
|
+
import { Timeframe as Timeframe2 } from "@dxos/timeframe";
|
|
1620
|
+
import { ComplexMap } from "@dxos/util";
|
|
1621
|
+
|
|
1622
|
+
// packages/core/echo/echo-pipeline/src/pipeline/message-selector.ts
|
|
1623
|
+
import { invariant as invariant7 } from "@dxos/invariant";
|
|
1624
|
+
import { log as log6 } from "@dxos/log";
|
|
1625
|
+
var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/pipeline/message-selector.ts";
|
|
1626
|
+
var createMessageSelector = (timeframeClock) => {
|
|
1627
|
+
return (messages) => {
|
|
1628
|
+
for (let i = 0; i < messages.length; i++) {
|
|
1629
|
+
const { data: { timeframe } } = messages[i];
|
|
1630
|
+
invariant7(timeframe, void 0, {
|
|
1631
|
+
F: __dxlog_file8,
|
|
1632
|
+
L: 25,
|
|
1633
|
+
S: void 0,
|
|
1634
|
+
A: [
|
|
1635
|
+
"timeframe",
|
|
1636
|
+
""
|
|
1637
|
+
]
|
|
1638
|
+
});
|
|
1639
|
+
if (!timeframeClock.hasGaps(timeframe)) {
|
|
1640
|
+
return i;
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
log6("Skipping...", void 0, {
|
|
1644
|
+
F: __dxlog_file8,
|
|
1645
|
+
L: 33,
|
|
1646
|
+
S: void 0,
|
|
1647
|
+
C: (f, a) => f(...a)
|
|
1648
|
+
});
|
|
1649
|
+
};
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
// packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts
|
|
1653
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
1654
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1655
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
1656
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1657
|
+
else
|
|
1658
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
1659
|
+
if (d = decorators[i])
|
|
1660
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1661
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1662
|
+
}
|
|
1663
|
+
var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/pipeline/pipeline.ts";
|
|
1664
|
+
var PipelineState = class {
|
|
1665
|
+
constructor(_feeds, _timeframeClock) {
|
|
1666
|
+
this._feeds = _feeds;
|
|
1667
|
+
this._timeframeClock = _timeframeClock;
|
|
1668
|
+
this._ctx = new Context3(void 0, {
|
|
1669
|
+
F: __dxlog_file9,
|
|
1670
|
+
L: 41
|
|
1671
|
+
});
|
|
1672
|
+
this.timeframeUpdate = this._timeframeClock.update;
|
|
1673
|
+
this.stalled = new Event4();
|
|
1674
|
+
this._startTimeframe = new Timeframe2();
|
|
1675
|
+
this._reachedTarget = false;
|
|
1676
|
+
}
|
|
1677
|
+
/**
|
|
1678
|
+
* Latest theoretical timeframe based on the last mutation in each feed.
|
|
1679
|
+
* NOTE: This might never be reached if the mutation dependencies
|
|
1680
|
+
*/
|
|
1681
|
+
// TODO(dmaretskyi): Rename `totalTimeframe`? or `lastTimeframe`.
|
|
1682
|
+
get endTimeframe() {
|
|
1683
|
+
return mapFeedIndexesToTimeframe(Array.from(this._feeds.values()).filter((feed) => feed.length > 0).map((feed) => ({
|
|
1684
|
+
feedKey: feed.key,
|
|
1685
|
+
index: feed.length - 1
|
|
1686
|
+
})));
|
|
1687
|
+
}
|
|
1688
|
+
get startTimeframe() {
|
|
1689
|
+
return this._startTimeframe;
|
|
1690
|
+
}
|
|
1691
|
+
get timeframe() {
|
|
1692
|
+
return this._timeframeClock.timeframe;
|
|
1693
|
+
}
|
|
1694
|
+
get pendingTimeframe() {
|
|
1695
|
+
return this._timeframeClock.pendingTimeframe;
|
|
1696
|
+
}
|
|
1697
|
+
get targetTimeframe() {
|
|
1698
|
+
return this._targetTimeframe ? this._targetTimeframe : new Timeframe2();
|
|
1699
|
+
}
|
|
1700
|
+
get reachedTarget() {
|
|
1701
|
+
return this._reachedTarget;
|
|
1702
|
+
}
|
|
1703
|
+
get feeds() {
|
|
1704
|
+
return Array.from(this._feeds.values());
|
|
1705
|
+
}
|
|
1706
|
+
async waitUntilTimeframe(target) {
|
|
1707
|
+
await this._timeframeClock.waitUntilReached(target);
|
|
1708
|
+
}
|
|
1709
|
+
setTargetTimeframe(target) {
|
|
1710
|
+
this._targetTimeframe = target;
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Wait until the pipeline processes all messages in the feed and reaches the target timeframe if that is set.
|
|
1714
|
+
*
|
|
1715
|
+
* This function will resolve immediately if the pipeline is stalled.
|
|
1716
|
+
*
|
|
1717
|
+
* @param timeout Timeout in milliseconds to specify the maximum wait time.
|
|
1718
|
+
*/
|
|
1719
|
+
async waitUntilReachedTargetTimeframe({ ctx = new Context3(void 0, {
|
|
1720
|
+
F: __dxlog_file9,
|
|
1721
|
+
L: 129
|
|
1722
|
+
}), timeout, breakOnStall = true } = {}) {
|
|
1723
|
+
log7("waitUntilReachedTargetTimeframe", {
|
|
1724
|
+
timeout,
|
|
1725
|
+
current: this.timeframe,
|
|
1726
|
+
target: this.targetTimeframe
|
|
1727
|
+
}, {
|
|
1728
|
+
F: __dxlog_file9,
|
|
1729
|
+
L: 133,
|
|
1730
|
+
S: this,
|
|
1731
|
+
C: (f, a) => f(...a)
|
|
1732
|
+
});
|
|
1733
|
+
this._reachedTargetPromise ??= Promise.race([
|
|
1734
|
+
this._timeframeClock.update.waitForCondition(() => {
|
|
1735
|
+
return Timeframe2.dependencies(this.targetTimeframe, this.timeframe).isEmpty();
|
|
1736
|
+
}),
|
|
1737
|
+
...breakOnStall ? [
|
|
1738
|
+
this.stalled.discardParameter().waitForCount(1)
|
|
1739
|
+
] : []
|
|
1740
|
+
]);
|
|
1741
|
+
let done = false;
|
|
1742
|
+
if (timeout) {
|
|
1743
|
+
return Promise.race([
|
|
1744
|
+
rejectOnDispose(ctx),
|
|
1745
|
+
rejectOnDispose(this._ctx),
|
|
1746
|
+
this._reachedTargetPromise.then(() => {
|
|
1747
|
+
done = true;
|
|
1748
|
+
this._reachedTarget = true;
|
|
938
1749
|
}),
|
|
939
1750
|
sleepWithContext(this._ctx, timeout).then(() => {
|
|
940
1751
|
if (done) {
|
|
941
1752
|
return;
|
|
942
1753
|
}
|
|
943
|
-
|
|
1754
|
+
log7.warn("waitUntilReachedTargetTimeframe timed out", {
|
|
944
1755
|
timeout,
|
|
945
1756
|
current: this.timeframe,
|
|
946
1757
|
target: this.targetTimeframe,
|
|
947
1758
|
dependencies: Timeframe2.dependencies(this.targetTimeframe, this.timeframe)
|
|
948
1759
|
}, {
|
|
949
|
-
F:
|
|
1760
|
+
F: __dxlog_file9,
|
|
950
1761
|
L: 161,
|
|
951
1762
|
S: this,
|
|
952
1763
|
C: (f, a) => f(...a)
|
|
@@ -961,14 +1772,14 @@ var PipelineState = class {
|
|
|
961
1772
|
var Pipeline = class {
|
|
962
1773
|
constructor() {
|
|
963
1774
|
this._timeframeClock = new TimeframeClock(new Timeframe2());
|
|
964
|
-
this._feeds = new
|
|
1775
|
+
this._feeds = new ComplexMap(PublicKey3.hash);
|
|
965
1776
|
// External state accessor.
|
|
966
1777
|
this._state = new PipelineState(this._feeds, this._timeframeClock);
|
|
967
1778
|
// Waits for the message consumer to process the message and yield control back to the pipeline.
|
|
968
|
-
this._processingTrigger = new
|
|
969
|
-
this._pauseTrigger = new
|
|
1779
|
+
this._processingTrigger = new Trigger2().wake();
|
|
1780
|
+
this._pauseTrigger = new Trigger2().wake();
|
|
970
1781
|
// Pending downloads.
|
|
971
|
-
this._downloads = new
|
|
1782
|
+
this._downloads = new ComplexMap((value) => PublicKey3.hash(value.key));
|
|
972
1783
|
this._isStopping = false;
|
|
973
1784
|
this._isStarted = false;
|
|
974
1785
|
this._isBeingConsumed = false;
|
|
@@ -978,8 +1789,8 @@ var Pipeline = class {
|
|
|
978
1789
|
return this._state;
|
|
979
1790
|
}
|
|
980
1791
|
get writer() {
|
|
981
|
-
|
|
982
|
-
F:
|
|
1792
|
+
invariant8(this._writer, "Writer not set.", {
|
|
1793
|
+
F: __dxlog_file9,
|
|
983
1794
|
L: 243,
|
|
984
1795
|
S: this,
|
|
985
1796
|
A: [
|
|
@@ -1007,8 +1818,8 @@ var Pipeline = class {
|
|
|
1007
1818
|
}
|
|
1008
1819
|
}
|
|
1009
1820
|
setWriteFeed(feed) {
|
|
1010
|
-
|
|
1011
|
-
F:
|
|
1821
|
+
invariant8(!this._writer, "Writer already set.", {
|
|
1822
|
+
F: __dxlog_file9,
|
|
1012
1823
|
L: 270,
|
|
1013
1824
|
S: this,
|
|
1014
1825
|
A: [
|
|
@@ -1016,8 +1827,8 @@ var Pipeline = class {
|
|
|
1016
1827
|
"'Writer already set.'"
|
|
1017
1828
|
]
|
|
1018
1829
|
});
|
|
1019
|
-
|
|
1020
|
-
F:
|
|
1830
|
+
invariant8(feed.properties.writable, "Feed must be writable.", {
|
|
1831
|
+
F: __dxlog_file9,
|
|
1021
1832
|
L: 271,
|
|
1022
1833
|
S: this,
|
|
1023
1834
|
A: [
|
|
@@ -1031,8 +1842,8 @@ var Pipeline = class {
|
|
|
1031
1842
|
}), feed.createFeedWriter());
|
|
1032
1843
|
}
|
|
1033
1844
|
async start() {
|
|
1034
|
-
|
|
1035
|
-
F:
|
|
1845
|
+
invariant8(!this._isStarted, "Pipeline is already started.", {
|
|
1846
|
+
F: __dxlog_file9,
|
|
1036
1847
|
L: 284,
|
|
1037
1848
|
S: this,
|
|
1038
1849
|
A: [
|
|
@@ -1040,8 +1851,8 @@ var Pipeline = class {
|
|
|
1040
1851
|
"'Pipeline is already started.'"
|
|
1041
1852
|
]
|
|
1042
1853
|
});
|
|
1043
|
-
|
|
1044
|
-
F:
|
|
1854
|
+
log7("starting...", void 0, {
|
|
1855
|
+
F: __dxlog_file9,
|
|
1045
1856
|
L: 285,
|
|
1046
1857
|
S: this,
|
|
1047
1858
|
C: (f, a) => f(...a)
|
|
@@ -1049,8 +1860,8 @@ var Pipeline = class {
|
|
|
1049
1860
|
await this._initIterator();
|
|
1050
1861
|
await this._feedSetIterator.open();
|
|
1051
1862
|
this._isStarted = true;
|
|
1052
|
-
|
|
1053
|
-
F:
|
|
1863
|
+
log7("started", void 0, {
|
|
1864
|
+
F: __dxlog_file9,
|
|
1054
1865
|
L: 289,
|
|
1055
1866
|
S: this,
|
|
1056
1867
|
C: (f, a) => f(...a)
|
|
@@ -1062,8 +1873,8 @@ var Pipeline = class {
|
|
|
1062
1873
|
}
|
|
1063
1874
|
}
|
|
1064
1875
|
async stop() {
|
|
1065
|
-
|
|
1066
|
-
F:
|
|
1876
|
+
log7("stopping...", void 0, {
|
|
1877
|
+
F: __dxlog_file9,
|
|
1067
1878
|
L: 300,
|
|
1068
1879
|
S: this,
|
|
1069
1880
|
C: (f, a) => f(...a)
|
|
@@ -1076,15 +1887,15 @@ var Pipeline = class {
|
|
|
1076
1887
|
await this._feedSetIterator?.close();
|
|
1077
1888
|
await this._processingTrigger.wait();
|
|
1078
1889
|
await this._state._ctx.dispose();
|
|
1079
|
-
this._state._ctx = new
|
|
1080
|
-
F:
|
|
1890
|
+
this._state._ctx = new Context3(void 0, {
|
|
1891
|
+
F: __dxlog_file9,
|
|
1081
1892
|
L: 309
|
|
1082
1893
|
});
|
|
1083
1894
|
this._state._reachedTargetPromise = void 0;
|
|
1084
1895
|
this._state._reachedTarget = false;
|
|
1085
1896
|
this._isStarted = false;
|
|
1086
|
-
|
|
1087
|
-
F:
|
|
1897
|
+
log7("stopped", void 0, {
|
|
1898
|
+
F: __dxlog_file9,
|
|
1088
1899
|
L: 313,
|
|
1089
1900
|
S: this,
|
|
1090
1901
|
C: (f, a) => f(...a)
|
|
@@ -1095,8 +1906,8 @@ var Pipeline = class {
|
|
|
1095
1906
|
* The pipeline will start processing messages AFTER this timeframe.
|
|
1096
1907
|
*/
|
|
1097
1908
|
async setCursor(timeframe) {
|
|
1098
|
-
|
|
1099
|
-
F:
|
|
1909
|
+
invariant8(!this._isStarted || this._isPaused, "Invalid state.", {
|
|
1910
|
+
F: __dxlog_file9,
|
|
1100
1911
|
L: 322,
|
|
1101
1912
|
S: this,
|
|
1102
1913
|
A: [
|
|
@@ -1124,8 +1935,8 @@ var Pipeline = class {
|
|
|
1124
1935
|
this._isPaused = true;
|
|
1125
1936
|
}
|
|
1126
1937
|
async unpause() {
|
|
1127
|
-
|
|
1128
|
-
F:
|
|
1938
|
+
invariant8(this._isPaused, "Pipeline is not paused.", {
|
|
1939
|
+
F: __dxlog_file9,
|
|
1129
1940
|
L: 351,
|
|
1130
1941
|
S: this,
|
|
1131
1942
|
A: [
|
|
@@ -1144,8 +1955,8 @@ var Pipeline = class {
|
|
|
1144
1955
|
* Updates the timeframe clock after the message has bee processed.
|
|
1145
1956
|
*/
|
|
1146
1957
|
async *consume() {
|
|
1147
|
-
|
|
1148
|
-
F:
|
|
1958
|
+
invariant8(!this._isBeingConsumed, "Pipeline is already being consumed.", {
|
|
1959
|
+
F: __dxlog_file9,
|
|
1149
1960
|
L: 366,
|
|
1150
1961
|
S: this,
|
|
1151
1962
|
A: [
|
|
@@ -1154,8 +1965,8 @@ var Pipeline = class {
|
|
|
1154
1965
|
]
|
|
1155
1966
|
});
|
|
1156
1967
|
this._isBeingConsumed = true;
|
|
1157
|
-
|
|
1158
|
-
F:
|
|
1968
|
+
invariant8(this._feedSetIterator, "Iterator not initialized.", {
|
|
1969
|
+
F: __dxlog_file9,
|
|
1159
1970
|
L: 369,
|
|
1160
1971
|
S: this,
|
|
1161
1972
|
A: [
|
|
@@ -1168,8 +1979,8 @@ var Pipeline = class {
|
|
|
1168
1979
|
while (!this._isStopping) {
|
|
1169
1980
|
await this._pauseTrigger.wait();
|
|
1170
1981
|
if (lastFeedSetIterator !== this._feedSetIterator) {
|
|
1171
|
-
|
|
1172
|
-
F:
|
|
1982
|
+
invariant8(this._feedSetIterator, "Iterator not initialized.", {
|
|
1983
|
+
F: __dxlog_file9,
|
|
1173
1984
|
L: 378,
|
|
1174
1985
|
S: this,
|
|
1175
1986
|
A: [
|
|
@@ -1199,12 +2010,12 @@ var Pipeline = class {
|
|
|
1199
2010
|
}
|
|
1200
2011
|
const timeframe = this._state._startTimeframe;
|
|
1201
2012
|
const seq = timeframe.get(feed.key) ?? -1;
|
|
1202
|
-
|
|
2013
|
+
log7("download", {
|
|
1203
2014
|
feed: feed.key.truncate(),
|
|
1204
2015
|
seq,
|
|
1205
2016
|
length: feed.length
|
|
1206
2017
|
}, {
|
|
1207
|
-
F:
|
|
2018
|
+
F: __dxlog_file9,
|
|
1208
2019
|
L: 407,
|
|
1209
2020
|
S: this,
|
|
1210
2021
|
C: (f, a) => f(...a)
|
|
@@ -1215,10 +2026,10 @@ var Pipeline = class {
|
|
|
1215
2026
|
}, (err, data) => {
|
|
1216
2027
|
if (err) {
|
|
1217
2028
|
} else {
|
|
1218
|
-
|
|
2029
|
+
log7.info("downloaded", {
|
|
1219
2030
|
data
|
|
1220
2031
|
}, {
|
|
1221
|
-
F:
|
|
2032
|
+
F: __dxlog_file9,
|
|
1222
2033
|
L: 412,
|
|
1223
2034
|
S: this,
|
|
1224
2035
|
C: (f, a) => f(...a)
|
|
@@ -1233,8 +2044,8 @@ var Pipeline = class {
|
|
|
1233
2044
|
stallTimeout: 1e3
|
|
1234
2045
|
});
|
|
1235
2046
|
this._feedSetIterator.stalled.on((iterator) => {
|
|
1236
|
-
|
|
1237
|
-
F:
|
|
2047
|
+
log7.warn(`Stalled after ${iterator.options.stallTimeout}ms with ${iterator.size} feeds.`, void 0, {
|
|
2048
|
+
F: __dxlog_file9,
|
|
1238
2049
|
L: 426,
|
|
1239
2050
|
S: this,
|
|
1240
2051
|
C: (f, a) => f(...a)
|
|
@@ -1246,142 +2057,32 @@ var Pipeline = class {
|
|
|
1246
2057
|
}
|
|
1247
2058
|
}
|
|
1248
2059
|
};
|
|
1249
|
-
|
|
2060
|
+
_ts_decorate4([
|
|
1250
2061
|
synchronized2
|
|
1251
2062
|
], Pipeline.prototype, "start", null);
|
|
1252
|
-
|
|
2063
|
+
_ts_decorate4([
|
|
1253
2064
|
synchronized2
|
|
1254
2065
|
], Pipeline.prototype, "stop", null);
|
|
1255
|
-
|
|
2066
|
+
_ts_decorate4([
|
|
1256
2067
|
synchronized2
|
|
1257
2068
|
], Pipeline.prototype, "setCursor", null);
|
|
1258
|
-
|
|
2069
|
+
_ts_decorate4([
|
|
1259
2070
|
synchronized2
|
|
1260
2071
|
], Pipeline.prototype, "pause", null);
|
|
1261
|
-
|
|
2072
|
+
_ts_decorate4([
|
|
1262
2073
|
synchronized2
|
|
1263
2074
|
], Pipeline.prototype, "unpause", null);
|
|
1264
2075
|
|
|
1265
|
-
// packages/core/echo/echo-pipeline/src/space/auth.ts
|
|
1266
|
-
import { runInContext, scheduleTask } from "@dxos/async";
|
|
1267
|
-
import { Context as Context3 } from "@dxos/context";
|
|
1268
|
-
import { randomBytes } from "@dxos/crypto";
|
|
1269
|
-
import { invariant as invariant7 } from "@dxos/invariant";
|
|
1270
|
-
import { log as log7 } from "@dxos/log";
|
|
1271
|
-
import { schema as schema5 } from "@dxos/protocols";
|
|
1272
|
-
import { RpcExtension } from "@dxos/teleport";
|
|
1273
|
-
var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/auth.ts";
|
|
1274
|
-
var AuthExtension = class extends RpcExtension {
|
|
1275
|
-
constructor(_authParams) {
|
|
1276
|
-
super({
|
|
1277
|
-
requested: {
|
|
1278
|
-
AuthService: schema5.getService("dxos.mesh.teleport.auth.AuthService")
|
|
1279
|
-
},
|
|
1280
|
-
exposed: {
|
|
1281
|
-
AuthService: schema5.getService("dxos.mesh.teleport.auth.AuthService")
|
|
1282
|
-
},
|
|
1283
|
-
timeout: 60 * 1e3
|
|
1284
|
-
});
|
|
1285
|
-
this._authParams = _authParams;
|
|
1286
|
-
this._ctx = new Context3({
|
|
1287
|
-
onError: (err) => {
|
|
1288
|
-
log7.catch(err, void 0, {
|
|
1289
|
-
F: __dxlog_file8,
|
|
1290
|
-
L: 28,
|
|
1291
|
-
S: this,
|
|
1292
|
-
C: (f, a) => f(...a)
|
|
1293
|
-
});
|
|
1294
|
-
}
|
|
1295
|
-
}, {
|
|
1296
|
-
F: __dxlog_file8,
|
|
1297
|
-
L: 26
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
async getHandlers() {
|
|
1301
|
-
return {
|
|
1302
|
-
AuthService: {
|
|
1303
|
-
authenticate: async ({ challenge }) => {
|
|
1304
|
-
try {
|
|
1305
|
-
const credential = await this._authParams.provider(challenge);
|
|
1306
|
-
if (!credential) {
|
|
1307
|
-
throw new Error("auth rejected");
|
|
1308
|
-
}
|
|
1309
|
-
return {
|
|
1310
|
-
credential
|
|
1311
|
-
};
|
|
1312
|
-
} catch (err) {
|
|
1313
|
-
log7.error("failed to generate auth credentials", err, {
|
|
1314
|
-
F: __dxlog_file8,
|
|
1315
|
-
L: 55,
|
|
1316
|
-
S: this,
|
|
1317
|
-
C: (f, a) => f(...a)
|
|
1318
|
-
});
|
|
1319
|
-
throw new Error("auth rejected");
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
}
|
|
1325
|
-
async onOpen(context) {
|
|
1326
|
-
await super.onOpen(context);
|
|
1327
|
-
scheduleTask(this._ctx, async () => {
|
|
1328
|
-
try {
|
|
1329
|
-
const challenge = randomBytes(32);
|
|
1330
|
-
const { credential } = await this.rpc.AuthService.authenticate({
|
|
1331
|
-
challenge
|
|
1332
|
-
});
|
|
1333
|
-
invariant7(credential?.length > 0, "invalid credential", {
|
|
1334
|
-
F: __dxlog_file8,
|
|
1335
|
-
L: 69,
|
|
1336
|
-
S: this,
|
|
1337
|
-
A: [
|
|
1338
|
-
"credential?.length > 0",
|
|
1339
|
-
"'invalid credential'"
|
|
1340
|
-
]
|
|
1341
|
-
});
|
|
1342
|
-
const success = await this._authParams.verifier(challenge, credential);
|
|
1343
|
-
invariant7(success, "credential not verified", {
|
|
1344
|
-
F: __dxlog_file8,
|
|
1345
|
-
L: 71,
|
|
1346
|
-
S: this,
|
|
1347
|
-
A: [
|
|
1348
|
-
"success",
|
|
1349
|
-
"'credential not verified'"
|
|
1350
|
-
]
|
|
1351
|
-
});
|
|
1352
|
-
runInContext(this._ctx, () => this._authParams.onAuthSuccess());
|
|
1353
|
-
} catch (err) {
|
|
1354
|
-
log7("auth failed", err, {
|
|
1355
|
-
F: __dxlog_file8,
|
|
1356
|
-
L: 74,
|
|
1357
|
-
S: this,
|
|
1358
|
-
C: (f, a) => f(...a)
|
|
1359
|
-
});
|
|
1360
|
-
this.close();
|
|
1361
|
-
this._authParams.onAuthFailure();
|
|
1362
|
-
}
|
|
1363
|
-
});
|
|
1364
|
-
}
|
|
1365
|
-
async onClose() {
|
|
1366
|
-
await this._ctx.dispose();
|
|
1367
|
-
await super.onClose();
|
|
1368
|
-
}
|
|
1369
|
-
async onAbort() {
|
|
1370
|
-
await this._ctx.dispose();
|
|
1371
|
-
await super.onAbort();
|
|
1372
|
-
}
|
|
1373
|
-
};
|
|
1374
|
-
|
|
1375
2076
|
// packages/core/echo/echo-pipeline/src/space/space.ts
|
|
1376
|
-
import { Event as
|
|
1377
|
-
import { LifecycleState, Resource as
|
|
2077
|
+
import { Event as Event5, Mutex, synchronized as synchronized3, trackLeaks as trackLeaks2 } from "@dxos/async";
|
|
2078
|
+
import { LifecycleState as LifecycleState3, Resource as Resource5 } from "@dxos/context";
|
|
1378
2079
|
import { subtleCrypto as subtleCrypto2 } from "@dxos/crypto";
|
|
1379
|
-
import { invariant as
|
|
1380
|
-
import { PublicKey as PublicKey5, SpaceId } from "@dxos/keys";
|
|
2080
|
+
import { invariant as invariant9 } from "@dxos/invariant";
|
|
2081
|
+
import { PublicKey as PublicKey5, SpaceId as SpaceId2 } from "@dxos/keys";
|
|
1381
2082
|
import { log as log9, logInfo } from "@dxos/log";
|
|
1382
2083
|
import { AdmittedFeed as AdmittedFeed2 } from "@dxos/protocols/proto/dxos/halo/credentials";
|
|
1383
|
-
import { trace as
|
|
1384
|
-
import { Callback as Callback2, ComplexMap as
|
|
2084
|
+
import { trace as trace3 } from "@dxos/tracing";
|
|
2085
|
+
import { Callback as Callback2, ComplexMap as ComplexMap2 } from "@dxos/util";
|
|
1385
2086
|
|
|
1386
2087
|
// packages/core/echo/echo-pipeline/src/space/control-pipeline.ts
|
|
1387
2088
|
import { DeferredTask, sleepWithContext as sleepWithContext2, trackLeaks } from "@dxos/async";
|
|
@@ -1391,9 +2092,9 @@ import { PublicKey as PublicKey4 } from "@dxos/keys";
|
|
|
1391
2092
|
import { log as log8 } from "@dxos/log";
|
|
1392
2093
|
import { AdmittedFeed } from "@dxos/protocols/proto/dxos/halo/credentials";
|
|
1393
2094
|
import { Timeframe as Timeframe3 } from "@dxos/timeframe";
|
|
1394
|
-
import { TimeSeriesCounter, TimeUsageCounter, trace } from "@dxos/tracing";
|
|
2095
|
+
import { TimeSeriesCounter, TimeUsageCounter, trace as trace2 } from "@dxos/tracing";
|
|
1395
2096
|
import { Callback, tracer } from "@dxos/util";
|
|
1396
|
-
function
|
|
2097
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
1397
2098
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1398
2099
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
1399
2100
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1403,14 +2104,14 @@ function _ts_decorate4(decorators, target, key, desc) {
|
|
|
1403
2104
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1404
2105
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1405
2106
|
}
|
|
1406
|
-
var
|
|
2107
|
+
var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/control-pipeline.ts";
|
|
1407
2108
|
var TIMEFRAME_SAVE_DEBOUNCE_INTERVAL = 500;
|
|
1408
2109
|
var CONTROL_PIPELINE_SNAPSHOT_DELAY = 1e4;
|
|
1409
2110
|
var USE_SNAPSHOTS = true;
|
|
1410
2111
|
var ControlPipeline = class {
|
|
1411
2112
|
constructor({ spaceKey, genesisFeed, feedProvider, metadataStore }) {
|
|
1412
2113
|
this._ctx = new Context4(void 0, {
|
|
1413
|
-
F:
|
|
2114
|
+
F: __dxlog_file10,
|
|
1414
2115
|
L: 47
|
|
1415
2116
|
});
|
|
1416
2117
|
this._lastTimeframeSaveTime = Date.now();
|
|
@@ -1430,7 +2131,7 @@ var ControlPipeline = class {
|
|
|
1430
2131
|
log8("feed admitted", {
|
|
1431
2132
|
key: info.key
|
|
1432
2133
|
}, {
|
|
1433
|
-
F:
|
|
2134
|
+
F: __dxlog_file10,
|
|
1434
2135
|
L: 82,
|
|
1435
2136
|
S: this,
|
|
1436
2137
|
C: (f, a) => f(...a)
|
|
@@ -1444,7 +2145,7 @@ var ControlPipeline = class {
|
|
|
1444
2145
|
}
|
|
1445
2146
|
} catch (err) {
|
|
1446
2147
|
log8.catch(err, void 0, {
|
|
1447
|
-
F:
|
|
2148
|
+
F: __dxlog_file10,
|
|
1448
2149
|
L: 93,
|
|
1449
2150
|
S: this,
|
|
1450
2151
|
C: (f, a) => f(...a)
|
|
@@ -1476,7 +2177,7 @@ var ControlPipeline = class {
|
|
|
1476
2177
|
present: !!snapshot,
|
|
1477
2178
|
tf: snapshot?.timeframe
|
|
1478
2179
|
}, {
|
|
1479
|
-
F:
|
|
2180
|
+
F: __dxlog_file10,
|
|
1480
2181
|
L: 123,
|
|
1481
2182
|
S: this,
|
|
1482
2183
|
C: (f, a) => f(...a)
|
|
@@ -1485,20 +2186,20 @@ var ControlPipeline = class {
|
|
|
1485
2186
|
await this._processSnapshot(snapshot);
|
|
1486
2187
|
}
|
|
1487
2188
|
log8("starting...", void 0, {
|
|
1488
|
-
F:
|
|
2189
|
+
F: __dxlog_file10,
|
|
1489
2190
|
L: 128,
|
|
1490
2191
|
S: this,
|
|
1491
2192
|
C: (f, a) => f(...a)
|
|
1492
2193
|
});
|
|
1493
2194
|
setTimeout(async () => {
|
|
1494
2195
|
void this._consumePipeline(new Context4(void 0, {
|
|
1495
|
-
F:
|
|
2196
|
+
F: __dxlog_file10,
|
|
1496
2197
|
L: 130
|
|
1497
2198
|
}));
|
|
1498
2199
|
});
|
|
1499
2200
|
await this._pipeline.start();
|
|
1500
2201
|
log8("started", void 0, {
|
|
1501
|
-
F:
|
|
2202
|
+
F: __dxlog_file10,
|
|
1502
2203
|
L: 134,
|
|
1503
2204
|
S: this,
|
|
1504
2205
|
C: (f, a) => f(...a)
|
|
@@ -1515,7 +2216,7 @@ var ControlPipeline = class {
|
|
|
1515
2216
|
log8.warn("credential processing failed from snapshot", {
|
|
1516
2217
|
message
|
|
1517
2218
|
}, {
|
|
1518
|
-
F:
|
|
2219
|
+
F: __dxlog_file10,
|
|
1519
2220
|
L: 147,
|
|
1520
2221
|
S: this,
|
|
1521
2222
|
C: (f, a) => f(...a)
|
|
@@ -1537,7 +2238,7 @@ var ControlPipeline = class {
|
|
|
1537
2238
|
key: this._spaceKey,
|
|
1538
2239
|
snapshot
|
|
1539
2240
|
}, {
|
|
1540
|
-
F:
|
|
2241
|
+
F: __dxlog_file10,
|
|
1541
2242
|
L: 163,
|
|
1542
2243
|
S: this,
|
|
1543
2244
|
C: (f, a) => f(...a)
|
|
@@ -1552,7 +2253,7 @@ var ControlPipeline = class {
|
|
|
1552
2253
|
await this._processMessage(ctx, msg);
|
|
1553
2254
|
} catch (err) {
|
|
1554
2255
|
log8.catch(err, void 0, {
|
|
1555
|
-
F:
|
|
2256
|
+
F: __dxlog_file10,
|
|
1556
2257
|
L: 176,
|
|
1557
2258
|
S: this,
|
|
1558
2259
|
C: (f, a) => f(...a)
|
|
@@ -1566,7 +2267,7 @@ var ControlPipeline = class {
|
|
|
1566
2267
|
key: msg.feedKey,
|
|
1567
2268
|
seq: msg.seq
|
|
1568
2269
|
}, {
|
|
1569
|
-
F:
|
|
2270
|
+
F: __dxlog_file10,
|
|
1570
2271
|
L: 186,
|
|
1571
2272
|
S: this,
|
|
1572
2273
|
C: (f, a) => f(...a)
|
|
@@ -1581,7 +2282,7 @@ var ControlPipeline = class {
|
|
|
1581
2282
|
log8.warn("processing failed", {
|
|
1582
2283
|
msg
|
|
1583
2284
|
}, {
|
|
1584
|
-
F:
|
|
2285
|
+
F: __dxlog_file10,
|
|
1585
2286
|
L: 195,
|
|
1586
2287
|
S: this,
|
|
1587
2288
|
C: (f, a) => f(...a)
|
|
@@ -1600,7 +2301,7 @@ var ControlPipeline = class {
|
|
|
1600
2301
|
}
|
|
1601
2302
|
async stop() {
|
|
1602
2303
|
log8("stopping...", void 0, {
|
|
1603
|
-
F:
|
|
2304
|
+
F: __dxlog_file10,
|
|
1604
2305
|
L: 215,
|
|
1605
2306
|
S: this,
|
|
1606
2307
|
C: (f, a) => f(...a)
|
|
@@ -1609,7 +2310,7 @@ var ControlPipeline = class {
|
|
|
1609
2310
|
await this._pipeline.stop();
|
|
1610
2311
|
await this._saveTargetTimeframe(this._pipeline.state.timeframe);
|
|
1611
2312
|
log8("stopped", void 0, {
|
|
1612
|
-
F:
|
|
2313
|
+
F: __dxlog_file10,
|
|
1613
2314
|
L: 219,
|
|
1614
2315
|
S: this,
|
|
1615
2316
|
C: (f, a) => f(...a)
|
|
@@ -1622,7 +2323,7 @@ var ControlPipeline = class {
|
|
|
1622
2323
|
this._targetTimeframe = newTimeframe;
|
|
1623
2324
|
} catch (err) {
|
|
1624
2325
|
log8(err, void 0, {
|
|
1625
|
-
F:
|
|
2326
|
+
F: __dxlog_file10,
|
|
1626
2327
|
L: 228,
|
|
1627
2328
|
S: this,
|
|
1628
2329
|
C: (f, a) => f(...a)
|
|
@@ -1630,30 +2331,30 @@ var ControlPipeline = class {
|
|
|
1630
2331
|
}
|
|
1631
2332
|
}
|
|
1632
2333
|
};
|
|
1633
|
-
|
|
1634
|
-
|
|
2334
|
+
_ts_decorate5([
|
|
2335
|
+
trace2.metricsCounter()
|
|
1635
2336
|
], ControlPipeline.prototype, "_usage", void 0);
|
|
1636
|
-
|
|
1637
|
-
|
|
2337
|
+
_ts_decorate5([
|
|
2338
|
+
trace2.metricsCounter()
|
|
1638
2339
|
], ControlPipeline.prototype, "_mutations", void 0);
|
|
1639
|
-
|
|
1640
|
-
|
|
2340
|
+
_ts_decorate5([
|
|
2341
|
+
trace2.span({
|
|
1641
2342
|
showInBrowserTimeline: true
|
|
1642
2343
|
})
|
|
1643
2344
|
], ControlPipeline.prototype, "start", null);
|
|
1644
|
-
|
|
1645
|
-
|
|
2345
|
+
_ts_decorate5([
|
|
2346
|
+
trace2.span()
|
|
1646
2347
|
], ControlPipeline.prototype, "_consumePipeline", null);
|
|
1647
|
-
|
|
1648
|
-
|
|
2348
|
+
_ts_decorate5([
|
|
2349
|
+
trace2.span()
|
|
1649
2350
|
], ControlPipeline.prototype, "_processMessage", null);
|
|
1650
|
-
ControlPipeline =
|
|
1651
|
-
|
|
2351
|
+
ControlPipeline = _ts_decorate5([
|
|
2352
|
+
trace2.resource(),
|
|
1652
2353
|
trackLeaks("start", "stop")
|
|
1653
2354
|
], ControlPipeline);
|
|
1654
2355
|
|
|
1655
2356
|
// packages/core/echo/echo-pipeline/src/space/space.ts
|
|
1656
|
-
function
|
|
2357
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
1657
2358
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1658
2359
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
1659
2360
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1663,15 +2364,15 @@ function _ts_decorate5(decorators, target, key, desc) {
|
|
|
1663
2364
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1664
2365
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1665
2366
|
}
|
|
1666
|
-
var
|
|
1667
|
-
var Space = class extends
|
|
2367
|
+
var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space.ts";
|
|
2368
|
+
var Space = class extends Resource5 {
|
|
1668
2369
|
constructor(params) {
|
|
1669
2370
|
super();
|
|
1670
2371
|
this._addFeedMutex = new Mutex();
|
|
1671
2372
|
this.onCredentialProcessed = new Callback2();
|
|
1672
|
-
this.stateUpdate = new
|
|
1673
|
-
|
|
1674
|
-
F:
|
|
2373
|
+
this.stateUpdate = new Event5();
|
|
2374
|
+
invariant9(params.spaceKey && params.feedProvider, void 0, {
|
|
2375
|
+
F: __dxlog_file11,
|
|
1675
2376
|
L: 78,
|
|
1676
2377
|
S: this,
|
|
1677
2378
|
A: [
|
|
@@ -1705,7 +2406,7 @@ var Space = class extends Resource2 {
|
|
|
1705
2406
|
log9("onCredentialProcessed", {
|
|
1706
2407
|
credential
|
|
1707
2408
|
}, {
|
|
1708
|
-
F:
|
|
2409
|
+
F: __dxlog_file11,
|
|
1709
2410
|
L: 106,
|
|
1710
2411
|
S: this,
|
|
1711
2412
|
C: (f, a) => f(...a)
|
|
@@ -1716,7 +2417,7 @@ var Space = class extends Resource2 {
|
|
|
1716
2417
|
log9("onDelegatedInvitation", {
|
|
1717
2418
|
invitation
|
|
1718
2419
|
}, {
|
|
1719
|
-
F:
|
|
2420
|
+
F: __dxlog_file11,
|
|
1720
2421
|
L: 110,
|
|
1721
2422
|
S: this,
|
|
1722
2423
|
C: (f, a) => f(...a)
|
|
@@ -1727,7 +2428,7 @@ var Space = class extends Resource2 {
|
|
|
1727
2428
|
log9("onDelegatedInvitationRemoved", {
|
|
1728
2429
|
invitation
|
|
1729
2430
|
}, {
|
|
1730
|
-
F:
|
|
2431
|
+
F: __dxlog_file11,
|
|
1731
2432
|
L: 114,
|
|
1732
2433
|
S: this,
|
|
1733
2434
|
C: (f, a) => f(...a)
|
|
@@ -1741,7 +2442,7 @@ var Space = class extends Resource2 {
|
|
|
1741
2442
|
m.role
|
|
1742
2443
|
])
|
|
1743
2444
|
}), {
|
|
1744
|
-
F:
|
|
2445
|
+
F: __dxlog_file11,
|
|
1745
2446
|
L: 118,
|
|
1746
2447
|
S: this,
|
|
1747
2448
|
C: (f, a) => f(...a)
|
|
@@ -1758,7 +2459,7 @@ var Space = class extends Resource2 {
|
|
|
1758
2459
|
return this._key;
|
|
1759
2460
|
}
|
|
1760
2461
|
get isOpen() {
|
|
1761
|
-
return this._lifecycleState ===
|
|
2462
|
+
return this._lifecycleState === LifecycleState3.OPEN;
|
|
1762
2463
|
}
|
|
1763
2464
|
get genesisFeedKey() {
|
|
1764
2465
|
return this._genesisFeedKey;
|
|
@@ -1782,8 +2483,8 @@ var Space = class extends Resource2 {
|
|
|
1782
2483
|
return this._snapshotManager;
|
|
1783
2484
|
}
|
|
1784
2485
|
async setControlFeed(feed) {
|
|
1785
|
-
|
|
1786
|
-
F:
|
|
2486
|
+
invariant9(!this._controlFeed, "Control feed already set.", {
|
|
2487
|
+
F: __dxlog_file11,
|
|
1787
2488
|
L: 171,
|
|
1788
2489
|
S: this,
|
|
1789
2490
|
A: [
|
|
@@ -1796,8 +2497,8 @@ var Space = class extends Resource2 {
|
|
|
1796
2497
|
return this;
|
|
1797
2498
|
}
|
|
1798
2499
|
async setDataFeed(feed) {
|
|
1799
|
-
|
|
1800
|
-
F:
|
|
2500
|
+
invariant9(!this._dataFeed, "Data feed already set.", {
|
|
2501
|
+
F: __dxlog_file11,
|
|
1801
2502
|
L: 178,
|
|
1802
2503
|
S: this,
|
|
1803
2504
|
A: [
|
|
@@ -1816,7 +2517,7 @@ var Space = class extends Resource2 {
|
|
|
1816
2517
|
}
|
|
1817
2518
|
async _open(ctx) {
|
|
1818
2519
|
log9("opening...", void 0, {
|
|
1819
|
-
F:
|
|
2520
|
+
F: __dxlog_file11,
|
|
1820
2521
|
L: 192,
|
|
1821
2522
|
S: this,
|
|
1822
2523
|
C: (f, a) => f(...a)
|
|
@@ -1824,7 +2525,7 @@ var Space = class extends Resource2 {
|
|
|
1824
2525
|
await this._controlPipeline.start();
|
|
1825
2526
|
await this.protocol.start();
|
|
1826
2527
|
log9("opened", void 0, {
|
|
1827
|
-
F:
|
|
2528
|
+
F: __dxlog_file11,
|
|
1828
2529
|
L: 198,
|
|
1829
2530
|
S: this,
|
|
1830
2531
|
C: (f, a) => f(...a)
|
|
@@ -1834,7 +2535,7 @@ var Space = class extends Resource2 {
|
|
|
1834
2535
|
log9("closing...", {
|
|
1835
2536
|
key: this._key
|
|
1836
2537
|
}, {
|
|
1837
|
-
F:
|
|
2538
|
+
F: __dxlog_file11,
|
|
1838
2539
|
L: 203,
|
|
1839
2540
|
S: this,
|
|
1840
2541
|
C: (f, a) => f(...a)
|
|
@@ -1842,67 +2543,67 @@ var Space = class extends Resource2 {
|
|
|
1842
2543
|
await this.protocol.stop();
|
|
1843
2544
|
await this._controlPipeline.stop();
|
|
1844
2545
|
log9("closed", void 0, {
|
|
1845
|
-
F:
|
|
2546
|
+
F: __dxlog_file11,
|
|
1846
2547
|
L: 209,
|
|
1847
2548
|
S: this,
|
|
1848
2549
|
C: (f, a) => f(...a)
|
|
1849
2550
|
});
|
|
1850
2551
|
}
|
|
1851
2552
|
};
|
|
1852
|
-
|
|
1853
|
-
|
|
2553
|
+
_ts_decorate6([
|
|
2554
|
+
trace3.info()
|
|
1854
2555
|
], Space.prototype, "protocol", void 0);
|
|
1855
|
-
|
|
1856
|
-
|
|
2556
|
+
_ts_decorate6([
|
|
2557
|
+
trace3.info()
|
|
1857
2558
|
], Space.prototype, "_controlPipeline", void 0);
|
|
1858
|
-
|
|
2559
|
+
_ts_decorate6([
|
|
1859
2560
|
logInfo,
|
|
1860
|
-
|
|
2561
|
+
trace3.info()
|
|
1861
2562
|
], Space.prototype, "id", null);
|
|
1862
|
-
|
|
2563
|
+
_ts_decorate6([
|
|
1863
2564
|
logInfo,
|
|
1864
|
-
|
|
2565
|
+
trace3.info()
|
|
1865
2566
|
], Space.prototype, "key", null);
|
|
1866
|
-
|
|
1867
|
-
|
|
2567
|
+
_ts_decorate6([
|
|
2568
|
+
trace3.span()
|
|
1868
2569
|
], Space.prototype, "_open", null);
|
|
1869
|
-
|
|
2570
|
+
_ts_decorate6([
|
|
1870
2571
|
synchronized3
|
|
1871
2572
|
], Space.prototype, "_close", null);
|
|
1872
|
-
Space =
|
|
2573
|
+
Space = _ts_decorate6([
|
|
1873
2574
|
trackLeaks2("open", "close"),
|
|
1874
|
-
|
|
2575
|
+
trace3.resource()
|
|
1875
2576
|
], Space);
|
|
1876
|
-
var SPACE_IDS_CACHE = new
|
|
2577
|
+
var SPACE_IDS_CACHE = new ComplexMap2(PublicKey5.hash);
|
|
1877
2578
|
var createIdFromSpaceKey = async (spaceKey) => {
|
|
1878
2579
|
const cachedValue = SPACE_IDS_CACHE.get(spaceKey);
|
|
1879
2580
|
if (cachedValue !== void 0) {
|
|
1880
2581
|
return cachedValue;
|
|
1881
2582
|
}
|
|
1882
2583
|
const digest = await subtleCrypto2.digest("SHA-256", spaceKey.asUint8Array());
|
|
1883
|
-
const bytes = new Uint8Array(digest).slice(0,
|
|
1884
|
-
const spaceId =
|
|
2584
|
+
const bytes = new Uint8Array(digest).slice(0, SpaceId2.byteLength);
|
|
2585
|
+
const spaceId = SpaceId2.encode(bytes);
|
|
1885
2586
|
SPACE_IDS_CACHE.set(spaceKey, spaceId);
|
|
1886
2587
|
return spaceId;
|
|
1887
2588
|
};
|
|
1888
2589
|
|
|
1889
2590
|
// packages/core/echo/echo-pipeline/src/space/admission-discovery-extension.ts
|
|
1890
|
-
import { scheduleTask as
|
|
2591
|
+
import { scheduleTask as scheduleTask3 } from "@dxos/async";
|
|
1891
2592
|
import { Context as Context5 } from "@dxos/context";
|
|
1892
|
-
import { ProtocolError, schema as
|
|
2593
|
+
import { ProtocolError, schema as schema5 } from "@dxos/protocols";
|
|
1893
2594
|
import { RpcExtension as RpcExtension2 } from "@dxos/teleport";
|
|
1894
|
-
var
|
|
2595
|
+
var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/admission-discovery-extension.ts";
|
|
1895
2596
|
var CredentialRetrieverExtension = class extends RpcExtension2 {
|
|
1896
2597
|
constructor(_request, _onResult) {
|
|
1897
2598
|
super({
|
|
1898
2599
|
requested: {
|
|
1899
|
-
AdmissionDiscoveryService:
|
|
2600
|
+
AdmissionDiscoveryService: schema5.getService("dxos.mesh.teleport.AdmissionDiscoveryService")
|
|
1900
2601
|
}
|
|
1901
2602
|
});
|
|
1902
2603
|
this._request = _request;
|
|
1903
2604
|
this._onResult = _onResult;
|
|
1904
2605
|
this._ctx = new Context5(void 0, {
|
|
1905
|
-
F:
|
|
2606
|
+
F: __dxlog_file12,
|
|
1906
2607
|
L: 25
|
|
1907
2608
|
});
|
|
1908
2609
|
}
|
|
@@ -1911,7 +2612,7 @@ var CredentialRetrieverExtension = class extends RpcExtension2 {
|
|
|
1911
2612
|
}
|
|
1912
2613
|
async onOpen(context) {
|
|
1913
2614
|
await super.onOpen(context);
|
|
1914
|
-
|
|
2615
|
+
scheduleTask3(this._ctx, async () => {
|
|
1915
2616
|
try {
|
|
1916
2617
|
const result = await this.rpc.AdmissionDiscoveryService.getAdmissionCredential(this._request);
|
|
1917
2618
|
this._onResult.wake(result.admissionCredential);
|
|
@@ -1919,267 +2620,719 @@ var CredentialRetrieverExtension = class extends RpcExtension2 {
|
|
|
1919
2620
|
context.close(err);
|
|
1920
2621
|
}
|
|
1921
2622
|
});
|
|
1922
|
-
}
|
|
1923
|
-
async onClose() {
|
|
1924
|
-
await this._ctx.dispose();
|
|
1925
|
-
}
|
|
1926
|
-
async onAbort() {
|
|
1927
|
-
await this._ctx.dispose();
|
|
1928
|
-
}
|
|
1929
|
-
};
|
|
1930
|
-
var CredentialServerExtension = class extends RpcExtension2 {
|
|
1931
|
-
constructor(_space) {
|
|
1932
|
-
super({
|
|
1933
|
-
exposed: {
|
|
1934
|
-
AdmissionDiscoveryService:
|
|
2623
|
+
}
|
|
2624
|
+
async onClose() {
|
|
2625
|
+
await this._ctx.dispose();
|
|
2626
|
+
}
|
|
2627
|
+
async onAbort() {
|
|
2628
|
+
await this._ctx.dispose();
|
|
2629
|
+
}
|
|
2630
|
+
};
|
|
2631
|
+
var CredentialServerExtension = class extends RpcExtension2 {
|
|
2632
|
+
constructor(_space) {
|
|
2633
|
+
super({
|
|
2634
|
+
exposed: {
|
|
2635
|
+
AdmissionDiscoveryService: schema5.getService("dxos.mesh.teleport.AdmissionDiscoveryService")
|
|
2636
|
+
}
|
|
2637
|
+
});
|
|
2638
|
+
this._space = _space;
|
|
2639
|
+
}
|
|
2640
|
+
async getHandlers() {
|
|
2641
|
+
return {
|
|
2642
|
+
AdmissionDiscoveryService: {
|
|
2643
|
+
getAdmissionCredential: async (request) => {
|
|
2644
|
+
const memberInfo = this._space.spaceState.members.get(request.memberKey);
|
|
2645
|
+
if (!memberInfo?.credential) {
|
|
2646
|
+
throw new ProtocolError("Space member not found.", request);
|
|
2647
|
+
}
|
|
2648
|
+
return {
|
|
2649
|
+
admissionCredential: memberInfo.credential
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
};
|
|
2656
|
+
|
|
2657
|
+
// packages/core/echo/echo-pipeline/src/space/space-protocol.ts
|
|
2658
|
+
import { discoveryKey, subtleCrypto as subtleCrypto3 } from "@dxos/crypto";
|
|
2659
|
+
import { PublicKey as PublicKey6 } from "@dxos/keys";
|
|
2660
|
+
import { log as log10, logInfo as logInfo2 } from "@dxos/log";
|
|
2661
|
+
import { MMSTTopology } from "@dxos/network-manager";
|
|
2662
|
+
import { Teleport } from "@dxos/teleport";
|
|
2663
|
+
import { BlobSync } from "@dxos/teleport-extension-object-sync";
|
|
2664
|
+
import { ReplicatorExtension } from "@dxos/teleport-extension-replicator";
|
|
2665
|
+
import { trace as trace4 } from "@dxos/tracing";
|
|
2666
|
+
import { ComplexMap as ComplexMap3 } from "@dxos/util";
|
|
2667
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
2668
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2669
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
2670
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
2671
|
+
else
|
|
2672
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
2673
|
+
if (d = decorators[i])
|
|
2674
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2675
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2676
|
+
}
|
|
2677
|
+
var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space-protocol.ts";
|
|
2678
|
+
var MOCK_AUTH_PROVIDER = async (nonce) => Buffer.from("mock");
|
|
2679
|
+
var MOCK_AUTH_VERIFIER = async (nonce, credential) => true;
|
|
2680
|
+
var SpaceProtocol = class {
|
|
2681
|
+
constructor({ topic, swarmIdentity, networkManager, onSessionAuth, onAuthFailure, blobStore }) {
|
|
2682
|
+
this._feeds = /* @__PURE__ */ new Set();
|
|
2683
|
+
this._sessions = new ComplexMap3(PublicKey6.hash);
|
|
2684
|
+
// TODO(burdon): Move to config (with sensible defaults).
|
|
2685
|
+
this._topology = new MMSTTopology({
|
|
2686
|
+
originateConnections: 4,
|
|
2687
|
+
maxPeers: 10,
|
|
2688
|
+
sampleSize: 20
|
|
2689
|
+
});
|
|
2690
|
+
this._spaceKey = topic;
|
|
2691
|
+
this._networkManager = networkManager;
|
|
2692
|
+
this._swarmIdentity = swarmIdentity;
|
|
2693
|
+
this._onSessionAuth = onSessionAuth;
|
|
2694
|
+
this._onAuthFailure = onAuthFailure;
|
|
2695
|
+
this.blobSync = new BlobSync({
|
|
2696
|
+
blobStore
|
|
2697
|
+
});
|
|
2698
|
+
this._topic = subtleCrypto3.digest("SHA-256", topic.asBuffer()).then(discoveryKey).then(PublicKey6.from);
|
|
2699
|
+
}
|
|
2700
|
+
get sessions() {
|
|
2701
|
+
return this._sessions;
|
|
2702
|
+
}
|
|
2703
|
+
get feeds() {
|
|
2704
|
+
return this._feeds;
|
|
2705
|
+
}
|
|
2706
|
+
get _ownPeerKey() {
|
|
2707
|
+
return this._swarmIdentity.peerKey;
|
|
2708
|
+
}
|
|
2709
|
+
// TODO(burdon): Create abstraction for Space (e.g., add keys and have provider).
|
|
2710
|
+
addFeed(feed) {
|
|
2711
|
+
log10("addFeed", {
|
|
2712
|
+
key: feed.key
|
|
2713
|
+
}, {
|
|
2714
|
+
F: __dxlog_file13,
|
|
2715
|
+
L: 109,
|
|
2716
|
+
S: this,
|
|
2717
|
+
C: (f, a) => f(...a)
|
|
2718
|
+
});
|
|
2719
|
+
this._feeds.add(feed);
|
|
2720
|
+
for (const session of this._sessions.values()) {
|
|
2721
|
+
session.replicator.addFeed(feed);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
// TODO(burdon): Rename open? Common open/close interfaces for all services?
|
|
2725
|
+
async start() {
|
|
2726
|
+
if (this._connection) {
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
const credentials = await this._swarmIdentity.credentialProvider(Buffer.from(""));
|
|
2730
|
+
await this.blobSync.open();
|
|
2731
|
+
log10("starting...", void 0, {
|
|
2732
|
+
F: __dxlog_file13,
|
|
2733
|
+
L: 128,
|
|
2734
|
+
S: this,
|
|
2735
|
+
C: (f, a) => f(...a)
|
|
2736
|
+
});
|
|
2737
|
+
const topic = await this._topic;
|
|
2738
|
+
this._connection = await this._networkManager.joinSwarm({
|
|
2739
|
+
protocolProvider: this._createProtocolProvider(credentials),
|
|
2740
|
+
peerId: this._swarmIdentity.peerKey,
|
|
2741
|
+
topic,
|
|
2742
|
+
topology: this._topology,
|
|
2743
|
+
label: `swarm ${topic.truncate()} for space ${this._spaceKey.truncate()}`
|
|
2744
|
+
});
|
|
2745
|
+
log10("started", void 0, {
|
|
2746
|
+
F: __dxlog_file13,
|
|
2747
|
+
L: 138,
|
|
2748
|
+
S: this,
|
|
2749
|
+
C: (f, a) => f(...a)
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
updateTopology() {
|
|
2753
|
+
this._topology.forceUpdate();
|
|
2754
|
+
}
|
|
2755
|
+
async stop() {
|
|
2756
|
+
await this.blobSync.close();
|
|
2757
|
+
if (this._connection) {
|
|
2758
|
+
log10("stopping...", void 0, {
|
|
2759
|
+
F: __dxlog_file13,
|
|
2760
|
+
L: 149,
|
|
2761
|
+
S: this,
|
|
2762
|
+
C: (f, a) => f(...a)
|
|
2763
|
+
});
|
|
2764
|
+
await this._connection.close();
|
|
2765
|
+
log10("stopped", void 0, {
|
|
2766
|
+
F: __dxlog_file13,
|
|
2767
|
+
L: 151,
|
|
2768
|
+
S: this,
|
|
2769
|
+
C: (f, a) => f(...a)
|
|
2770
|
+
});
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
_createProtocolProvider(credentials) {
|
|
2774
|
+
return (wireParams) => {
|
|
2775
|
+
const session = new SpaceProtocolSession({
|
|
2776
|
+
wireParams,
|
|
2777
|
+
swarmIdentity: this._swarmIdentity,
|
|
2778
|
+
onSessionAuth: this._onSessionAuth,
|
|
2779
|
+
onAuthFailure: this._onAuthFailure,
|
|
2780
|
+
blobSync: this.blobSync
|
|
2781
|
+
});
|
|
2782
|
+
this._sessions.set(wireParams.remotePeerId, session);
|
|
2783
|
+
for (const feed of this._feeds) {
|
|
2784
|
+
session.replicator.addFeed(feed);
|
|
2785
|
+
}
|
|
2786
|
+
return session;
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
};
|
|
2790
|
+
_ts_decorate7([
|
|
2791
|
+
logInfo2,
|
|
2792
|
+
trace4.info()
|
|
2793
|
+
], SpaceProtocol.prototype, "_topic", void 0);
|
|
2794
|
+
_ts_decorate7([
|
|
2795
|
+
trace4.info()
|
|
2796
|
+
], SpaceProtocol.prototype, "_spaceKey", void 0);
|
|
2797
|
+
_ts_decorate7([
|
|
2798
|
+
logInfo2
|
|
2799
|
+
], SpaceProtocol.prototype, "_ownPeerKey", null);
|
|
2800
|
+
SpaceProtocol = _ts_decorate7([
|
|
2801
|
+
trace4.resource()
|
|
2802
|
+
], SpaceProtocol);
|
|
2803
|
+
var AuthStatus;
|
|
2804
|
+
(function(AuthStatus2) {
|
|
2805
|
+
AuthStatus2["INITIAL"] = "INITIAL";
|
|
2806
|
+
AuthStatus2["SUCCESS"] = "SUCCESS";
|
|
2807
|
+
AuthStatus2["FAILURE"] = "FAILURE";
|
|
2808
|
+
})(AuthStatus || (AuthStatus = {}));
|
|
2809
|
+
var SpaceProtocolSession = class {
|
|
2810
|
+
// TODO(dmaretskyi): Allow to pass in extra extensions.
|
|
2811
|
+
constructor({ wireParams, swarmIdentity, onSessionAuth, onAuthFailure, blobSync }) {
|
|
2812
|
+
// TODO(dmaretskyi): Start with upload=false when switching it on the fly works.
|
|
2813
|
+
this.replicator = new ReplicatorExtension().setOptions({
|
|
2814
|
+
upload: true
|
|
2815
|
+
});
|
|
2816
|
+
this._authStatus = "INITIAL";
|
|
2817
|
+
this._wireParams = wireParams;
|
|
2818
|
+
this._swarmIdentity = swarmIdentity;
|
|
2819
|
+
this._onSessionAuth = onSessionAuth;
|
|
2820
|
+
this._onAuthFailure = onAuthFailure;
|
|
2821
|
+
this._blobSync = blobSync;
|
|
2822
|
+
this._teleport = new Teleport(wireParams);
|
|
2823
|
+
}
|
|
2824
|
+
get authStatus() {
|
|
2825
|
+
return this._authStatus;
|
|
2826
|
+
}
|
|
2827
|
+
get stats() {
|
|
2828
|
+
return this._teleport.stats;
|
|
2829
|
+
}
|
|
2830
|
+
get stream() {
|
|
2831
|
+
return this._teleport.stream;
|
|
2832
|
+
}
|
|
2833
|
+
async open(sessionId) {
|
|
2834
|
+
await this._teleport.open(sessionId);
|
|
2835
|
+
this._teleport.addExtension("dxos.mesh.teleport.auth", new AuthExtension({
|
|
2836
|
+
provider: this._swarmIdentity.credentialProvider,
|
|
2837
|
+
verifier: this._swarmIdentity.credentialAuthenticator,
|
|
2838
|
+
onAuthSuccess: () => {
|
|
2839
|
+
log10("Peer authenticated", void 0, {
|
|
2840
|
+
F: __dxlog_file13,
|
|
2841
|
+
L: 248,
|
|
2842
|
+
S: this,
|
|
2843
|
+
C: (f, a) => f(...a)
|
|
2844
|
+
});
|
|
2845
|
+
this._authStatus = "SUCCESS";
|
|
2846
|
+
this._onSessionAuth?.(this._teleport);
|
|
2847
|
+
},
|
|
2848
|
+
onAuthFailure: () => {
|
|
2849
|
+
this._authStatus = "FAILURE";
|
|
2850
|
+
this._onAuthFailure?.(this._teleport);
|
|
2851
|
+
}
|
|
2852
|
+
}));
|
|
2853
|
+
this._teleport.addExtension("dxos.mesh.teleport.replicator", this.replicator);
|
|
2854
|
+
this._teleport.addExtension("dxos.mesh.teleport.blobsync", this._blobSync.createExtension());
|
|
2855
|
+
}
|
|
2856
|
+
async close() {
|
|
2857
|
+
log10("close", void 0, {
|
|
2858
|
+
F: __dxlog_file13,
|
|
2859
|
+
L: 264,
|
|
2860
|
+
S: this,
|
|
2861
|
+
C: (f, a) => f(...a)
|
|
2862
|
+
});
|
|
2863
|
+
await this._teleport.close();
|
|
2864
|
+
}
|
|
2865
|
+
async abort() {
|
|
2866
|
+
await this._teleport.abort();
|
|
2867
|
+
}
|
|
2868
|
+
};
|
|
2869
|
+
_ts_decorate7([
|
|
2870
|
+
logInfo2
|
|
2871
|
+
], SpaceProtocolSession.prototype, "_wireParams", void 0);
|
|
2872
|
+
_ts_decorate7([
|
|
2873
|
+
logInfo2
|
|
2874
|
+
], SpaceProtocolSession.prototype, "authStatus", null);
|
|
2875
|
+
|
|
2876
|
+
// packages/core/echo/echo-pipeline/src/space/space-manager.ts
|
|
2877
|
+
import { synchronized as synchronized4, trackLeaks as trackLeaks3, Trigger as Trigger3 } from "@dxos/async";
|
|
2878
|
+
import { failUndefined as failUndefined2 } from "@dxos/debug";
|
|
2879
|
+
import { PublicKey as PublicKey8 } from "@dxos/keys";
|
|
2880
|
+
import { log as log14 } from "@dxos/log";
|
|
2881
|
+
import { trace as trace5 } from "@dxos/protocols";
|
|
2882
|
+
import { ComplexMap as ComplexMap4 } from "@dxos/util";
|
|
2883
|
+
|
|
2884
|
+
// packages/core/echo/echo-pipeline/src/db-host/data-service.ts
|
|
2885
|
+
import { Stream } from "@dxos/codec-protobuf";
|
|
2886
|
+
import { invariant as invariant12 } from "@dxos/invariant";
|
|
2887
|
+
import { SpaceId as SpaceId3 } from "@dxos/keys";
|
|
2888
|
+
import { log as log13 } from "@dxos/log";
|
|
2889
|
+
|
|
2890
|
+
// packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts
|
|
2891
|
+
import { invariant as invariant11 } from "@dxos/invariant";
|
|
2892
|
+
import { PublicKey as PublicKey7 } from "@dxos/keys";
|
|
2893
|
+
import { log as log12 } from "@dxos/log";
|
|
2894
|
+
import { ComplexSet, defaultMap as defaultMap2 } from "@dxos/util";
|
|
2895
|
+
|
|
2896
|
+
// packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts
|
|
2897
|
+
import { cbor } from "@dxos/automerge/automerge-repo";
|
|
2898
|
+
import { Resource as Resource6 } from "@dxos/context";
|
|
2899
|
+
import { invariant as invariant10 } from "@dxos/invariant";
|
|
2900
|
+
import { log as log11 } from "@dxos/log";
|
|
2901
|
+
import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
|
|
2902
|
+
var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
|
|
2903
|
+
var DEFAULT_FACTORY = (params) => new AutomergeReplicator(...params);
|
|
2904
|
+
var MeshReplicatorConnection = class extends Resource6 {
|
|
2905
|
+
constructor(_params) {
|
|
2906
|
+
super();
|
|
2907
|
+
this._params = _params;
|
|
2908
|
+
this.remoteDeviceKey = null;
|
|
2909
|
+
this._remotePeerId = null;
|
|
2910
|
+
this._isEnabled = false;
|
|
2911
|
+
let readableStreamController;
|
|
2912
|
+
this.readable = new ReadableStream({
|
|
2913
|
+
start: (controller) => {
|
|
2914
|
+
readableStreamController = controller;
|
|
2915
|
+
this._ctx.onDispose(() => controller.close());
|
|
2916
|
+
}
|
|
2917
|
+
});
|
|
2918
|
+
this.writable = new WritableStream({
|
|
2919
|
+
write: async (message, controller) => {
|
|
2920
|
+
invariant10(this._isEnabled, "Writing to a disabled connection", {
|
|
2921
|
+
F: __dxlog_file14,
|
|
2922
|
+
L: 48,
|
|
2923
|
+
S: this,
|
|
2924
|
+
A: [
|
|
2925
|
+
"this._isEnabled",
|
|
2926
|
+
"'Writing to a disabled connection'"
|
|
2927
|
+
]
|
|
2928
|
+
});
|
|
2929
|
+
try {
|
|
2930
|
+
await this.replicatorExtension.sendSyncMessage({
|
|
2931
|
+
payload: cbor.encode(message)
|
|
2932
|
+
});
|
|
2933
|
+
} catch (err) {
|
|
2934
|
+
controller.error(err);
|
|
2935
|
+
this._disconnectIfEnabled();
|
|
2936
|
+
}
|
|
1935
2937
|
}
|
|
1936
2938
|
});
|
|
1937
|
-
this.
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2939
|
+
const createAutomergeReplicator = this._params.replicatorFactory ?? DEFAULT_FACTORY;
|
|
2940
|
+
this.replicatorExtension = createAutomergeReplicator([
|
|
2941
|
+
{
|
|
2942
|
+
peerId: this._params.ownPeerId
|
|
2943
|
+
},
|
|
2944
|
+
{
|
|
2945
|
+
onStartReplication: async (info, remotePeerId) => {
|
|
2946
|
+
this.remoteDeviceKey = remotePeerId;
|
|
2947
|
+
this._remotePeerId = info.id;
|
|
2948
|
+
log11("onStartReplication", {
|
|
2949
|
+
id: info.id,
|
|
2950
|
+
thisPeerId: this.peerId,
|
|
2951
|
+
remotePeerId: remotePeerId.toHex()
|
|
2952
|
+
}, {
|
|
2953
|
+
F: __dxlog_file14,
|
|
2954
|
+
L: 82,
|
|
2955
|
+
S: this,
|
|
2956
|
+
C: (f, a) => f(...a)
|
|
2957
|
+
});
|
|
2958
|
+
this._params.onRemoteConnected();
|
|
2959
|
+
},
|
|
2960
|
+
onSyncMessage: async ({ payload }) => {
|
|
2961
|
+
if (!this._isEnabled) {
|
|
2962
|
+
return;
|
|
1946
2963
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2964
|
+
const message = cbor.decode(payload);
|
|
2965
|
+
readableStreamController.enqueue(message);
|
|
2966
|
+
},
|
|
2967
|
+
onClose: async () => {
|
|
2968
|
+
this._disconnectIfEnabled();
|
|
1950
2969
|
}
|
|
1951
2970
|
}
|
|
1952
|
-
|
|
2971
|
+
]);
|
|
1953
2972
|
}
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
import { PublicKey as PublicKey6 } from "@dxos/keys";
|
|
1959
|
-
import { log as log10, logInfo as logInfo2 } from "@dxos/log";
|
|
1960
|
-
import { MMSTTopology } from "@dxos/network-manager";
|
|
1961
|
-
import { Teleport } from "@dxos/teleport";
|
|
1962
|
-
import { BlobSync } from "@dxos/teleport-extension-object-sync";
|
|
1963
|
-
import { ReplicatorExtension } from "@dxos/teleport-extension-replicator";
|
|
1964
|
-
import { trace as trace3 } from "@dxos/tracing";
|
|
1965
|
-
import { ComplexMap as ComplexMap4 } from "@dxos/util";
|
|
1966
|
-
function _ts_decorate6(decorators, target, key, desc) {
|
|
1967
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1968
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
1969
|
-
r = Reflect.decorate(decorators, target, key, desc);
|
|
1970
|
-
else
|
|
1971
|
-
for (var i = decorators.length - 1; i >= 0; i--)
|
|
1972
|
-
if (d = decorators[i])
|
|
1973
|
-
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1974
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1975
|
-
}
|
|
1976
|
-
var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space-protocol.ts";
|
|
1977
|
-
var MOCK_AUTH_PROVIDER = async (nonce) => Buffer.from("mock");
|
|
1978
|
-
var MOCK_AUTH_VERIFIER = async (nonce, credential) => true;
|
|
1979
|
-
var SpaceProtocol = class {
|
|
1980
|
-
constructor({ topic, swarmIdentity, networkManager, onSessionAuth, onAuthFailure, blobStore }) {
|
|
1981
|
-
this._feeds = /* @__PURE__ */ new Set();
|
|
1982
|
-
this._sessions = new ComplexMap4(PublicKey6.hash);
|
|
1983
|
-
// TODO(burdon): Move to config (with sensible defaults).
|
|
1984
|
-
this._topology = new MMSTTopology({
|
|
1985
|
-
originateConnections: 4,
|
|
1986
|
-
maxPeers: 10,
|
|
1987
|
-
sampleSize: 20
|
|
1988
|
-
});
|
|
1989
|
-
this._spaceKey = topic;
|
|
1990
|
-
this._networkManager = networkManager;
|
|
1991
|
-
this._swarmIdentity = swarmIdentity;
|
|
1992
|
-
this._onSessionAuth = onSessionAuth;
|
|
1993
|
-
this._onAuthFailure = onAuthFailure;
|
|
1994
|
-
this.blobSync = new BlobSync({
|
|
1995
|
-
blobStore
|
|
1996
|
-
});
|
|
1997
|
-
this._topic = subtleCrypto3.digest("SHA-256", topic.asBuffer()).then(discoveryKey).then(PublicKey6.from);
|
|
2973
|
+
_disconnectIfEnabled() {
|
|
2974
|
+
if (this._isEnabled) {
|
|
2975
|
+
this._params.onRemoteDisconnected();
|
|
2976
|
+
}
|
|
1998
2977
|
}
|
|
1999
|
-
get
|
|
2000
|
-
|
|
2978
|
+
get peerId() {
|
|
2979
|
+
invariant10(this._remotePeerId != null, "Remote peer has not connected yet.", {
|
|
2980
|
+
F: __dxlog_file14,
|
|
2981
|
+
L: 108,
|
|
2982
|
+
S: this,
|
|
2983
|
+
A: [
|
|
2984
|
+
"this._remotePeerId != null",
|
|
2985
|
+
"'Remote peer has not connected yet.'"
|
|
2986
|
+
]
|
|
2987
|
+
});
|
|
2988
|
+
return this._remotePeerId;
|
|
2001
2989
|
}
|
|
2002
|
-
|
|
2003
|
-
return this.
|
|
2990
|
+
async shouldAdvertise(params) {
|
|
2991
|
+
return this._params.shouldAdvertise(params);
|
|
2004
2992
|
}
|
|
2005
|
-
|
|
2006
|
-
return this.
|
|
2993
|
+
shouldSyncCollection(params) {
|
|
2994
|
+
return this._params.shouldSyncCollection(params);
|
|
2007
2995
|
}
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2996
|
+
/**
|
|
2997
|
+
* Start exchanging messages with the remote peer.
|
|
2998
|
+
* Call after the remote peer has connected.
|
|
2999
|
+
*/
|
|
3000
|
+
enable() {
|
|
3001
|
+
invariant10(this._remotePeerId != null, "Remote peer has not connected yet.", {
|
|
3002
|
+
F: __dxlog_file14,
|
|
3003
|
+
L: 125,
|
|
2015
3004
|
S: this,
|
|
2016
|
-
|
|
3005
|
+
A: [
|
|
3006
|
+
"this._remotePeerId != null",
|
|
3007
|
+
"'Remote peer has not connected yet.'"
|
|
3008
|
+
]
|
|
2017
3009
|
});
|
|
2018
|
-
this.
|
|
2019
|
-
for (const session of this._sessions.values()) {
|
|
2020
|
-
session.replicator.addFeed(feed);
|
|
2021
|
-
}
|
|
3010
|
+
this._isEnabled = true;
|
|
2022
3011
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
3012
|
+
/**
|
|
3013
|
+
* Stop exchanging messages with the remote peer.
|
|
3014
|
+
*/
|
|
3015
|
+
disable() {
|
|
3016
|
+
this._isEnabled = false;
|
|
3017
|
+
}
|
|
3018
|
+
};
|
|
3019
|
+
|
|
3020
|
+
// packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts
|
|
3021
|
+
var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
|
|
3022
|
+
var MeshEchoReplicator = class {
|
|
3023
|
+
constructor() {
|
|
3024
|
+
this._connections = /* @__PURE__ */ new Set();
|
|
3025
|
+
/**
|
|
3026
|
+
* Using automerge peerId as a key.
|
|
3027
|
+
*/
|
|
3028
|
+
this._connectionsPerPeer = /* @__PURE__ */ new Map();
|
|
3029
|
+
/**
|
|
3030
|
+
* spaceId -> deviceKey[]
|
|
3031
|
+
*/
|
|
3032
|
+
this._authorizedDevices = /* @__PURE__ */ new Map();
|
|
3033
|
+
this._context = null;
|
|
3034
|
+
}
|
|
3035
|
+
async connect(context) {
|
|
3036
|
+
this._context = context;
|
|
3037
|
+
}
|
|
3038
|
+
async disconnect() {
|
|
3039
|
+
for (const connection of this._connectionsPerPeer.values()) {
|
|
3040
|
+
this._context?.onConnectionClosed(connection);
|
|
2027
3041
|
}
|
|
2028
|
-
const
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
3042
|
+
for (const connection of this._connections) {
|
|
3043
|
+
await connection.close();
|
|
3044
|
+
}
|
|
3045
|
+
this._connections.clear();
|
|
3046
|
+
this._connectionsPerPeer.clear();
|
|
3047
|
+
this._context = null;
|
|
3048
|
+
}
|
|
3049
|
+
createExtension(extensionFactory) {
|
|
3050
|
+
invariant11(this._context, void 0, {
|
|
3051
|
+
F: __dxlog_file15,
|
|
3052
|
+
L: 56,
|
|
2033
3053
|
S: this,
|
|
2034
|
-
|
|
3054
|
+
A: [
|
|
3055
|
+
"this._context",
|
|
3056
|
+
""
|
|
3057
|
+
]
|
|
2035
3058
|
});
|
|
2036
|
-
const
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
3059
|
+
const connection = new MeshReplicatorConnection({
|
|
3060
|
+
ownPeerId: this._context.peerId,
|
|
3061
|
+
replicatorFactory: extensionFactory,
|
|
3062
|
+
onRemoteConnected: async () => {
|
|
3063
|
+
log12("onRemoteConnected", {
|
|
3064
|
+
peerId: connection.peerId
|
|
3065
|
+
}, {
|
|
3066
|
+
F: __dxlog_file15,
|
|
3067
|
+
L: 62,
|
|
3068
|
+
S: this,
|
|
3069
|
+
C: (f, a) => f(...a)
|
|
3070
|
+
});
|
|
3071
|
+
invariant11(this._context, void 0, {
|
|
3072
|
+
F: __dxlog_file15,
|
|
3073
|
+
L: 63,
|
|
3074
|
+
S: this,
|
|
3075
|
+
A: [
|
|
3076
|
+
"this._context",
|
|
3077
|
+
""
|
|
3078
|
+
]
|
|
3079
|
+
});
|
|
3080
|
+
if (this._connectionsPerPeer.has(connection.peerId)) {
|
|
3081
|
+
this._context.onConnectionAuthScopeChanged(connection);
|
|
3082
|
+
} else {
|
|
3083
|
+
this._connectionsPerPeer.set(connection.peerId, connection);
|
|
3084
|
+
this._context.onConnectionOpen(connection);
|
|
3085
|
+
connection.enable();
|
|
3086
|
+
}
|
|
3087
|
+
},
|
|
3088
|
+
onRemoteDisconnected: async () => {
|
|
3089
|
+
log12("onRemoteDisconnected", {
|
|
3090
|
+
peerId: connection.peerId
|
|
3091
|
+
}, {
|
|
3092
|
+
F: __dxlog_file15,
|
|
3093
|
+
L: 74,
|
|
3094
|
+
S: this,
|
|
3095
|
+
C: (f, a) => f(...a)
|
|
3096
|
+
});
|
|
3097
|
+
this._context?.onConnectionClosed(connection);
|
|
3098
|
+
this._connectionsPerPeer.delete(connection.peerId);
|
|
3099
|
+
connection.disable();
|
|
3100
|
+
this._connections.delete(connection);
|
|
3101
|
+
},
|
|
3102
|
+
shouldAdvertise: async (params) => {
|
|
3103
|
+
log12("shouldAdvertise", {
|
|
3104
|
+
peerId: connection.peerId,
|
|
3105
|
+
documentId: params.documentId
|
|
3106
|
+
}, {
|
|
3107
|
+
F: __dxlog_file15,
|
|
3108
|
+
L: 81,
|
|
3109
|
+
S: this,
|
|
3110
|
+
C: (f, a) => f(...a)
|
|
3111
|
+
});
|
|
3112
|
+
invariant11(this._context, void 0, {
|
|
3113
|
+
F: __dxlog_file15,
|
|
3114
|
+
L: 82,
|
|
3115
|
+
S: this,
|
|
3116
|
+
A: [
|
|
3117
|
+
"this._context",
|
|
3118
|
+
""
|
|
3119
|
+
]
|
|
3120
|
+
});
|
|
3121
|
+
try {
|
|
3122
|
+
const spaceKey = await this._context.getContainingSpaceForDocument(params.documentId);
|
|
3123
|
+
if (!spaceKey) {
|
|
3124
|
+
log12("space key not found for share policy check", {
|
|
3125
|
+
peerId: connection.peerId,
|
|
3126
|
+
documentId: params.documentId
|
|
3127
|
+
}, {
|
|
3128
|
+
F: __dxlog_file15,
|
|
3129
|
+
L: 86,
|
|
3130
|
+
S: this,
|
|
3131
|
+
C: (f, a) => f(...a)
|
|
3132
|
+
});
|
|
3133
|
+
return false;
|
|
3134
|
+
}
|
|
3135
|
+
const spaceId = await createIdFromSpaceKey(spaceKey);
|
|
3136
|
+
const authorizedDevices = this._authorizedDevices.get(spaceId);
|
|
3137
|
+
if (!connection.remoteDeviceKey) {
|
|
3138
|
+
log12("device key not found for share policy check", {
|
|
3139
|
+
peerId: connection.peerId,
|
|
3140
|
+
documentId: params.documentId
|
|
3141
|
+
}, {
|
|
3142
|
+
F: __dxlog_file15,
|
|
3143
|
+
L: 98,
|
|
3144
|
+
S: this,
|
|
3145
|
+
C: (f, a) => f(...a)
|
|
3146
|
+
});
|
|
3147
|
+
return false;
|
|
3148
|
+
}
|
|
3149
|
+
const isAuthorized = authorizedDevices?.has(connection.remoteDeviceKey) ?? false;
|
|
3150
|
+
log12("share policy check", {
|
|
3151
|
+
localPeer: this._context.peerId,
|
|
3152
|
+
remotePeer: connection.peerId,
|
|
3153
|
+
documentId: params.documentId,
|
|
3154
|
+
deviceKey: connection.remoteDeviceKey,
|
|
3155
|
+
spaceKey,
|
|
3156
|
+
isAuthorized
|
|
3157
|
+
}, {
|
|
3158
|
+
F: __dxlog_file15,
|
|
3159
|
+
L: 106,
|
|
3160
|
+
S: this,
|
|
3161
|
+
C: (f, a) => f(...a)
|
|
3162
|
+
});
|
|
3163
|
+
return isAuthorized;
|
|
3164
|
+
} catch (err) {
|
|
3165
|
+
log12.catch(err, void 0, {
|
|
3166
|
+
F: __dxlog_file15,
|
|
3167
|
+
L: 116,
|
|
3168
|
+
S: this,
|
|
3169
|
+
C: (f, a) => f(...a)
|
|
3170
|
+
});
|
|
3171
|
+
return false;
|
|
3172
|
+
}
|
|
3173
|
+
},
|
|
3174
|
+
shouldSyncCollection: ({ collectionId }) => {
|
|
3175
|
+
const spaceId = getSpaceIdFromCollectionId(collectionId);
|
|
3176
|
+
const authorizedDevices = this._authorizedDevices.get(spaceId);
|
|
3177
|
+
if (!connection.remoteDeviceKey) {
|
|
3178
|
+
log12("device key not found for collection sync check", {
|
|
3179
|
+
peerId: connection.peerId,
|
|
3180
|
+
collectionId
|
|
3181
|
+
}, {
|
|
3182
|
+
F: __dxlog_file15,
|
|
3183
|
+
L: 126,
|
|
3184
|
+
S: this,
|
|
3185
|
+
C: (f, a) => f(...a)
|
|
3186
|
+
});
|
|
3187
|
+
return false;
|
|
3188
|
+
}
|
|
3189
|
+
const isAuthorized = authorizedDevices?.has(connection.remoteDeviceKey) ?? false;
|
|
3190
|
+
return isAuthorized;
|
|
3191
|
+
}
|
|
2043
3192
|
});
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
3193
|
+
this._connections.add(connection);
|
|
3194
|
+
return connection.replicatorExtension;
|
|
3195
|
+
}
|
|
3196
|
+
async authorizeDevice(spaceKey, deviceKey) {
|
|
3197
|
+
log12("authorizeDevice", {
|
|
3198
|
+
spaceKey,
|
|
3199
|
+
deviceKey
|
|
3200
|
+
}, {
|
|
3201
|
+
F: __dxlog_file15,
|
|
3202
|
+
L: 143,
|
|
2047
3203
|
S: this,
|
|
2048
3204
|
C: (f, a) => f(...a)
|
|
2049
3205
|
});
|
|
3206
|
+
const spaceId = await createIdFromSpaceKey(spaceKey);
|
|
3207
|
+
defaultMap2(this._authorizedDevices, spaceId, () => new ComplexSet(PublicKey7.hash)).add(deviceKey);
|
|
3208
|
+
for (const connection of this._connections) {
|
|
3209
|
+
if (connection.remoteDeviceKey && connection.remoteDeviceKey.equals(deviceKey)) {
|
|
3210
|
+
if (this._connectionsPerPeer.has(connection.peerId)) {
|
|
3211
|
+
this._context?.onConnectionAuthScopeChanged(connection);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
2050
3215
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
3216
|
+
};
|
|
3217
|
+
|
|
3218
|
+
// packages/core/echo/echo-pipeline/src/db-host/data-service.ts
|
|
3219
|
+
var __dxlog_file16 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service.ts";
|
|
3220
|
+
var DataServiceImpl = class {
|
|
3221
|
+
constructor(params) {
|
|
3222
|
+
/**
|
|
3223
|
+
* Map of subscriptions.
|
|
3224
|
+
* subscriptionId -> DocumentsSynchronizer
|
|
3225
|
+
*/
|
|
3226
|
+
this._subscriptions = /* @__PURE__ */ new Map();
|
|
3227
|
+
this._automergeHost = params.automergeHost;
|
|
3228
|
+
this._updateIndexes = params.updateIndexes;
|
|
2053
3229
|
}
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
L: 149,
|
|
2060
|
-
S: this,
|
|
2061
|
-
C: (f, a) => f(...a)
|
|
3230
|
+
subscribe(request) {
|
|
3231
|
+
return new Stream(({ next, ready }) => {
|
|
3232
|
+
const synchronizer = new DocumentsSynchronizer({
|
|
3233
|
+
repo: this._automergeHost.repo,
|
|
3234
|
+
sendUpdates: (updates) => next(updates)
|
|
2062
3235
|
});
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
3236
|
+
synchronizer.open().then(() => {
|
|
3237
|
+
this._subscriptions.set(request.subscriptionId, synchronizer);
|
|
3238
|
+
ready();
|
|
3239
|
+
}).catch((err) => log13.catch(err, void 0, {
|
|
3240
|
+
F: __dxlog_file16,
|
|
3241
|
+
L: 64,
|
|
2067
3242
|
S: this,
|
|
2068
3243
|
C: (f, a) => f(...a)
|
|
2069
|
-
});
|
|
3244
|
+
}));
|
|
3245
|
+
return () => synchronizer.close();
|
|
3246
|
+
});
|
|
3247
|
+
}
|
|
3248
|
+
async updateSubscription(request) {
|
|
3249
|
+
const synchronizer = this._subscriptions.get(request.subscriptionId);
|
|
3250
|
+
invariant12(synchronizer, "Subscription not found", {
|
|
3251
|
+
F: __dxlog_file16,
|
|
3252
|
+
L: 71,
|
|
3253
|
+
S: this,
|
|
3254
|
+
A: [
|
|
3255
|
+
"synchronizer",
|
|
3256
|
+
"'Subscription not found'"
|
|
3257
|
+
]
|
|
3258
|
+
});
|
|
3259
|
+
if (request.addIds?.length) {
|
|
3260
|
+
await synchronizer.addDocuments(request.addIds);
|
|
3261
|
+
}
|
|
3262
|
+
if (request.removeIds?.length) {
|
|
3263
|
+
await synchronizer.removeDocuments(request.removeIds);
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
async update(request) {
|
|
3267
|
+
if (!request.updates) {
|
|
3268
|
+
return;
|
|
2070
3269
|
}
|
|
3270
|
+
const synchronizer = this._subscriptions.get(request.subscriptionId);
|
|
3271
|
+
invariant12(synchronizer, "Subscription not found", {
|
|
3272
|
+
F: __dxlog_file16,
|
|
3273
|
+
L: 86,
|
|
3274
|
+
S: this,
|
|
3275
|
+
A: [
|
|
3276
|
+
"synchronizer",
|
|
3277
|
+
"'Subscription not found'"
|
|
3278
|
+
]
|
|
3279
|
+
});
|
|
3280
|
+
synchronizer.update(request.updates);
|
|
2071
3281
|
}
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
3282
|
+
async flush(request) {
|
|
3283
|
+
await this._automergeHost.flush(request);
|
|
3284
|
+
}
|
|
3285
|
+
async getDocumentHeads(request) {
|
|
3286
|
+
const documentIds = request.documentIds;
|
|
3287
|
+
if (!documentIds) {
|
|
3288
|
+
return {
|
|
3289
|
+
heads: {
|
|
3290
|
+
entries: []
|
|
3291
|
+
}
|
|
3292
|
+
};
|
|
3293
|
+
}
|
|
3294
|
+
const heads = await this._automergeHost.getHeads(documentIds);
|
|
3295
|
+
return {
|
|
3296
|
+
heads: {
|
|
3297
|
+
entries: heads.map((heads2, idx) => ({
|
|
3298
|
+
documentId: documentIds[idx],
|
|
3299
|
+
heads: heads2
|
|
3300
|
+
}))
|
|
2084
3301
|
}
|
|
2085
|
-
return session;
|
|
2086
3302
|
};
|
|
2087
3303
|
}
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
logInfo2,
|
|
2091
|
-
trace3.info()
|
|
2092
|
-
], SpaceProtocol.prototype, "_topic", void 0);
|
|
2093
|
-
_ts_decorate6([
|
|
2094
|
-
trace3.info()
|
|
2095
|
-
], SpaceProtocol.prototype, "_spaceKey", void 0);
|
|
2096
|
-
_ts_decorate6([
|
|
2097
|
-
logInfo2
|
|
2098
|
-
], SpaceProtocol.prototype, "_ownPeerKey", null);
|
|
2099
|
-
SpaceProtocol = _ts_decorate6([
|
|
2100
|
-
trace3.resource()
|
|
2101
|
-
], SpaceProtocol);
|
|
2102
|
-
var AuthStatus;
|
|
2103
|
-
(function(AuthStatus2) {
|
|
2104
|
-
AuthStatus2["INITIAL"] = "INITIAL";
|
|
2105
|
-
AuthStatus2["SUCCESS"] = "SUCCESS";
|
|
2106
|
-
AuthStatus2["FAILURE"] = "FAILURE";
|
|
2107
|
-
})(AuthStatus || (AuthStatus = {}));
|
|
2108
|
-
var SpaceProtocolSession = class {
|
|
2109
|
-
// TODO(dmaretskyi): Allow to pass in extra extensions.
|
|
2110
|
-
constructor({ wireParams, swarmIdentity, onSessionAuth, onAuthFailure, blobSync }) {
|
|
2111
|
-
// TODO(dmaretskyi): Start with upload=false when switching it on the fly works.
|
|
2112
|
-
this.replicator = new ReplicatorExtension().setOptions({
|
|
2113
|
-
upload: true
|
|
2114
|
-
});
|
|
2115
|
-
this._authStatus = "INITIAL";
|
|
2116
|
-
this._wireParams = wireParams;
|
|
2117
|
-
this._swarmIdentity = swarmIdentity;
|
|
2118
|
-
this._onSessionAuth = onSessionAuth;
|
|
2119
|
-
this._onAuthFailure = onAuthFailure;
|
|
2120
|
-
this._blobSync = blobSync;
|
|
2121
|
-
this._teleport = new Teleport(wireParams);
|
|
2122
|
-
}
|
|
2123
|
-
get authStatus() {
|
|
2124
|
-
return this._authStatus;
|
|
2125
|
-
}
|
|
2126
|
-
get stats() {
|
|
2127
|
-
return this._teleport.stats;
|
|
3304
|
+
async waitUntilHeadsReplicated(request, options) {
|
|
3305
|
+
await this._automergeHost.waitUntilHeadsReplicated(request.heads);
|
|
2128
3306
|
}
|
|
2129
|
-
|
|
2130
|
-
|
|
3307
|
+
async reIndexHeads(request, options) {
|
|
3308
|
+
await this._automergeHost.reIndexHeads(request.documentIds ?? []);
|
|
2131
3309
|
}
|
|
2132
|
-
async
|
|
2133
|
-
await this.
|
|
2134
|
-
this._teleport.addExtension("dxos.mesh.teleport.auth", new AuthExtension({
|
|
2135
|
-
provider: this._swarmIdentity.credentialProvider,
|
|
2136
|
-
verifier: this._swarmIdentity.credentialAuthenticator,
|
|
2137
|
-
onAuthSuccess: () => {
|
|
2138
|
-
log10("Peer authenticated", void 0, {
|
|
2139
|
-
F: __dxlog_file12,
|
|
2140
|
-
L: 248,
|
|
2141
|
-
S: this,
|
|
2142
|
-
C: (f, a) => f(...a)
|
|
2143
|
-
});
|
|
2144
|
-
this._authStatus = "SUCCESS";
|
|
2145
|
-
this._onSessionAuth?.(this._teleport);
|
|
2146
|
-
},
|
|
2147
|
-
onAuthFailure: () => {
|
|
2148
|
-
this._authStatus = "FAILURE";
|
|
2149
|
-
this._onAuthFailure?.(this._teleport);
|
|
2150
|
-
}
|
|
2151
|
-
}));
|
|
2152
|
-
this._teleport.addExtension("dxos.mesh.teleport.replicator", this.replicator);
|
|
2153
|
-
this._teleport.addExtension("dxos.mesh.teleport.blobsync", this._blobSync.createExtension());
|
|
3310
|
+
async updateIndexes() {
|
|
3311
|
+
await this._updateIndexes();
|
|
2154
3312
|
}
|
|
2155
|
-
async
|
|
2156
|
-
|
|
2157
|
-
F:
|
|
2158
|
-
L:
|
|
3313
|
+
async getSpaceSyncState(request, options) {
|
|
3314
|
+
invariant12(SpaceId3.isValid(request.spaceId), void 0, {
|
|
3315
|
+
F: __dxlog_file16,
|
|
3316
|
+
L: 127,
|
|
2159
3317
|
S: this,
|
|
2160
|
-
|
|
3318
|
+
A: [
|
|
3319
|
+
"SpaceId.isValid(request.spaceId)",
|
|
3320
|
+
""
|
|
3321
|
+
]
|
|
2161
3322
|
});
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
3323
|
+
const collectionId = deriveCollectionIdFromSpaceId(request.spaceId);
|
|
3324
|
+
const state = await this._automergeHost.getCollectionSyncState(collectionId);
|
|
3325
|
+
return {
|
|
3326
|
+
peers: state.peers.map((peer) => ({
|
|
3327
|
+
peerId: peer.peerId,
|
|
3328
|
+
documentsToReconcile: peer.differentDocuments
|
|
3329
|
+
}))
|
|
3330
|
+
};
|
|
2166
3331
|
}
|
|
2167
3332
|
};
|
|
2168
|
-
_ts_decorate6([
|
|
2169
|
-
logInfo2
|
|
2170
|
-
], SpaceProtocolSession.prototype, "_wireParams", void 0);
|
|
2171
|
-
_ts_decorate6([
|
|
2172
|
-
logInfo2
|
|
2173
|
-
], SpaceProtocolSession.prototype, "authStatus", null);
|
|
2174
3333
|
|
|
2175
3334
|
// packages/core/echo/echo-pipeline/src/space/space-manager.ts
|
|
2176
|
-
|
|
2177
|
-
import { failUndefined as failUndefined2 } from "@dxos/debug";
|
|
2178
|
-
import { PublicKey as PublicKey7 } from "@dxos/keys";
|
|
2179
|
-
import { log as log11 } from "@dxos/log";
|
|
2180
|
-
import { trace as trace4 } from "@dxos/protocols";
|
|
2181
|
-
import { ComplexMap as ComplexMap5 } from "@dxos/util";
|
|
2182
|
-
function _ts_decorate7(decorators, target, key, desc) {
|
|
3335
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
2183
3336
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2184
3337
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
2185
3338
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -2189,11 +3342,11 @@ function _ts_decorate7(decorators, target, key, desc) {
|
|
|
2189
3342
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2190
3343
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2191
3344
|
}
|
|
2192
|
-
var
|
|
3345
|
+
var __dxlog_file17 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/space/space-manager.ts";
|
|
2193
3346
|
var SpaceManager = class {
|
|
2194
3347
|
constructor({ feedStore, networkManager, metadataStore, snapshotStore, blobStore }) {
|
|
2195
|
-
this._spaces = new
|
|
2196
|
-
this._instanceId =
|
|
3348
|
+
this._spaces = new ComplexMap4(PublicKey8.hash);
|
|
3349
|
+
this._instanceId = PublicKey8.random().toHex();
|
|
2197
3350
|
this._feedStore = feedStore;
|
|
2198
3351
|
this._networkManager = networkManager;
|
|
2199
3352
|
this._metadataStore = metadataStore;
|
|
@@ -2212,18 +3365,18 @@ var SpaceManager = class {
|
|
|
2212
3365
|
].map((space) => space.close()));
|
|
2213
3366
|
}
|
|
2214
3367
|
async constructSpace({ metadata, swarmIdentity, onAuthorizedConnection, onAuthFailure, onDelegatedInvitationStatusChange, onMemberRolesChanged, memberKey }) {
|
|
2215
|
-
|
|
3368
|
+
log14.trace("dxos.echo.space-manager.construct-space", trace5.begin({
|
|
2216
3369
|
id: this._instanceId
|
|
2217
3370
|
}), {
|
|
2218
|
-
F:
|
|
3371
|
+
F: __dxlog_file17,
|
|
2219
3372
|
L: 103,
|
|
2220
3373
|
S: this,
|
|
2221
3374
|
C: (f, a) => f(...a)
|
|
2222
3375
|
});
|
|
2223
|
-
|
|
3376
|
+
log14("constructing space...", {
|
|
2224
3377
|
spaceKey: metadata.genesisFeedKey
|
|
2225
3378
|
}, {
|
|
2226
|
-
F:
|
|
3379
|
+
F: __dxlog_file17,
|
|
2227
3380
|
L: 104,
|
|
2228
3381
|
S: this,
|
|
2229
3382
|
C: (f, a) => f(...a)
|
|
@@ -2253,10 +3406,10 @@ var SpaceManager = class {
|
|
|
2253
3406
|
onMemberRolesChanged
|
|
2254
3407
|
});
|
|
2255
3408
|
this._spaces.set(space.key, space);
|
|
2256
|
-
|
|
3409
|
+
log14.trace("dxos.echo.space-manager.construct-space", trace5.end({
|
|
2257
3410
|
id: this._instanceId
|
|
2258
3411
|
}), {
|
|
2259
|
-
F:
|
|
3412
|
+
F: __dxlog_file17,
|
|
2260
3413
|
L: 135,
|
|
2261
3414
|
S: this,
|
|
2262
3415
|
C: (f, a) => f(...a)
|
|
@@ -2265,93 +3418,439 @@ var SpaceManager = class {
|
|
|
2265
3418
|
}
|
|
2266
3419
|
async requestSpaceAdmissionCredential(params) {
|
|
2267
3420
|
const traceKey = "dxos.echo.space-manager.request-space-admission";
|
|
2268
|
-
|
|
3421
|
+
log14.trace(traceKey, trace5.begin({
|
|
2269
3422
|
id: this._instanceId
|
|
2270
3423
|
}), {
|
|
2271
|
-
F:
|
|
3424
|
+
F: __dxlog_file17,
|
|
2272
3425
|
L: 141,
|
|
2273
3426
|
S: this,
|
|
2274
3427
|
C: (f, a) => f(...a)
|
|
2275
3428
|
});
|
|
2276
|
-
|
|
3429
|
+
log14("requesting space admission credential...", {
|
|
2277
3430
|
spaceKey: params.spaceKey
|
|
2278
3431
|
}, {
|
|
2279
|
-
F:
|
|
2280
|
-
L: 142,
|
|
3432
|
+
F: __dxlog_file17,
|
|
3433
|
+
L: 142,
|
|
3434
|
+
S: this,
|
|
3435
|
+
C: (f, a) => f(...a)
|
|
3436
|
+
});
|
|
3437
|
+
const onCredentialResolved = new Trigger3();
|
|
3438
|
+
const protocol = new SpaceProtocol({
|
|
3439
|
+
topic: params.spaceKey,
|
|
3440
|
+
swarmIdentity: params.swarmIdentity,
|
|
3441
|
+
networkManager: this._networkManager,
|
|
3442
|
+
onSessionAuth: (session) => {
|
|
3443
|
+
session.addExtension("dxos.mesh.teleport.admission-discovery", new CredentialRetrieverExtension({
|
|
3444
|
+
spaceKey: params.spaceKey,
|
|
3445
|
+
memberKey: params.identityKey
|
|
3446
|
+
}, onCredentialResolved));
|
|
3447
|
+
},
|
|
3448
|
+
onAuthFailure: (session) => session.close(),
|
|
3449
|
+
blobStore: this._blobStore
|
|
3450
|
+
});
|
|
3451
|
+
try {
|
|
3452
|
+
await protocol.start();
|
|
3453
|
+
const credential = await onCredentialResolved.wait({
|
|
3454
|
+
timeout: params.timeout
|
|
3455
|
+
});
|
|
3456
|
+
log14.trace(traceKey, trace5.end({
|
|
3457
|
+
id: this._instanceId
|
|
3458
|
+
}), {
|
|
3459
|
+
F: __dxlog_file17,
|
|
3460
|
+
L: 165,
|
|
3461
|
+
S: this,
|
|
3462
|
+
C: (f, a) => f(...a)
|
|
3463
|
+
});
|
|
3464
|
+
return credential;
|
|
3465
|
+
} catch (err) {
|
|
3466
|
+
log14.trace(traceKey, trace5.error({
|
|
3467
|
+
id: this._instanceId,
|
|
3468
|
+
error: err
|
|
3469
|
+
}), {
|
|
3470
|
+
F: __dxlog_file17,
|
|
3471
|
+
L: 168,
|
|
3472
|
+
S: this,
|
|
3473
|
+
C: (f, a) => f(...a)
|
|
3474
|
+
});
|
|
3475
|
+
throw err;
|
|
3476
|
+
} finally {
|
|
3477
|
+
await protocol.stop();
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
};
|
|
3481
|
+
_ts_decorate8([
|
|
3482
|
+
synchronized4
|
|
3483
|
+
], SpaceManager.prototype, "open", null);
|
|
3484
|
+
_ts_decorate8([
|
|
3485
|
+
synchronized4
|
|
3486
|
+
], SpaceManager.prototype, "close", null);
|
|
3487
|
+
SpaceManager = _ts_decorate8([
|
|
3488
|
+
trackLeaks3("open", "close")
|
|
3489
|
+
], SpaceManager);
|
|
3490
|
+
|
|
3491
|
+
// packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts
|
|
3492
|
+
import CRC32 from "crc-32";
|
|
3493
|
+
import { Event as Event6, scheduleTaskInterval as scheduleTaskInterval2, synchronized as synchronized5 } from "@dxos/async";
|
|
3494
|
+
import { Context as Context6 } from "@dxos/context";
|
|
3495
|
+
import { invariant as invariant13 } from "@dxos/invariant";
|
|
3496
|
+
import { PublicKey as PublicKey9 } from "@dxos/keys";
|
|
3497
|
+
import { log as log15 } from "@dxos/log";
|
|
3498
|
+
import { DataCorruptionError, STORAGE_VERSION, schema as schema6 } from "@dxos/protocols";
|
|
3499
|
+
import { Invitation, SpaceState } from "@dxos/protocols/proto/dxos/client/services";
|
|
3500
|
+
import { ComplexMap as ComplexMap5, arrayToBuffer, forEachAsync, isNotNullOrUndefined } from "@dxos/util";
|
|
3501
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
3502
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3503
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
3504
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
3505
|
+
else
|
|
3506
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
3507
|
+
if (d = decorators[i])
|
|
3508
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
3509
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3510
|
+
}
|
|
3511
|
+
var __dxlog_file18 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/metadata/metadata-store.ts";
|
|
3512
|
+
var EXPIRED_INVITATION_CLEANUP_INTERVAL = 60 * 60 * 1e3;
|
|
3513
|
+
var emptyEchoMetadata = () => ({
|
|
3514
|
+
version: STORAGE_VERSION,
|
|
3515
|
+
spaces: [],
|
|
3516
|
+
created: /* @__PURE__ */ new Date(),
|
|
3517
|
+
updated: /* @__PURE__ */ new Date()
|
|
3518
|
+
});
|
|
3519
|
+
var emptyLargeSpaceMetadata = () => ({});
|
|
3520
|
+
var EchoMetadata = schema6.getCodecForType("dxos.echo.metadata.EchoMetadata");
|
|
3521
|
+
var LargeSpaceMetadata = schema6.getCodecForType("dxos.echo.metadata.LargeSpaceMetadata");
|
|
3522
|
+
var MetadataStore = class {
|
|
3523
|
+
constructor(directory) {
|
|
3524
|
+
this._metadata = emptyEchoMetadata();
|
|
3525
|
+
this._spaceLargeMetadata = new ComplexMap5(PublicKey9.hash);
|
|
3526
|
+
this._metadataFile = void 0;
|
|
3527
|
+
this.update = new Event6();
|
|
3528
|
+
this._invitationCleanupCtx = new Context6(void 0, {
|
|
3529
|
+
F: __dxlog_file18,
|
|
3530
|
+
L: 53
|
|
3531
|
+
});
|
|
3532
|
+
this._directory = directory;
|
|
3533
|
+
}
|
|
3534
|
+
get metadata() {
|
|
3535
|
+
return this._metadata;
|
|
3536
|
+
}
|
|
3537
|
+
get version() {
|
|
3538
|
+
return this._metadata.version ?? 0;
|
|
3539
|
+
}
|
|
3540
|
+
/**
|
|
3541
|
+
* Returns a list of currently saved spaces. The list and objects in it can be modified addSpace and
|
|
3542
|
+
* addSpaceFeed functions.
|
|
3543
|
+
*/
|
|
3544
|
+
get spaces() {
|
|
3545
|
+
return this._metadata.spaces ?? [];
|
|
3546
|
+
}
|
|
3547
|
+
async _readFile(file, codec2) {
|
|
3548
|
+
try {
|
|
3549
|
+
const { size: fileLength } = await file.stat();
|
|
3550
|
+
if (fileLength < 8) {
|
|
3551
|
+
return;
|
|
3552
|
+
}
|
|
3553
|
+
const dataSize = fromBytesInt32(await file.read(0, 4));
|
|
3554
|
+
const checksum = fromBytesInt32(await file.read(4, 4));
|
|
3555
|
+
log15("loaded", {
|
|
3556
|
+
size: dataSize,
|
|
3557
|
+
checksum,
|
|
3558
|
+
name: file.filename
|
|
3559
|
+
}, {
|
|
3560
|
+
F: __dxlog_file18,
|
|
3561
|
+
L: 89,
|
|
3562
|
+
S: this,
|
|
3563
|
+
C: (f, a) => f(...a)
|
|
3564
|
+
});
|
|
3565
|
+
if (fileLength < dataSize + 8) {
|
|
3566
|
+
throw new DataCorruptionError("Metadata size is smaller than expected.", {
|
|
3567
|
+
fileLength,
|
|
3568
|
+
dataSize
|
|
3569
|
+
});
|
|
3570
|
+
}
|
|
3571
|
+
const data = await file.read(8, dataSize);
|
|
3572
|
+
const calculatedChecksum = CRC32.buf(data);
|
|
3573
|
+
if (calculatedChecksum !== checksum) {
|
|
3574
|
+
throw new DataCorruptionError("Metadata checksum is invalid.");
|
|
3575
|
+
}
|
|
3576
|
+
return codec2.decode(data);
|
|
3577
|
+
} finally {
|
|
3578
|
+
await file.close();
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
/**
|
|
3582
|
+
* @internal
|
|
3583
|
+
*/
|
|
3584
|
+
async _writeFile(file, codec2, data) {
|
|
3585
|
+
const encoded = arrayToBuffer(codec2.encode(data));
|
|
3586
|
+
const checksum = CRC32.buf(encoded);
|
|
3587
|
+
const result = Buffer.alloc(8 + encoded.length);
|
|
3588
|
+
result.writeInt32LE(encoded.length, 0);
|
|
3589
|
+
result.writeInt32LE(checksum, 4);
|
|
3590
|
+
encoded.copy(result, 8);
|
|
3591
|
+
await file.write(0, result);
|
|
3592
|
+
log15("saved", {
|
|
3593
|
+
size: encoded.length,
|
|
3594
|
+
checksum
|
|
3595
|
+
}, {
|
|
3596
|
+
F: __dxlog_file18,
|
|
3597
|
+
L: 124,
|
|
2281
3598
|
S: this,
|
|
2282
3599
|
C: (f, a) => f(...a)
|
|
2283
3600
|
});
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
3601
|
+
}
|
|
3602
|
+
async close() {
|
|
3603
|
+
await this._invitationCleanupCtx.dispose();
|
|
3604
|
+
await this.flush();
|
|
3605
|
+
await this._metadataFile?.close();
|
|
3606
|
+
this._metadataFile = void 0;
|
|
3607
|
+
this._metadata = emptyEchoMetadata();
|
|
3608
|
+
this._spaceLargeMetadata.clear();
|
|
3609
|
+
}
|
|
3610
|
+
/**
|
|
3611
|
+
* Loads metadata from persistent storage.
|
|
3612
|
+
*/
|
|
3613
|
+
async load() {
|
|
3614
|
+
if (!this._metadataFile || this._metadataFile.closed) {
|
|
3615
|
+
this._metadataFile = this._directory.getOrCreateFile("EchoMetadata");
|
|
3616
|
+
}
|
|
2298
3617
|
try {
|
|
2299
|
-
await
|
|
2300
|
-
|
|
2301
|
-
|
|
3618
|
+
const metadata = await this._readFile(this._metadataFile, EchoMetadata);
|
|
3619
|
+
if (metadata) {
|
|
3620
|
+
this._metadata = metadata;
|
|
3621
|
+
}
|
|
3622
|
+
this._metadata.spaces?.forEach((space) => {
|
|
3623
|
+
space.state ??= SpaceState.SPACE_ACTIVE;
|
|
2302
3624
|
});
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
3625
|
+
} catch (err) {
|
|
3626
|
+
log15.error("failed to load metadata", {
|
|
3627
|
+
err
|
|
3628
|
+
}, {
|
|
3629
|
+
F: __dxlog_file18,
|
|
3630
|
+
L: 156,
|
|
2308
3631
|
S: this,
|
|
2309
3632
|
C: (f, a) => f(...a)
|
|
2310
3633
|
});
|
|
2311
|
-
|
|
3634
|
+
this._metadata = emptyEchoMetadata();
|
|
3635
|
+
}
|
|
3636
|
+
await forEachAsync([
|
|
3637
|
+
this._metadata.identity?.haloSpace.key,
|
|
3638
|
+
...this._metadata.spaces?.map((space) => space.key) ?? []
|
|
3639
|
+
].filter(isNotNullOrUndefined), async (key) => {
|
|
3640
|
+
try {
|
|
3641
|
+
await this._loadSpaceLargeMetadata(key);
|
|
3642
|
+
} catch (err) {
|
|
3643
|
+
log15.error("failed to load space large metadata", {
|
|
3644
|
+
err
|
|
3645
|
+
}, {
|
|
3646
|
+
F: __dxlog_file18,
|
|
3647
|
+
L: 168,
|
|
3648
|
+
S: this,
|
|
3649
|
+
C: (f, a) => f(...a)
|
|
3650
|
+
});
|
|
3651
|
+
}
|
|
3652
|
+
});
|
|
3653
|
+
scheduleTaskInterval2(this._invitationCleanupCtx, async () => {
|
|
3654
|
+
for (const invitation of this._metadata.invitations ?? []) {
|
|
3655
|
+
if (hasInvitationExpired(invitation) || isLegacyInvitationFormat(invitation)) {
|
|
3656
|
+
await this.removeInvitation(invitation.invitationId);
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
}, EXPIRED_INVITATION_CLEANUP_INTERVAL);
|
|
3660
|
+
}
|
|
3661
|
+
async _save() {
|
|
3662
|
+
const data = {
|
|
3663
|
+
...this._metadata,
|
|
3664
|
+
version: STORAGE_VERSION,
|
|
3665
|
+
created: this._metadata.created ?? /* @__PURE__ */ new Date(),
|
|
3666
|
+
updated: /* @__PURE__ */ new Date()
|
|
3667
|
+
};
|
|
3668
|
+
this.update.emit(data);
|
|
3669
|
+
const file = this._directory.getOrCreateFile("EchoMetadata");
|
|
3670
|
+
await this._writeFile(file, EchoMetadata, data);
|
|
3671
|
+
}
|
|
3672
|
+
async _loadSpaceLargeMetadata(key) {
|
|
3673
|
+
const file = this._directory.getOrCreateFile(`space_${key.toHex()}_large`);
|
|
3674
|
+
try {
|
|
3675
|
+
const metadata = await this._readFile(file, LargeSpaceMetadata);
|
|
3676
|
+
if (metadata) {
|
|
3677
|
+
this._spaceLargeMetadata.set(key, metadata);
|
|
3678
|
+
}
|
|
2312
3679
|
} catch (err) {
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
L: 168,
|
|
3680
|
+
log15.error("failed to load space large metadata", {
|
|
3681
|
+
err
|
|
3682
|
+
}, {
|
|
3683
|
+
F: __dxlog_file18,
|
|
3684
|
+
L: 210,
|
|
2319
3685
|
S: this,
|
|
2320
3686
|
C: (f, a) => f(...a)
|
|
2321
3687
|
});
|
|
2322
|
-
throw err;
|
|
2323
|
-
} finally {
|
|
2324
|
-
await protocol.stop();
|
|
2325
3688
|
}
|
|
2326
3689
|
}
|
|
3690
|
+
async _saveSpaceLargeMetadata(key) {
|
|
3691
|
+
const data = this._getLargeSpaceMetadata(key);
|
|
3692
|
+
const file = this._directory.getOrCreateFile(`space_${key.toHex()}_large`);
|
|
3693
|
+
await this._writeFile(file, LargeSpaceMetadata, data);
|
|
3694
|
+
}
|
|
3695
|
+
async flush() {
|
|
3696
|
+
await this._directory.flush();
|
|
3697
|
+
}
|
|
3698
|
+
_getSpace(spaceKey) {
|
|
3699
|
+
if (this._metadata.identity?.haloSpace.key.equals(spaceKey)) {
|
|
3700
|
+
return this._metadata.identity.haloSpace;
|
|
3701
|
+
}
|
|
3702
|
+
const space = this.spaces.find((space2) => space2.key === spaceKey);
|
|
3703
|
+
invariant13(space, "Space not found", {
|
|
3704
|
+
F: __dxlog_file18,
|
|
3705
|
+
L: 232,
|
|
3706
|
+
S: this,
|
|
3707
|
+
A: [
|
|
3708
|
+
"space",
|
|
3709
|
+
"'Space not found'"
|
|
3710
|
+
]
|
|
3711
|
+
});
|
|
3712
|
+
return space;
|
|
3713
|
+
}
|
|
3714
|
+
_getLargeSpaceMetadata(key) {
|
|
3715
|
+
let entry = this._spaceLargeMetadata.get(key);
|
|
3716
|
+
if (entry) {
|
|
3717
|
+
return entry;
|
|
3718
|
+
}
|
|
3719
|
+
entry = emptyLargeSpaceMetadata();
|
|
3720
|
+
this._spaceLargeMetadata.set(key, entry);
|
|
3721
|
+
return entry;
|
|
3722
|
+
}
|
|
3723
|
+
/**
|
|
3724
|
+
* Clears storage - doesn't work for now.
|
|
3725
|
+
*/
|
|
3726
|
+
async clear() {
|
|
3727
|
+
log15("clearing all metadata", void 0, {
|
|
3728
|
+
F: __dxlog_file18,
|
|
3729
|
+
L: 251,
|
|
3730
|
+
S: this,
|
|
3731
|
+
C: (f, a) => f(...a)
|
|
3732
|
+
});
|
|
3733
|
+
await this._directory.delete();
|
|
3734
|
+
this._metadata = emptyEchoMetadata();
|
|
3735
|
+
}
|
|
3736
|
+
getIdentityRecord() {
|
|
3737
|
+
return this._metadata.identity;
|
|
3738
|
+
}
|
|
3739
|
+
async setIdentityRecord(record) {
|
|
3740
|
+
invariant13(!this._metadata.identity, "Cannot overwrite existing identity in metadata", {
|
|
3741
|
+
F: __dxlog_file18,
|
|
3742
|
+
L: 261,
|
|
3743
|
+
S: this,
|
|
3744
|
+
A: [
|
|
3745
|
+
"!this._metadata.identity",
|
|
3746
|
+
"'Cannot overwrite existing identity in metadata'"
|
|
3747
|
+
]
|
|
3748
|
+
});
|
|
3749
|
+
this._metadata.identity = record;
|
|
3750
|
+
await this._save();
|
|
3751
|
+
await this.flush();
|
|
3752
|
+
}
|
|
3753
|
+
getInvitations() {
|
|
3754
|
+
return this._metadata.invitations ?? [];
|
|
3755
|
+
}
|
|
3756
|
+
async addInvitation(invitation) {
|
|
3757
|
+
if (this._metadata.invitations?.find((i) => i.invitationId === invitation.invitationId)) {
|
|
3758
|
+
return;
|
|
3759
|
+
}
|
|
3760
|
+
(this._metadata.invitations ??= []).push(invitation);
|
|
3761
|
+
await this._save();
|
|
3762
|
+
await this.flush();
|
|
3763
|
+
}
|
|
3764
|
+
async removeInvitation(invitationId) {
|
|
3765
|
+
this._metadata.invitations = (this._metadata.invitations ?? []).filter((i) => i.invitationId !== invitationId);
|
|
3766
|
+
await this._save();
|
|
3767
|
+
await this.flush();
|
|
3768
|
+
}
|
|
3769
|
+
async addSpace(record) {
|
|
3770
|
+
invariant13(!(this._metadata.spaces ?? []).find((space) => space.key === record.key), "Cannot overwrite existing space in metadata", {
|
|
3771
|
+
F: __dxlog_file18,
|
|
3772
|
+
L: 289,
|
|
3773
|
+
S: this,
|
|
3774
|
+
A: [
|
|
3775
|
+
"!(this._metadata.spaces ?? []).find((space) => space.key === record.key)",
|
|
3776
|
+
"'Cannot overwrite existing space in metadata'"
|
|
3777
|
+
]
|
|
3778
|
+
});
|
|
3779
|
+
(this._metadata.spaces ??= []).push(record);
|
|
3780
|
+
await this._save();
|
|
3781
|
+
await this.flush();
|
|
3782
|
+
}
|
|
3783
|
+
async setSpaceDataLatestTimeframe(spaceKey, timeframe) {
|
|
3784
|
+
this._getSpace(spaceKey).dataTimeframe = timeframe;
|
|
3785
|
+
await this._save();
|
|
3786
|
+
}
|
|
3787
|
+
async setSpaceControlLatestTimeframe(spaceKey, timeframe) {
|
|
3788
|
+
this._getSpace(spaceKey).controlTimeframe = timeframe;
|
|
3789
|
+
await this._save();
|
|
3790
|
+
await this.flush();
|
|
3791
|
+
}
|
|
3792
|
+
async setCache(spaceKey, cache) {
|
|
3793
|
+
this._getSpace(spaceKey).cache = cache;
|
|
3794
|
+
await this._save();
|
|
3795
|
+
}
|
|
3796
|
+
async setWritableFeedKeys(spaceKey, controlFeedKey, dataFeedKey) {
|
|
3797
|
+
const space = this._getSpace(spaceKey);
|
|
3798
|
+
space.controlFeedKey = controlFeedKey;
|
|
3799
|
+
space.dataFeedKey = dataFeedKey;
|
|
3800
|
+
await this._save();
|
|
3801
|
+
await this.flush();
|
|
3802
|
+
}
|
|
3803
|
+
async setSpaceState(spaceKey, state) {
|
|
3804
|
+
this._getSpace(spaceKey).state = state;
|
|
3805
|
+
await this._save();
|
|
3806
|
+
await this.flush();
|
|
3807
|
+
}
|
|
3808
|
+
getSpaceControlPipelineSnapshot(spaceKey) {
|
|
3809
|
+
return this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot;
|
|
3810
|
+
}
|
|
3811
|
+
async setSpaceControlPipelineSnapshot(spaceKey, snapshot) {
|
|
3812
|
+
this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot = snapshot;
|
|
3813
|
+
await this._saveSpaceLargeMetadata(spaceKey);
|
|
3814
|
+
await this.flush();
|
|
3815
|
+
}
|
|
3816
|
+
};
|
|
3817
|
+
_ts_decorate9([
|
|
3818
|
+
synchronized5
|
|
3819
|
+
], MetadataStore.prototype, "load", null);
|
|
3820
|
+
_ts_decorate9([
|
|
3821
|
+
synchronized5
|
|
3822
|
+
], MetadataStore.prototype, "_save", null);
|
|
3823
|
+
_ts_decorate9([
|
|
3824
|
+
synchronized5
|
|
3825
|
+
], MetadataStore.prototype, "_saveSpaceLargeMetadata", null);
|
|
3826
|
+
var fromBytesInt32 = (buf) => buf.readInt32LE(0);
|
|
3827
|
+
var hasInvitationExpired = (invitation) => {
|
|
3828
|
+
return Boolean(invitation.created && invitation.lifetime && invitation.lifetime !== 0 && invitation.created.getTime() + invitation.lifetime * 1e3 < Date.now());
|
|
3829
|
+
};
|
|
3830
|
+
var isLegacyInvitationFormat = (invitation) => {
|
|
3831
|
+
return invitation.type === Invitation.Type.MULTIUSE;
|
|
2327
3832
|
};
|
|
2328
|
-
_ts_decorate7([
|
|
2329
|
-
synchronized4
|
|
2330
|
-
], SpaceManager.prototype, "open", null);
|
|
2331
|
-
_ts_decorate7([
|
|
2332
|
-
synchronized4
|
|
2333
|
-
], SpaceManager.prototype, "close", null);
|
|
2334
|
-
SpaceManager = _ts_decorate7([
|
|
2335
|
-
trackLeaks3("open", "close")
|
|
2336
|
-
], SpaceManager);
|
|
2337
3833
|
|
|
2338
3834
|
export {
|
|
2339
|
-
Buffer,
|
|
2340
3835
|
codec,
|
|
2341
3836
|
valueEncoding,
|
|
2342
3837
|
createMappedFeedWriter,
|
|
2343
3838
|
SnapshotManager,
|
|
2344
3839
|
SnapshotStore,
|
|
2345
3840
|
DocumentsSynchronizer,
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
3841
|
+
diffCollectionState,
|
|
3842
|
+
LevelDBStorageAdapter,
|
|
3843
|
+
encodingOptions,
|
|
3844
|
+
AutomergeHost,
|
|
3845
|
+
getSpaceKeyFromDoc,
|
|
3846
|
+
deriveCollectionIdFromSpaceId,
|
|
3847
|
+
getSpaceIdFromCollectionId,
|
|
3848
|
+
AuthExtension,
|
|
2349
3849
|
mapTimeframeToFeedIndexes,
|
|
2350
3850
|
mapFeedIndexesToTimeframe,
|
|
2351
3851
|
startAfter,
|
|
2352
3852
|
TimeframeClock,
|
|
2353
3853
|
Pipeline,
|
|
2354
|
-
AuthExtension,
|
|
2355
3854
|
Space,
|
|
2356
3855
|
createIdFromSpaceKey,
|
|
2357
3856
|
CredentialRetrieverExtension,
|
|
@@ -2361,6 +3860,10 @@ export {
|
|
|
2361
3860
|
SpaceProtocol,
|
|
2362
3861
|
AuthStatus,
|
|
2363
3862
|
SpaceProtocolSession,
|
|
2364
|
-
SpaceManager
|
|
3863
|
+
SpaceManager,
|
|
3864
|
+
MeshEchoReplicator,
|
|
3865
|
+
DataServiceImpl,
|
|
3866
|
+
MetadataStore,
|
|
3867
|
+
hasInvitationExpired
|
|
2365
3868
|
};
|
|
2366
|
-
//# sourceMappingURL=chunk-
|
|
3869
|
+
//# sourceMappingURL=chunk-6MJEONOX.mjs.map
|