core-3nweb-client-lib 0.25.6 → 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 +15 -32
- package/build/ipc-via-protobuf/connector-clients-side.js +2 -2
- package/build/ipc-via-protobuf/file.js +22 -14
- package/build/ipc-via-protobuf/fs.js +31 -33
- 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 +4 -4
- package/build/lib-client/objs-on-disk/file-writing-proc.js +2 -2
- package/build/lib-client/objs-on-disk/obj-folders.js +2 -2
- 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.js +4 -3
- 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
|
@@ -27,7 +27,7 @@ const error_1 = require("../../../lib-common/exceptions/error");
|
|
|
27
27
|
const node_in_fs_1 = require("./node-in-fs");
|
|
28
28
|
const file_node_1 = require("./file-node");
|
|
29
29
|
const link_node_1 = require("./link-node");
|
|
30
|
-
const
|
|
30
|
+
const deferred_1 = require("../../../lib-common/processes/deferred");
|
|
31
31
|
const json_utils_1 = require("../../../lib-common/json-utils");
|
|
32
32
|
const xsp_files_1 = require("xsp-files");
|
|
33
33
|
const random = require("../../../lib-common/random-node");
|
|
@@ -62,6 +62,17 @@ class FolderPersistance extends node_persistence_1.NodePersistance {
|
|
|
62
62
|
}
|
|
63
63
|
Object.freeze(FolderPersistance.prototype);
|
|
64
64
|
Object.freeze(FolderPersistance);
|
|
65
|
+
let nextMoveLabel = Math.floor(Math.random() / 2 * Number.MAX_SAFE_INTEGER);
|
|
66
|
+
function getMoveLabel() {
|
|
67
|
+
const label = nextMoveLabel;
|
|
68
|
+
if (nextMoveLabel >= Number.MAX_SAFE_INTEGER) {
|
|
69
|
+
nextMoveLabel = 0;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
nextMoveLabel += 1;
|
|
73
|
+
}
|
|
74
|
+
return label;
|
|
75
|
+
}
|
|
65
76
|
class FolderNode extends node_in_fs_1.NodeInFS {
|
|
66
77
|
constructor(storage, name, objId, zNonce, version, parentId, key, setNewAttrs) {
|
|
67
78
|
super(storage, 'folder', name, objId, version, parentId);
|
|
@@ -183,7 +194,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
183
194
|
if (nodePromise) {
|
|
184
195
|
return { nodeOrPromise: nodePromise };
|
|
185
196
|
}
|
|
186
|
-
const deferred =
|
|
197
|
+
const deferred = deferred_1.defer();
|
|
187
198
|
this.storage.nodes.setPromise(objId, deferred.promise);
|
|
188
199
|
return { deferred };
|
|
189
200
|
}
|
|
@@ -462,28 +473,30 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
462
473
|
}
|
|
463
474
|
if (dst === this) {
|
|
464
475
|
// In this case we only need to change child's name
|
|
465
|
-
|
|
476
|
+
await this.changeChildName(childName, nameInDst);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
const childJSON = this.getNodeInfo(childName);
|
|
480
|
+
// we have two transitions here, in this and in dst.
|
|
481
|
+
const moveLabel = getMoveLabel();
|
|
482
|
+
await dst.moveChildIn(nameInDst, childJSON, moveLabel);
|
|
483
|
+
await this.moveChildOut(childName, moveLabel);
|
|
466
484
|
}
|
|
467
|
-
const childJSON = this.getNodeInfo(childName);
|
|
468
|
-
// we have two transitions here, in this and in dst.
|
|
469
|
-
await Promise.all([
|
|
470
|
-
await dst.moveChildIn(nameInDst, childJSON),
|
|
471
|
-
await this.moveChildOut(childName)
|
|
472
|
-
]);
|
|
473
485
|
}
|
|
474
|
-
async moveChildOut(name) {
|
|
486
|
+
async moveChildOut(name, moveLabel) {
|
|
475
487
|
await this.doTransition(async (state, version) => {
|
|
476
488
|
delete state.nodes[name];
|
|
477
489
|
const event = {
|
|
478
490
|
type: 'entry-removal',
|
|
479
491
|
path: this.name,
|
|
480
492
|
name,
|
|
481
|
-
newVersion: version
|
|
493
|
+
newVersion: version,
|
|
494
|
+
moveLabel
|
|
482
495
|
};
|
|
483
496
|
return event;
|
|
484
497
|
});
|
|
485
498
|
}
|
|
486
|
-
async moveChildIn(newName, child) {
|
|
499
|
+
async moveChildIn(newName, child, moveLabel) {
|
|
487
500
|
child = json_utils_1.copy(child);
|
|
488
501
|
await this.doTransition(async (state, version) => {
|
|
489
502
|
child.name = newName;
|
|
@@ -497,7 +510,8 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
497
510
|
isFolder: child.isFolder,
|
|
498
511
|
isLink: child.isLink
|
|
499
512
|
},
|
|
500
|
-
newVersion: version
|
|
513
|
+
newVersion: version,
|
|
514
|
+
moveLabel
|
|
501
515
|
};
|
|
502
516
|
return event;
|
|
503
517
|
});
|
|
@@ -23,12 +23,14 @@ declare type FileByteSource = web3n.files.FileByteSource;
|
|
|
23
23
|
declare type FileByteSink = web3n.files.FileByteSink;
|
|
24
24
|
declare type XAttrsChanges = web3n.files.XAttrsChanges;
|
|
25
25
|
export declare class XspFS implements WritableFS {
|
|
26
|
-
|
|
27
|
-
writable: boolean;
|
|
26
|
+
readonly writable: boolean;
|
|
28
27
|
name: string;
|
|
29
|
-
type: FSType;
|
|
30
|
-
v: V;
|
|
28
|
+
readonly type: FSType;
|
|
29
|
+
readonly v: V;
|
|
30
|
+
private store;
|
|
31
|
+
private readonly fsObs;
|
|
31
32
|
private constructor();
|
|
33
|
+
private storage;
|
|
32
34
|
readonlySubRoot(path: string): Promise<ReadonlyFS>;
|
|
33
35
|
writableSubRoot(path: string, flags?: web3n.files.VersionedFileFlags): Promise<WritableFS>;
|
|
34
36
|
/**
|
|
@@ -74,6 +76,7 @@ export declare class XspFS implements WritableFS {
|
|
|
74
76
|
readLink(path: string): Promise<SymLink>;
|
|
75
77
|
getLinkParams(): Promise<LinkParameters<any>>;
|
|
76
78
|
static makeFolderFromLinkParams(storage: Storage, params: LinkParameters<FolderLinkParams>): Promise<ReadonlyFS | WritableFS>;
|
|
79
|
+
private getCloseEvent$;
|
|
77
80
|
watchFolder(path: string, observer: Observer<FolderEvent>): () => void;
|
|
78
81
|
watchFile(path: string, observer: Observer<FileEvent>): () => void;
|
|
79
82
|
watchTree(path: string, observer: Observer<FolderEvent | FileEvent>): () => void;
|
|
@@ -93,8 +96,10 @@ export declare class XspFS implements WritableFS {
|
|
|
93
96
|
}
|
|
94
97
|
declare type WritableFSVersionedAPI = web3n.files.WritableFSVersionedAPI;
|
|
95
98
|
declare class V implements WritableFSVersionedAPI {
|
|
96
|
-
|
|
97
|
-
constructor();
|
|
99
|
+
private rootNode;
|
|
100
|
+
constructor(root: FolderNode);
|
|
101
|
+
close(): void;
|
|
102
|
+
getRootIfNotClosed(excPath: string): FolderNode;
|
|
98
103
|
getOrCreateFile(path: string, flags: FileFlags): Promise<FileNode>;
|
|
99
104
|
get(path: string): Promise<NodeInFS<any>>;
|
|
100
105
|
updateXAttrs(path: string, changes: XAttrsChanges): Promise<number>;
|
|
@@ -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 {};
|