cojson 0.13.2 → 0.13.7
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 +16 -0
- package/LICENSE.txt +1 -1
- package/dist/PeerState.d.ts +6 -0
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +43 -0
- package/dist/PeerState.js.map +1 -1
- package/dist/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore.js +1 -0
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValueState.d.ts +1 -0
- package/dist/coValueState.d.ts.map +1 -1
- package/dist/coValueState.js +27 -2
- package/dist/coValueState.js.map +1 -1
- package/dist/coValues/group.d.ts +1 -0
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +45 -21
- package/dist/coValues/group.js.map +1 -1
- package/dist/crypto/crypto.d.ts +2 -2
- package/dist/crypto/crypto.d.ts.map +1 -1
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +19 -3
- package/dist/permissions.js.map +1 -1
- package/dist/storage/FileSystem.d.ts +2 -2
- package/dist/storage/FileSystem.d.ts.map +1 -1
- package/dist/sync.d.ts +14 -4
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +146 -146
- package/dist/sync.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +51 -46
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +51 -2
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coValueState.test.js +31 -4
- package/dist/tests/coValueState.test.js.map +1 -1
- package/dist/tests/group.test.js +135 -2
- package/dist/tests/group.test.js.map +1 -1
- package/dist/tests/messagesTestUtils.d.ts +13 -0
- package/dist/tests/messagesTestUtils.d.ts.map +1 -0
- package/dist/tests/messagesTestUtils.js +42 -0
- package/dist/tests/messagesTestUtils.js.map +1 -0
- package/dist/tests/sync.load.test.d.ts +2 -0
- package/dist/tests/sync.load.test.d.ts.map +1 -0
- package/dist/tests/sync.load.test.js +249 -0
- package/dist/tests/sync.load.test.js.map +1 -0
- package/dist/tests/sync.mesh.test.d.ts +2 -0
- package/dist/tests/sync.mesh.test.d.ts.map +1 -0
- package/dist/tests/sync.mesh.test.js +157 -0
- package/dist/tests/sync.mesh.test.js.map +1 -0
- package/dist/tests/sync.peerReconciliation.test.d.ts +2 -0
- package/dist/tests/sync.peerReconciliation.test.d.ts.map +1 -0
- package/dist/tests/sync.peerReconciliation.test.js +130 -0
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -0
- package/dist/tests/sync.storage.test.d.ts +2 -0
- package/dist/tests/sync.storage.test.d.ts.map +1 -0
- package/dist/tests/sync.storage.test.js +201 -0
- package/dist/tests/sync.storage.test.js.map +1 -0
- package/dist/tests/sync.test.js +139 -1048
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.d.ts +2 -0
- package/dist/tests/sync.upload.test.d.ts.map +1 -0
- package/dist/tests/sync.upload.test.js +156 -0
- package/dist/tests/sync.upload.test.js.map +1 -0
- package/dist/tests/testUtils.d.ts +76 -33
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +153 -47
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +3 -3
- package/src/PeerState.ts +59 -1
- package/src/coValueCore.ts +1 -0
- package/src/coValueState.ts +34 -3
- package/src/coValues/group.ts +83 -45
- package/src/permissions.ts +31 -3
- package/src/sync.ts +169 -185
- package/src/tests/SyncStateManager.test.ts +58 -70
- package/src/tests/coValueCore.test.ts +70 -1
- package/src/tests/coValueState.test.ts +59 -5
- package/src/tests/group.test.ts +250 -2
- package/src/tests/messagesTestUtils.ts +75 -0
- package/src/tests/sync.load.test.ts +327 -0
- package/src/tests/sync.mesh.test.ts +219 -0
- package/src/tests/sync.peerReconciliation.test.ts +201 -0
- package/src/tests/sync.storage.test.ts +259 -0
- package/src/tests/sync.test.ts +170 -1245
- package/src/tests/sync.upload.test.ts +202 -0
- package/src/tests/testUtils.ts +213 -61
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { expectMap } from "../coValue";
|
|
4
|
+
import {
|
|
5
|
+
SyncMessagesLog,
|
|
6
|
+
loadCoValueOrFail,
|
|
7
|
+
setupTestNode,
|
|
8
|
+
waitFor,
|
|
9
|
+
} from "./testUtils";
|
|
10
|
+
|
|
11
|
+
let jazzCloud = setupTestNode({ isSyncServer: true });
|
|
12
|
+
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
SyncMessagesLog.clear();
|
|
15
|
+
jazzCloud = setupTestNode({ isSyncServer: true });
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("client to server upload", () => {
|
|
19
|
+
test("coValue uploading", async () => {
|
|
20
|
+
const client = setupTestNode({
|
|
21
|
+
connected: true,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const group = client.node.createGroup();
|
|
25
|
+
const map = group.createMap();
|
|
26
|
+
map.set("hello", "world", "trusting");
|
|
27
|
+
|
|
28
|
+
await map.core.waitForSync();
|
|
29
|
+
|
|
30
|
+
const mapOnServer = await loadCoValueOrFail(jazzCloud.node, map.id);
|
|
31
|
+
expect(mapOnServer.get("hello")).toEqual("world");
|
|
32
|
+
|
|
33
|
+
expect(
|
|
34
|
+
SyncMessagesLog.getMessages({
|
|
35
|
+
Group: group.core,
|
|
36
|
+
Map: map.core,
|
|
37
|
+
}),
|
|
38
|
+
).toMatchInlineSnapshot(`
|
|
39
|
+
[
|
|
40
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
41
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
42
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
43
|
+
"server -> client | KNOWN Map sessions: header/1",
|
|
44
|
+
]
|
|
45
|
+
`);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("coValue with parent groups uploading", async () => {
|
|
49
|
+
const client = setupTestNode({
|
|
50
|
+
connected: true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const group = client.node.createGroup();
|
|
54
|
+
const parentGroup = client.node.createGroup();
|
|
55
|
+
parentGroup.addMember("everyone", "reader");
|
|
56
|
+
|
|
57
|
+
group.extend(parentGroup);
|
|
58
|
+
|
|
59
|
+
const map = group.createMap();
|
|
60
|
+
map.set("hello", "world");
|
|
61
|
+
|
|
62
|
+
await map.core.waitForSync();
|
|
63
|
+
|
|
64
|
+
const mapOnServer = await loadCoValueOrFail(jazzCloud.node, map.id);
|
|
65
|
+
expect(mapOnServer.get("hello")).toEqual("world");
|
|
66
|
+
|
|
67
|
+
expect(
|
|
68
|
+
SyncMessagesLog.getMessages({
|
|
69
|
+
ParentGroup: parentGroup.core,
|
|
70
|
+
Group: group.core,
|
|
71
|
+
Map: map.core,
|
|
72
|
+
}),
|
|
73
|
+
).toMatchInlineSnapshot(`
|
|
74
|
+
[
|
|
75
|
+
"client -> server | CONTENT ParentGroup header: true new: After: 0 New: 6",
|
|
76
|
+
"server -> client | KNOWN ParentGroup sessions: header/6",
|
|
77
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
78
|
+
"server -> client | KNOWN Group sessions: header/5",
|
|
79
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
80
|
+
"server -> client | KNOWN Map sessions: header/1",
|
|
81
|
+
]
|
|
82
|
+
`);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("wrong optimistic known state should be corrected", async () => {
|
|
86
|
+
const client = setupTestNode({
|
|
87
|
+
connected: true,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const group = client.node.createGroup();
|
|
91
|
+
group.addMember("everyone", "writer");
|
|
92
|
+
|
|
93
|
+
const map = group.createMap({
|
|
94
|
+
fromServer: "initial",
|
|
95
|
+
fromClient: "initial",
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Load the coValue on the client
|
|
99
|
+
await map.core.waitForSync();
|
|
100
|
+
|
|
101
|
+
// Forcefully delete the coValue from the client (simulating some data loss)
|
|
102
|
+
jazzCloud.node.coValuesStore.coValues.delete(map.id);
|
|
103
|
+
|
|
104
|
+
map.set("fromClient", "updated", "trusting");
|
|
105
|
+
|
|
106
|
+
await waitFor(() => {
|
|
107
|
+
const coValue = expectMap(
|
|
108
|
+
jazzCloud.node.expectCoValueLoaded(map.id).getCurrentContent(),
|
|
109
|
+
);
|
|
110
|
+
expect(coValue.get("fromClient")).toEqual("updated");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(
|
|
114
|
+
SyncMessagesLog.getMessages({
|
|
115
|
+
Group: group.core,
|
|
116
|
+
Map: map.core,
|
|
117
|
+
}),
|
|
118
|
+
).toMatchInlineSnapshot(`
|
|
119
|
+
[
|
|
120
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
121
|
+
"server -> client | KNOWN Group sessions: header/5",
|
|
122
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
123
|
+
"server -> client | KNOWN Map sessions: header/1",
|
|
124
|
+
"client -> server | CONTENT Map header: false new: After: 1 New: 1",
|
|
125
|
+
"server -> client | KNOWN CORRECTION Map sessions: empty",
|
|
126
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 2",
|
|
127
|
+
"server -> client | KNOWN Map sessions: header/2",
|
|
128
|
+
]
|
|
129
|
+
`);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("large coValue upload streaming", async () => {
|
|
133
|
+
const client = setupTestNode({
|
|
134
|
+
connected: true,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const group = client.node.createGroup();
|
|
138
|
+
group.addMember("everyone", "writer");
|
|
139
|
+
|
|
140
|
+
const largeMap = group.createMap();
|
|
141
|
+
|
|
142
|
+
// Generate a large amount of data (about 100MB)
|
|
143
|
+
const dataSize = 1 * 1024 * 1024;
|
|
144
|
+
const chunkSize = 1024; // 1KB chunks
|
|
145
|
+
const chunks = dataSize / chunkSize;
|
|
146
|
+
|
|
147
|
+
const value = Buffer.alloc(chunkSize, `value$`).toString("base64");
|
|
148
|
+
|
|
149
|
+
for (let i = 0; i < chunks; i++) {
|
|
150
|
+
const key = `key${i}`;
|
|
151
|
+
largeMap.set(key, value, "trusting");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
await loadCoValueOrFail(client.node, largeMap.id);
|
|
155
|
+
|
|
156
|
+
await largeMap.core.waitForSync();
|
|
157
|
+
|
|
158
|
+
expect(
|
|
159
|
+
SyncMessagesLog.getMessages({
|
|
160
|
+
Group: group.core,
|
|
161
|
+
Map: largeMap.core,
|
|
162
|
+
}),
|
|
163
|
+
).toMatchInlineSnapshot(`
|
|
164
|
+
[
|
|
165
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
166
|
+
"server -> client | KNOWN Group sessions: header/5",
|
|
167
|
+
"client -> server | CONTENT Map header: true new: ",
|
|
168
|
+
"server -> client | KNOWN Map sessions: header/0",
|
|
169
|
+
"client -> server | CONTENT Map header: false new: After: 0 New: 73",
|
|
170
|
+
"server -> client | KNOWN Map sessions: header/73",
|
|
171
|
+
"client -> server | CONTENT Map header: false new: After: 73 New: 73",
|
|
172
|
+
"client -> server | CONTENT Map header: false new: After: 146 New: 73",
|
|
173
|
+
"server -> client | KNOWN Map sessions: header/146",
|
|
174
|
+
"client -> server | CONTENT Map header: false new: After: 219 New: 73",
|
|
175
|
+
"client -> server | CONTENT Map header: false new: After: 292 New: 73",
|
|
176
|
+
"server -> client | KNOWN Map sessions: header/219",
|
|
177
|
+
"client -> server | CONTENT Map header: false new: After: 365 New: 73",
|
|
178
|
+
"client -> server | CONTENT Map header: false new: After: 438 New: 73",
|
|
179
|
+
"server -> client | KNOWN Map sessions: header/292",
|
|
180
|
+
"client -> server | CONTENT Map header: false new: After: 511 New: 73",
|
|
181
|
+
"client -> server | CONTENT Map header: false new: After: 584 New: 73",
|
|
182
|
+
"server -> client | KNOWN Map sessions: header/365",
|
|
183
|
+
"client -> server | CONTENT Map header: false new: After: 657 New: 73",
|
|
184
|
+
"client -> server | CONTENT Map header: false new: After: 730 New: 73",
|
|
185
|
+
"server -> client | KNOWN Map sessions: header/438",
|
|
186
|
+
"client -> server | CONTENT Map header: false new: After: 803 New: 73",
|
|
187
|
+
"client -> server | CONTENT Map header: false new: After: 876 New: 73",
|
|
188
|
+
"server -> client | KNOWN Map sessions: header/511",
|
|
189
|
+
"client -> server | CONTENT Map header: false new: After: 949 New: 73",
|
|
190
|
+
"client -> server | CONTENT Map header: false new: After: 1022 New: 2",
|
|
191
|
+
"server -> client | KNOWN Map sessions: header/584",
|
|
192
|
+
"server -> client | KNOWN Map sessions: header/657",
|
|
193
|
+
"server -> client | KNOWN Map sessions: header/730",
|
|
194
|
+
"server -> client | KNOWN Map sessions: header/803",
|
|
195
|
+
"server -> client | KNOWN Map sessions: header/876",
|
|
196
|
+
"server -> client | KNOWN Map sessions: header/949",
|
|
197
|
+
"server -> client | KNOWN Map sessions: header/1022",
|
|
198
|
+
"server -> client | KNOWN Map sessions: header/1024",
|
|
199
|
+
]
|
|
200
|
+
`);
|
|
201
|
+
});
|
|
202
|
+
});
|
package/src/tests/testUtils.ts
CHANGED
|
@@ -8,12 +8,13 @@ import {
|
|
|
8
8
|
import { expect, onTestFinished, vi } from "vitest";
|
|
9
9
|
import { ControlledAgent } from "../coValues/account.js";
|
|
10
10
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
11
|
-
import type { CoID, RawCoValue } from "../exports.js";
|
|
11
|
+
import type { CoID, CoValueCore, RawCoValue } from "../exports.js";
|
|
12
12
|
import type { SessionID } from "../ids.js";
|
|
13
13
|
import { LocalNode } from "../localNode.js";
|
|
14
14
|
import { connectedPeers } from "../streamUtils.js";
|
|
15
15
|
import type { Peer, SyncMessage } from "../sync.js";
|
|
16
16
|
import { expectGroup } from "../typeUtils/expectGroup.js";
|
|
17
|
+
import { toSimplifiedMessages } from "./messagesTestUtils.js";
|
|
17
18
|
|
|
18
19
|
const Crypto = await WasmCrypto.create();
|
|
19
20
|
|
|
@@ -234,11 +235,13 @@ export function shouldNotResolve<T>(
|
|
|
234
235
|
});
|
|
235
236
|
}
|
|
236
237
|
|
|
237
|
-
export function waitFor(
|
|
238
|
+
export function waitFor(
|
|
239
|
+
callback: () => boolean | void | Promise<boolean | void>,
|
|
240
|
+
) {
|
|
238
241
|
return new Promise<void>((resolve, reject) => {
|
|
239
|
-
const checkPassed = () => {
|
|
242
|
+
const checkPassed = async () => {
|
|
240
243
|
try {
|
|
241
|
-
return { ok: callback(), error: null };
|
|
244
|
+
return { ok: await callback(), error: null };
|
|
242
245
|
} catch (error) {
|
|
243
246
|
return { ok: false, error };
|
|
244
247
|
}
|
|
@@ -246,8 +249,8 @@ export function waitFor(callback: () => boolean | void) {
|
|
|
246
249
|
|
|
247
250
|
let retries = 0;
|
|
248
251
|
|
|
249
|
-
const interval = setInterval(() => {
|
|
250
|
-
const { ok, error } = checkPassed();
|
|
252
|
+
const interval = setInterval(async () => {
|
|
253
|
+
const { ok, error } = await checkPassed();
|
|
251
254
|
|
|
252
255
|
if (ok !== false) {
|
|
253
256
|
clearInterval(interval);
|
|
@@ -378,89 +381,238 @@ export function tearDownTestMetricReader() {
|
|
|
378
381
|
metrics.disable();
|
|
379
382
|
}
|
|
380
383
|
|
|
381
|
-
export
|
|
382
|
-
|
|
383
|
-
return syncServer.current;
|
|
384
|
-
}
|
|
384
|
+
export class SyncMessagesLog {
|
|
385
|
+
static messages: SyncTestMessage[] = [];
|
|
385
386
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
throw new Error("Sync server not initialized");
|
|
387
|
+
static add(message: SyncTestMessage) {
|
|
388
|
+
this.messages.push(message);
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
|
|
392
|
-
|
|
391
|
+
static clear() {
|
|
392
|
+
this.messages.length = 0;
|
|
393
|
+
}
|
|
393
394
|
|
|
394
|
-
|
|
395
|
-
|
|
395
|
+
static getMessages(coValueMapping: { [key: string]: CoValueCore }) {
|
|
396
|
+
return toSimplifiedMessages(coValueMapping, SyncMessagesLog.messages);
|
|
397
|
+
}
|
|
396
398
|
|
|
397
|
-
|
|
399
|
+
static debugMessages(coValueMapping: { [key: string]: CoValueCore }) {
|
|
400
|
+
console.log(SyncMessagesLog.getMessages(coValueMapping));
|
|
401
|
+
}
|
|
398
402
|
}
|
|
399
403
|
|
|
400
|
-
export
|
|
401
|
-
|
|
402
|
-
|
|
404
|
+
export function setupTestNode(
|
|
405
|
+
opts: {
|
|
406
|
+
isSyncServer?: boolean;
|
|
407
|
+
connected?: boolean;
|
|
408
|
+
} = {},
|
|
409
|
+
) {
|
|
410
|
+
const [admin, session] = randomAnonymousAccountAndSessionID();
|
|
411
|
+
let node = new LocalNode(admin, session, Crypto);
|
|
412
|
+
|
|
413
|
+
if (opts.isSyncServer) {
|
|
414
|
+
syncServer.current = node;
|
|
403
415
|
}
|
|
404
416
|
|
|
417
|
+
function connectToSyncServer(opts?: {
|
|
418
|
+
syncServerName?: string;
|
|
419
|
+
ourName?: string;
|
|
420
|
+
syncServer?: LocalNode;
|
|
421
|
+
}) {
|
|
422
|
+
const currentSyncServer = opts?.syncServer ?? syncServer.current;
|
|
423
|
+
|
|
424
|
+
if (!currentSyncServer) {
|
|
425
|
+
throw new Error("Sync server not initialized");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (currentSyncServer.account.id === node.account.id) {
|
|
429
|
+
throw new Error("Cannot connect to self");
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const { peer1, peer2 } = connectedPeersWithMessagesTracking({
|
|
433
|
+
peer1: {
|
|
434
|
+
id: currentSyncServer.account.id,
|
|
435
|
+
role: "server",
|
|
436
|
+
name: opts?.syncServerName,
|
|
437
|
+
},
|
|
438
|
+
peer2: { id: node.account.id, role: "client", name: opts?.ourName },
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
node.syncManager.addPeer(peer1);
|
|
442
|
+
currentSyncServer.syncManager.addPeer(peer2);
|
|
443
|
+
|
|
444
|
+
return {
|
|
445
|
+
peerState: node.syncManager.peers[peer1.id]!,
|
|
446
|
+
peer: peer1,
|
|
447
|
+
peerStateOnServer: currentSyncServer.syncManager.peers[peer2.id]!,
|
|
448
|
+
peerOnServer: peer2,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function addStoragePeer(opts: { ourName?: string } = {}) {
|
|
453
|
+
const storage = createTestNode();
|
|
454
|
+
|
|
455
|
+
const { peer1, peer2 } = connectedPeersWithMessagesTracking({
|
|
456
|
+
peer1: { id: storage.account.id, role: "storage" },
|
|
457
|
+
peer2: { id: node.account.id, role: "client", name: opts.ourName },
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
peer1.priority = 100;
|
|
461
|
+
|
|
462
|
+
node.syncManager.addPeer(peer1);
|
|
463
|
+
storage.syncManager.addPeer(peer2);
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
storage,
|
|
467
|
+
peer: node.syncManager.peers[peer1.id]!,
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (opts.connected) {
|
|
472
|
+
connectToSyncServer();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return {
|
|
476
|
+
node,
|
|
477
|
+
connectToSyncServer,
|
|
478
|
+
addStoragePeer,
|
|
479
|
+
restart: () => {
|
|
480
|
+
node.gracefulShutdown();
|
|
481
|
+
node = new LocalNode(admin, session, Crypto);
|
|
482
|
+
|
|
483
|
+
if (opts.isSyncServer) {
|
|
484
|
+
syncServer.current = node;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return node;
|
|
488
|
+
},
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export async function setupTestAccount(
|
|
493
|
+
opts: {
|
|
494
|
+
isSyncServer?: boolean;
|
|
495
|
+
connected?: boolean;
|
|
496
|
+
} = {},
|
|
497
|
+
) {
|
|
405
498
|
const ctx = await LocalNode.withNewlyCreatedAccount({
|
|
406
499
|
peersToLoadFrom: [],
|
|
407
500
|
crypto: Crypto,
|
|
408
501
|
creationProps: { name: "Client" },
|
|
409
502
|
});
|
|
410
503
|
|
|
411
|
-
|
|
412
|
-
|
|
504
|
+
if (opts.isSyncServer) {
|
|
505
|
+
syncServer.current = ctx.node;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function connectToSyncServer(opts?: {
|
|
509
|
+
syncServerName?: string;
|
|
510
|
+
ourName?: string;
|
|
511
|
+
syncServer?: LocalNode;
|
|
512
|
+
}) {
|
|
513
|
+
const currentSyncServer = opts?.syncServer ?? syncServer.current;
|
|
514
|
+
|
|
515
|
+
if (!currentSyncServer) {
|
|
516
|
+
throw new Error("Sync server not initialized");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (currentSyncServer.account.id === ctx.node.account.id) {
|
|
520
|
+
throw new Error("Cannot connect to self");
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const { peer1, peer2 } = connectedPeersWithMessagesTracking({
|
|
524
|
+
peer1: {
|
|
525
|
+
id: currentSyncServer.account.id,
|
|
526
|
+
role: "server",
|
|
527
|
+
name: opts?.syncServerName,
|
|
528
|
+
},
|
|
529
|
+
peer2: { id: ctx.node.account.id, role: "client", name: opts?.ourName },
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
ctx.node.syncManager.addPeer(peer1);
|
|
533
|
+
currentSyncServer.syncManager.addPeer(peer2);
|
|
534
|
+
|
|
535
|
+
function getCurrentPeerState() {
|
|
536
|
+
return ctx.node.syncManager.peers[peer1.id]!;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return {
|
|
540
|
+
peerState: getCurrentPeerState(),
|
|
541
|
+
peer: peer1,
|
|
542
|
+
peerStateOnServer: currentSyncServer.syncManager.peers[peer2.id]!,
|
|
543
|
+
peerOnServer: peer2,
|
|
544
|
+
getCurrentPeerState,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function addStoragePeer(opts: { ourName?: string } = {}) {
|
|
549
|
+
const storage = createTestNode();
|
|
550
|
+
|
|
551
|
+
const { peer1, peer2 } = connectedPeersWithMessagesTracking({
|
|
552
|
+
peer1: { id: storage.account.id, role: "storage" },
|
|
553
|
+
peer2: { id: ctx.node.account.id, role: "client", name: opts.ourName },
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
peer1.priority = 100;
|
|
557
|
+
|
|
558
|
+
ctx.node.syncManager.addPeer(peer1);
|
|
559
|
+
storage.syncManager.addPeer(peer2);
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
storage,
|
|
563
|
+
peer: ctx.node.syncManager.peers[peer1.id]!,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (opts.connected) {
|
|
568
|
+
connectToSyncServer();
|
|
569
|
+
}
|
|
413
570
|
|
|
414
571
|
return {
|
|
415
572
|
node: ctx.node,
|
|
416
573
|
accountID: ctx.accountID,
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
messages,
|
|
420
|
-
addServerPeer,
|
|
574
|
+
connectToSyncServer,
|
|
575
|
+
addStoragePeer,
|
|
421
576
|
};
|
|
422
577
|
}
|
|
423
578
|
|
|
424
|
-
export
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const [nodeToServerPeer, serverToNodePeer] = connectedPeers(
|
|
430
|
-
syncServer.current.account.id,
|
|
431
|
-
node.account.id,
|
|
432
|
-
{
|
|
433
|
-
peer1role: "server",
|
|
434
|
-
peer2role: "client",
|
|
435
|
-
},
|
|
436
|
-
);
|
|
579
|
+
export type SyncTestMessage = {
|
|
580
|
+
from: string;
|
|
581
|
+
to: string;
|
|
582
|
+
msg: SyncMessage;
|
|
583
|
+
};
|
|
437
584
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
585
|
+
export function connectedPeersWithMessagesTracking(opts: {
|
|
586
|
+
peer1: { id: string; role: Peer["role"]; name?: string };
|
|
587
|
+
peer2: { id: string; role: Peer["role"]; name?: string };
|
|
588
|
+
}) {
|
|
589
|
+
const [peer1, peer2] = connectedPeers(opts.peer1.id, opts.peer2.id, {
|
|
590
|
+
peer1role: opts.peer1.role,
|
|
591
|
+
peer2role: opts.peer2.role,
|
|
592
|
+
});
|
|
442
593
|
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
594
|
+
const peer1Push = peer1.outgoing.push;
|
|
595
|
+
peer1.outgoing.push = (msg) => {
|
|
596
|
+
SyncMessagesLog.add({
|
|
597
|
+
from: opts.peer2.name ?? opts.peer2.role,
|
|
598
|
+
to: opts.peer1.name ?? opts.peer1.role,
|
|
599
|
+
msg,
|
|
600
|
+
});
|
|
601
|
+
return peer1Push.call(peer1.outgoing, msg);
|
|
447
602
|
};
|
|
448
603
|
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
604
|
+
const peer2Push = peer2.outgoing.push;
|
|
605
|
+
peer2.outgoing.push = (msg) => {
|
|
606
|
+
SyncMessagesLog.add({
|
|
607
|
+
from: opts.peer1.name ?? opts.peer1.role,
|
|
608
|
+
to: opts.peer2.name ?? opts.peer2.role,
|
|
609
|
+
msg,
|
|
610
|
+
});
|
|
611
|
+
return peer2Push.call(peer2.outgoing, msg);
|
|
453
612
|
};
|
|
454
613
|
|
|
455
|
-
syncServer.current.syncManager.addPeer(serverToNodePeer);
|
|
456
|
-
if (connected) {
|
|
457
|
-
node.syncManager.addPeer(nodeToServerPeer);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
614
|
return {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
messages,
|
|
464
|
-
addServerPeer: () => node.syncManager.addPeer(nodeToServerPeer),
|
|
615
|
+
peer1,
|
|
616
|
+
peer2,
|
|
465
617
|
};
|
|
466
618
|
}
|