@peerbit/shared-log 9.2.13 → 10.0.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.
Files changed (104) hide show
  1. package/dist/benchmark/get-samples.js +190 -64
  2. package/dist/benchmark/get-samples.js.map +1 -1
  3. package/dist/benchmark/index.js +16 -38
  4. package/dist/benchmark/index.js.map +1 -1
  5. package/dist/benchmark/memory/child.js.map +1 -1
  6. package/dist/benchmark/partial-sync.d.ts +3 -0
  7. package/dist/benchmark/partial-sync.d.ts.map +1 -0
  8. package/dist/benchmark/partial-sync.js +121 -0
  9. package/dist/benchmark/partial-sync.js.map +1 -0
  10. package/dist/benchmark/replication-prune.js.map +1 -1
  11. package/dist/benchmark/replication.js.map +1 -1
  12. package/dist/benchmark/to-rebalance.d.ts +2 -0
  13. package/dist/benchmark/to-rebalance.d.ts.map +1 -0
  14. package/dist/benchmark/to-rebalance.js +117 -0
  15. package/dist/benchmark/to-rebalance.js.map +1 -0
  16. package/dist/benchmark/utils.d.ts +24 -0
  17. package/dist/benchmark/utils.d.ts.map +1 -0
  18. package/dist/benchmark/utils.js +47 -0
  19. package/dist/benchmark/utils.js.map +1 -0
  20. package/dist/src/debounce.d.ts +2 -2
  21. package/dist/src/debounce.d.ts.map +1 -1
  22. package/dist/src/debounce.js +17 -47
  23. package/dist/src/debounce.js.map +1 -1
  24. package/dist/src/exchange-heads.d.ts +1 -13
  25. package/dist/src/exchange-heads.d.ts.map +1 -1
  26. package/dist/src/exchange-heads.js +0 -32
  27. package/dist/src/exchange-heads.js.map +1 -1
  28. package/dist/src/index.d.ts +119 -60
  29. package/dist/src/index.d.ts.map +1 -1
  30. package/dist/src/index.js +1116 -762
  31. package/dist/src/index.js.map +1 -1
  32. package/dist/src/integers.d.ts +22 -0
  33. package/dist/src/integers.d.ts.map +1 -0
  34. package/dist/src/integers.js +76 -0
  35. package/dist/src/integers.js.map +1 -0
  36. package/dist/src/pid.d.ts.map +1 -1
  37. package/dist/src/pid.js +22 -22
  38. package/dist/src/pid.js.map +1 -1
  39. package/dist/src/ranges.d.ts +168 -38
  40. package/dist/src/ranges.d.ts.map +1 -1
  41. package/dist/src/ranges.js +869 -272
  42. package/dist/src/ranges.js.map +1 -1
  43. package/dist/src/replication-domain-hash.d.ts +2 -3
  44. package/dist/src/replication-domain-hash.d.ts.map +1 -1
  45. package/dist/src/replication-domain-hash.js +40 -15
  46. package/dist/src/replication-domain-hash.js.map +1 -1
  47. package/dist/src/replication-domain-time.d.ts +5 -5
  48. package/dist/src/replication-domain-time.d.ts.map +1 -1
  49. package/dist/src/replication-domain-time.js +2 -0
  50. package/dist/src/replication-domain-time.js.map +1 -1
  51. package/dist/src/replication-domain.d.ts +17 -19
  52. package/dist/src/replication-domain.d.ts.map +1 -1
  53. package/dist/src/replication-domain.js +2 -6
  54. package/dist/src/replication-domain.js.map +1 -1
  55. package/dist/src/replication.d.ts +6 -6
  56. package/dist/src/replication.d.ts.map +1 -1
  57. package/dist/src/replication.js +4 -4
  58. package/dist/src/replication.js.map +1 -1
  59. package/dist/src/role.d.ts +3 -6
  60. package/dist/src/role.d.ts.map +1 -1
  61. package/dist/src/role.js +4 -5
  62. package/dist/src/role.js.map +1 -1
  63. package/dist/src/sync/index.d.ts +40 -0
  64. package/dist/src/sync/index.d.ts.map +1 -0
  65. package/dist/src/sync/index.js +2 -0
  66. package/dist/src/sync/index.js.map +1 -0
  67. package/dist/src/sync/rateless-iblt.d.ts +124 -0
  68. package/dist/src/sync/rateless-iblt.d.ts.map +1 -0
  69. package/dist/src/sync/rateless-iblt.js +495 -0
  70. package/dist/src/sync/rateless-iblt.js.map +1 -0
  71. package/dist/src/sync/simple.d.ts +69 -0
  72. package/dist/src/sync/simple.d.ts.map +1 -0
  73. package/dist/src/sync/simple.js +338 -0
  74. package/dist/src/sync/simple.js.map +1 -0
  75. package/dist/src/sync/wasm-init.browser.d.ts +1 -0
  76. package/dist/src/sync/wasm-init.browser.d.ts.map +1 -0
  77. package/dist/src/sync/wasm-init.browser.js +3 -0
  78. package/dist/src/sync/wasm-init.browser.js.map +1 -0
  79. package/dist/src/sync/wasm-init.d.ts +2 -0
  80. package/dist/src/sync/wasm-init.d.ts.map +1 -0
  81. package/dist/src/sync/wasm-init.js +13 -0
  82. package/dist/src/sync/wasm-init.js.map +1 -0
  83. package/dist/src/utils.d.ts +3 -3
  84. package/dist/src/utils.d.ts.map +1 -1
  85. package/dist/src/utils.js +2 -2
  86. package/dist/src/utils.js.map +1 -1
  87. package/package.json +10 -6
  88. package/src/debounce.ts +16 -51
  89. package/src/exchange-heads.ts +1 -23
  90. package/src/index.ts +1532 -1038
  91. package/src/integers.ts +102 -0
  92. package/src/pid.ts +23 -22
  93. package/src/ranges.ts +1204 -413
  94. package/src/replication-domain-hash.ts +43 -18
  95. package/src/replication-domain-time.ts +9 -9
  96. package/src/replication-domain.ts +21 -31
  97. package/src/replication.ts +10 -9
  98. package/src/role.ts +4 -6
  99. package/src/sync/index.ts +51 -0
  100. package/src/sync/rateless-iblt.ts +617 -0
  101. package/src/sync/simple.ts +403 -0
  102. package/src/sync/wasm-init.browser.ts +1 -0
  103. package/src/sync/wasm-init.ts +14 -0
  104. package/src/utils.ts +10 -4
