cojson 0.15.7 → 0.15.9
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/IncomingMessagesQueue.d.ts +27 -0
- package/dist/IncomingMessagesQueue.d.ts.map +1 -0
- package/dist/IncomingMessagesQueue.js +114 -0
- package/dist/IncomingMessagesQueue.js.map +1 -0
- package/dist/PeerState.d.ts +2 -10
- package/dist/PeerState.d.ts.map +1 -1
- package/dist/PeerState.js +9 -90
- package/dist/PeerState.js.map +1 -1
- package/dist/PriorityBasedMessageQueue.d.ts +2 -1
- package/dist/PriorityBasedMessageQueue.d.ts.map +1 -1
- package/dist/PriorityBasedMessageQueue.js +9 -6
- package/dist/PriorityBasedMessageQueue.js.map +1 -1
- package/dist/SyncStateManager.d.ts +1 -0
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +1 -1
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValue.d.ts +1 -1
- package/dist/coValueCore/coValueCore.d.ts +9 -17
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +75 -50
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/coValueCore/verifiedState.d.ts +10 -3
- package/dist/coValueCore/verifiedState.d.ts.map +1 -1
- package/dist/coValueCore/verifiedState.js +73 -14
- package/dist/coValueCore/verifiedState.js.map +1 -1
- package/dist/coValues/coMap.d.ts +3 -3
- package/dist/coValues/coStream.d.ts +2 -2
- package/dist/coValues/group.d.ts +1 -1
- package/dist/coValues/group.d.ts.map +1 -1
- package/dist/coValues/group.js +2 -4
- package/dist/coValues/group.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +23 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto/WasmCrypto.d.ts.map +1 -1
- package/dist/crypto/WasmCrypto.js +2 -1
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/exports.d.ts +18 -7
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +11 -8
- package/dist/exports.js.map +1 -1
- package/dist/localNode.d.ts +8 -2
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +19 -12
- package/dist/localNode.js.map +1 -1
- package/dist/storage/StoreQueue.d.ts +15 -0
- package/dist/storage/StoreQueue.d.ts.map +1 -0
- package/dist/storage/StoreQueue.js +35 -0
- package/dist/storage/StoreQueue.js.map +1 -0
- package/dist/storage/index.d.ts +6 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/knownState.d.ts +18 -0
- package/dist/storage/knownState.d.ts.map +1 -0
- package/dist/storage/knownState.js +63 -0
- package/dist/storage/knownState.js.map +1 -0
- package/dist/storage/sqlite/client.d.ts +37 -0
- package/dist/storage/sqlite/client.d.ts.map +1 -0
- package/dist/storage/sqlite/client.js +89 -0
- package/dist/storage/sqlite/client.js.map +1 -0
- package/dist/storage/sqlite/index.d.ts +5 -0
- package/dist/storage/sqlite/index.d.ts.map +1 -0
- package/dist/storage/sqlite/index.js +13 -0
- package/dist/storage/sqlite/index.js.map +1 -0
- package/dist/storage/sqlite/sqliteMigrations.d.ts +3 -0
- package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -0
- package/dist/storage/sqlite/sqliteMigrations.js +44 -0
- package/dist/storage/sqlite/sqliteMigrations.js.map +1 -0
- package/dist/storage/sqlite/types.d.ts +8 -0
- package/dist/storage/sqlite/types.d.ts.map +1 -0
- package/dist/storage/sqlite/types.js +2 -0
- package/dist/storage/sqlite/types.js.map +1 -0
- package/dist/storage/sqliteAsync/client.d.ts +37 -0
- package/dist/storage/sqliteAsync/client.d.ts.map +1 -0
- package/dist/storage/sqliteAsync/client.js +88 -0
- package/dist/storage/sqliteAsync/client.js.map +1 -0
- package/dist/storage/sqliteAsync/index.d.ts +6 -0
- package/dist/storage/sqliteAsync/index.d.ts.map +1 -0
- package/dist/storage/sqliteAsync/index.js +15 -0
- package/dist/storage/sqliteAsync/index.js.map +1 -0
- package/dist/storage/sqliteAsync/types.d.ts +9 -0
- package/dist/storage/sqliteAsync/types.d.ts.map +1 -0
- package/dist/storage/sqliteAsync/types.js +2 -0
- package/dist/storage/sqliteAsync/types.js.map +1 -0
- package/dist/storage/storageAsync.d.ts +22 -0
- package/dist/storage/storageAsync.d.ts.map +1 -0
- package/dist/storage/storageAsync.js +214 -0
- package/dist/storage/storageAsync.js.map +1 -0
- package/dist/storage/storageSync.d.ts +21 -0
- package/dist/storage/storageSync.d.ts.map +1 -0
- package/dist/storage/storageSync.js +206 -0
- package/dist/storage/storageSync.js.map +1 -0
- package/dist/storage/syncUtils.d.ts +13 -0
- package/dist/storage/syncUtils.d.ts.map +1 -0
- package/dist/storage/syncUtils.js +25 -0
- package/dist/storage/syncUtils.js.map +1 -0
- package/dist/storage/types.d.ts +82 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/streamUtils.d.ts +13 -9
- package/dist/streamUtils.d.ts.map +1 -1
- package/dist/streamUtils.js +46 -13
- package/dist/streamUtils.js.map +1 -1
- package/dist/sync.d.ts +22 -14
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +143 -125
- package/dist/sync.js.map +1 -1
- package/dist/tests/IncomingMessagesQueue.test.d.ts +2 -0
- package/dist/tests/IncomingMessagesQueue.test.d.ts.map +1 -0
- package/dist/tests/IncomingMessagesQueue.test.js +437 -0
- package/dist/tests/IncomingMessagesQueue.test.js.map +1 -0
- package/dist/tests/PeerState.test.js +6 -94
- package/dist/tests/PeerState.test.js.map +1 -1
- package/dist/tests/PriorityBasedMessageQueue.test.js +14 -14
- package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -1
- package/dist/tests/StoreQueue.test.d.ts +2 -0
- package/dist/tests/StoreQueue.test.d.ts.map +1 -0
- package/dist/tests/StoreQueue.test.js +208 -0
- package/dist/tests/StoreQueue.test.js.map +1 -0
- package/dist/tests/SyncStateManager.test.js +3 -1
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/account.test.js +9 -9
- package/dist/tests/account.test.js.map +1 -1
- package/dist/tests/coStream.test.js +1 -1
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/coValueCore.test.js +208 -1
- package/dist/tests/coValueCore.test.js.map +1 -1
- package/dist/tests/coValueCoreLoadingState.test.js +2 -2
- package/dist/tests/coValueCoreLoadingState.test.js.map +1 -1
- package/dist/tests/group.addMember.test.js.map +1 -1
- package/dist/tests/group.removeMember.test.js +1 -1
- package/dist/tests/group.removeMember.test.js.map +1 -1
- package/dist/tests/messagesTestUtils.js +1 -1
- package/dist/tests/messagesTestUtils.js.map +1 -1
- package/dist/tests/sync.auth.test.js +23 -15
- package/dist/tests/sync.auth.test.js.map +1 -1
- package/dist/tests/sync.invite.test.js +10 -16
- package/dist/tests/sync.invite.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +52 -50
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +173 -56
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +42 -32
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +162 -62
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.d.ts +2 -0
- package/dist/tests/sync.storageAsync.test.d.ts.map +1 -0
- package/dist/tests/sync.storageAsync.test.js +361 -0
- package/dist/tests/sync.storageAsync.test.js.map +1 -0
- package/dist/tests/sync.test.js +16 -21
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/sync.upload.test.js +28 -25
- package/dist/tests/sync.upload.test.js.map +1 -1
- package/dist/tests/testStorage.d.ts +12 -0
- package/dist/tests/testStorage.d.ts.map +1 -0
- package/dist/tests/testStorage.js +151 -0
- package/dist/tests/testStorage.js.map +1 -0
- package/dist/tests/testUtils.d.ts +20 -15
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +79 -45
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +2 -2
- package/src/IncomingMessagesQueue.ts +142 -0
- package/src/PeerState.ts +11 -110
- package/src/PriorityBasedMessageQueue.ts +13 -5
- package/src/SyncStateManager.ts +1 -1
- package/src/coValueCore/coValueCore.ts +100 -66
- package/src/coValueCore/verifiedState.ts +91 -21
- package/src/coValues/group.ts +2 -4
- package/src/config.ts +26 -0
- package/src/crypto/WasmCrypto.ts +3 -1
- package/src/exports.ts +20 -27
- package/src/localNode.ts +27 -12
- package/src/storage/StoreQueue.ts +56 -0
- package/src/storage/index.ts +5 -0
- package/src/storage/knownState.ts +88 -0
- package/src/storage/sqlite/client.ts +180 -0
- package/src/storage/sqlite/index.ts +19 -0
- package/src/storage/sqlite/sqliteMigrations.ts +44 -0
- package/src/storage/sqlite/types.ts +7 -0
- package/src/storage/sqliteAsync/client.ts +179 -0
- package/src/storage/sqliteAsync/index.ts +25 -0
- package/src/storage/sqliteAsync/types.ts +8 -0
- package/src/storage/storageAsync.ts +367 -0
- package/src/storage/storageSync.ts +343 -0
- package/src/storage/syncUtils.ts +50 -0
- package/src/storage/types.ts +162 -0
- package/src/streamUtils.ts +61 -19
- package/src/sync.ts +191 -160
- package/src/tests/IncomingMessagesQueue.test.ts +626 -0
- package/src/tests/PeerState.test.ts +6 -118
- package/src/tests/PriorityBasedMessageQueue.test.ts +18 -14
- package/src/tests/StoreQueue.test.ts +283 -0
- package/src/tests/SyncStateManager.test.ts +4 -1
- package/src/tests/account.test.ts +11 -12
- package/src/tests/coStream.test.ts +1 -3
- package/src/tests/coValueCore.test.ts +270 -1
- package/src/tests/coValueCoreLoadingState.test.ts +2 -2
- package/src/tests/group.addMember.test.ts +1 -0
- package/src/tests/group.removeMember.test.ts +2 -8
- package/src/tests/messagesTestUtils.ts +2 -2
- package/src/tests/sync.auth.test.ts +24 -14
- package/src/tests/sync.invite.test.ts +11 -17
- package/src/tests/sync.load.test.ts +53 -49
- package/src/tests/sync.mesh.test.ts +198 -56
- package/src/tests/sync.peerReconciliation.test.ts +44 -34
- package/src/tests/sync.storage.test.ts +231 -64
- package/src/tests/sync.storageAsync.test.ts +486 -0
- package/src/tests/sync.test.ts +17 -23
- package/src/tests/sync.upload.test.ts +29 -24
- package/src/tests/testStorage.ts +216 -0
- package/src/tests/testUtils.ts +89 -54
package/src/sync.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { Histogram, ValueType, metrics } from "@opentelemetry/api";
|
|
2
|
+
import { IncomingMessagesQueue } from "./IncomingMessagesQueue.js";
|
|
2
3
|
import { PeerState } from "./PeerState.js";
|
|
3
4
|
import { SyncStateManager } from "./SyncStateManager.js";
|
|
4
|
-
import {
|
|
5
|
-
AvailableCoValueCore,
|
|
6
|
-
CoValueCore,
|
|
7
|
-
} from "./coValueCore/coValueCore.js";
|
|
5
|
+
import { CoValueCore } from "./coValueCore/coValueCore.js";
|
|
8
6
|
import { getDependedOnCoValuesFromRawData } from "./coValueCore/utils.js";
|
|
9
7
|
import { CoValueHeader, Transaction } from "./coValueCore/verifiedState.js";
|
|
10
8
|
import { Signature } from "./crypto/crypto.js";
|
|
@@ -53,6 +51,9 @@ export type NewContentMessage = {
|
|
|
53
51
|
new: {
|
|
54
52
|
[sessionID: SessionID]: SessionNewContent;
|
|
55
53
|
};
|
|
54
|
+
expectContentUntil?: {
|
|
55
|
+
[sessionID: SessionID]: number;
|
|
56
|
+
};
|
|
56
57
|
};
|
|
57
58
|
|
|
58
59
|
export type SessionNewContent = {
|
|
@@ -69,23 +70,24 @@ export type PeerID = string;
|
|
|
69
70
|
|
|
70
71
|
export type DisconnectedError = "Disconnected";
|
|
71
72
|
|
|
72
|
-
export
|
|
73
|
+
export interface IncomingPeerChannel {
|
|
74
|
+
close: () => void;
|
|
75
|
+
onMessage: (callback: (msg: SyncMessage | DisconnectedError) => void) => void;
|
|
76
|
+
onClose: (callback: () => void) => void;
|
|
77
|
+
}
|
|
73
78
|
|
|
74
|
-
export
|
|
75
|
-
SyncMessage | DisconnectedError
|
|
76
|
-
>;
|
|
77
|
-
export type OutgoingSyncQueue = {
|
|
78
|
-
push: (msg: SyncMessage) => Promise<unknown>;
|
|
79
|
+
export interface OutgoingPeerChannel {
|
|
80
|
+
push: (msg: SyncMessage | DisconnectedError) => void;
|
|
79
81
|
close: () => void;
|
|
80
|
-
|
|
82
|
+
onClose: (callback: () => void) => void;
|
|
83
|
+
}
|
|
81
84
|
|
|
82
85
|
export interface Peer {
|
|
83
86
|
id: PeerID;
|
|
84
|
-
incoming:
|
|
85
|
-
outgoing:
|
|
86
|
-
role: "server" | "client"
|
|
87
|
+
incoming: IncomingPeerChannel;
|
|
88
|
+
outgoing: OutgoingPeerChannel;
|
|
89
|
+
role: "server" | "client";
|
|
87
90
|
priority?: number;
|
|
88
|
-
crashOnClose: boolean;
|
|
89
91
|
deletePeerStateOnClose?: boolean;
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -153,18 +155,10 @@ export class SyncManager {
|
|
|
153
155
|
return Object.values(this.peers);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
|
|
157
|
-
return this.
|
|
158
|
+
getServerPeers(excludePeerId?: PeerID): PeerState[] {
|
|
159
|
+
return this.getPeers().filter(
|
|
158
160
|
(peer) =>
|
|
159
|
-
peer.
|
|
160
|
-
peer.id !== excludePeerId &&
|
|
161
|
-
!peer.closed,
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
hasStoragePeers(): boolean {
|
|
166
|
-
return this.getPeers().some(
|
|
167
|
-
(peer) => peer.role === "storage" && !peer.closed,
|
|
161
|
+
peer.role === "server" && peer.id !== excludePeerId && !peer.closed,
|
|
168
162
|
);
|
|
169
163
|
}
|
|
170
164
|
|
|
@@ -199,7 +193,7 @@ export class SyncManager {
|
|
|
199
193
|
case "content":
|
|
200
194
|
return this.handleNewContent(msg, peer);
|
|
201
195
|
case "done":
|
|
202
|
-
return
|
|
196
|
+
return;
|
|
203
197
|
default:
|
|
204
198
|
throw new Error(
|
|
205
199
|
`Unknown message type ${(msg as { action: "string" }).action}`,
|
|
@@ -241,7 +235,7 @@ export class SyncManager {
|
|
|
241
235
|
} else if (!peer.toldKnownState.has(id)) {
|
|
242
236
|
this.trySendToPeer(peer, {
|
|
243
237
|
action: "known",
|
|
244
|
-
...coValue.
|
|
238
|
+
...coValue.knownStateWithStreaming(),
|
|
245
239
|
});
|
|
246
240
|
}
|
|
247
241
|
|
|
@@ -311,6 +305,19 @@ export class SyncManager {
|
|
|
311
305
|
}
|
|
312
306
|
}
|
|
313
307
|
|
|
308
|
+
messagesQueue = new IncomingMessagesQueue();
|
|
309
|
+
pushMessage(incoming: SyncMessage, peer: PeerState) {
|
|
310
|
+
this.messagesQueue.push(incoming, peer);
|
|
311
|
+
|
|
312
|
+
if (this.messagesQueue.processing) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
this.messagesQueue.processQueue((msg, peer) => {
|
|
317
|
+
this.handleSyncMessage(msg, peer);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
314
321
|
addPeer(peer: Peer) {
|
|
315
322
|
const prevPeer = this.peers[peer.id];
|
|
316
323
|
|
|
@@ -329,45 +336,27 @@ export class SyncManager {
|
|
|
329
336
|
},
|
|
330
337
|
);
|
|
331
338
|
|
|
332
|
-
if (peerState.
|
|
339
|
+
if (peerState.role === "server") {
|
|
333
340
|
void this.startPeerReconciliation(peerState);
|
|
334
341
|
}
|
|
335
342
|
|
|
336
|
-
peerState
|
|
337
|
-
|
|
338
|
-
this.handleSyncMessage(msg, peerState);
|
|
339
|
-
})
|
|
340
|
-
.then(() => {
|
|
341
|
-
if (peer.crashOnClose) {
|
|
342
|
-
logger.error("Unexepcted close from peer", {
|
|
343
|
-
peerId: peer.id,
|
|
344
|
-
peerRole: peer.role,
|
|
345
|
-
});
|
|
346
|
-
this.local.crashed = new Error("Unexpected close from peer");
|
|
347
|
-
throw new Error("Unexpected close from peer");
|
|
348
|
-
}
|
|
349
|
-
})
|
|
350
|
-
.catch((e) => {
|
|
351
|
-
logger.error("Error processing messages from peer", {
|
|
352
|
-
err: e,
|
|
353
|
-
peerId: peer.id,
|
|
354
|
-
peerRole: peer.role,
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
if (peer.crashOnClose) {
|
|
358
|
-
this.local.crashed = e;
|
|
359
|
-
throw new Error(e);
|
|
360
|
-
}
|
|
361
|
-
})
|
|
362
|
-
.finally(() => {
|
|
343
|
+
peerState.incoming.onMessage((msg) => {
|
|
344
|
+
if (msg === "Disconnected") {
|
|
363
345
|
peerState.gracefulShutdown();
|
|
364
|
-
|
|
365
|
-
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
366
348
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
349
|
+
this.pushMessage(msg, peerState);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
peerState.addCloseListener(() => {
|
|
353
|
+
unsubscribeFromKnownStatesUpdates();
|
|
354
|
+
this.peersCounter.add(-1, { role: peer.role });
|
|
355
|
+
|
|
356
|
+
if (peer.deletePeerStateOnClose && this.peers[peer.id] === peerState) {
|
|
357
|
+
delete this.peers[peer.id];
|
|
358
|
+
}
|
|
359
|
+
});
|
|
371
360
|
}
|
|
372
361
|
|
|
373
362
|
trySendToPeer(peer: PeerState, msg: SyncMessage) {
|
|
@@ -397,12 +386,16 @@ export class SyncManager {
|
|
|
397
386
|
return;
|
|
398
387
|
}
|
|
399
388
|
|
|
400
|
-
const
|
|
389
|
+
const peers = this.getServerPeers(peer.id);
|
|
390
|
+
|
|
391
|
+
coValue.load(peers);
|
|
392
|
+
|
|
393
|
+
const handleLoadResult = () => {
|
|
394
|
+
if (coValue.isAvailable()) {
|
|
395
|
+
this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
401
398
|
|
|
402
|
-
if (eligiblePeers.length === 0) {
|
|
403
|
-
// We don't have any eligible peers to load the coValue from
|
|
404
|
-
// so we send a known state back to the sender to let it know
|
|
405
|
-
// that the coValue is unavailable
|
|
406
399
|
peer.trackToldKnownState(msg.id);
|
|
407
400
|
this.trySendToPeer(peer, {
|
|
408
401
|
action: "known",
|
|
@@ -410,41 +403,15 @@ export class SyncManager {
|
|
|
410
403
|
header: false,
|
|
411
404
|
sessions: {},
|
|
412
405
|
});
|
|
406
|
+
};
|
|
413
407
|
|
|
414
|
-
|
|
408
|
+
if (peers.length > 0 || this.local.storage) {
|
|
409
|
+
coValue.waitForAvailableOrUnavailable().then(handleLoadResult);
|
|
410
|
+
} else {
|
|
411
|
+
handleLoadResult();
|
|
415
412
|
}
|
|
416
|
-
|
|
417
|
-
coValue.loadFromPeers(eligiblePeers).catch((e) => {
|
|
418
|
-
logger.error("Error loading coValue in handleLoad", { err: e });
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// We need to return from handleLoad immediately and wait for the CoValue to be loaded
|
|
422
|
-
// in a new task, otherwise we might block further incoming content messages that would
|
|
423
|
-
// resolve the CoValue as available. This can happen when we receive fresh
|
|
424
|
-
// content from a client, but we are a server with our own upstream server(s)
|
|
425
|
-
coValue
|
|
426
|
-
.waitForAvailableOrUnavailable()
|
|
427
|
-
.then((value) => {
|
|
428
|
-
if (!value.isAvailable()) {
|
|
429
|
-
peer.trackToldKnownState(msg.id);
|
|
430
|
-
this.trySendToPeer(peer, {
|
|
431
|
-
action: "known",
|
|
432
|
-
id: msg.id,
|
|
433
|
-
header: false,
|
|
434
|
-
sessions: {},
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
441
|
-
})
|
|
442
|
-
.catch((e) => {
|
|
443
|
-
logger.error("Error loading coValue in handleLoad loading state", {
|
|
444
|
-
err: e,
|
|
445
|
-
});
|
|
446
|
-
});
|
|
447
413
|
}
|
|
414
|
+
|
|
448
415
|
handleKnownState(msg: KnownStateMessage, peer: PeerState) {
|
|
449
416
|
const coValue = this.local.getCoValue(msg.id);
|
|
450
417
|
|
|
@@ -476,18 +443,28 @@ export class SyncManager {
|
|
|
476
443
|
}
|
|
477
444
|
}
|
|
478
445
|
|
|
479
|
-
handleNewContent(msg: NewContentMessage,
|
|
446
|
+
handleNewContent(msg: NewContentMessage, from: PeerState | "storage") {
|
|
480
447
|
const coValue = this.local.getCoValue(msg.id);
|
|
448
|
+
const peer = from === "storage" ? undefined : from;
|
|
481
449
|
|
|
482
|
-
if (!coValue.
|
|
450
|
+
if (!coValue.hasVerifiedContent()) {
|
|
483
451
|
if (!msg.header) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
452
|
+
if (peer) {
|
|
453
|
+
this.trySendToPeer(peer, {
|
|
454
|
+
action: "known",
|
|
455
|
+
isCorrection: true,
|
|
456
|
+
id: msg.id,
|
|
457
|
+
header: false,
|
|
458
|
+
sessions: {},
|
|
459
|
+
});
|
|
460
|
+
} else {
|
|
461
|
+
logger.error(
|
|
462
|
+
"Received new content with no header on a missing CoValue",
|
|
463
|
+
{
|
|
464
|
+
id: msg.id,
|
|
465
|
+
},
|
|
466
|
+
);
|
|
467
|
+
}
|
|
491
468
|
return;
|
|
492
469
|
}
|
|
493
470
|
|
|
@@ -504,28 +481,40 @@ export class SyncManager {
|
|
|
504
481
|
)) {
|
|
505
482
|
const dependencyCoValue = this.local.getCoValue(dependency);
|
|
506
483
|
|
|
507
|
-
if (!dependencyCoValue.
|
|
484
|
+
if (!dependencyCoValue.hasVerifiedContent()) {
|
|
508
485
|
coValue.markMissingDependency(dependency);
|
|
509
486
|
|
|
510
|
-
|
|
511
|
-
const peers = this.getServerAndStoragePeers();
|
|
512
|
-
|
|
513
|
-
// if the peer that sent the content is a client, we add it to the list of peers
|
|
514
|
-
// to also ask them for the dependency
|
|
515
|
-
if (peer.role === "client") {
|
|
516
|
-
peers.push(peer);
|
|
517
|
-
}
|
|
487
|
+
const peers = this.getServerPeers();
|
|
518
488
|
|
|
519
|
-
|
|
489
|
+
// if the peer that sent the content is a client, we add it to the list of peers
|
|
490
|
+
// to also ask them for the dependency
|
|
491
|
+
if (peer?.role === "client") {
|
|
492
|
+
peers.push(peer);
|
|
520
493
|
}
|
|
494
|
+
|
|
495
|
+
dependencyCoValue.load(peers);
|
|
496
|
+
} else if (!dependencyCoValue.isAvailable()) {
|
|
497
|
+
coValue.markMissingDependency(dependency);
|
|
521
498
|
}
|
|
522
499
|
}
|
|
523
500
|
|
|
524
|
-
peer
|
|
525
|
-
coValue.provideHeader(
|
|
501
|
+
peer?.updateHeader(msg.id, true);
|
|
502
|
+
coValue.provideHeader(
|
|
503
|
+
msg.header,
|
|
504
|
+
peer?.id ?? "storage",
|
|
505
|
+
msg.expectContentUntil,
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
if (msg.expectContentUntil) {
|
|
509
|
+
peer?.combineWith(msg.id, {
|
|
510
|
+
id: msg.id,
|
|
511
|
+
header: true,
|
|
512
|
+
sessions: msg.expectContentUntil,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
526
515
|
}
|
|
527
516
|
|
|
528
|
-
if (!coValue.
|
|
517
|
+
if (!coValue.hasVerifiedContent()) {
|
|
529
518
|
throw new Error(
|
|
530
519
|
"Unreachable: CoValue should always have a verified state at this point",
|
|
531
520
|
);
|
|
@@ -567,15 +556,15 @@ export class SyncManager {
|
|
|
567
556
|
// This covers the case where we are getting a new session on an already loaded coValue
|
|
568
557
|
// where we need to load the account to get their public key
|
|
569
558
|
if (!coValue.missingDependencies.has(accountId)) {
|
|
570
|
-
const peers = this.
|
|
559
|
+
const peers = this.getServerPeers();
|
|
571
560
|
|
|
572
|
-
if (peer
|
|
561
|
+
if (peer?.role === "client") {
|
|
573
562
|
// if the peer that sent the content is a client, we add it to the list of peers
|
|
574
563
|
// to also ask them for the dependency
|
|
575
564
|
peers.push(peer);
|
|
576
565
|
}
|
|
577
566
|
|
|
578
|
-
account.
|
|
567
|
+
account.load(peers);
|
|
579
568
|
}
|
|
580
569
|
|
|
581
570
|
// We need to wait for the account to be available before we can verify the transaction
|
|
@@ -598,7 +587,7 @@ export class SyncManager {
|
|
|
598
587
|
},
|
|
599
588
|
priority: msg.priority,
|
|
600
589
|
},
|
|
601
|
-
|
|
590
|
+
from,
|
|
602
591
|
);
|
|
603
592
|
});
|
|
604
593
|
continue;
|
|
@@ -610,23 +599,30 @@ export class SyncManager {
|
|
|
610
599
|
newTransactions,
|
|
611
600
|
undefined,
|
|
612
601
|
newContentForSession.lastSignature,
|
|
613
|
-
"immediate",
|
|
602
|
+
"immediate",
|
|
614
603
|
);
|
|
615
604
|
|
|
616
605
|
if (result.isErr()) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
606
|
+
if (peer) {
|
|
607
|
+
logger.error("Failed to add transactions", {
|
|
608
|
+
peerId: peer.id,
|
|
609
|
+
peerRole: peer.role,
|
|
610
|
+
id: msg.id,
|
|
611
|
+
err: result.error,
|
|
612
|
+
});
|
|
613
|
+
coValue.markErrored(peer.id, result.error);
|
|
614
|
+
} else {
|
|
615
|
+
logger.error("Failed to add transactions from storage", {
|
|
616
|
+
id: msg.id,
|
|
617
|
+
err: result.error,
|
|
618
|
+
});
|
|
619
|
+
}
|
|
624
620
|
continue;
|
|
625
621
|
}
|
|
626
622
|
|
|
627
|
-
this.recordTransactionsSize(newTransactions, peer
|
|
623
|
+
this.recordTransactionsSize(newTransactions, peer?.role ?? "storage");
|
|
628
624
|
|
|
629
|
-
peer
|
|
625
|
+
peer?.updateSessionCounter(
|
|
630
626
|
msg.id,
|
|
631
627
|
sessionID,
|
|
632
628
|
newContentForSession.after +
|
|
@@ -635,13 +631,22 @@ export class SyncManager {
|
|
|
635
631
|
}
|
|
636
632
|
|
|
637
633
|
if (invalidStateAssumed) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
634
|
+
if (peer) {
|
|
635
|
+
this.trySendToPeer(peer, {
|
|
636
|
+
action: "known",
|
|
637
|
+
isCorrection: true,
|
|
638
|
+
...coValue.knownState(),
|
|
639
|
+
});
|
|
640
|
+
peer.trackToldKnownState(msg.id);
|
|
641
|
+
} else {
|
|
642
|
+
logger.error(
|
|
643
|
+
"Invalid state assumed when handling new content from storage",
|
|
644
|
+
{
|
|
645
|
+
id: msg.id,
|
|
646
|
+
},
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
} else if (peer) {
|
|
645
650
|
/**
|
|
646
651
|
* We are sending a known state message to the peer to acknowledge the
|
|
647
652
|
* receipt of the new content.
|
|
@@ -656,18 +661,17 @@ export class SyncManager {
|
|
|
656
661
|
peer.trackToldKnownState(msg.id);
|
|
657
662
|
}
|
|
658
663
|
|
|
659
|
-
const sourcePeer = peer;
|
|
660
664
|
const syncedPeers = [];
|
|
661
665
|
|
|
666
|
+
if (from !== "storage") {
|
|
667
|
+
this.storeCoValue(coValue, [msg]);
|
|
668
|
+
}
|
|
669
|
+
|
|
662
670
|
for (const peer of this.peersInPriorityOrder()) {
|
|
663
671
|
/**
|
|
664
672
|
* We sync the content against the source peer if it is a client or server peers
|
|
665
673
|
* to upload any content that is available on the current node and not on the source peer.
|
|
666
|
-
*
|
|
667
|
-
* We don't need to do this with storage peers because we don't get updates from those peers,
|
|
668
|
-
* only load and store content.
|
|
669
674
|
*/
|
|
670
|
-
if (peer.id === sourcePeer.id && sourcePeer.role === "storage") continue;
|
|
671
675
|
if (peer.closed) continue;
|
|
672
676
|
if (coValue.isErroredInPeer(peer.id)) continue;
|
|
673
677
|
|
|
@@ -676,7 +680,7 @@ export class SyncManager {
|
|
|
676
680
|
this.sendNewContentIncludingDependencies(coValue.id, peer);
|
|
677
681
|
syncedPeers.push(peer);
|
|
678
682
|
} else if (
|
|
679
|
-
peer.
|
|
683
|
+
peer.role === "server" &&
|
|
680
684
|
!peer.loadRequestSent.has(coValue.id)
|
|
681
685
|
) {
|
|
682
686
|
const state = coValue.getStateForPeer(peer.id)?.type;
|
|
@@ -688,7 +692,7 @@ export class SyncManager {
|
|
|
688
692
|
// before sending the new content
|
|
689
693
|
this.trySendToPeer(peer, {
|
|
690
694
|
action: "load",
|
|
691
|
-
...coValue.
|
|
695
|
+
...coValue.knownStateWithStreaming(),
|
|
692
696
|
});
|
|
693
697
|
peer.trackLoadRequestSent(coValue.id);
|
|
694
698
|
syncedPeers.push(peer);
|
|
@@ -707,8 +711,6 @@ export class SyncManager {
|
|
|
707
711
|
return this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
708
712
|
}
|
|
709
713
|
|
|
710
|
-
handleUnsubscribe(_msg: DoneMessage) {}
|
|
711
|
-
|
|
712
714
|
requestedSyncs = new Set<RawCoID>();
|
|
713
715
|
requestCoValueSync(coValue: CoValueCore) {
|
|
714
716
|
if (this.requestedSyncs.has(coValue.id)) {
|
|
@@ -724,9 +726,42 @@ export class SyncManager {
|
|
|
724
726
|
this.requestedSyncs.add(coValue.id);
|
|
725
727
|
}
|
|
726
728
|
|
|
729
|
+
storeCoValue(coValue: CoValueCore, data: NewContentMessage[] | undefined) {
|
|
730
|
+
const storage = this.local.storage;
|
|
731
|
+
|
|
732
|
+
if (!storage || !data) return;
|
|
733
|
+
|
|
734
|
+
// Try to store the content as-is for performance
|
|
735
|
+
// In case that some transactions are missing, a correction will be requested, but it's an edge case
|
|
736
|
+
storage.store(data, (correction) => {
|
|
737
|
+
if (!coValue.hasVerifiedContent()) return;
|
|
738
|
+
|
|
739
|
+
const newContentPieces = coValue.verified.newContentSince(correction);
|
|
740
|
+
|
|
741
|
+
if (!newContentPieces) return;
|
|
742
|
+
|
|
743
|
+
storage.store(newContentPieces, (response) => {
|
|
744
|
+
logger.error(
|
|
745
|
+
"Correction requested by storage after sending a correction content",
|
|
746
|
+
{
|
|
747
|
+
response,
|
|
748
|
+
knownState: coValue.knownState(),
|
|
749
|
+
},
|
|
750
|
+
);
|
|
751
|
+
});
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
|
|
727
755
|
syncCoValue(coValue: CoValueCore) {
|
|
728
756
|
this.requestedSyncs.delete(coValue.id);
|
|
729
757
|
|
|
758
|
+
if (this.local.storage && coValue.hasVerifiedContent()) {
|
|
759
|
+
const knownState = this.local.storage.getKnownState(coValue.id);
|
|
760
|
+
const newContentPieces = coValue.verified.newContentSince(knownState);
|
|
761
|
+
|
|
762
|
+
this.storeCoValue(coValue, newContentPieces);
|
|
763
|
+
}
|
|
764
|
+
|
|
730
765
|
for (const peer of this.peersInPriorityOrder()) {
|
|
731
766
|
if (peer.closed) continue;
|
|
732
767
|
if (coValue.isErroredInPeer(peer.id)) continue;
|
|
@@ -791,21 +826,17 @@ export class SyncManager {
|
|
|
791
826
|
});
|
|
792
827
|
}
|
|
793
828
|
|
|
794
|
-
waitForStorageSync(id: RawCoID
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
return Promise.all(
|
|
798
|
-
peers
|
|
799
|
-
.filter((peer) => peer.role === "storage")
|
|
800
|
-
.map((peer) => this.waitForSyncWithPeer(peer.id, id, timeout)),
|
|
801
|
-
);
|
|
829
|
+
waitForStorageSync(id: RawCoID) {
|
|
830
|
+
return this.local.storage?.waitForSync(id, this.local.getCoValue(id));
|
|
802
831
|
}
|
|
803
832
|
|
|
804
833
|
waitForSync(id: RawCoID, timeout = 30_000) {
|
|
805
834
|
const peers = this.getPeers();
|
|
806
835
|
|
|
807
836
|
return Promise.all(
|
|
808
|
-
peers
|
|
837
|
+
peers
|
|
838
|
+
.map((peer) => this.waitForSyncWithPeer(peer.id, id, timeout))
|
|
839
|
+
.concat(this.waitForStorageSync(id)),
|
|
809
840
|
);
|
|
810
841
|
}
|
|
811
842
|
|