cojson 0.7.35-unique.2 → 0.8.0
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 +2 -7
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +321 -253
- package/CHANGELOG.md +10 -2
- package/dist/PeerState.js +66 -0
- package/dist/PeerState.js.map +1 -0
- package/dist/PriorityBasedMessageQueue.js +51 -0
- package/dist/PriorityBasedMessageQueue.js.map +1 -0
- package/dist/base64url.js.map +1 -1
- package/dist/coValue.js.map +1 -1
- package/dist/coValueCore.js +3 -6
- package/dist/coValueCore.js.map +1 -1
- package/dist/coValues/account.js +0 -1
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +14 -15
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/group.js.map +1 -1
- package/dist/coreToCoValue.js.map +1 -1
- package/dist/crypto/PureJSCrypto.js.map +1 -1
- package/dist/crypto/WasmCrypto.js.map +1 -1
- package/dist/crypto/crypto.js +3 -0
- package/dist/crypto/crypto.js.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/jsonStringify.js.map +1 -1
- package/dist/localNode.js +7 -7
- package/dist/localNode.js.map +1 -1
- package/dist/permissions.js.map +1 -1
- package/dist/priority.js +31 -0
- package/dist/priority.js.map +1 -0
- package/dist/storage/FileSystem.js.map +1 -1
- package/dist/storage/chunksAndKnownStates.js +2 -0
- package/dist/storage/chunksAndKnownStates.js.map +1 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/streamUtils.js.map +1 -1
- package/dist/sync.js +7 -18
- package/dist/sync.js.map +1 -1
- package/dist/tests/PeerState.test.js +80 -0
- package/dist/tests/PeerState.test.js.map +1 -0
- package/dist/tests/PriorityBasedMessageQueue.test.js +97 -0
- package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -0
- package/dist/tests/account.test.js +1 -2
- package/dist/tests/account.test.js.map +1 -1
- package/dist/tests/coMap.test.js.map +1 -1
- package/dist/tests/coStream.test.js +34 -1
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/permissions.test.js +41 -42
- package/dist/tests/permissions.test.js.map +1 -1
- package/dist/tests/priority.test.js +61 -0
- package/dist/tests/priority.test.js.map +1 -0
- package/dist/tests/sync.test.js +327 -17
- package/dist/tests/sync.test.js.map +1 -1
- package/dist/tests/testUtils.js +1 -2
- package/dist/tests/testUtils.js.map +1 -1
- package/dist/typeUtils/expectGroup.js.map +1 -1
- package/package.json +3 -3
- package/src/PeerState.ts +85 -0
- package/src/PriorityBasedMessageQueue.ts +77 -0
- package/src/coValueCore.ts +4 -9
- package/src/coValues/account.ts +0 -1
- package/src/coValues/coStream.ts +21 -18
- package/src/crypto/crypto.ts +5 -0
- package/src/index.ts +3 -3
- package/src/localNode.ts +6 -7
- package/src/priority.ts +39 -0
- package/src/storage/chunksAndKnownStates.ts +2 -0
- package/src/sync.ts +19 -34
- package/src/tests/PeerState.test.ts +92 -0
- package/src/tests/PriorityBasedMessageQueue.test.ts +111 -0
- package/src/tests/account.test.ts +1 -2
- package/src/tests/coStream.test.ts +58 -1
- package/src/tests/permissions.test.ts +41 -42
- package/src/tests/priority.test.ts +75 -0
- package/src/tests/sync.test.ts +488 -26
- package/src/tests/testUtils.ts +1 -2
package/src/priority.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type CoValueHeader } from "./coValueCore.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The priority of a `CoValue` determines how much priority is given
|
|
5
|
+
* to its content messages.
|
|
6
|
+
*
|
|
7
|
+
* The priority value is handled as weight in the weighed round robin algorithm
|
|
8
|
+
* used to determine the order in which messages are sent.
|
|
9
|
+
*
|
|
10
|
+
* Follows the HTTP urgency range and order:
|
|
11
|
+
* - https://www.rfc-editor.org/rfc/rfc9218.html#name-urgency
|
|
12
|
+
*/
|
|
13
|
+
export const CO_VALUE_PRIORITY = {
|
|
14
|
+
HIGH: 0,
|
|
15
|
+
MEDIUM: 3,
|
|
16
|
+
LOW: 6,
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
export type CoValuePriority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
|
20
|
+
|
|
21
|
+
export function getPriorityFromHeader(header: CoValueHeader | undefined | boolean): CoValuePriority {
|
|
22
|
+
if (typeof header === "boolean" || !header) {
|
|
23
|
+
return CO_VALUE_PRIORITY.MEDIUM;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (header.meta?.type === "account") {
|
|
27
|
+
return CO_VALUE_PRIORITY.HIGH;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (header.ruleset.type === "group") {
|
|
31
|
+
return CO_VALUE_PRIORITY.HIGH;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (header.type === "costream" && header.meta?.type === "binary") {
|
|
35
|
+
return CO_VALUE_PRIORITY.LOW;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return CO_VALUE_PRIORITY.MEDIUM;
|
|
39
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RawCoID, SessionID } from "../ids.js";
|
|
2
2
|
import { MAX_RECOMMENDED_TX_SIZE } from "../index.js";
|
|
3
|
+
import { getPriorityFromHeader } from "../priority.js";
|
|
3
4
|
import { CoValueKnownState, NewContentMessage } from "../sync.js";
|
|
4
5
|
import { CoValueChunk } from "./index.js";
|
|
5
6
|
|
|
@@ -15,6 +16,7 @@ export function contentSinceChunk(
|
|
|
15
16
|
action: "content",
|
|
16
17
|
header: known?.header ? undefined : chunk.header,
|
|
17
18
|
new: {},
|
|
19
|
+
priority: getPriorityFromHeader(chunk.header),
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
for (const [sessionID, sessionsEntry] of Object.entries(
|
package/src/sync.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { CoValueHeader, Transaction } from "./coValueCore.js";
|
|
|
3
3
|
import { CoValueCore } from "./coValueCore.js";
|
|
4
4
|
import { LocalNode, newLoadingState } from "./localNode.js";
|
|
5
5
|
import { RawCoID, SessionID } from "./ids.js";
|
|
6
|
+
import { PeerState } from "./PeerState.js";
|
|
7
|
+
import { CoValuePriority } from "./priority.js";
|
|
6
8
|
|
|
7
9
|
export type CoValueKnownState = {
|
|
8
10
|
id: RawCoID;
|
|
@@ -38,6 +40,7 @@ export type NewContentMessage = {
|
|
|
38
40
|
action: "content";
|
|
39
41
|
id: RawCoID;
|
|
40
42
|
header?: CoValueHeader;
|
|
43
|
+
priority: CoValuePriority;
|
|
41
44
|
new: {
|
|
42
45
|
[sessionID: SessionID]: SessionNewContent;
|
|
43
46
|
};
|
|
@@ -76,17 +79,6 @@ export interface Peer {
|
|
|
76
79
|
crashOnClose: boolean;
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
export interface PeerState {
|
|
80
|
-
id: PeerID;
|
|
81
|
-
optimisticKnownStates: { [id: RawCoID]: CoValueKnownState };
|
|
82
|
-
toldKnownState: Set<RawCoID>;
|
|
83
|
-
incoming: IncomingSyncStream;
|
|
84
|
-
outgoing: OutgoingSyncQueue;
|
|
85
|
-
role: "peer" | "server" | "client";
|
|
86
|
-
priority?: number;
|
|
87
|
-
crashOnClose: boolean;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
82
|
export function combinedKnownStates(
|
|
91
83
|
stateA: CoValueKnownState,
|
|
92
84
|
stateB: CoValueKnownState,
|
|
@@ -141,7 +133,7 @@ export class SyncManager {
|
|
|
141
133
|
|
|
142
134
|
for (const peer of eligiblePeers) {
|
|
143
135
|
// console.log("loading", id, "from", peer.id);
|
|
144
|
-
await peer.
|
|
136
|
+
await peer.pushOutgoingMessage({
|
|
145
137
|
action: "load",
|
|
146
138
|
id: id,
|
|
147
139
|
header: false,
|
|
@@ -227,7 +219,7 @@ export class SyncManager {
|
|
|
227
219
|
id,
|
|
228
220
|
header: false,
|
|
229
221
|
sessions: {},
|
|
230
|
-
}).catch((e) => {
|
|
222
|
+
}).catch((e: unknown) => {
|
|
231
223
|
console.error("Error sending load", e);
|
|
232
224
|
});
|
|
233
225
|
return;
|
|
@@ -244,7 +236,7 @@ export class SyncManager {
|
|
|
244
236
|
this.trySendToPeer(peer, {
|
|
245
237
|
action: "load",
|
|
246
238
|
...coValue.knownState(),
|
|
247
|
-
}).catch((e) => {
|
|
239
|
+
}).catch((e: unknown) => {
|
|
248
240
|
console.error("Error sending load", e);
|
|
249
241
|
});
|
|
250
242
|
}
|
|
@@ -274,7 +266,7 @@ export class SyncManager {
|
|
|
274
266
|
action: "known",
|
|
275
267
|
asDependencyOf,
|
|
276
268
|
...coValue.knownState(),
|
|
277
|
-
}).catch((e) => {
|
|
269
|
+
}).catch((e: unknown) => {
|
|
278
270
|
console.error("Error sending known state", e);
|
|
279
271
|
});
|
|
280
272
|
|
|
@@ -282,7 +274,10 @@ export class SyncManager {
|
|
|
282
274
|
}
|
|
283
275
|
}
|
|
284
276
|
|
|
285
|
-
async sendNewContentIncludingDependencies(
|
|
277
|
+
async sendNewContentIncludingDependencies(
|
|
278
|
+
id: RawCoID,
|
|
279
|
+
peer: PeerState,
|
|
280
|
+
) {
|
|
286
281
|
const coValue = this.local.expectCoValueLoaded(id);
|
|
287
282
|
|
|
288
283
|
await Promise.all(
|
|
@@ -310,9 +305,11 @@ export class SyncManager {
|
|
|
310
305
|
// } header: ${!!piece.header}`,
|
|
311
306
|
// // Object.values(piece.new).map((s) => s.newTransactions)
|
|
312
307
|
// );
|
|
313
|
-
|
|
308
|
+
|
|
309
|
+
this.trySendToPeer(peer, piece).catch((e: unknown) => {
|
|
314
310
|
console.error("Error sending content piece", e);
|
|
315
311
|
});
|
|
312
|
+
|
|
316
313
|
if (performance.now() - lastYield > 10) {
|
|
317
314
|
await new Promise<void>((resolve) => {
|
|
318
315
|
setTimeout(resolve, 0);
|
|
@@ -336,16 +333,7 @@ export class SyncManager {
|
|
|
336
333
|
}
|
|
337
334
|
|
|
338
335
|
addPeer(peer: Peer) {
|
|
339
|
-
const peerState
|
|
340
|
-
id: peer.id,
|
|
341
|
-
optimisticKnownStates: {},
|
|
342
|
-
incoming: peer.incoming,
|
|
343
|
-
outgoing: peer.outgoing,
|
|
344
|
-
toldKnownState: new Set(),
|
|
345
|
-
role: peer.role,
|
|
346
|
-
priority: peer.priority,
|
|
347
|
-
crashOnClose: peer.crashOnClose,
|
|
348
|
-
};
|
|
336
|
+
const peerState = new PeerState(peer);
|
|
349
337
|
this.peers[peer.id] = peerState;
|
|
350
338
|
|
|
351
339
|
if (peer.role === "server") {
|
|
@@ -420,7 +408,7 @@ export class SyncManager {
|
|
|
420
408
|
}
|
|
421
409
|
|
|
422
410
|
trySendToPeer(peer: PeerState, msg: SyncMessage) {
|
|
423
|
-
return peer.
|
|
411
|
+
return peer.pushOutgoingMessage(msg);
|
|
424
412
|
}
|
|
425
413
|
|
|
426
414
|
async handleLoad(msg: LoadMessage, peer: PeerState) {
|
|
@@ -679,7 +667,8 @@ export class SyncManager {
|
|
|
679
667
|
newTransactions.length + " new transactions",
|
|
680
668
|
"after: " + newContentForSession.after,
|
|
681
669
|
"our last known tx idx initially: " + ourKnownTxIdx,
|
|
682
|
-
"our last known tx idx now: " +
|
|
670
|
+
"our last known tx idx now: " +
|
|
671
|
+
coValue.sessionLogs.get(sessionID)?.transactions.length,
|
|
683
672
|
);
|
|
684
673
|
continue;
|
|
685
674
|
}
|
|
@@ -774,11 +763,7 @@ export class SyncManager {
|
|
|
774
763
|
|
|
775
764
|
gracefulShutdown() {
|
|
776
765
|
for (const peer of Object.values(this.peers)) {
|
|
777
|
-
|
|
778
|
-
peer.outgoing.close();
|
|
779
|
-
peer.incoming = (async function* () {
|
|
780
|
-
yield "Disconnected" as const;
|
|
781
|
-
})();
|
|
766
|
+
peer.gracefulShutdown();
|
|
782
767
|
}
|
|
783
768
|
}
|
|
784
769
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, test, expect, vi } from "vitest";
|
|
2
|
+
import { PeerState } from "../PeerState.js";
|
|
3
|
+
import { Peer, SyncMessage } from "../sync.js";
|
|
4
|
+
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
5
|
+
|
|
6
|
+
function setup() {
|
|
7
|
+
const mockPeer: Peer = {
|
|
8
|
+
id: "test-peer",
|
|
9
|
+
role: "peer",
|
|
10
|
+
priority: 1,
|
|
11
|
+
crashOnClose: false,
|
|
12
|
+
incoming: (async function* () {})(),
|
|
13
|
+
outgoing: {
|
|
14
|
+
push: vi.fn().mockResolvedValue(undefined),
|
|
15
|
+
close: vi.fn(),
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const peerState = new PeerState(mockPeer);
|
|
19
|
+
return { mockPeer, peerState };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe("PeerState", () => {
|
|
23
|
+
test("should initialize with correct properties", () => {
|
|
24
|
+
const { peerState } = setup();
|
|
25
|
+
expect(peerState.id).toBe("test-peer");
|
|
26
|
+
expect(peerState.role).toBe("peer");
|
|
27
|
+
expect(peerState.priority).toBe(1);
|
|
28
|
+
expect(peerState.crashOnClose).toBe(false);
|
|
29
|
+
expect(peerState.closed).toBe(false);
|
|
30
|
+
expect(peerState.optimisticKnownStates).toEqual({});
|
|
31
|
+
expect(peerState.toldKnownState).toEqual(new Set());
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("should push outgoing message to peer", async () => {
|
|
35
|
+
const { mockPeer, peerState } = setup();
|
|
36
|
+
const message: SyncMessage = { action: "load", id: "co_ztest-id", header: false, sessions: {} };
|
|
37
|
+
await peerState.pushOutgoingMessage(message);
|
|
38
|
+
expect(mockPeer.outgoing.push).toHaveBeenCalledWith(message);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("should return peer's incoming when not closed", () => {
|
|
42
|
+
const { mockPeer, peerState } = setup();
|
|
43
|
+
expect(peerState.incoming).toBe(mockPeer.incoming);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("should return Disconnected when closed", async () => {
|
|
47
|
+
const { peerState } = setup();
|
|
48
|
+
peerState.gracefulShutdown();
|
|
49
|
+
const incomingIterator = peerState.incoming[Symbol.asyncIterator]();
|
|
50
|
+
const { value, done } = await incomingIterator.next();
|
|
51
|
+
expect(value).toBe("Disconnected");
|
|
52
|
+
expect(done).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("should perform graceful shutdown", () => {
|
|
56
|
+
const { mockPeer, peerState } = setup();
|
|
57
|
+
const consoleSpy = vi.spyOn(console, "debug").mockImplementation(() => {});
|
|
58
|
+
peerState.gracefulShutdown();
|
|
59
|
+
expect(mockPeer.outgoing.close).toHaveBeenCalled();
|
|
60
|
+
expect(peerState.closed).toBe(true);
|
|
61
|
+
expect(consoleSpy).toHaveBeenCalledWith("Gracefully closing", "test-peer");
|
|
62
|
+
consoleSpy.mockRestore();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("should schedule outgoing messages based on their priority", async () => {
|
|
66
|
+
const { peerState } = setup();
|
|
67
|
+
|
|
68
|
+
const loadMessage: SyncMessage = { action: "load", id: "co_zhigh", header: false, sessions: {} };
|
|
69
|
+
const contentMessageHigh: SyncMessage = { action: "content", id: "co_zhigh", new: {}, priority: CO_VALUE_PRIORITY.HIGH };
|
|
70
|
+
const contentMessageMid: SyncMessage = { action: "content", id: "co_zmid", new: {}, priority: CO_VALUE_PRIORITY.MEDIUM };
|
|
71
|
+
const contentMessageLow: SyncMessage = { action: "content", id: "co_zlow", new: {}, priority: CO_VALUE_PRIORITY.LOW };
|
|
72
|
+
|
|
73
|
+
const promises = [
|
|
74
|
+
peerState.pushOutgoingMessage(contentMessageLow),
|
|
75
|
+
peerState.pushOutgoingMessage(contentMessageMid),
|
|
76
|
+
peerState.pushOutgoingMessage(contentMessageHigh),
|
|
77
|
+
peerState.pushOutgoingMessage(loadMessage),
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
await Promise.all(promises);
|
|
81
|
+
|
|
82
|
+
// The first message is pushed directly, the other three are queued because are waiting
|
|
83
|
+
// for the first push to be completed.
|
|
84
|
+
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(1, contentMessageLow);
|
|
85
|
+
|
|
86
|
+
// Load message are managed as high priority messages and having the same priority as the content message
|
|
87
|
+
// they follow the push order.
|
|
88
|
+
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(2, contentMessageHigh);
|
|
89
|
+
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(3, loadMessage);
|
|
90
|
+
expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(4, contentMessageMid);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { PriorityBasedMessageQueue } from "../PriorityBasedMessageQueue.js";
|
|
3
|
+
import { SyncMessage } from "../sync.js";
|
|
4
|
+
import { CO_VALUE_PRIORITY } from "../priority.js";
|
|
5
|
+
|
|
6
|
+
function setup() {
|
|
7
|
+
const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM);
|
|
8
|
+
return { queue };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe("PriorityBasedMessageQueue", () => {
|
|
12
|
+
test("should initialize with correct properties", () => {
|
|
13
|
+
const { queue } = setup();
|
|
14
|
+
expect(queue["defaultPriority"]).toBe(CO_VALUE_PRIORITY.MEDIUM);
|
|
15
|
+
expect(queue["queues"].length).toBe(8);
|
|
16
|
+
expect(queue["queues"].every((q) => q.length === 0)).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("should push message with default priority", async () => {
|
|
20
|
+
const { queue } = setup();
|
|
21
|
+
const message: SyncMessage = {
|
|
22
|
+
action: "load",
|
|
23
|
+
id: "co_ztest-id",
|
|
24
|
+
header: false,
|
|
25
|
+
sessions: {},
|
|
26
|
+
};
|
|
27
|
+
void queue.push(message);
|
|
28
|
+
const pulledEntry = queue.pull();
|
|
29
|
+
expect(pulledEntry?.msg).toEqual(message);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("should push message with specified priority", async () => {
|
|
33
|
+
const { queue } = setup();
|
|
34
|
+
const message: SyncMessage = {
|
|
35
|
+
action: "content",
|
|
36
|
+
id: "co_zhigh",
|
|
37
|
+
new: {},
|
|
38
|
+
priority: CO_VALUE_PRIORITY.HIGH,
|
|
39
|
+
};
|
|
40
|
+
void queue.push(message);
|
|
41
|
+
const pulledEntry = queue.pull();
|
|
42
|
+
expect(pulledEntry?.msg).toEqual(message);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("should pull messages in priority order", async () => {
|
|
46
|
+
const { queue } = setup();
|
|
47
|
+
const lowPriorityMsg: SyncMessage = {
|
|
48
|
+
action: "content",
|
|
49
|
+
id: "co_zlow",
|
|
50
|
+
new: {},
|
|
51
|
+
priority: CO_VALUE_PRIORITY.LOW,
|
|
52
|
+
};
|
|
53
|
+
const mediumPriorityMsg: SyncMessage = {
|
|
54
|
+
action: "content",
|
|
55
|
+
id: "co_zmedium",
|
|
56
|
+
new: {},
|
|
57
|
+
priority: CO_VALUE_PRIORITY.MEDIUM,
|
|
58
|
+
};
|
|
59
|
+
const highPriorityMsg: SyncMessage = {
|
|
60
|
+
action: "content",
|
|
61
|
+
id: "co_zhigh",
|
|
62
|
+
new: {},
|
|
63
|
+
priority: CO_VALUE_PRIORITY.HIGH,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
void queue.push(lowPriorityMsg);
|
|
67
|
+
void queue.push(mediumPriorityMsg);
|
|
68
|
+
void queue.push(highPriorityMsg);
|
|
69
|
+
|
|
70
|
+
expect(queue.pull()?.msg).toEqual(highPriorityMsg);
|
|
71
|
+
expect(queue.pull()?.msg).toEqual(mediumPriorityMsg);
|
|
72
|
+
expect(queue.pull()?.msg).toEqual(lowPriorityMsg);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("should return undefined when pulling from empty queue", () => {
|
|
76
|
+
const { queue } = setup();
|
|
77
|
+
expect(queue.pull()).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("should resolve promise when message is pulled", async () => {
|
|
81
|
+
const { queue } = setup();
|
|
82
|
+
const message: SyncMessage = {
|
|
83
|
+
action: "load",
|
|
84
|
+
id: "co_ztest-id",
|
|
85
|
+
header: false,
|
|
86
|
+
sessions: {},
|
|
87
|
+
};
|
|
88
|
+
const pushPromise = queue.push(message);
|
|
89
|
+
|
|
90
|
+
const pulledEntry = queue.pull();
|
|
91
|
+
pulledEntry?.resolve();
|
|
92
|
+
|
|
93
|
+
await expect(pushPromise).resolves.toBeUndefined();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("should reject promise when message is rejected", async () => {
|
|
97
|
+
const { queue } = setup();
|
|
98
|
+
const message: SyncMessage = {
|
|
99
|
+
action: "load",
|
|
100
|
+
id: "co_ztest-id",
|
|
101
|
+
header: false,
|
|
102
|
+
sessions: {},
|
|
103
|
+
};
|
|
104
|
+
const pushPromise = queue.push(message);
|
|
105
|
+
|
|
106
|
+
const pulledEntry = queue.pull();
|
|
107
|
+
pulledEntry?.reject(new Error("Test error"));
|
|
108
|
+
|
|
109
|
+
await expect(pushPromise).rejects.toThrow("Test error");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { expect, test } from "vitest";
|
|
2
|
-
import { newRandomSessionID } from "../coValueCore.js";
|
|
3
2
|
import { LocalNode } from "../localNode.js";
|
|
4
3
|
import { connectedPeers } from "../streamUtils.js";
|
|
5
4
|
import { WasmCrypto } from "../crypto/WasmCrypto.js";
|
|
@@ -65,7 +64,7 @@ test("Can create account with one node, and then load it on another", async () =
|
|
|
65
64
|
const node2 = await LocalNode.withLoadedAccount({
|
|
66
65
|
accountID,
|
|
67
66
|
accountSecret,
|
|
68
|
-
sessionID: newRandomSessionID(accountID),
|
|
67
|
+
sessionID: Crypto.newRandomSessionID(accountID),
|
|
69
68
|
peersToLoadFrom: [node1asPeer],
|
|
70
69
|
crypto: Crypto,
|
|
71
70
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
1
|
+
import { expect, test, describe } from "vitest";
|
|
2
2
|
import { expectStream } from "../coValue.js";
|
|
3
3
|
import { RawBinaryCoStream } from "../coValues/coStream.js";
|
|
4
4
|
import { MAX_RECOMMENDED_TX_SIZE, WasmCrypto } from "../index.js";
|
|
@@ -244,3 +244,60 @@ test("When adding large transactions (bigger than MAX_RECOMMENDED_TX_SIZE), we s
|
|
|
244
244
|
sessionEntry.lastSignature,
|
|
245
245
|
);
|
|
246
246
|
});
|
|
247
|
+
|
|
248
|
+
describe("isBinaryStreamEnded", () => {
|
|
249
|
+
function setup() {
|
|
250
|
+
const node = new LocalNode(
|
|
251
|
+
...randomAnonymousAccountAndSessionID(),
|
|
252
|
+
Crypto,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const coValue = node.createCoValue({
|
|
256
|
+
type: "costream",
|
|
257
|
+
ruleset: { type: "unsafeAllowAll" },
|
|
258
|
+
meta: { type: "binary" },
|
|
259
|
+
...Crypto.createdNowUnique(),
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const content = coValue.getCurrentContent();
|
|
263
|
+
|
|
264
|
+
if (
|
|
265
|
+
content.type !== "costream" ||
|
|
266
|
+
content.headerMeta?.type !== "binary" ||
|
|
267
|
+
!(content instanceof RawBinaryCoStream)
|
|
268
|
+
) {
|
|
269
|
+
throw new Error("Expected binary stream");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return content;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
test("returns true when the last item is end", () => {
|
|
276
|
+
const stream = setup();
|
|
277
|
+
|
|
278
|
+
stream.startBinaryStream(
|
|
279
|
+
{ mimeType: "text/plain", fileName: "test.txt" },
|
|
280
|
+
"trusting",
|
|
281
|
+
);
|
|
282
|
+
stream.endBinaryStream("trusting");
|
|
283
|
+
|
|
284
|
+
expect(stream.isBinaryStreamEnded()).toBe(true);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test("returns false if the stream isn't ended", () => {
|
|
288
|
+
const stream = setup();
|
|
289
|
+
|
|
290
|
+
stream.startBinaryStream(
|
|
291
|
+
{ mimeType: "text/plain", fileName: "test.txt" },
|
|
292
|
+
"trusting",
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
expect(stream.isBinaryStreamEnded()).toBe(false);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("returns false if the stream isn't started", () => {
|
|
299
|
+
const stream = setup();
|
|
300
|
+
|
|
301
|
+
expect(stream.isBinaryStreamEnded()).toBe(false);
|
|
302
|
+
});
|
|
303
|
+
});
|