@@ -0,0 +1,617 @@
1
+ import { field, variant, vec } from "@dao-xyz/borsh";
2
+ import { Cache } from "@peerbit/cache";
3
+ import { type PublicSignKey, randomBytes, toBase64 } from "@peerbit/crypto";
4
+ import { type Index } from "@peerbit/indexer-interface";
5
+ import type { Entry, Log } from "@peerbit/log";
6
+ import init, { DecoderWrapper, EncoderWrapper } from "@peerbit/riblt";
7
+ import type { RPC, RequestContext } from "@peerbit/rpc";
8
+ import { SilentDelivery } from "@peerbit/stream-interface";
9
+ import type { SyncableKey, Syncronizer } from ".";
10
+ import { type EntryWithRefs } from "../exchange-heads.js";
11
+ import { type NumberFromType, type Numbers } from "../integers.js";
12
+ import { TransportMessage } from "../message.js";
13
+ import {
14
+ type EntryReplicated,
15
+ type ReplicationRangeIndexable,
16
+ matchEntriesInRangeQuery,
17
+ } from "../ranges.js";
18
+ import { SimpleSyncronizer } from "./simple.js";
19
+ import "./wasm-init.js";
20
+
21
+ await init();
22
+
23
+ type NumberOrBigint = number | bigint;
24
+
25
+ const coerceBigInt = (value: NumberOrBigint): bigint =>
26
+ typeof value === "bigint" ? value : BigInt(value);
27
+
28
+ class SymbolSerialized implements SSymbol {
29
+ @field({ type: "u64" })
30
+ count: bigint;
31
+
32
+ @field({ type: "u64" })
33
+ hash: bigint;
34
+
35
+ @field({ type: "u64" })
36
+ symbol: bigint;
37
+
38
+ constructor(props: { count: bigint; hash: bigint; symbol: bigint }) {
39
+ this.count = props.count;
40
+ this.hash = props.hash;
41
+ this.symbol = props.symbol;
42
+ }
43
+ }
44
+
45
+ const getSyncIdString = (message: { syncId: Uint8Array }) => {
46
+ return toBase64(message.syncId);
47
+ };
48
+
49
+ @variant([3, 0])
50
+ export class StartSync extends TransportMessage {
51
+ @field({ type: Uint8Array })
52
+ syncId: Uint8Array;
53
+
54
+ @field({ type: "u64" })
55
+ start: bigint;
56
+
57
+ @field({ type: "u64" })
58
+ end: bigint;
59
+
60
+ @field({ type: vec(SymbolSerialized) })
61
+ symbols: SymbolSerialized[];
62
+
63
+ constructor(props: {
64
+ from: NumberOrBigint;
65
+ to: NumberOrBigint;
66
+ symbols: SymbolSerialized[];
67
+ }) {
68
+ super();
69
+ this.syncId = randomBytes(32);
70
+ this.start = coerceBigInt(props.from);
71
+ this.end = coerceBigInt(props.to);
72
+ this.symbols = props.symbols;
73
+ }
74
+ }
75
+
76
+ @variant([3, 1])
77
+ export class MoreSymbols extends TransportMessage {
78
+ @field({ type: Uint8Array })
79
+ syncId: Uint8Array;
80
+
81
+ @field({ type: "u64" })
82
+ seqNo: bigint;
83
+
84
+ @field({ type: vec(SymbolSerialized) })
85
+ symbols: SymbolSerialized[];
86
+
87
+ constructor(props: {
88
+ syncId: Uint8Array;
89
+ lastSeqNo: bigint;
90
+ symbols: SymbolSerialized[];
91
+ }) {
92
+ super();
93
+ this.syncId = props.syncId;
94
+ this.seqNo = props.lastSeqNo + 1n;
95
+ this.symbols = props.symbols;
96
+ }
97
+ }
98
+
99
+ @variant([3, 2])
100
+ export class RequestMoreSymbols extends TransportMessage {
101
+ @field({ type: Uint8Array })
102
+ syncId: Uint8Array;
103
+
104
+ @field({ type: "u64" })
105
+ lastSeqNo: bigint;
106
+
107
+ constructor(props: { syncId: Uint8Array; lastSeqNo: bigint }) {
108
+ super();
109
+ this.syncId = props.syncId;
110
+ this.lastSeqNo = props.lastSeqNo;
111
+ }
112
+ }
113
+
114
+ @variant([3, 3])
115
+ export class RequestAll extends TransportMessage {
116
+ @field({ type: Uint8Array })
117
+ syncId: Uint8Array;
118
+
119
+ constructor(props: { syncId: Uint8Array }) {
120
+ super();
121
+ this.syncId = props.syncId;
122
+ }
123
+ }
124
+
125
+ export interface SSymbol {
126
+ count: bigint;
127
+ hash: bigint;
128
+ symbol: bigint;
129
+ }
130
+
131
+ const buildEncoderOrDecoderFromRange = async <
132
+ T extends "encoder" | "decoder",
133
+ E = T extends "encoder" ? EncoderWrapper : DecoderWrapper,
134
+ D extends "u32" | "u64" = "u64",
135
+ >(
136
+ ranges: {
137
+ start1: NumberOrBigint;
138
+ end1: NumberOrBigint;
139
+ start2: NumberOrBigint;
140
+ end2: NumberOrBigint;
141
+ },
142
+ entryIndex: Index<EntryReplicated<D>>,
143
+ type: T,
144
+ ): Promise<E | false> => {
145
+ const encoder =
146
+ type === "encoder" ? new EncoderWrapper() : new DecoderWrapper();
147
+
148
+ /* const buildDecoderStart = +new Date(); */
149
+ let symbolCount = 0;
150
+
151
+ const entries = await entryIndex
152
+ .iterate(
153
+ {
154
+ query: matchEntriesInRangeQuery({
155
+ end1: ranges.end1,
156
+ start1: ranges.start1,
157
+ end2: ranges.end2,
158
+ start2: ranges.start2,
159
+ }),
160
+ },
161
+ {
162
+ shape: {
163
+ coordinates: true,
164
+ },
165
+ },
166
+ )
167
+ .all();
168
+
169
+ if (entries.length === 0) {
170
+ return false;
171
+ }
172
+
173
+ for (const entry of entries) {
174
+ symbolCount += entry.value.coordinates.length;
175
+
176
+ for (const coordinate of entry.value.coordinates) {
177
+ encoder.add_symbol(coerceBigInt(coordinate));
178
+ }
179
+ }
180
+
181
+ return encoder as E;
182
+ };
183
+
184
+ export class RatelessIBLTSynchronizer<
185
+ D extends "u32" | "u64",
186
+ N = NumberFromType<D>,
187
+ > implements Syncronizer<D>
188
+ {
189
+ simple: SimpleSyncronizer<D>;
190
+
191
+ startedOrCompletedSynchronizations: Cache<string>;
192
+ ingoingSyncProcesses: Map<
193
+ string,
194
+ {
195
+ decoder: DecoderWrapper;
196
+ timeout: ReturnType<typeof setTimeout>;
197
+ refresh: () => void;
198
+ process: (message: {
199
+ seqNo: bigint;
200
+ symbols: SSymbol[];
201
+ }) => Promise<boolean | undefined>;
202
+ free: () => void;
203
+ }
204
+ >;
205
+
206
+ outgoingSyncProcesses: Map<
207
+ string,
208
+ {
209
+ outgoing: Map<string, EntryReplicated<D>>;
210
+ encoder: EncoderWrapper;
211
+ timeout: ReturnType<typeof setTimeout>;
212
+ refresh: () => void;
213
+ next: (message: { lastSeqNo: bigint }) => SSymbol[];
214
+ free: () => void;
215
+ }
216
+ >;
217
+
218
+ constructor(
219
+ readonly properties: {
220
+ rpc: RPC<TransportMessage, TransportMessage>;
221
+ rangeIndex: Index<ReplicationRangeIndexable<D>, any>;
222
+ entryIndex: Index<EntryReplicated<D>, any>;
223
+ log: Log<any>;
224
+ coordinateToHash: Cache<string>;
225
+ numbers: Numbers<D>;
226
+ },
227
+ ) {
228
+ this.simple = new SimpleSyncronizer(properties);
229
+ this.outgoingSyncProcesses = new Map();
230
+ this.ingoingSyncProcesses = new Map();
231
+ this.startedOrCompletedSynchronizations = new Cache({ max: 1e4 });
232
+ }
233
+
234
+ async onMaybeMissingEntries(properties: {
235
+ entries: Map<string, EntryReplicated<D>>;
236
+ targets: string[];
237
+ }): Promise<void> {
238
+ // calculate the smallest range that covers all the entries
239
+ // calculate the largest gap and the smallest range will be the one that starts at the end of it
240
+
241
+ // assume sorted, and find the largest gap
242
+ let largestGap = 0n;
243
+ let largestGapIndex = 0;
244
+
245
+ let entriesToSyncNaively: Map<string, EntryReplicated<D>> = new Map();
246
+
247
+ let allCoordinatesToSyncWithIblt: bigint[] = [];
248
+ let minSyncIbltSize = 333; // TODO arg
249
+ let maxSyncWithSimpleMethod = 1e3;
250
+
251
+ for (const entry of properties.entries.values()) {
252
+ if (
253
+ entry.assignedToRangeBoundary ||
254
+ properties.entries.size < minSyncIbltSize
255
+ ) {
256
+ entriesToSyncNaively.set(entry.hash, entry);
257
+ } else {
258
+ for (const coordinate of entry.coordinates) {
259
+ allCoordinatesToSyncWithIblt.push(coerceBigInt(coordinate));
260
+ }
261
+ }
262
+ }
263
+
264
+ if (
265
+ allCoordinatesToSyncWithIblt.length === 0 ||
266
+ entriesToSyncNaively.size > maxSyncWithSimpleMethod
267
+ ) {
268
+ // add all coordinates to sync with iblt
269
+ allCoordinatesToSyncWithIblt = Array.from(
270
+ properties.entries.values(),
271
+ ).flatMap((entry) => entry.coordinates.map((y) => coerceBigInt(y)));
272
+ } else {
273
+ // TODO what happens if too many
274
+ await this.simple.onMaybeMissingEntries({
275
+ entries: entriesToSyncNaively,
276
+ targets: properties.targets,
277
+ });
278
+ }
279
+
280
+ if (allCoordinatesToSyncWithIblt.length === 0) {
281
+ return;
282
+ }
283
+
284
+ const sortedEntries = allCoordinatesToSyncWithIblt.sort((a, b) => {
285
+ if (a > b) {
286
+ return 1;
287
+ } else if (a < b) {
288
+ return -1;
289
+ } else {
290
+ return 0;
291
+ }
292
+ });
293
+
294
+ for (let i = 0; i < sortedEntries.length - 1; i++) {
295
+ const current = sortedEntries[i];
296
+ const next = sortedEntries[i + 1];
297
+ const gap =
298
+ next >= current
299
+ ? next - current
300
+ : coerceBigInt(this.properties.numbers.maxValue) - current + next;
301
+ if (gap > largestGap) {
302
+ largestGap = gap;
303
+ largestGapIndex = i;
304
+ }
305
+ }
306
+
307
+ const smallestRangeStartIndex =
308
+ (largestGapIndex + 1) % sortedEntries.length;
309
+ const smallestRangeEndIndex = largestGapIndex; /// === (smallRangeStartIndex + 1) % sortedEntries.length
310
+ let smallestRangeStart = sortedEntries[smallestRangeStartIndex];
311
+ let smallestRangeEnd = sortedEntries[smallestRangeEndIndex];
312
+ let start: bigint, end: bigint;
313
+ if (smallestRangeEnd === smallestRangeStart) {
314
+ start = smallestRangeEnd;
315
+ end = smallestRangeEnd + 1n;
316
+ if (end > this.properties.numbers.maxValue) {
317
+ end = 0n;
318
+ }
319
+ } else {
320
+ start = smallestRangeStart;
321
+ end = smallestRangeEnd;
322
+ }
323
+
324
+ const startSync = new StartSync({ from: start, to: end, symbols: [] });
325
+ const encoder = new EncoderWrapper();
326
+ for (const entry of sortedEntries) {
327
+ encoder.add_symbol(BigInt(entry));
328
+ }
329
+
330
+ let initialSymbols = Math.round(
331
+ Math.sqrt(allCoordinatesToSyncWithIblt.length),
332
+ ); // TODO choose better
333
+ for (let i = 0; i < initialSymbols; i++) {
334
+ startSync.symbols.push(
335
+ new SymbolSerialized(encoder.produce_next_coded_symbol()),
336
+ );
337
+ }
338
+
339
+ const clear = () => {
340
+ // encoder.free(); TODO?
341
+ clearTimeout(
342
+ this.outgoingSyncProcesses.get(getSyncIdString(startSync))?.timeout,
343
+ );
344
+ this.outgoingSyncProcesses.delete(getSyncIdString(startSync));
345
+ };
346
+ const createTimeout = () => {
347
+ return setTimeout(clear, 1e4); // TODO arg
348
+ };
349
+
350
+ let lastSeqNo = -1n;
351
+ let nextBatch = 1e4;
352
+ const obj = {
353
+ encoder,
354
+ timeout: createTimeout(),
355
+ refresh: () => {
356
+ let prevTimeout = obj.timeout;
357
+ if (prevTimeout) {
358
+ clearTimeout(prevTimeout);
359
+ }
360
+ obj.timeout = createTimeout();
361
+ },
362
+ next: (properties: { lastSeqNo: bigint }): SSymbol[] => {
363
+ if (properties.lastSeqNo <= lastSeqNo) {
364
+ return [];
365
+ }
366
+ lastSeqNo++;
367
+ obj.refresh(); // TODO use timestamp instead and collective pruning/refresh
368
+
369
+ let result: SSymbol[] = [];
370
+ for (let i = 0; i < nextBatch; i++) {
371
+ result.push(encoder.produce_next_coded_symbol());
372
+ }
373
+ return result;
374
+ },
375
+ free: clear,
376
+ outgoing: properties.entries,
377
+ };
378
+
379
+ this.outgoingSyncProcesses.set(getSyncIdString(startSync), obj);
380
+ this.simple.rpc.send(startSync, {
381
+ mode: new SilentDelivery({ to: properties.targets, redundancy: 1 }),
382
+ priority: 1,
383
+ });
384
+ }
385
+
386
+ async onMessage(
387
+ message: TransportMessage,
388
+ context: RequestContext,
389
+ ): Promise<boolean> {
390
+ if (message instanceof StartSync) {
391
+ const syncId = getSyncIdString(message);
392
+ if (this.ingoingSyncProcesses.has(syncId)) {
393
+ return true;
394
+ }
395
+
396
+ if (this.startedOrCompletedSynchronizations.has(syncId)) {
397
+ return true;
398
+ }
399
+
400
+ this.startedOrCompletedSynchronizations.add(syncId);
401
+
402
+ const wrapped = message.end < message.start;
403
+ const decoder = await buildEncoderOrDecoderFromRange(
404
+ {
405
+ start1: message.start,
406
+ end1: wrapped ? this.properties.numbers.maxValue : message.end,
407
+ start2: 0n,
408
+ end2: wrapped ? message.end : 0n,
409
+ },
410
+ this.properties.entryIndex,
411
+ "decoder",
412
+ );
413
+
414
+ if (!decoder) {
415
+ await this.simple.rpc.send(
416
+ new RequestAll({
417
+ syncId: message.syncId,
418
+ }),
419
+ {
420
+ mode: new SilentDelivery({ to: [context.from!], redundancy: 1 }),
421
+ priority: 1,
422
+ },
423
+ );
424
+ return true;
425
+ }
426
+
427
+ const createTimeout = () => {
428
+ return setTimeout(() => {
429
+ // decoder.free(); TODO?
430
+ this.ingoingSyncProcesses.delete(syncId);
431
+ }, 2e4); // TODO arg
432
+ };
433
+
434
+ let count = 0;
435
+ /* let t0 = +new Date(); */
436
+ let messageQueue: {
437
+ seqNo: bigint;
438
+ symbols: (SSymbol | SymbolSerialized)[];
439
+ }[] = [];
440
+ let lastSeqNo = -1n;
441
+ const obj = {
442
+ decoder,
443
+ timeout: createTimeout(),
444
+ refresh: () => {
445
+ let prevTimeout = obj.timeout;
446
+ if (prevTimeout) {
447
+ clearTimeout(prevTimeout);
448
+ }
449
+ obj.timeout = createTimeout();
450
+ },
451
+ process: async (newMessage: {
452
+ seqNo: bigint;
453
+ symbols: (SSymbol | SymbolSerialized)[];
454
+ }): Promise<boolean | undefined> => {
455
+ obj.refresh(); // TODO use timestamp instead and collective pruning/refresh
456
+
457
+ if (newMessage.seqNo <= lastSeqNo) {
458
+ return undefined;
459
+ }
460
+
461
+ messageQueue.push(newMessage);
462
+ messageQueue.sort((a, b) => Number(a.seqNo - b.seqNo));
463
+ if (messageQueue[0].seqNo !== lastSeqNo + 1n) {
464
+ return;
465
+ }
466
+ lastSeqNo++;
467
+
468
+ const message = messageQueue.shift();
469
+ if (!message) {
470
+ return;
471
+ }
472
+
473
+ for (const symbol of message.symbols) {
474
+ decoder.add_coded_symbol(symbol);
475
+ }
476
+ decoder.try_decode();
477
+ count += message.symbols.length;
478
+
479
+ if (decoder.decoded()) {
480
+ let allMissingSymbolsInRemote: bigint[] = [];
481
+ for (const missingSymbol of decoder.get_remote_symbols()) {
482
+ allMissingSymbolsInRemote.push(missingSymbol);
483
+ }
484
+
485
+ this.simple.queueSync(allMissingSymbolsInRemote, context.from!, {
486
+ skipCheck: true,
487
+ });
488
+ obj.free();
489
+ return true;
490
+ }
491
+ return false;
492
+ },
493
+ free: () => {
494
+ // decoder.free(); TODO?
495
+ clearTimeout(this.ingoingSyncProcesses.get(syncId)?.timeout);
496
+ this.ingoingSyncProcesses.delete(syncId);
497
+ },
498
+ };
499
+
500
+ this.ingoingSyncProcesses.set(syncId, obj);
501
+
502
+ if (await obj.process({ seqNo: 0n, symbols: message.symbols })) {
503
+ return true;
504
+ }
505
+
506
+ // not done, request more symbols
507
+ await this.simple.rpc.send(
508
+ new RequestMoreSymbols({
509
+ lastSeqNo: 0n,
510
+ syncId: message.syncId,
511
+ }),
512
+ {
513
+ mode: new SilentDelivery({ to: [context.from!], redundancy: 1 }),
514
+ priority: 1,
515
+ },
516
+ );
517
+
518
+ return true;
519
+ } else if (message instanceof MoreSymbols) {
520
+ const obj = this.ingoingSyncProcesses.get(getSyncIdString(message));
521
+ if (!obj) {
522
+ return true;
523
+ }
524
+ const outProcess = await obj.process(message);
525
+
526
+ if (outProcess === true) {
527
+ return true;
528
+ } else if (outProcess === undefined) {
529
+ return false; // we don't have enough information, or received information that is redundant
530
+ }
531
+
532
+ // we are not done
533
+
534
+ this.simple.rpc.send(
535
+ new RequestMoreSymbols({
536
+ lastSeqNo: message.seqNo,
537
+ syncId: message.syncId,
538
+ }),
539
+ {
540
+ mode: new SilentDelivery({ to: [context.from!], redundancy: 1 }),
541
+ priority: 1,
542
+ },
543
+ );
544
+
545
+ return true;
546
+ } else if (message instanceof RequestMoreSymbols) {
547
+ const obj = this.outgoingSyncProcesses.get(getSyncIdString(message));
548
+ if (!obj) {
549
+ return true;
550
+ }
551
+ await this.properties.rpc.send(
552
+ new MoreSymbols({
553
+ lastSeqNo: message.lastSeqNo,
554
+ syncId: message.syncId,
555
+ symbols: obj.next(message).map((x) => new SymbolSerialized(x)),
556
+ }),
557
+ {
558
+ mode: new SilentDelivery({ to: [context.from!], redundancy: 1 }),
559
+ priority: 1,
560
+ },
561
+ );
562
+ return true;
563
+ } else if (message instanceof RequestAll) {
564
+ const p = this.outgoingSyncProcesses.get(getSyncIdString(message));
565
+ if (!p) {
566
+ return true;
567
+ }
568
+ await this.simple.onMaybeMissingEntries({
569
+ entries: p.outgoing,
570
+ targets: [context.from!.hashcode()],
571
+ });
572
+ return true;
573
+ }
574
+ return this.simple.onMessage(message, context);
575
+ }
576
+
577
+ onReceivedEntries(properties: {
578
+ entries: EntryWithRefs<any>[];
579
+ from: PublicSignKey;
580
+ }): Promise<void> | void {
581
+ return this.simple.onReceivedEntries(properties);
582
+ }
583
+
584
+ onEntryAdded(entry: Entry<any>): void {
585
+ return this.simple.onEntryAdded(entry);
586
+ }
587
+
588
+ onEntryRemoved(hash: string) {
589
+ return this.simple.onEntryRemoved(hash);
590
+ }
591
+
592
+ onPeerDisconnected(key: PublicSignKey) {
593
+ return this.simple.onPeerDisconnected(key);
594
+ }
595
+
596
+ open(): Promise<void> | void {
597
+ return this.simple.open();
598
+ }
599
+
600
+ close(): Promise<void> | void {
601
+ for (const [, obj] of this.ingoingSyncProcesses) {
602
+ obj.free();
603
+ }
604
+ for (const [, obj] of this.outgoingSyncProcesses) {
605
+ obj.free();
606
+ }
607
+ return this.simple.close();
608
+ }
609
+
610
+ get syncInFlight(): Map<string, Map<SyncableKey, { timestamp: number }>> {
611
+ return this.simple.syncInFlight;
612
+ }
613
+
614
+ get pending(): number {
615
+ return this.simple.pending;
616
+ }
617
+ }