cojson 0.13.13 → 0.13.15
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/PeerState.d.ts +4 -6
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +30 -26
- package/dist/PeerState.js.map +1 -1
- package/dist/PriorityBasedMessageQueue.d.ts +2 -8
- package/dist/PriorityBasedMessageQueue.d.ts.map +1 -1
- package/dist/PriorityBasedMessageQueue.js +1 -17
- package/dist/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/coValueCore.js +1 -1
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValueState.d.ts.map +1 -1
- package/dist/coValueState.js +1 -8
- package/dist/coValueState.js.map +1 -1
- package/dist/coValues/coList.d.ts +2 -4
- package/dist/coValues/coList.d.ts.map +1 -1
- package/dist/coValues/coList.js +14 -18
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coPlainText.js +1 -1
- package/dist/coValues/coPlainText.js.map +1 -1
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +2 -2
- package/dist/localNode.js.map +1 -1
- package/dist/streamUtils.d.ts.map +1 -1
- package/dist/streamUtils.js +1 -1
- package/dist/streamUtils.js.map +1 -1
- package/dist/sync.d.ts +11 -17
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +49 -91
- package/dist/sync.js.map +1 -1
- package/dist/tests/PeerState.test.js +27 -14
- package/dist/tests/PeerState.test.js.map +1 -1
- package/dist/tests/PriorityBasedMessageQueue.test.js +5 -33
- package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +5 -9
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coList.test.js +0 -9
- package/dist/tests/coList.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +21 -17
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +46 -18
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +13 -15
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +13 -9
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.test.js +16 -28
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +13 -13
- package/dist/tests/testUtils.d.ts +1 -0
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +1 -0
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +1 -1
- package/src/PeerState.ts +33 -37
- package/src/PriorityBasedMessageQueue.ts +2 -30
- package/src/coValueCore.ts +1 -1
- package/src/coValueState.ts +4 -10
- package/src/coValues/coList.ts +20 -29
- package/src/coValues/coPlainText.ts +1 -1
- package/src/localNode.ts +4 -2
- package/src/streamUtils.ts +2 -2
- package/src/sync.ts +58 -103
- package/src/tests/PeerState.test.ts +28 -14
- package/src/tests/PriorityBasedMessageQueue.test.ts +5 -39
- package/src/tests/SyncStateManager.test.ts +4 -12
- package/src/tests/coList.test.ts +0 -13
- package/src/tests/sync.load.test.ts +21 -17
- package/src/tests/sync.mesh.test.ts +46 -18
- package/src/tests/sync.peerReconciliation.test.ts +13 -25
- package/src/tests/sync.storage.test.ts +13 -9
- package/src/tests/sync.test.ts +16 -30
- package/src/tests/sync.upload.test.ts +13 -13
- package/src/tests/testUtils.ts +1 -0
package/src/localNode.ts
CHANGED
|
@@ -140,7 +140,9 @@ export class LocalNode {
|
|
|
140
140
|
function syncAllCoValuesAfterCreateAccount() {
|
|
141
141
|
for (const coValueEntry of nodeWithAccount.coValuesStore.getValues()) {
|
|
142
142
|
if (coValueEntry.isAvailable()) {
|
|
143
|
-
void nodeWithAccount.syncManager.
|
|
143
|
+
void nodeWithAccount.syncManager.requestCoValueSync(
|
|
144
|
+
coValueEntry.core,
|
|
145
|
+
);
|
|
144
146
|
}
|
|
145
147
|
}
|
|
146
148
|
}
|
|
@@ -248,7 +250,7 @@ export class LocalNode {
|
|
|
248
250
|
const coValue = new CoValueCore(header, this);
|
|
249
251
|
this.coValuesStore.internalMarkMagicallyAvailable(coValue.id, coValue);
|
|
250
252
|
|
|
251
|
-
void this.syncManager.
|
|
253
|
+
void this.syncManager.requestCoValueSync(coValue);
|
|
252
254
|
|
|
253
255
|
return coValue;
|
|
254
256
|
}
|
package/src/streamUtils.ts
CHANGED
package/src/sync.ts
CHANGED
|
@@ -78,7 +78,7 @@ export interface Peer {
|
|
|
78
78
|
id: PeerID;
|
|
79
79
|
incoming: IncomingSyncStream;
|
|
80
80
|
outgoing: OutgoingSyncQueue;
|
|
81
|
-
role: "
|
|
81
|
+
role: "server" | "client" | "storage";
|
|
82
82
|
priority?: number;
|
|
83
83
|
crashOnClose: boolean;
|
|
84
84
|
deletePeerStateOnClose?: boolean;
|
|
@@ -112,11 +112,6 @@ export function combinedKnownStates(
|
|
|
112
112
|
export class SyncManager {
|
|
113
113
|
peers: { [key: PeerID]: PeerState } = {};
|
|
114
114
|
local: LocalNode;
|
|
115
|
-
requestedSyncs: {
|
|
116
|
-
[id: RawCoID]:
|
|
117
|
-
| { done: Promise<void>; nRequestsThisTick: number }
|
|
118
|
-
| undefined;
|
|
119
|
-
} = {};
|
|
120
115
|
|
|
121
116
|
peersCounter = metrics.getMeter("cojson").createUpDownCounter("jazz.peers", {
|
|
122
117
|
description: "Amount of connected peers",
|
|
@@ -162,7 +157,7 @@ export class SyncManager {
|
|
|
162
157
|
);
|
|
163
158
|
}
|
|
164
159
|
|
|
165
|
-
|
|
160
|
+
handleSyncMessage(msg: SyncMessage, peer: PeerState) {
|
|
166
161
|
if (this.local.coValuesStore.get(msg.id).isErroredInPeer(peer.id)) {
|
|
167
162
|
logger.warn(
|
|
168
163
|
`Skipping message ${msg.action} on errored coValue ${msg.id} from peer ${peer.id}`,
|
|
@@ -183,18 +178,17 @@ export class SyncManager {
|
|
|
183
178
|
// TODO: validate
|
|
184
179
|
switch (msg.action) {
|
|
185
180
|
case "load":
|
|
186
|
-
return
|
|
181
|
+
return this.handleLoad(msg, peer);
|
|
187
182
|
case "known":
|
|
188
183
|
if (msg.isCorrection) {
|
|
189
|
-
return
|
|
184
|
+
return this.handleCorrection(msg, peer);
|
|
190
185
|
} else {
|
|
191
|
-
return
|
|
186
|
+
return this.handleKnownState(msg, peer);
|
|
192
187
|
}
|
|
193
188
|
case "content":
|
|
194
|
-
|
|
195
|
-
return await this.handleNewContent(msg, peer);
|
|
189
|
+
return this.handleNewContent(msg, peer);
|
|
196
190
|
case "done":
|
|
197
|
-
return
|
|
191
|
+
return this.handleUnsubscribe(msg);
|
|
198
192
|
default:
|
|
199
193
|
throw new Error(
|
|
200
194
|
`Unknown message type ${(msg as { action: "string" }).action}`,
|
|
@@ -202,14 +196,12 @@ export class SyncManager {
|
|
|
202
196
|
}
|
|
203
197
|
}
|
|
204
198
|
|
|
205
|
-
|
|
199
|
+
sendNewContentIncludingDependencies(id: RawCoID, peer: PeerState) {
|
|
206
200
|
const coValue = this.local.expectCoValueLoaded(id);
|
|
207
201
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
.map((id) => this.sendNewContentIncludingDependencies(id, peer)),
|
|
212
|
-
);
|
|
202
|
+
coValue
|
|
203
|
+
.getDependedOnCoValues()
|
|
204
|
+
.map((id) => this.sendNewContentIncludingDependencies(id, peer));
|
|
213
205
|
|
|
214
206
|
const newContentPieces = coValue.newContentSince(
|
|
215
207
|
peer.optimisticKnownStates.get(id),
|
|
@@ -217,9 +209,7 @@ export class SyncManager {
|
|
|
217
209
|
|
|
218
210
|
if (newContentPieces) {
|
|
219
211
|
for (const piece of newContentPieces) {
|
|
220
|
-
this.trySendToPeer(peer, piece)
|
|
221
|
-
logger.error("Error sending content piece", { err: e });
|
|
222
|
-
});
|
|
212
|
+
this.trySendToPeer(peer, piece);
|
|
223
213
|
}
|
|
224
214
|
|
|
225
215
|
peer.toldKnownState.add(id);
|
|
@@ -228,15 +218,13 @@ export class SyncManager {
|
|
|
228
218
|
this.trySendToPeer(peer, {
|
|
229
219
|
action: "known",
|
|
230
220
|
...coValue.knownState(),
|
|
231
|
-
}).catch((e: unknown) => {
|
|
232
|
-
logger.error("Error sending known state", { err: e });
|
|
233
221
|
});
|
|
234
222
|
|
|
235
223
|
peer.toldKnownState.add(id);
|
|
236
224
|
}
|
|
237
225
|
}
|
|
238
226
|
|
|
239
|
-
|
|
227
|
+
startPeerReconciliation(peer: PeerState) {
|
|
240
228
|
const coValuesOrderedByDependency: CoValueCore[] = [];
|
|
241
229
|
|
|
242
230
|
const gathered = new Set<string>();
|
|
@@ -264,8 +252,12 @@ export class SyncManager {
|
|
|
264
252
|
// If the coValue is unavailable and we never tried this peer
|
|
265
253
|
// we try to load it from the peer
|
|
266
254
|
if (!peer.toldKnownState.has(entry.id)) {
|
|
267
|
-
|
|
268
|
-
|
|
255
|
+
peer.toldKnownState.add(entry.id);
|
|
256
|
+
this.trySendToPeer(peer, {
|
|
257
|
+
action: "load",
|
|
258
|
+
header: false,
|
|
259
|
+
id: entry.id,
|
|
260
|
+
sessions: {},
|
|
269
261
|
});
|
|
270
262
|
}
|
|
271
263
|
} else {
|
|
@@ -293,33 +285,15 @@ export class SyncManager {
|
|
|
293
285
|
this.trySendToPeer(peer, {
|
|
294
286
|
action: "load",
|
|
295
287
|
...coValue.knownState(),
|
|
296
|
-
}).catch((e: unknown) => {
|
|
297
|
-
logger.error("Error sending load", { err: e });
|
|
298
288
|
});
|
|
299
289
|
}
|
|
300
290
|
}
|
|
301
291
|
|
|
302
|
-
nextPeer: Map<PeerID, Peer> = new Map();
|
|
303
|
-
|
|
304
292
|
async addPeer(peer: Peer) {
|
|
305
293
|
const prevPeer = this.peers[peer.id];
|
|
306
294
|
|
|
307
|
-
if (prevPeer) {
|
|
308
|
-
|
|
309
|
-
prevPeer.nextPeer = peer;
|
|
310
|
-
|
|
311
|
-
if (!prevPeer.closed) {
|
|
312
|
-
prevPeer.gracefulShutdown();
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// Wait for the previous peer to finish processing the incoming messages
|
|
316
|
-
await prevPeer.incomingMessagesProcessingPromise?.catch((e) => {});
|
|
317
|
-
|
|
318
|
-
// If another peer was added in the meantime, we close this peer
|
|
319
|
-
if (prevPeer.nextPeer !== peer) {
|
|
320
|
-
peer.outgoing.close();
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
295
|
+
if (prevPeer && !prevPeer.closed) {
|
|
296
|
+
prevPeer.gracefulShutdown();
|
|
323
297
|
}
|
|
324
298
|
|
|
325
299
|
const peerState = new PeerState(peer, prevPeer?.knownStates);
|
|
@@ -338,8 +312,8 @@ export class SyncManager {
|
|
|
338
312
|
}
|
|
339
313
|
|
|
340
314
|
peerState
|
|
341
|
-
.processIncomingMessages(
|
|
342
|
-
|
|
315
|
+
.processIncomingMessages((msg) => {
|
|
316
|
+
this.handleSyncMessage(msg, peerState);
|
|
343
317
|
})
|
|
344
318
|
.then(() => {
|
|
345
319
|
if (peer.crashOnClose) {
|
|
@@ -386,7 +360,7 @@ export class SyncManager {
|
|
|
386
360
|
* - The peer known state is stored as-is instead of being merged
|
|
387
361
|
* - The load message always replies with a known state message
|
|
388
362
|
*/
|
|
389
|
-
|
|
363
|
+
handleLoad(msg: LoadMessage, peer: PeerState) {
|
|
390
364
|
/**
|
|
391
365
|
* We use the msg sessions as source of truth for the known states
|
|
392
366
|
*
|
|
@@ -413,8 +387,6 @@ export class SyncManager {
|
|
|
413
387
|
id: msg.id,
|
|
414
388
|
header: false,
|
|
415
389
|
sessions: {},
|
|
416
|
-
}).catch((e) => {
|
|
417
|
-
logger.error("Error sending known state back", { err: e });
|
|
418
390
|
});
|
|
419
391
|
|
|
420
392
|
return;
|
|
@@ -442,14 +414,12 @@ export class SyncManager {
|
|
|
442
414
|
id: msg.id,
|
|
443
415
|
header: false,
|
|
444
416
|
sessions: {},
|
|
445
|
-
}).catch((e) => {
|
|
446
|
-
logger.error("Error sending known state back", { err: e });
|
|
447
417
|
});
|
|
448
418
|
|
|
449
419
|
return;
|
|
450
420
|
}
|
|
451
421
|
|
|
452
|
-
|
|
422
|
+
this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
453
423
|
})
|
|
454
424
|
.catch((e) => {
|
|
455
425
|
logger.error("Error loading coValue in handleLoad loading state", {
|
|
@@ -457,7 +427,7 @@ export class SyncManager {
|
|
|
457
427
|
});
|
|
458
428
|
});
|
|
459
429
|
} else if (entry.isAvailable()) {
|
|
460
|
-
|
|
430
|
+
this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
461
431
|
} else {
|
|
462
432
|
this.trySendToPeer(peer, {
|
|
463
433
|
action: "known",
|
|
@@ -468,7 +438,7 @@ export class SyncManager {
|
|
|
468
438
|
}
|
|
469
439
|
}
|
|
470
440
|
|
|
471
|
-
|
|
441
|
+
handleKnownState(msg: KnownStateMessage, peer: PeerState) {
|
|
472
442
|
const entry = this.local.coValuesStore.get(msg.id);
|
|
473
443
|
|
|
474
444
|
peer.combineWith(msg.id, knownStateIn(msg));
|
|
@@ -482,7 +452,7 @@ export class SyncManager {
|
|
|
482
452
|
}
|
|
483
453
|
|
|
484
454
|
if (entry.isAvailable()) {
|
|
485
|
-
|
|
455
|
+
this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
486
456
|
}
|
|
487
457
|
}
|
|
488
458
|
|
|
@@ -499,7 +469,7 @@ export class SyncManager {
|
|
|
499
469
|
}
|
|
500
470
|
}
|
|
501
471
|
|
|
502
|
-
|
|
472
|
+
handleNewContent(msg: NewContentMessage, peer: PeerState) {
|
|
503
473
|
const entry = this.local.coValuesStore.get(msg.id);
|
|
504
474
|
|
|
505
475
|
let coValue: CoValueCore;
|
|
@@ -512,12 +482,6 @@ export class SyncManager {
|
|
|
512
482
|
id: msg.id,
|
|
513
483
|
header: false,
|
|
514
484
|
sessions: {},
|
|
515
|
-
}).catch((e) => {
|
|
516
|
-
logger.error("Error sending known state correction", {
|
|
517
|
-
peerId: peer.id,
|
|
518
|
-
peerRole: peer.role,
|
|
519
|
-
err: e,
|
|
520
|
-
});
|
|
521
485
|
});
|
|
522
486
|
return;
|
|
523
487
|
}
|
|
@@ -590,12 +554,6 @@ export class SyncManager {
|
|
|
590
554
|
action: "known",
|
|
591
555
|
isCorrection: true,
|
|
592
556
|
...coValue.knownState(),
|
|
593
|
-
}).catch((e) => {
|
|
594
|
-
logger.error("Error sending known state correction", {
|
|
595
|
-
peerId: peer.id,
|
|
596
|
-
peerRole: peer.role,
|
|
597
|
-
err: e,
|
|
598
|
-
});
|
|
599
557
|
});
|
|
600
558
|
peer.toldKnownState.add(msg.id);
|
|
601
559
|
} else {
|
|
@@ -609,12 +567,6 @@ export class SyncManager {
|
|
|
609
567
|
this.trySendToPeer(peer, {
|
|
610
568
|
action: "known",
|
|
611
569
|
...coValue.knownState(),
|
|
612
|
-
}).catch((e: unknown) => {
|
|
613
|
-
logger.error("Error sending known state", {
|
|
614
|
-
peerId: peer.id,
|
|
615
|
-
peerRole: peer.role,
|
|
616
|
-
err: e,
|
|
617
|
-
});
|
|
618
570
|
});
|
|
619
571
|
peer.toldKnownState.add(msg.id);
|
|
620
572
|
}
|
|
@@ -624,51 +576,54 @@ export class SyncManager {
|
|
|
624
576
|
* response to the peers that are waiting for confirmation that a coValue is
|
|
625
577
|
* fully synced
|
|
626
578
|
*/
|
|
627
|
-
this.
|
|
579
|
+
this.requestCoValueSync(coValue);
|
|
628
580
|
}
|
|
629
581
|
|
|
630
|
-
|
|
582
|
+
handleCorrection(msg: KnownStateMessage, peer: PeerState) {
|
|
631
583
|
peer.setKnownState(msg.id, knownStateIn(msg));
|
|
632
584
|
|
|
633
585
|
return this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
634
586
|
}
|
|
635
587
|
|
|
636
|
-
handleUnsubscribe(_msg: DoneMessage) {
|
|
637
|
-
throw new Error("Method not implemented.");
|
|
638
|
-
}
|
|
588
|
+
handleUnsubscribe(_msg: DoneMessage) {}
|
|
639
589
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
590
|
+
requestedSyncs = new Map<RawCoID, Promise<void>>();
|
|
591
|
+
|
|
592
|
+
async requestCoValueSync(coValue: CoValueCore) {
|
|
593
|
+
const promise = this.requestedSyncs.get(coValue.id);
|
|
594
|
+
|
|
595
|
+
if (promise) {
|
|
596
|
+
return promise;
|
|
644
597
|
} else {
|
|
645
|
-
const
|
|
646
|
-
queueMicrotask(
|
|
647
|
-
|
|
648
|
-
|
|
598
|
+
const promise = new Promise<void>((resolve) => {
|
|
599
|
+
queueMicrotask(() => {
|
|
600
|
+
this.requestedSyncs.delete(coValue.id);
|
|
601
|
+
this.syncCoValue(coValue);
|
|
649
602
|
resolve();
|
|
650
603
|
});
|
|
651
604
|
});
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
};
|
|
656
|
-
this.requestedSyncs[coValue.id] = entry;
|
|
657
|
-
return done;
|
|
605
|
+
|
|
606
|
+
this.requestedSyncs.set(coValue.id, promise);
|
|
607
|
+
return promise;
|
|
658
608
|
}
|
|
659
609
|
}
|
|
660
610
|
|
|
661
|
-
async
|
|
611
|
+
async syncCoValue(coValue: CoValueCore) {
|
|
612
|
+
const entry = this.local.coValuesStore.get(coValue.id);
|
|
613
|
+
|
|
662
614
|
for (const peer of this.peersInPriorityOrder()) {
|
|
663
615
|
if (peer.closed) continue;
|
|
664
|
-
if (
|
|
665
|
-
continue;
|
|
616
|
+
if (entry.isErroredInPeer(peer.id)) continue;
|
|
666
617
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
618
|
+
// Only subscribed CoValues are synced to clients
|
|
619
|
+
if (
|
|
620
|
+
peer.role === "client" &&
|
|
621
|
+
!peer.optimisticKnownStates.has(coValue.id)
|
|
622
|
+
) {
|
|
623
|
+
continue;
|
|
671
624
|
}
|
|
625
|
+
|
|
626
|
+
this.sendNewContentIncludingDependencies(coValue.id, peer);
|
|
672
627
|
}
|
|
673
628
|
|
|
674
629
|
for (const peer of this.getPeers()) {
|
|
@@ -2,11 +2,12 @@ import { describe, expect, test, vi } from "vitest";
|
|
|
2
2
|
import { PeerState } from "../PeerState.js";
|
|
3
3
|
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
4
4
|
import { CoValueKnownState, Peer, SyncMessage } from "../sync.js";
|
|
5
|
+
import { waitFor } from "./testUtils.js";
|
|
5
6
|
|
|
6
7
|
function setup() {
|
|
7
8
|
const mockPeer: Peer = {
|
|
8
9
|
id: "test-peer",
|
|
9
|
-
role: "
|
|
10
|
+
role: "client",
|
|
10
11
|
priority: 1,
|
|
11
12
|
crashOnClose: false,
|
|
12
13
|
incoming: (async function* () {})(),
|
|
@@ -62,13 +63,19 @@ describe("PeerState", () => {
|
|
|
62
63
|
});
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
peerState.pushOutgoingMessage({
|
|
66
67
|
action: "content",
|
|
67
68
|
id: "co_z1",
|
|
68
69
|
new: {},
|
|
69
70
|
priority: CO_VALUE_PRIORITY.HIGH,
|
|
70
71
|
});
|
|
71
|
-
|
|
72
|
+
peerState.pushOutgoingMessage({
|
|
73
|
+
action: "content",
|
|
74
|
+
id: "co_z1",
|
|
75
|
+
new: {},
|
|
76
|
+
priority: CO_VALUE_PRIORITY.HIGH,
|
|
77
|
+
});
|
|
78
|
+
peerState.pushOutgoingMessage({
|
|
72
79
|
action: "content",
|
|
73
80
|
id: "co_z1",
|
|
74
81
|
new: {},
|
|
@@ -77,14 +84,21 @@ describe("PeerState", () => {
|
|
|
77
84
|
|
|
78
85
|
peerState.gracefulShutdown();
|
|
79
86
|
|
|
80
|
-
await
|
|
87
|
+
await waitFor(() => {
|
|
88
|
+
expect(peerState.isProcessing()).toBe(false);
|
|
89
|
+
});
|
|
81
90
|
|
|
82
|
-
|
|
83
|
-
await expect(message2).resolves.toBe(undefined);
|
|
91
|
+
expect(mockPeer.outgoing.push).toHaveBeenCalledTimes(1);
|
|
84
92
|
});
|
|
85
93
|
|
|
86
94
|
test("should schedule outgoing messages based on their priority", async () => {
|
|
87
|
-
const { peerState } = setup();
|
|
95
|
+
const { peerState, mockPeer } = setup();
|
|
96
|
+
|
|
97
|
+
mockPeer.outgoing.push = vi.fn().mockImplementation((message) => {
|
|
98
|
+
return new Promise<void>((resolve) => {
|
|
99
|
+
setTimeout(resolve, 0);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
88
102
|
|
|
89
103
|
const loadMessage: SyncMessage = {
|
|
90
104
|
action: "load",
|
|
@@ -111,14 +125,14 @@ describe("PeerState", () => {
|
|
|
111
125
|
priority: CO_VALUE_PRIORITY.LOW,
|
|
112
126
|
};
|
|
113
127
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
peerState.pushOutgoingMessage(loadMessage),
|
|
119
|
-
];
|
|
128
|
+
peerState.pushOutgoingMessage(contentMessageLow);
|
|
129
|
+
peerState.pushOutgoingMessage(contentMessageMid);
|
|
130
|
+
peerState.pushOutgoingMessage(contentMessageHigh);
|
|
131
|
+
peerState.pushOutgoingMessage(loadMessage);
|
|
120
132
|
|
|
121
|
-
await
|
|
133
|
+
await waitFor(() => {
|
|
134
|
+
expect(peerState.isProcessing()).toBe(false);
|
|
135
|
+
});
|
|
122
136
|
|
|
123
137
|
// The first message is pushed directly, the other three are queued because are waiting
|
|
124
138
|
// for the first push to be completed.
|
|
@@ -157,8 +157,7 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
157
157
|
sessions: {},
|
|
158
158
|
};
|
|
159
159
|
void queue.push(message);
|
|
160
|
-
|
|
161
|
-
expect(pulledEntry?.msg).toEqual(message);
|
|
160
|
+
expect(queue.pull()).toEqual(message);
|
|
162
161
|
});
|
|
163
162
|
|
|
164
163
|
test("should push message with specified priority", async () => {
|
|
@@ -170,8 +169,7 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
170
169
|
priority: CO_VALUE_PRIORITY.HIGH,
|
|
171
170
|
};
|
|
172
171
|
void queue.push(message);
|
|
173
|
-
|
|
174
|
-
expect(pulledEntry?.msg).toEqual(message);
|
|
172
|
+
expect(queue.pull()).toEqual(message);
|
|
175
173
|
});
|
|
176
174
|
|
|
177
175
|
test("should pull messages in priority order", async () => {
|
|
@@ -199,45 +197,13 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
199
197
|
void queue.push(mediumPriorityMsg);
|
|
200
198
|
void queue.push(highPriorityMsg);
|
|
201
199
|
|
|
202
|
-
expect(queue.pull()
|
|
203
|
-
expect(queue.pull()
|
|
204
|
-
expect(queue.pull()
|
|
200
|
+
expect(queue.pull()).toEqual(highPriorityMsg);
|
|
201
|
+
expect(queue.pull()).toEqual(mediumPriorityMsg);
|
|
202
|
+
expect(queue.pull()).toEqual(lowPriorityMsg);
|
|
205
203
|
});
|
|
206
204
|
|
|
207
205
|
test("should return undefined when pulling from empty queue", () => {
|
|
208
206
|
const { queue } = setup();
|
|
209
207
|
expect(queue.pull()).toBeUndefined();
|
|
210
208
|
});
|
|
211
|
-
|
|
212
|
-
test("should resolve promise when message is pulled", async () => {
|
|
213
|
-
const { queue } = setup();
|
|
214
|
-
const message: SyncMessage = {
|
|
215
|
-
action: "load",
|
|
216
|
-
id: "co_ztest-id",
|
|
217
|
-
header: false,
|
|
218
|
-
sessions: {},
|
|
219
|
-
};
|
|
220
|
-
const pushPromise = queue.push(message);
|
|
221
|
-
|
|
222
|
-
const pulledEntry = queue.pull();
|
|
223
|
-
pulledEntry?.resolve();
|
|
224
|
-
|
|
225
|
-
await expect(pushPromise).resolves.toBeUndefined();
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test("should reject promise when message is rejected", async () => {
|
|
229
|
-
const { queue } = setup();
|
|
230
|
-
const message: SyncMessage = {
|
|
231
|
-
action: "load",
|
|
232
|
-
id: "co_ztest-id",
|
|
233
|
-
header: false,
|
|
234
|
-
sessions: {},
|
|
235
|
-
};
|
|
236
|
-
const pushPromise = queue.push(message);
|
|
237
|
-
|
|
238
|
-
const pulledEntry = queue.pull();
|
|
239
|
-
pulledEntry?.reject(new Error("Test error"));
|
|
240
|
-
|
|
241
|
-
await expect(pushPromise).rejects.toThrow("Test error");
|
|
242
|
-
});
|
|
243
209
|
});
|
|
@@ -7,8 +7,6 @@ import { connectedPeers } from "../streamUtils.js";
|
|
|
7
7
|
import { emptyKnownState } from "../sync.js";
|
|
8
8
|
import {
|
|
9
9
|
SyncMessagesLog,
|
|
10
|
-
blockMessageTypeOnOutgoingPeer,
|
|
11
|
-
createTestNode,
|
|
12
10
|
loadCoValueOrFail,
|
|
13
11
|
setupTestNode,
|
|
14
12
|
waitFor,
|
|
@@ -37,7 +35,7 @@ describe("SyncStateManager", () => {
|
|
|
37
35
|
const updateSpy: GlobalSyncStateListenerCallback = vi.fn();
|
|
38
36
|
const unsubscribe = subscriptionManager.subscribeToUpdates(updateSpy);
|
|
39
37
|
|
|
40
|
-
await client.node.syncManager.
|
|
38
|
+
await client.node.syncManager.syncCoValue(map.core);
|
|
41
39
|
|
|
42
40
|
expect(updateSpy).toHaveBeenCalledWith(
|
|
43
41
|
peerState.id,
|
|
@@ -97,7 +95,7 @@ describe("SyncStateManager", () => {
|
|
|
97
95
|
unsubscribe2();
|
|
98
96
|
});
|
|
99
97
|
|
|
100
|
-
await client.node.syncManager.
|
|
98
|
+
await client.node.syncManager.syncCoValue(map.core);
|
|
101
99
|
|
|
102
100
|
expect(updateToJazzCloudSpy).toHaveBeenCalledWith(
|
|
103
101
|
emptyKnownState(map.core.id),
|
|
@@ -132,7 +130,7 @@ describe("SyncStateManager", () => {
|
|
|
132
130
|
const map = group.createMap();
|
|
133
131
|
map.set("key1", "value1", "trusting");
|
|
134
132
|
|
|
135
|
-
await client.node.syncManager.
|
|
133
|
+
await client.node.syncManager.syncCoValue(map.core);
|
|
136
134
|
|
|
137
135
|
const subscriptionManager = client.node.syncManager.syncState;
|
|
138
136
|
|
|
@@ -173,7 +171,7 @@ describe("SyncStateManager", () => {
|
|
|
173
171
|
unsubscribe1();
|
|
174
172
|
unsubscribe2();
|
|
175
173
|
|
|
176
|
-
await client.node.syncManager.
|
|
174
|
+
await client.node.syncManager.syncCoValue(map.core);
|
|
177
175
|
|
|
178
176
|
anyUpdateSpy.mockClear();
|
|
179
177
|
|
|
@@ -217,9 +215,6 @@ describe("SyncStateManager", () => {
|
|
|
217
215
|
|
|
218
216
|
const mapOnServer = await loadCoValueOrFail(serverNode, map.id);
|
|
219
217
|
|
|
220
|
-
// Block the content messages so the client won't fully sync immediately
|
|
221
|
-
const outgoing = blockMessageTypeOnOutgoingPeer(peerOnServer, "content");
|
|
222
|
-
|
|
223
218
|
mapOnServer.set("key2", "value2", "trusting");
|
|
224
219
|
|
|
225
220
|
expect(
|
|
@@ -236,9 +231,6 @@ describe("SyncStateManager", () => {
|
|
|
236
231
|
),
|
|
237
232
|
).toEqual({ uploaded: false });
|
|
238
233
|
|
|
239
|
-
await outgoing.sendBlockedMessages();
|
|
240
|
-
outgoing.unblock();
|
|
241
|
-
|
|
242
234
|
await mapOnServer.core.waitForSync();
|
|
243
235
|
|
|
244
236
|
expect(
|
package/src/tests/coList.test.ts
CHANGED
|
@@ -221,16 +221,3 @@ test("Items prepended to start appear with latest first", () => {
|
|
|
221
221
|
|
|
222
222
|
expect(content.toJSON()).toEqual(["third", "second", "first"]);
|
|
223
223
|
});
|
|
224
|
-
|
|
225
|
-
test("should handle large lists", () => {
|
|
226
|
-
const node = new LocalNode(...randomAnonymousAccountAndSessionID(), Crypto);
|
|
227
|
-
|
|
228
|
-
const group = node.createGroup();
|
|
229
|
-
const coValue = group.createList();
|
|
230
|
-
|
|
231
|
-
for (let i = 0; i < 8_000; i++) {
|
|
232
|
-
coValue.append(`item ${i}`, undefined, "trusting");
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
expect(coValue.toJSON().length).toEqual(8_000);
|
|
236
|
-
});
|