cojson 0.8.3 → 0.8.11
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/CHANGELOG.md +13 -0
- package/dist/native/PeerKnownStates.js +63 -0
- package/dist/native/PeerKnownStates.js.map +1 -0
- package/dist/native/PeerState.js +2 -1
- package/dist/native/PeerState.js.map +1 -1
- package/dist/native/coValueState.js +74 -0
- package/dist/native/coValueState.js.map +1 -0
- package/dist/native/exports.js +39 -0
- package/dist/native/exports.js.map +1 -0
- package/dist/native/index.native.js +2 -39
- package/dist/native/index.native.js.map +1 -1
- package/dist/native/localNode.js +40 -51
- package/dist/native/localNode.js.map +1 -1
- package/dist/native/storage/index.js +1 -1
- package/dist/native/storage/index.js.map +1 -1
- package/dist/native/sync.js +85 -105
- package/dist/native/sync.js.map +1 -1
- package/dist/web/PeerKnownStates.js +63 -0
- package/dist/web/PeerKnownStates.js.map +1 -0
- package/dist/web/PeerState.js +2 -1
- package/dist/web/PeerState.js.map +1 -1
- package/dist/web/coValueState.js +74 -0
- package/dist/web/coValueState.js.map +1 -0
- package/dist/web/exports.js +39 -0
- package/dist/web/exports.js.map +1 -0
- package/dist/web/index.web.js +2 -39
- package/dist/web/index.web.js.map +1 -1
- package/dist/web/localNode.js +40 -51
- package/dist/web/localNode.js.map +1 -1
- package/dist/web/storage/index.js +1 -1
- package/dist/web/storage/index.js.map +1 -1
- package/dist/web/sync.js +85 -105
- package/dist/web/sync.js.map +1 -1
- package/package.json +5 -5
- package/src/PeerKnownStates.ts +108 -0
- package/src/PeerState.ts +4 -2
- package/src/coValueState.ts +107 -0
- package/src/exports.ts +149 -0
- package/src/index.native.ts +2 -152
- package/src/index.web.ts +2 -152
- package/src/jsonValue.ts +25 -0
- package/src/localNode.ts +52 -88
- package/src/storage/index.ts +1 -1
- package/src/sync.ts +90 -143
- package/src/tests/PeerKnownStates.test.ts +100 -0
- package/src/tests/PeerState.test.ts +0 -11
- package/src/tests/sync.test.ts +2 -2
- package/.turbo/turbo-build.log +0 -8
- package/.turbo/turbo-lint.log +0 -4
- package/.turbo/turbo-test.log +0 -1001
package/src/localNode.ts
CHANGED
|
@@ -28,10 +28,11 @@ import {
|
|
|
28
28
|
import { RawCoValue } from "./coValue.js";
|
|
29
29
|
import { expectGroup } from "./typeUtils/expectGroup.js";
|
|
30
30
|
import { err, ok, okAsync, Result, ResultAsync } from "neverthrow";
|
|
31
|
+
import { CoValueState } from "./coValueState.js";
|
|
31
32
|
|
|
32
33
|
/** A `LocalNode` represents a local view of a set of loaded `CoValue`s, from the perspective of a particular account (or primitive cryptographic agent).
|
|
33
34
|
|
|
34
|
-
A `LocalNode` can have peers that it syncs to, for example some form of local persistence, or a sync server, such as `
|
|
35
|
+
A `LocalNode` can have peers that it syncs to, for example some form of local persistence, or a sync server, such as `cloud.jazz.tools` (Jazz Cloud).
|
|
35
36
|
|
|
36
37
|
@example
|
|
37
38
|
You typically get hold of a `LocalNode` using `jazz-react`'s `useJazz()`:
|
|
@@ -130,10 +131,9 @@ export class LocalNode {
|
|
|
130
131
|
);
|
|
131
132
|
|
|
132
133
|
nodeWithAccount.account = controlledAccount;
|
|
133
|
-
nodeWithAccount.coValues[controlledAccount.id] =
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
};
|
|
134
|
+
nodeWithAccount.coValues[controlledAccount.id] = CoValueState.Available(
|
|
135
|
+
controlledAccount.core,
|
|
136
|
+
);
|
|
137
137
|
controlledAccount.core._cachedContent = undefined;
|
|
138
138
|
|
|
139
139
|
if (!controlledAccount.get("profile")) {
|
|
@@ -145,9 +145,9 @@ export class LocalNode {
|
|
|
145
145
|
for (const coValueEntry of Object.values(
|
|
146
146
|
nodeWithAccount.coValues,
|
|
147
147
|
)) {
|
|
148
|
-
if (coValueEntry.state === "
|
|
148
|
+
if (coValueEntry.state.type === "available") {
|
|
149
149
|
void nodeWithAccount.syncManager.syncCoValue(
|
|
150
|
-
coValueEntry.coValue,
|
|
150
|
+
coValueEntry.state.coValue,
|
|
151
151
|
);
|
|
152
152
|
}
|
|
153
153
|
}
|
|
@@ -214,10 +214,9 @@ export class LocalNode {
|
|
|
214
214
|
node.syncManager.local = node;
|
|
215
215
|
|
|
216
216
|
controlledAccount.core.node = node;
|
|
217
|
-
node.coValues[accountID] =
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
};
|
|
217
|
+
node.coValues[accountID] = CoValueState.Available(
|
|
218
|
+
controlledAccount.core,
|
|
219
|
+
);
|
|
221
220
|
controlledAccount.core._cachedContent = undefined;
|
|
222
221
|
|
|
223
222
|
const profileID = account.get("profile");
|
|
@@ -257,7 +256,7 @@ export class LocalNode {
|
|
|
257
256
|
}
|
|
258
257
|
|
|
259
258
|
const coValue = new CoValueCore(header, this);
|
|
260
|
-
this.coValues[coValue.id] =
|
|
259
|
+
this.coValues[coValue.id] = CoValueState.Available(coValue);
|
|
261
260
|
|
|
262
261
|
void this.syncManager.syncCoValue(coValue);
|
|
263
262
|
|
|
@@ -270,7 +269,6 @@ export class LocalNode {
|
|
|
270
269
|
options: {
|
|
271
270
|
dontLoadFrom?: PeerID;
|
|
272
271
|
dontWaitFor?: PeerID;
|
|
273
|
-
onProgress?: (progress: number) => void;
|
|
274
272
|
} = {},
|
|
275
273
|
): Promise<CoValueCore | "unavailable"> {
|
|
276
274
|
if (this.crashed) {
|
|
@@ -287,7 +285,7 @@ export class LocalNode {
|
|
|
287
285
|
.map((peer) => peer.id),
|
|
288
286
|
);
|
|
289
287
|
if (options.dontWaitFor) peersToWaitFor.delete(options.dontWaitFor);
|
|
290
|
-
entry =
|
|
288
|
+
entry = CoValueState.Unknown(peersToWaitFor);
|
|
291
289
|
|
|
292
290
|
this.coValues[id] = entry;
|
|
293
291
|
|
|
@@ -302,10 +300,19 @@ export class LocalNode {
|
|
|
302
300
|
);
|
|
303
301
|
});
|
|
304
302
|
}
|
|
305
|
-
if (entry.state === "
|
|
306
|
-
return Promise.resolve(entry.coValue);
|
|
303
|
+
if (entry.state.type === "available") {
|
|
304
|
+
return Promise.resolve(entry.state.coValue);
|
|
307
305
|
}
|
|
308
|
-
|
|
306
|
+
|
|
307
|
+
await entry.state.ready;
|
|
308
|
+
|
|
309
|
+
const updatedEntry = this.coValues[id];
|
|
310
|
+
|
|
311
|
+
if (updatedEntry?.state.type === "available") {
|
|
312
|
+
return Promise.resolve(updatedEntry.state.coValue);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return "unavailable";
|
|
309
316
|
}
|
|
310
317
|
|
|
311
318
|
/**
|
|
@@ -315,11 +322,8 @@ export class LocalNode {
|
|
|
315
322
|
*
|
|
316
323
|
* @category 3. Low-level
|
|
317
324
|
*/
|
|
318
|
-
async load<T extends RawCoValue>(
|
|
319
|
-
id
|
|
320
|
-
onProgress?: (progress: number) => void,
|
|
321
|
-
): Promise<T | "unavailable"> {
|
|
322
|
-
const core = await this.loadCoValueCore(id, { onProgress });
|
|
325
|
+
async load<T extends RawCoValue>(id: CoID<T>): Promise<T | "unavailable"> {
|
|
326
|
+
const core = await this.loadCoValueCore(id);
|
|
323
327
|
|
|
324
328
|
if (core === "unavailable") {
|
|
325
329
|
return "unavailable";
|
|
@@ -333,8 +337,8 @@ export class LocalNode {
|
|
|
333
337
|
if (!entry) {
|
|
334
338
|
return undefined;
|
|
335
339
|
}
|
|
336
|
-
if (entry.state === "
|
|
337
|
-
return entry.coValue.getCurrentContent() as T;
|
|
340
|
+
if (entry.state.type === "available") {
|
|
341
|
+
return entry.state.coValue.getCurrentContent() as T;
|
|
338
342
|
}
|
|
339
343
|
return undefined;
|
|
340
344
|
}
|
|
@@ -465,14 +469,14 @@ export class LocalNode {
|
|
|
465
469
|
`${expectation ? expectation + ": " : ""}Unknown CoValue ${id}`,
|
|
466
470
|
);
|
|
467
471
|
}
|
|
468
|
-
if (entry.state === "
|
|
472
|
+
if (entry.state.type === "unknown") {
|
|
469
473
|
throw new Error(
|
|
470
474
|
`${
|
|
471
475
|
expectation ? expectation + ": " : ""
|
|
472
476
|
}CoValue ${id} not yet loaded`,
|
|
473
477
|
);
|
|
474
478
|
}
|
|
475
|
-
return entry.coValue;
|
|
479
|
+
return entry.state.coValue;
|
|
476
480
|
}
|
|
477
481
|
|
|
478
482
|
/** @internal */
|
|
@@ -546,7 +550,18 @@ export class LocalNode {
|
|
|
546
550
|
return ok(id);
|
|
547
551
|
}
|
|
548
552
|
|
|
549
|
-
|
|
553
|
+
let coValue: CoValueCore;
|
|
554
|
+
|
|
555
|
+
try {
|
|
556
|
+
coValue = this.expectCoValueLoaded(id, expectation);
|
|
557
|
+
} catch (e) {
|
|
558
|
+
return err({
|
|
559
|
+
type: "ErrorLoadingCoValueCore",
|
|
560
|
+
expectation,
|
|
561
|
+
id,
|
|
562
|
+
error: e,
|
|
563
|
+
} satisfies LoadCoValueCoreError);
|
|
564
|
+
}
|
|
550
565
|
|
|
551
566
|
if (
|
|
552
567
|
coValue.header.type !== "comap" ||
|
|
@@ -662,13 +677,16 @@ export class LocalNode {
|
|
|
662
677
|
const [coValueID, entry] =
|
|
663
678
|
coValuesToCopy[coValuesToCopy.length - 1]!;
|
|
664
679
|
|
|
665
|
-
if (entry.state === "
|
|
680
|
+
if (entry.state.type === "unknown") {
|
|
666
681
|
coValuesToCopy.pop();
|
|
667
682
|
continue;
|
|
668
683
|
} else {
|
|
669
|
-
const allDepsCopied = entry.coValue
|
|
684
|
+
const allDepsCopied = entry.state.coValue
|
|
670
685
|
.getDependedOnCoValues()
|
|
671
|
-
.every(
|
|
686
|
+
.every(
|
|
687
|
+
(dep) =>
|
|
688
|
+
newNode.coValues[dep]?.state.type === "available",
|
|
689
|
+
);
|
|
672
690
|
|
|
673
691
|
if (!allDepsCopied) {
|
|
674
692
|
// move to end of queue
|
|
@@ -677,15 +695,13 @@ export class LocalNode {
|
|
|
677
695
|
}
|
|
678
696
|
|
|
679
697
|
const newCoValue = new CoValueCore(
|
|
680
|
-
entry.coValue.header,
|
|
698
|
+
entry.state.coValue.header,
|
|
681
699
|
newNode,
|
|
682
|
-
new Map(entry.coValue.sessionLogs),
|
|
700
|
+
new Map(entry.state.coValue.sessionLogs),
|
|
683
701
|
);
|
|
684
702
|
|
|
685
|
-
newNode.coValues[coValueID as RawCoID] =
|
|
686
|
-
|
|
687
|
-
coValue: newCoValue,
|
|
688
|
-
};
|
|
703
|
+
newNode.coValues[coValueID as RawCoID] =
|
|
704
|
+
CoValueState.Available(newCoValue);
|
|
689
705
|
|
|
690
706
|
coValuesToCopy.pop();
|
|
691
707
|
}
|
|
@@ -711,30 +727,6 @@ export class LocalNode {
|
|
|
711
727
|
}
|
|
712
728
|
}
|
|
713
729
|
|
|
714
|
-
/** @internal */
|
|
715
|
-
type CoValueState =
|
|
716
|
-
| {
|
|
717
|
-
state: "loading";
|
|
718
|
-
done: Promise<CoValueCore | "unavailable">;
|
|
719
|
-
resolve: (coValue: CoValueCore | "unavailable") => void;
|
|
720
|
-
onProgress?: (progress: number) => void;
|
|
721
|
-
firstPeerState: {
|
|
722
|
-
[peerID: string]:
|
|
723
|
-
| {
|
|
724
|
-
type: "waiting";
|
|
725
|
-
done: Promise<void>;
|
|
726
|
-
resolve: () => void;
|
|
727
|
-
}
|
|
728
|
-
| { type: "available" }
|
|
729
|
-
| { type: "unavailable" };
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
| {
|
|
733
|
-
state: "loaded";
|
|
734
|
-
coValue: CoValueCore;
|
|
735
|
-
onProgress?: (progress: number) => void;
|
|
736
|
-
};
|
|
737
|
-
|
|
738
730
|
export type LoadCoValueCoreError = {
|
|
739
731
|
type: "ErrorLoadingCoValueCore";
|
|
740
732
|
error: unknown;
|
|
@@ -759,31 +751,3 @@ export type ResolveAccountAgentError =
|
|
|
759
751
|
| LoadCoValueCoreError
|
|
760
752
|
| AccountUnavailableFromAllPeersError
|
|
761
753
|
| UnexpectedlyNotAccountError;
|
|
762
|
-
|
|
763
|
-
/** @internal */
|
|
764
|
-
export function newLoadingState(
|
|
765
|
-
currentPeerIds: Set<PeerID>,
|
|
766
|
-
onProgress?: (progress: number) => void,
|
|
767
|
-
): CoValueState {
|
|
768
|
-
let resolve: (coValue: CoValueCore | "unavailable") => void;
|
|
769
|
-
|
|
770
|
-
const promise = new Promise<CoValueCore | "unavailable">((r) => {
|
|
771
|
-
resolve = r;
|
|
772
|
-
});
|
|
773
|
-
|
|
774
|
-
return {
|
|
775
|
-
state: "loading",
|
|
776
|
-
done: promise,
|
|
777
|
-
resolve: resolve!,
|
|
778
|
-
onProgress,
|
|
779
|
-
firstPeerState: Object.fromEntries(
|
|
780
|
-
[...currentPeerIds].map((id) => {
|
|
781
|
-
let resolve: () => void;
|
|
782
|
-
const done = new Promise<void>((r) => {
|
|
783
|
-
resolve = r;
|
|
784
|
-
});
|
|
785
|
-
return [id, { type: "waiting", done, resolve: resolve! }];
|
|
786
|
-
}),
|
|
787
|
-
),
|
|
788
|
-
};
|
|
789
|
-
}
|
package/src/storage/index.ts
CHANGED
|
@@ -79,7 +79,7 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
|
|
|
79
79
|
|
|
80
80
|
if (msg.action === "content") {
|
|
81
81
|
await this.handleNewContent(msg);
|
|
82
|
-
} else {
|
|
82
|
+
} else if (msg.action === 'load' || msg.action === 'known') {
|
|
83
83
|
await this.sendNewContent(msg.id, msg, undefined);
|
|
84
84
|
}
|
|
85
85
|
} catch (e) {
|
package/src/sync.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Signature } from "./crypto/crypto.js";
|
|
2
2
|
import { CoValueHeader, Transaction } from "./coValueCore.js";
|
|
3
3
|
import { CoValueCore } from "./coValueCore.js";
|
|
4
|
-
import { LocalNode
|
|
4
|
+
import { LocalNode } from "./localNode.js";
|
|
5
|
+
import { CoValueState } from "./coValueState.js";
|
|
5
6
|
import { RawCoID, SessionID } from "./ids.js";
|
|
6
7
|
import { PeerState } from "./PeerState.js";
|
|
7
8
|
import { CoValuePriority } from "./priority.js";
|
|
@@ -131,8 +132,9 @@ export class SyncManager {
|
|
|
131
132
|
(peer) => peer.id !== forPeer && peer.role === "server",
|
|
132
133
|
);
|
|
133
134
|
|
|
135
|
+
const coValueEntry = this.local.coValues[id];
|
|
136
|
+
|
|
134
137
|
for (const peer of eligiblePeers) {
|
|
135
|
-
// console.log("loading", id, "from", peer.id);
|
|
136
138
|
await peer.pushOutgoingMessage({
|
|
137
139
|
action: "load",
|
|
138
140
|
id: id,
|
|
@@ -140,44 +142,9 @@ export class SyncManager {
|
|
|
140
142
|
sessions: {},
|
|
141
143
|
});
|
|
142
144
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
continue;
|
|
145
|
+
if (coValueEntry?.state.type === "unknown") {
|
|
146
|
+
await coValueEntry.state.waitForPeer(peer.id);
|
|
146
147
|
}
|
|
147
|
-
const firstStateEntry = coValueEntry.firstPeerState[peer.id];
|
|
148
|
-
if (firstStateEntry?.type !== "waiting") {
|
|
149
|
-
throw new Error("Expected firstPeerState to be waiting " + id);
|
|
150
|
-
}
|
|
151
|
-
await new Promise<void>((resolve) => {
|
|
152
|
-
// const timeout = setTimeout(() => {
|
|
153
|
-
// if (this.local.coValues[id]?.state === "loading") {
|
|
154
|
-
// console.warn(
|
|
155
|
-
// "Timeout waiting for peer to load",
|
|
156
|
-
// id,
|
|
157
|
-
// "from",
|
|
158
|
-
// peer.id,
|
|
159
|
-
// "and it hasn't loaded from other peers yet"
|
|
160
|
-
// );
|
|
161
|
-
// }
|
|
162
|
-
// resolve();
|
|
163
|
-
// }, 1000);
|
|
164
|
-
firstStateEntry.done
|
|
165
|
-
.then(() => {
|
|
166
|
-
// clearTimeout(timeout);
|
|
167
|
-
resolve();
|
|
168
|
-
})
|
|
169
|
-
.catch((e) => {
|
|
170
|
-
// clearTimeout(timeout);
|
|
171
|
-
console.error(
|
|
172
|
-
"Error waiting for peer to load",
|
|
173
|
-
id,
|
|
174
|
-
"from",
|
|
175
|
-
peer.id,
|
|
176
|
-
e,
|
|
177
|
-
);
|
|
178
|
-
resolve();
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
148
|
}
|
|
182
149
|
}
|
|
183
150
|
|
|
@@ -213,7 +180,7 @@ export class SyncManager {
|
|
|
213
180
|
throw new Error("Expected coValue entry on subscribe");
|
|
214
181
|
}
|
|
215
182
|
|
|
216
|
-
if (entry.state === "
|
|
183
|
+
if (entry.state.type === "unknown") {
|
|
217
184
|
this.trySendToPeer(peer, {
|
|
218
185
|
action: "load",
|
|
219
186
|
id,
|
|
@@ -225,7 +192,7 @@ export class SyncManager {
|
|
|
225
192
|
return;
|
|
226
193
|
}
|
|
227
194
|
|
|
228
|
-
const coValue = entry.coValue;
|
|
195
|
+
const coValue = entry.state.coValue;
|
|
229
196
|
|
|
230
197
|
for (const id of coValue.getDependedOnCoValues()) {
|
|
231
198
|
await this.subscribeToIncludingDependencies(id, peer);
|
|
@@ -274,10 +241,7 @@ export class SyncManager {
|
|
|
274
241
|
}
|
|
275
242
|
}
|
|
276
243
|
|
|
277
|
-
async sendNewContentIncludingDependencies(
|
|
278
|
-
id: RawCoID,
|
|
279
|
-
peer: PeerState,
|
|
280
|
-
) {
|
|
244
|
+
async sendNewContentIncludingDependencies(id: RawCoID, peer: PeerState) {
|
|
281
245
|
const coValue = this.local.expectCoValueLoaded(id);
|
|
282
246
|
|
|
283
247
|
await Promise.all(
|
|
@@ -289,12 +253,12 @@ export class SyncManager {
|
|
|
289
253
|
);
|
|
290
254
|
|
|
291
255
|
const newContentPieces = coValue.newContentSince(
|
|
292
|
-
peer.optimisticKnownStates
|
|
256
|
+
peer.optimisticKnownStates.get(id),
|
|
293
257
|
);
|
|
294
258
|
|
|
295
259
|
if (newContentPieces) {
|
|
296
260
|
const optimisticKnownStateBefore =
|
|
297
|
-
peer.optimisticKnownStates
|
|
261
|
+
peer.optimisticKnownStates.get(id) || emptyKnownState(id);
|
|
298
262
|
|
|
299
263
|
const sendPieces = async () => {
|
|
300
264
|
let lastYield = performance.now();
|
|
@@ -321,14 +285,19 @@ export class SyncManager {
|
|
|
321
285
|
|
|
322
286
|
sendPieces().catch((e) => {
|
|
323
287
|
console.error("Error sending new content piece, retrying", e);
|
|
324
|
-
peer.optimisticKnownStates
|
|
288
|
+
peer.optimisticKnownStates.dispatch({
|
|
289
|
+
type: "SET",
|
|
290
|
+
id,
|
|
291
|
+
value: optimisticKnownStateBefore ?? emptyKnownState(id),
|
|
292
|
+
});
|
|
325
293
|
return this.sendNewContentIncludingDependencies(id, peer);
|
|
326
294
|
});
|
|
327
295
|
|
|
328
|
-
peer.optimisticKnownStates
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
296
|
+
peer.optimisticKnownStates.dispatch({
|
|
297
|
+
type: "COMBINE_WITH",
|
|
298
|
+
id,
|
|
299
|
+
value: coValue.knownState(),
|
|
300
|
+
});
|
|
332
301
|
}
|
|
333
302
|
}
|
|
334
303
|
|
|
@@ -344,11 +313,10 @@ export class SyncManager {
|
|
|
344
313
|
// console.log("subscribing to after peer added", id, peer.id)
|
|
345
314
|
await this.subscribeToIncludingDependencies(id, peerState);
|
|
346
315
|
|
|
347
|
-
peerState.optimisticKnownStates
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
};
|
|
316
|
+
peerState.optimisticKnownStates.dispatch({
|
|
317
|
+
type: "SET_AS_EMPTY",
|
|
318
|
+
id,
|
|
319
|
+
});
|
|
352
320
|
}
|
|
353
321
|
};
|
|
354
322
|
void initialSync();
|
|
@@ -412,7 +380,11 @@ export class SyncManager {
|
|
|
412
380
|
}
|
|
413
381
|
|
|
414
382
|
async handleLoad(msg: LoadMessage, peer: PeerState) {
|
|
415
|
-
peer.optimisticKnownStates
|
|
383
|
+
peer.optimisticKnownStates.dispatch({
|
|
384
|
+
type: "SET",
|
|
385
|
+
id: msg.id,
|
|
386
|
+
value: knownStateIn(msg),
|
|
387
|
+
});
|
|
416
388
|
let entry = this.local.coValues[msg.id];
|
|
417
389
|
|
|
418
390
|
if (!entry) {
|
|
@@ -425,7 +397,7 @@ export class SyncManager {
|
|
|
425
397
|
);
|
|
426
398
|
if (eligiblePeers.length === 0) {
|
|
427
399
|
if (msg.header || Object.keys(msg.sessions).length > 0) {
|
|
428
|
-
this.local.coValues[msg.id] =
|
|
400
|
+
this.local.coValues[msg.id] = CoValueState.Unknown(
|
|
429
401
|
new Set([peer.id]),
|
|
430
402
|
);
|
|
431
403
|
this.trySendToPeer(peer, {
|
|
@@ -452,17 +424,21 @@ export class SyncManager {
|
|
|
452
424
|
entry = this.local.coValues[msg.id]!;
|
|
453
425
|
}
|
|
454
426
|
|
|
455
|
-
if (entry.state === "
|
|
427
|
+
if (entry.state.type === "unknown") {
|
|
456
428
|
// console.debug(
|
|
457
429
|
// "Waiting for loaded",
|
|
458
430
|
// msg.id,
|
|
459
431
|
// "after message from",
|
|
460
432
|
// peer.id,
|
|
461
433
|
// );
|
|
462
|
-
const loaded = await entry.
|
|
463
|
-
|
|
434
|
+
const loaded = await entry.state.ready;
|
|
435
|
+
|
|
464
436
|
if (loaded === "unavailable") {
|
|
465
|
-
peer.optimisticKnownStates
|
|
437
|
+
peer.optimisticKnownStates.dispatch({
|
|
438
|
+
type: "SET",
|
|
439
|
+
id: msg.id,
|
|
440
|
+
value: knownStateIn(msg),
|
|
441
|
+
});
|
|
466
442
|
peer.toldKnownState.add(msg.id);
|
|
467
443
|
|
|
468
444
|
this.trySendToPeer(peer, {
|
|
@@ -485,10 +461,11 @@ export class SyncManager {
|
|
|
485
461
|
async handleKnownState(msg: KnownStateMessage, peer: PeerState) {
|
|
486
462
|
let entry = this.local.coValues[msg.id];
|
|
487
463
|
|
|
488
|
-
peer.optimisticKnownStates
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
464
|
+
peer.optimisticKnownStates.dispatch({
|
|
465
|
+
type: "COMBINE_WITH",
|
|
466
|
+
id: msg.id,
|
|
467
|
+
value: knownStateIn(msg),
|
|
468
|
+
});
|
|
492
469
|
|
|
493
470
|
if (!entry) {
|
|
494
471
|
if (msg.asDependencyOf) {
|
|
@@ -514,31 +491,17 @@ export class SyncManager {
|
|
|
514
491
|
}
|
|
515
492
|
}
|
|
516
493
|
|
|
517
|
-
if (entry.state === "
|
|
518
|
-
const availableOnPeer = peer.optimisticKnownStates
|
|
519
|
-
|
|
520
|
-
if (
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
: { type: "unavailable" };
|
|
526
|
-
// console.log(
|
|
527
|
-
// "Marking",
|
|
528
|
-
// msg.id,
|
|
529
|
-
// "as",
|
|
530
|
-
// entry.firstPeerState[peer.id]?.type,
|
|
531
|
-
// "from",
|
|
532
|
-
// peer.id
|
|
533
|
-
// );
|
|
534
|
-
if (
|
|
535
|
-
Object.values(entry.firstPeerState).every(
|
|
536
|
-
(s) => s.type === "unavailable",
|
|
537
|
-
)
|
|
538
|
-
) {
|
|
539
|
-
entry.resolve("unavailable");
|
|
494
|
+
if (entry.state.type === "unknown") {
|
|
495
|
+
const availableOnPeer = peer.optimisticKnownStates.get(msg.id)?.header;
|
|
496
|
+
|
|
497
|
+
if (!availableOnPeer) {
|
|
498
|
+
entry.dispatch({
|
|
499
|
+
type: "not-found",
|
|
500
|
+
peerId: peer.id,
|
|
501
|
+
});
|
|
540
502
|
}
|
|
541
|
-
|
|
503
|
+
|
|
504
|
+
return;
|
|
542
505
|
}
|
|
543
506
|
|
|
544
507
|
await this.tellUntoldKnownStateIncludingDependencies(msg.id, peer);
|
|
@@ -546,7 +509,7 @@ export class SyncManager {
|
|
|
546
509
|
}
|
|
547
510
|
|
|
548
511
|
async handleNewContent(msg: NewContentMessage, peer: PeerState) {
|
|
549
|
-
|
|
512
|
+
const entry = this.local.coValues[msg.id];
|
|
550
513
|
|
|
551
514
|
if (!entry) {
|
|
552
515
|
console.error(
|
|
@@ -555,46 +518,31 @@ export class SyncManager {
|
|
|
555
518
|
return;
|
|
556
519
|
}
|
|
557
520
|
|
|
558
|
-
let
|
|
559
|
-
|
|
560
|
-
const peerOptimisticKnownState = peer.optimisticKnownStates[msg.id];
|
|
561
|
-
|
|
562
|
-
if (!peerOptimisticKnownState) {
|
|
563
|
-
console.error(
|
|
564
|
-
"Expected optimisticKnownState to be set for coValue we receive new content for",
|
|
565
|
-
);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
521
|
+
let coValue: CoValueCore;
|
|
568
522
|
|
|
569
|
-
if (entry.state === "
|
|
523
|
+
if (entry.state.type === "unknown") {
|
|
570
524
|
if (!msg.header) {
|
|
571
525
|
console.error("Expected header to be sent in first message");
|
|
572
526
|
return;
|
|
573
527
|
}
|
|
574
528
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
peerOptimisticKnownState.header = true;
|
|
582
|
-
|
|
583
|
-
const coValue = new CoValueCore(msg.header, this.local);
|
|
529
|
+
peer.optimisticKnownStates.dispatch({
|
|
530
|
+
type: "UPDATE_HEADER",
|
|
531
|
+
id: msg.id,
|
|
532
|
+
header: true,
|
|
533
|
+
});
|
|
584
534
|
|
|
585
|
-
|
|
535
|
+
coValue = new CoValueCore(msg.header, this.local);
|
|
586
536
|
|
|
587
|
-
entry
|
|
588
|
-
|
|
589
|
-
coValue
|
|
590
|
-
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
|
|
537
|
+
entry.dispatch({
|
|
538
|
+
type: "found",
|
|
539
|
+
coValue,
|
|
540
|
+
peerId: peer.id,
|
|
541
|
+
});
|
|
542
|
+
} else {
|
|
543
|
+
coValue = entry.state.coValue;
|
|
594
544
|
}
|
|
595
545
|
|
|
596
|
-
const coValue = entry.coValue;
|
|
597
|
-
|
|
598
546
|
let invalidStateAssumed = false;
|
|
599
547
|
|
|
600
548
|
for (const [sessionID, newContentForSession] of Object.entries(
|
|
@@ -648,15 +596,13 @@ export class SyncManager {
|
|
|
648
596
|
);
|
|
649
597
|
}
|
|
650
598
|
|
|
651
|
-
const theirTotalnTxs = Object.values(
|
|
652
|
-
|
|
653
|
-
).reduce((sum, nTxs) => sum + nTxs, 0);
|
|
654
|
-
const ourTotalnTxs = [...coValue.sessionLogs.values()].reduce(
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
);
|
|
658
|
-
|
|
659
|
-
entry.onProgress?.(ourTotalnTxs / theirTotalnTxs);
|
|
599
|
+
// const theirTotalnTxs = Object.values(
|
|
600
|
+
// peer.optimisticKnownStates[msg.id]?.sessions || {},
|
|
601
|
+
// ).reduce((sum, nTxs) => sum + nTxs, 0);
|
|
602
|
+
// const ourTotalnTxs = [...coValue.sessionLogs.values()].reduce(
|
|
603
|
+
// (sum, session) => sum + session.transactions.length,
|
|
604
|
+
// 0,
|
|
605
|
+
// );
|
|
660
606
|
|
|
661
607
|
if (result.isErr()) {
|
|
662
608
|
console.error(
|
|
@@ -673,15 +619,14 @@ export class SyncManager {
|
|
|
673
619
|
continue;
|
|
674
620
|
}
|
|
675
621
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
622
|
+
peer.optimisticKnownStates.dispatch({
|
|
623
|
+
type: "UPDATE_SESSION_COUNTER",
|
|
624
|
+
id: msg.id,
|
|
625
|
+
sessionId: sessionID,
|
|
626
|
+
value:
|
|
627
|
+
newContentForSession.after +
|
|
679
628
|
newContentForSession.newTransactions.length,
|
|
680
|
-
);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if (resolveAfterDone) {
|
|
684
|
-
resolveAfterDone(coValue);
|
|
629
|
+
});
|
|
685
630
|
}
|
|
686
631
|
|
|
687
632
|
await this.syncCoValue(coValue);
|
|
@@ -698,7 +643,11 @@ export class SyncManager {
|
|
|
698
643
|
}
|
|
699
644
|
|
|
700
645
|
async handleCorrection(msg: KnownStateMessage, peer: PeerState) {
|
|
701
|
-
peer.optimisticKnownStates
|
|
646
|
+
peer.optimisticKnownStates.dispatch({
|
|
647
|
+
type: "SET",
|
|
648
|
+
id: msg.id,
|
|
649
|
+
value: knownStateIn(msg),
|
|
650
|
+
});
|
|
702
651
|
|
|
703
652
|
return this.sendNewContentIncludingDependencies(msg.id, peer);
|
|
704
653
|
}
|
|
@@ -740,9 +689,7 @@ export class SyncManager {
|
|
|
740
689
|
// });
|
|
741
690
|
// blockingSince = performance.now();
|
|
742
691
|
// }
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
if (optimisticKnownState) {
|
|
692
|
+
if (peer.optimisticKnownStates.has(coValue.id)) {
|
|
746
693
|
await this.tellUntoldKnownStateIncludingDependencies(
|
|
747
694
|
coValue.id,
|
|
748
695
|
peer,
|