@twin.org/synchronised-storage-service 0.0.1-next.5 → 0.0.1-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +194 -155
- package/dist/esm/index.mjs +194 -155
- package/dist/types/entities/syncSnapshotEntry.d.ts +4 -0
- package/dist/types/helpers/blobStorageHelper.d.ts +3 -3
- package/dist/types/helpers/changeSetHelper.d.ts +3 -3
- package/dist/types/helpers/localSyncStateHelper.d.ts +3 -3
- package/dist/types/helpers/remoteSyncStateHelper.d.ts +3 -3
- package/dist/types/models/ISyncSnapshot.d.ts +4 -0
- package/dist/types/models/ISynchronisedStorageServiceConstructorOptions.d.ts +2 -2
- package/docs/changelog.md +28 -0
- package/docs/reference/classes/SyncSnapshotEntry.md +8 -0
- package/docs/reference/interfaces/ISyncSnapshot.md +8 -0
- package/docs/reference/interfaces/ISynchronisedStorageServiceConstructorOptions.md +3 -3
- package/package.json +2 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -4,7 +4,6 @@ import { HttpStatusCode } from '@twin.org/web';
|
|
|
4
4
|
import { BlobStorageConnectorFactory } from '@twin.org/blob-storage-models';
|
|
5
5
|
import { EntityStorageConnectorFactory } from '@twin.org/entity-storage-models';
|
|
6
6
|
import { DocumentHelper, IdentityConnectorFactory } from '@twin.org/identity-models';
|
|
7
|
-
import { LoggingConnectorFactory } from '@twin.org/logging-models';
|
|
8
7
|
import { ProofTypes } from '@twin.org/standards-w3c-did';
|
|
9
8
|
import { SyncChangeOperation, SynchronisedStorageTopics, SyncNodeIdentityMode } from '@twin.org/synchronised-storage-models';
|
|
10
9
|
import { VaultEncryptionType, VaultConnectorFactory } from '@twin.org/vault-models';
|
|
@@ -45,6 +44,10 @@ let SyncSnapshotEntry = class SyncSnapshotEntry {
|
|
|
45
44
|
* The flag to determine if this is a consolidated snapshot.
|
|
46
45
|
*/
|
|
47
46
|
isConsolidated;
|
|
47
|
+
/**
|
|
48
|
+
* The epoch for the changeset.
|
|
49
|
+
*/
|
|
50
|
+
epoch;
|
|
48
51
|
/**
|
|
49
52
|
* The ids of the storage for the change sets in the snapshot, if this is not a local snapshot.
|
|
50
53
|
*/
|
|
@@ -82,6 +85,10 @@ __decorate([
|
|
|
82
85
|
property({ type: "boolean" }),
|
|
83
86
|
__metadata("design:type", Boolean)
|
|
84
87
|
], SyncSnapshotEntry.prototype, "isConsolidated", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
property({ type: "number" }),
|
|
90
|
+
__metadata("design:type", Number)
|
|
91
|
+
], SyncSnapshotEntry.prototype, "epoch", void 0);
|
|
85
92
|
__decorate([
|
|
86
93
|
property({ type: "array", itemType: "string", optional: true }),
|
|
87
94
|
__metadata("design:type", Array)
|
|
@@ -287,10 +294,10 @@ class BlobStorageHelper {
|
|
|
287
294
|
*/
|
|
288
295
|
CLASS_NAME = "BlobStorageHelper";
|
|
289
296
|
/**
|
|
290
|
-
* The logging
|
|
297
|
+
* The logging component to use for logging.
|
|
291
298
|
* @internal
|
|
292
299
|
*/
|
|
293
|
-
|
|
300
|
+
_loggingComponent;
|
|
294
301
|
/**
|
|
295
302
|
* The vault connector.
|
|
296
303
|
* @internal
|
|
@@ -313,14 +320,14 @@ class BlobStorageHelper {
|
|
|
313
320
|
_isTrustedNode;
|
|
314
321
|
/**
|
|
315
322
|
* Create a new instance of BlobStorageHelper.
|
|
316
|
-
* @param
|
|
323
|
+
* @param loggingComponent The logging connector to use for logging.
|
|
317
324
|
* @param vaultConnector The vault connector to use for for the encryption key.
|
|
318
325
|
* @param blobStorageConnector The blob storage component to use.
|
|
319
326
|
* @param blobStorageEncryptionKeyId The id of the vault key to use for encrypting/decrypting blobs.
|
|
320
327
|
* @param isTrustedNode Is this a trusted node.
|
|
321
328
|
*/
|
|
322
|
-
constructor(
|
|
323
|
-
this.
|
|
329
|
+
constructor(loggingComponent, vaultConnector, blobStorageConnector, blobStorageEncryptionKeyId, isTrustedNode) {
|
|
330
|
+
this._loggingComponent = loggingComponent;
|
|
324
331
|
this._vaultConnector = vaultConnector;
|
|
325
332
|
this._blobStorageConnector = blobStorageConnector;
|
|
326
333
|
this._blobStorageEncryptionKeyId = blobStorageEncryptionKeyId;
|
|
@@ -332,7 +339,7 @@ class BlobStorageHelper {
|
|
|
332
339
|
* @returns The blob.
|
|
333
340
|
*/
|
|
334
341
|
async loadBlob(blobId) {
|
|
335
|
-
await this.
|
|
342
|
+
await this._loggingComponent?.log({
|
|
336
343
|
level: "info",
|
|
337
344
|
source: this.CLASS_NAME,
|
|
338
345
|
message: "loadBlob",
|
|
@@ -355,7 +362,7 @@ class BlobStorageHelper {
|
|
|
355
362
|
compressedBlob = rsa.decrypt(encryptedBlob);
|
|
356
363
|
}
|
|
357
364
|
const decompressedBlob = await Compression.decompress(compressedBlob, CompressionType.Gzip);
|
|
358
|
-
await this.
|
|
365
|
+
await this._loggingComponent?.log({
|
|
359
366
|
level: "info",
|
|
360
367
|
source: this.CLASS_NAME,
|
|
361
368
|
message: "loadedBlob",
|
|
@@ -367,7 +374,7 @@ class BlobStorageHelper {
|
|
|
367
374
|
}
|
|
368
375
|
}
|
|
369
376
|
catch (error) {
|
|
370
|
-
await this.
|
|
377
|
+
await this._loggingComponent?.log({
|
|
371
378
|
level: "error",
|
|
372
379
|
source: this.CLASS_NAME,
|
|
373
380
|
message: "loadBlobFailed",
|
|
@@ -377,7 +384,7 @@ class BlobStorageHelper {
|
|
|
377
384
|
error: BaseError.fromError(error)
|
|
378
385
|
});
|
|
379
386
|
}
|
|
380
|
-
await this.
|
|
387
|
+
await this._loggingComponent?.log({
|
|
381
388
|
level: "info",
|
|
382
389
|
source: this.CLASS_NAME,
|
|
383
390
|
message: "loadBlobEmpty",
|
|
@@ -392,7 +399,7 @@ class BlobStorageHelper {
|
|
|
392
399
|
* @returns The id of the blob.
|
|
393
400
|
*/
|
|
394
401
|
async saveBlob(blob) {
|
|
395
|
-
await this.
|
|
402
|
+
await this._loggingComponent?.log({
|
|
396
403
|
level: "info",
|
|
397
404
|
source: this.CLASS_NAME,
|
|
398
405
|
message: "saveBlob"
|
|
@@ -404,7 +411,7 @@ class BlobStorageHelper {
|
|
|
404
411
|
const encryptedBlob = await this._vaultConnector.encrypt(this._blobStorageEncryptionKeyId, VaultEncryptionType.Rsa2048, compressedBlob);
|
|
405
412
|
try {
|
|
406
413
|
const blobId = await this._blobStorageConnector.set(encryptedBlob);
|
|
407
|
-
await this.
|
|
414
|
+
await this._loggingComponent?.log({
|
|
408
415
|
level: "info",
|
|
409
416
|
source: this.CLASS_NAME,
|
|
410
417
|
message: "savedBlob",
|
|
@@ -415,7 +422,7 @@ class BlobStorageHelper {
|
|
|
415
422
|
return blobId;
|
|
416
423
|
}
|
|
417
424
|
catch (error) {
|
|
418
|
-
await this.
|
|
425
|
+
await this._loggingComponent?.log({
|
|
419
426
|
level: "error",
|
|
420
427
|
source: this.CLASS_NAME,
|
|
421
428
|
message: "saveBlobFailed",
|
|
@@ -430,7 +437,7 @@ class BlobStorageHelper {
|
|
|
430
437
|
* @returns Nothing.
|
|
431
438
|
*/
|
|
432
439
|
async removeBlob(blobId) {
|
|
433
|
-
await this.
|
|
440
|
+
await this._loggingComponent?.log({
|
|
434
441
|
level: "info",
|
|
435
442
|
source: this.CLASS_NAME,
|
|
436
443
|
message: "removeBlob",
|
|
@@ -440,7 +447,7 @@ class BlobStorageHelper {
|
|
|
440
447
|
});
|
|
441
448
|
try {
|
|
442
449
|
await this._blobStorageConnector.remove(blobId);
|
|
443
|
-
await this.
|
|
450
|
+
await this._loggingComponent?.log({
|
|
444
451
|
level: "info",
|
|
445
452
|
source: this.CLASS_NAME,
|
|
446
453
|
message: "removedBlob",
|
|
@@ -450,7 +457,7 @@ class BlobStorageHelper {
|
|
|
450
457
|
});
|
|
451
458
|
}
|
|
452
459
|
catch (error) {
|
|
453
|
-
await this.
|
|
460
|
+
await this._loggingComponent?.log({
|
|
454
461
|
level: "error",
|
|
455
462
|
source: this.CLASS_NAME,
|
|
456
463
|
message: "removeBlobFailed",
|
|
@@ -460,7 +467,7 @@ class BlobStorageHelper {
|
|
|
460
467
|
error: BaseError.fromError(error)
|
|
461
468
|
});
|
|
462
469
|
}
|
|
463
|
-
await this.
|
|
470
|
+
await this._loggingComponent?.log({
|
|
464
471
|
level: "info",
|
|
465
472
|
source: this.CLASS_NAME,
|
|
466
473
|
message: "removeBlobEmpty",
|
|
@@ -482,10 +489,10 @@ class ChangeSetHelper {
|
|
|
482
489
|
*/
|
|
483
490
|
CLASS_NAME = "ChangeSetHelper";
|
|
484
491
|
/**
|
|
485
|
-
* The logging
|
|
492
|
+
* The logging component to use for logging.
|
|
486
493
|
* @internal
|
|
487
494
|
*/
|
|
488
|
-
|
|
495
|
+
_loggingComponent;
|
|
489
496
|
/**
|
|
490
497
|
* The event bus component.
|
|
491
498
|
* @internal
|
|
@@ -513,14 +520,14 @@ class ChangeSetHelper {
|
|
|
513
520
|
_nodeIdentity;
|
|
514
521
|
/**
|
|
515
522
|
* Create a new instance of ChangeSetHelper.
|
|
516
|
-
* @param
|
|
523
|
+
* @param loggingComponent The logging connector to use for logging.
|
|
517
524
|
* @param eventBusComponent The event bus component to use for events.
|
|
518
525
|
* @param identityConnector The identity connector to use for signing/verifying changesets.
|
|
519
526
|
* @param blobStorageHelper The blob storage component to use for remote sync states.
|
|
520
527
|
* @param decentralisedStorageMethodId The id of the identity method to use when signing/verifying changesets.
|
|
521
528
|
*/
|
|
522
|
-
constructor(
|
|
523
|
-
this.
|
|
529
|
+
constructor(loggingComponent, eventBusComponent, identityConnector, blobStorageHelper, decentralisedStorageMethodId) {
|
|
530
|
+
this._loggingComponent = loggingComponent;
|
|
524
531
|
this._eventBusComponent = eventBusComponent;
|
|
525
532
|
this._decentralisedStorageMethodId = decentralisedStorageMethodId;
|
|
526
533
|
this._blobStorageHelper = blobStorageHelper;
|
|
@@ -539,7 +546,7 @@ class ChangeSetHelper {
|
|
|
539
546
|
* @returns The changeset if it was verified.
|
|
540
547
|
*/
|
|
541
548
|
async getAndVerifyChangeset(changeSetStorageId) {
|
|
542
|
-
await this.
|
|
549
|
+
await this._loggingComponent?.log({
|
|
543
550
|
level: "info",
|
|
544
551
|
source: this.CLASS_NAME,
|
|
545
552
|
message: "getChangeSet",
|
|
@@ -555,7 +562,7 @@ class ChangeSetHelper {
|
|
|
555
562
|
}
|
|
556
563
|
}
|
|
557
564
|
catch (error) {
|
|
558
|
-
await this.
|
|
565
|
+
await this._loggingComponent?.log({
|
|
559
566
|
level: "warn",
|
|
560
567
|
source: this.CLASS_NAME,
|
|
561
568
|
message: "getChangeSetError",
|
|
@@ -565,7 +572,7 @@ class ChangeSetHelper {
|
|
|
565
572
|
error: BaseError.fromError(error)
|
|
566
573
|
});
|
|
567
574
|
}
|
|
568
|
-
await this.
|
|
575
|
+
await this._loggingComponent?.log({
|
|
569
576
|
level: "info",
|
|
570
577
|
source: this.CLASS_NAME,
|
|
571
578
|
message: "getChangeSetEmpty",
|
|
@@ -596,7 +603,7 @@ class ChangeSetHelper {
|
|
|
596
603
|
async applyChangeset(syncChangeset) {
|
|
597
604
|
if (Is.arrayValue(syncChangeset.changes)) {
|
|
598
605
|
for (const change of syncChangeset.changes) {
|
|
599
|
-
await this.
|
|
606
|
+
await this._loggingComponent?.log({
|
|
600
607
|
level: "info",
|
|
601
608
|
source: this.CLASS_NAME,
|
|
602
609
|
message: "changeSetApplyingChange",
|
|
@@ -642,7 +649,7 @@ class ChangeSetHelper {
|
|
|
642
649
|
* @returns The id of the change set.
|
|
643
650
|
*/
|
|
644
651
|
async storeChangeSet(syncChangeSet) {
|
|
645
|
-
await this.
|
|
652
|
+
await this._loggingComponent?.log({
|
|
646
653
|
level: "info",
|
|
647
654
|
source: this.CLASS_NAME,
|
|
648
655
|
message: "changeSetStoring",
|
|
@@ -659,7 +666,7 @@ class ChangeSetHelper {
|
|
|
659
666
|
*/
|
|
660
667
|
async verifyChangesetProof(syncChangeset) {
|
|
661
668
|
if (Is.empty(syncChangeset.proof)) {
|
|
662
|
-
await this.
|
|
669
|
+
await this._loggingComponent?.log({
|
|
663
670
|
level: "info",
|
|
664
671
|
source: this.CLASS_NAME,
|
|
665
672
|
message: "verifyChangeSetProofMissing",
|
|
@@ -672,7 +679,7 @@ class ChangeSetHelper {
|
|
|
672
679
|
// If the proof or verification method is missing, the proof is invalid
|
|
673
680
|
const verificationMethod = syncChangeset.proof?.verificationMethod;
|
|
674
681
|
if (!Is.stringValue(verificationMethod)) {
|
|
675
|
-
await this.
|
|
682
|
+
await this._loggingComponent?.log({
|
|
676
683
|
level: "error",
|
|
677
684
|
source: this.CLASS_NAME,
|
|
678
685
|
message: "verifyChangeSetProofMissing",
|
|
@@ -686,7 +693,7 @@ class ChangeSetHelper {
|
|
|
686
693
|
// otherwise you could sign a changeset for another node
|
|
687
694
|
const changeSetNodeIdentity = DocumentHelper.parseId(verificationMethod ?? "");
|
|
688
695
|
if (changeSetNodeIdentity.id !== syncChangeset.nodeIdentity) {
|
|
689
|
-
await this.
|
|
696
|
+
await this._loggingComponent?.log({
|
|
690
697
|
level: "error",
|
|
691
698
|
source: this.CLASS_NAME,
|
|
692
699
|
message: "verifyChangeSetProofNodeIdentityMismatch",
|
|
@@ -699,7 +706,7 @@ class ChangeSetHelper {
|
|
|
699
706
|
delete changeSetWithoutProof.proof;
|
|
700
707
|
const isValid = await this._identityConnector.verifyProof(changeSetWithoutProof, syncChangeset.proof);
|
|
701
708
|
if (!isValid) {
|
|
702
|
-
await this.
|
|
709
|
+
await this._loggingComponent?.log({
|
|
703
710
|
level: "error",
|
|
704
711
|
source: this.CLASS_NAME,
|
|
705
712
|
message: "verifyChangeSetProofInvalid",
|
|
@@ -709,7 +716,7 @@ class ChangeSetHelper {
|
|
|
709
716
|
});
|
|
710
717
|
}
|
|
711
718
|
else {
|
|
712
|
-
await this.
|
|
719
|
+
await this._loggingComponent?.log({
|
|
713
720
|
level: "error",
|
|
714
721
|
source: this.CLASS_NAME,
|
|
715
722
|
message: "verifyChangeSetProofValid",
|
|
@@ -730,7 +737,7 @@ class ChangeSetHelper {
|
|
|
730
737
|
const changeSetWithoutProof = ObjectHelper.clone(syncChangeset);
|
|
731
738
|
delete changeSetWithoutProof.proof;
|
|
732
739
|
const proof = await this._identityConnector.createProof(this._nodeIdentity, DocumentHelper.joinId(this._nodeIdentity, this._decentralisedStorageMethodId), ProofTypes.DataIntegrityProof, changeSetWithoutProof);
|
|
733
|
-
await this.
|
|
740
|
+
await this._loggingComponent?.log({
|
|
734
741
|
level: "info",
|
|
735
742
|
source: this.CLASS_NAME,
|
|
736
743
|
message: "createdChangeSetProof",
|
|
@@ -750,7 +757,7 @@ class ChangeSetHelper {
|
|
|
750
757
|
if (Is.stringValue(this._nodeIdentity)) {
|
|
751
758
|
const verified = await this.verifyChangesetProof(syncChangeSet);
|
|
752
759
|
if (verified) {
|
|
753
|
-
await this.
|
|
760
|
+
await this._loggingComponent?.log({
|
|
754
761
|
level: "info",
|
|
755
762
|
source: this.CLASS_NAME,
|
|
756
763
|
message: "copyChangeSet",
|
|
@@ -779,7 +786,7 @@ class ChangeSetHelper {
|
|
|
779
786
|
async reset(storageKey, resetMode) {
|
|
780
787
|
// If we are applying a consolidation we need to reset the local db
|
|
781
788
|
// but keep any entries from the local node, as they might have been updated
|
|
782
|
-
await this.
|
|
789
|
+
await this._loggingComponent?.log({
|
|
783
790
|
level: "info",
|
|
784
791
|
source: this.CLASS_NAME,
|
|
785
792
|
message: "storageReset",
|
|
@@ -811,10 +818,10 @@ class LocalSyncStateHelper {
|
|
|
811
818
|
*/
|
|
812
819
|
CLASS_NAME = "LocalSyncStateHelper";
|
|
813
820
|
/**
|
|
814
|
-
* The logging
|
|
821
|
+
* The logging component to use for logging.
|
|
815
822
|
* @internal
|
|
816
823
|
*/
|
|
817
|
-
|
|
824
|
+
_loggingComponent;
|
|
818
825
|
/**
|
|
819
826
|
* The storage connector for the sync snapshot entries.
|
|
820
827
|
* @internal
|
|
@@ -827,12 +834,12 @@ class LocalSyncStateHelper {
|
|
|
827
834
|
_changeSetHelper;
|
|
828
835
|
/**
|
|
829
836
|
* Create a new instance of LocalSyncStateHelper.
|
|
830
|
-
* @param
|
|
837
|
+
* @param loggingComponent The logging connector to use for logging.
|
|
831
838
|
* @param snapshotEntryEntityStorage The storage connector for the sync snapshot entries.
|
|
832
839
|
* @param changeSetHelper The change set helper to use for applying changesets.
|
|
833
840
|
*/
|
|
834
|
-
constructor(
|
|
835
|
-
this.
|
|
841
|
+
constructor(loggingComponent, snapshotEntryEntityStorage, changeSetHelper) {
|
|
842
|
+
this._loggingComponent = loggingComponent;
|
|
836
843
|
this._snapshotEntryEntityStorage = snapshotEntryEntityStorage;
|
|
837
844
|
this._changeSetHelper = changeSetHelper;
|
|
838
845
|
}
|
|
@@ -844,7 +851,7 @@ class LocalSyncStateHelper {
|
|
|
844
851
|
* @returns Nothing.
|
|
845
852
|
*/
|
|
846
853
|
async addLocalChange(storageKey, operation, id) {
|
|
847
|
-
await this.
|
|
854
|
+
await this._loggingComponent?.log({
|
|
848
855
|
level: "info",
|
|
849
856
|
source: this.CLASS_NAME,
|
|
850
857
|
message: "addLocalChange",
|
|
@@ -865,6 +872,9 @@ class LocalSyncStateHelper {
|
|
|
865
872
|
if (previousChangeIndex !== -1) {
|
|
866
873
|
localChangeSnapshot.changes.splice(previousChangeIndex, 1);
|
|
867
874
|
}
|
|
875
|
+
// If we already have changes from previous updates
|
|
876
|
+
// then make sure we update the dateModified, otherwise
|
|
877
|
+
// we assume this is the first change and setting modified is not necessary
|
|
868
878
|
if (localChangeSnapshot.changes.length > 0) {
|
|
869
879
|
localChangeSnapshot.dateModified = new Date(Date.now()).toISOString();
|
|
870
880
|
}
|
|
@@ -879,7 +889,7 @@ class LocalSyncStateHelper {
|
|
|
879
889
|
* @returns The local snapshot entry.
|
|
880
890
|
*/
|
|
881
891
|
async getSnapshots(storageKey, isLocal) {
|
|
882
|
-
await this.
|
|
892
|
+
await this._loggingComponent?.log({
|
|
883
893
|
level: "info",
|
|
884
894
|
source: this.CLASS_NAME,
|
|
885
895
|
message: "getSnapshots",
|
|
@@ -902,7 +912,7 @@ class LocalSyncStateHelper {
|
|
|
902
912
|
]
|
|
903
913
|
});
|
|
904
914
|
if (queryResult.entities.length > 0) {
|
|
905
|
-
await this.
|
|
915
|
+
await this._loggingComponent?.log({
|
|
906
916
|
level: "info",
|
|
907
917
|
source: this.CLASS_NAME,
|
|
908
918
|
message: "getSnapshotsExists",
|
|
@@ -912,7 +922,7 @@ class LocalSyncStateHelper {
|
|
|
912
922
|
});
|
|
913
923
|
return queryResult.entities;
|
|
914
924
|
}
|
|
915
|
-
await this.
|
|
925
|
+
await this._loggingComponent?.log({
|
|
916
926
|
level: "info",
|
|
917
927
|
source: this.CLASS_NAME,
|
|
918
928
|
message: "getSnapshotsDoesNotExist",
|
|
@@ -930,7 +940,8 @@ class LocalSyncStateHelper {
|
|
|
930
940
|
dateModified: now,
|
|
931
941
|
changeSetStorageIds: [],
|
|
932
942
|
isLocal,
|
|
933
|
-
isConsolidated: false
|
|
943
|
+
isConsolidated: false,
|
|
944
|
+
epoch: 0
|
|
934
945
|
}
|
|
935
946
|
];
|
|
936
947
|
}
|
|
@@ -940,7 +951,7 @@ class LocalSyncStateHelper {
|
|
|
940
951
|
* @returns Nothing.
|
|
941
952
|
*/
|
|
942
953
|
async setLocalChangeSnapshot(localChangeSnapshot) {
|
|
943
|
-
await this.
|
|
954
|
+
await this._loggingComponent?.log({
|
|
944
955
|
level: "info",
|
|
945
956
|
source: this.CLASS_NAME,
|
|
946
957
|
message: "setLocalChangeSnapshot",
|
|
@@ -956,7 +967,7 @@ class LocalSyncStateHelper {
|
|
|
956
967
|
* @returns Nothing.
|
|
957
968
|
*/
|
|
958
969
|
async removeLocalChangeSnapshot(localChangeSnapshot) {
|
|
959
|
-
await this.
|
|
970
|
+
await this._loggingComponent?.log({
|
|
960
971
|
level: "info",
|
|
961
972
|
source: this.CLASS_NAME,
|
|
962
973
|
message: "removeLocalChangeSnapshot",
|
|
@@ -973,7 +984,7 @@ class LocalSyncStateHelper {
|
|
|
973
984
|
* @returns Nothing.
|
|
974
985
|
*/
|
|
975
986
|
async applySyncState(storageKey, syncState) {
|
|
976
|
-
await this.
|
|
987
|
+
await this._loggingComponent?.log({
|
|
977
988
|
level: "info",
|
|
978
989
|
source: this.CLASS_NAME,
|
|
979
990
|
message: "applySyncState",
|
|
@@ -982,14 +993,23 @@ class LocalSyncStateHelper {
|
|
|
982
993
|
}
|
|
983
994
|
});
|
|
984
995
|
// Get all the existing snapshots that we have processed previously
|
|
985
|
-
|
|
996
|
+
let existingSnapshots = await this.getSnapshots(storageKey, false);
|
|
986
997
|
// Sort from newest to oldest
|
|
987
|
-
|
|
988
|
-
//
|
|
989
|
-
|
|
990
|
-
//
|
|
991
|
-
|
|
992
|
-
|
|
998
|
+
existingSnapshots = existingSnapshots.sort((a, b) => new Date(b.dateCreated).getTime() - new Date(a.dateCreated).getTime());
|
|
999
|
+
// Sort from newest to oldest
|
|
1000
|
+
const syncStateSnapshots = syncState.snapshots.sort((a, b) => new Date(b.dateCreated).getTime() - new Date(a.dateCreated).getTime());
|
|
1001
|
+
// Get the newest epoch from the local storage
|
|
1002
|
+
const newestExistingEpoch = existingSnapshots[0]?.epoch ?? 0;
|
|
1003
|
+
// Get the oldest epoch from the remote storage
|
|
1004
|
+
const oldestSyncStateEpoch = syncStateSnapshots[syncStateSnapshots.length - 1]?.epoch ?? 0;
|
|
1005
|
+
// If there is a gap between the largest epoch we have locally
|
|
1006
|
+
// and the smallest epoch we have remotely then we have missed
|
|
1007
|
+
// data so we need to perform a full sync
|
|
1008
|
+
const hasEpochGap = newestExistingEpoch + 1 < oldestSyncStateEpoch;
|
|
1009
|
+
// If we have an epoch gap or no existing snapshots then we need to apply
|
|
1010
|
+
// a full sync from a consolidation
|
|
1011
|
+
if (!existingSnapshots.some(s => s.isConsolidated) || hasEpochGap) {
|
|
1012
|
+
await this._loggingComponent?.log({
|
|
993
1013
|
level: "info",
|
|
994
1014
|
source: this.CLASS_NAME,
|
|
995
1015
|
message: "applySnapshotNoExisting",
|
|
@@ -997,31 +1017,38 @@ class LocalSyncStateHelper {
|
|
|
997
1017
|
storageKey
|
|
998
1018
|
}
|
|
999
1019
|
});
|
|
1000
|
-
const
|
|
1001
|
-
if (
|
|
1002
|
-
// We found
|
|
1003
|
-
await this.
|
|
1020
|
+
const mostRecentConsolidation = syncStateSnapshots.findIndex(snapshot => snapshot.isConsolidated);
|
|
1021
|
+
if (mostRecentConsolidation !== -1) {
|
|
1022
|
+
// We found the most recent consolidated snapshot, we can use it
|
|
1023
|
+
await this._loggingComponent?.log({
|
|
1004
1024
|
level: "info",
|
|
1005
1025
|
source: this.CLASS_NAME,
|
|
1006
1026
|
message: "applySnapshotFoundConsolidated",
|
|
1007
1027
|
data: {
|
|
1008
1028
|
storageKey,
|
|
1009
|
-
snapshotId:
|
|
1029
|
+
snapshotId: syncStateSnapshots[mostRecentConsolidation].id
|
|
1010
1030
|
}
|
|
1011
1031
|
});
|
|
1012
1032
|
// We need to reset the entity storage and remove all the remote items
|
|
1013
|
-
// so that we use just the ones from the consolidation
|
|
1033
|
+
// so that we use just the ones from the consolidation, since
|
|
1034
|
+
// we don't have any existing there shouldn't be any remote entries
|
|
1035
|
+
// but we reset nonetheless
|
|
1014
1036
|
await this._changeSetHelper.reset(storageKey, SyncNodeIdentityMode.Remote);
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1037
|
+
// We need to process the most recent consolidation and all changes
|
|
1038
|
+
// that were made since then, from newest to oldest (so newer changes override older ones)
|
|
1039
|
+
// Process snapshots from the consolidation point (most recent) back to the newest
|
|
1040
|
+
for (let i = mostRecentConsolidation; i >= 0; i--) {
|
|
1041
|
+
await this.processNewSnapshots([
|
|
1042
|
+
{
|
|
1043
|
+
...syncStateSnapshots[i],
|
|
1044
|
+
storageKey,
|
|
1045
|
+
isLocal: false
|
|
1046
|
+
}
|
|
1047
|
+
]);
|
|
1048
|
+
}
|
|
1022
1049
|
}
|
|
1023
1050
|
else {
|
|
1024
|
-
await this.
|
|
1051
|
+
await this._loggingComponent?.log({
|
|
1025
1052
|
level: "info",
|
|
1026
1053
|
source: this.CLASS_NAME,
|
|
1027
1054
|
message: "applySnapshotNoConsolidated",
|
|
@@ -1032,16 +1059,21 @@ class LocalSyncStateHelper {
|
|
|
1032
1059
|
}
|
|
1033
1060
|
}
|
|
1034
1061
|
else {
|
|
1062
|
+
// We have existing consolidated remote snapshots, so we can assume that we have
|
|
1063
|
+
// applied at least one consolidation snapshot, in this case we need to look at the changes since
|
|
1064
|
+
// then and apply them if we haven't already
|
|
1065
|
+
// We don't need to apply any additional consolidated snapshots, just the changesets
|
|
1035
1066
|
// Create a lookup map for the existing snapshots
|
|
1036
|
-
const
|
|
1037
|
-
for (const snapshot of
|
|
1038
|
-
|
|
1067
|
+
const existingSnapshotsMap = {};
|
|
1068
|
+
for (const snapshot of existingSnapshots) {
|
|
1069
|
+
existingSnapshotsMap[snapshot.id] = snapshot;
|
|
1039
1070
|
}
|
|
1040
1071
|
const newSnapshots = [];
|
|
1041
1072
|
const modifiedSnapshots = [];
|
|
1042
|
-
const referencedExistingSnapshots = Object.keys(
|
|
1043
|
-
|
|
1044
|
-
|
|
1073
|
+
const referencedExistingSnapshots = Object.keys(existingSnapshotsMap);
|
|
1074
|
+
let completedProcessing = false;
|
|
1075
|
+
for (const snapshot of syncStateSnapshots) {
|
|
1076
|
+
await this._loggingComponent?.log({
|
|
1045
1077
|
level: "info",
|
|
1046
1078
|
source: this.CLASS_NAME,
|
|
1047
1079
|
message: "applySnapshot",
|
|
@@ -1050,34 +1082,37 @@ class LocalSyncStateHelper {
|
|
|
1050
1082
|
dateCreated: new Date(snapshot.dateCreated).toISOString()
|
|
1051
1083
|
}
|
|
1052
1084
|
});
|
|
1053
|
-
// See if we have the
|
|
1054
|
-
const currentSnapshot =
|
|
1085
|
+
// See if we have the snapshot stored locally
|
|
1086
|
+
const currentSnapshot = existingSnapshotsMap[snapshot.id];
|
|
1055
1087
|
// As we are referencing an existing snapshot, we need to remove it from the list
|
|
1056
1088
|
// to allow us to cleanup any unreferenced snapshots later
|
|
1057
1089
|
const idx = referencedExistingSnapshots.indexOf(snapshot.id);
|
|
1058
1090
|
if (idx !== -1) {
|
|
1059
1091
|
referencedExistingSnapshots.splice(idx, 1);
|
|
1060
1092
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1093
|
+
// No need to apply consolidated snapshots
|
|
1094
|
+
if (!snapshot.isConsolidated && !completedProcessing) {
|
|
1095
|
+
const updatedSnapshot = {
|
|
1096
|
+
...snapshot,
|
|
1097
|
+
storageKey,
|
|
1098
|
+
isLocal: false
|
|
1099
|
+
};
|
|
1100
|
+
if (Is.empty(currentSnapshot)) {
|
|
1101
|
+
// We don't have the snapshot locally, so we need to process all of it
|
|
1102
|
+
newSnapshots.push(updatedSnapshot);
|
|
1103
|
+
}
|
|
1104
|
+
else if (currentSnapshot.dateModified !== snapshot.dateModified) {
|
|
1105
|
+
// If the local snapshot has a different dateModified, we need to update it
|
|
1106
|
+
modifiedSnapshots.push({
|
|
1107
|
+
currentSnapshot,
|
|
1108
|
+
updatedSnapshot
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
// we sorted the snapshots from newest to oldest, so if we found a local snapshot
|
|
1113
|
+
// with the same dateModified as the remote snapshot, we can stop processing further
|
|
1114
|
+
completedProcessing = true;
|
|
1115
|
+
}
|
|
1081
1116
|
}
|
|
1082
1117
|
}
|
|
1083
1118
|
// We reverse the order of the snapshots to process them from oldest to newest
|
|
@@ -1099,7 +1134,7 @@ class LocalSyncStateHelper {
|
|
|
1099
1134
|
*/
|
|
1100
1135
|
async processModifiedSnapshots(modifiedSnapshots) {
|
|
1101
1136
|
for (const modifiedSnapshot of modifiedSnapshots) {
|
|
1102
|
-
await this.
|
|
1137
|
+
await this._loggingComponent?.log({
|
|
1103
1138
|
level: "info",
|
|
1104
1139
|
source: this.CLASS_NAME,
|
|
1105
1140
|
message: "processModifiedSnapshot",
|
|
@@ -1132,7 +1167,7 @@ class LocalSyncStateHelper {
|
|
|
1132
1167
|
*/
|
|
1133
1168
|
async processNewSnapshots(newSnapshots) {
|
|
1134
1169
|
for (const newSnapshot of newSnapshots) {
|
|
1135
|
-
await this.
|
|
1170
|
+
await this._loggingComponent?.log({
|
|
1136
1171
|
level: "info",
|
|
1137
1172
|
source: this.CLASS_NAME,
|
|
1138
1173
|
message: "processNewSnapshot",
|
|
@@ -1163,10 +1198,10 @@ class RemoteSyncStateHelper {
|
|
|
1163
1198
|
*/
|
|
1164
1199
|
CLASS_NAME = "RemoteSyncStateHelper";
|
|
1165
1200
|
/**
|
|
1166
|
-
* The logging
|
|
1201
|
+
* The logging component to use for logging.
|
|
1167
1202
|
* @internal
|
|
1168
1203
|
*/
|
|
1169
|
-
|
|
1204
|
+
_loggingComponent;
|
|
1170
1205
|
/**
|
|
1171
1206
|
* The event bus component.
|
|
1172
1207
|
* @internal
|
|
@@ -1219,7 +1254,7 @@ class RemoteSyncStateHelper {
|
|
|
1219
1254
|
_maxConsolidations;
|
|
1220
1255
|
/**
|
|
1221
1256
|
* Create a new instance of DecentralisedEntityStorageConnector.
|
|
1222
|
-
* @param
|
|
1257
|
+
* @param loggingComponent The logging component to use for logging.
|
|
1223
1258
|
* @param eventBusComponent The event bus component to use for events.
|
|
1224
1259
|
* @param verifiableSyncPointerStorageConnector The verifiable storage connector to use for storing sync pointers.
|
|
1225
1260
|
* @param blobStorageHelper The blob storage helper to use for remote sync states.
|
|
@@ -1227,8 +1262,8 @@ class RemoteSyncStateHelper {
|
|
|
1227
1262
|
* @param isTrustedNode Whether the node is trusted or not.
|
|
1228
1263
|
* @param maxConsolidations The maximum number of consolidations to keep in storage.
|
|
1229
1264
|
*/
|
|
1230
|
-
constructor(
|
|
1231
|
-
this.
|
|
1265
|
+
constructor(loggingComponent, eventBusComponent, verifiableSyncPointerStorageConnector, blobStorageHelper, changeSetHelper, isTrustedNode, maxConsolidations) {
|
|
1266
|
+
this._loggingComponent = loggingComponent;
|
|
1232
1267
|
this._eventBusComponent = eventBusComponent;
|
|
1233
1268
|
this._verifiableSyncPointerStorageConnector = verifiableSyncPointerStorageConnector;
|
|
1234
1269
|
this._changeSetHelper = changeSetHelper;
|
|
@@ -1266,7 +1301,7 @@ class RemoteSyncStateHelper {
|
|
|
1266
1301
|
* @returns The storage id of the change set if created.
|
|
1267
1302
|
*/
|
|
1268
1303
|
async buildChangeSet(storageKey, changes, completeCallback) {
|
|
1269
|
-
await this.
|
|
1304
|
+
await this._loggingComponent?.log({
|
|
1270
1305
|
level: "info",
|
|
1271
1306
|
source: this.CLASS_NAME,
|
|
1272
1307
|
message: "buildingChangeSet",
|
|
@@ -1292,7 +1327,7 @@ class RemoteSyncStateHelper {
|
|
|
1292
1327
|
// Once all the requests are handled the callback will be called
|
|
1293
1328
|
for (const change of setChanges) {
|
|
1294
1329
|
// Create a request for each change to populate the full details
|
|
1295
|
-
await this.
|
|
1330
|
+
await this._loggingComponent?.log({
|
|
1296
1331
|
level: "info",
|
|
1297
1332
|
source: this.CLASS_NAME,
|
|
1298
1333
|
message: "createChangeSetRequestingItem",
|
|
@@ -1315,7 +1350,7 @@ class RemoteSyncStateHelper {
|
|
|
1315
1350
|
* @returns Nothing.
|
|
1316
1351
|
*/
|
|
1317
1352
|
async finaliseFullChanges(storageKey, completeCallback) {
|
|
1318
|
-
await this.
|
|
1353
|
+
await this._loggingComponent?.log({
|
|
1319
1354
|
level: "info",
|
|
1320
1355
|
source: this.CLASS_NAME,
|
|
1321
1356
|
message: "finalisingSyncChanges",
|
|
@@ -1356,7 +1391,7 @@ class RemoteSyncStateHelper {
|
|
|
1356
1391
|
await completeCallback(syncChangeSet, changeSetStorageId);
|
|
1357
1392
|
}
|
|
1358
1393
|
catch (err) {
|
|
1359
|
-
await this.
|
|
1394
|
+
await this._loggingComponent?.log({
|
|
1360
1395
|
level: "error",
|
|
1361
1396
|
source: this.CLASS_NAME,
|
|
1362
1397
|
message: "finalisingSyncChangesFailed",
|
|
@@ -1379,7 +1414,7 @@ class RemoteSyncStateHelper {
|
|
|
1379
1414
|
* @returns Nothing.
|
|
1380
1415
|
*/
|
|
1381
1416
|
async addChangeSetToSyncState(storageKey, changeSetStorageId) {
|
|
1382
|
-
await this.
|
|
1417
|
+
await this._loggingComponent?.log({
|
|
1383
1418
|
level: "info",
|
|
1384
1419
|
source: this.CLASS_NAME,
|
|
1385
1420
|
message: "addChangeSetToSyncState",
|
|
@@ -1402,6 +1437,7 @@ class RemoteSyncStateHelper {
|
|
|
1402
1437
|
const sortedSnapshots = syncState.snapshots.sort((a, b) => a.dateCreated.localeCompare(b.dateCreated));
|
|
1403
1438
|
// Get the current snapshot, if it does not exist we create a new one
|
|
1404
1439
|
let currentSnapshot = sortedSnapshots[sortedSnapshots.length - 1];
|
|
1440
|
+
const currentEpoch = currentSnapshot?.epoch ?? 0;
|
|
1405
1441
|
const now = new Date(Date.now()).toISOString();
|
|
1406
1442
|
// If there is no snapshot or the current one is a consolidation
|
|
1407
1443
|
// we start a new snapshot
|
|
@@ -1412,6 +1448,7 @@ class RemoteSyncStateHelper {
|
|
|
1412
1448
|
dateCreated: now,
|
|
1413
1449
|
dateModified: now,
|
|
1414
1450
|
isConsolidated: false,
|
|
1451
|
+
epoch: currentEpoch + 1,
|
|
1415
1452
|
changeSetStorageIds: []
|
|
1416
1453
|
};
|
|
1417
1454
|
syncState.snapshots.push(currentSnapshot);
|
|
@@ -1434,7 +1471,7 @@ class RemoteSyncStateHelper {
|
|
|
1434
1471
|
* @returns Nothing.
|
|
1435
1472
|
*/
|
|
1436
1473
|
async consolidationStart(storageKey, batchSize) {
|
|
1437
|
-
await this.
|
|
1474
|
+
await this._loggingComponent?.log({
|
|
1438
1475
|
level: "info",
|
|
1439
1476
|
source: this.CLASS_NAME,
|
|
1440
1477
|
message: "consolidationStarting"
|
|
@@ -1449,7 +1486,7 @@ class RemoteSyncStateHelper {
|
|
|
1449
1486
|
async getVerifiableSyncPointerStore() {
|
|
1450
1487
|
if (Is.stringValue(this._synchronisedStorageKey)) {
|
|
1451
1488
|
try {
|
|
1452
|
-
await this.
|
|
1489
|
+
await this._loggingComponent?.log({
|
|
1453
1490
|
level: "info",
|
|
1454
1491
|
source: this.CLASS_NAME,
|
|
1455
1492
|
message: "verifiableSyncPointerStoreRetrieving",
|
|
@@ -1460,7 +1497,7 @@ class RemoteSyncStateHelper {
|
|
|
1460
1497
|
const syncPointerStore = await this._verifiableSyncPointerStorageConnector.get(this._synchronisedStorageKey, { includeData: true });
|
|
1461
1498
|
if (Is.uint8Array(syncPointerStore.data)) {
|
|
1462
1499
|
const syncPointer = ObjectHelper.fromBytes(syncPointerStore.data);
|
|
1463
|
-
await this.
|
|
1500
|
+
await this._loggingComponent?.log({
|
|
1464
1501
|
level: "info",
|
|
1465
1502
|
source: this.CLASS_NAME,
|
|
1466
1503
|
message: "verifiableSyncPointerStoreRetrieved",
|
|
@@ -1476,7 +1513,7 @@ class RemoteSyncStateHelper {
|
|
|
1476
1513
|
throw err;
|
|
1477
1514
|
}
|
|
1478
1515
|
}
|
|
1479
|
-
await this.
|
|
1516
|
+
await this._loggingComponent?.log({
|
|
1480
1517
|
level: "info",
|
|
1481
1518
|
source: this.CLASS_NAME,
|
|
1482
1519
|
message: "verifiableSyncPointerStoreNotFound",
|
|
@@ -1498,7 +1535,7 @@ class RemoteSyncStateHelper {
|
|
|
1498
1535
|
*/
|
|
1499
1536
|
async storeVerifiableSyncPointerStore(syncPointerStore) {
|
|
1500
1537
|
if (Is.stringValue(this._nodeIdentity) && Is.stringValue(this._synchronisedStorageKey)) {
|
|
1501
|
-
await this.
|
|
1538
|
+
await this._loggingComponent?.log({
|
|
1502
1539
|
level: "info",
|
|
1503
1540
|
source: this.CLASS_NAME,
|
|
1504
1541
|
message: "verifiableSyncPointerStoreStoring",
|
|
@@ -1516,7 +1553,7 @@ class RemoteSyncStateHelper {
|
|
|
1516
1553
|
* @returns The id of the sync state.
|
|
1517
1554
|
*/
|
|
1518
1555
|
async storeRemoteSyncState(syncState) {
|
|
1519
|
-
await this.
|
|
1556
|
+
await this._loggingComponent?.log({
|
|
1520
1557
|
level: "info",
|
|
1521
1558
|
source: this.CLASS_NAME,
|
|
1522
1559
|
message: "syncStateStoring",
|
|
@@ -1542,7 +1579,12 @@ class RemoteSyncStateHelper {
|
|
|
1542
1579
|
const toRemove = snapshots.slice(consolidationIndexes[this._maxConsolidations - 1] + 1);
|
|
1543
1580
|
syncState.snapshots = snapshots.slice(0, consolidationIndexes[this._maxConsolidations - 1] + 1);
|
|
1544
1581
|
for (const snapshot of toRemove) {
|
|
1545
|
-
|
|
1582
|
+
// We need to remove all the storage ids associated with the snapshot
|
|
1583
|
+
if (Is.arrayValue(snapshot.changeSetStorageIds)) {
|
|
1584
|
+
for (const storageId of snapshot.changeSetStorageIds) {
|
|
1585
|
+
await this._blobStorageHelper.removeBlob(storageId);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1546
1588
|
}
|
|
1547
1589
|
}
|
|
1548
1590
|
return this._blobStorageHelper.saveBlob(syncState);
|
|
@@ -1554,7 +1596,7 @@ class RemoteSyncStateHelper {
|
|
|
1554
1596
|
*/
|
|
1555
1597
|
async getSyncState(syncPointerId) {
|
|
1556
1598
|
try {
|
|
1557
|
-
await this.
|
|
1599
|
+
await this._loggingComponent?.log({
|
|
1558
1600
|
level: "info",
|
|
1559
1601
|
source: this.CLASS_NAME,
|
|
1560
1602
|
message: "syncStateRetrieving",
|
|
@@ -1564,7 +1606,7 @@ class RemoteSyncStateHelper {
|
|
|
1564
1606
|
});
|
|
1565
1607
|
const syncState = await this._blobStorageHelper.loadBlob(syncPointerId);
|
|
1566
1608
|
if (Is.object(syncState)) {
|
|
1567
|
-
await this.
|
|
1609
|
+
await this._loggingComponent?.log({
|
|
1568
1610
|
level: "info",
|
|
1569
1611
|
source: this.CLASS_NAME,
|
|
1570
1612
|
message: "syncStateRetrieved",
|
|
@@ -1577,7 +1619,7 @@ class RemoteSyncStateHelper {
|
|
|
1577
1619
|
}
|
|
1578
1620
|
}
|
|
1579
1621
|
catch (error) {
|
|
1580
|
-
await this.
|
|
1622
|
+
await this._loggingComponent?.log({
|
|
1581
1623
|
level: "warn",
|
|
1582
1624
|
source: this.CLASS_NAME,
|
|
1583
1625
|
message: "getSyncStateError",
|
|
@@ -1587,7 +1629,7 @@ class RemoteSyncStateHelper {
|
|
|
1587
1629
|
error: BaseError.fromError(error)
|
|
1588
1630
|
});
|
|
1589
1631
|
}
|
|
1590
|
-
await this.
|
|
1632
|
+
await this._loggingComponent?.log({
|
|
1591
1633
|
level: "info",
|
|
1592
1634
|
source: this.CLASS_NAME,
|
|
1593
1635
|
message: "syncStateNotFound",
|
|
@@ -1637,12 +1679,17 @@ class RemoteSyncStateHelper {
|
|
|
1637
1679
|
storageKey: response.storageKey,
|
|
1638
1680
|
snapshots: []
|
|
1639
1681
|
};
|
|
1682
|
+
// Sort the snapshots so the newest snapshot is last in the array
|
|
1683
|
+
const sortedSnapshots = syncState.snapshots.sort((a, b) => a.dateCreated.localeCompare(b.dateCreated));
|
|
1684
|
+
const currentSnapshot = sortedSnapshots[sortedSnapshots.length - 1];
|
|
1685
|
+
const currentEpoch = currentSnapshot?.epoch ?? 0;
|
|
1640
1686
|
const batchSnapshot = {
|
|
1641
1687
|
version: SYNC_SNAPSHOT_VERSION,
|
|
1642
1688
|
id: Converter.bytesToHex(RandomHelper.generate(32)),
|
|
1643
1689
|
dateCreated: now,
|
|
1644
1690
|
dateModified: now,
|
|
1645
1691
|
isConsolidated: true,
|
|
1692
|
+
epoch: currentEpoch + 1,
|
|
1646
1693
|
changeSetStorageIds: this._batchResponseStorageIds[response.storageKey]
|
|
1647
1694
|
};
|
|
1648
1695
|
syncState.snapshots.push(batchSnapshot);
|
|
@@ -1654,7 +1701,7 @@ class RemoteSyncStateHelper {
|
|
|
1654
1701
|
// Remove the batch response storage ids for the storage key
|
|
1655
1702
|
// as we have consolidated the changes
|
|
1656
1703
|
delete this._batchResponseStorageIds[response.storageKey];
|
|
1657
|
-
await this.
|
|
1704
|
+
await this._loggingComponent?.log({
|
|
1658
1705
|
level: "info",
|
|
1659
1706
|
source: this.CLASS_NAME,
|
|
1660
1707
|
message: "consolidationCompleted"
|
|
@@ -1667,7 +1714,7 @@ class RemoteSyncStateHelper {
|
|
|
1667
1714
|
* @param response The item response to handle.
|
|
1668
1715
|
*/
|
|
1669
1716
|
async handleLocalItemResponse(response) {
|
|
1670
|
-
await this.
|
|
1717
|
+
await this._loggingComponent?.log({
|
|
1671
1718
|
level: "info",
|
|
1672
1719
|
source: this.CLASS_NAME,
|
|
1673
1720
|
message: "createChangeSetRespondingItem",
|
|
@@ -1721,10 +1768,10 @@ class SynchronisedStorageService {
|
|
|
1721
1768
|
*/
|
|
1722
1769
|
CLASS_NAME = "SynchronisedStorageService";
|
|
1723
1770
|
/**
|
|
1724
|
-
* The logging
|
|
1771
|
+
* The logging component to use for logging.
|
|
1725
1772
|
* @internal
|
|
1726
1773
|
*/
|
|
1727
|
-
|
|
1774
|
+
_loggingComponent;
|
|
1728
1775
|
/**
|
|
1729
1776
|
* The event bus component.
|
|
1730
1777
|
* @internal
|
|
@@ -1818,7 +1865,7 @@ class SynchronisedStorageService {
|
|
|
1818
1865
|
Guards.object(this.CLASS_NAME, "options", options);
|
|
1819
1866
|
Guards.object(this.CLASS_NAME, "options.config", options.config);
|
|
1820
1867
|
this._eventBusComponent = ComponentFactory.get(options.eventBusComponentType ?? "event-bus");
|
|
1821
|
-
this.
|
|
1868
|
+
this._loggingComponent = ComponentFactory.getIfExists(options.loggingComponentType ?? "logging");
|
|
1822
1869
|
this._vaultConnector = VaultConnectorFactory.get(options.vaultConnectorType ?? "vault");
|
|
1823
1870
|
this._localSyncSnapshotEntryEntityStorage = EntityStorageConnectorFactory.get(options.syncSnapshotStorageConnectorType ?? "sync-snapshot-entry");
|
|
1824
1871
|
this._verifiableSyncPointerStorageConnector = VerifiableStorageConnectorFactory.get(options.verifiableStorageConnectorType ?? "verifiable-storage");
|
|
@@ -1847,10 +1894,10 @@ class SynchronisedStorageService {
|
|
|
1847
1894
|
this._trustedSynchronisedStorageComponent =
|
|
1848
1895
|
ComponentFactory.get(options.trustedSynchronisedStorageComponentType);
|
|
1849
1896
|
}
|
|
1850
|
-
this._blobStorageHelper = new BlobStorageHelper(this.
|
|
1851
|
-
this._changeSetHelper = new ChangeSetHelper(this.
|
|
1852
|
-
this._localSyncStateHelper = new LocalSyncStateHelper(this.
|
|
1853
|
-
this._remoteSyncStateHelper = new RemoteSyncStateHelper(this.
|
|
1897
|
+
this._blobStorageHelper = new BlobStorageHelper(this._loggingComponent, this._vaultConnector, this._blobStorageConnector, this._config.blobStorageEncryptionKeyId, this._config.isTrustedNode);
|
|
1898
|
+
this._changeSetHelper = new ChangeSetHelper(this._loggingComponent, this._eventBusComponent, this._identityConnector, this._blobStorageHelper, this._config.synchronisedStorageMethodId);
|
|
1899
|
+
this._localSyncStateHelper = new LocalSyncStateHelper(this._loggingComponent, this._localSyncSnapshotEntryEntityStorage, this._changeSetHelper);
|
|
1900
|
+
this._remoteSyncStateHelper = new RemoteSyncStateHelper(this._loggingComponent, this._eventBusComponent, this._verifiableSyncPointerStorageConnector, this._blobStorageHelper, this._changeSetHelper, this._config.isTrustedNode, this._config.maxConsolidations);
|
|
1854
1901
|
this._serviceStarted = false;
|
|
1855
1902
|
this._activeStorageKeys = {};
|
|
1856
1903
|
this._eventBusComponent.subscribe(SynchronisedStorageTopics.RegisterStorageKey, async (event) => this.registerStorageKey(event.data));
|
|
@@ -1935,7 +1982,7 @@ class SynchronisedStorageService {
|
|
|
1935
1982
|
throw new GeneralError(this.CLASS_NAME, "notTrustedNode");
|
|
1936
1983
|
}
|
|
1937
1984
|
Guards.object(this.CLASS_NAME, "syncChangeSet", syncChangeSet);
|
|
1938
|
-
await this.
|
|
1985
|
+
await this._loggingComponent?.log({
|
|
1939
1986
|
level: "info",
|
|
1940
1987
|
source: this.CLASS_NAME,
|
|
1941
1988
|
message: "syncChangeSetForRemoteNode",
|
|
@@ -1964,7 +2011,7 @@ class SynchronisedStorageService {
|
|
|
1964
2011
|
*/
|
|
1965
2012
|
async startEntitySync(storageKey) {
|
|
1966
2013
|
try {
|
|
1967
|
-
await this.
|
|
2014
|
+
await this._loggingComponent?.log({
|
|
1968
2015
|
level: "info",
|
|
1969
2016
|
source: this.CLASS_NAME,
|
|
1970
2017
|
message: "startEntitySync",
|
|
@@ -1978,7 +2025,7 @@ class SynchronisedStorageService {
|
|
|
1978
2025
|
await this.updateFromLocalSyncState(storageKey);
|
|
1979
2026
|
}
|
|
1980
2027
|
catch (error) {
|
|
1981
|
-
await this.
|
|
2028
|
+
await this._loggingComponent?.log({
|
|
1982
2029
|
level: "error",
|
|
1983
2030
|
source: this.CLASS_NAME,
|
|
1984
2031
|
message: "entitySyncFailed",
|
|
@@ -1993,7 +2040,7 @@ class SynchronisedStorageService {
|
|
|
1993
2040
|
* @internal
|
|
1994
2041
|
*/
|
|
1995
2042
|
async updateFromRemoteSyncState(storageKey) {
|
|
1996
|
-
await this.
|
|
2043
|
+
await this._loggingComponent?.log({
|
|
1997
2044
|
level: "info",
|
|
1998
2045
|
source: this.CLASS_NAME,
|
|
1999
2046
|
message: "updateFromRemoteSyncState",
|
|
@@ -2019,7 +2066,7 @@ class SynchronisedStorageService {
|
|
|
2019
2066
|
* @internal
|
|
2020
2067
|
*/
|
|
2021
2068
|
async updateFromLocalSyncState(storageKey) {
|
|
2022
|
-
await this.
|
|
2069
|
+
await this._loggingComponent?.log({
|
|
2023
2070
|
level: "info",
|
|
2024
2071
|
source: this.CLASS_NAME,
|
|
2025
2072
|
message: "updateFromLocalSyncState",
|
|
@@ -2033,7 +2080,7 @@ class SynchronisedStorageService {
|
|
|
2033
2080
|
if (Is.arrayValue(localChangeSnapshot.changes)) {
|
|
2034
2081
|
await this._remoteSyncStateHelper.buildChangeSet(storageKey, localChangeSnapshot.changes, async (syncChangeSet, changeSetStorageId) => {
|
|
2035
2082
|
if (Is.empty(syncChangeSet) && Is.empty(changeSetStorageId)) {
|
|
2036
|
-
await this.
|
|
2083
|
+
await this._loggingComponent?.log({
|
|
2037
2084
|
level: "info",
|
|
2038
2085
|
source: this.CLASS_NAME,
|
|
2039
2086
|
message: "builtStorageChangeSetNone",
|
|
@@ -2043,7 +2090,7 @@ class SynchronisedStorageService {
|
|
|
2043
2090
|
});
|
|
2044
2091
|
}
|
|
2045
2092
|
else {
|
|
2046
|
-
await this.
|
|
2093
|
+
await this._loggingComponent?.log({
|
|
2047
2094
|
level: "info",
|
|
2048
2095
|
source: this.CLASS_NAME,
|
|
2049
2096
|
message: "builtStorageChangeSet",
|
|
@@ -2063,7 +2110,7 @@ class SynchronisedStorageService {
|
|
|
2063
2110
|
Is.object(syncChangeSet)) {
|
|
2064
2111
|
// If we are not a trusted node, we need to send the changes to the trusted node
|
|
2065
2112
|
// and then remove the local change snapshot
|
|
2066
|
-
await this.
|
|
2113
|
+
await this._loggingComponent?.log({
|
|
2067
2114
|
level: "info",
|
|
2068
2115
|
source: this.CLASS_NAME,
|
|
2069
2116
|
message: "sendingChangeSetToTrustedNode",
|
|
@@ -2079,7 +2126,7 @@ class SynchronisedStorageService {
|
|
|
2079
2126
|
});
|
|
2080
2127
|
}
|
|
2081
2128
|
else {
|
|
2082
|
-
await this.
|
|
2129
|
+
await this._loggingComponent?.log({
|
|
2083
2130
|
level: "info",
|
|
2084
2131
|
source: this.CLASS_NAME,
|
|
2085
2132
|
message: "updateFromLocalSyncStateNoChanges",
|
|
@@ -2097,26 +2144,18 @@ class SynchronisedStorageService {
|
|
|
2097
2144
|
* @internal
|
|
2098
2145
|
*/
|
|
2099
2146
|
async startConsolidationSync(storageKey) {
|
|
2100
|
-
let localChangeSnapshot;
|
|
2101
2147
|
try {
|
|
2102
|
-
// If we are
|
|
2103
|
-
//
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
}
|
|
2148
|
+
// If we are going to perform a consolidation first take any local updates
|
|
2149
|
+
// we have and create a changeset from them, so that anybody applying
|
|
2150
|
+
// just changes since a consolidation can use the changeset
|
|
2151
|
+
// and skip the consolidation
|
|
2152
|
+
await this.updateFromLocalSyncState(storageKey);
|
|
2153
|
+
// Now start the consolidation
|
|
2109
2154
|
await this._remoteSyncStateHelper.consolidationStart(storageKey, this._config.consolidationBatchSize ??
|
|
2110
2155
|
SynchronisedStorageService._DEFAULT_CONSOLIDATION_BATCH_SIZE);
|
|
2111
|
-
// The consolidation was successful, so we can remove the local change snapshot permanently
|
|
2112
|
-
localChangeSnapshot = undefined;
|
|
2113
2156
|
}
|
|
2114
2157
|
catch (error) {
|
|
2115
|
-
|
|
2116
|
-
// If the consolidation failed, we can keep the local change snapshot
|
|
2117
|
-
await this._localSyncStateHelper.setLocalChangeSnapshot(localChangeSnapshot);
|
|
2118
|
-
}
|
|
2119
|
-
await this._logging?.log({
|
|
2158
|
+
await this._loggingComponent?.log({
|
|
2120
2159
|
level: "error",
|
|
2121
2160
|
source: this.CLASS_NAME,
|
|
2122
2161
|
message: "consolidationSyncFailed",
|
|
@@ -2130,7 +2169,7 @@ class SynchronisedStorageService {
|
|
|
2130
2169
|
* @internal
|
|
2131
2170
|
*/
|
|
2132
2171
|
async registerStorageKey(syncRegisterStorageKey) {
|
|
2133
|
-
await this.
|
|
2172
|
+
await this._loggingComponent?.log({
|
|
2134
2173
|
level: "info",
|
|
2135
2174
|
source: this.CLASS_NAME,
|
|
2136
2175
|
message: "registerStorageKey",
|
|
@@ -2152,7 +2191,7 @@ class SynchronisedStorageService {
|
|
|
2152
2191
|
*/
|
|
2153
2192
|
async activateStorageKey(storageKey) {
|
|
2154
2193
|
if (!Is.empty(this._activeStorageKeys[storageKey]) && !this._activeStorageKeys[storageKey]) {
|
|
2155
|
-
await this.
|
|
2194
|
+
await this._loggingComponent?.log({
|
|
2156
2195
|
level: "info",
|
|
2157
2196
|
source: this.CLASS_NAME,
|
|
2158
2197
|
message: "activateStorageKey",
|