@filen/sync 0.1.1 → 0.1.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/LICENSE +661 -661
- package/README.md +1 -1
- package/SECURITY.md +17 -17
- package/dist/constants.d.ts +7 -0
- package/dist/constants.js +51 -1
- package/dist/constants.js.map +1 -1
- package/dist/ignorer.d.ts +14 -0
- package/dist/ignorer.js +69 -0
- package/dist/ignorer.js.map +1 -0
- package/dist/index.d.ts +27 -6
- package/dist/index.js +113 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/deltas.d.ts +9 -31
- package/dist/lib/deltas.js +59 -65
- package/dist/lib/deltas.js.map +1 -1
- package/dist/lib/filesystems/local.d.ts +25 -20
- package/dist/lib/filesystems/local.js +203 -55
- package/dist/lib/filesystems/local.js.map +1 -1
- package/dist/lib/filesystems/remote.d.ts +18 -7
- package/dist/lib/filesystems/remote.js +435 -61
- package/dist/lib/filesystems/remote.js.map +1 -1
- package/dist/lib/ipc.d.ts +9 -0
- package/dist/lib/ipc.js +56 -0
- package/dist/lib/ipc.js.map +1 -0
- package/dist/lib/logger.d.ts +14 -0
- package/dist/lib/logger.js +93 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/state.d.ts +4 -15
- package/dist/lib/state.js +16 -29
- package/dist/lib/state.js.map +1 -1
- package/dist/lib/sync.d.ts +23 -9
- package/dist/lib/sync.js +242 -28
- package/dist/lib/sync.js.map +1 -1
- package/dist/lib/tasks.d.ts +18 -33
- package/dist/lib/tasks.js +52 -29
- package/dist/lib/tasks.js.map +1 -1
- package/dist/types.d.ts +175 -0
- package/dist/utils.d.ts +24 -0
- package/dist/utils.js +132 -1
- package/dist/utils.js.map +1 -1
- package/package.json +60 -58
- package/tsconfig.json +24 -24
- package/index.d.ts +0 -298
|
@@ -4,43 +4,278 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.RemoteFileSystem = void 0;
|
|
7
|
+
const sdk_1 = require("@filen/sdk");
|
|
7
8
|
const path_1 = __importDefault(require("path"));
|
|
8
9
|
const semaphore_1 = require("../../semaphore");
|
|
9
10
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
11
|
+
const ipc_1 = require("../ipc");
|
|
12
|
+
const utils_1 = require("../../utils");
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
const constants_1 = require("../../constants");
|
|
10
15
|
class RemoteFileSystem {
|
|
11
|
-
constructor(
|
|
16
|
+
constructor(sync) {
|
|
12
17
|
this.getDirectoryTreeCache = {
|
|
13
18
|
timestamp: 0,
|
|
14
19
|
tree: {},
|
|
15
20
|
uuids: {}
|
|
16
21
|
};
|
|
22
|
+
this.previousTreeRawResponse = "";
|
|
17
23
|
this.mutex = new semaphore_1.Semaphore(1);
|
|
18
24
|
this.mkdirMutex = new semaphore_1.Semaphore(1);
|
|
25
|
+
this.itemsMutex = new semaphore_1.Semaphore(1);
|
|
26
|
+
this.deviceIdCache = "";
|
|
19
27
|
this.sync = sync;
|
|
20
28
|
}
|
|
21
|
-
async
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
async getDeviceId() {
|
|
30
|
+
if (this.deviceIdCache.length > 0) {
|
|
31
|
+
return this.deviceIdCache;
|
|
32
|
+
}
|
|
33
|
+
const deviceIdFile = path_1.default.join(this.sync.dbPath, this.sync.syncPair.uuid, "deviceId");
|
|
34
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(deviceIdFile));
|
|
35
|
+
let deviceId = "";
|
|
36
|
+
if (!(await fs_extra_1.default.exists(deviceIdFile))) {
|
|
37
|
+
deviceId = (0, uuid_1.v4)();
|
|
38
|
+
await fs_extra_1.default.writeFile(deviceIdFile, deviceId, {
|
|
39
|
+
encoding: "utf-8"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
deviceId = await fs_extra_1.default.readFile(deviceIdFile, {
|
|
44
|
+
encoding: "utf-8"
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
this.deviceIdCache = deviceId;
|
|
48
|
+
return deviceId;
|
|
49
|
+
}
|
|
50
|
+
async getDirectoryTree(skipCache = false) {
|
|
51
|
+
var _a;
|
|
52
|
+
const deviceId = await this.getDeviceId();
|
|
53
|
+
const dir = await this.sync.sdk.api(3).dir().tree({
|
|
54
|
+
uuid: this.sync.syncPair.remoteParentUUID,
|
|
55
|
+
deviceId,
|
|
56
|
+
skipCache,
|
|
57
|
+
includeRaw: true
|
|
58
|
+
});
|
|
59
|
+
// Data did not change, use cache
|
|
60
|
+
if (dir.files.length === 0 && dir.folders.length === 0) {
|
|
61
|
+
if (this.getDirectoryTreeCache.timestamp === 0) {
|
|
62
|
+
// Re-run but with API caching disabled since our internal client cache is empty
|
|
63
|
+
return await this.getDirectoryTree(true);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
result: this.getDirectoryTreeCache,
|
|
67
|
+
ignored: [],
|
|
68
|
+
changed: false
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// eslint-disable-next-line quotes
|
|
72
|
+
const rawEx = dir.raw.split('"randomBytes"');
|
|
73
|
+
// Compare API response with the previous dataset, this way we can save time computing the tree if it's the same
|
|
74
|
+
if (rawEx.length === 2 && this.previousTreeRawResponse === rawEx[0] && this.getDirectoryTreeCache.timestamp !== 0) {
|
|
75
|
+
return {
|
|
76
|
+
result: this.getDirectoryTreeCache,
|
|
77
|
+
ignored: [],
|
|
78
|
+
changed: false
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const baseFolder = dir.folders[0];
|
|
82
|
+
if (!baseFolder) {
|
|
83
|
+
throw new Error("Could not get base folder.");
|
|
84
|
+
}
|
|
85
|
+
const baseFolderParent = baseFolder[2];
|
|
86
|
+
if (baseFolderParent !== "base") {
|
|
87
|
+
throw new Error("Invalid base folder parent.");
|
|
88
|
+
}
|
|
89
|
+
const folderNames = { base: "/" };
|
|
24
90
|
const tree = {};
|
|
25
|
-
const dir = await this.sync.sdk.cloud().getDirectoryTree({ uuid: this.sync.syncPair.remoteParentUUID });
|
|
26
91
|
const uuids = {};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
92
|
+
const pathsAdded = {};
|
|
93
|
+
const ignored = [];
|
|
94
|
+
for (const folder of dir.folders) {
|
|
95
|
+
try {
|
|
96
|
+
const decrypted = await this.sync.sdk.crypto().decrypt().folderMetadata({ metadata: folder[1] });
|
|
97
|
+
if (folder[2] !== "base" && decrypted.name.length === 0) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const parentPath = folder[2] === "base" ? "" : `${folderNames[folder[2]]}/`;
|
|
101
|
+
const folderPath = folder[2] === "base" ? "" : `${parentPath}${decrypted.name}`;
|
|
102
|
+
const localPath = path_1.default.join(this.sync.syncPair.localPath, folderPath);
|
|
103
|
+
folderNames[folder[0]] = folderPath;
|
|
104
|
+
if (folderPath.startsWith(constants_1.LOCAL_TRASH_NAME) || decrypted.name.startsWith(constants_1.LOCAL_TRASH_NAME)) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (this.sync.remoteIgnorer.ignores(folderPath)) {
|
|
108
|
+
ignored.push({
|
|
109
|
+
localPath,
|
|
110
|
+
relativePath: folderPath,
|
|
111
|
+
reason: "remoteIgnore"
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (this.sync.excludeDotFiles && decrypted.name.startsWith(".")) {
|
|
116
|
+
ignored.push({
|
|
117
|
+
localPath,
|
|
118
|
+
relativePath: folderPath,
|
|
119
|
+
reason: "dotFile"
|
|
120
|
+
});
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if ((0, utils_1.isPathOverMaxLength)(localPath)) {
|
|
124
|
+
ignored.push({
|
|
125
|
+
localPath,
|
|
126
|
+
relativePath: folderPath,
|
|
127
|
+
reason: "pathLength"
|
|
128
|
+
});
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if ((0, utils_1.isNameOverMaxLength)(decrypted.name)) {
|
|
132
|
+
ignored.push({
|
|
133
|
+
localPath,
|
|
134
|
+
relativePath: folderPath,
|
|
135
|
+
reason: "nameLength"
|
|
136
|
+
});
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (!(0, utils_1.isValidPath)(localPath)) {
|
|
140
|
+
ignored.push({
|
|
141
|
+
localPath,
|
|
142
|
+
relativePath: folderPath,
|
|
143
|
+
reason: "invalidPath"
|
|
144
|
+
});
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if ((0, utils_1.isDirectoryPathIgnoredByDefault)(folderPath) || (0, utils_1.isRelativePathIgnoredByDefault)(folderPath)) {
|
|
148
|
+
ignored.push({
|
|
149
|
+
localPath,
|
|
150
|
+
relativePath: folderPath,
|
|
151
|
+
reason: "defaultIgnore"
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const lowercasePath = folderPath.toLowerCase();
|
|
156
|
+
if (pathsAdded[lowercasePath]) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
pathsAdded[lowercasePath] = true;
|
|
160
|
+
const item = {
|
|
161
|
+
type: "directory",
|
|
162
|
+
uuid: folder[0],
|
|
163
|
+
name: decrypted.name,
|
|
164
|
+
size: 0,
|
|
165
|
+
path: folderPath
|
|
166
|
+
};
|
|
167
|
+
tree[folderPath] = item;
|
|
168
|
+
uuids[folder[0]] = item;
|
|
30
169
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const treeItem = tree[path];
|
|
34
|
-
if (treeItem) {
|
|
35
|
-
uuids[treeItem.uuid] = item;
|
|
170
|
+
catch (e) {
|
|
171
|
+
this.sync.worker.logger.log("error", e, "filesystems.remote.getDirectoryTree");
|
|
36
172
|
}
|
|
37
173
|
}
|
|
174
|
+
if (Object.keys(folderNames).length === 0) {
|
|
175
|
+
throw new Error("Could not build directory tree.");
|
|
176
|
+
}
|
|
177
|
+
await (0, utils_1.promiseAllSettledChunked)(dir.files.map(async (file) => {
|
|
178
|
+
try {
|
|
179
|
+
const decrypted = await this.sync.sdk.crypto().decrypt().fileMetadata({ metadata: file[5] });
|
|
180
|
+
if (decrypted.name.length === 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const parentPath = folderNames[file[4]];
|
|
184
|
+
const filePath = `${parentPath}/${decrypted.name}`;
|
|
185
|
+
const localPath = path_1.default.join(this.sync.syncPair.localPath, filePath);
|
|
186
|
+
if (filePath.startsWith(constants_1.LOCAL_TRASH_NAME) || decrypted.name.startsWith(constants_1.LOCAL_TRASH_NAME)) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (this.sync.remoteIgnorer.ignores(filePath)) {
|
|
190
|
+
ignored.push({
|
|
191
|
+
localPath,
|
|
192
|
+
relativePath: filePath,
|
|
193
|
+
reason: "remoteIgnore"
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (this.sync.excludeDotFiles && decrypted.name.startsWith(".")) {
|
|
198
|
+
ignored.push({
|
|
199
|
+
localPath,
|
|
200
|
+
relativePath: filePath,
|
|
201
|
+
reason: "dotFile"
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if ((0, utils_1.isPathOverMaxLength)(localPath)) {
|
|
206
|
+
ignored.push({
|
|
207
|
+
localPath,
|
|
208
|
+
relativePath: filePath,
|
|
209
|
+
reason: "pathLength"
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if ((0, utils_1.isNameOverMaxLength)(decrypted.name)) {
|
|
214
|
+
ignored.push({
|
|
215
|
+
localPath,
|
|
216
|
+
relativePath: filePath,
|
|
217
|
+
reason: "nameLength"
|
|
218
|
+
});
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (!(0, utils_1.isValidPath)(localPath)) {
|
|
222
|
+
ignored.push({
|
|
223
|
+
localPath,
|
|
224
|
+
relativePath: filePath,
|
|
225
|
+
reason: "invalidPath"
|
|
226
|
+
});
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if ((0, utils_1.isDirectoryPathIgnoredByDefault)(filePath) || (0, utils_1.isRelativePathIgnoredByDefault)(filePath)) {
|
|
230
|
+
ignored.push({
|
|
231
|
+
localPath,
|
|
232
|
+
relativePath: filePath,
|
|
233
|
+
reason: "defaultIgnore"
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const lowercasePath = filePath.toLowerCase();
|
|
238
|
+
if (pathsAdded[lowercasePath]) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
pathsAdded[lowercasePath] = true;
|
|
242
|
+
const item = {
|
|
243
|
+
type: "file",
|
|
244
|
+
uuid: file[0],
|
|
245
|
+
name: decrypted.name,
|
|
246
|
+
size: decrypted.size,
|
|
247
|
+
mime: decrypted.mime,
|
|
248
|
+
lastModified: (0, utils_1.convertTimestampToMs)(decrypted.lastModified),
|
|
249
|
+
version: file[6],
|
|
250
|
+
chunks: file[3],
|
|
251
|
+
key: decrypted.key,
|
|
252
|
+
bucket: file[1],
|
|
253
|
+
region: file[2],
|
|
254
|
+
creation: decrypted.creation,
|
|
255
|
+
hash: decrypted.hash,
|
|
256
|
+
path: filePath
|
|
257
|
+
};
|
|
258
|
+
tree[filePath] = item;
|
|
259
|
+
uuids[item.uuid] = item;
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
this.sync.worker.logger.log("error", e, "filesystems.remote.getDirectoryTree");
|
|
263
|
+
}
|
|
264
|
+
}));
|
|
265
|
+
this.previousTreeRawResponse = rawEx.length === 2 ? (_a = rawEx[0]) !== null && _a !== void 0 ? _a : "" : "";
|
|
38
266
|
this.getDirectoryTreeCache = {
|
|
39
267
|
timestamp: Date.now(),
|
|
40
268
|
tree,
|
|
41
269
|
uuids
|
|
42
270
|
};
|
|
43
|
-
return {
|
|
271
|
+
return {
|
|
272
|
+
result: {
|
|
273
|
+
tree,
|
|
274
|
+
uuids
|
|
275
|
+
},
|
|
276
|
+
ignored,
|
|
277
|
+
changed: true
|
|
278
|
+
};
|
|
44
279
|
}
|
|
45
280
|
/**
|
|
46
281
|
* Find the corresponding UUID of the relative path.
|
|
@@ -90,6 +325,7 @@ class RemoteFileSystem {
|
|
|
90
325
|
const basename = path_1.default.posix.basename(relativePath);
|
|
91
326
|
if (parentPath === "/" || parentPath === "." || parentPath.length <= 0) {
|
|
92
327
|
const uuid = await this.sync.sdk.cloud().createDirectory({ name: basename, parent: this.sync.syncPair.remoteParentUUID });
|
|
328
|
+
await this.itemsMutex.acquire();
|
|
93
329
|
this.getDirectoryTreeCache.tree[relativePath] = {
|
|
94
330
|
type: "directory",
|
|
95
331
|
uuid,
|
|
@@ -97,6 +333,14 @@ class RemoteFileSystem {
|
|
|
97
333
|
size: 0,
|
|
98
334
|
path: relativePath
|
|
99
335
|
};
|
|
336
|
+
this.getDirectoryTreeCache.uuids[uuid] = {
|
|
337
|
+
type: "directory",
|
|
338
|
+
uuid,
|
|
339
|
+
name: basename,
|
|
340
|
+
size: 0,
|
|
341
|
+
path: relativePath
|
|
342
|
+
};
|
|
343
|
+
this.itemsMutex.release();
|
|
100
344
|
return uuid;
|
|
101
345
|
}
|
|
102
346
|
const pathEx = relativePath.split("/");
|
|
@@ -116,6 +360,7 @@ class RemoteFileSystem {
|
|
|
116
360
|
const parentIsBase = partParentPath === "/" || partParentPath === "." || partParentPath === "";
|
|
117
361
|
const parentUUID = parentIsBase ? this.sync.syncPair.remoteParentUUID : parentItem.uuid;
|
|
118
362
|
const uuid = await this.sync.sdk.cloud().createDirectory({ name: partBasename, parent: parentUUID });
|
|
363
|
+
await this.itemsMutex.acquire();
|
|
119
364
|
this.getDirectoryTreeCache.tree[relativePath] = {
|
|
120
365
|
type: "directory",
|
|
121
366
|
uuid,
|
|
@@ -123,6 +368,14 @@ class RemoteFileSystem {
|
|
|
123
368
|
size: 0,
|
|
124
369
|
path: relativePath
|
|
125
370
|
};
|
|
371
|
+
this.getDirectoryTreeCache.uuids[uuid] = {
|
|
372
|
+
type: "directory",
|
|
373
|
+
uuid,
|
|
374
|
+
name: partBasename,
|
|
375
|
+
size: 0,
|
|
376
|
+
path: relativePath
|
|
377
|
+
};
|
|
378
|
+
this.itemsMutex.release();
|
|
126
379
|
}
|
|
127
380
|
}
|
|
128
381
|
if (!this.getDirectoryTreeCache.tree[relativePath]) {
|
|
@@ -150,14 +403,15 @@ class RemoteFileSystem {
|
|
|
150
403
|
await this.mutex.acquire();
|
|
151
404
|
try {
|
|
152
405
|
const uuid = await this.pathToItemUUID({ relativePath });
|
|
153
|
-
|
|
406
|
+
const item = this.getDirectoryTreeCache.tree[relativePath];
|
|
407
|
+
if (!uuid || !item) {
|
|
154
408
|
return;
|
|
155
409
|
}
|
|
156
410
|
const acceptedTypes = !type ? ["directory", "file"] : type === "directory" ? ["directory"] : ["file"];
|
|
157
|
-
if (!acceptedTypes.includes(
|
|
411
|
+
if (!acceptedTypes.includes(item.type)) {
|
|
158
412
|
return;
|
|
159
413
|
}
|
|
160
|
-
if (
|
|
414
|
+
if (item.type === "directory") {
|
|
161
415
|
if (permanent) {
|
|
162
416
|
await this.sync.sdk.cloud().deleteDirectory({ uuid });
|
|
163
417
|
}
|
|
@@ -173,19 +427,26 @@ class RemoteFileSystem {
|
|
|
173
427
|
await this.sync.sdk.cloud().trashFile({ uuid });
|
|
174
428
|
}
|
|
175
429
|
}
|
|
430
|
+
await this.itemsMutex.acquire();
|
|
176
431
|
delete this.getDirectoryTreeCache.tree[relativePath];
|
|
432
|
+
delete this.getDirectoryTreeCache.uuids[uuid];
|
|
177
433
|
for (const entry in this.getDirectoryTreeCache.tree) {
|
|
178
|
-
if (entry.startsWith(relativePath + "/")) {
|
|
434
|
+
if (entry.startsWith(relativePath + "/") || entry === relativePath) {
|
|
435
|
+
const entryItem = this.getDirectoryTreeCache.tree[entry];
|
|
436
|
+
if (entryItem) {
|
|
437
|
+
delete this.getDirectoryTreeCache.uuids[entryItem.uuid];
|
|
438
|
+
}
|
|
179
439
|
delete this.getDirectoryTreeCache.tree[entry];
|
|
180
440
|
}
|
|
181
441
|
}
|
|
442
|
+
this.itemsMutex.release();
|
|
182
443
|
}
|
|
183
444
|
finally {
|
|
184
445
|
this.mutex.release();
|
|
185
446
|
}
|
|
186
447
|
}
|
|
187
448
|
/**
|
|
188
|
-
* Rename a file/directory inside the remote sync path. Recursively creates intermediate directories if needed.
|
|
449
|
+
* Rename/Move a file/directory inside the remote sync path. Recursively creates intermediate directories if needed.
|
|
189
450
|
* @date 3/2/2024 - 9:35:12 PM
|
|
190
451
|
*
|
|
191
452
|
* @public
|
|
@@ -228,7 +489,10 @@ class RemoteFileSystem {
|
|
|
228
489
|
return;
|
|
229
490
|
}
|
|
230
491
|
if (item.type === "directory") {
|
|
231
|
-
await this.sync.sdk.cloud().renameDirectory({
|
|
492
|
+
await this.sync.sdk.cloud().renameDirectory({
|
|
493
|
+
uuid,
|
|
494
|
+
name: newBasename
|
|
495
|
+
});
|
|
232
496
|
}
|
|
233
497
|
else {
|
|
234
498
|
await this.sync.sdk.cloud().renameFile({
|
|
@@ -237,16 +501,17 @@ class RemoteFileSystem {
|
|
|
237
501
|
name: newBasename
|
|
238
502
|
});
|
|
239
503
|
}
|
|
240
|
-
const oldItem = this.getDirectoryTreeCache.tree[fromRelativePath];
|
|
241
|
-
if (oldItem) {
|
|
242
|
-
this.getDirectoryTreeCache.tree[toRelativePath] = Object.assign(Object.assign({}, oldItem), { name: newBasename });
|
|
243
|
-
}
|
|
244
|
-
delete this.getDirectoryTreeCache.tree[fromRelativePath];
|
|
245
504
|
}
|
|
246
505
|
else {
|
|
506
|
+
if (toRelativePath.startsWith(fromRelativePath)) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
247
509
|
if (oldBasename !== newBasename) {
|
|
248
510
|
if (item.type === "directory") {
|
|
249
|
-
await this.sync.sdk.cloud().renameDirectory({
|
|
511
|
+
await this.sync.sdk.cloud().renameDirectory({
|
|
512
|
+
uuid,
|
|
513
|
+
name: newBasename
|
|
514
|
+
});
|
|
250
515
|
}
|
|
251
516
|
else {
|
|
252
517
|
await this.sync.sdk.cloud().renameFile({
|
|
@@ -258,14 +523,18 @@ class RemoteFileSystem {
|
|
|
258
523
|
}
|
|
259
524
|
if (newParentPath === "/" || newParentPath === "." || newParentPath === "") {
|
|
260
525
|
if (item.type === "directory") {
|
|
261
|
-
await this.sync.sdk
|
|
262
|
-
|
|
263
|
-
|
|
526
|
+
await this.sync.sdk.cloud().moveDirectory({
|
|
527
|
+
uuid,
|
|
528
|
+
to: this.sync.syncPair.remoteParentUUID,
|
|
529
|
+
metadata: itemMetadata
|
|
530
|
+
});
|
|
264
531
|
}
|
|
265
532
|
else {
|
|
266
|
-
await this.sync.sdk
|
|
267
|
-
|
|
268
|
-
|
|
533
|
+
await this.sync.sdk.cloud().moveFile({
|
|
534
|
+
uuid,
|
|
535
|
+
to: this.sync.syncPair.remoteParentUUID,
|
|
536
|
+
metadata: itemMetadata
|
|
537
|
+
});
|
|
269
538
|
}
|
|
270
539
|
}
|
|
271
540
|
else {
|
|
@@ -275,29 +544,39 @@ class RemoteFileSystem {
|
|
|
275
544
|
throw new Error(`Could not find path ${newParentPath}.`);
|
|
276
545
|
}
|
|
277
546
|
if (item.type === "directory") {
|
|
278
|
-
await this.sync.sdk
|
|
279
|
-
|
|
280
|
-
|
|
547
|
+
await this.sync.sdk.cloud().moveDirectory({
|
|
548
|
+
uuid,
|
|
549
|
+
to: newParentItem.uuid,
|
|
550
|
+
metadata: itemMetadata
|
|
551
|
+
});
|
|
281
552
|
}
|
|
282
553
|
else {
|
|
283
|
-
await this.sync.sdk.cloud().moveFile({
|
|
554
|
+
await this.sync.sdk.cloud().moveFile({
|
|
555
|
+
uuid,
|
|
556
|
+
to: newParentItem.uuid,
|
|
557
|
+
metadata: itemMetadata
|
|
558
|
+
});
|
|
284
559
|
}
|
|
285
560
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
561
|
+
await this.itemsMutex.acquire();
|
|
562
|
+
this.getDirectoryTreeCache.tree[toRelativePath] = Object.assign(Object.assign({}, item), { name: path_1.default.basename(toRelativePath), path: toRelativePath });
|
|
563
|
+
this.getDirectoryTreeCache.uuids[item.uuid] = Object.assign(Object.assign({}, item), { name: path_1.default.basename(toRelativePath), path: toRelativePath });
|
|
290
564
|
delete this.getDirectoryTreeCache.tree[fromRelativePath];
|
|
291
565
|
for (const oldPath in this.getDirectoryTreeCache.tree) {
|
|
292
|
-
if (oldPath.startsWith(fromRelativePath + "/")) {
|
|
566
|
+
if (oldPath.startsWith(fromRelativePath + "/") && oldPath !== fromRelativePath) {
|
|
293
567
|
const newPath = oldPath.split(fromRelativePath).join(toRelativePath);
|
|
294
568
|
const oldItem = this.getDirectoryTreeCache.tree[oldPath];
|
|
295
569
|
if (oldItem) {
|
|
296
|
-
this.getDirectoryTreeCache.tree[newPath] = Object.assign(Object.assign({}, oldItem), { name:
|
|
570
|
+
this.getDirectoryTreeCache.tree[newPath] = Object.assign(Object.assign({}, oldItem), { name: path_1.default.basename(newPath), path: newPath });
|
|
571
|
+
delete this.getDirectoryTreeCache.tree[oldPath];
|
|
572
|
+
const oldItemUUID = this.getDirectoryTreeCache.uuids[oldItem.uuid];
|
|
573
|
+
if (oldItemUUID) {
|
|
574
|
+
this.getDirectoryTreeCache.uuids[oldItem.uuid] = Object.assign(Object.assign({}, oldItemUUID), { name: path_1.default.basename(newPath), path: newPath });
|
|
575
|
+
}
|
|
297
576
|
}
|
|
298
|
-
delete this.getDirectoryTreeCache.tree[oldPath];
|
|
299
577
|
}
|
|
300
578
|
}
|
|
579
|
+
this.itemsMutex.release();
|
|
301
580
|
}
|
|
302
581
|
}
|
|
303
582
|
finally {
|
|
@@ -315,28 +594,123 @@ class RemoteFileSystem {
|
|
|
315
594
|
* @returns {Promise<fs.Stats>}
|
|
316
595
|
*/
|
|
317
596
|
async download({ relativePath }) {
|
|
597
|
+
var _a;
|
|
318
598
|
const localPath = path_1.default.posix.join(this.sync.syncPair.localPath, relativePath);
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
if (!
|
|
322
|
-
|
|
599
|
+
const tmpLocalPath = path_1.default.join(this.sync.syncPair.localPath, constants_1.LOCAL_TRASH_NAME, (0, uuid_1.v4)());
|
|
600
|
+
const signalKey = `upload:${relativePath}`;
|
|
601
|
+
if (!this.sync.pauseSignals[signalKey]) {
|
|
602
|
+
this.sync.pauseSignals[signalKey] = new sdk_1.PauseSignal();
|
|
323
603
|
}
|
|
324
|
-
if (
|
|
325
|
-
|
|
604
|
+
if (!this.sync.abortControllers[signalKey]) {
|
|
605
|
+
this.sync.abortControllers[signalKey] = new AbortController();
|
|
326
606
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
overwrite: true
|
|
607
|
+
(0, ipc_1.postMessageToMain)({
|
|
608
|
+
type: "transfer",
|
|
609
|
+
syncPair: this.sync.syncPair,
|
|
610
|
+
data: {
|
|
611
|
+
of: "download",
|
|
612
|
+
type: "queued",
|
|
613
|
+
relativePath,
|
|
614
|
+
localPath
|
|
615
|
+
}
|
|
337
616
|
});
|
|
338
|
-
|
|
339
|
-
|
|
617
|
+
try {
|
|
618
|
+
const uuid = await this.pathToItemUUID({ relativePath });
|
|
619
|
+
const item = this.getDirectoryTreeCache.tree[relativePath];
|
|
620
|
+
if (!uuid || !item) {
|
|
621
|
+
throw new Error(`Could not download ${relativePath}: File not found.`);
|
|
622
|
+
}
|
|
623
|
+
if (item.type === "directory") {
|
|
624
|
+
throw new Error(`Could not download ${relativePath}: Not a file.`);
|
|
625
|
+
}
|
|
626
|
+
await this.sync.sdk.cloud().downloadFileToLocal({
|
|
627
|
+
uuid,
|
|
628
|
+
bucket: item.bucket,
|
|
629
|
+
region: item.region,
|
|
630
|
+
chunks: item.chunks,
|
|
631
|
+
version: item.version,
|
|
632
|
+
to: tmpLocalPath,
|
|
633
|
+
key: item.key,
|
|
634
|
+
size: item.size,
|
|
635
|
+
pauseSignal: this.sync.pauseSignals[signalKey],
|
|
636
|
+
abortSignal: (_a = this.sync.abortControllers[signalKey]) === null || _a === void 0 ? void 0 : _a.signal,
|
|
637
|
+
onError: err => {
|
|
638
|
+
this.sync.worker.logger.log("error", err, "filesystems.remote.download");
|
|
639
|
+
(0, ipc_1.postMessageToMain)({
|
|
640
|
+
type: "transfer",
|
|
641
|
+
syncPair: this.sync.syncPair,
|
|
642
|
+
data: {
|
|
643
|
+
of: "download",
|
|
644
|
+
type: "error",
|
|
645
|
+
relativePath,
|
|
646
|
+
localPath,
|
|
647
|
+
error: (0, utils_1.serializeError)(err)
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
},
|
|
651
|
+
onProgress: bytes => {
|
|
652
|
+
(0, ipc_1.postMessageToMain)({
|
|
653
|
+
type: "transfer",
|
|
654
|
+
syncPair: this.sync.syncPair,
|
|
655
|
+
data: {
|
|
656
|
+
of: "download",
|
|
657
|
+
type: "progress",
|
|
658
|
+
relativePath,
|
|
659
|
+
localPath,
|
|
660
|
+
bytes
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
},
|
|
664
|
+
onStarted: () => {
|
|
665
|
+
(0, ipc_1.postMessageToMain)({
|
|
666
|
+
type: "transfer",
|
|
667
|
+
syncPair: this.sync.syncPair,
|
|
668
|
+
data: {
|
|
669
|
+
of: "download",
|
|
670
|
+
type: "started",
|
|
671
|
+
relativePath,
|
|
672
|
+
localPath
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
await fs_extra_1.default.utimes(tmpLocalPath, new Date(), new Date((0, utils_1.convertTimestampToMs)(item.lastModified)));
|
|
678
|
+
await fs_extra_1.default.move(tmpLocalPath, localPath, {
|
|
679
|
+
overwrite: true
|
|
680
|
+
});
|
|
681
|
+
(0, ipc_1.postMessageToMain)({
|
|
682
|
+
type: "transfer",
|
|
683
|
+
syncPair: this.sync.syncPair,
|
|
684
|
+
data: {
|
|
685
|
+
of: "download",
|
|
686
|
+
type: "finished",
|
|
687
|
+
relativePath,
|
|
688
|
+
localPath
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
return await fs_extra_1.default.stat(localPath);
|
|
692
|
+
}
|
|
693
|
+
catch (e) {
|
|
694
|
+
this.sync.worker.logger.log("error", e, "filesystems.remote.download");
|
|
695
|
+
if (e instanceof Error) {
|
|
696
|
+
(0, ipc_1.postMessageToMain)({
|
|
697
|
+
type: "transfer",
|
|
698
|
+
syncPair: this.sync.syncPair,
|
|
699
|
+
data: {
|
|
700
|
+
of: "download",
|
|
701
|
+
type: "error",
|
|
702
|
+
relativePath,
|
|
703
|
+
localPath,
|
|
704
|
+
error: (0, utils_1.serializeError)(e)
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
throw e;
|
|
709
|
+
}
|
|
710
|
+
finally {
|
|
711
|
+
delete this.sync.pauseSignals[signalKey];
|
|
712
|
+
delete this.sync.abortControllers[signalKey];
|
|
713
|
+
}
|
|
340
714
|
}
|
|
341
715
|
}
|
|
342
716
|
exports.RemoteFileSystem = RemoteFileSystem;
|