core-3nweb-client-lib 0.25.3 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/build/api-defs/files.d.ts +23 -20
- package/build/core/asmail/config/common.js +2 -2
- package/build/core/asmail/delivery/index.js +4 -3
- package/build/core/asmail/delivery/msg.js +5 -4
- package/build/core/asmail/delivery/per-recipient-wip.js +2 -2
- package/build/core/asmail/inbox/attachments/fs.js +6 -0
- package/build/core/asmail/inbox/cached-msgs.js +2 -2
- package/build/core/asmail/inbox/inbox-events.js +2 -1
- package/build/core/asmail/inbox/index.js +2 -2
- package/build/core/asmail/inbox/msg-downloader.js +2 -2
- package/build/core/asmail/inbox/msg-indexing.js +3 -3
- package/build/core/asmail/inbox/msg-on-disk.js +2 -2
- package/build/core/asmail/keyring/keyring-storage.js +2 -2
- package/build/core/asmail/sending-params/own-params.js +2 -2
- package/build/core/asmail/sending-params/params-from-others.js +2 -2
- package/build/core/id-manager.js +2 -2
- package/build/core/sign-in.d.ts +5 -4
- package/build/core/sign-in.js +9 -11
- package/build/core/sign-up.d.ts +1 -0
- package/build/core/sign-up.js +7 -3
- package/build/core/storage/common/json-saving.d.ts +21 -0
- package/build/core/storage/common/json-saving.js +82 -0
- package/build/core/storage/common/obj-info-file.d.ts +43 -0
- package/build/core/storage/common/obj-info-file.js +119 -3
- package/build/core/storage/index.js +1 -1
- package/build/core/storage/local/obj-files-gc.js +8 -6
- package/build/core/storage/local/obj-files.d.ts +3 -3
- package/build/core/storage/local/obj-files.js +9 -9
- package/build/core/storage/local/obj-status.d.ts +9 -25
- package/build/core/storage/local/obj-status.js +28 -110
- package/build/core/storage/local/storage.d.ts +8 -1
- package/build/core/storage/local/storage.js +10 -2
- package/build/core/storage/synced/downloader.js +6 -5
- package/build/core/storage/synced/obj-files-gc.d.ts +1 -0
- package/build/core/storage/synced/obj-files-gc.js +44 -5
- package/build/core/storage/synced/obj-files.d.ts +13 -20
- package/build/core/storage/synced/obj-files.js +70 -48
- package/build/core/storage/synced/obj-status.d.ts +74 -15
- package/build/core/storage/synced/obj-status.js +291 -107
- package/build/core/storage/synced/remote-events.js +32 -26
- package/build/core/storage/synced/storage.d.ts +11 -1
- package/build/core/storage/synced/storage.js +28 -3
- package/build/core/storage/synced/upsyncer.d.ts +8 -7
- package/build/core/storage/synced/upsyncer.js +211 -163
- package/build/ipc-via-protobuf/asmail-cap.js +17 -34
- package/build/ipc-via-protobuf/connector-clients-side.js +2 -2
- package/build/ipc-via-protobuf/file.js +26 -18
- package/build/ipc-via-protobuf/fs.js +33 -35
- package/build/ipc-via-protobuf/mailerid.js +3 -2
- package/build/ipc-via-protobuf/protobuf-msg.d.ts +2 -0
- package/build/ipc-via-protobuf/protobuf-msg.js +11 -1
- package/build/ipc-via-protobuf/startup-cap.js +5 -5
- package/build/lib-client/3nstorage/exceptions.d.ts +9 -8
- package/build/lib-client/3nstorage/exceptions.js +18 -9
- package/build/lib-client/3nstorage/service.js +10 -6
- package/build/lib-client/3nstorage/xsp-fs/common.d.ts +18 -4
- package/build/lib-client/3nstorage/xsp-fs/common.js +6 -1
- package/build/lib-client/3nstorage/xsp-fs/file-node.js +3 -3
- package/build/lib-client/3nstorage/xsp-fs/file.js +4 -1
- package/build/lib-client/3nstorage/xsp-fs/folder-node.js +27 -13
- package/build/lib-client/3nstorage/xsp-fs/fs.d.ts +11 -6
- package/build/lib-client/3nstorage/xsp-fs/fs.js +189 -58
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.d.ts +4 -0
- package/build/lib-client/3nstorage/xsp-fs/node-in-fs.js +51 -24
- package/build/lib-client/3nstorage/xsp-fs/node-persistence.js +2 -2
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v1.js +2 -2
- package/build/lib-client/3nstorage/xsp-fs/xsp-payload-v2.js +3 -3
- package/build/lib-client/cryptor/cryptor-in-worker.js +4 -4
- package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
- package/build/lib-client/cryptor/cryptor.wasm +0 -0
- package/build/lib-client/cryptor/in-proc-wasm.js +2 -2
- package/build/lib-client/files.js +2 -0
- package/build/lib-client/fs-collection.js +3 -2
- package/build/lib-client/logging/log-to-file.js +6 -14
- package/build/lib-client/objs-on-disk/file-writing-proc.js +2 -2
- package/build/lib-client/objs-on-disk/obj-folders.d.ts +12 -1
- package/build/lib-client/objs-on-disk/obj-folders.js +26 -19
- package/build/lib-client/request-utils.js +2 -2
- package/build/lib-client/server-events.js +4 -3
- package/build/lib-client/ws-utils.js +2 -2
- package/build/lib-common/async-fs-node.d.ts +6 -0
- package/build/lib-common/async-fs-node.js +28 -4
- package/build/lib-common/byte-streaming/wrapping.js +17 -17
- package/build/lib-common/exceptions/file.js +6 -1
- package/build/lib-common/ipc/generic-ipc.js +2 -2
- package/build/lib-common/json-utils.js +2 -1
- package/build/lib-common/objs-on-disk/obj-file.js +4 -3
- package/build/lib-common/objs-on-disk/utils.js +2 -2
- package/build/lib-common/processes/deferred.d.ts +6 -0
- package/build/lib-common/processes/deferred.js +30 -0
- package/build/lib-common/processes/labelled-exec-pools.d.ts +33 -0
- package/build/lib-common/processes/labelled-exec-pools.js +141 -0
- package/build/lib-common/processes/pressure.d.ts +7 -0
- package/build/lib-common/processes/pressure.js +56 -0
- package/build/lib-common/processes/sleep.d.ts +1 -0
- package/build/lib-common/processes/sleep.js +26 -0
- package/build/lib-common/{processes.d.ts → processes/synced.d.ts} +0 -40
- package/build/lib-common/{processes.js → processes/synced.js} +187 -204
- package/build/lib-common/processes/timeout.d.ts +1 -0
- package/build/lib-common/processes/timeout.js +51 -0
- package/build/lib-common/service-api/3nstorage/owner.d.ts +5 -4
- package/build/lib-common/service-api/3nstorage/owner.js +3 -2
- package/build/lib-common/utils-for-observables.d.ts +15 -1
- package/build/lib-common/utils-for-observables.js +68 -17
- package/build/protos/asmail.proto.js +404 -78
- package/build/protos/file.proto.js +370 -44
- package/build/protos/fs.proto.js +404 -78
- package/package.json +4 -4
- package/protos/file.proto +10 -2
- package/protos/fs.proto +2 -2
- package/build/core/storage/synced/upsync-status.d.ts +0 -41
- package/build/core/storage/synced/upsync-status.js +0 -158
|
@@ -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.
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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.
|
|
94
|
+
this.execPools.start();
|
|
57
95
|
}
|
|
58
96
|
async stop() {
|
|
59
|
-
await this.
|
|
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.
|
|
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,
|
|
115
|
+
constructor(obj, remoteStorage, execPools, logError, broadcastUpSyncEvent) {
|
|
84
116
|
this.obj = obj;
|
|
85
|
-
this.status = status;
|
|
86
117
|
this.remoteStorage = remoteStorage;
|
|
87
|
-
this.
|
|
118
|
+
this.execPools = execPools;
|
|
88
119
|
this.logError = logError;
|
|
89
|
-
this.
|
|
90
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
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.
|
|
184
|
+
this.enqueueTask({
|
|
111
185
|
type: 'removal',
|
|
112
186
|
archivedVersions: version
|
|
113
187
|
});
|
|
114
|
-
this.addToWorker(this);
|
|
115
188
|
}
|
|
116
|
-
|
|
117
|
-
|
|
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.
|
|
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
|
-
|
|
214
|
+
this.runningProc = this.processUpload(task);
|
|
127
215
|
}
|
|
128
216
|
else if (task.type === 'removal') {
|
|
129
|
-
|
|
217
|
+
this.runningProc = this.processRemoval(task);
|
|
130
218
|
}
|
|
131
219
|
else if (task.type === 'archiving') {
|
|
132
|
-
|
|
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, `
|
|
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.
|
|
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.
|
|
254
|
+
await this.recordTaskCompletion(task);
|
|
255
|
+
this.obj.scheduleSelfGC();
|
|
164
256
|
}
|
|
165
257
|
async processUpload(task) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
228
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
|
254
|
-
|
|
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.
|
|
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
|
|
346
|
+
last
|
|
275
347
|
};
|
|
276
348
|
await this.remoteStorage.saveNewObjVersion(this.obj.objId, segs, undefined, opts);
|
|
277
|
-
uploadInfo.
|
|
278
|
-
uploadInfo
|
|
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.
|
|
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.
|
|
365
|
+
this.execPools.add(this);
|
|
294
366
|
}
|
|
295
367
|
}
|
|
296
368
|
}
|
|
297
369
|
Object.freeze(ObjUpSync.prototype);
|
|
298
370
|
Object.freeze(ObjUpSync);
|
|
299
|
-
|
|
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);
|