core-3nweb-client-lib 0.27.1 → 0.27.3
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/build/api-defs/files.d.ts +4 -7
- package/build/core/asmail/inbox/attachments/fs.d.ts +2 -1
- package/build/core/asmail/inbox/attachments/fs.js +4 -3
- package/build/core/asmail/inbox/index.js +1 -1
- package/build/core/id-manager/index.d.ts +43 -0
- package/build/core/{id-manager.js → id-manager/index.js} +33 -114
- package/build/core/id-manager/key-storage.d.ts +21 -0
- package/build/core/id-manager/key-storage.js +96 -0
- package/build/core/index.js +21 -23
- package/build/core/sign-in.d.ts +1 -2
- package/build/core/sign-in.js +4 -13
- package/build/core/sign-up.d.ts +2 -0
- package/build/core/sign-up.js +2 -1
- package/build/core/storage/index.d.ts +4 -2
- package/build/core/storage/index.js +36 -57
- package/build/core/storage/local/storage.d.ts +1 -1
- package/build/core/storage/synced/obj-files-gc.d.ts +1 -4
- package/build/core/storage/synced/obj-files-gc.js +1 -18
- package/build/core/storage/synced/obj-files.d.ts +9 -1
- package/build/core/storage/synced/obj-files.js +41 -33
- package/build/core/storage/synced/obj-status.d.ts +18 -7
- package/build/core/storage/synced/obj-status.js +148 -83
- package/build/core/storage/synced/storage.d.ts +7 -2
- package/build/core/storage/synced/storage.js +50 -10
- package/build/core/storage/synced/upsyncer.d.ts +4 -4
- package/build/core/storage/synced/upsyncer.js +12 -6
- package/build/lib-client/3nstorage/exceptions.d.ts +13 -1
- package/build/lib-client/3nstorage/exceptions.js +9 -3
- package/build/lib-client/3nstorage/service.d.ts +6 -1
- package/build/lib-client/3nstorage/service.js +31 -15
- package/build/lib-client/3nstorage/util/file-based-json.js +2 -1
- package/build/lib-client/3nstorage/util/for-arrays.d.ts +1 -0
- package/build/lib-client/3nstorage/util/for-arrays.js +32 -0
- package/build/lib-client/3nstorage/xsp-fs/common.d.ts +5 -4
- package/build/lib-client/3nstorage/xsp-fs/common.js +1 -0
- package/build/lib-client/3nstorage/xsp-fs/file.js +2 -2
- package/build/lib-client/3nstorage/xsp-fs/folder-node.d.ts +11 -5
- package/build/lib-client/3nstorage/xsp-fs/folder-node.js +232 -68
- package/build/lib-client/3nstorage/xsp-fs/fs.js +15 -19
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +4 -9
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +16 -17
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +1 -1
- package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
- package/build/lib-client/cryptor/cryptor.wasm +0 -0
- package/build/lib-client/local-files/device-fs.js +11 -11
- package/build/lib-client/user-with-mid-session.d.ts +2 -1
- package/build/lib-client/user-with-mid-session.js +7 -1
- package/build/lib-common/async-fs-node.js +8 -8
- package/build/lib-common/exceptions/file.d.ts +4 -2
- package/build/lib-common/exceptions/file.js +24 -58
- package/build/lib-common/ipc/generic-ipc.js +5 -4
- package/build/lib-common/objs-on-disk/utils.js +1 -1
- package/build/lib-common/service-api/3nstorage/owner.d.ts +8 -5
- package/build/lib-common/service-api/3nstorage/owner.js +2 -1
- package/package.json +3 -2
- package/build/core/id-manager.d.ts +0 -46
|
@@ -37,6 +37,7 @@ const folder_node_serialization_1 = require("./folder-node-serialization");
|
|
|
37
37
|
const attrs_1 = require("./attrs");
|
|
38
38
|
const node_persistence_1 = require("./node-persistence");
|
|
39
39
|
const assert_1 = require("../../../lib-common/assert");
|
|
40
|
+
const for_arrays_1 = require("../util/for-arrays");
|
|
40
41
|
function jsonToInfoAndAttrs(json) {
|
|
41
42
|
const folderInfo = {
|
|
42
43
|
nodes: (0, json_utils_1.copy)(json.nodes)
|
|
@@ -62,6 +63,14 @@ class FolderPersistance extends node_persistence_1.NodePersistance {
|
|
|
62
63
|
const folderInfo = (0, folder_node_serialization_1.parseFolderInfo)(content);
|
|
63
64
|
return { folderInfo, xattrs, attrs: attrs_1.CommonAttrs.fromAttrs(attrs) };
|
|
64
65
|
}
|
|
66
|
+
static async readFolderContent(objId, key, src, cryptor) {
|
|
67
|
+
if (objId === null) {
|
|
68
|
+
throw new Error("Missing objId for non-root folder");
|
|
69
|
+
}
|
|
70
|
+
const zNonce = (0, xsp_files_1.idToHeaderNonce)(objId);
|
|
71
|
+
const { folderInfo } = await (new FolderPersistance(zNonce, key, cryptor)).read(src);
|
|
72
|
+
return folderInfo;
|
|
73
|
+
}
|
|
65
74
|
}
|
|
66
75
|
Object.freeze(FolderPersistance.prototype);
|
|
67
76
|
Object.freeze(FolderPersistance);
|
|
@@ -84,7 +93,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
84
93
|
(0, assert_1.assert)(!objId && !parentId, `Root folder must have both objId and parent as nulls.`);
|
|
85
94
|
}
|
|
86
95
|
else if (objId === null) {
|
|
87
|
-
new Error("Missing objId for non-root folder");
|
|
96
|
+
throw new Error("Missing objId for non-root folder");
|
|
88
97
|
}
|
|
89
98
|
this.crypto = new FolderPersistance(zNonce, key, storage.cryptor);
|
|
90
99
|
if (setNewAttrs) {
|
|
@@ -198,7 +207,16 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
198
207
|
return;
|
|
199
208
|
}
|
|
200
209
|
for (const objToRm of objsToRm) {
|
|
201
|
-
|
|
210
|
+
const nodeToRm = await this.getOrMakeChildNodeForInfo(objToRm);
|
|
211
|
+
this.callRemoveObjOn('sync', nodeToRm);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
callRemoveObjOn(src, node) {
|
|
215
|
+
if (node.type === 'folder') {
|
|
216
|
+
node.removeFolderObj(src);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
node.removeNonFolderObj(src);
|
|
202
220
|
}
|
|
203
221
|
}
|
|
204
222
|
list() {
|
|
@@ -207,18 +225,25 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
207
225
|
return { lst, version: this.version };
|
|
208
226
|
}
|
|
209
227
|
async childExistsInSyncedVersion(childObjId) {
|
|
210
|
-
const
|
|
211
|
-
if (
|
|
228
|
+
const { state, synced } = await this.syncStatus();
|
|
229
|
+
if (state === 'synced') {
|
|
212
230
|
return true;
|
|
213
231
|
}
|
|
214
|
-
if (!
|
|
232
|
+
if (!(synced === null || synced === void 0 ? void 0 : synced.latest)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
const storage = this.syncedStorage();
|
|
236
|
+
try {
|
|
237
|
+
const syncedContent = await storage.getObjSrc(this.objId, synced.latest);
|
|
238
|
+
const { folderInfo } = await this.crypto.read(syncedContent);
|
|
239
|
+
const childIsInSynced = !!Object.values(folderInfo.nodes)
|
|
240
|
+
.find(({ objId }) => (objId === childObjId));
|
|
241
|
+
return childIsInSynced;
|
|
242
|
+
}
|
|
243
|
+
catch (exc) {
|
|
244
|
+
storage.logError(exc, `Exception thrown in checking whether child node's obj is present in synced version.`);
|
|
215
245
|
return false;
|
|
216
246
|
}
|
|
217
|
-
// XXX FolderNode.childExistsInSyncedVersion() should implement check in synced version
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
listFolders() {
|
|
221
|
-
return Object.keys(this.currentState.nodes).filter(name => !!this.currentState.nodes[name].isFolder);
|
|
222
247
|
}
|
|
223
248
|
getNodeInfo(name, undefOnMissing = false) {
|
|
224
249
|
const fj = this.currentState.nodes[name];
|
|
@@ -229,7 +254,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
229
254
|
return;
|
|
230
255
|
}
|
|
231
256
|
else {
|
|
232
|
-
throw (0, file_1.makeFileException)(
|
|
257
|
+
throw (0, file_1.makeFileException)('notFound', name);
|
|
233
258
|
}
|
|
234
259
|
}
|
|
235
260
|
hasChild(childName, throwIfMissing = false) {
|
|
@@ -242,13 +267,13 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
242
267
|
}
|
|
243
268
|
if (type) {
|
|
244
269
|
if ((type === 'file') && !childInfo.isFile) {
|
|
245
|
-
throw (0, file_1.makeFileException)(
|
|
270
|
+
throw (0, file_1.makeFileException)('notFile', childInfo.name);
|
|
246
271
|
}
|
|
247
272
|
else if ((type === 'folder') && !childInfo.isFolder) {
|
|
248
|
-
throw (0, file_1.makeFileException)(
|
|
273
|
+
throw (0, file_1.makeFileException)('notDirectory', childInfo.name);
|
|
249
274
|
}
|
|
250
275
|
else if ((type === 'link') && !childInfo.isLink) {
|
|
251
|
-
throw (0, file_1.makeFileException)(
|
|
276
|
+
throw (0, file_1.makeFileException)('notLink', childInfo.name);
|
|
252
277
|
}
|
|
253
278
|
}
|
|
254
279
|
return this.getOrMakeChildNodeForInfo(childInfo);
|
|
@@ -314,7 +339,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
314
339
|
};
|
|
315
340
|
return { event, childObjId: childInfo.objId };
|
|
316
341
|
}).catch(noop);
|
|
317
|
-
const fileExc = (0, file_1.makeFileException)(
|
|
342
|
+
const fileExc = (0, file_1.makeFileException)('notFound', childInfo.name, exc);
|
|
318
343
|
fileExc.inconsistentStateOfFS = true;
|
|
319
344
|
throw fileExc;
|
|
320
345
|
}
|
|
@@ -421,7 +446,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
421
446
|
// do check for concurrent creation of a node
|
|
422
447
|
if (this.getNodeInfo(name, true)) {
|
|
423
448
|
if (exclusive) {
|
|
424
|
-
throw (0, file_1.makeFileException)(
|
|
449
|
+
throw (0, file_1.makeFileException)('alreadyExists', name);
|
|
425
450
|
}
|
|
426
451
|
else if (type === 'folder') {
|
|
427
452
|
return (await this.getNode('folder', name));
|
|
@@ -494,7 +519,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
494
519
|
// explicitly do not wait on a result of child's delete, cause if it fails
|
|
495
520
|
// we just get traceable garbage, yet, the rest of a live/non-deleted tree
|
|
496
521
|
// stays consistent
|
|
497
|
-
|
|
522
|
+
this.callRemoveObjOn('local', f);
|
|
498
523
|
}
|
|
499
524
|
changeChildName(initName, newName) {
|
|
500
525
|
return this.doTransition(async (state, version) => {
|
|
@@ -519,7 +544,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
519
544
|
}
|
|
520
545
|
async moveChildTo(childName, dst, nameInDst) {
|
|
521
546
|
if (dst.hasChild(nameInDst)) {
|
|
522
|
-
throw (0, file_1.makeFileException)(
|
|
547
|
+
throw (0, file_1.makeFileException)('alreadyExists', nameInDst);
|
|
523
548
|
}
|
|
524
549
|
if (dst === this) {
|
|
525
550
|
// In this case we only need to change child's name
|
|
@@ -574,7 +599,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
574
599
|
// existing folder at this point
|
|
575
600
|
if (path.length === 1) {
|
|
576
601
|
if (exclusiveCreate) {
|
|
577
|
-
throw (0, file_1.makeFileException)(
|
|
602
|
+
throw (0, file_1.makeFileException)('alreadyExists', path[0]);
|
|
578
603
|
}
|
|
579
604
|
else {
|
|
580
605
|
return f;
|
|
@@ -631,22 +656,91 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
631
656
|
}
|
|
632
657
|
return content;
|
|
633
658
|
}
|
|
634
|
-
async
|
|
635
|
-
const childrenNodes = await this.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
659
|
+
async removeFolderObj(src, passIdsForRmUpload = false) {
|
|
660
|
+
const childrenNodes = await this.doChange(true, async () => {
|
|
661
|
+
const childrenNodes = await this.getAllNodes();
|
|
662
|
+
await this.removeThisNodeAsLeaf(src);
|
|
663
|
+
return childrenNodes;
|
|
664
|
+
});
|
|
665
|
+
if (childrenNodes.length === 0) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
if (this.isInSyncedStorage) {
|
|
669
|
+
if (passIdsForRmUpload) {
|
|
670
|
+
return this.removeChildrenObjsInSyncedStorage(childrenNodes, src, true);
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
this.removeChildrenObjsInSyncedStorage(childrenNodes, src, false);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
this.callRemoveObjOnAll(src, childrenNodes);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
callRemoveObjOnAll(src, nodes) {
|
|
681
|
+
for (const f of nodes) {
|
|
682
|
+
this.callRemoveObjOn(src, f);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
async removeChildrenObjsInSyncedStorage(childrenNodes, src, passIdsForRmUpload) {
|
|
686
|
+
let uploadRmsHere;
|
|
687
|
+
let collectedIds;
|
|
688
|
+
if (passIdsForRmUpload) {
|
|
689
|
+
collectedIds = [];
|
|
690
|
+
uploadRmsHere = false;
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
try {
|
|
694
|
+
const status = await this.syncedStorage().status(this.objId);
|
|
695
|
+
if (status.neverUploaded()) {
|
|
696
|
+
collectedIds = [];
|
|
697
|
+
uploadRmsHere = true;
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
collectedIds = undefined;
|
|
701
|
+
uploadRmsHere = false;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
catch (exc) {
|
|
705
|
+
if (exc.objNotFound) {
|
|
706
|
+
collectedIds = [];
|
|
707
|
+
uploadRmsHere = true;
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
throw exc;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (!collectedIds) {
|
|
715
|
+
this.callRemoveObjOnAll(src, childrenNodes);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
await Promise.allSettled(childrenNodes.map(async (child) => {
|
|
719
|
+
const status = await this.syncedStorage().status(child.objId);
|
|
720
|
+
if (!status.neverUploaded()) {
|
|
721
|
+
collectedIds.push(child.objId);
|
|
722
|
+
}
|
|
723
|
+
if (child.type === 'folder') {
|
|
724
|
+
const ids = await child.removeFolderObj(src, passIdsForRmUpload);
|
|
725
|
+
if (ids) {
|
|
726
|
+
collectedIds.push(...ids);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
await child.removeNonFolderObj(src);
|
|
731
|
+
}
|
|
732
|
+
}));
|
|
733
|
+
if (uploadRmsHere) {
|
|
734
|
+
await this.uploadRemovalOfObjs(collectedIds);
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
return collectedIds;
|
|
648
738
|
}
|
|
649
739
|
}
|
|
740
|
+
async uploadRemovalOfObjs(objsToRm) {
|
|
741
|
+
objsToRm.sort(); // shuffle order
|
|
742
|
+
await Promise.allSettled(objsToRm.map(objToRm => this.syncedStorage().uploadObjRemoval(objToRm)));
|
|
743
|
+
}
|
|
650
744
|
getParamsForLink() {
|
|
651
745
|
if ((this.storage.type !== 'synced') && (this.storage.type !== 'local')) {
|
|
652
746
|
throw new Error(`Creating link parameters to object in ${this.storage.type} file system, is not implemented.`);
|
|
@@ -664,24 +758,73 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
664
758
|
return linkParams;
|
|
665
759
|
}
|
|
666
760
|
async upload(opts) {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
761
|
+
try {
|
|
762
|
+
const toUpload = await this.needUpload(opts === null || opts === void 0 ? void 0 : opts.localVersion);
|
|
763
|
+
if (!toUpload) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
if (toUpload.createOnRemote) {
|
|
767
|
+
await super.upload(opts);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
const storage = this.syncedStorage();
|
|
771
|
+
const { localVersion, uploadVersion } = toUpload;
|
|
772
|
+
const removedNodes = await this.getNodesRemovedBetweenVersions(localVersion, uploadVersion - 1);
|
|
773
|
+
const uploadHeader = await this.uploadHeaderChange(localVersion, uploadVersion);
|
|
774
|
+
await storage.upload(this.objId, localVersion, uploadVersion, uploadHeader, false);
|
|
775
|
+
if (removedNodes.length > 0) {
|
|
776
|
+
// start upload of children's removal after folder's upload;
|
|
777
|
+
// we also don't await for chidren removal
|
|
778
|
+
this.uploadRemovalOf(removedNodes);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
catch (exc) {
|
|
782
|
+
throw (0, common_1.setPathInExc)(exc, this.name);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
async uploadRemovalOf(removedNodes) {
|
|
786
|
+
const storage = this.syncedStorage();
|
|
787
|
+
const rmObjs = [];
|
|
788
|
+
for (const node of removedNodes) {
|
|
789
|
+
(0, for_arrays_1.appendArray)(rmObjs, await this.listRemovedInTreeToUploadRm(node));
|
|
790
|
+
}
|
|
791
|
+
await this.uploadRemovalOfObjs(rmObjs);
|
|
792
|
+
}
|
|
793
|
+
async listRemovedInTreeToUploadRm(node) {
|
|
794
|
+
const storage = this.syncedStorage();
|
|
795
|
+
let versionBeforeRm;
|
|
796
|
+
try {
|
|
797
|
+
const status = await storage.status(node.objId);
|
|
798
|
+
versionBeforeRm = status.versionBeforeUnsyncedRemoval();
|
|
799
|
+
if (!versionBeforeRm) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
catch (exc) {
|
|
804
|
+
if (exc.objNotFound
|
|
805
|
+
|| exc.notFound) {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
throw exc;
|
|
809
|
+
}
|
|
810
|
+
if (node.isFolder) {
|
|
811
|
+
const objs = [node.objId];
|
|
812
|
+
const src = await storage.getObjSrc(node.objId, versionBeforeRm, true);
|
|
813
|
+
const folderContent = await FolderPersistance.readFolderContent(node.objId, node.key, src, storage.cryptor);
|
|
814
|
+
for (const child of Object.values(folderContent.nodes)) {
|
|
815
|
+
(0, for_arrays_1.appendArray)(objs, await this.listRemovedInTreeToUploadRm(child));
|
|
816
|
+
}
|
|
817
|
+
return objs;
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
return node.objId;
|
|
821
|
+
}
|
|
676
822
|
}
|
|
677
823
|
async needUpload(localVersion) {
|
|
678
824
|
const toUpload = await super.needUpload(localVersion);
|
|
679
825
|
if (!toUpload) {
|
|
680
826
|
return;
|
|
681
827
|
}
|
|
682
|
-
// XXX can put the following into private ensureAllChildrenUploaded(),
|
|
683
|
-
// but it also need to get a consistent state, while current one can
|
|
684
|
-
// be broken by simultaneous change in folder.
|
|
685
828
|
const storage = this.syncedStorage();
|
|
686
829
|
if (toUpload.localVersion === this.version) {
|
|
687
830
|
for (const { objId, name } of Object.values(this.currentState.nodes)) {
|
|
@@ -693,10 +836,29 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
693
836
|
}
|
|
694
837
|
}
|
|
695
838
|
else {
|
|
696
|
-
throw
|
|
839
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
840
|
+
versionMismatch: true,
|
|
841
|
+
localVersion: toUpload.localVersion,
|
|
842
|
+
message: `Local version has concurrently changed from ${toUpload.localVersion} to current ${this.version}`
|
|
843
|
+
});
|
|
697
844
|
}
|
|
698
845
|
return toUpload;
|
|
699
846
|
}
|
|
847
|
+
async getNodesRemovedBetweenVersions(newVer, syncedVer) {
|
|
848
|
+
const storage = this.syncedStorage();
|
|
849
|
+
let stateToUpload;
|
|
850
|
+
if (this.version === newVer) {
|
|
851
|
+
stateToUpload = this.currentState;
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
854
|
+
const localVerSrc = await storage.getObjSrcOfRemoteVersion(this.objId, newVer);
|
|
855
|
+
({ folderInfo: stateToUpload } = await this.crypto.read(localVerSrc));
|
|
856
|
+
}
|
|
857
|
+
const syncedVerSrc = await storage.getObjSrcOfRemoteVersion(this.objId, syncedVer);
|
|
858
|
+
const { folderInfo: syncedState } = await this.crypto.read(syncedVerSrc);
|
|
859
|
+
const { removedNodes } = identifyChanges(syncedState.nodes, stateToUpload.nodes);
|
|
860
|
+
return removedNodes;
|
|
861
|
+
}
|
|
700
862
|
async adoptRemoteFolderItem(itemName, opts) {
|
|
701
863
|
if (opts === null || opts === void 0 ? void 0 : opts.localVersion) {
|
|
702
864
|
if (this.version !== opts.localVersion) {
|
|
@@ -741,10 +903,12 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
741
903
|
return await this.addRemoteChild(remoteChildNode);
|
|
742
904
|
}
|
|
743
905
|
else if (localNodeToRm.objId === remoteChildNode.objId) {
|
|
744
|
-
|
|
906
|
+
(0, assert_1.assert)(typeOfNode(localNodeToRm) === typeOfNode(remoteChildNode));
|
|
907
|
+
// XXX
|
|
908
|
+
throw new Error(`Adaptation of changing keys needs implementation`);
|
|
745
909
|
}
|
|
746
910
|
else {
|
|
747
|
-
return await this.replaceLocalChildWithRemote(
|
|
911
|
+
return await this.replaceLocalChildWithRemote(remoteChildNode);
|
|
748
912
|
}
|
|
749
913
|
}
|
|
750
914
|
async addRemoteChild(remoteChildNode) {
|
|
@@ -761,25 +925,14 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
761
925
|
};
|
|
762
926
|
return { event, childObjId: remoteChildNode.objId };
|
|
763
927
|
});
|
|
764
|
-
// XXX child should update sync info, and adopt change.
|
|
765
928
|
return newVersion;
|
|
766
929
|
}
|
|
767
|
-
async
|
|
930
|
+
async replaceLocalChildWithRemote(remoteChildNode) {
|
|
931
|
+
let origChildNode;
|
|
768
932
|
let newVersion;
|
|
769
933
|
await this.doTransition(async (state, version) => {
|
|
770
934
|
newVersion = version;
|
|
771
|
-
state.nodes[remoteChildNode.name]
|
|
772
|
-
return [];
|
|
773
|
-
});
|
|
774
|
-
// XXX child should update sync info, and adopt change, cause changed key
|
|
775
|
-
// requires changed cypher.
|
|
776
|
-
return newVersion;
|
|
777
|
-
}
|
|
778
|
-
async replaceLocalChildWithRemote(origChildNode, remoteChildNode) {
|
|
779
|
-
let newVersion;
|
|
780
|
-
await this.doTransition(async (state, version) => {
|
|
781
|
-
newVersion = version;
|
|
782
|
-
const presentNode = state.nodes[remoteChildNode.name];
|
|
935
|
+
origChildNode = state.nodes[remoteChildNode.name];
|
|
783
936
|
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
784
937
|
const additionEvent = {
|
|
785
938
|
type: 'entry-addition',
|
|
@@ -799,12 +952,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
799
952
|
{ event: additionEvent, childObjId: remoteChildNode.objId }
|
|
800
953
|
];
|
|
801
954
|
});
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
// - if only local, should be removed,
|
|
806
|
-
// - else should update sync info, and adopt both removal and change.
|
|
807
|
-
(await this.getOrMakeChildNodeForInfo(origChildNode)).removeObj('sync');
|
|
955
|
+
const origChild = await this.getOrMakeChildNodeForInfo(origChildNode);
|
|
956
|
+
const removalsToUpload = (await this.removeChildrenObjsInSyncedStorage([origChild], 'sync', true));
|
|
957
|
+
this.uploadRemovalOfObjs(removalsToUpload);
|
|
808
958
|
return newVersion;
|
|
809
959
|
}
|
|
810
960
|
async diffCurrentAndRemote(remoteVersion) {
|
|
@@ -907,6 +1057,20 @@ function nodeToListingEntry({ name, type }) {
|
|
|
907
1057
|
return { name };
|
|
908
1058
|
}
|
|
909
1059
|
}
|
|
1060
|
+
function typeOfNode(nodeInfo) {
|
|
1061
|
+
if (nodeInfo.isFolder) {
|
|
1062
|
+
return 'folder';
|
|
1063
|
+
}
|
|
1064
|
+
else if (nodeInfo.isFile) {
|
|
1065
|
+
return 'file';
|
|
1066
|
+
}
|
|
1067
|
+
else if (nodeInfo.isLink) {
|
|
1068
|
+
return 'link';
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
throw new Error(`Unknown type of node info`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
910
1074
|
function addToTransitionState(state, f, key) {
|
|
911
1075
|
const nodeInfo = {
|
|
912
1076
|
name: f.name,
|
|
@@ -68,7 +68,7 @@ class XspFS {
|
|
|
68
68
|
}
|
|
69
69
|
storage() {
|
|
70
70
|
if (!this.store) {
|
|
71
|
-
throw (0, file_1.makeFileException)(
|
|
71
|
+
throw (0, file_1.makeFileException)('storageClosed', this.name);
|
|
72
72
|
}
|
|
73
73
|
return this.store;
|
|
74
74
|
}
|
|
@@ -146,8 +146,10 @@ class XspFS {
|
|
|
146
146
|
const folder = (await parentFolder.getFolder(folderName)
|
|
147
147
|
.catch(setExcPath(path)));
|
|
148
148
|
if (!removeContent && !folder.isEmpty()) {
|
|
149
|
-
throw (0, file_1.makeFileException)(
|
|
149
|
+
throw (0, file_1.makeFileException)('notEmpty', path);
|
|
150
150
|
}
|
|
151
|
+
// note that internal folder.delete() removes all children as a matter
|
|
152
|
+
// of not leaving inaccessible nodes, i.e. content is removed implicitly
|
|
151
153
|
await parentFolder.removeChild(folder);
|
|
152
154
|
}
|
|
153
155
|
async deleteFile(path) {
|
|
@@ -252,17 +254,11 @@ class XspFS {
|
|
|
252
254
|
return true;
|
|
253
255
|
}
|
|
254
256
|
else if (throwIfMissing) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
257
|
+
switch (type) {
|
|
258
|
+
case 'file': throw (0, file_1.makeFileException)('notFile', path);
|
|
259
|
+
case 'folder': throw (0, file_1.makeFileException)('notDirectory', path);
|
|
260
|
+
case 'link': throw (0, file_1.makeFileException)('notLink', path);
|
|
258
261
|
}
|
|
259
|
-
else if (type === 'folder') {
|
|
260
|
-
code = file_1.Code.notDirectory;
|
|
261
|
-
}
|
|
262
|
-
else if (type === 'link') {
|
|
263
|
-
code = file_1.Code.notLink;
|
|
264
|
-
}
|
|
265
|
-
throw (0, file_1.makeFileException)(code, path);
|
|
266
262
|
}
|
|
267
263
|
else {
|
|
268
264
|
return false;
|
|
@@ -415,14 +411,14 @@ class XspFS {
|
|
|
415
411
|
const exists = await this.checkFilePresence(path);
|
|
416
412
|
if (exists) {
|
|
417
413
|
if (flags.create && flags.exclusive) {
|
|
418
|
-
throw (0, file_1.makeFileException)(
|
|
414
|
+
throw (0, file_1.makeFileException)('alreadyExists', path);
|
|
419
415
|
}
|
|
420
416
|
const fNode = await this.v.getOrCreateFile(path, flags);
|
|
421
417
|
return (0, files_1.wrapWritableFile)(file_2.FileObject.makeExisting(fNode, true));
|
|
422
418
|
}
|
|
423
419
|
else {
|
|
424
420
|
if (!flags.create) {
|
|
425
|
-
throw (0, file_1.makeFileException)(
|
|
421
|
+
throw (0, file_1.makeFileException)('notFound', path);
|
|
426
422
|
}
|
|
427
423
|
return (0, files_1.wrapWritableFile)(file_2.FileObject.makeForNotExisiting(path_1.posix.basename(path), () => this.v.getOrCreateFile(path, flags), !!this.v.sync));
|
|
428
424
|
}
|
|
@@ -512,7 +508,7 @@ class V {
|
|
|
512
508
|
}
|
|
513
509
|
getRootIfNotClosed(excPath) {
|
|
514
510
|
if (!this.rootNode) {
|
|
515
|
-
throw (0, file_1.makeFileException)(
|
|
511
|
+
throw (0, file_1.makeFileException)('storageClosed', excPath);
|
|
516
512
|
}
|
|
517
513
|
return this.rootNode;
|
|
518
514
|
}
|
|
@@ -525,7 +521,7 @@ class V {
|
|
|
525
521
|
.catch(setExcPath(path));
|
|
526
522
|
if (file) {
|
|
527
523
|
if (exclusive) {
|
|
528
|
-
throw (0, file_1.makeFileException)(
|
|
524
|
+
throw (0, file_1.makeFileException)('alreadyExists', path);
|
|
529
525
|
}
|
|
530
526
|
}
|
|
531
527
|
else {
|
|
@@ -591,7 +587,7 @@ class V {
|
|
|
591
587
|
return { txt, version };
|
|
592
588
|
}
|
|
593
589
|
catch (err) {
|
|
594
|
-
throw (0, file_1.makeFileException)(
|
|
590
|
+
throw (0, file_1.makeFileException)('parsingError', path, err);
|
|
595
591
|
}
|
|
596
592
|
}
|
|
597
593
|
writeJSONFile(path, json, flags = WRITE_NONEXCL_FLAGS) {
|
|
@@ -605,7 +601,7 @@ class V {
|
|
|
605
601
|
return { json, version };
|
|
606
602
|
}
|
|
607
603
|
catch (err) {
|
|
608
|
-
throw (0, file_1.makeFileException)(
|
|
604
|
+
throw (0, file_1.makeFileException)('parsingError', path, err);
|
|
609
605
|
}
|
|
610
606
|
}
|
|
611
607
|
async getByteSink(path, flags = WRITE_NONEXCL_FLAGS) {
|
|
@@ -780,7 +776,7 @@ class S {
|
|
|
780
776
|
async getFolderNode(path) {
|
|
781
777
|
const node = await this.n.get(path);
|
|
782
778
|
if (node.type !== 'folder') {
|
|
783
|
-
throw (0, file_1.makeFileException)(
|
|
779
|
+
throw (0, file_1.makeFileException)('notDirectory', path);
|
|
784
780
|
}
|
|
785
781
|
return node;
|
|
786
782
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FSChangeSrc, Node, NodeType, Storage, SyncedStorage } from './common';
|
|
1
|
+
import { FSChangeSrc, Node, NodeType, Storage, SyncedStorage, UploadHeaderChange } from './common';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { CommonAttrs, XAttrs } from './attrs';
|
|
4
4
|
import { NodePersistance } from './node-persistence';
|
|
@@ -40,13 +40,8 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
|
|
|
40
40
|
archived?: number[];
|
|
41
41
|
}>;
|
|
42
42
|
archiveCurrent(version?: number): Promise<number>;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
* This non-synchronized method deletes object from storage, and detaches
|
|
46
|
-
* this node from storage. Make sure to call it inside access synchronization
|
|
47
|
-
* construct.
|
|
48
|
-
*/
|
|
49
|
-
protected delete(src: FSChangeSrc): Promise<void>;
|
|
43
|
+
removeNonFolderObj(src: FSChangeSrc): Promise<void>;
|
|
44
|
+
protected removeThisNodeAsLeaf(src: FSChangeSrc): Promise<void>;
|
|
50
45
|
/**
|
|
51
46
|
* This method runs node changing function in an exclusive manner.
|
|
52
47
|
* Returned promise resolves to whatever change function returns.
|
|
@@ -80,6 +75,6 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
|
|
|
80
75
|
createOnRemote: boolean;
|
|
81
76
|
} | undefined>;
|
|
82
77
|
upload(opts: OptionsToUploadLocal | undefined): Promise<void>;
|
|
83
|
-
|
|
78
|
+
protected uploadHeaderChange(localVersion: number, uploadVersion: number): Promise<UploadHeaderChange | undefined>;
|
|
84
79
|
}
|
|
85
80
|
export {};
|