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