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
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020 3NSoft Inc.
3
+ Copyright (C) 2015 - 2020, 2022 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -13,7 +13,8 @@
13
13
  See the GNU General Public License for more details.
14
14
 
15
15
  You should have received a copy of the GNU General Public License along with
16
- this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
17
18
  Object.defineProperty(exports, "__esModule", { value: true });
18
19
  exports.SyncedStore = void 0;
19
20
  const common_1 = require("../../../lib-client/3nstorage/xsp-fs/common");
@@ -26,6 +27,7 @@ const xsp_files_1 = require("xsp-files");
26
27
  const downloader_1 = require("./downloader");
27
28
  const remote_events_1 = require("./remote-events");
28
29
  const upsyncer_1 = require("./upsyncer");
30
+ const utils_for_observables_1 = require("../../../lib-common/utils-for-observables");
29
31
  class SyncedStore {
30
32
  constructor(files, remoteStorage, getStorages, cryptor, logError) {
31
33
  this.files = files;
@@ -36,15 +38,17 @@ class SyncedStore {
36
38
  this.type = 'synced';
37
39
  this.versioned = true;
38
40
  this.nodes = new common_1.NodesContainer();
41
+ this.events = new utils_for_observables_1.Broadcast();
39
42
  const getFSNodes = (objId) => this.nodes.get(objId);
40
43
  this.remoteEvents = new remote_events_1.RemoteEvents(this.remoteStorage, this.files, getFSNodes, this.logError);
41
- this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.files, this.logError);
44
+ this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.logError, this.broadcastUpSyncEvent.bind(this));
42
45
  Object.seal(this);
43
46
  }
