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.
Files changed (113) 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 +17 -34
  47. package/build/ipc-via-protobuf/connector-clients-side.js +2 -2
  48. package/build/ipc-via-protobuf/file.js +26 -18
  49. package/build/ipc-via-protobuf/fs.js +33 -35
  50. package/build/ipc-via-protobuf/mailerid.js +3 -2
  51. package/build/ipc-via-protobuf/protobuf-msg.d.ts +2 -0
  52. package/build/ipc-via-protobuf/protobuf-msg.js +11 -1
  53. package/build/ipc-via-protobuf/startup-cap.js +5 -5
  54. package/build/lib-client/3nstorage/exceptions.d.ts +9 -8
  55. package/build/lib-client/3nstorage/exceptions.js +18 -9
  56. package/build/lib-client/3nstorage/service.js +10 -6
  57. package/build/lib-client/3nstorage/xsp-fs/common.d.ts +18 -4
  58. package/build/lib-client/3nstorage/xsp-fs/common.js +6 -1
  59. package/build/lib-client/3nstorage/xsp-fs/file-node.js +3 -3
  60. package/build/lib-client/3nstorage/xsp-fs/file.js +4 -1
  61. package/build/lib-client/3nstorage/xsp-fs/folder-node.js +27 -13
  62. package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +11 -6
  63. package/build/lib-client/3nstorage/xsp-fs/fs.js +189 -58
  64. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +4 -0
  65. package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +51 -24
  66. package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +2 -2
  67. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +2 -2
  68. package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +3 -3
  69. package/build/lib-client/cryptor/cryptor-in-worker.js +4 -4
  70. package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
  71. package/build/lib-client/cryptor/cryptor.wasm +0 -0
  72. package/build/lib-client/cryptor/in-proc-wasm.js +2 -2
  73. package/build/lib-client/files.js +2 -0
  74. package/build/lib-client/fs-collection.js +3 -2
  75. package/build/lib-client/logging/log-to-file.js +6 -14
  76. package/build/lib-client/objs-on-disk/file-writing-proc.js +2 -2
  77. package/build/lib-client/objs-on-disk/obj-folders.d.ts +12 -1
  78. package/build/lib-client/objs-on-disk/obj-folders.js +26 -19
  79. package/build/lib-client/request-utils.js +2 -2
  80. package/build/lib-client/server-events.js +4 -3
  81. package/build/lib-client/ws-utils.js +2 -2
  82. package/build/lib-common/async-fs-node.d.ts +6 -0
  83. package/build/lib-common/async-fs-node.js +28 -4
  84. package/build/lib-common/byte-streaming/wrapping.js +17 -17
  85. package/build/lib-common/exceptions/file.js +6 -1
  86. package/build/lib-common/ipc/generic-ipc.js +2 -2
  87. package/build/lib-common/json-utils.js +2 -1
  88. package/build/lib-common/objs-on-disk/obj-file.js +4 -3
  89. package/build/lib-common/objs-on-disk/utils.js +2 -2
  90. package/build/lib-common/processes/deferred.d.ts +6 -0
  91. package/build/lib-common/processes/deferred.js +30 -0
  92. package/build/lib-common/processes/labelled-exec-pools.d.ts +33 -0
  93. package/build/lib-common/processes/labelled-exec-pools.js +141 -0
  94. package/build/lib-common/processes/pressure.d.ts +7 -0
  95. package/build/lib-common/processes/pressure.js +56 -0
  96. package/build/lib-common/processes/sleep.d.ts +1 -0
  97. package/build/lib-common/processes/sleep.js +26 -0
  98. package/build/lib-common/{processes.d.ts → processes/synced.d.ts} +0 -40
  99. package/build/lib-common/{processes.js → processes/synced.js} +187 -204
  100. package/build/lib-common/processes/timeout.d.ts +1 -0
  101. package/build/lib-common/processes/timeout.js +51 -0
  102. package/build/lib-common/service-api/3nstorage/owner.d.ts +5 -4
  103. package/build/lib-common/service-api/3nstorage/owner.js +3 -2
  104. package/build/lib-common/utils-for-observables.d.ts +15 -1
  105. package/build/lib-common/utils-for-observables.js +68 -17
  106. package/build/protos/asmail.proto.js +404 -78
  107. package/build/protos/file.proto.js +370 -44
  108. package/build/protos/fs.proto.js +404 -78
  109. package/package.json +4 -4
  110. package/protos/file.proto +10 -2
  111. package/protos/fs.proto +2 -2
  112. package/build/core/storage/synced/upsync-status.d.ts +0 -41
  113. 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.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 {};
@@ -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 processes_1 = require("../../../lib-common/processes");
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 (!remoteEvent) {
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 processes_1.SingleProc();
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
- try {
182
- const res = await this.writeProc.startOrChain(() => {
183
- if (this.currentVersion < 0) {
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
- if (exc.type === 'storage') {
195
- if (exc.concurrentTransaction) {
196
- throw file_1.makeFileException(file_1.Code.concurrentUpdate, this.name, exc);
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
- else if (exc.objNotFound) {
199
- throw file_1.makeFileException(file_1.Code.notFound, this.name, exc);
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
- throw file_1.makeFileException(file_1.Code.ioError, this.name, exc);
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 processes_1 = require("../../../lib-common/processes");
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 = processes_1.defer();
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 processes_1 = require("../../../lib-common/processes");
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 processes_1.SingleProc();
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 processes_1 = require("../../../lib-common/processes");
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 processes_1.SingleProc();
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 processes_1.SingleProc();
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) {