@dxos/echo-pipeline 0.7.4 → 0.7.5-main.499c70c
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/index.mjs +54 -32
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +46 -31
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +54 -32
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +1 -1
- package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +34 -34
- package/src/automerge/automerge-host.ts +4 -1
- package/src/automerge/collection-synchronizer.ts +1 -1
- package/src/automerge/mesh-echo-replicator.ts +2 -2
- package/src/edge/echo-edge-replicator.ts +47 -19
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Mutex, scheduleTask, scheduleMicroTask } from '@dxos/async';
|
|
6
|
-
import * as A from '@dxos/automerge/automerge';
|
|
5
|
+
import { Mutex, scheduleTask, scheduleMicroTask, Trigger } from '@dxos/async';
|
|
7
6
|
import { cbor } from '@dxos/automerge/automerge-repo';
|
|
8
7
|
import { Context, Resource } from '@dxos/context';
|
|
9
8
|
import { randomUUID } from '@dxos/crypto';
|
|
@@ -184,9 +183,11 @@ type EdgeReplicatorConnectionsParams = {
|
|
|
184
183
|
onRestartRequested: () => Promise<void>;
|
|
185
184
|
};
|
|
186
185
|
|
|
186
|
+
const MAX_INFLIGHT_REQUESTS = 5;
|
|
187
|
+
|
|
187
188
|
class EdgeReplicatorConnection extends Resource implements ReplicatorConnection {
|
|
188
189
|
private readonly _edgeConnection: EdgeConnection;
|
|
189
|
-
private _remotePeerId: string | null = null;
|
|
190
|
+
private readonly _remotePeerId: string | null = null;
|
|
190
191
|
private readonly _targetServiceId: string;
|
|
191
192
|
private readonly _spaceId: SpaceId;
|
|
192
193
|
private readonly _context: EchoReplicatorContext;
|
|
@@ -195,6 +196,16 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
195
196
|
private readonly _onRemoteDisconnected: () => Promise<void>;
|
|
196
197
|
private readonly _onRestartRequested: () => void;
|
|
197
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Prevents sending too many messages to edge over this connection so that we don't overwhelm
|
|
201
|
+
* a replicator durable object.
|
|
202
|
+
* inflightRequests counter is incremented on outgoing sync messages and decremented on incoming messages.
|
|
203
|
+
* The trigger is waiting while the counter is above MAX_INFLIGHT_REQUESTS.
|
|
204
|
+
* The counter can go negative because we receive edge-initiated sync messages on doc change broadcasts.
|
|
205
|
+
*/
|
|
206
|
+
private _outgoingRequestsBarrier = new Trigger();
|
|
207
|
+
private _inflightRequests = 0;
|
|
208
|
+
|
|
198
209
|
private _readableStreamController!: ReadableStreamDefaultController<AutomergeProtocolMessage>;
|
|
199
210
|
|
|
200
211
|
public readable: ReadableStream<AutomergeProtocolMessage>;
|
|
@@ -213,7 +224,6 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
213
224
|
this._edgeConnection = edgeConnection;
|
|
214
225
|
this._spaceId = spaceId;
|
|
215
226
|
this._context = context;
|
|
216
|
-
|
|
217
227
|
// Generate a unique peer id for every connection.
|
|
218
228
|
// This way automerge-repo will have separate sync states for every connection.
|
|
219
229
|
// This is important because the previous connection might have had some messages that failed to deliver
|
|
@@ -225,6 +235,8 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
225
235
|
this._onRemoteDisconnected = onRemoteDisconnected;
|
|
226
236
|
this._onRestartRequested = onRestartRequested;
|
|
227
237
|
|
|
238
|
+
this._outgoingRequestsBarrier.wake();
|
|
239
|
+
|
|
228
240
|
this.readable = new ReadableStream<AutomergeProtocolMessage>({
|
|
229
241
|
start: (controller) => {
|
|
230
242
|
this._readableStreamController = controller;
|
|
@@ -233,6 +245,13 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
233
245
|
|
|
234
246
|
this.writable = new WritableStream<AutomergeProtocolMessage>({
|
|
235
247
|
write: async (message: AutomergeProtocolMessage, controller) => {
|
|
248
|
+
await this._outgoingRequestsBarrier.wait();
|
|
249
|
+
|
|
250
|
+
this._inflightRequests++;
|
|
251
|
+
if (this._inflightRequests === MAX_INFLIGHT_REQUESTS) {
|
|
252
|
+
this._outgoingRequestsBarrier.reset();
|
|
253
|
+
}
|
|
254
|
+
|
|
236
255
|
await this._sendMessage(message);
|
|
237
256
|
},
|
|
238
257
|
});
|
|
@@ -253,6 +272,9 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
253
272
|
protected override async _close(): Promise<void> {
|
|
254
273
|
log('close');
|
|
255
274
|
this._readableStreamController.close();
|
|
275
|
+
|
|
276
|
+
this._outgoingRequestsBarrier.throw(new Error('Connection closed.'));
|
|
277
|
+
|
|
256
278
|
await this._onRemoteDisconnected();
|
|
257
279
|
}
|
|
258
280
|
|
|
@@ -272,9 +294,10 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
272
294
|
peerId: this._remotePeerId as PeerId,
|
|
273
295
|
});
|
|
274
296
|
|
|
275
|
-
log.
|
|
297
|
+
log.verbose('edge-replicator document not found locally for share policy check', {
|
|
276
298
|
documentId: params.documentId,
|
|
277
|
-
remoteDocumentExists,
|
|
299
|
+
acceptDocument: remoteDocumentExists,
|
|
300
|
+
remoteId: this._remotePeerId,
|
|
278
301
|
});
|
|
279
302
|
|
|
280
303
|
// If a document is not present locally return true only if it already exists on edge.
|
|
@@ -290,7 +313,8 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
290
313
|
return true;
|
|
291
314
|
}
|
|
292
315
|
const spaceId = getSpaceIdFromCollectionId(params.collectionId as CollectionId);
|
|
293
|
-
|
|
316
|
+
// Only sync collections of form space:id:rootDoc, edge ignores legacy space:id collections
|
|
317
|
+
return spaceId === this._spaceId && params.collectionId.split(':').length === 3;
|
|
294
318
|
}
|
|
295
319
|
|
|
296
320
|
private _onMessage(message: RouterMessage) {
|
|
@@ -299,15 +323,12 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
299
323
|
}
|
|
300
324
|
|
|
301
325
|
const payload = cbor.decode(message.payload!.value) as AutomergeProtocolMessage;
|
|
302
|
-
log('
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
: payload.type === 'collection-state'
|
|
307
|
-
? (payload as any).state
|
|
308
|
-
: payload;
|
|
309
|
-
return { from: message.serviceId, type: payload.type, decodedData };
|
|
326
|
+
log.verbose('edge replicator receive', {
|
|
327
|
+
type: payload.type,
|
|
328
|
+
documentId: payload.type === 'sync' && payload.documentId,
|
|
329
|
+
remoteId: this._remotePeerId,
|
|
310
330
|
});
|
|
331
|
+
|
|
311
332
|
// Fix the peer id.
|
|
312
333
|
payload.senderId = this._remotePeerId! as PeerId;
|
|
313
334
|
this._processMessage(payload);
|
|
@@ -322,6 +343,13 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
322
343
|
return;
|
|
323
344
|
}
|
|
324
345
|
|
|
346
|
+
if (message.type === 'sync') {
|
|
347
|
+
this._inflightRequests--;
|
|
348
|
+
if (this._inflightRequests === MAX_INFLIGHT_REQUESTS - 1) {
|
|
349
|
+
this._outgoingRequestsBarrier.wake();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
325
353
|
this._readableStreamController.enqueue(message);
|
|
326
354
|
}
|
|
327
355
|
|
|
@@ -329,12 +357,12 @@ class EdgeReplicatorConnection extends Resource implements ReplicatorConnection
|
|
|
329
357
|
// Fix the peer id.
|
|
330
358
|
(message as any).targetId = this._targetServiceId as PeerId;
|
|
331
359
|
|
|
332
|
-
log('send', {
|
|
360
|
+
log.verbose('edge replicator send', {
|
|
333
361
|
type: message.type,
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
documentId: (message as any).documentId,
|
|
362
|
+
documentId: message.type === 'sync' && message.documentId,
|
|
363
|
+
remoteId: this._remotePeerId,
|
|
337
364
|
});
|
|
365
|
+
|
|
338
366
|
const encoded = cbor.encode(message);
|
|
339
367
|
|
|
340
368
|
await this._edgeConnection.send(
|