44
47
  static async makeAndStart(path, user, getSigner, getStorages, cryptor, remoteServiceUrl, makeNet, logError) {
45
48
  const remote = new service_1.StorageOwner(user, getSigner, remoteServiceUrl, makeNet());
46
49
  const objFiles = await obj_files_1.ObjFiles.makeFor(path, new downloader_1.Downloader(remote), logError);
47
50
  const s = new SyncedStore(objFiles, remote, getStorages, cryptor, logError);
51
+ s.uploader.start();
48
52
  return {
49
53
  syncedStore: common_1.wrapSyncStorageImplementation(s),
50
54
  startObjProcs: () => {
@@ -52,6 +56,19 @@ class SyncedStore {
52
56
  }
53
57
  };
54
58
  }
59
+ getNodeEvents() {
60
+ return this.events.event$;
61
+ }
62
+ broadcastNodeEvent(objId, parentObjId, event) {
63
+ this.events.next({ objId, parentObjId, event });
64
+ }
65
+ broadcastUpSyncEvent(objId, task) {
66
+ const node = this.nodes.get(objId);
67
+ if (!node) {
68
+ return;
69
+ }
70
+ node.broadcastUpSyncEvent(task);
71
+ }
55
72
  storageForLinking(type, location) {
56
73
  if (type === 'synced') {
57
74
  return common_1.wrapStorageImplementation(this);
@@ -63,6 +80,13 @@ class SyncedStore {
63
80
  throw new Error(`Getting ${type} storage is not implemented in local storage.`);
64
81
  }
65
82
  }
83
+ async getObjSyncInfo(objId) {
84
+ const obj = await this.files.findObj(objId);
85
+ if (!obj) {
86
+ return;
87
+ }
88
+ return obj.sync().stat();
89
+ }
66
90
  getRootKeyDerivParamsFromServer() {
67
91
  return this.remoteStorage.getKeyDerivParams();
68
92
  }
@@ -132,6 +156,7 @@ class SyncedStore {
132
156
  async close() {
133
157
  try {
134
158
  await this.uploader.stop();
159
+ this.events.done();
135
160
  await this.remoteEvents.close();
136
161
  await this.remoteStorage.logout();
137
162
  }
@@ -1,21 +1,22 @@
1
1
  import { StorageOwner } from "../../../lib-client/3nstorage/service";
2
- import { SyncedObj, ObjFiles } from "./obj-files";
2
+ import { SyncedObj } from "./obj-files";
3
3
  import { MonoTypeOperatorFunction } from "rxjs";
4
4
  import { FileWrite } from "../../../lib-client/objs-on-disk/file-writing-proc";
5
5
  import { LogError } from "../../../lib-client/logging/log-to-file";
6
+ import { UpSyncTaskInfo } from "./obj-status";
7
+ import { ObjId } from "../../../lib-client/3nstorage/xsp-fs/common";
8
+ export declare type FileWriteTapOperator = MonoTypeOperatorFunction<FileWrite[]>;
9
+ export declare type BroadcastUpSyncEvent = (objId: ObjId, task: UpSyncTaskInfo) => void;
6
10
  export declare class UpSyncer {
7
11
  private readonly remoteStorage;
8
- private readonly files;
9
12
  private readonly logError;
13
+ private readonly broadcastUpSyncEvent;
14
+ private readonly execPools;
10
15
  private readonly uploads;
11
- constructor(remoteStorage: StorageOwner, files: ObjFiles, logError: LogError);
16
+ constructor(remoteStorage: StorageOwner, logError: LogError, broadcastUpSyncEvent: BroadcastUpSyncEvent);
12
17
  private getOrMakeUploadsFor;
13
18
  start(): void;
14
19
  stop(): Promise<void>;
15
- get chunkSize(): number;
16
- private readonly addToWorker;
17
20
  tapFileWrite(obj: SyncedObj, isNew: boolean, newVersion: number, baseVersion?: number): FileWriteTapOperator;
18
21
  removeCurrentVersionOf(obj: SyncedObj): Promise<void>;
19
- private readonly worker;
20
22
  }
21
- export declare type FileWriteTapOperator = MonoTypeOperatorFunction<FileWrite[]>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020 3NSoft Inc.
3
+ Copyright (C) 2020, 2022 3NSoft Inc.
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under
6
6
  the terms of the GNU General Public License as published by the Free Software
@@ -13,139 +13,230 @@
13
13
  See the GNU General Public License for more details.
14
14
 
15
15
  You should have received a copy of the GNU General Public License along with
16
- this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
17
18
  Object.defineProperty(exports, "__esModule", { value: true });
18
19
  exports.UpSyncer = void 0;
19
20
  const operators_1 = require("rxjs/operators");
20
- const processes_1 = require("../../../lib-common/processes");
21
- const upsync_status_1 = require("./upsync-status");
21
+ const labelled_exec_pools_1 = require("../../../lib-common/processes/labelled-exec-pools");
22
22
  const assert_1 = require("../../../lib-common/assert");
23
23
  const MAX_CHUNK_SIZE = 512 * 1024;
24
+ const MAX_FAST_UPLOAD = 2 * 1024 * 1024;
25
+ function executorLabelFor(info) {
26
+ let uploadSize = 0;
27
+ if (info.header) {
28
+ uploadSize += info.header;
29
+ }
30
+ for (const seg of info.segs) {
31
+ uploadSize += seg.len;
32
+ }
33
+ return ((uploadSize <= MAX_FAST_UPLOAD) ? 'fast' : 'long');
34
+ }
35
+ function addEventToInfo(info, writeEv) {
36
+ for (const w of writeEv) {
37
+ if (w.isHeader) {
38
+ info.header = w.bytes.length;
39
+ }
40
+ else {
41
+ mergeSections(info.segs, w);
42
+ }
43
+ }
44
+ }
45
+ function mergeSections(segs, w) {
46
+ const wStart = w.ofs;
47
+ const wLen = w.bytes.length;
48
+ for (let i = 0; i < segs.length; i += 1) {
49
+ const section = segs[i];
50
+ const sectionEnd = section.ofs + section.len;
51
+ if (sectionEnd < wStart) {
52
+ continue;
53
+ }
54
+ if (sectionEnd === wStart) {
55
+ section.len += wLen;
56
+ }
57
+ else if (section.ofs <= wStart) {
58
+ const maxOverlap = section.len - (wStart - section.ofs);
59
+ if (maxOverlap < wLen) {
60
+ section.len += wLen - maxOverlap;
61
+ }
62
+ }
63
+ else if ((wStart + wLen) === section.ofs) {
64
+ section.ofs = wStart;
65
+ }
66
+ else {
67
+ segs.splice(i, 0, { ofs: wStart, len: wLen });
68
+ }
69
+ return;
70
+ }
71
+ segs.push({ ofs: wStart, len: wLen });
72
+ }
24
73
  class UpSyncer {
25
- constructor(remoteStorage, files, logError) {
74
+ constructor(remoteStorage, logError, broadcastUpSyncEvent) {
26
75
  this.remoteStorage = remoteStorage;
27
- this.files = files;
28
76
  this.logError = logError;
77
+ this.broadcastUpSyncEvent = broadcastUpSyncEvent;
29
78
  this.uploads = new Map();
30
- this.addToWorker = (ready) => {
31
- this.worker.add(ready);
32
- };
33
- this.worker = new processes_1.Worker(async (u) => {
34
- await u.process();
35
- if (u.isDone() && (u === this.uploads.get(u.obj))) {
36
- this.uploads.delete(u.obj);
37
- }
38
- }, async (queue) => {
39
- for (const u of queue) {
40
- u.stop();
41
- this.uploads.delete(u.obj);
42
- }
43
- });
79
+ this.execPools = new labelled_exec_pools_1.LabelledExecPools([
80
+ { label: 'long', maxProcs: 1 },
81
+ { label: 'fast', maxProcs: 1 }
82
+ ], logError);
44
83
  Object.seal(this);
45
84
  }
46
85
  getOrMakeUploadsFor(obj) {
47
86
  let uploads = this.uploads.get(obj);
48
87
  if (!uploads) {
49
- const status = new upsync_status_1.UpSyncTasks(obj.objFolder, this.logError);
50
- uploads = new ObjUpSync(obj, status, this.remoteStorage, this.addToWorker, this.logError);
88
+ uploads = new ObjUpSync(obj, this.remoteStorage, this.execPools, this.logError, this.broadcastUpSyncEvent);
51
89
  this.uploads.set(obj, uploads);
52
90
  }
53
91
  return uploads;
54
92
  }
55
93
  start() {
56
- this.worker.start(2);
94
+ this.execPools.start();
57
95
  }
58
96
  async stop() {
59
- await this.worker.stop();
60
- for (const upload of this.uploads.values()) {
61
- upload.stop();
62
- }
97
+ await this.execPools.stop(); // implicitly cancels all upsync tasks
63
98
  this.uploads.clear();
64
99
  }
65
- get chunkSize() {
66
- return (this.remoteStorage.maxChunkSize ?
67
- Math.min(this.remoteStorage.maxChunkSize, MAX_CHUNK_SIZE) :
68
- MAX_CHUNK_SIZE);
69
- }
70
100
  tapFileWrite(obj, isNew, newVersion, baseVersion) {
71
101
  const objUploads = this.getOrMakeUploadsFor(obj);
72
102
  return objUploads.tapFileWrite(isNew, newVersion, baseVersion);
73
103
  }
74
104
  async removeCurrentVersionOf(obj) {
75
105
  const objUploads = this.getOrMakeUploadsFor(obj);
76
- objUploads.removeCurrentVersion();
106
+ if (objUploads.neededExecutor()) {
107
+ this.execPools.add(objUploads);
108
+ }
77
109
  }
78
110
  }
79
111
  exports.UpSyncer = UpSyncer;
80
112
  Object.freeze(UpSyncer.prototype);
81
113
  Object.freeze(UpSyncer);
82
114
  class ObjUpSync {
83
- constructor(obj, status, remoteStorage, addToWorker, logError) {
115
+ constructor(obj, remoteStorage, execPools, logError, broadcastUpSyncEvent) {
84
116
  this.obj = obj;
85
- this.status = status;
86
117
  this.remoteStorage = remoteStorage;
87
- this.addToWorker = addToWorker;
118
+ this.execPools = execPools;
88
119
  this.logError = logError;
89
- this.objWriteTaps = new Map();
90
- Object.freeze(this);
120
+ this.broadcastUpSyncEvent = broadcastUpSyncEvent;
121
+ this.taskInProcess = undefined;
122
+ this.isCancelled = false;
123
+ this.runningProc = undefined;
124
+ Object.seal(this);
91
125
  }
92
126
  tapFileWrite(isObjNew, newVersion, baseVersion) {
93
- const tap = new ObjWriteTap(this.obj, newVersion, baseVersion, isObjNew);
94
- const uploadInfo = upsync_status_1.makeUploadInfo(tap.version, tap.baseVersion);
95
- this.objWriteTaps.set(uploadInfo, tap);
96
- return tap.tapOperator();
127
+ // XXX for now upload is started when write is complete, but tapped code
128
+ // layout can adopt upload as before completion.
129
+ const uploadInfo = {
130
+ type: 'upload',
131
+ version: newVersion,
132
+ baseVersion,
133
+ needUpload: {
134
+ segs: []
135
+ }
136
+ };
137
+ if (isObjNew) {
138
+ uploadInfo.createObj = true;
139
+ }
140
+ return operators_1.tap(writeEv => {
141
+ addEventToInfo(uploadInfo.needUpload, writeEv);
142
+ }, async (err) => {
143
+ // XXX cancel in-tap upload, when it will be added.
144
+ // Something should be done in case there is a transaction that
145
+ // needs cancelling.
146
+ await this.cancelTransactionIfOpen(uploadInfo);
147
+ await this.logError(err);
148
+ }, () => {
149
+ uploadInfo.needUpload.allByteOnDisk = true;
150
+ this.enqueueTask(uploadInfo);
151
+ });
152
+ }
153
+ enqueueTask(task) {
154
+ this.obj.sync().queueTask(task);
155
+ if (this.neededExecutor()) {
156
+ this.execPools.add(this);
157
+ }
158
+ else {
159
+ this.obj.scheduleSelfGC();
160
+ }
97
161
  }
98
- stop() {
99
- // XXX
100
- // - is something needed here?
162
+ async recordTaskCompletion(task) {
163
+ this.taskInProcess = undefined;
164
+ if (task.type === 'upload') {
165
+ await this.obj.markVersionSynced(task.version);
166
+ }
167
+ await this.obj.sync().recordTaskCompletion(task);
168
+ this.broadcastUpSyncEvent(this.obj.objId, task);
101
169
  }
102
- removeCurrentVersion() {
103
- this.status.queueTask({
104
- type: 'removal',
105
- currentVersion: true
106
- });
107
- this.addToWorker(this);
170
+ neededExecutor() {
171
+ const task = this.obj.sync().glanceOnNextTask();
172
+ if (!task) {
173
+ return;
174
+ }
175
+ if (task.type !== 'upload') {
176
+ return 'fast';
177
+ }
178
+ if (!task.needUpload) {
179
+ return;
180
+ }
181
+ return executorLabelFor(task.needUpload);
108
182
  }
109
183
  removeArchivedVersion(version) {
110
- this.status.queueTask({
184
+ this.enqueueTask({
111
185
  type: 'removal',
112
186
  archivedVersions: version
113
187
  });
114
- this.addToWorker(this);
115
188
  }
116
- isDone() {
117
- return this.status.isDone();
189
+ async cancel() {
190
+ var _a;
191
+ this.isCancelled = true;
192
+ await ((_a = this.runningProc) === null || _a === void 0 ? void 0 : _a.catch(noop));
118
193
  }
119
194
  async process() {
120
- if (this.isDone()) {
195
+ if (this.obj.sync().isSyncDone() || this.isCancelled) {
196
+ return;
197
+ }
198
+ let task = undefined;
199
+ try {
200
+ if (!this.taskInProcess) {
201
+ this.taskInProcess = (await this.obj.sync().getTaskForProcessing());
202
+ if (this.isCancelled) {
203
+ return;
204
+ }
205
+ }
206
+ task = this.taskInProcess;
207
+ }
208
+ catch (err) {
209
+ await this.logError(err, `ObjUpSync.process fails to get task`);
121
210
  return;
122
211
  }
123
212
  try {
124
- const task = (await this.status.nextTask());
125
213
  if (task.type === 'upload') {
126
- await this.processUpload(task);
214
+ this.runningProc = this.processUpload(task);
127
215
  }
128
216
  else if (task.type === 'removal') {
129
- await this.processRemoval(task);
217
+ this.runningProc = this.processRemoval(task);
130
218
  }
131
219
  else if (task.type === 'archiving') {
132
- await this.processArchival(task);
220
+ this.runningProc = this.processArchival(task);
133
221
  }
134
222
  else {
135
223
  throw new Error(`This shouldn't be reached`);
136
224
  }
225
+ try {
226
+ await this.runningProc;
227
+ }
228
+ finally {
229
+ this.runningProc = undefined;
230
+ }
137
231
  }
138
232
  catch (err) {
139
- await this.logError(err, `Error occured in uploader processing`);
140
- }
141
- if (!this.isDone()) {
142
- this.addToWorker(this);
233
+ await this.logError(err, `From ObjUpSync.process task ${task.type}`);
143
234
  }
144
235
  }
145
236
  async processArchival(task) {
146
237
  // XXX tell server to archive current version
147
238
  await this.logError(`Archival of current version is not implemented, yet.`);
148
- await this.status.recordTaskCompletion(task);
239
+ await this.recordTaskCompletion(task);
149
240
  }
150
241
  async processRemoval(task) {
151
242
  if (task.currentVersion) {
@@ -160,33 +251,22 @@ class ObjUpSync {
160
251
  // XXX tell server to remove given archived versions
161
252
  await this.logError(`Removal of archived version is not implemented, yet.`);
162
253
  }
163
- await this.status.recordTaskCompletion(task);
254
+ await this.recordTaskCompletion(task);
255
+ this.obj.scheduleSelfGC();
164
256
  }
165
257
  async processUpload(task) {
166
- const tap = this.objWriteTaps.get(task);
167
- if (tap && !task.done) {
168
- await this.uploadReadyBytes(task, tap);
169
- }
170
- if (tap && !task.done) {
171
- await this.status.recordInterimStateOfCurrentTask(task);
258
+ if (task.needUpload) {
259
+ if (task.needUpload.allByteOnDisk) {
260
+ if (task.transactionId) {
261
+ await this.continueUploadOfCompletedVersion(task);
262
+ }
263
+ else {
264
+ await this.startUploadOfCompletedVersion(task);
265
+ }
266
+ }
172
267
  }
173
268
  else {
174
- this.objWriteTaps.delete(task);
175
- await this.status.recordTaskCompletion(task);
176
- }
177
- }
178
- async uploadReadyBytes(uploadInfo, tap) {
179
- if (tap.cancelledOrErred()) {
180
- await this.cancelTransactionIfOpen(uploadInfo);
181
- return;
182
- }
183
- if (uploadInfo.transactionId) {
184
- await this.doUploadInTransaction(uploadInfo, tap);
185
- }
186
- else if (tap.isDone) {
187
- // XXX current code does upload after file is written, future code
188
- // can start upload sooner, and do diff-ed uploads
189
- await this.doFirstUpload(uploadInfo, tap);
269
+ await this.recordTaskCompletion(task);
190
270
  }
191
271
  }
192
272
  async cancelTransactionIfOpen(uploadInfo) {
@@ -201,62 +281,54 @@ class ObjUpSync {
201
281
  }
202
282
  });
203
283
  }
204
- async doFirstUpload(uploadInfo, tap) {
205
- assert_1.assert(tap.isDone, `Current implementation works only on completely saved to disk objects`);
206
- assert_1.assert(!uploadInfo.awaiting);
284
+ async startUploadOfCompletedVersion(uploadInfo) {
207
285
  const src = await this.obj.getObjSrc(uploadInfo.version);
208
- // note that endlessness/finiteness of src is not used
209
286
  const header = await src.readHeader();
210
287
  const maxChunkLen = (this.remoteStorage.maxChunkSize ?
211
288
  this.remoteStorage.maxChunkSize - header.length : MAX_CHUNK_SIZE);
212
289
  assert_1.assert(maxChunkLen > 0);
213
- const segs = await src.segSrc.read(maxChunkLen);
214
290
  const srcLen = (await src.segSrc.getSize()).size;
215
- let last;
216
- let bytesToSend;
217
- if (segs) {
218
- if (segs.length === maxChunkLen) {
219
- last = (srcLen === segs.length);
220
- }
221
- else {
222
- last = false;
223
- }
224
- bytesToSend = [header, segs];
291
+ if (srcLen <= maxChunkLen) {
292
+ const segs = await src.segSrc.read(maxChunkLen);
293
+ await this.uploadWholeVersion(!!uploadInfo.createObj, uploadInfo.version, header, segs);
294
+ uploadInfo.needUpload = undefined;
295
+ await this.recordTaskCompletion(uploadInfo);
225
296
  }
226
297
  else {
227
- last = true;
228
- bytesToSend = header;
298
+ const segs = await src.segSrc.read(maxChunkLen);
299
+ uploadInfo.transactionId = await this.startUploadTransaction(!!uploadInfo.createObj, uploadInfo.version, header, segs);
300
+ uploadInfo.needUpload.segs = [
301
+ { ofs: segs.length, len: srcLen - segs.length }
302
+ ];
303
+ await this.obj.sync().recordInterimStateOfCurrentTask(uploadInfo);
304
+ this.execPools.add(this);
229
305
  }
230
- if (last) {
231
- const opts = {
232
- header: header.length, ver: uploadInfo.version, last
233
- };
234
- await this.remoteStorage.saveNewObjVersion(this.obj.objId, bytesToSend, opts, undefined);
235
- uploadInfo.done = true;
306
+ }
307
+ async uploadWholeVersion(create, ver, header, segs) {
308
+ const opts = {
309
+ header: header.length, ver, last: true
310
+ };
311
+ if (create) {
312
+ opts.create = true;
236
313
  }
237
- else {
238
- const opts = {
239
- header: header.length, ver: uploadInfo.version
240
- };
241
- const txnId = await this.remoteStorage.saveNewObjVersion(this.obj.objId, bytesToSend, opts, undefined);
242
- if (!txnId) {
243
- throw new Error(`Server didn't start obj saving transaction`);
244
- }
245
- uploadInfo.transactionId = txnId;
246
- uploadInfo.awaiting = {
247
- allByteOnDisk: true,
248
- segs: [{ ofs: segs.length, len: srcLen - segs.length }]
249
- };
250
- this.addToWorker(this);
314
+ const bytes = (segs ? [header, segs] : [header]);
315
+ await this.remoteStorage.saveNewObjVersion(this.obj.objId, bytes, opts, undefined);
316
+ }
317
+ async startUploadTransaction(create, ver, header, segs) {
318
+ const opts = {
319
+ header: header.length, ver
320
+ };
321
+ if (create) {
322
+ opts.create = true;
251
323
  }
324
+ const txnId = await this.remoteStorage.saveNewObjVersion(this.obj.objId, [header, segs], opts, undefined);
325
+ if (!txnId) {
326
+ throw new Error(`Server didn't start obj saving transaction`);
327
+ }
328
+ return txnId;
252
329
  }
253
- async doUploadInTransaction(uploadInfo, tap) {
254
- assert_1.assert(tap.isDone, `Current implementation works only on completely saved to disk objects`);
255
- assert_1.assert(!!uploadInfo.transactionId
256
- && !!uploadInfo.awaiting
257
- && (uploadInfo.awaiting.segs.length > 0)
258
- && (uploadInfo.awaiting.segs[0].len > 0));
259
- const section = uploadInfo.awaiting.segs[0];
330
+ async continueUploadOfCompletedVersion(uploadInfo) {
331
+ const section = uploadInfo.needUpload.segs[0];
260
332
  const lenToRead = Math.min(section.len, (this.remoteStorage.maxChunkSize ?
261
333
  this.remoteStorage.maxChunkSize : MAX_CHUNK_SIZE));
262
334
  const src = await this.obj.getObjSrc(uploadInfo.version);
@@ -265,17 +337,17 @@ class ObjUpSync {
265
337
  if (!segs || (segs.length < lenToRead)) {
266
338
  throw new Error(`Unexpected end of obj source`);
267
339
  }
268
- const last = ((uploadInfo.awaiting.segs.length === 0) &&
340
+ const last = ((uploadInfo.needUpload.segs.length === 1) &&
269
341
  (segs.length === section.len));
270
342
  if (last) {
271
343
  const opts = {
272
344
  ofs: section.ofs,
273
345
  trans: uploadInfo.transactionId,
274
- last: true
346
+ last
275
347
  };
276
348
  await this.remoteStorage.saveNewObjVersion(this.obj.objId, segs, undefined, opts);
277
- uploadInfo.done = true;
278
- uploadInfo.awaiting = undefined;
349
+ uploadInfo.needUpload = undefined;
350
+ await this.recordTaskCompletion(uploadInfo);
279
351
  }
280
352
  else {
281
353
  const opts = {
@@ -284,41 +356,17 @@ class ObjUpSync {
284
356
  };
285
357
  await this.remoteStorage.saveNewObjVersion(this.obj.objId, segs, undefined, opts);
286
358
  if (segs.length === section.len) {
287
- uploadInfo.awaiting.segs.splice(0, 1);
359
+ uploadInfo.needUpload.segs.splice(0, 1);
288
360
  }
289
361
  else {
290
362
  section.ofs += segs.length;
291
363
  section.len -= segs.length;
292
364
  }
293
- this.addToWorker(this);
365
+ this.execPools.add(this);
294
366
  }
295
367
  }
296
368
  }
297
369
  Object.freeze(ObjUpSync.prototype);
298
370
  Object.freeze(ObjUpSync);
299
- class ObjWriteTap {
300
- constructor(obj, version, baseVersion, isObjNew) {
301
- this.obj = obj;
302
- this.version = version;
303
- this.baseVersion = baseVersion;
304
- this.isObjNew = isObjNew;
305
- this.isDone = false;
306
- this.isCancelled = false;
307
- this.err = undefined;
308
- Object.seal(this);
309
- }
310
- tapOperator() {
311
- return operators_1.tap(w => { }, err => {
312
- this.err = err;
313
- this.isDone = true;
314
- }, () => {
315
- this.isDone = true;
316
- });
317
- }
318
- cancelledOrErred() {
319
- return (this.isCancelled || (this.isDone && this.err));
320
- }
321
- }
322
- Object.freeze(ObjWriteTap.prototype);
323
- Object.freeze(ObjWriteTap);
371
+ function noop() { }
324
372
  Object.freeze(exports);