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.
Files changed (108) hide show
  1. package/README.md +2 -2
  2. package/build/api-defs/files.d.ts +23 -20
  3. package/build/core/asmail/config/common.js +2 -2
  4. package/build/core/asmail/delivery/index.js +4 -3
  5. package/build/core/asmail/delivery/msg.js +5 -4
  6. package/build/core/asmail/delivery/per-recipient-wip.js +2 -2
  7. package/build/core/asmail/inbox/attachments/fs.js +6 -0
  8. package/build/core/asmail/inbox/cached-msgs.js +2 -2
  9. package/build/core/asmail/inbox/inbox-events.js +2 -1
  10. package/build/core/asmail/inbox/index.js +2 -2
  11. package/build/core/asmail/inbox/msg-downloader.js +2 -2
  12. package/build/core/asmail/inbox/msg-indexing.js +3 -3
  13. package/build/core/asmail/inbox/msg-on-disk.js +2 -2
  14. package/build/core/asmail/keyring/keyring-storage.js +2 -2
  15. package/build/core/asmail/sending-params/own-params.js +2 -2
  16. package/build/core/asmail/sending-params/params-from-others.js +2 -2
  17. package/build/core/id-manager.js +2 -2
  18. package/build/core/sign-in.d.ts +5 -4
  19. package/build/core/sign-in.js +9 -11
  20. package/build/core/sign-up.d.ts +1 -0
  21. package/build/core/sign-up.js +7 -3
  22. package/build/core/storage/common/json-saving.d.ts +21 -0
  23. package/build/core/storage/common/json-saving.js +82 -0
  24. package/build/core/storage/common/obj-info-file.d.ts +43 -0
  25. package/build/core/storage/common/obj-info-file.js +119 -3
  26. package/build/core/storage/index.js +1 -1
  27. package/build/core/storage/local/obj-files-gc.js +8 -6
  28. package/build/core/storage/local/obj-files.d.ts +3 -3
  29. package/build/core/storage/local/obj-files.js +9 -9
  30. package/build/core/storage/local/obj-status.d.ts +9 -25
  31. package/build/core/storage/local/obj-status.js +28 -110
  32. package/build/core/storage/local/storage.d.ts +8 -1
  33. package/build/core/storage/local/storage.js +10 -2
  34. package/build/core/storage/synced/downloader.js +6 -5
  35. package/build/core/storage/synced/obj-files-gc.d.ts +1 -0
  36. package/build/core/storage/synced/obj-files-gc.js +44 -5
  37. package/build/core/storage/synced/obj-files.d.ts +13 -20
  38. package/build/core/storage/synced/obj-files.js +70 -48
  39. package/build/core/storage/synced/obj-status.d.ts +74 -15
  40. package/build/core/storage/synced/obj-status.js +291 -107
  41. package/build/core/storage/synced/remote-events.js +32 -26
  42. package/build/core/storage/synced/storage.d.ts +11 -1
  43. package/build/core/storage/synced/storage.js +28 -3
  44. package/build/core/storage/synced/upsyncer.d.ts +8 -7
  45. package/build/core/storage/synced/upsyncer.js +211 -163
  46. package/build/ipc-via-protobuf/asmail-cap.js +15 -32
  47. package/build/ipc-via-protobuf/connector-clients-side.js +2 -2
  48. package/build/ipc-via-protobuf/file.js +22 -14
  49. package/build/ipc-via-protobuf/fs.js +31 -33
  50. package/build/ipc-via-protobuf/startup-cap.js +5 -5
  51. package/build/lib-client/3nstorage/exceptions.d.ts +9 -8
  52. package/build/lib-client/3nstorage/exceptions.js +18 -9
  53. package/build/lib-client/3nstorage/service.js +10 -6
  54. package/build/lib-client/3nstorage/xsp-fs/common.d.ts +18 -4
  55. package/build/lib-client/3nstorage/xsp-fs/common.js +6 -1
  56. package/build/lib-client/3nstorage/xsp-fs/file-node.js +3 -3
  57. package/build/lib-client/3nstorage/xsp-fs/file.js +4 -1
  58. package/build/lib-client/3nstorage/xsp-fs/folder-node.js +27 -13
  59. package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +11 -6
  60. package/build/lib-client/3nstorage/xsp-fs/fs.js +189 -58
  61. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +4 -0
  62. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +51 -24
  63. package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +2 -2
  64. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +2 -2
  65. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +3 -3
  66. package/build/lib-client/cryptor/cryptor-in-worker.js +4 -4
  67. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  68. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  69. package/build/lib-client/cryptor/in-proc-wasm.js +2 -2
  70. package/build/lib-client/files.js +2 -0
  71. package/build/lib-client/fs-collection.js +3 -2
  72. package/build/lib-client/logging/log-to-file.js +4 -4
  73. package/build/lib-client/objs-on-disk/file-writing-proc.js +2 -2
  74. package/build/lib-client/objs-on-disk/obj-folders.js +2 -2
  75. package/build/lib-client/request-utils.js +2 -2
  76. package/build/lib-client/server-events.js +4 -3
  77. package/build/lib-client/ws-utils.js +2 -2
  78. package/build/lib-common/async-fs-node.js +4 -3
  79. package/build/lib-common/byte-streaming/wrapping.js +17 -17
  80. package/build/lib-common/exceptions/file.js +6 -1
  81. package/build/lib-common/ipc/generic-ipc.js +2 -2
  82. package/build/lib-common/json-utils.js +2 -1
  83. package/build/lib-common/objs-on-disk/obj-file.js +4 -3
  84. package/build/lib-common/objs-on-disk/utils.js +2 -2
  85. package/build/lib-common/processes/deferred.d.ts +6 -0
  86. package/build/lib-common/processes/deferred.js +30 -0
  87. package/build/lib-common/processes/labelled-exec-pools.d.ts +33 -0
  88. package/build/lib-common/processes/labelled-exec-pools.js +141 -0
  89. package/build/lib-common/processes/pressure.d.ts +7 -0
  90. package/build/lib-common/processes/pressure.js +56 -0
  91. package/build/lib-common/processes/sleep.d.ts +1 -0
  92. package/build/lib-common/processes/sleep.js +26 -0
  93. package/build/lib-common/{processes.d.ts → processes/synced.d.ts} +0 -40
  94. package/build/lib-common/{processes.js → processes/synced.js} +187 -204
  95. package/build/lib-common/processes/timeout.d.ts +1 -0
  96. package/build/lib-common/processes/timeout.js +51 -0
  97. package/build/lib-common/service-api/3nstorage/owner.d.ts +5 -4
  98. package/build/lib-common/service-api/3nstorage/owner.js +3 -2
  99. package/build/lib-common/utils-for-observables.d.ts +15 -1
  100. package/build/lib-common/utils-for-observables.js +68 -17
  101. package/build/protos/asmail.proto.js +404 -78
  102. package/build/protos/file.proto.js +370 -44
  103. package/build/protos/fs.proto.js +404 -78
  104. package/package.json +4 -4
  105. package/protos/file.proto +10 -2
  106. package/protos/fs.proto +2 -2
  107. package/build/core/storage/synced/upsync-status.d.ts +0 -41
  108. 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 processes_1 = require("../../../lib-common/processes");
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 = processes_1.defer();
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
- return this.changeChildName(childName, nameInDst);
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
- storage: Storage;
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
- root: FolderNode;
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.v = new V();
63
- this.type = this.storage.type;
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 folder = await this.v.root.getFolderInThisSubTree(pathParts, false)
69
- .catch(setExcPath(path));
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 folder = await this.v.root.getFolderInThisSubTree(pathParts, flags.create, flags.exclusive)
79
- .catch(setExcPath(path));
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 fs = new XspFS(storage, true);
94
- fs.v.root = await folder_node_1.FolderNode.newRoot(fs.storage, key);
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
- fs.v.root = await folder_node_1.FolderNode.rootFromObjBytes(fs.storage, undefined, null, objSrc, key);
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 fs = new XspFS(storage, false, rootName);
111
- fs.v.root = folder_node_1.FolderNode.rootFromJSON(storage, rootName, folderJson);
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.root = undefined;
119
- this.storage = undefined;
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
- await this.v.root.getFolderInThisSubTree(folderPath, true, exclusive)
124
- .catch(setExcPath(path));
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 parentFolder = await this.v.root.getFolderInThisSubTree(parentPath)
132
- .catch(setExcPath(parentPath.join('/')));
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 parentFolder = await this.v.root.getFolderInThisSubTree(folderPath)
146
- .catch(setExcPath(path));
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 parentFolder = await this.v.root.getFolderInThisSubTree(folderPath)
154
- .catch(setExcPath(path));
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 this.v.root.getFolderInThisSubTree(srcFolderPath);
180
+ const srcFolder = await root.getFolderInThisSubTree(srcFolderPath);
174
181
  srcFolder.hasChild(initFName, true);
