core-3nweb-client-lib 0.26.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/asmail.d.ts +1 -1
- package/build/api-defs/files.d.ts +281 -75
- package/build/core/app-files.js +7 -7
- package/build/core/asmail/config/common.js +2 -2
- package/build/core/asmail/config/index.js +2 -2
- package/build/core/asmail/config/published-intro-key.js +1 -1
- package/build/core/asmail/delivery/common.js +7 -7
- package/build/core/asmail/delivery/index.js +5 -5
- package/build/core/asmail/delivery/msg.js +4 -4
- package/build/core/asmail/delivery/per-recipient-wip.js +1 -1
- package/build/core/asmail/inbox/attachments/fs.d.ts +2 -1
- package/build/core/asmail/inbox/attachments/fs.js +9 -4
- package/build/core/asmail/inbox/cached-msgs.js +1 -1
- package/build/core/asmail/inbox/inbox-events.js +4 -4
- package/build/core/asmail/inbox/index.js +10 -10
- package/build/core/asmail/inbox/msg-downloader.js +1 -1
- package/build/core/asmail/inbox/msg-indexing.js +1 -1
- package/build/core/asmail/inbox/msg-on-disk.js +5 -5
- package/build/core/asmail/index.d.ts +3 -3
- package/build/core/asmail/index.js +13 -8
- package/build/core/asmail/key-verification.js +5 -5
- package/build/core/asmail/keyring/common.js +7 -6
- package/build/core/asmail/keyring/correspondent-keys.js +8 -7
- package/build/core/asmail/keyring/id-to-email-map.js +2 -1
- package/build/core/asmail/keyring/index.d.ts +7 -8
- package/build/core/asmail/keyring/index.js +15 -14
- package/build/core/asmail/keyring/keyring-storage.js +2 -1
- package/build/core/asmail/msg/opener.js +3 -3
- package/build/core/asmail/msg/packer.js +13 -13
- package/build/core/asmail/sending-params/own-params.js +2 -2
- package/build/core/asmail/sending-params/params-from-others.js +1 -1
- package/build/core/id-manager/index.d.ts +43 -0
- package/build/core/{id-manager.js → id-manager/index.js} +36 -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.d.ts +2 -1
- package/build/core/index.js +31 -33
- package/build/core/sign-in.d.ts +1 -2
- package/build/core/sign-in.js +8 -17
- package/build/core/sign-up.d.ts +2 -0
- package/build/core/sign-up.js +11 -10
- package/build/core/storage/common/json-saving.js +2 -2
- package/build/core/storage/common/obj-info-file.d.ts +12 -4
- package/build/core/storage/common/obj-info-file.js +66 -34
- package/build/core/storage/common/utils.d.ts +2 -0
- package/build/core/storage/common/utils.js +32 -0
- package/build/core/storage/index.d.ts +5 -17
- package/build/core/storage/index.js +78 -119
- package/build/core/storage/local/obj-files-gc.d.ts +2 -0
- package/build/core/storage/local/obj-files-gc.js +49 -37
- package/build/core/storage/local/obj-files.d.ts +4 -7
- package/build/core/storage/local/obj-files.js +7 -10
- package/build/core/storage/local/obj-status.d.ts +12 -6
- package/build/core/storage/local/obj-status.js +24 -9
- package/build/core/storage/local/storage.d.ts +10 -7
- package/build/core/storage/local/storage.js +29 -18
- package/build/core/storage/synced/downloader.js +1 -1
- package/build/core/storage/synced/obj-files-gc.d.ts +1 -0
- package/build/core/storage/synced/obj-files-gc.js +76 -39
- package/build/core/storage/synced/obj-files.d.ts +50 -36
- package/build/core/storage/synced/obj-files.js +201 -162
- package/build/core/storage/synced/obj-status.d.ts +99 -86
- package/build/core/storage/synced/obj-status.js +520 -251
- package/build/core/storage/synced/remote-events.d.ts +11 -12
- package/build/core/storage/synced/remote-events.js +73 -56
- package/build/core/storage/synced/storage.d.ts +24 -10
- package/build/core/storage/synced/storage.js +147 -47
- package/build/core/storage/synced/upload-header-file.d.ts +4 -0
- package/build/core/storage/synced/upload-header-file.js +64 -0
- package/build/core/storage/synced/upsyncer.d.ts +12 -7
- package/build/core/storage/synced/upsyncer.js +210 -280
- package/build/core/storage/system-folders/apps-data.d.ts +16 -0
- package/build/core/storage/system-folders/apps-data.js +110 -0
- package/build/core/storage/system-folders/index.d.ts +18 -0
- package/build/core/storage/system-folders/index.js +77 -0
- package/build/core-ipc/common-caps.js +3 -3
- package/build/core-ipc/generic.js +8 -8
- package/build/core-ipc/startup-caps.js +2 -2
- package/build/cryptors.js +6 -2
- package/build/ipc-via-protobuf/asmail-cap.js +58 -57
- package/build/ipc-via-protobuf/bytes.js +16 -17
- package/build/ipc-via-protobuf/connector-clients-side.d.ts +1 -0
- package/build/ipc-via-protobuf/connector-clients-side.js +14 -15
- package/build/ipc-via-protobuf/connector-services-side.js +10 -10
- package/build/ipc-via-protobuf/connector.js +4 -4
- package/build/ipc-via-protobuf/file.d.ts +48 -12
- package/build/ipc-via-protobuf/file.js +474 -126
- package/build/ipc-via-protobuf/fs.d.ts +8 -0
- package/build/ipc-via-protobuf/fs.js +577 -142
- package/build/ipc-via-protobuf/log-cap.js +2 -2
- package/build/ipc-via-protobuf/mailerid.js +3 -3
- package/build/ipc-via-protobuf/protobuf-msg.d.ts +1 -0
- package/build/ipc-via-protobuf/protobuf-msg.js +11 -7
- package/build/ipc-via-protobuf/startup-cap.js +21 -21
- package/build/ipc-via-protobuf/storage-cap.js +12 -12
- package/build/ipc.js +7 -2
- package/build/lib-client/3nstorage/exceptions.d.ts +16 -1
- package/build/lib-client/3nstorage/exceptions.js +21 -3
- package/build/lib-client/3nstorage/service.d.ts +21 -3
- package/build/lib-client/3nstorage/service.js +128 -46
- package/build/lib-client/3nstorage/util/file-based-json.d.ts +2 -1
- package/build/lib-client/3nstorage/util/file-based-json.js +3 -2
- 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/attrs.js +17 -17
- package/build/lib-client/3nstorage/xsp-fs/common.d.ts +44 -19
- package/build/lib-client/3nstorage/xsp-fs/common.js +30 -19
- package/build/lib-client/3nstorage/xsp-fs/file-node.d.ts +1 -0
- package/build/lib-client/3nstorage/xsp-fs/file-node.js +17 -13
- package/build/lib-client/3nstorage/xsp-fs/file.d.ts +31 -6
- package/build/lib-client/3nstorage/xsp-fs/file.js +73 -25
- package/build/lib-client/3nstorage/xsp-fs/folder-node-serialization.js +4 -4
- package/build/lib-client/3nstorage/xsp-fs/folder-node.d.ts +32 -13
- package/build/lib-client/3nstorage/xsp-fs/folder-node.js +752 -192
- package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +35 -4
- package/build/lib-client/3nstorage/xsp-fs/fs.js +236 -119
- package/build/lib-client/3nstorage/xsp-fs/link-node.d.ts +1 -0
- package/build/lib-client/3nstorage/xsp-fs/link-node.js +7 -2
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +30 -29
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +232 -127
- package/build/lib-client/3nstorage/xsp-fs/node-persistence.d.ts +1 -1
- package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +17 -18
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +3 -3
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +53 -53
- package/build/lib-client/3nweb-signup.js +4 -4
- package/build/lib-client/asmail/recipient.js +15 -15
- package/build/lib-client/asmail/sender.js +22 -22
- package/build/lib-client/asmail/service-config.js +3 -3
- package/build/lib-client/cryptor/cryptor-in-worker.js +18 -16
- package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
- package/build/lib-client/cryptor/cryptor.js +4 -2
- package/build/lib-client/cryptor/cryptor.wasm +0 -0
- package/build/lib-client/cryptor/in-proc-js.js +1 -1
- package/build/lib-client/cryptor/in-proc-wasm.js +6 -6
- package/build/lib-client/cryptor/worker-js.js +2 -2
- package/build/lib-client/cryptor/worker-wasm.js +2 -2
- package/build/lib-client/files-select.js +1 -1
- package/build/lib-client/files.d.ts +1 -1
- package/build/lib-client/files.js +71 -6
- package/build/lib-client/fs-collection.js +1 -1
- package/build/lib-client/fs-sync-utils.d.ts +5 -0
- package/build/lib-client/fs-sync-utils.js +61 -0
- package/build/lib-client/fs-view.d.ts +14 -0
- package/build/lib-client/fs-view.js +33 -0
- package/build/lib-client/key-derivation.js +1 -1
- package/build/lib-client/local-files/dev-file-sink.js +9 -9
- package/build/lib-client/local-files/dev-file-src.js +2 -2
- package/build/lib-client/local-files/device-fs.d.ts +1 -1
- package/build/lib-client/local-files/device-fs.js +56 -54
- package/build/lib-client/logging/log-to-file.d.ts +1 -1
- package/build/lib-client/logging/log-to-file.js +7 -7
- package/build/lib-client/mailer-id/login.js +7 -7
- package/build/lib-client/mailer-id/provisioner.js +12 -12
- package/build/lib-client/objs-on-disk/file-writing-proc.js +3 -3
- package/build/lib-client/objs-on-disk/obj-folders.js +31 -31
- package/build/lib-client/objs-on-disk/obj-on-disk.d.ts +13 -2
- package/build/lib-client/objs-on-disk/obj-on-disk.js +24 -9
- package/build/lib-client/request-utils.d.ts +1 -0
- package/build/lib-client/request-utils.js +13 -13
- package/build/lib-client/server-events.d.ts +3 -3
- package/build/lib-client/server-events.js +9 -8
- package/build/lib-client/service-locator.js +10 -10
- package/build/lib-client/user-with-mid-session.d.ts +2 -1
- package/build/lib-client/user-with-mid-session.js +14 -8
- package/build/lib-client/user-with-pkl-session.js +25 -25
- package/build/lib-client/ws-utils.js +2 -2
- package/build/lib-common/async-cryptor-wrap.js +4 -4
- package/build/lib-common/async-fs-node.d.ts +5 -3
- package/build/lib-common/async-fs-node.js +17 -17
- package/build/lib-common/byte-streaming/pipe.js +1 -1
- package/build/lib-common/byte-streaming/wrapping.js +13 -13
- package/build/lib-common/canonical-address.js +1 -1
- package/build/lib-common/exceptions/error.d.ts +1 -0
- package/build/lib-common/exceptions/error.js +7 -6
- package/build/lib-common/exceptions/file.d.ts +4 -2
- package/build/lib-common/exceptions/file.js +24 -54
- package/build/lib-common/ipc/generic-ipc.js +5 -4
- package/build/lib-common/ipc/ws-ipc.js +2 -2
- package/build/lib-common/mid-sigs-NaCl-Ed.js +14 -14
- package/build/lib-common/objs-on-disk/file-layout.d.ts +19 -0
- package/build/lib-common/objs-on-disk/file-layout.js +130 -12
- package/build/lib-common/objs-on-disk/obj-file.d.ts +13 -2
- package/build/lib-common/objs-on-disk/obj-file.js +96 -35
- package/build/lib-common/objs-on-disk/utils.d.ts +1 -0
- package/build/lib-common/objs-on-disk/utils.js +3 -3
- package/build/lib-common/objs-on-disk/v1-obj-file-format.js +14 -14
- package/build/lib-common/processes/labelled-exec-pools.d.ts +1 -1
- package/build/lib-common/processes/labelled-exec-pools.js +1 -1
- package/build/lib-common/processes/pressure.js +2 -2
- package/build/lib-common/processes/synced.js +1 -1
- package/build/lib-common/processes/timeout.js +2 -2
- package/build/lib-common/random-node.js +7 -7
- package/build/lib-common/service-api/3nstorage/owner.d.ts +101 -42
- package/build/lib-common/service-api/3nstorage/owner.js +83 -40
- package/build/lib-common/service-api/asmail/delivery.js +2 -2
- package/build/lib-common/service-api/asmail/retrieval.js +1 -1
- package/build/lib-common/timed-cache.d.ts +1 -0
- package/build/lib-common/timed-non-weak-cache.d.ts +1 -0
- package/build/lib-common/timed-non-weak-cache.js +11 -0
- package/build/lib-common/utils-for-observables.js +4 -4
- package/build/lib-common/weak-cache.d.ts +1 -0
- package/build/lib-common/weak-cache.js +12 -1
- package/build/lib-index.d.ts +2 -1
- package/build/lib-index.js +10 -7
- package/build/protos/asmail.proto.js +12955 -7496
- package/build/protos/file.proto.js +4867 -2744
- package/build/protos/fs.proto.js +9227 -3768
- package/package.json +7 -5
- package/protos/file.proto +91 -19
- package/protos/fs.proto +107 -8
- package/build/core/id-manager.d.ts +0 -46
|
@@ -24,9 +24,11 @@ exports.FolderNode = void 0;
|
|
|
24
24
|
const buffer_utils_1 = require("../../../lib-common/buffer-utils");
|
|
25
25
|
const file_1 = require("../../../lib-common/exceptions/file");
|
|
26
26
|
const error_1 = require("../../../lib-common/exceptions/error");
|
|
27
|
+
const common_1 = require("./common");
|
|
27
28
|
const node_in_fs_1 = require("./node-in-fs");
|
|
28
29
|
const file_node_1 = require("./file-node");
|
|
29
30
|
const link_node_1 = require("./link-node");
|
|
31
|
+
const exceptions_1 = require("../exceptions");
|
|
30
32
|
const deferred_1 = require("../../../lib-common/processes/deferred");
|
|
31
33
|
const json_utils_1 = require("../../../lib-common/json-utils");
|
|
32
34
|
const xsp_files_1 = require("xsp-files");
|
|
@@ -34,9 +36,11 @@ const random = require("../../../lib-common/random-node");
|
|
|
34
36
|
const folder_node_serialization_1 = require("./folder-node-serialization");
|
|
35
37
|
const attrs_1 = require("./attrs");
|
|
36
38
|
const node_persistence_1 = require("./node-persistence");
|
|
39
|
+
const assert_1 = require("../../../lib-common/assert");
|
|
40
|
+
const for_arrays_1 = require("../util/for-arrays");
|
|
37
41
|
function jsonToInfoAndAttrs(json) {
|
|
38
42
|
const folderInfo = {
|
|
39
|
-
nodes: json_utils_1.copy(json.nodes)
|
|
43
|
+
nodes: (0, json_utils_1.copy)(json.nodes)
|
|
40
44
|
};
|
|
41
45
|
for (const node of Object.values(folderInfo.nodes)) {
|
|
42
46
|
node.key = buffer_utils_1.base64.open(node.key);
|
|
@@ -51,14 +55,22 @@ class FolderPersistance extends node_persistence_1.NodePersistance {
|
|
|
51
55
|
Object.seal(this);
|
|
52
56
|
}
|
|
53
57
|
async write(folderInfo, version, attrs, xattrs) {
|
|
54
|
-
const bytes = folder_node_serialization_1.serializeFolderInfo(folderInfo);
|
|
58
|
+
const bytes = (0, folder_node_serialization_1.serializeFolderInfo)(folderInfo);
|
|
55
59
|
return this.writeWhole(bytes, version, attrs, xattrs);
|
|
56
60
|
}
|
|
57
61
|
async read(src) {
|
|
58
62
|
const { content, xattrs, attrs } = await this.readAll(src);
|
|
59
|
-
const folderInfo = folder_node_serialization_1.parseFolderInfo(content);
|
|
63
|
+
const folderInfo = (0, folder_node_serialization_1.parseFolderInfo)(content);
|
|
60
64
|
return { folderInfo, xattrs, attrs: attrs_1.CommonAttrs.fromAttrs(attrs) };
|
|
61
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
|
+
}
|
|
62
74
|
}
|
|
63
75
|
Object.freeze(FolderPersistance.prototype);
|
|
64
76
|
Object.freeze(FolderPersistance);
|
|
@@ -77,18 +89,11 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
77
89
|
constructor(storage, name, objId, zNonce, version, parentId, key, setNewAttrs) {
|
|
78
90
|
super(storage, 'folder', name, objId, version, parentId);
|
|
79
91
|
this.currentState = { nodes: {} };
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
"have both objId and parent as nulls.");
|
|
92
|
+
if (name === undefined) {
|
|
93
|
+
(0, assert_1.assert)(!objId && !parentId, `Root folder must have both objId and parent as nulls.`);
|
|
83
94
|
}
|
|
84
95
|
else if (objId === null) {
|
|
85
|
-
new Error("Missing objId for non-root folder");
|
|
86
|
-
}
|
|
87
|
-
if (!zNonce) {
|
|
88
|
-
if (!objId) {
|
|
89
|
-
throw new Error(`Missing object id for folder, when zeroth nonce is not given`);
|
|
90
|
-
}
|
|
91
|
-
zNonce = xsp_files_1.idToHeaderNonce(objId);
|
|
96
|
+
throw new Error("Missing objId for non-root folder");
|
|
92
97
|
}
|
|
93
98
|
this.crypto = new FolderPersistance(zNonce, key, storage.cryptor);
|
|
94
99
|
if (setNewAttrs) {
|
|
@@ -104,20 +109,21 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
104
109
|
return rf;
|
|
105
110
|
}
|
|
106
111
|
static async rootFromObjBytes(storage, name, objId, src, key) {
|
|
107
|
-
|
|
108
|
-
if (!objId) {
|
|
109
|
-
const header = await src.readHeader();
|
|
110
|
-
zNonce = xsp_files_1.calculateNonce(header.subarray(0, xsp_files_1.NONCE_LENGTH), -src.version);
|
|
111
|
-
}
|
|
112
|
-
const rf = await FolderNode.readNodeFromObjBytes(storage, name, objId, zNonce, src, key);
|
|
112
|
+
const rf = await FolderNode.readNodeFromObjBytes(storage, name, objId, src, key);
|
|
113
113
|
rf.storage.nodes.set(rf);
|
|
114
114
|
return rf;
|
|
115
115
|
}
|
|
116
|
-
static async readNodeFromObjBytes(storage, name, objId,
|
|
116
|
+
static async readNodeFromObjBytes(storage, name, objId, src, key) {
|
|
117
|
+
let zNonce;
|
|
118
|
+
if (objId) {
|
|
119
|
+
zNonce = (0, xsp_files_1.idToHeaderNonce)(objId);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const header = await src.readHeader();
|
|
123
|
+
zNonce = (0, xsp_files_1.calculateNonce)(header.subarray(0, xsp_files_1.NONCE_LENGTH), -src.version);
|
|
124
|
+
}
|
|
117
125
|
const rf = new FolderNode(storage, name, objId, zNonce, src.version, undefined, key, false);
|
|
118
|
-
|
|
119
|
-
rf.currentState = folderInfo;
|
|
120
|
-
rf.setUpdatedParams(src.version, attrs, xattrs);
|
|
126
|
+
await rf.setCurrentStateFrom(src);
|
|
121
127
|
return rf;
|
|
122
128
|
}
|
|
123
129
|
static async rootFromLinkParams(storage, params) {
|
|
@@ -132,38 +138,112 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
132
138
|
existingNode.crypto.compareKey(params.fKey);
|
|
133
139
|
return existingNode;
|
|
134
140
|
}
|
|
135
|
-
const src = await storage.
|
|
141
|
+
const src = await storage.getObjSrc(params.objId);
|
|
136
142
|
const key = buffer_utils_1.base64.open(params.fKey);
|
|
137
143
|
return FolderNode.rootFromObjBytes(storage, params.folderName, params.objId, src, key);
|
|
138
144
|
}
|
|
139
145
|
static rootFromJSON(storage, name, folderJson) {
|
|
140
|
-
const rf = new FolderNode(storage, name, 'readonly-root', EMPTY_ARR, 0, undefined,
|
|
146
|
+
const rf = new FolderNode(storage, name, 'readonly-root', EMPTY_ARR, 0, undefined, EMPTY_ARR, false);
|
|
141
147
|
const { folderInfo, attrs, xattrs } = jsonToInfoAndAttrs(folderJson);
|
|
142
148
|
rf.currentState = folderInfo;
|
|
143
149
|
rf.setUpdatedParams(0, attrs, xattrs);
|
|
144
150
|
return rf;
|
|
145
151
|
}
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
async setCurrentStateFrom(src) {
|
|
153
|
+
const { folderInfo, attrs, xattrs } = await this.crypto.read(src);
|
|
154
|
+
this.currentState = folderInfo;
|
|
155
|
+
this.setUpdatedParams(src.version, attrs, xattrs);
|
|
156
|
+
}
|
|
157
|
+
async adoptRemote(opts) {
|
|
158
|
+
const objsToRm = await this.doChange(true, async () => {
|
|
159
|
+
try {
|
|
160
|
+
const adopted = await this.syncedStorage().adoptRemote(this.objId, opts);
|
|
161
|
+
if (!adopted) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const src = await this.storage.getObjSrc(this.objId, adopted);
|
|
165
|
+
const originalState = this.currentState;
|
|
166
|
+
await this.setCurrentStateFrom(src);
|
|
167
|
+
const newState = this.currentState;
|
|
168
|
+
const { renamedNodes, addedNodes, removedNodes } = identifyChanges(originalState.nodes, newState.nodes);
|
|
169
|
+
for (const node of removedNodes) {
|
|
170
|
+
const event = {
|
|
171
|
+
type: 'entry-removal',
|
|
172
|
+
src: 'sync',
|
|
173
|
+
path: this.name,
|
|
174
|
+
newVersion: this.version,
|
|
175
|
+
name: node.name
|
|
176
|
+
};
|
|
177
|
+
this.broadcastEvent(event, false, node.objId);
|
|
178
|
+
}
|
|
179
|
+
for (const node of addedNodes) {
|
|
180
|
+
const event = {
|
|
181
|
+
type: 'entry-addition',
|
|
182
|
+
src: 'sync',
|
|
183
|
+
entry: nodeInfoToListingEntry(node),
|
|
184
|
+
path: this.name,
|
|
185
|
+
newVersion: this.version
|
|
186
|
+
};
|
|
187
|
+
this.broadcastEvent(event, false, node.objId);
|
|
188
|
+
}
|
|
189
|
+
for (const { objId, oldName, newName } of renamedNodes) {
|
|
190
|
+
const event = {
|
|
191
|
+
type: 'entry-renaming',
|
|
192
|
+
src: 'sync',
|
|
193
|
+
oldName,
|
|
194
|
+
newName,
|
|
195
|
+
path: this.name,
|
|
196
|
+
newVersion: this.version
|
|
197
|
+
};
|
|
198
|
+
this.broadcastEvent(event, false, objId);
|
|
199
|
+
}
|
|
200
|
+
return removedNodes;
|
|
157
201
|
}
|
|
158
|
-
|
|
159
|
-
|
|
202
|
+
catch (exc) {
|
|
203
|
+
throw (0, common_1.setPathInExc)(exc, this.name);
|
|
160
204
|
}
|
|
161
|
-
|
|
205
|
+
});
|
|
206
|
+
if (!objsToRm) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
for (const objToRm of objsToRm) {
|
|
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);
|
|
162
217
|
}
|
|
218
|
+
else {
|
|
219
|
+
node.removeNonFolderObj(src);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
list() {
|
|
223
|
+
const lst = Object.values(this.currentState.nodes)
|
|
224
|
+
.map(nodeInfoToListingEntry);
|
|
163
225
|
return { lst, version: this.version };
|
|
164
226
|
}
|
|
165
|
-
|
|
166
|
-
|
|
227
|
+
async childExistsInSyncedVersion(childObjId) {
|
|
228
|
+
const { state, synced } = await this.syncStatus();
|
|
229
|
+
if (state === 'synced') {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
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.`);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
167
247
|
}
|
|
168
248
|
getNodeInfo(name, undefOnMissing = false) {
|
|
169
249
|
const fj = this.currentState.nodes[name];
|
|
@@ -174,30 +254,12 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
174
254
|
return;
|
|
175
255
|
}
|
|
176
256
|
else {
|
|
177
|
-
throw file_1.makeFileException(
|
|
257
|
+
throw (0, file_1.makeFileException)('notFound', name);
|
|
178
258
|
}
|
|
179
259
|
}
|
|
180
260
|
hasChild(childName, throwIfMissing = false) {
|
|
181
261
|
return !!this.getNodeInfo(childName, !throwIfMissing);
|
|
182
262
|
}
|
|
183
|
-
/**
|
|
184
|
-
* @param objId
|
|
185
|
-
* @return either node (promise for node), or a deferred, which promise has
|
|
186
|
-
* been registered under a given id, and, therefore, has to be resolved with
|
|
187
|
-
* node.
|
|
188
|
-
*/
|
|
189
|
-
getNodeOrArrangePromise(objId) {
|
|
190
|
-
const { node, nodePromise } = this.storage.nodes.getNodeOrPromise(objId);
|
|
191
|
-
if (node) {
|
|
192
|
-
return { nodeOrPromise: node };
|
|
193
|
-
}
|
|
194
|
-
if (nodePromise) {
|
|
195
|
-
return { nodeOrPromise: nodePromise };
|
|
196
|
-
}
|
|
197
|
-
const deferred = deferred_1.defer();
|
|
198
|
-
this.storage.nodes.setPromise(objId, deferred.promise);
|
|
199
|
-
return { deferred };
|
|
200
|
-
}
|
|
201
263
|
async getNode(type, name, undefOnMissing = false) {
|
|
202
264
|
const childInfo = this.getNodeInfo(name, undefOnMissing);
|
|
203
265
|
if (!childInfo) {
|
|
@@ -205,36 +267,38 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
205
267
|
}
|
|
206
268
|
if (type) {
|
|
207
269
|
if ((type === 'file') && !childInfo.isFile) {
|
|
208
|
-
throw file_1.makeFileException(
|
|
270
|
+
throw (0, file_1.makeFileException)('notFile', childInfo.name);
|
|
209
271
|
}
|
|
210
272
|
else if ((type === 'folder') && !childInfo.isFolder) {
|
|
211
|
-
throw file_1.makeFileException(
|
|
273
|
+
throw (0, file_1.makeFileException)('notDirectory', childInfo.name);
|
|
212
274
|
}
|
|
213
275
|
else if ((type === 'link') && !childInfo.isLink) {
|
|
214
|
-
throw file_1.makeFileException(
|
|
276
|
+
throw (0, file_1.makeFileException)('notLink', childInfo.name);
|
|
215
277
|
}
|
|
216
278
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
279
|
+
return this.getOrMakeChildNodeForInfo(childInfo);
|
|
280
|
+
}
|
|
281
|
+
async getOrMakeChildNodeForInfo(info) {
|
|
282
|
+
const { node, nodePromise } = this.storage.nodes.getNodeOrPromise(info.objId);
|
|
283
|
+
if (node) {
|
|
284
|
+
return node;
|
|
285
|
+
}
|
|
286
|
+
if (nodePromise) {
|
|
287
|
+
return nodePromise;
|
|
220
288
|
}
|
|
289
|
+
const deferred = (0, deferred_1.defer)();
|
|
290
|
+
this.storage.nodes.setPromise(info.objId, deferred.promise);
|
|
221
291
|
try {
|
|
222
292
|
let node;
|
|
223
|
-
if (
|
|
224
|
-
node = await file_node_1.FileNode.makeForExisting(this.storage, this.objId, name,
|
|
225
|
-
}
|
|
226
|
-
else if (
|
|
227
|
-
const src = await this.storage.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
// f.currentState = folderInfo;
|
|
233
|
-
// f.attrs = (attrs ? attrs : AttrsHolder.makeReadonlyForFolder(0));
|
|
234
|
-
node = await FolderNode.readNodeFromObjBytes(this.storage, childInfo.name, childInfo.objId, undefined, src, childInfo.key);
|
|
235
|
-
}
|
|
236
|
-
else if (childInfo.isLink) {
|
|
237
|
-
node = await link_node_1.LinkNode.makeForExisting(this.storage, this.objId, name, childInfo.objId, childInfo.key);
|
|
293
|
+
if (info.isFile) {
|
|
294
|
+
node = await file_node_1.FileNode.makeForExisting(this.storage, this.objId, info.name, info.objId, info.key);
|
|
295
|
+
}
|
|
296
|
+
else if (info.isFolder) {
|
|
297
|
+
const src = await this.storage.getObjSrc(info.objId);
|
|
298
|
+
node = await FolderNode.readNodeFromObjBytes(this.storage, info.name, info.objId, src, info.key);
|
|
299
|
+
}
|
|
300
|
+
else if (info.isLink) {
|
|
301
|
+
node = await link_node_1.LinkNode.makeForExisting(this.storage, this.objId, info.name, info.objId, info.key);
|
|
238
302
|
}
|
|
239
303
|
else {
|
|
240
304
|
throw new Error(`Unknown type of fs node`);
|
|
@@ -245,9 +309,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
245
309
|
catch (exc) {
|
|
246
310
|
deferred.reject(exc);
|
|
247
311
|
if (exc.objNotFound) {
|
|
248
|
-
await this.fixMissingChildAndThrow(exc,
|
|
312
|
+
await this.fixMissingChildAndThrow(exc, info);
|
|
249
313
|
}
|
|
250
|
-
throw error_1.errWithCause(exc, `
|
|
314
|
+
throw (0, error_1.errWithCause)(exc, `Failed to instantiate fs node '${this.name}/${info.name}'`);
|
|
251
315
|
}
|
|
252
316
|
}
|
|
253
317
|
getFolder(name, undefOnMissing = false) {
|
|
@@ -261,16 +325,21 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
261
325
|
}
|
|
262
326
|
async fixMissingChildAndThrow(exc, childInfo) {
|
|
263
327
|
await this.doTransition(async (state, version) => {
|
|
328
|
+
const presentChild = state.nodes[childInfo.name];
|
|
329
|
+
if (!presentChild || (presentChild.objId !== childInfo.objId)) {
|
|
330
|
+
return [];
|
|
331
|
+
}
|
|
264
332
|
delete state.nodes[childInfo.name];
|
|
265
333
|
const event = {
|
|
266
334
|
type: 'entry-removal',
|
|
267
335
|
path: this.name,
|
|
336
|
+
src: 'local',
|
|
268
337
|
name: childInfo.name,
|
|
269
338
|
newVersion: version
|
|
270
339
|
};
|
|
271
|
-
return event;
|
|
340
|
+
return { event, childObjId: childInfo.objId };
|
|
272
341
|
}).catch(noop);
|
|
273
|
-
const fileExc = file_1.makeFileException(
|
|
342
|
+
const fileExc = (0, file_1.makeFileException)('notFound', childInfo.name, exc);
|
|
274
343
|
fileExc.inconsistentStateOfFS = true;
|
|
275
344
|
throw fileExc;
|
|
276
345
|
}
|
|
@@ -289,11 +358,11 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
289
358
|
async performTransition(change) {
|
|
290
359
|
// start transition and prepare transition state
|
|
291
360
|
// Note on copy: byte arrays are not cloned
|
|
292
|
-
const state = json_utils_1.copy(this.currentState);
|
|
361
|
+
const state = (0, json_utils_1.copy)(this.currentState);
|
|
293
362
|
const version = this.version + 1;
|
|
294
363
|
const attrs = this.attrs.copy();
|
|
295
364
|
// do action within transition state
|
|
296
|
-
const
|
|
365
|
+
const changeEvents = await change(state, version);
|
|
297
366
|
// save transition state
|
|
298
367
|
const encSub = await this.crypto.write(state, version, attrs, this.xattrs);
|
|
299
368
|
await this.storage.saveObj(this.objId, version, encSub);
|
|
@@ -301,7 +370,15 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
301
370
|
this.currentState = state;
|
|
302
371
|
this.setCurrentVersion(version);
|
|
303
372
|
this.attrs = attrs;
|
|
304
|
-
|
|
373
|
+
if (Array.isArray(changeEvents)) {
|
|
374
|
+
for (const { event, childObjId } of changeEvents) {
|
|
375
|
+
this.broadcastEvent(event, false, childObjId);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
const { event, childObjId } = changeEvents;
|
|
380
|
+
this.broadcastEvent(event, false, childObjId);
|
|
381
|
+
}
|
|
305
382
|
}
|
|
306
383
|
/**
|
|
307
384
|
* This function only creates folder node, but it doesn't insert it anywhere.
|
|
@@ -310,7 +387,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
310
387
|
async makeAndSaveNewChildFolderNode(name, changes) {
|
|
311
388
|
const key = await random.bytes(xsp_files_1.KEY_LENGTH);
|
|
312
389
|
const childObjId = await this.storage.generateNewObjId();
|
|
313
|
-
const node = new FolderNode(this.storage, name, childObjId,
|
|
390
|
+
const node = new FolderNode(this.storage, name, childObjId, (0, xsp_files_1.idToHeaderNonce)(childObjId), 0, this.objId, key, true);
|
|
314
391
|
await node.saveFirstVersion(changes).catch((exc) => {
|
|
315
392
|
if (!exc.objExists) {
|
|
316
393
|
throw exc;
|
|
@@ -369,7 +446,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
369
446
|
// do check for concurrent creation of a node
|
|
370
447
|
if (this.getNodeInfo(name, true)) {
|
|
371
448
|
if (exclusive) {
|
|
372
|
-
throw file_1.makeFileException(
|
|
449
|
+
throw (0, file_1.makeFileException)('alreadyExists', name);
|
|
373
450
|
}
|
|
374
451
|
else if (type === 'folder') {
|
|
375
452
|
return (await this.getNode('folder', name));
|
|
@@ -405,15 +482,11 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
405
482
|
const event = {
|
|
406
483
|
type: 'entry-addition',
|
|
407
484
|
path: this.name,
|
|
485
|
+
src: 'local',
|
|
408
486
|
newVersion: version,
|
|
409
|
-
entry:
|
|
410
|
-
name: node.name,
|
|
411
|
-
isFile: (node.type === 'file'),
|
|
412
|
-
isFolder: (node.type === 'folder'),
|
|
413
|
-
isLink: (node.type === 'link')
|
|
414
|
-
}
|
|
487
|
+
entry: nodeToListingEntry(node)
|
|
415
488
|
};
|
|
416
|
-
return event;
|
|
489
|
+
return { event, childObjId: node.objId };
|
|
417
490
|
});
|
|
418
491
|
return node;
|
|
419
492
|
});
|
|
@@ -437,15 +510,16 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
437
510
|
const event = {
|
|
438
511
|
type: 'entry-removal',
|
|
439
512
|
path: this.name,
|
|
513
|
+
src: 'local',
|
|
440
514
|
name: f.name,
|
|
441
515
|
newVersion: version
|
|
442
516
|
};
|
|
443
|
-
return event;
|
|
517
|
+
return { event, childObjId: f.objId };
|
|
444
518
|
});
|
|
445
519
|
// explicitly do not wait on a result of child's delete, cause if it fails
|
|
446
520
|
// we just get traceable garbage, yet, the rest of a live/non-deleted tree
|
|
447
521
|
// stays consistent
|
|
448
|
-
|
|
522
|
+
this.callRemoveObjOn('local', f);
|
|
449
523
|
}
|
|
450
524
|
changeChildName(initName, newName) {
|
|
451
525
|
return this.doTransition(async (state, version) => {
|
|
@@ -460,16 +534,17 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
460
534
|
const event = {
|
|
461
535
|
type: 'entry-renaming',
|
|
462
536
|
path: this.name,
|
|
537
|
+
src: 'local',
|
|
463
538
|
newName,
|
|
464
539
|
oldName: initName,
|
|
465
540
|
newVersion: version
|
|
466
541
|
};
|
|
467
|
-
return event;
|
|
542
|
+
return { event, childObjId: child.objId };
|
|
468
543
|
});
|
|
469
544
|
}
|
|
470
545
|
async moveChildTo(childName, dst, nameInDst) {
|
|
471
546
|
if (dst.hasChild(nameInDst)) {
|
|
472
|
-
throw file_1.makeFileException(
|
|
547
|
+
throw (0, file_1.makeFileException)('alreadyExists', nameInDst);
|
|
473
548
|
}
|
|
474
549
|
if (dst === this) {
|
|
475
550
|
// In this case we only need to change child's name
|
|
@@ -480,40 +555,38 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
480
555
|
// we have two transitions here, in this and in dst.
|
|
481
556
|
const moveLabel = getMoveLabel();
|
|
482
557
|
await dst.moveChildIn(nameInDst, childJSON, moveLabel);
|
|
483
|
-
await this.moveChildOut(childName, moveLabel);
|
|
558
|
+
await this.moveChildOut(childName, childJSON.objId, moveLabel);
|
|
484
559
|
}
|
|
485
560
|
}
|
|
486
|
-
async moveChildOut(name, moveLabel) {
|
|
561
|
+
async moveChildOut(name, childObjId, moveLabel) {
|
|
487
562
|
await this.doTransition(async (state, version) => {
|
|
563
|
+
const child = state.nodes[name];
|
|
488
564
|
delete state.nodes[name];
|
|
489
565
|
const event = {
|
|
490
566
|
type: 'entry-removal',
|
|
491
567
|
path: this.name,
|
|
568
|
+
src: 'local',
|
|
492
569
|
name,
|
|
493
570
|
newVersion: version,
|
|
494
571
|
moveLabel
|
|
495
572
|
};
|
|
496
|
-
return event;
|
|
573
|
+
return { event, childObjId };
|
|
497
574
|
});
|
|
498
575
|
}
|
|
499
576
|
async moveChildIn(newName, child, moveLabel) {
|
|
500
|
-
child = json_utils_1.copy(child);
|
|
577
|
+
child = (0, json_utils_1.copy)(child);
|
|
501
578
|
await this.doTransition(async (state, version) => {
|
|
502
579
|
child.name = newName;
|
|
503
580
|
state.nodes[child.name] = child;
|
|
504
581
|
const event = {
|
|
505
582
|
type: 'entry-addition',
|
|
506
583
|
path: this.name,
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
isFile: child.isFile,
|
|
510
|
-
isFolder: child.isFolder,
|
|
511
|
-
isLink: child.isLink
|
|
512
|
-
},
|
|
584
|
+
src: 'local',
|
|
585
|
+
entry: nodeInfoToListingEntry(child),
|
|
513
586
|
newVersion: version,
|
|
514
587
|
moveLabel
|
|
515
588
|
};
|
|
516
|
-
return event;
|
|
589
|
+
return { event, childObjId: child.objId };
|
|
517
590
|
});
|
|
518
591
|
}
|
|
519
592
|
async getFolderInThisSubTree(path, createIfMissing = false, exclusiveCreate = false) {
|
|
@@ -526,7 +599,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
526
599
|
// existing folder at this point
|
|
527
600
|
if (path.length === 1) {
|
|
528
601
|
if (exclusiveCreate) {
|
|
529
|
-
throw file_1.makeFileException(
|
|
602
|
+
throw (0, file_1.makeFileException)('alreadyExists', path[0]);
|
|
530
603
|
}
|
|
531
604
|
else {
|
|
532
605
|
return f;
|
|
@@ -583,28 +656,91 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
583
656
|
}
|
|
584
657
|
return content;
|
|
585
658
|
}
|
|
586
|
-
async
|
|
587
|
-
|
|
588
|
-
|
|
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;
|
|
589
667
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
this.broadcastEvent(event, true);
|
|
601
|
-
// explicitly do not wait on a result of child's delete, cause if it fails
|
|
602
|
-
// we just get traceable garbage, yet, the rest of a live/non-deleted tree
|
|
603
|
-
// stays consistent
|
|
604
|
-
for (const node of childrenNodes) {
|
|
605
|
-
node.localDelete();
|
|
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);
|
|
606
678
|
}
|
|
607
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;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
async uploadRemovalOfObjs(objsToRm) {
|
|
741
|
+
objsToRm.sort(); // shuffle order
|
|
742
|
+
await Promise.allSettled(objsToRm.map(objToRm => this.syncedStorage().uploadObjRemoval(objToRm)));
|
|
743
|
+
}
|
|
608
744
|
getParamsForLink() {
|
|
609
745
|
if ((this.storage.type !== 'synced') && (this.storage.type !== 'local')) {
|
|
610
746
|
throw new Error(`Creating link parameters to object in ${this.storage.type} file system, is not implemented.`);
|
|
@@ -621,77 +757,270 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
621
757
|
};
|
|
622
758
|
return linkParams;
|
|
623
759
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
760
|
+
async upload(opts) {
|
|
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
|
+
}
|
|
638
780
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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
|
+
}
|
|
822
|
+
}
|
|
823
|
+
async needUpload(localVersion) {
|
|
824
|
+
const toUpload = await super.needUpload(localVersion);
|
|
825
|
+
if (!toUpload) {
|
|
642
826
|
return;
|
|
643
827
|
}
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
828
|
+
const storage = this.syncedStorage();
|
|
829
|
+
if (toUpload.localVersion === this.version) {
|
|
830
|
+
for (const { objId, name } of Object.values(this.currentState.nodes)) {
|
|
831
|
+
if ((await storage.status(objId)).neverUploaded()) {
|
|
832
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
833
|
+
childNeverUploaded: true, childName: name
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
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
|
+
});
|
|
844
|
+
}
|
|
845
|
+
return toUpload;
|
|
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
|
+
}
|
|
862
|
+
async adoptRemoteFolderItem(itemName, opts) {
|
|
863
|
+
if (opts === null || opts === void 0 ? void 0 : opts.localVersion) {
|
|
864
|
+
if (this.version !== opts.localVersion) {
|
|
865
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
866
|
+
versionMismatch: true,
|
|
867
|
+
message: `Given local version ${opts.localVersion} is not equal to current ${this.version}`
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
const { remote } = await this.syncStatus();
|
|
872
|
+
if (!remote) {
|
|
873
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
874
|
+
versionMismatch: true,
|
|
875
|
+
message: `No remote versions`
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
if (opts === null || opts === void 0 ? void 0 : opts.remoteVersion) {
|
|
879
|
+
if (opts.remoteVersion !== remote.latest) {
|
|
880
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
881
|
+
versionMismatch: true,
|
|
882
|
+
message: `Unknown remote version ${opts.remoteVersion}`
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
else if (!remote.latest) {
|
|
887
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
888
|
+
remoteIsArchived: true
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
const storage = this.syncedStorage();
|
|
892
|
+
const srcOfRemote = await storage.getObjSrcOfRemoteVersion(this.objId, remote.latest);
|
|
893
|
+
const { folderInfo: { nodes: remoteNodes } } = await this.crypto.read(srcOfRemote);
|
|
894
|
+
const remoteChildNode = remoteNodes[itemName];
|
|
895
|
+
if (!remoteChildNode) {
|
|
896
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
897
|
+
remoteFolderItemNotFound: true,
|
|
898
|
+
message: `Item '${itemName}' is not found in remote version`
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
const localNodeToRm = this.getNodeInfo(itemName, true);
|
|
902
|
+
if (!localNodeToRm) {
|
|
903
|
+
return await this.addRemoteChild(remoteChildNode);
|
|
904
|
+
}
|
|
905
|
+
else if (localNodeToRm.objId === remoteChildNode.objId) {
|
|
906
|
+
(0, assert_1.assert)(typeOfNode(localNodeToRm) === typeOfNode(remoteChildNode));
|
|
907
|
+
// XXX
|
|
908
|
+
throw new Error(`Adaptation of changing keys needs implementation`);
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
return await this.replaceLocalChildWithRemote(remoteChildNode);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
async addRemoteChild(remoteChildNode) {
|
|
915
|
+
let newVersion;
|
|
916
|
+
await this.doTransition(async (state, version) => {
|
|
917
|
+
newVersion = version;
|
|
918
|
+
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
656
919
|
const event = {
|
|
657
|
-
type: 'entry-
|
|
920
|
+
type: 'entry-addition',
|
|
658
921
|
path: this.name,
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
newName: addedEntries[0],
|
|
922
|
+
src: 'sync',
|
|
923
|
+
entry: nodeInfoToListingEntry(remoteChildNode),
|
|
662
924
|
newVersion
|
|
663
925
|
};
|
|
664
|
-
|
|
926
|
+
return { event, childObjId: remoteChildNode.objId };
|
|
927
|
+
});
|
|
928
|
+
return newVersion;
|
|
929
|
+
}
|
|
930
|
+
async replaceLocalChildWithRemote(remoteChildNode) {
|
|
931
|
+
let origChildNode;
|
|
932
|
+
let newVersion;
|
|
933
|
+
await this.doTransition(async (state, version) => {
|
|
934
|
+
newVersion = version;
|
|
935
|
+
origChildNode = state.nodes[remoteChildNode.name];
|
|
936
|
+
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
937
|
+
const additionEvent = {
|
|
938
|
+
type: 'entry-addition',
|
|
939
|
+
path: this.name,
|
|
940
|
+
src: 'sync',
|
|
941
|
+
entry: nodeInfoToListingEntry(remoteChildNode),
|
|
942
|
+
newVersion
|
|
943
|
+
};
|
|
944
|
+
const rmEvent = {
|
|
945
|
+
type: 'entry-removal',
|
|
946
|
+
path: this.name,
|
|
947
|
+
src: 'sync',
|
|
948
|
+
name: origChildNode.name
|
|
949
|
+
};
|
|
950
|
+
return [
|
|
951
|
+
{ event: rmEvent, childObjId: origChildNode.objId },
|
|
952
|
+
{ event: additionEvent, childObjId: remoteChildNode.objId }
|
|
953
|
+
];
|
|
954
|
+
});
|
|
955
|
+
const origChild = await this.getOrMakeChildNodeForInfo(origChildNode);
|
|
956
|
+
const removalsToUpload = (await this.removeChildrenObjsInSyncedStorage([origChild], 'sync', true));
|
|
957
|
+
this.uploadRemovalOfObjs(removalsToUpload);
|
|
958
|
+
return newVersion;
|
|
959
|
+
}
|
|
960
|
+
async diffCurrentAndRemote(remoteVersion) {
|
|
961
|
+
var _a;
|
|
962
|
+
const { state, remote } = await this.syncStatus();
|
|
963
|
+
let isCurrentLocal;
|
|
964
|
+
if (state === 'behind') {
|
|
965
|
+
isCurrentLocal = false;
|
|
966
|
+
}
|
|
967
|
+
else if (state === 'conflicting') {
|
|
968
|
+
isCurrentLocal = true;
|
|
665
969
|
}
|
|
666
970
|
else {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
newVersion
|
|
690
|
-
};
|
|
691
|
-
this.broadcastEvent(event);
|
|
692
|
-
});
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
if (remote.isArchived) {
|
|
974
|
+
return this.diffWithArchivedRemote(isCurrentLocal);
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
if (remoteVersion) {
|
|
978
|
+
if ((remoteVersion !== remote.latest)
|
|
979
|
+
&& !((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(remoteVersion))) {
|
|
980
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
981
|
+
versionMismatch: true,
|
|
982
|
+
message: `Unknown remote version ${remoteVersion}`
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
remoteVersion = remote.latest;
|
|
988
|
+
}
|
|
989
|
+
const storage = this.syncedStorage();
|
|
990
|
+
const srcOfRemote = await storage.getObjSrcOfRemoteVersion(this.objId, remote.latest);
|
|
991
|
+
const { folderInfo, attrs, xattrs } = await this.crypto.read(srcOfRemote);
|
|
992
|
+
return this.diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs);
|
|
693
993
|
}
|
|
694
994
|
}
|
|
995
|
+
diffWithArchivedRemote(isCurrentLocal) {
|
|
996
|
+
return {
|
|
997
|
+
currentVersion: this.version,
|
|
998
|
+
isCurrentLocal,
|
|
999
|
+
isRemoteArchived: true,
|
|
1000
|
+
ctime: {
|
|
1001
|
+
current: new Date(this.attrs.ctime)
|
|
1002
|
+
},
|
|
1003
|
+
mtime: {
|
|
1004
|
+
current: new Date(this.attrs.ctime)
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs) {
|
|
1009
|
+
const { ctime, mtime } = diffAttrs(this.attrs, attrs);
|
|
1010
|
+
const { inCurrent, inRemote, nameOverlaps } = diffNodes(this.currentState, folderInfo);
|
|
1011
|
+
return {
|
|
1012
|
+
currentVersion: this.version,
|
|
1013
|
+
isCurrentLocal,
|
|
1014
|
+
isRemoteArchived: false,
|
|
1015
|
+
remoteVersion,
|
|
1016
|
+
inCurrent,
|
|
1017
|
+
inRemote,
|
|
1018
|
+
nameOverlaps,
|
|
1019
|
+
ctime,
|
|
1020
|
+
mtime,
|
|
1021
|
+
xattrs: diffXAttrs(this.xattrs, xattrs)
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
695
1024
|
}
|
|
696
1025
|
exports.FolderNode = FolderNode;
|
|
697
1026
|
Object.freeze(FolderNode.prototype);
|
|
@@ -702,6 +1031,46 @@ function checkFolderInfo(folderJson) {
|
|
|
702
1031
|
// TODO throw if folderJson is not ok
|
|
703
1032
|
return folderJson;
|
|
704
1033
|
}
|
|
1034
|
+
function nodeInfoToListingEntry({ name, isFile, isFolder, isLink }) {
|
|
1035
|
+
if (isFolder) {
|
|
1036
|
+
return { name, isFolder };
|
|
1037
|
+
}
|
|
1038
|
+
else if (isFile) {
|
|
1039
|
+
return { name, isFile };
|
|
1040
|
+
}
|
|
1041
|
+
else if (isLink) {
|
|
1042
|
+
return { name, isLink };
|
|
1043
|
+
}
|
|
1044
|
+
else {
|
|
1045
|
+
return { name };
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
function nodeToListingEntry({ name, type }) {
|
|
1049
|
+
switch (type) {
|
|
1050
|
+
case 'file':
|
|
1051
|
+
return { name, isFolder: true };
|
|
1052
|
+
case 'folder':
|
|
1053
|
+
return { name, isFolder: true };
|
|
1054
|
+
case 'link':
|
|
1055
|
+
return { name, isLink: true };
|
|
1056
|
+
default:
|
|
1057
|
+
return { name };
|
|
1058
|
+
}
|
|
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
|
+
}
|
|
705
1074
|
function addToTransitionState(state, f, key) {
|
|
706
1075
|
const nodeInfo = {
|
|
707
1076
|
name: f.name,
|
|
@@ -722,4 +1091,195 @@ function addToTransitionState(state, f, key) {
|
|
|
722
1091
|
}
|
|
723
1092
|
state.nodes[nodeInfo.name] = nodeInfo;
|
|
724
1093
|
}
|
|
1094
|
+
function diffAttrs(current, remote) {
|
|
1095
|
+
return {
|
|
1096
|
+
ctime: {
|
|
1097
|
+
current: new Date(current.ctime),
|
|
1098
|
+
remote: new Date(remote.ctime)
|
|
1099
|
+
},
|
|
1100
|
+
mtime: {
|
|
1101
|
+
current: new Date(current.mtime),
|
|
1102
|
+
remote: new Date(remote.mtime)
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
function diffNodes(current, remote) {
|
|
1107
|
+
const inCurrent = getOnlyNotEqualNodes(current.nodes, remote.nodes);
|
|
1108
|
+
const inRemote = getOnlyNotEqualNodes(remote.nodes, current.nodes);
|
|
1109
|
+
const combined = combineCheckingNameOverlaps(inCurrent, inRemote);
|
|
1110
|
+
return (combined ? combined : {});
|
|
1111
|
+
}
|
|
1112
|
+
function getOnlyNotEqualNodes(src, exclude) {
|
|
1113
|
+
const collected = [];
|
|
1114
|
+
for (const [name, nodeInSrc] of Object.entries(src)) {
|
|
1115
|
+
const nodeInExclude = exclude[name];
|
|
1116
|
+
if (!nodeInExclude
|
|
1117
|
+
|| !areNodesEqual(nodeInSrc, nodeInExclude)) {
|
|
1118
|
+
collected.push(nodeInfoToListingEntry(nodeInSrc));
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return ((collected.length > 0) ? collected : undefined);
|
|
1122
|
+
}
|
|
1123
|
+
function areNodesEqual(n1, n2) {
|
|
1124
|
+
if (n1.name !== n2.name) {
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
if (n1.isFile && !n2.isFile) {
|
|
1128
|
+
return false;
|
|
1129
|
+
}
|
|
1130
|
+
if (n1.isFolder && !n2.isFolder) {
|
|
1131
|
+
return false;
|
|
1132
|
+
}
|
|
1133
|
+
if (n1.isLink && !n2.isLink) {
|
|
1134
|
+
return false;
|
|
1135
|
+
}
|
|
1136
|
+
if (n1.objId !== n2.objId) {
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
if (!areBytesEqual(n1.key, n2.key)) {
|
|
1140
|
+
return false;
|
|
1141
|
+
}
|
|
1142
|
+
return true;
|
|
1143
|
+
}
|
|
1144
|
+
function combineCheckingNameOverlaps(inCurrent, inRemote) {
|
|
1145
|
+
if (inCurrent) {
|
|
1146
|
+
if (inRemote) {
|
|
1147
|
+
const nameOverlaps = [];
|
|
1148
|
+
for (const { name: nameInCurrent } of inCurrent) {
|
|
1149
|
+
if (inRemote.find(({ name }) => (name === nameInCurrent))) {
|
|
1150
|
+
nameOverlaps.push(nameInCurrent);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (nameOverlaps.length > 0) {
|
|
1154
|
+
return { inCurrent, inRemote, nameOverlaps };
|
|
1155
|
+
}
|
|
1156
|
+
else {
|
|
1157
|
+
return { inCurrent, inRemote };
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1161
|
+
return { inCurrent };
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
if (inRemote) {
|
|
1166
|
+
return { inRemote };
|
|
1167
|
+
}
|
|
1168
|
+
else {
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
function diffXAttrs(current, remote) {
|
|
1174
|
+
const haveCurrentXAttrs = (current && (current.list().length > 0));
|
|
1175
|
+
const haveRemoteXAttrs = (remote && (remote.list().length > 0));
|
|
1176
|
+
if (haveCurrentXAttrs && haveRemoteXAttrs) {
|
|
1177
|
+
const inCurrent = getOnlyNotEqualXAttrs(current, remote);
|
|
1178
|
+
const inRemote = getOnlyNotEqualXAttrs(remote, current);
|
|
1179
|
+
return combineCheckingNameOverlaps(inCurrent, inRemote);
|
|
1180
|
+
}
|
|
1181
|
+
else if (haveCurrentXAttrs && !haveRemoteXAttrs) {
|
|
1182
|
+
return { inCurrent: allXAttrsToDiff(current) };
|
|
1183
|
+
}
|
|
1184
|
+
else if (!haveCurrentXAttrs && haveRemoteXAttrs) {
|
|
1185
|
+
return { inRemote: allXAttrsToDiff(remote) };
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
function allXAttrsToDiff(src) {
|
|
1192
|
+
const collected = [];
|
|
1193
|
+
for (const name of src.list()) {
|
|
1194
|
+
const value = src.get(name);
|
|
1195
|
+
if (value !== undefined) {
|
|
1196
|
+
collected.push({ name, value });
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
return collected;
|
|
1200
|
+
}
|
|
1201
|
+
function getOnlyNotEqualXAttrs(src, exclude) {
|
|
1202
|
+
const collected = [];
|
|
1203
|
+
for (const name of src.list()) {
|
|
1204
|
+
const valueInSrc = src.get(name);
|
|
1205
|
+
if (valueInSrc === undefined) {
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
1208
|
+
const valueInExclude = exclude.get(name);
|
|
1209
|
+
if ((valueInExclude === undefined)
|
|
1210
|
+
|| !areXAttrValuesEqual(valueInSrc, valueInExclude)) {
|
|
1211
|
+
collected.push({ name, value: valueInSrc });
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return ((collected.length > 0) ? collected : undefined);
|
|
1215
|
+
}
|
|
1216
|
+
function areXAttrValuesEqual(v1, v2) {
|
|
1217
|
+
if (Buffer.isBuffer(v1) || ArrayBuffer.isView(v1)) {
|
|
1218
|
+
if (Buffer.isBuffer(v2) || ArrayBuffer.isView(v2)) {
|
|
1219
|
+
return areBytesEqual(v1, v2);
|
|
1220
|
+
}
|
|
1221
|
+
{
|
|
1222
|
+
return false;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
else if (typeof v1 === 'string') {
|
|
1226
|
+
if (typeof v2 === 'string') {
|
|
1227
|
+
return (v1 === v2);
|
|
1228
|
+
}
|
|
1229
|
+
else {
|
|
1230
|
+
return false;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
else {
|
|
1234
|
+
if (Buffer.isBuffer(v2) || ArrayBuffer.isView(v2)
|
|
1235
|
+
|| (typeof v2 === 'string')) {
|
|
1236
|
+
return false;
|
|
1237
|
+
}
|
|
1238
|
+
else {
|
|
1239
|
+
return (0, json_utils_1.deepEqual)(v1, v2);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
function areBytesEqual(b1, b2) {
|
|
1244
|
+
if (b1.length !== b2.length) {
|
|
1245
|
+
return false;
|
|
1246
|
+
}
|
|
1247
|
+
for (let i = 0; i < b1.length; i += 1) {
|
|
1248
|
+
if (b1[i] !== b2[i]) {
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return true;
|
|
1253
|
+
}
|
|
1254
|
+
function identifyChanges(originalNodes, newNodes) {
|
|
1255
|
+
const removedNodes = [];
|
|
1256
|
+
const addedNodes = [];
|
|
1257
|
+
const renamedNodes = [];
|
|
1258
|
+
for (const [name, node] of Object.entries(originalNodes)) {
|
|
1259
|
+
const newNode = newNodes[name];
|
|
1260
|
+
if (newNode && (newNode.objId === node.objId)) {
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
removedNodes.push(node);
|
|
1264
|
+
}
|
|
1265
|
+
for (const [name, newNode] of Object.entries(newNodes)) {
|
|
1266
|
+
const node = originalNodes[name];
|
|
1267
|
+
if (node && (newNode.objId === node.objId)) {
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
const indInRm = removedNodes.findIndex(n => (n.objId === newNode.objId));
|
|
1271
|
+
if (indInRm < 0) {
|
|
1272
|
+
addedNodes.push(newNode);
|
|
1273
|
+
}
|
|
1274
|
+
else {
|
|
1275
|
+
const oldNode = removedNodes.splice(indInRm, 1)[0];
|
|
1276
|
+
renamedNodes.push({
|
|
1277
|
+
oldName: oldNode.name,
|
|
1278
|
+
newName: newNode.name,
|
|
1279
|
+
objId: newNode.objId
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
return { addedNodes, removedNodes, renamedNodes };
|
|
1284
|
+
}
|
|
725
1285
|
Object.freeze(exports);
|