cojson 0.12.1 → 0.13.2
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 +22 -0
- package/dist/PeerState.d.ts +1 -7
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +5 -3
- package/dist/PeerState.js.map +1 -1
- package/dist/PriorityBasedMessageQueue.d.ts +17 -3
- package/dist/PriorityBasedMessageQueue.d.ts.map +1 -1
- package/dist/PriorityBasedMessageQueue.js +57 -29
- package/dist/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/coValueCore.d.ts +1 -5
- package/dist/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore.js +29 -43
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValueState.d.ts.map +1 -1
- package/dist/coValueState.js +18 -4
- package/dist/coValueState.js.map +1 -1
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/crypto/crypto.js +3 -1
- package/dist/crypto/crypto.js.map +1 -1
- package/dist/priority.d.ts +2 -2
- package/dist/priority.d.ts.map +1 -1
- package/dist/priority.js +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +21 -28
- package/dist/sync.js.map +1 -1
- package/dist/tests/PriorityBasedMessageQueue.test.js +86 -22
- package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -1
- package/dist/tests/sync.test.js +51 -12
- package/dist/tests/sync.test.js.map +1 -1
- package/package.json +2 -3
- package/src/PeerState.ts +11 -7
- package/src/PriorityBasedMessageQueue.ts +75 -35
- package/src/coValueCore.ts +50 -60
- package/src/coValueState.ts +23 -4
- package/src/crypto/crypto.ts +4 -1
- package/src/priority.ts +2 -2
- package/src/sync.ts +21 -38
- package/src/tests/PriorityBasedMessageQueue.test.ts +127 -34
- package/src/tests/sync.test.ts +64 -21
package/src/coValueState.ts
CHANGED
|
@@ -176,11 +176,12 @@ export class CoValueState {
|
|
|
176
176
|
async loadFromPeers(peers: PeerState[]) {
|
|
177
177
|
const state = this.state;
|
|
178
178
|
|
|
179
|
-
if (state.type
|
|
179
|
+
if (state.type === "loading" || state.type === "available") {
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
if (peers.length === 0) {
|
|
184
|
+
this.moveToState(new CoValueUnavailableState());
|
|
184
185
|
return;
|
|
185
186
|
}
|
|
186
187
|
|
|
@@ -192,7 +193,11 @@ export class CoValueState {
|
|
|
192
193
|
|
|
193
194
|
// If we are in the loading state we move to a new loading state
|
|
194
195
|
// to reset all the loading promises
|
|
195
|
-
if (
|
|
196
|
+
if (
|
|
197
|
+
this.state.type === "loading" ||
|
|
198
|
+
this.state.type === "unknown" ||
|
|
199
|
+
this.state.type === "unavailable"
|
|
200
|
+
) {
|
|
196
201
|
this.moveToState(
|
|
197
202
|
new CoValueLoadingState(peersWithoutErrors.map((p) => p.id)),
|
|
198
203
|
);
|
|
@@ -308,6 +313,19 @@ async function loadCoValueFromPeers(
|
|
|
308
313
|
}
|
|
309
314
|
|
|
310
315
|
if (coValueEntry.state.type === "loading") {
|
|
316
|
+
const { promise, resolve } = createResolvablePromise<void>();
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Use a very long timeout for storage peers, because under pressure
|
|
320
|
+
* they may take a long time to consume the messages queue
|
|
321
|
+
*
|
|
322
|
+
* TODO: Track errors on storage and do not rely on timeout
|
|
323
|
+
*/
|
|
324
|
+
const timeoutDuration =
|
|
325
|
+
peer.role === "storage"
|
|
326
|
+
? CO_VALUE_LOADING_CONFIG.TIMEOUT * 10
|
|
327
|
+
: CO_VALUE_LOADING_CONFIG.TIMEOUT;
|
|
328
|
+
|
|
311
329
|
const timeout = setTimeout(() => {
|
|
312
330
|
if (coValueEntry.state.type === "loading") {
|
|
313
331
|
logger.warn("Failed to load coValue from peer", {
|
|
@@ -319,9 +337,10 @@ async function loadCoValueFromPeers(
|
|
|
319
337
|
type: "not-found-in-peer",
|
|
320
338
|
peerId: peer.id,
|
|
321
339
|
});
|
|
340
|
+
resolve();
|
|
322
341
|
}
|
|
323
|
-
},
|
|
324
|
-
await coValueEntry.state.waitForPeer(peer.id);
|
|
342
|
+
}, timeoutDuration);
|
|
343
|
+
await Promise.race([promise, coValueEntry.state.waitForPeer(peer.id)]);
|
|
325
344
|
clearTimeout(timeout);
|
|
326
345
|
}
|
|
327
346
|
}
|
package/src/crypto/crypto.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomBytes } from "@noble/ciphers/webcrypto/utils";
|
|
2
1
|
import { base58 } from "@scure/base";
|
|
3
2
|
import { RawAccountID } from "../coValues/account.js";
|
|
4
3
|
import { AgentID, RawCoID, TransactionID } from "../ids.js";
|
|
@@ -7,6 +6,10 @@ import { Stringified, parseJSON, stableStringify } from "../jsonStringify.js";
|
|
|
7
6
|
import { JsonValue } from "../jsonValue.js";
|
|
8
7
|
import { logger } from "../logger.js";
|
|
9
8
|
|
|
9
|
+
function randomBytes(bytesLength = 32): Uint8Array {
|
|
10
|
+
return crypto.getRandomValues(new Uint8Array(bytesLength));
|
|
11
|
+
}
|
|
12
|
+
|
|
10
13
|
export type SignerSecret = `signerSecret_z${string}`;
|
|
11
14
|
export type SignerID = `signer_z${string}`;
|
|
12
15
|
export type Signature = `signature_z${string}`;
|
package/src/priority.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { type CoValueHeader } from "./coValueCore.js";
|
|
|
7
7
|
* The priority value is handled as weight in the weighed round robin algorithm
|
|
8
8
|
* used to determine the order in which messages are sent.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* Loosely follows the HTTP urgency range and order, but limited to 3 values:
|
|
11
11
|
* - https://www.rfc-editor.org/rfc/rfc9218.html#name-urgency
|
|
12
12
|
*/
|
|
13
13
|
export const CO_VALUE_PRIORITY = {
|
|
@@ -16,7 +16,7 @@ export const CO_VALUE_PRIORITY = {
|
|
|
16
16
|
LOW: 6,
|
|
17
17
|
} as const;
|
|
18
18
|
|
|
19
|
-
export type CoValuePriority = 0 |
|
|
19
|
+
export type CoValuePriority = 0 | 3 | 6;
|
|
20
20
|
|
|
21
21
|
export function getPriorityFromHeader(
|
|
22
22
|
header: CoValueHeader | undefined | boolean,
|
package/src/sync.ts
CHANGED
|
@@ -23,10 +23,6 @@ export function emptyKnownState(id: RawCoID): CoValueKnownState {
|
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function getErrorMessage(e: unknown) {
|
|
27
|
-
return e instanceof Error ? e.message : "Unknown error";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
export type SyncMessage =
|
|
31
27
|
| LoadMessage
|
|
32
28
|
| KnownStateMessage
|
|
@@ -415,7 +411,20 @@ export class SyncManager {
|
|
|
415
411
|
entry.loadFromPeers([peer]).catch((e) => {
|
|
416
412
|
logger.error("Error loading coValue in handleLoad", { err: e });
|
|
417
413
|
});
|
|
414
|
+
} else {
|
|
415
|
+
// We don't have any eligible peers to load the coValue from
|
|
416
|
+
// so we send a known state back to the sender to let it know
|
|
417
|
+
// that the coValue is unavailable
|
|
418
|
+
this.trySendToPeer(peer, {
|
|
419
|
+
action: "known",
|
|
420
|
+
id: msg.id,
|
|
421
|
+
header: false,
|
|
422
|
+
sessions: {},
|
|
423
|
+
}).catch((e) => {
|
|
424
|
+
logger.error("Error sending known state back", { err: e });
|
|
425
|
+
});
|
|
418
426
|
}
|
|
427
|
+
|
|
419
428
|
return;
|
|
420
429
|
} else {
|
|
421
430
|
this.local.loadCoValueCore(msg.id, peer.id).catch((e) => {
|
|
@@ -460,6 +469,13 @@ export class SyncManager {
|
|
|
460
469
|
err: e,
|
|
461
470
|
});
|
|
462
471
|
});
|
|
472
|
+
} else if (entry.state.type === "unavailable") {
|
|
473
|
+
this.trySendToPeer(peer, {
|
|
474
|
+
action: "known",
|
|
475
|
+
id: msg.id,
|
|
476
|
+
header: false,
|
|
477
|
+
sessions: {},
|
|
478
|
+
});
|
|
463
479
|
}
|
|
464
480
|
|
|
465
481
|
if (entry.state.type === "available") {
|
|
@@ -604,39 +620,12 @@ export class SyncManager {
|
|
|
604
620
|
continue;
|
|
605
621
|
}
|
|
606
622
|
|
|
607
|
-
const before = performance.now();
|
|
608
|
-
// eslint-disable-next-line neverthrow/must-use-result
|
|
609
623
|
const result = coValue.tryAddTransactions(
|
|
610
624
|
sessionID,
|
|
611
625
|
newTransactions,
|
|
612
626
|
undefined,
|
|
613
627
|
newContentForSession.lastSignature,
|
|
614
628
|
);
|
|
615
|
-
const after = performance.now();
|
|
616
|
-
if (after - before > 80) {
|
|
617
|
-
const totalTxLength = newTransactions
|
|
618
|
-
.map((t) =>
|
|
619
|
-
t.privacy === "private"
|
|
620
|
-
? t.encryptedChanges.length
|
|
621
|
-
: t.changes.length,
|
|
622
|
-
)
|
|
623
|
-
.reduce((a, b) => a + b, 0);
|
|
624
|
-
logger.debug(
|
|
625
|
-
`Adding incoming transactions took ${(after - before).toFixed(
|
|
626
|
-
2,
|
|
627
|
-
)}ms for ${totalTxLength} bytes = bandwidth: ${(
|
|
628
|
-
(1000 * totalTxLength) / (after - before) / (1024 * 1024)
|
|
629
|
-
).toFixed(2)} MB/s`,
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// const theirTotalnTxs = Object.values(
|
|
634
|
-
// peer.optimisticKnownStates[msg.id]?.sessions || {},
|
|
635
|
-
// ).reduce((sum, nTxs) => sum + nTxs, 0);
|
|
636
|
-
// const ourTotalnTxs = [...coValue.sessionLogs.values()].reduce(
|
|
637
|
-
// (sum, session) => sum + session.transactions.length,
|
|
638
|
-
// 0,
|
|
639
|
-
// );
|
|
640
629
|
|
|
641
630
|
if (result.isErr()) {
|
|
642
631
|
logger.error("Failed to add transactions", {
|
|
@@ -735,16 +724,10 @@ export class SyncManager {
|
|
|
735
724
|
}
|
|
736
725
|
|
|
737
726
|
async actuallySyncCoValue(coValue: CoValueCore) {
|
|
738
|
-
// let blockingSince = performance.now();
|
|
739
727
|
for (const peer of this.peersInPriorityOrder()) {
|
|
740
728
|
if (peer.closed) continue;
|
|
741
729
|
if (peer.erroredCoValues.has(coValue.id)) continue;
|
|
742
|
-
|
|
743
|
-
// await new Promise<void>((resolve) => {
|
|
744
|
-
// setTimeout(resolve, 0);
|
|
745
|
-
// });
|
|
746
|
-
// blockingSince = performance.now();
|
|
747
|
-
// }
|
|
730
|
+
|
|
748
731
|
if (peer.optimisticKnownStates.has(coValue.id)) {
|
|
749
732
|
await this.tellUntoldKnownStateIncludingDependencies(coValue.id, peer);
|
|
750
733
|
await this.sendNewContentIncludingDependencies(coValue.id, peer);
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
tearDownTestMetricReader,
|
|
8
8
|
} from "./testUtils.js";
|
|
9
9
|
|
|
10
|
-
function setup() {
|
|
10
|
+
function setup(attrs?: Record<string, string | number>) {
|
|
11
11
|
const metricReader = createTestMetricReader();
|
|
12
|
-
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM);
|
|
12
|
+
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM, attrs);
|
|
13
13
|
return { queue, metricReader };
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -18,10 +18,133 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
18
18
|
tearDownTestMetricReader();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
+
describe("meteredQueue", () => {
|
|
22
|
+
test("should corretly count pushes", async () => {
|
|
23
|
+
const { queue, metricReader } = setup();
|
|
24
|
+
const message: SyncMessage = {
|
|
25
|
+
action: "load",
|
|
26
|
+
id: "co_ztest-id",
|
|
27
|
+
header: false,
|
|
28
|
+
sessions: {},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
expect(
|
|
32
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
33
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
34
|
+
}),
|
|
35
|
+
).toBe(0);
|
|
36
|
+
|
|
37
|
+
void queue.push(message);
|
|
38
|
+
expect(
|
|
39
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
40
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
41
|
+
}),
|
|
42
|
+
).toBe(1);
|
|
43
|
+
|
|
44
|
+
void queue.push(message);
|
|
45
|
+
expect(
|
|
46
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
47
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
48
|
+
}),
|
|
49
|
+
).toBe(2);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("should corretly count pulls", async () => {
|
|
53
|
+
const { queue, metricReader } = setup();
|
|
54
|
+
const message: SyncMessage = {
|
|
55
|
+
action: "load",
|
|
56
|
+
id: "co_ztest-id",
|
|
57
|
+
header: false,
|
|
58
|
+
sessions: {},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
expect(
|
|
62
|
+
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
63
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
64
|
+
}),
|
|
65
|
+
).toBe(0);
|
|
66
|
+
|
|
67
|
+
void queue.push(message);
|
|
68
|
+
expect(
|
|
69
|
+
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
70
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
71
|
+
}),
|
|
72
|
+
).toBe(0);
|
|
73
|
+
|
|
74
|
+
void queue.pull();
|
|
75
|
+
|
|
76
|
+
expect(
|
|
77
|
+
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
78
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
79
|
+
}),
|
|
80
|
+
).toBe(1);
|
|
81
|
+
|
|
82
|
+
// We only have one item in the queue, so this should not change the metric value
|
|
83
|
+
void queue.pull();
|
|
84
|
+
expect(
|
|
85
|
+
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
86
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
87
|
+
}),
|
|
88
|
+
).toBe(1);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("should corretly set custom attributes to the metrics", async () => {
|
|
92
|
+
const { queue, metricReader } = setup({ role: "server" });
|
|
93
|
+
const message: SyncMessage = {
|
|
94
|
+
action: "load",
|
|
95
|
+
id: "co_ztest-id",
|
|
96
|
+
header: false,
|
|
97
|
+
sessions: {},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
expect(
|
|
101
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
102
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
103
|
+
role: "server",
|
|
104
|
+
}),
|
|
105
|
+
).toBe(0);
|
|
106
|
+
expect(
|
|
107
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
108
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
109
|
+
role: "client",
|
|
110
|
+
}),
|
|
111
|
+
).toBeUndefined();
|
|
112
|
+
|
|
113
|
+
void queue.push(message);
|
|
114
|
+
expect(
|
|
115
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
116
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
117
|
+
role: "server",
|
|
118
|
+
}),
|
|
119
|
+
).toBe(1);
|
|
120
|
+
expect(
|
|
121
|
+
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
122
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
123
|
+
role: "server",
|
|
124
|
+
}),
|
|
125
|
+
).toBe(0);
|
|
126
|
+
|
|
127
|
+
void queue.pull();
|
|
128
|
+
|
|
129
|
+
expect(
|
|
130
|
+
await metricReader.getMetricValue("jazz.messagequeue.pushed", {
|
|
131
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
132
|
+
role: "server",
|
|
133
|
+
}),
|
|
134
|
+
).toBe(1);
|
|
135
|
+
expect(
|
|
136
|
+
await metricReader.getMetricValue("jazz.messagequeue.pulled", {
|
|
137
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
138
|
+
role: "server",
|
|
139
|
+
}),
|
|
140
|
+
).toBe(1);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
21
144
|
test("should initialize with correct properties", () => {
|
|
22
145
|
const { queue } = setup();
|
|
23
146
|
expect(queue["defaultPriority"]).toBe(CO_VALUE_PRIORITY.MEDIUM);
|
|
24
|
-
expect(queue["queues"].length).toBe(
|
|
147
|
+
expect(queue["queues"].length).toBe(3);
|
|
25
148
|
expect(queue["queues"].every((q) => !q.length)).toBe(true);
|
|
26
149
|
});
|
|
27
150
|
|
|
@@ -52,7 +175,7 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
52
175
|
});
|
|
53
176
|
|
|
54
177
|
test("should pull messages in priority order", async () => {
|
|
55
|
-
const { queue
|
|
178
|
+
const { queue } = setup();
|
|
56
179
|
const lowPriorityMsg: SyncMessage = {
|
|
57
180
|
action: "content",
|
|
58
181
|
id: "co_zlow",
|
|
@@ -73,42 +196,12 @@ describe("PriorityBasedMessageQueue", () => {
|
|
|
73
196
|
};
|
|
74
197
|
|
|
75
198
|
void queue.push(lowPriorityMsg);
|
|
76
|
-
expect(
|
|
77
|
-
await metricReader.getMetricValue("jazz.messagequeue.size", {
|
|
78
|
-
priority: lowPriorityMsg.priority,
|
|
79
|
-
}),
|
|
80
|
-
).toBe(1);
|
|
81
199
|
void queue.push(mediumPriorityMsg);
|
|
82
|
-
expect(
|
|
83
|
-
await metricReader.getMetricValue("jazz.messagequeue.size", {
|
|
84
|
-
priority: mediumPriorityMsg.priority,
|
|
85
|
-
}),
|
|
86
|
-
).toBe(1);
|
|
87
200
|
void queue.push(highPriorityMsg);
|
|
88
|
-
expect(
|
|
89
|
-
await metricReader.getMetricValue("jazz.messagequeue.size", {
|
|
90
|
-
priority: highPriorityMsg.priority,
|
|
91
|
-
}),
|
|
92
|
-
).toBe(1);
|
|
93
201
|
|
|
94
202
|
expect(queue.pull()?.msg).toEqual(highPriorityMsg);
|
|
95
|
-
expect(
|
|
96
|
-
await metricReader.getMetricValue("jazz.messagequeue.size", {
|
|
97
|
-
priority: highPriorityMsg.priority,
|
|
98
|
-
}),
|
|
99
|
-
).toBe(0);
|
|
100
203
|
expect(queue.pull()?.msg).toEqual(mediumPriorityMsg);
|
|
101
|
-
expect(
|
|
102
|
-
await metricReader.getMetricValue("jazz.messagequeue.size", {
|
|
103
|
-
priority: mediumPriorityMsg.priority,
|
|
104
|
-
}),
|
|
105
|
-
).toBe(0);
|
|
106
204
|
expect(queue.pull()?.msg).toEqual(lowPriorityMsg);
|
|
107
|
-
expect(
|
|
108
|
-
await metricReader.getMetricValue("jazz.messagequeue.size", {
|
|
109
|
-
priority: lowPriorityMsg.priority,
|
|
110
|
-
}),
|
|
111
|
-
).toBe(0);
|
|
112
205
|
});
|
|
113
206
|
|
|
114
207
|
test("should return undefined when pulling from empty queue", () => {
|
package/src/tests/sync.test.ts
CHANGED
|
@@ -956,27 +956,6 @@ test.skip("When a peer's incoming/readable stream closes, we remove the peer", a
|
|
|
956
956
|
*/
|
|
957
957
|
});
|
|
958
958
|
|
|
959
|
-
test("If we start loading a coValue before connecting to a peer that has it, it will load it once we connect", async () => {
|
|
960
|
-
const { node: node1 } = await createConnectedTestNode();
|
|
961
|
-
|
|
962
|
-
const group = node1.createGroup();
|
|
963
|
-
|
|
964
|
-
const map = group.createMap();
|
|
965
|
-
map.set("hello", "world", "trusting");
|
|
966
|
-
|
|
967
|
-
const node2 = createTestNode();
|
|
968
|
-
|
|
969
|
-
const mapOnNode2Promise = loadCoValueOrFail(node2, map.id);
|
|
970
|
-
|
|
971
|
-
expect(node2.coValuesStore.get(map.core.id).state.type).toEqual("unknown");
|
|
972
|
-
|
|
973
|
-
connectNodeToSyncServer(node2);
|
|
974
|
-
|
|
975
|
-
const mapOnNode2 = await mapOnNode2Promise;
|
|
976
|
-
|
|
977
|
-
expect(mapOnNode2.get("hello")).toEqual("world");
|
|
978
|
-
});
|
|
979
|
-
|
|
980
959
|
test("should keep the peer state when the peer closes", async () => {
|
|
981
960
|
const client = createTestNode();
|
|
982
961
|
|
|
@@ -1726,6 +1705,45 @@ describe("loadCoValueCore with retry", () => {
|
|
|
1726
1705
|
await expect(promise1).resolves.not.toBe("unavailable");
|
|
1727
1706
|
await expect(promise2).resolves.not.toBe("unavailable");
|
|
1728
1707
|
});
|
|
1708
|
+
|
|
1709
|
+
test("should load unavailable coValues after they are synced", async () => {
|
|
1710
|
+
const bob = createTestNode();
|
|
1711
|
+
const alice = createTestNode();
|
|
1712
|
+
|
|
1713
|
+
// Create a group and map on anotherClient
|
|
1714
|
+
const group = alice.createGroup();
|
|
1715
|
+
const map = group.createMap();
|
|
1716
|
+
map.set("key1", "value1", "trusting");
|
|
1717
|
+
|
|
1718
|
+
// Start loading before syncing
|
|
1719
|
+
const result = await bob.loadCoValueCore(map.id);
|
|
1720
|
+
|
|
1721
|
+
expect(result).toBe("unavailable");
|
|
1722
|
+
|
|
1723
|
+
connectTwoPeers(alice, bob, "server", "server");
|
|
1724
|
+
|
|
1725
|
+
const result2 = await bob.loadCoValueCore(map.id);
|
|
1726
|
+
|
|
1727
|
+
expect(result2).not.toBe("unavailable");
|
|
1728
|
+
});
|
|
1729
|
+
|
|
1730
|
+
test("should successfully mark a coValue as unavailable if the server does not have it", async () => {
|
|
1731
|
+
const bob = createTestNode();
|
|
1732
|
+
const alice = createTestNode();
|
|
1733
|
+
const charlie = createTestNode();
|
|
1734
|
+
|
|
1735
|
+
connectTwoPeers(bob, charlie, "client", "server");
|
|
1736
|
+
|
|
1737
|
+
// Create a group and map on anotherClient
|
|
1738
|
+
const group = alice.createGroup();
|
|
1739
|
+
const map = group.createMap();
|
|
1740
|
+
map.set("key1", "value1", "trusting");
|
|
1741
|
+
|
|
1742
|
+
// Start loading before syncing
|
|
1743
|
+
const result = await bob.loadCoValueCore(map.id);
|
|
1744
|
+
|
|
1745
|
+
expect(result).toBe("unavailable");
|
|
1746
|
+
});
|
|
1729
1747
|
});
|
|
1730
1748
|
|
|
1731
1749
|
describe("waitForSyncWithPeer", () => {
|
|
@@ -1894,6 +1912,8 @@ describe("sync protocol", () => {
|
|
|
1894
1912
|
const map = group.createMap();
|
|
1895
1913
|
map.set("hello", "world", "trusting");
|
|
1896
1914
|
|
|
1915
|
+
await map.core.waitForSync();
|
|
1916
|
+
|
|
1897
1917
|
const mapOnJazzCloud = await loadCoValueOrFail(jazzCloud, map.id);
|
|
1898
1918
|
expect(mapOnJazzCloud.get("hello")).toEqual("world");
|
|
1899
1919
|
|
|
@@ -2038,6 +2058,29 @@ describe("sync protocol", () => {
|
|
|
2038
2058
|
},
|
|
2039
2059
|
},
|
|
2040
2060
|
},
|
|
2061
|
+
{
|
|
2062
|
+
from: "server",
|
|
2063
|
+
msg: {
|
|
2064
|
+
action: "known",
|
|
2065
|
+
header: true,
|
|
2066
|
+
id: map.id,
|
|
2067
|
+
sessions: {
|
|
2068
|
+
[client.currentSessionID]: 1,
|
|
2069
|
+
},
|
|
2070
|
+
},
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
from: "server",
|
|
2074
|
+
msg: {
|
|
2075
|
+
action: "known",
|
|
2076
|
+
asDependencyOf: undefined,
|
|
2077
|
+
header: true,
|
|
2078
|
+
id: map.id,
|
|
2079
|
+
sessions: {
|
|
2080
|
+
[client.currentSessionID]: 1,
|
|
2081
|
+
},
|
|
2082
|
+
},
|
|
2083
|
+
},
|
|
2041
2084
|
]);
|
|
2042
2085
|
});
|
|
2043
2086
|
});
|