175
- const dstFolder = await this.v.root.getFolderInThisSubTree(dstFolderPath, true);
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
- if (this.storage.type === 'local') {
323
+ const storage = this.storage();
324
+ if (storage.type === 'local') {
315
325
  return;
316
326
  }
317
- else if (this.storage.type === 'synced') {
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 (this.storage.type === 'share') {
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 ${this.storage.type} storage.`);
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 folder = await this.v.root.getFolderInThisSubTree(folderPath, true)
339
- .catch(setExcPath(path));
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 folder = await this.v.root.getFolderInThisSubTree(folderPath)
345
- .catch(setExcPath(path));
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 linkParams = this.v.root.getParamsForLink();
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 fs = new XspFS(storage, writable, name);
360
- fs.v.root = await folder_node_1.FolderNode.rootFromLinkParams(storage, params.params);
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 watchSub = rxjs_1.from(this.v.root.getFolderInThisSubTree(splitPathIntoParts(path), false))
365
- .pipe(operators_1.mergeMap(f => f.event$))
366
- .subscribe(observer);
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 watchSub = rxjs_1.from(this.v.root.getFolderInThisSubTree(folderPath, false))
372
- .pipe(operators_1.mergeMap(folder => folder.getFile(fileName)), operators_1.mergeMap(f => f.event$))
373
- .subscribe(observer);
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
- throw new Error('Not implemented, yet');
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.root = undefined;
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.root.getFolderInThisSubTree(folderPath, create)
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 folder = await this.root.getFolderInThisSubTree(folderPath, false)
483
- .catch(setExcPath(path));
524
+ const root = this.getRootIfNotClosed(path);
525
+ const folder = await root.getFolderInThisSubTree(folderPath, false).catch(setExcPath(path));
484
526
  if (fileName === undefined) {
485
- return this.root;
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 folder = await this.root.getFolderInThisSubTree(splitPathIntoParts(path), false).catch(setExcPath(path));
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 {};