core-3nweb-client-lib 0.25.3 → 0.26.0
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/README.md +2 -2
- package/build/api-defs/files.d.ts +23 -20
- package/build/core/asmail/config/common.js +2 -2
- package/build/core/asmail/delivery/index.js +4 -3
- package/build/core/asmail/delivery/msg.js +5 -4
- package/build/core/asmail/delivery/per-recipient-wip.js +2 -2
- package/build/core/asmail/inbox/attachments/fs.js +6 -0
- package/build/core/asmail/inbox/cached-msgs.js +2 -2
- package/build/core/asmail/inbox/inbox-events.js +2 -1
- package/build/core/asmail/inbox/index.js +2 -2
- package/build/core/asmail/inbox/msg-downloader.js +2 -2
- package/build/core/asmail/inbox/msg-indexing.js +3 -3
- package/build/core/asmail/inbox/msg-on-disk.js +2 -2
- package/build/core/asmail/keyring/keyring-storage.js +2 -2
- package/build/core/asmail/sending-params/own-params.js +2 -2
- package/build/core/asmail/sending-params/params-from-others.js +2 -2
- package/build/core/id-manager.js +2 -2
- package/build/core/sign-in.d.ts +5 -4
- package/build/core/sign-in.js +9 -11
- package/build/core/sign-up.d.ts +1 -0
- package/build/core/sign-up.js +7 -3
- package/build/core/storage/common/json-saving.d.ts +21 -0
- package/build/core/storage/common/json-saving.js +82 -0
- package/build/core/storage/common/obj-info-file.d.ts +43 -0
- package/build/core/storage/common/obj-info-file.js +119 -3
- package/build/core/storage/index.js +1 -1
- package/build/core/storage/local/obj-files-gc.js +8 -6
- package/build/core/storage/local/obj-files.d.ts +3 -3
- package/build/core/storage/local/obj-files.js +9 -9
- package/build/core/storage/local/obj-status.d.ts +9 -25
- package/build/core/storage/local/obj-status.js +28 -110
- package/build/core/storage/local/storage.d.ts +8 -1
- package/build/core/storage/local/storage.js +10 -2
- package/build/core/storage/synced/downloader.js +6 -5
- package/build/core/storage/synced/obj-files-gc.d.ts +1 -0
- package/build/core/storage/synced/obj-files-gc.js +44 -5
- package/build/core/storage/synced/obj-files.d.ts +13 -20
- package/build/core/storage/synced/obj-files.js +70 -48
- package/build/core/storage/synced/obj-status.d.ts +74 -15
- package/build/core/storage/synced/obj-status.js +291 -107
- package/build/core/storage/synced/remote-events.js +32 -26
- package/build/core/storage/synced/storage.d.ts +11 -1
- package/build/core/storage/synced/storage.js +28 -3
- package/build/core/storage/synced/upsyncer.d.ts +8 -7
- package/build/core/storage/synced/upsyncer.js +211 -163
- package/build/ipc-via-protobuf/asmail-cap.js +17 -34
- package/build/ipc-via-protobuf/connector-clients-side.js +2 -2
- package/build/ipc-via-protobuf/file.js +26 -18
- package/build/ipc-via-protobuf/fs.js +33 -35
- package/build/ipc-via-protobuf/mailerid.js +3 -2
- package/build/ipc-via-protobuf/protobuf-msg.d.ts +2 -0
- package/build/ipc-via-protobuf/protobuf-msg.js +11 -1
- package/build/ipc-via-protobuf/startup-cap.js +5 -5
- package/build/lib-client/3nstorage/exceptions.d.ts +9 -8
- package/build/lib-client/3nstorage/exceptions.js +18 -9
- package/build/lib-client/3nstorage/service.js +10 -6
- package/build/lib-client/3nstorage/xsp-fs/common.d.ts +18 -4
- package/build/lib-client/3nstorage/xsp-fs/common.js +6 -1
- package/build/lib-client/3nstorage/xsp-fs/file-node.js +3 -3
- package/build/lib-client/3nstorage/xsp-fs/file.js +4 -1
- package/build/lib-client/3nstorage/xsp-fs/folder-node.js +27 -13
- package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +11 -6
- package/build/lib-client/3nstorage/xsp-fs/fs.js +189 -58
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +4 -0
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +51 -24
- package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +2 -2
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +2 -2
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +3 -3
- package/build/lib-client/cryptor/cryptor-in-worker.js +4 -4
- package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
- package/build/lib-client/cryptor/cryptor.wasm +0 -0
- package/build/lib-client/cryptor/in-proc-wasm.js +2 -2
- package/build/lib-client/files.js +2 -0
- package/build/lib-client/fs-collection.js +3 -2
- package/build/lib-client/logging/log-to-file.js +6 -14
- package/build/lib-client/objs-on-disk/file-writing-proc.js +2 -2
- package/build/lib-client/objs-on-disk/obj-folders.d.ts +12 -1
- package/build/lib-client/objs-on-disk/obj-folders.js +26 -19
- package/build/lib-client/request-utils.js +2 -2
- package/build/lib-client/server-events.js +4 -3
- package/build/lib-client/ws-utils.js +2 -2
- package/build/lib-common/async-fs-node.d.ts +6 -0
- package/build/lib-common/async-fs-node.js +28 -4
- package/build/lib-common/byte-streaming/wrapping.js +17 -17
- package/build/lib-common/exceptions/file.js +6 -1
- package/build/lib-common/ipc/generic-ipc.js +2 -2
- package/build/lib-common/json-utils.js +2 -1
- package/build/lib-common/objs-on-disk/obj-file.js +4 -3
- package/build/lib-common/objs-on-disk/utils.js +2 -2
- package/build/lib-common/processes/deferred.d.ts +6 -0
- package/build/lib-common/processes/deferred.js +30 -0
- package/build/lib-common/processes/labelled-exec-pools.d.ts +33 -0
- package/build/lib-common/processes/labelled-exec-pools.js +141 -0
- package/build/lib-common/processes/pressure.d.ts +7 -0
- package/build/lib-common/processes/pressure.js +56 -0
- package/build/lib-common/processes/sleep.d.ts +1 -0
- package/build/lib-common/processes/sleep.js +26 -0
- package/build/lib-common/{processes.d.ts → processes/synced.d.ts} +0 -40
- package/build/lib-common/{processes.js → processes/synced.js} +187 -204
- package/build/lib-common/processes/timeout.d.ts +1 -0
- package/build/lib-common/processes/timeout.js +51 -0
- package/build/lib-common/service-api/3nstorage/owner.d.ts +5 -4
- package/build/lib-common/service-api/3nstorage/owner.js +3 -2
- package/build/lib-common/utils-for-observables.d.ts +15 -1
- package/build/lib-common/utils-for-observables.js +68 -17
- package/build/protos/asmail.proto.js +404 -78
- package/build/protos/file.proto.js +370 -44
- package/build/protos/fs.proto.js +404 -78
- package/package.json +4 -4
- package/protos/file.proto +10 -2
- package/protos/fs.proto +2 -2
- package/build/core/storage/synced/upsync-status.d.ts +0 -41
- package/build/core/storage/synced/upsync-status.js +0 -158
|
@@ -31,6 +31,7 @@ const pipe_1 = require("../../../lib-common/byte-streaming/pipe");
|
|
|
31
31
|
const buffer_utils_1 = require("../../../lib-common/buffer-utils");
|
|
32
32
|
const rxjs_1 = require("rxjs");
|
|
33
33
|
const operators_1 = require("rxjs/operators");
|
|
34
|
+
const utils_for_observables_1 = require("../../../lib-common/utils-for-observables");
|
|
34
35
|
function splitPathIntoParts(path) {
|
|
35
36
|
return path_1.posix.resolve('/', path).split('/').filter(part => !!part);
|
|
36
37
|
}
|
|
@@ -55,32 +56,37 @@ const WRITE_NONEXCL_FLAGS = {
|
|
|
55
56
|
truncate: true
|
|
56
57
|
};
|
|
57
58
|
class XspFS {
|
|
58
|
-
constructor(storage, writable, name = '') {
|
|
59
|
-
this.storage = storage;
|
|
59
|
+
constructor(storage, writable, rootNode, name = '') {
|
|
60
60
|
this.writable = writable;
|
|
61
61
|
this.name = name;
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
62
|
+
this.fsObs = new utils_for_observables_1.Broadcast();
|
|
63
|
+
this.store = storage;
|
|
64
|
+
this.type = this.store.type;
|
|
65
|
+
this.v = new V(rootNode);
|
|
64
66
|
Object.seal(this);
|
|
65
67
|
}
|
|
68
|
+
storage() {
|
|
69
|
+
if (!this.store) {
|
|
70
|
+
throw file_1.makeFileException(file_1.Code.storageClosed, this.name);
|
|
71
|
+
}
|
|
72
|
+
return this.store;
|
|
73
|
+
}
|
|
66
74
|
async readonlySubRoot(path) {
|
|
67
75
|
const pathParts = splitPathIntoParts(path);
|
|
68
|
-
const
|
|
69
|
-
|
|
76
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
77
|
+
const folder = await root.getFolderInThisSubTree(pathParts, false).catch(setExcPath(path));
|
|
70
78
|
const folderName = ((pathParts.length === 0) ?
|
|
71
79
|
this.name : pathParts[pathParts.length - 1]);
|
|
72
|
-
const fs = new XspFS(this.storage, false, folderName);
|
|
73
|
-
fs.v.root = folder;
|
|
80
|
+
const fs = new XspFS(this.storage(), false, folder, folderName);
|
|
74
81
|
return files_1.wrapReadonlyFS(fs);
|
|
75
82
|
}
|
|
76
83
|
async writableSubRoot(path, flags = WRITE_NONEXCL_FLAGS) {
|
|
77
84
|
const pathParts = splitPathIntoParts(path);
|
|
78
|
-
const
|
|
79
|
-
|
|
85
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
86
|
+
const folder = await root.getFolderInThisSubTree(pathParts, flags.create, flags.exclusive).catch(setExcPath(path));
|
|
80
87
|
const folderName = ((pathParts.length === 0) ?
|
|
81
88
|
this.name : pathParts[pathParts.length - 1]);
|
|
82
|
-
const fs = new XspFS(this.storage, true, folderName);
|
|
83
|
-
fs.v.root = folder;
|
|
89
|
+
const fs = new XspFS(this.storage(), true, folder, folderName);
|
|
84
90
|
return files_1.wrapWritableFS(fs);
|
|
85
91
|
}
|
|
86
92
|
/**
|
|
@@ -90,8 +96,8 @@ class XspFS {
|
|
|
90
96
|
* @param key is a file key of a root object
|
|
91
97
|
*/
|
|
92
98
|
static async makeNewRoot(storage, key) {
|
|
93
|
-
const
|
|
94
|
-
fs
|
|
99
|
+
const root = await folder_node_1.FolderNode.newRoot(storage, key);
|
|
100
|
+
const fs = new XspFS(storage, true, root);
|
|
95
101
|
return files_1.wrapWritableFS(fs);
|
|
96
102
|
}
|
|
97
103
|
/**
|
|
@@ -101,35 +107,36 @@ class XspFS {
|
|
|
101
107
|
* @param key is a file key of a root object
|
|
102
108
|
*/
|
|
103
109
|
static async fromExistingRoot(storage, key) {
|
|
104
|
-
const fs = new XspFS(storage, true);
|
|
105
110
|
const objSrc = await storage.getObj(null);
|
|
106
|
-
|
|
111
|
+
const root = await folder_node_1.FolderNode.rootFromObjBytes(storage, undefined, null, objSrc, key);
|
|
112
|
+
const fs = new XspFS(storage, true, root);
|
|
107
113
|
return files_1.wrapWritableFS(fs);
|
|
108
114
|
}
|
|
109
115
|
static fromASMailMsgRootFromJSON(storage, folderJson, rootName) {
|
|
110
|
-
const
|
|
111
|
-
fs
|
|
116
|
+
const root = folder_node_1.FolderNode.rootFromJSON(storage, rootName, folderJson);
|
|
117
|
+
const fs = new XspFS(storage, false, root, rootName);
|
|
112
118
|
return files_1.wrapIntoVersionlessReadonlyFS(fs);
|
|
113
119
|
}
|
|
114
120
|
/**
|
|
115
121
|
* Note that this method doesn't close storage.
|
|
116
122
|
*/
|
|
117
123
|
async close() {
|
|
118
|
-
this.v.
|
|
119
|
-
this.
|
|
124
|
+
this.v.close();
|
|
125
|
+
this.store = undefined;
|
|
126
|
+
this.fsObs.done();
|
|
120
127
|
}
|
|
121
128
|
async makeFolder(path, exclusive = false) {
|
|
122
129
|
const folderPath = splitPathIntoParts(path);
|
|
123
|
-
|
|
124
|
-
|
|
130
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
131
|
+
await root.getFolderInThisSubTree(folderPath, true, exclusive).catch(setExcPath(path));
|
|
125
132
|
}
|
|
126
133
|
select(path, criteria) {
|
|
127
134
|
return files_select_1.selectInFS(this, path, criteria);
|
|
128
135
|
}
|
|
129
136
|
async deleteFolder(path, removeContent = false) {
|
|
130
137
|
const { fileName: folderName, folderPath: parentPath } = split(path);
|
|
131
|
-
const
|
|
132
|
-
|
|
138
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
139
|
+
const parentFolder = await root.getFolderInThisSubTree(parentPath).catch(setExcPath(parentPath.join('/')));
|
|
133
140
|
if (typeof folderName !== 'string') {
|
|
134
141
|
throw new Error('Cannot remove root folder');
|
|
135
142
|
}
|
|
@@ -142,18 +149,17 @@ class XspFS {
|
|
|
142
149
|
}
|
|
143
150
|
async deleteFile(path) {
|
|
144
151
|
const { fileName, folderPath } = split(path);
|
|
145
|
-
const
|
|
146
|
-
|
|
152
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
153
|
+
const parentFolder = await root.getFolderInThisSubTree(folderPath).catch(setExcPath(path));
|
|
147
154
|
const file = await parentFolder.getFile(fileName)
|
|
148
155
|
.catch(setExcPath(path));
|
|
149
156
|
await parentFolder.removeChild(file);
|
|
150
157
|
}
|
|
151
158
|
async deleteLink(path) {
|
|
152
159
|
const { fileName, folderPath } = split(path);
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
const link = await parentFolder.getLink(fileName)
|
|
156
|
-
.catch(setExcPath(path));
|
|
160
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
161
|
+
const parentFolder = await root.getFolderInThisSubTree(folderPath).catch(setExcPath(path));
|
|
162
|
+
const link = await parentFolder.getLink(fileName).catch(setExcPath(path));
|
|
157
163
|
await parentFolder.removeChild(link);
|
|
158
164
|
}
|
|
159
165
|
async move(initPath, newPath) {
|
|
@@ -169,10 +175,11 @@ class XspFS {
|
|
|
169
175
|
}
|
|
170
176
|
const dstFName = dstFolderPath[dstFolderPath.length - 1];
|
|
171
177
|
dstFolderPath.splice(dstFolderPath.length - 1, 1);
|
|
178
|
+
const root = this.v.getRootIfNotClosed(initPath);
|
|
172
179
|
try {
|
|
173
|
-
const srcFolder = await
|
|
180
|
+
const srcFolder = await root.getFolderInThisSubTree(srcFolderPath);
|
|
174
181
|
srcFolder.hasChild(initFName, true);
|
|
175
|
-
const dstFolder = await
|
|
182
|
+
const dstFolder = await root.getFolderInThisSubTree(dstFolderPath, true);
|
|
176
183
|
await srcFolder.moveChildTo(initFName, dstFolder, dstFName);
|
|
177
184
|
}
|
|
178
185
|
catch (exc) {
|
|
@@ -190,11 +197,13 @@ class XspFS {
|
|
|
190
197
|
}
|
|
191
198
|
async stat(path) {
|
|
192
199
|
const node = await this.v.get(path);
|
|
200
|
+
const sync = await node.sync();
|
|
193
201
|
const attrs = node.getAttrs();
|
|
194
202
|
const stats = {
|
|
195
203
|
ctime: new Date(attrs.ctime),
|
|
196
204
|
mtime: new Date(attrs.mtime),
|
|
197
205
|
version: node.version,
|
|
206
|
+
sync,
|
|
198
207
|
writable: this.writable,
|
|
199
208
|
};
|
|
200
209
|
if (node.type === 'file') {
|
|
@@ -311,21 +320,22 @@ class XspFS {
|
|
|
311
320
|
}
|
|
312
321
|
}
|
|
313
322
|
ensureLinkingAllowedTo(params) {
|
|
314
|
-
|
|
323
|
+
const storage = this.storage();
|
|
324
|
+
if (storage.type === 'local') {
|
|
315
325
|
return;
|
|
316
326
|
}
|
|
317
|
-
else if (
|
|
327
|
+
else if (storage.type === 'synced') {
|
|
318
328
|
if ((params.storageType === 'share') ||
|
|
319
329
|
(params.storageType === 'synced')) {
|
|
320
330
|
return;
|
|
321
331
|
}
|
|
322
332
|
}
|
|
323
|
-
else if (
|
|
333
|
+
else if (storage.type === 'share') {
|
|
324
334
|
if (params.storageType === 'share') {
|
|
325
335
|
return;
|
|
326
336
|
}
|
|
327
337
|
}
|
|
328
|
-
throw new Error(`Cannot create link to ${params.storageType} from ${
|
|
338
|
+
throw new Error(`Cannot create link to ${params.storageType} from ${storage.type} storage.`);
|
|
329
339
|
}
|
|
330
340
|
async link(path, target) {
|
|
331
341
|
if (!target ||
|
|
@@ -335,20 +345,21 @@ class XspFS {
|
|
|
335
345
|
const params = await target.getLinkParams();
|
|
336
346
|
this.ensureLinkingAllowedTo(params);
|
|
337
347
|
const { fileName, folderPath } = split(path);
|
|
338
|
-
const
|
|
339
|
-
|
|
348
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
349
|
+
const folder = await root.getFolderInThisSubTree(folderPath, true).catch(setExcPath(path));
|
|
340
350
|
await folder.createLink(fileName, params);
|
|
341
351
|
}
|
|
342
352
|
async readLink(path) {
|
|
343
353
|
const { fileName, folderPath } = split(path);
|
|
344
|
-
const
|
|
345
|
-
|
|
354
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
355
|
+
const folder = await root.getFolderInThisSubTree(folderPath).catch(setExcPath(path));
|
|
346
356
|
const link = await folder.getLink(fileName)
|
|
347
357
|
.catch(setExcPath(path));
|
|
348
358
|
return await link.read();
|
|
349
359
|
}
|
|
350
360
|
async getLinkParams() {
|
|
351
|
-
const
|
|
361
|
+
const root = this.v.getRootIfNotClosed(this.name);
|
|
362
|
+
const linkParams = root.getParamsForLink();
|
|
352
363
|
linkParams.params.folderName = this.name;
|
|
353
364
|
linkParams.readonly = !this.writable;
|
|
354
365
|
return linkParams;
|
|
@@ -356,25 +367,48 @@ class XspFS {
|
|
|
356
367
|
static async makeFolderFromLinkParams(storage, params) {
|
|
357
368
|
const name = params.params.folderName;
|
|
358
369
|
const writable = !params.readonly;
|
|
359
|
-
const
|
|
360
|
-
fs
|
|
370
|
+
const root = await folder_node_1.FolderNode.rootFromLinkParams(storage, params.params);
|
|
371
|
+
const fs = new XspFS(storage, writable, root, name);
|
|
361
372
|
return (fs.writable ? files_1.wrapWritableFS(fs) : files_1.wrapReadonlyFS(fs));
|
|
362
373
|
}
|
|
374
|
+
getCloseEvent$() {
|
|
375
|
+
return this.fsObs.event$.pipe(operators_1.filter(ev => (ev === 'close')));
|
|
376
|
+
}
|
|
363
377
|
watchFolder(path, observer) {
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
378
|
+
const folderPath = splitPathIntoParts(path);
|
|
379
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
380
|
+
const nodeProm = root.getFolderInThisSubTree(folderPath, false);
|
|
381
|
+
const watchSub = rxjs_1.from(nodeProm)
|
|
382
|
+
.pipe(operators_1.mergeMap(f => f.event$), operators_1.takeUntil(this.getCloseEvent$()))
|
|
383
|
+
.subscribe(utils_for_observables_1.toRxObserver(observer));
|
|
367
384
|
return () => watchSub.unsubscribe();
|
|
368
385
|
}
|
|
369
386
|
watchFile(path, observer) {
|
|
370
387
|
const { fileName, folderPath } = split(path);
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
388
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
389
|
+
const nodeProm = root.getFolderInThisSubTree(folderPath, false);
|
|
390
|
+
const watchSub = rxjs_1.from(nodeProm)
|
|
391
|
+
.pipe(operators_1.mergeMap(folder => folder.getFile(fileName)), operators_1.mergeMap(f => f.event$), operators_1.takeUntil(this.getCloseEvent$()))
|
|
392
|
+
.subscribe(utils_for_observables_1.toRxObserver(observer));
|
|
374
393
|
return () => watchSub.unsubscribe();
|
|
375
394
|
}
|
|
376
395
|
watchTree(path, observer) {
|
|
377
|
-
|
|
396
|
+
const folderPath = splitPathIntoParts(path);
|
|
397
|
+
const root = this.v.getRootIfNotClosed(path);
|
|
398
|
+
const idToPath = new ObjIdToPathMap();
|
|
399
|
+
const setupFilterMap = root.getFolderInThisSubTree(folderPath, false)
|
|
400
|
+
.then(rootNode => idToPath.fillFromTree(rootNode));
|
|
401
|
+
const watchSub = rxjs_1.from(setupFilterMap)
|
|
402
|
+
.pipe(operators_1.mergeMap(() => this.storage().getNodeEvents()), operators_1.map(nodeEvent => {
|
|
403
|
+
const path = idToPath.getPathCorrectingTreeMap(nodeEvent);
|
|
404
|
+
if (path) {
|
|
405
|
+
const event = nodeEvent.event;
|
|
406
|
+
event.path = path;
|
|
407
|
+
return event;
|
|
408
|
+
}
|
|
409
|
+
}, 1), operators_1.filter(event => !!event), operators_1.takeUntil(this.getCloseEvent$()))
|
|
410
|
+
.subscribe(utils_for_observables_1.toRxObserver(observer));
|
|
411
|
+
return () => watchSub.unsubscribe();
|
|
378
412
|
}
|
|
379
413
|
async readonlyFile(path) {
|
|
380
414
|
const fNode = await this.v.getOrCreateFile(path, {});
|
|
@@ -455,15 +489,23 @@ exports.XspFS = XspFS;
|
|
|
455
489
|
Object.freeze(XspFS.prototype);
|
|
456
490
|
Object.freeze(XspFS);
|
|
457
491
|
class V {
|
|
458
|
-
constructor() {
|
|
459
|
-
this.
|
|
492
|
+
constructor(root) {
|
|
493
|
+
this.rootNode = root;
|
|
460
494
|
Object.seal(this);
|
|
461
495
|
}
|
|
496
|
+
close() {
|
|
497
|
+
this.rootNode = undefined;
|
|
498
|
+
}
|
|
499
|
+
getRootIfNotClosed(excPath) {
|
|
500
|
+
if (!this.rootNode) {
|
|
501
|
+
throw file_1.makeFileException(file_1.Code.storageClosed, excPath);
|
|
502
|
+
}
|
|
503
|
+
return this.rootNode;
|
|
504
|
+
}
|
|
462
505
|
async getOrCreateFile(path, flags) {
|
|
463
506
|
const { fileName, folderPath } = split(path);
|
|
464
507
|
const { create, exclusive } = flags;
|
|
465
|
-
const folder = await this.
|
|
466
|
-
.catch(setExcPath(path));
|
|
508
|
+
const folder = await this.getRootIfNotClosed(path).getFolderInThisSubTree(folderPath, create).catch(setExcPath(path));
|
|
467
509
|
const nullOnMissing = create;
|
|
468
510
|
let file = await folder.getFile(fileName, nullOnMissing)
|
|
469
511
|
.catch(setExcPath(path));
|
|
@@ -479,10 +521,10 @@ class V {
|
|
|
479
521
|
}
|
|
480
522
|
async get(path) {
|
|
481
523
|
const { fileName, folderPath } = split(path);
|
|
482
|
-
const
|
|
483
|
-
|
|
524
|
+
const root = this.getRootIfNotClosed(path);
|
|
525
|
+
const folder = await root.getFolderInThisSubTree(folderPath, false).catch(setExcPath(path));
|
|
484
526
|
if (fileName === undefined) {
|
|
485
|
-
return
|
|
527
|
+
return root;
|
|
486
528
|
}
|
|
487
529
|
const node = await folder.getNode(undefined, fileName)
|
|
488
530
|
.catch(setExcPath(path));
|
|
@@ -505,7 +547,8 @@ class V {
|
|
|
505
547
|
};
|
|
506
548
|
}
|
|
507
549
|
async listFolder(path) {
|
|
508
|
-
const
|
|
550
|
+
const root = this.getRootIfNotClosed(path);
|
|
551
|
+
const folder = await root.getFolderInThisSubTree(splitPathIntoParts(path), false).catch(setExcPath(path));
|
|
509
552
|
return folder.list();
|
|
510
553
|
}
|
|
511
554
|
async writeBytes(path, bytes, flags = WRITE_NONEXCL_FLAGS) {
|
|
@@ -555,4 +598,92 @@ class V {
|
|
|
555
598
|
}
|
|
556
599
|
Object.freeze(V.prototype);
|
|
557
600
|
Object.freeze(V);
|
|
601
|
+
class ObjIdToPathMap {
|
|
602
|
+
constructor() {
|
|
603
|
+
this.map = new Map();
|
|
604
|
+
this.moves = new Map();
|
|
605
|
+
Object.seal(this);
|
|
606
|
+
}
|
|
607
|
+
async fillFromTree(root) {
|
|
608
|
+
for (const [objId, path] of await recursiveIdAndPathList(root, '.')) {
|
|
609
|
+
this.map.set(objId, path);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
getPathCorrectingTreeMap({ event, objId, parentObjId }) {
|
|
613
|
+
let path = this.map.get(objId);
|
|
614
|
+
if (path) {
|
|
615
|
+
if (event.type === 'removed') {
|
|
616
|
+
this.map.delete(objId);
|
|
617
|
+
}
|
|
618
|
+
else if (event.type === 'entry-renaming') {
|
|
619
|
+
const { newName, oldName } = event;
|
|
620
|
+
const child = this.findObjIdByPath(`${path}/${oldName}`);
|
|
621
|
+
if (child) {
|
|
622
|
+
this.map.set(child, `${path}/${newName}`);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
else if (event.type === 'entry-removal') {
|
|
626
|
+
const { moveLabel, name } = event;
|
|
627
|
+
if (moveLabel) {
|
|
628
|
+
const child = this.findObjIdByPath(`${path}/${name}`);
|
|
629
|
+
if (child) {
|
|
630
|
+
const moveInfo = this.moves.get(moveLabel);
|
|
631
|
+
if (moveInfo) {
|
|
632
|
+
this.map.set(child, moveInfo.newPath);
|
|
633
|
+
this.moves.delete(moveLabel);
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
this.moves.set(moveLabel, { objId: child });
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
else if (event.type === 'entry-addition') {
|
|
642
|
+
const { moveLabel, entry: { name } } = event;
|
|
643
|
+
const newPath = `${path}/${name}`;
|
|
644
|
+
if (moveLabel) {
|
|
645
|
+
const moveInfo = this.moves.get(moveLabel);
|
|
646
|
+
if (moveInfo) {
|
|
647
|
+
this.map.set(moveInfo.objId, newPath);
|
|
648
|
+
this.moves.delete(moveLabel);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
this.moves.set(moveLabel, { newPath });
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return path;
|
|
656
|
+
}
|
|
657
|
+
const parentPath = this.map.get(parentObjId);
|
|
658
|
+
if (!parentPath || (event.type === 'removed')) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
path = `${parentPath}/${event.path}`;
|
|
662
|
+
this.map.set(objId, path);
|
|
663
|
+
return path;
|
|
664
|
+
}
|
|
665
|
+
findObjIdByPath(path) {
|
|
666
|
+
for (const [objId, p] of this.map.entries()) {
|
|
667
|
+
if (p === path) {
|
|
668
|
+
return objId;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
Object.freeze(ObjIdToPathMap.prototype);
|
|
674
|
+
Object.freeze(ObjIdToPathMap);
|
|
675
|
+
async function recursiveIdAndPathList(folder, path) {
|
|
676
|
+
const { lst } = folder.list();
|
|
677
|
+
const idAndPaths = [[folder.objId, path]];
|
|
678
|
+
for (const item of lst) {
|
|
679
|
+
if (item.isFile || item.isLink) {
|
|
680
|
+
}
|
|
681
|
+
else if (item.isFolder) {
|
|
682
|
+
const child = await folder.getFolder(item.name);
|
|
683
|
+
const childLst = await recursiveIdAndPathList(child, `${path}/${item.name}`);
|
|
684
|
+
idAndPaths.push(...childLst);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return idAndPaths;
|
|
688
|
+
}
|
|
558
689
|
Object.freeze(exports);
|
|
@@ -2,8 +2,10 @@ import { Node, NodeType, Storage, RemoteEvent } from './common';
|
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { CommonAttrs, XAttrs } from './attrs';
|
|
4
4
|
import { NodePersistance } from './node-persistence';
|
|
5
|
+
import { UpSyncTaskInfo } from '../../../core/storage/synced/obj-status';
|
|
5
6
|
export declare type FSEvent = web3n.files.FolderEvent | web3n.files.FileEvent;
|
|
6
7
|
declare type XAttrsChanges = web3n.files.XAttrsChanges;
|
|
8
|
+
declare type Stats = web3n.files.Stats;
|
|
7
9
|
export declare abstract class NodeInFS<P extends NodePersistance> implements Node {
|
|
8
10
|
protected readonly storage: Storage;
|
|
9
11
|
readonly type: NodeType;
|
|
@@ -34,6 +36,7 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
|
|
|
34
36
|
private bufferRemoteEvent;
|
|
35
37
|
private getBufferedEvent;
|
|
36
38
|
localDelete(): Promise<void>;
|
|
39
|
+
broadcastUpSyncEvent(task: UpSyncTaskInfo): void;
|
|
37
40
|
/**
|
|
38
41
|
* This non-synchronized method deletes object from storage, and detaches
|
|
39
42
|
* this node from storage. Make sure to call it inside access synchronization
|
|
@@ -71,5 +74,6 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
|
|
|
71
74
|
*/
|
|
72
75
|
private events;
|
|
73
76
|
get event$(): Observable<FSEvent>;
|
|
77
|
+
sync(): Promise<Stats['sync']>;
|
|
74
78
|
}
|
|
75
79
|
export {};
|
|
@@ -21,7 +21,7 @@ exports.NodeInFS = void 0;
|
|
|
21
21
|
* Everything in this module is assumed to be inside of a file system
|
|
22
22
|
* reliance set.
|
|
23
23
|
*/
|
|
24
|
-
const
|
|
24
|
+
const synced_1 = require("../../../lib-common/processes/synced");
|
|
25
25
|
const file_1 = require("../../../lib-common/exceptions/file");
|
|
26
26
|
const error_1 = require("../../../lib-common/exceptions/error");
|
|
27
27
|
const rxjs_1 = require("rxjs");
|
|
@@ -96,7 +96,7 @@ class NodeInFS {
|
|
|
96
96
|
getAttrs() {
|
|
97
97
|
return this.attrs;
|
|
98
98
|
}
|
|
99
|
-
processRemoteEvent(event) {
|
|
99
|
+
async processRemoteEvent(event) {
|
|
100
100
|
this.bufferRemoteEvent(event);
|
|
101
101
|
return this.doChange(true, async () => {
|
|
102
102
|
const event = this.getBufferedEvent();
|
|
@@ -104,6 +104,10 @@ class NodeInFS {
|
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
if (event.type === 'remote-change') {
|
|
107
|
+
// TODO
|
|
108
|
+
// uploader should show if there is process for this obj uploads with version
|
|
109
|
+
// in the event, and if so, wait for completion of that process to either ignore
|
|
110
|
+
// remote event, or to set conflict, or whatever
|
|
107
111
|
// XXX should we use here synced storage methods here?
|
|
108
112
|
// This method is called only in synced storage.
|
|
109
113
|
// XXX detect if there is a conflict
|
|
@@ -127,6 +131,9 @@ class NodeInFS {
|
|
|
127
131
|
this.remoteEvents = [];
|
|
128
132
|
}
|
|
129
133
|
this.remoteEvents.push(event);
|
|
134
|
+
if (this.remoteEvents.length > 1) {
|
|
135
|
+
// XXX attempt to compress events
|
|
136
|
+
}
|
|
130
137
|
}
|
|
131
138
|
getBufferedEvent() {
|
|
132
139
|
if (!this.remoteEvents) {
|
|
@@ -141,13 +148,27 @@ class NodeInFS {
|
|
|
141
148
|
localDelete() {
|
|
142
149
|
return this.doChange(true, () => this.delete());
|
|
143
150
|
}
|
|
151
|
+
broadcastUpSyncEvent(task) {
|
|
152
|
+
if (task.type === 'upload') {
|
|
153
|
+
this.broadcastEvent({
|
|
154
|
+
type: 'sync-upload',
|
|
155
|
+
path: this.name,
|
|
156
|
+
current: this.version,
|
|
157
|
+
uploaded: task.version
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
144
161
|
/**
|
|
145
162
|
* This non-synchronized method deletes object from storage, and detaches
|
|
146
163
|
* this node from storage. Make sure to call it inside access synchronization
|
|
147
164
|
* construct.
|
|
148
165
|
*/
|
|
149
166
|
async delete(remoteEvent) {
|
|
150
|
-
if (
|
|
167
|
+
if (remoteEvent) {
|
|
168
|
+
// XXX
|
|
169
|
+
throw Error(`Removal from remote side is not implemented, yet.`);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
151
172
|
await this.storage.removeObj(this.objId);
|
|
152
173
|
}
|
|
153
174
|
this.storage.nodes.delete(this);
|
|
@@ -173,34 +194,32 @@ class NodeInFS {
|
|
|
173
194
|
*/
|
|
174
195
|
async doChange(awaitPrevChange, change) {
|
|
175
196
|
if (!this.writeProc) {
|
|
176
|
-
this.writeProc = new
|
|
197
|
+
this.writeProc = new synced_1.SingleProc();
|
|
177
198
|
}
|
|
178
199
|
if (!awaitPrevChange && this.writeProc.isProcessing()) {
|
|
179
200
|
throw file_1.makeFileException(file_1.Code.concurrentUpdate, this.name + ` type ${this.type}`);
|
|
180
201
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
throw file_1.makeFileException(file_1.Code.notFound, this.name);
|
|
185
|
-
}
|
|
186
|
-
return change();
|
|
187
|
-
});
|
|
188
|
-
return res;
|
|
189
|
-
}
|
|
190
|
-
catch (exc) {
|
|
191
|
-
if (!exc.runtimeException) {
|
|
192
|
-
throw error_1.errWithCause(exc, `Cannot save changes to ${this.type} ${this.name}, version ${this.version}`);
|
|
202
|
+
const res = await this.writeProc.startOrChain(() => {
|
|
203
|
+
if (this.currentVersion < 0) {
|
|
204
|
+
throw file_1.makeFileException(file_1.Code.notFound, this.name, `Object is marked removed`);
|
|
193
205
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
206
|
+
return change()
|
|
207
|
+
.catch((exc) => {
|
|
208
|
+
if (!exc.runtimeException) {
|
|
209
|
+
throw error_1.errWithCause(exc, `Cannot save changes to ${this.type} ${this.name}, version ${this.version}`);
|
|
197
210
|
}
|
|
198
|
-
|
|
199
|
-
|
|
211
|
+
if (exc.type === 'storage') {
|
|
212
|
+
if (exc.concurrentTransaction) {
|
|
213
|
+
throw file_1.makeFileException(file_1.Code.concurrentUpdate, this.name, exc);
|
|
214
|
+
}
|
|
215
|
+
else if (exc.objNotFound) {
|
|
216
|
+
throw file_1.makeFileException(file_1.Code.notFound, this.name, exc);
|
|
217
|
+
}
|
|
200
218
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
219
|
+
throw file_1.makeFileException(file_1.Code.ioError, this.name, exc);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
return res;
|
|
204
223
|
}
|
|
205
224
|
/**
|
|
206
225
|
* This method is called on conflict with remote version. This method
|
|
@@ -238,12 +257,14 @@ class NodeInFS {
|
|
|
238
257
|
this.broadcastEvent(event);
|
|
239
258
|
}
|
|
240
259
|
broadcastEvent(event, complete) {
|
|
260
|
+
this.storage.broadcastNodeEvent(this.objId, this.parentId, event);
|
|
241
261
|
if (!this.events) {
|
|
242
262
|
return;
|
|
243
263
|
}
|
|
244
264
|
this.events.next(event);
|
|
245
265
|
if (complete) {
|
|
246
266
|
this.events.complete();
|
|
267
|
+
this.events = undefined;
|
|
247
268
|
}
|
|
248
269
|
}
|
|
249
270
|
get event$() {
|
|
@@ -252,6 +273,12 @@ class NodeInFS {
|
|
|
252
273
|
}
|
|
253
274
|
return this.events.asObservable().pipe(operators_1.share());
|
|
254
275
|
}
|
|
276
|
+
async sync() {
|
|
277
|
+
if ((this.storage.type === 'synced')
|
|
278
|
+
|| (this.storage.type === 'share')) {
|
|
279
|
+
return this.storage.getObjSyncInfo(this.objId);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
255
282
|
}
|
|
256
283
|
exports.NodeInFS = NodeInFS;
|
|
257
284
|
Object.freeze(NodeInFS.prototype);
|
|
@@ -23,7 +23,7 @@ exports.NodePersistance = void 0;
|
|
|
23
23
|
*/
|
|
24
24
|
const xsp_files_1 = require("xsp-files");
|
|
25
25
|
const buffer_utils_1 = require("../../../lib-common/buffer-utils");
|
|
26
|
-
const
|
|
26
|
+
const deferred_1 = require("../../../lib-common/processes/deferred");
|
|
27
27
|
const random = require("../../../lib-common/random-node");
|
|
28
28
|
const pv1 = require("./xsp-payload-v1");
|
|
29
29
|
const pv2 = require("./xsp-payload-v2");
|
|
@@ -148,7 +148,7 @@ class NodePersistance {
|
|
|
148
148
|
this.segWriterWithBase(newVersion, base) :
|
|
149
149
|
this.segWriter(newVersion));
|
|
150
150
|
const { sink, sub } = xsp_files_1.makeEncryptingByteSink(segWriter);
|
|
151
|
-
const defSink =
|
|
151
|
+
const defSink = deferred_1.defer();
|
|
152
152
|
return {
|
|
153
153
|
sinkPromise: defSink.promise,
|
|
154
154
|
sub: (obs, backpressure) => {
|
|
@@ -19,7 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
exports.makeReadonlyPayload = void 0;
|
|
20
20
|
const assert_1 = require("../../../lib-common/assert");
|
|
21
21
|
const file_1 = require("../../../lib-common/exceptions/file");
|
|
22
|
-
const
|
|
22
|
+
const synced_1 = require("../../../lib-common/processes/synced");
|
|
23
23
|
const attrs_1 = require("./attrs");
|
|
24
24
|
async function makeReadonlyPayload(src) {
|
|
25
25
|
const payload = await ReadonlyPayloadV1.makeFor(src);
|
|
@@ -31,7 +31,7 @@ class ReadonlyPayloadV1 {
|
|
|
31
31
|
this.src = src;
|
|
32
32
|
this.size = size;
|
|
33
33
|
this.isEndless = isEndless;
|
|
34
|
-
this.syncProc = new
|
|
34
|
+
this.syncProc = new synced_1.SingleProc();
|
|
35
35
|
this.xattrs = undefined;
|
|
36
36
|
this.isEndless = (this.size === undefined);
|
|
37
37
|
Object.seal(this);
|
|
@@ -20,7 +20,7 @@ exports.makeWritablePayloadFromBase = exports.makeWritablePayload = exports.make
|
|
|
20
20
|
const assert_1 = require("../../../lib-common/assert");
|
|
21
21
|
const big_endian_1 = require("../../../lib-common/big-endian");
|
|
22
22
|
const attrs_1 = require("./attrs");
|
|
23
|
-
const
|
|
23
|
+
const synced_1 = require("../../../lib-common/processes/synced");
|
|
24
24
|
const wrapping_1 = require("../../../lib-common/byte-streaming/wrapping");
|
|
25
25
|
const buffer_utils_1 = require("../../../lib-common/buffer-utils");
|
|
26
26
|
async function makeReadonlyPayload(src) {
|
|
@@ -47,7 +47,7 @@ class ReadonlyPayloadV2 {
|
|
|
47
47
|
this.attrs = attrs;
|
|
48
48
|
this.contentSections = contentSections;
|
|
49
49
|
this.xattrsSections = xattrsSections;
|
|
50
|
-
this.syncProc = new
|
|
50
|
+
this.syncProc = new synced_1.SingleProc();
|
|
51
51
|
this.xattrs = undefined;
|
|
52
52
|
this.size = sizeOfContent(this.contentSections);
|
|
53
53
|
Object.seal(this);
|
|
@@ -247,7 +247,7 @@ class WritablePayloadV2 {
|
|
|
247
247
|
this.attrs = attrs;
|
|
248
248
|
this.contentSections = contentSections;
|
|
249
249
|
this.xattrsSections = xattrsSections;
|
|
250
|
-
this.syncProc = new
|
|
250
|
+
this.syncProc = new synced_1.SingleProc();
|
|
251
251
|
this.completionErr = undefined;
|
|
252
252
|
assert_1.assert(!!this.sink);
|
|
253
253
|
if ((this.contentSections.length + this.xattrsSections.length) === 0) {
|