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