core-3nweb-client-lib 0.44.7 → 0.44.9
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/build/api-defs/files.d.ts +1 -0
- package/build/api-defs/web3n.d.ts +2 -1
- package/build/core/asmail/inbox/inbox-events.d.ts +0 -1
- package/build/core/asmail/inbox/inbox-events.js +3 -5
- package/build/core/asmail/inbox/index.js +1 -1
- package/build/core/asmail/inbox/msg-downloader.d.ts +1 -2
- package/build/core/asmail/inbox/msg-downloader.js +3 -4
- package/build/core/storage/common/obj-info-file.d.ts +0 -1
- package/build/core/storage/common/obj-info-file.js +0 -10
- package/build/core/storage/synced/obj-status.d.ts +1 -0
- package/build/core/storage/synced/obj-status.js +8 -12
- package/build/core/storage/synced/remote-events.d.ts +0 -1
- package/build/core/storage/synced/remote-events.js +5 -7
- package/build/core/storage/synced/storage.js +2 -2
- package/build/core/storage/synced/upsyncer.d.ts +1 -2
- package/build/core/storage/synced/upsyncer.js +49 -25
- package/build/lib-client/3nstorage/storage-owner.js +1 -1
- package/build/lib-client/asmail/recipient.js +8 -4
- package/build/lib-client/cryptor/worker-js.js +4 -2
- package/build/lib-client/local-files/dev-file-sink.js +30 -28
- package/build/lib-client/local-files/dev-file-src.js +7 -6
- package/build/lib-client/local-files/device-fs.js +23 -23
- package/build/lib-client/objs-on-disk/obj-folders.js +6 -3
- package/build/lib-client/request-utils.d.ts +2 -1
- package/build/lib-client/request-utils.js +8 -19
- package/build/lib-client/user-with-mid-session.d.ts +2 -0
- package/build/lib-client/user-with-mid-session.js +33 -22
- package/build/lib-client/xsp-fs/attrs.js +4 -2
- package/build/lib-client/xsp-fs/exceptions.js +5 -4
- package/build/lib-client/xsp-fs/folder-node-serialization.js +4 -2
- package/build/lib-client/xsp-fs/node-in-fs.js +2 -5
- package/build/lib-common/async-fs-node.d.ts +30 -46
- package/build/lib-common/async-fs-node.js +71 -309
- package/build/lib-common/awaitable-state.js +3 -1
- package/build/lib-common/exceptions/file.d.ts +1 -1
- package/build/lib-common/exceptions/file.js +11 -6
- package/build/lib-common/exceptions/runtime.d.ts +7 -1
- package/build/lib-common/exceptions/runtime.js +16 -2
- package/build/lib-common/objs-on-disk/obj-version-file.d.ts +1 -1
- package/build/lib-common/objs-on-disk/obj-version-file.js +35 -33
- package/build/lib-index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright (C) 2016 - 2018, 2020, 2025 3NSoft Inc.
|
|
2
|
+
Copyright (C) 2016 - 2018, 2020, 2025 - 2026 3NSoft Inc.
|
|
3
3
|
|
|
4
4
|
This program is free software: you can redistribute it and/or modify it under
|
|
5
5
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -31,6 +31,7 @@ declare namespace web3n {
|
|
|
31
31
|
type?: string;
|
|
32
32
|
cause?: any;
|
|
33
33
|
message?: string;
|
|
34
|
+
stack?: string;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
interface ConnectException extends RuntimeException {
|
|
@@ -31,7 +31,6 @@ export declare class InboxEvents {
|
|
|
31
31
|
readonly connectionEvent$: Observable<InboxConnectionStatus>;
|
|
32
32
|
private readonly wsProc;
|
|
33
33
|
private disconnectedAt;
|
|
34
|
-
private connection;
|
|
35
34
|
constructor(msgReceiver: MailRecipient, getMsg: (msgId: string) => Promise<IncomingMessage>, listNewMsgs: (fromTS: number) => Promise<MsgInfo[]>, rmMsg: (msgId: string) => Promise<void>, logError: LogError);
|
|
36
35
|
private makeProc;
|
|
37
36
|
whenConnected(): Promise<void>;
|
|
@@ -22,7 +22,6 @@ const retrieval_1 = require("../../../lib-common/service-api/asmail/retrieval");
|
|
|
22
22
|
const operators_1 = require("rxjs/operators");
|
|
23
23
|
const utils_for_observables_1 = require("../../../lib-common/utils-for-observables");
|
|
24
24
|
const ws_ipc_1 = require("../../../lib-common/ipc/ws-ipc");
|
|
25
|
-
const awaitable_state_1 = require("../../../lib-common/awaitable-state");
|
|
26
25
|
function toInboxConnectionStatus(status, params) {
|
|
27
26
|
return (0, ws_ipc_1.addToStatus)(status, {
|
|
28
27
|
service: 'inbox',
|
|
@@ -53,7 +52,6 @@ class InboxEvents {
|
|
|
53
52
|
this.connectionEvents = new rxjs_1.Subject();
|
|
54
53
|
this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
|
|
55
54
|
this.disconnectedAt = undefined;
|
|
56
|
-
this.connection = new awaitable_state_1.AwaitableState();
|
|
57
55
|
this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
|
|
58
56
|
this.wsProc.startListening();
|
|
59
57
|
Object.seal(this);
|
|
@@ -65,10 +63,10 @@ class InboxEvents {
|
|
|
65
63
|
next: ev => {
|
|
66
64
|
this.connectionEvents.next(toInboxConnectionStatus(ev));
|
|
67
65
|
if (ev.type === 'heartbeat') {
|
|
68
|
-
this.
|
|
66
|
+
this.msgReceiver.connectedState.setState();
|
|
69
67
|
}
|
|
70
68
|
else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
|
|
71
|
-
this.
|
|
69
|
+
this.msgReceiver.connectedState.clearState();
|
|
72
70
|
}
|
|
73
71
|
}
|
|
74
72
|
});
|
|
@@ -87,7 +85,7 @@ class InboxEvents {
|
|
|
87
85
|
return proc$;
|
|
88
86
|
}
|
|
89
87
|
async whenConnected() {
|
|
90
|
-
return this.
|
|
88
|
+
return this.msgReceiver.connectedState.whenStateIsSet();
|
|
91
89
|
}
|
|
92
90
|
async getMessage(msgId) {
|
|
93
91
|
try {
|
|
@@ -58,7 +58,7 @@ class InboxOnServer {
|
|
|
58
58
|
try {
|
|
59
59
|
(0, file_1.ensureCorrectFS)(syncedFS, 'synced', true);
|
|
60
60
|
const msgReceiver = new recipient_1.MailRecipient(r.address, r.getSigner, () => r.asmailResolver(r.address), r.makeNet());
|
|
61
|
-
const downloader = new msg_downloader_1.MsgDownloader(msgReceiver
|
|
61
|
+
const downloader = new msg_downloader_1.MsgDownloader(msgReceiver);
|
|
62
62
|
const cache = await cached_msgs_1.CachedMessages.makeFor(cachePath, downloader, r.logError);
|
|
63
63
|
const indexSyncedFS = await (0, fs_sync_utils_1.getOrMakeAndUploadFolderIn)(syncedFS, MSG_INDEX_FOLDER);
|
|
64
64
|
const index = await msg_indexing_1.MsgIndex.make(indexSyncedFS);
|
|
@@ -3,9 +3,8 @@ import { ObjDownloader } from "../../../lib-client/objs-on-disk/obj-on-disk";
|
|
|
3
3
|
import { MsgMeta } from "../../../lib-common/service-api/asmail/retrieval";
|
|
4
4
|
export declare class MsgDownloader {
|
|
5
5
|
private readonly msgReceiver;
|
|
6
|
-
private readonly whenConnected;
|
|
7
6
|
private readonly runner;
|
|
8
|
-
constructor(msgReceiver: MailRecipient
|
|
7
|
+
constructor(msgReceiver: MailRecipient);
|
|
9
8
|
getMsgMeta(msgId: string): Promise<MsgMeta>;
|
|
10
9
|
getObjDownloader(msgId: string): ObjDownloader;
|
|
11
10
|
private getLayoutWithHeaderAndFirstSegs;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2016 - 2019, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2016 - 2019, 2025 - 2026 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
|
|
@@ -21,9 +21,8 @@ const obj_on_disk_1 = require("../../../lib-client/objs-on-disk/obj-on-disk");
|
|
|
21
21
|
const MAX_GETTING_CHUNK = 512 * 1024;
|
|
22
22
|
const DOWNLOAD_START_CHUNK = 128 * 1024;
|
|
23
23
|
class MsgDownloader {
|
|
24
|
-
constructor(msgReceiver
|
|
24
|
+
constructor(msgReceiver) {
|
|
25
25
|
this.msgReceiver = msgReceiver;
|
|
26
|
-
this.whenConnected = whenConnected;
|
|
27
26
|
this.runner = new obj_on_disk_1.DownloadsRunner();
|
|
28
27
|
Object.freeze(this);
|
|
29
28
|
}
|
|
@@ -36,7 +35,7 @@ class MsgDownloader {
|
|
|
36
35
|
getSegs: (objId, v, start, end) => this.getSegs(msgId, objId, start, end),
|
|
37
36
|
splitSegsDownloads: (start, end) => (0, obj_on_disk_1.splitSegsDownloads)(start, end, MAX_GETTING_CHUNK),
|
|
38
37
|
schedule: this.runner.schedule.bind(this.runner),
|
|
39
|
-
whenConnected: this.
|
|
38
|
+
whenConnected: () => this.msgReceiver.connectedState.whenStateIsSet()
|
|
40
39
|
};
|
|
41
40
|
}
|
|
42
41
|
async getLayoutWithHeaderAndFirstSegs(msgId, objId) {
|
|
@@ -41,7 +41,6 @@ export declare function rmNonArchVersionsIn(versions: VersionsInfo, ver: number)
|
|
|
41
41
|
export declare function rmArchVersionFrom(versions: VersionsInfo, ver: number): boolean;
|
|
42
42
|
export declare function setCurrentVersionIn(versions: VersionsInfo, version: number, baseVer: number | undefined): void;
|
|
43
43
|
export declare function rmCurrentVersionIn(versions: VersionsInfo): number | undefined;
|
|
44
|
-
export declare function rmVersionIn(version: number, vers: VersionsInfo): void;
|
|
45
44
|
export declare function nonGarbageVersionsIn(versions: VersionsInfo): Set<number>;
|
|
46
45
|
export interface NonGarbageVersions {
|
|
47
46
|
gcMaxVer?: number;
|
|
@@ -23,7 +23,6 @@ exports.rmNonArchVersionsIn = rmNonArchVersionsIn;
|
|
|
23
23
|
exports.rmArchVersionFrom = rmArchVersionFrom;
|
|
24
24
|
exports.setCurrentVersionIn = setCurrentVersionIn;
|
|
25
25
|
exports.rmCurrentVersionIn = rmCurrentVersionIn;
|
|
26
|
-
exports.rmVersionIn = rmVersionIn;
|
|
27
26
|
exports.nonGarbageVersionsIn = nonGarbageVersionsIn;
|
|
28
27
|
exports.addWithBasesTo = addWithBasesTo;
|
|
29
28
|
exports.addArchived = addArchived;
|
|
@@ -131,15 +130,6 @@ function rmCurrentVersionIn(versions) {
|
|
|
131
130
|
}
|
|
132
131
|
return current;
|
|
133
132
|
}
|
|
134
|
-
function rmVersionIn(version, vers) {
|
|
135
|
-
if (vers.current === version) {
|
|
136
|
-
vers.current = undefined;
|
|
137
|
-
rmNonArchVersionsIn(vers, version);
|
|
138
|
-
}
|
|
139
|
-
if (isVersionIn(version, vers)) {
|
|
140
|
-
rmArchVersionFrom(vers, version);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
133
|
function nonGarbageVersionsIn(versions) {
|
|
144
134
|
const nonGarbage = new Set();
|
|
145
135
|
addWithBasesTo(nonGarbage, versions.current, versions);
|
|
@@ -111,6 +111,7 @@ export declare class ObjStatus implements SyncedObjStatus, UploadStatusRecorder
|
|
|
111
111
|
getNonGarbageVersions(): NonGarbage;
|
|
112
112
|
removeCurrentVersion(): Promise<void>;
|
|
113
113
|
private triggerSaveProc;
|
|
114
|
+
get upload(): UploadInfo | undefined;
|
|
114
115
|
recordUploadStart(info: NewVersionUpload): Promise<void>;
|
|
115
116
|
recordUploadInterimState(info: NewVersionUpload): Promise<void>;
|
|
116
117
|
recordUploadCancellation(info: NewVersionUpload): Promise<void>;
|
|
@@ -197,10 +197,7 @@ class ObjStatus {
|
|
|
197
197
|
return;
|
|
198
198
|
}
|
|
199
199
|
else {
|
|
200
|
-
throw (0, runtime_1.makeRuntimeException)('file', {
|
|
201
|
-
path: (0, path_1.join)(this.objFolder, exports.STATUS_FILE_NAME),
|
|
202
|
-
fsEtityType: 'file', message: `Upload is in progress`
|
|
203
|
-
}, { concurrentUpdate: true });
|
|
200
|
+
throw (0, runtime_1.makeRuntimeException)('file', { path: (0, path_1.join)(this.objFolder, exports.STATUS_FILE_NAME), fsEtityType: 'file', message: `Upload is in progress` }, { concurrentUpdate: true }, true);
|
|
204
201
|
}
|
|
205
202
|
}
|
|
206
203
|
if (!remote.isArchived && remote.current) {
|
|
@@ -237,6 +234,9 @@ class ObjStatus {
|
|
|
237
234
|
}
|
|
238
235
|
}
|
|
239
236
|
}
|
|
237
|
+
get upload() {
|
|
238
|
+
return this.status.upload;
|
|
239
|
+
}
|
|
240
240
|
recordUploadStart(info) {
|
|
241
241
|
var _a;
|
|
242
242
|
if (this.status.upload) {
|
|
@@ -474,15 +474,11 @@ class ObjStatus {
|
|
|
474
474
|
const local = this.status.local;
|
|
475
475
|
(0, assert_1.assert)(local.diffToBase[version] === localBase);
|
|
476
476
|
const lowerBase = local.diffToBase[localBase];
|
|
477
|
-
if (
|
|
478
|
-
|
|
479
|
-
local
|
|
480
|
-
}
|
|
481
|
-
else {
|
|
482
|
-
delete local.diffToBase[version];
|
|
477
|
+
if (lowerBase) {
|
|
478
|
+
// flip version's base to be new value before removing
|
|
479
|
+
(0, obj_info_file_1.addBaseToDiffLinkInVersInfo)(local, version, lowerBase);
|
|
483
480
|
}
|
|
484
|
-
|
|
485
|
-
delete local.baseToDiff[localBase];
|
|
481
|
+
(0, obj_info_file_1.rmNonArchVersionsIn)(local, localBase);
|
|
486
482
|
return this.triggerSaveProc();
|
|
487
483
|
}
|
|
488
484
|
latestSyncedVersion() {
|
|
@@ -19,7 +19,6 @@ export declare class RemoteEvents {
|
|
|
19
19
|
private readonly connectionEvents;
|
|
20
20
|
readonly connectionEvent$: Observable<StorageConnectionStatus>;
|
|
21
21
|
private readonly wsProc;
|
|
22
|
-
private connection;
|
|
23
22
|
constructor(remoteStorage: StorageOwner, files: ObjFiles, broadcastNodeEvent: Storage['broadcastNodeEvent'], logError: LogError);
|
|
24
23
|
private makeProc;
|
|
25
24
|
startListening(): void;
|
|
@@ -21,7 +21,6 @@ const rxjs_1 = require("rxjs");
|
|
|
21
21
|
const owner_1 = require("../../../lib-common/service-api/3nstorage/owner");
|
|
22
22
|
const operators_1 = require("rxjs/operators");
|
|
23
23
|
const ws_ipc_1 = require("../../../lib-common/ipc/ws-ipc");
|
|
24
|
-
const awaitable_state_1 = require("../../../lib-common/awaitable-state");
|
|
25
24
|
function toStorageConnectionStatus(status, params) {
|
|
26
25
|
return (0, ws_ipc_1.addToStatus)(status, {
|
|
27
26
|
service: 'storage',
|
|
@@ -41,21 +40,20 @@ class RemoteEvents {
|
|
|
41
40
|
this.logError = logError;
|
|
42
41
|
this.connectionEvents = new rxjs_1.Subject();
|
|
43
42
|
this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
|
|
44
|
-
this.connection = new awaitable_state_1.AwaitableState();
|
|
45
43
|
this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
|
|
46
44
|
Object.seal(this);
|
|
47
45
|
}
|
|
48
46
|
makeProc() {
|
|
49
47
|
return (0, rxjs_1.from)(this.remoteStorage.openEventSource().then(({ client, heartbeat }) => {
|
|
50
|
-
this.
|
|
48
|
+
this.remoteStorage.connectedState.setState();
|
|
51
49
|
heartbeat.subscribe({
|
|
52
50
|
next: ev => {
|
|
53
51
|
this.connectionEvents.next(toStorageConnectionStatus(ev));
|
|
54
52
|
if (ev.type === 'heartbeat') {
|
|
55
|
-
this.
|
|
53
|
+
this.remoteStorage.connectedState.setState();
|
|
56
54
|
}
|
|
57
55
|
else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
|
|
58
|
-
this.
|
|
56
|
+
this.remoteStorage.connectedState.clearState();
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
});
|
|
@@ -76,8 +74,8 @@ class RemoteEvents {
|
|
|
76
74
|
this.connectionEvents.complete();
|
|
77
75
|
this.wsProc.close();
|
|
78
76
|
}
|
|
79
|
-
|
|
80
|
-
return this.
|
|
77
|
+
whenConnected() {
|
|
78
|
+
return this.remoteStorage.connectedState.whenStateIsSet();
|
|
81
79
|
}
|
|
82
80
|
absorbObjChange(client) {
|
|
83
81
|
return (new rxjs_1.Observable(obs => client.subscribe(owner_1.events.objChanged.EVENT_NAME, obs)))
|
|
@@ -40,7 +40,7 @@ class SyncedStore {
|
|
|
40
40
|
this.nodes = new common_1.NodesContainer();
|
|
41
41
|
this.events = new utils_for_observables_1.Broadcast();
|
|
42
42
|
this.remoteEvents = new remote_events_1.RemoteEvents(this.remoteStorage, this.files, this.broadcastNodeEvent.bind(this), this.logError);
|
|
43
|
-
this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.
|
|
43
|
+
this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.logError);
|
|
44
44
|
Object.seal(this);
|
|
45
45
|
}
|
|
46
46
|
static async makeAndStart(path, user, getSigner, getStorages, cryptor, remoteServiceUrl, net, logError) {
|
|
@@ -249,7 +249,7 @@ class SyncedStore {
|
|
|
249
249
|
return this.remoteEvents.connectionEvent$;
|
|
250
250
|
}
|
|
251
251
|
whenConnected() {
|
|
252
|
-
return this.
|
|
252
|
+
return this.remoteStorage.connectedState.whenStateIsSet();
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
exports.SyncedStore = SyncedStore;
|
|
@@ -8,13 +8,12 @@ import { UploadEventSink, UploadHeaderChange } from "../../../lib-client/xsp-fs/
|
|
|
8
8
|
export type FileWriteTapOperator = MonoTypeOperatorFunction<FileWrite[]>;
|
|
9
9
|
export declare class UpSyncer {
|
|
10
10
|
private readonly remoteStorage;
|
|
11
|
-
private readonly whenConnected;
|
|
12
11
|
private readonly logError;
|
|
13
12
|
private readonly execPools;
|
|
14
13
|
private readonly tasksByObjIds;
|
|
15
14
|
private readonly tasksByIds;
|
|
16
15
|
private readonly syncedUploadStarts;
|
|
17
|
-
constructor(remoteStorage: StorageOwner,
|
|
16
|
+
constructor(remoteStorage: StorageOwner, logError: LogError);
|
|
18
17
|
start(): void;
|
|
19
18
|
stop(): Promise<void>;
|
|
20
19
|
removeCurrentVersionOf(obj: SyncedObj): Promise<void>;
|
|
@@ -27,9 +27,8 @@ const synced_1 = require("../../../lib-common/processes/synced");
|
|
|
27
27
|
const MAX_CHUNK_SIZE = 512 * 1024;
|
|
28
28
|
const MAX_FAST_UPLOAD = 2 * 1024 * 1024;
|
|
29
29
|
class UpSyncer {
|
|
30
|
-
constructor(remoteStorage,
|
|
30
|
+
constructor(remoteStorage, logError) {
|
|
31
31
|
this.remoteStorage = remoteStorage;
|
|
32
|
-
this.whenConnected = whenConnected;
|
|
33
32
|
this.logError = logError;
|
|
34
33
|
this.tasksByObjIds = new Map();
|
|
35
34
|
this.tasksByIds = new Map();
|
|
@@ -52,7 +51,7 @@ class UpSyncer {
|
|
|
52
51
|
}
|
|
53
52
|
catch (exc) {
|
|
54
53
|
if (exc.type === 'connect') {
|
|
55
|
-
await this.
|
|
54
|
+
await this.remoteStorage.connectedState.whenStateIsSet();
|
|
56
55
|
return this.removeCurrentVersionOf(obj);
|
|
57
56
|
}
|
|
58
57
|
else {
|
|
@@ -83,7 +82,7 @@ class UpSyncer {
|
|
|
83
82
|
if (uploadHeader) {
|
|
84
83
|
await obj.saveUploadHeaderFile(uploadHeader);
|
|
85
84
|
}
|
|
86
|
-
const task = await UploadTask.for(obj, localVersion, uploadVersion, uploadHeader === null || uploadHeader === void 0 ? void 0 : uploadHeader.uploadHeader, syncedBase, createOnRemote, uploadTaskId, eventSink, this.remoteStorage,
|
|
85
|
+
const task = await UploadTask.for(obj, localVersion, uploadVersion, uploadHeader === null || uploadHeader === void 0 ? void 0 : uploadHeader.uploadHeader, syncedBase, createOnRemote, uploadTaskId, eventSink, this.remoteStorage, async () => {
|
|
87
86
|
if (this.tasksByIds.delete(task.taskId)) {
|
|
88
87
|
this.tasksByObjIds.delete(task.objId);
|
|
89
88
|
}
|
|
@@ -108,10 +107,9 @@ exports.UpSyncer = UpSyncer;
|
|
|
108
107
|
Object.freeze(UpSyncer.prototype);
|
|
109
108
|
Object.freeze(UpSyncer);
|
|
110
109
|
class UploadTask {
|
|
111
|
-
constructor(taskId, remoteStorage,
|
|
110
|
+
constructor(taskId, remoteStorage, objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink, isRestart) {
|
|
112
111
|
this.taskId = taskId;
|
|
113
112
|
this.remoteStorage = remoteStorage;
|
|
114
|
-
this.whenConnected = whenConnected;
|
|
115
113
|
this.objId = objId;
|
|
116
114
|
this.objStatus = objStatus;
|
|
117
115
|
this.src = src;
|
|
@@ -122,29 +120,51 @@ class UploadTask {
|
|
|
122
120
|
this.uploadCompletion = (0, deferred_1.defer)();
|
|
123
121
|
this.execLabel = executorLabelFor(this.info.needUpload);
|
|
124
122
|
this.totalBytesToUpload = (0, obj_status_1.countBytesIn)(this.info);
|
|
125
|
-
this.emitUploadEvent('upload-started', { totalBytesToUpload: this.totalBytesToUpload });
|
|
123
|
+
this.emitUploadEvent('upload-started', { totalBytesToUpload: this.totalBytesToUpload, isRestart });
|
|
126
124
|
Object.seal(this);
|
|
127
125
|
}
|
|
128
|
-
static async for(obj, localVersion, uploadVersion, uploadHeader, syncedBase, createObj, taskId, eventSink, remoteStorage,
|
|
126
|
+
static async for(obj, localVersion, uploadVersion, uploadHeader, syncedBase, createObj, taskId, eventSink, remoteStorage, doAtCompletion) {
|
|
129
127
|
const src = await obj.getObjSrcFromLocalAndSyncedBranch(localVersion);
|
|
130
|
-
|
|
131
|
-
if (
|
|
132
|
-
const
|
|
133
|
-
|
|
128
|
+
const objStatus = obj.statusObj();
|
|
129
|
+
if (objStatus.upload) {
|
|
130
|
+
const info = objStatus.upload;
|
|
131
|
+
if ((info.type === 'new-version')
|
|
132
|
+
&& (info.localVersion === localVersion) && (info.uploadVersion === uploadVersion)) {
|
|
133
|
+
return new UploadTask(taskId, remoteStorage, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink, true);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
let message;
|
|
137
|
+
if (info.type === 'new-version') {
|
|
138
|
+
message = `Upload type ${info.type} of local version ${info.localVersion} as new remote ${info.uploadVersion} is already scheduled, and is different from uploading local version ${localVersion} as remote ${uploadVersion}.`;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
message = `Upload type ${info.type} is already scheduled`;
|
|
142
|
+
}
|
|
143
|
+
throw (0, exceptions_1.makeFSSyncException)('sync-task', {
|
|
144
|
+
alreadyUploading: true,
|
|
145
|
+
message
|
|
146
|
+
});
|
|
147
|
+
}
|
|
134
148
|
}
|
|
135
149
|
else {
|
|
136
|
-
needUpload
|
|
150
|
+
let needUpload;
|
|
151
|
+
if (syncedBase) {
|
|
152
|
+
const { diff, newSegsPackOrder } = await obj.diffForUploadOf(localVersion);
|
|
153
|
+
needUpload = await diffVerUpload(src, uploadHeader, diff, newSegsPackOrder);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
needUpload = await wholeVerUpload(src, uploadHeader, createObj);
|
|
157
|
+
}
|
|
158
|
+
const info = {
|
|
159
|
+
type: 'new-version',
|
|
160
|
+
localVersion,
|
|
161
|
+
uploadVersion,
|
|
162
|
+
baseVersion: syncedBase,
|
|
163
|
+
needUpload
|
|
164
|
+
};
|
|
165
|
+
await objStatus.recordUploadStart(info);
|
|
166
|
+
return new UploadTask(taskId, remoteStorage, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink, false);
|
|
137
167
|
}
|
|
138
|
-
const info = {
|
|
139
|
-
type: 'new-version',
|
|
140
|
-
localVersion,
|
|
141
|
-
uploadVersion,
|
|
142
|
-
baseVersion: syncedBase,
|
|
143
|
-
needUpload
|
|
144
|
-
};
|
|
145
|
-
const objStatus = obj.statusObj();
|
|
146
|
-
await objStatus.recordUploadStart(info);
|
|
147
|
-
return new UploadTask(taskId, remoteStorage, whenConnected, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink);
|
|
148
168
|
}
|
|
149
169
|
neededExecutor() {
|
|
150
170
|
return (!this.info.needUpload ? undefined : this.execLabel);
|
|
@@ -211,13 +231,17 @@ class UploadTask {
|
|
|
211
231
|
catch (exc) {
|
|
212
232
|
if (exc.type === 'connect') {
|
|
213
233
|
this.emitUploadEvent('upload-disconnected', {});
|
|
214
|
-
await this.
|
|
234
|
+
await this.remoteStorage.connectedState.whenStateIsSet();
|
|
215
235
|
return false;
|
|
216
236
|
}
|
|
217
237
|
else {
|
|
238
|
+
if (exc.unexpectedStatus && this.info.needUpload.transactionId) {
|
|
239
|
+
await this.remoteStorage.cancelTransaction(this.objId, this.info.needUpload.transactionId)
|
|
240
|
+
.catch(noop);
|
|
241
|
+
}
|
|
218
242
|
this.info.needUpload = undefined;
|
|
219
243
|
this.uploadCompletion.reject((0, exceptions_1.makeFSSyncException)(`obj-upload`, {
|
|
220
|
-
message: `Fail to upload local version ${this.info.
|
|
244
|
+
message: `Fail to upload version ${this.info.uploadVersion} of local version ${this.info.localVersion}`,
|
|
221
245
|
localVersion: this.info.uploadVersion,
|
|
222
246
|
cause: exc
|
|
223
247
|
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2017, 2020, 2022, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2017, 2020, 2022, 2025 - 2026 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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015, 2017, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015, 2017, 2025 - 2026 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
|
|
@@ -26,12 +26,14 @@ const user_with_mid_session_1 = require("../user-with-mid-session");
|
|
|
26
26
|
const service_locator_1 = require("../service-locator");
|
|
27
27
|
const ws_ipc_1 = require("../../lib-common/ipc/ws-ipc");
|
|
28
28
|
const http_1 = require("../../lib-common/exceptions/http");
|
|
29
|
+
const runtime_1 = require("../../lib-common/exceptions/runtime");
|
|
29
30
|
function makeMsgNotFoundException(msgId) {
|
|
30
31
|
const exc = {
|
|
31
32
|
runtimeException: true,
|
|
32
33
|
type: 'inbox',
|
|
33
34
|
msgId,
|
|
34
|
-
msgNotFound: true
|
|
35
|
+
msgNotFound: true,
|
|
36
|
+
stack: (0, runtime_1.getStackHere)(1)
|
|
35
37
|
};
|
|
36
38
|
return exc;
|
|
37
39
|
}
|
|
@@ -41,7 +43,8 @@ function makeObjNotFoundException(msgId, objId) {
|
|
|
41
43
|
type: 'inbox',
|
|
42
44
|
msgId,
|
|
43
45
|
objNotFound: true,
|
|
44
|
-
objId
|
|
46
|
+
objId,
|
|
47
|
+
stack: (0, runtime_1.getStackHere)(1)
|
|
45
48
|
};
|
|
46
49
|
return exc;
|
|
47
50
|
}
|
|
@@ -50,7 +53,8 @@ function makeMsgIsBrokenException(msgId) {
|
|
|
50
53
|
runtimeException: true,
|
|
51
54
|
type: 'inbox',
|
|
52
55
|
msgId,
|
|
53
|
-
msgIsBroken: true
|
|
56
|
+
msgIsBroken: true,
|
|
57
|
+
stack: (0, runtime_1.getStackHere)(1)
|
|
54
58
|
};
|
|
55
59
|
return exc;
|
|
56
60
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2020 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2020, 2026 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
|
|
@@ -19,6 +19,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
19
19
|
const worker_threads_1 = require("worker_threads");
|
|
20
20
|
const ecma_nacl_1 = require("ecma-nacl");
|
|
21
21
|
const error_1 = require("../../lib-common/exceptions/error");
|
|
22
|
+
const runtime_1 = require("../../lib-common/exceptions/runtime");
|
|
22
23
|
if (!worker_threads_1.parentPort) {
|
|
23
24
|
throw new Error(`Missing expected parentPort. Is this called within WebWorker process?`);
|
|
24
25
|
}
|
|
@@ -100,7 +101,8 @@ const funcs = {
|
|
|
100
101
|
function wrapError(err) {
|
|
101
102
|
const exc = {
|
|
102
103
|
runtimeException: true,
|
|
103
|
-
type: 'cryptor'
|
|
104
|
+
type: 'cryptor',
|
|
105
|
+
stack: (0, runtime_1.getStackHere)(1)
|
|
104
106
|
};
|
|
105
107
|
if (err.failedCipherVerification) {
|
|
106
108
|
exc.failedCipherVerification = true;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2018, 2020 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2018, 2020, 2026 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
|
|
@@ -21,6 +21,11 @@ const file_1 = require("../../lib-common/exceptions/file");
|
|
|
21
21
|
const wrapping_1 = require("../../lib-common/byte-streaming/wrapping");
|
|
22
22
|
const assert_1 = require("../../lib-common/assert");
|
|
23
23
|
const buffer_utils_1 = require("../../lib-common/buffer-utils");
|
|
24
|
+
function throwRangeErrorParamsIf(conditionToThrow) {
|
|
25
|
+
if (conditionToThrow) {
|
|
26
|
+
throw RangeError(`Invalid parameters given`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
24
29
|
class DevFileByteSink {
|
|
25
30
|
constructor(path, pathPrefixMaskLen, size) {
|
|
26
31
|
this.path = path;
|
|
@@ -44,13 +49,12 @@ class DevFileByteSink {
|
|
|
44
49
|
};
|
|
45
50
|
}
|
|
46
51
|
async truncate(size) {
|
|
47
|
-
(
|
|
52
|
+
throwRangeErrorParamsIf(!Number.isInteger(size) || (size < 0));
|
|
48
53
|
await fs.truncate(this.path, size);
|
|
49
54
|
this.size = size;
|
|
50
55
|
}
|
|
51
56
|
async splice(pos, del, bytes) {
|
|
52
|
-
(
|
|
53
|
-
&& Number.isInteger(del) && (del >= 0), `Invalid parameters given`);
|
|
57
|
+
throwRangeErrorParamsIf(!Number.isInteger(pos) || (pos < 0) || !Number.isInteger(del) || (del < 0));
|
|
54
58
|
const ins = (bytes ? bytes.length : 0);
|
|
55
59
|
if ((del === 0) && (ins === 0)) {
|
|
56
60
|
return;
|
|
@@ -71,17 +75,17 @@ class DevFileByteSink {
|
|
|
71
75
|
if (!bytes) {
|
|
72
76
|
return;
|
|
73
77
|
}
|
|
74
|
-
let
|
|
78
|
+
let fh = undefined;
|
|
75
79
|
try {
|
|
76
|
-
|
|
77
|
-
await fs.writeFromBuf(
|
|
80
|
+
fh = await fs.open(this.path, 'r+');
|
|
81
|
+
await fs.writeFromBuf(fh, pos, (0, buffer_utils_1.toBuffer)(bytes));
|
|
78
82
|
}
|
|
79
83
|
catch (e) {
|
|
80
84
|
throw (0, file_1.maskPathInExc)(this.pathPrefixMaskLen, e);
|
|
81
85
|
}
|
|
82
86
|
finally {
|
|
83
|
-
if (
|
|
84
|
-
await
|
|
87
|
+
if (fh !== undefined) {
|
|
88
|
+
await fh.close();
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
}
|
|
@@ -89,9 +93,8 @@ class DevFileByteSink {
|
|
|
89
93
|
if (delta === 0) {
|
|
90
94
|
return;
|
|
91
95
|
}
|
|
92
|
-
(
|
|
93
|
-
|
|
94
|
-
&& (pos <= initFileLen), `Invalid parameters given`);
|
|
96
|
+
throwRangeErrorParamsIf(!Number.isInteger(pos) || (pos < 0) || !Number.isInteger(delta) ||
|
|
97
|
+
!Number.isInteger(initFileLen) || (pos > initFileLen));
|
|
95
98
|
if (delta > 0) {
|
|
96
99
|
await this.insFileBytesAt(pos, delta, initFileLen);
|
|
97
100
|
}
|
|
@@ -102,20 +105,19 @@ class DevFileByteSink {
|
|
|
102
105
|
async insFileBytesAt(pos, ins, initFileLen) {
|
|
103
106
|
const bytesToMove = Math.max(0, initFileLen - pos);
|
|
104
107
|
const buf = Buffer.allocUnsafe(Math.min(MAX_SHIFT_BUFFER_SIZE, bytesToMove));
|
|
105
|
-
let
|
|
108
|
+
let fh = undefined;
|
|
106
109
|
try {
|
|
107
|
-
|
|
108
|
-
await
|
|
110
|
+
fh = await fs.open(this.path, 'r+');
|
|
111
|
+
await fh.truncate(initFileLen + ins);
|
|
109
112
|
let bytesLeft = bytesToMove;
|
|
110
113
|
let readPos = initFileLen;
|
|
111
114
|
let writePos = initFileLen + ins;
|
|
112
115
|
while (bytesLeft > 0) {
|
|
113
|
-
const chunk = ((buf.length <= bytesLeft) ?
|
|
114
|
-
buf : buf.slice(0, bytesLeft));
|
|
116
|
+
const chunk = ((buf.length <= bytesLeft) ? buf : buf.slice(0, bytesLeft));
|
|
115
117
|
readPos -= chunk.length;
|
|
116
118
|
writePos -= chunk.length;
|
|
117
|
-
await fs.readToBuf(
|
|
118
|
-
await fs.writeFromBuf(
|
|
119
|
+
await fs.readToBuf(fh, readPos, chunk);
|
|
120
|
+
await fs.writeFromBuf(fh, writePos, chunk);
|
|
119
121
|
bytesLeft -= chunk.length;
|
|
120
122
|
}
|
|
121
123
|
}
|
|
@@ -123,37 +125,37 @@ class DevFileByteSink {
|
|
|
123
125
|
throw (0, file_1.maskPathInExc)(this.pathPrefixMaskLen, e);
|
|
124
126
|
}
|
|
125
127
|
finally {
|
|
126
|
-
if (
|
|
127
|
-
await
|
|
128
|
+
if (fh !== undefined) {
|
|
129
|
+
await fh.close();
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
}
|
|
131
133
|
async rmFileBytesAt(pos, del, initFileLen) {
|
|
132
134
|
const bytesToMove = Math.max(0, initFileLen - pos - del);
|
|
133
135
|
const buf = Buffer.allocUnsafe(Math.min(MAX_SHIFT_BUFFER_SIZE, bytesToMove));
|
|
134
|
-
let
|
|
136
|
+
let fh = undefined;
|
|
135
137
|
try {
|
|
136
|
-
|
|
138
|
+
fh = await fs.open(this.path, 'r+');
|
|
137
139
|
let bytesLeft = bytesToMove;
|
|
138
140
|
let readPos = pos + del;
|
|
139
141
|
let writePos = pos;
|
|
140
142
|
while (bytesLeft > 0) {
|
|
141
143
|
const chunk = ((buf.length <= bytesLeft) ?
|
|
142
144
|
buf : buf.slice(0, bytesLeft));
|
|
143
|
-
await fs.readToBuf(
|
|
144
|
-
await fs.writeFromBuf(
|
|
145
|
+
await fs.readToBuf(fh, readPos, chunk);
|
|
146
|
+
await fs.writeFromBuf(fh, writePos, chunk);
|
|
145
147
|
bytesLeft -= chunk.length;
|
|
146
148
|
readPos += chunk.length;
|
|
147
149
|
writePos += chunk.length;
|
|
148
150
|
}
|
|
149
|
-
await
|
|
151
|
+
await fh.truncate(pos + bytesToMove);
|
|
150
152
|
}
|
|
151
153
|
catch (e) {
|
|
152
154
|
throw (0, file_1.maskPathInExc)(this.pathPrefixMaskLen, e);
|
|
153
155
|
}
|
|
154
156
|
finally {
|
|
155
|
-
if (
|
|
156
|
-
await
|
|
157
|
+
if (fh !== undefined) {
|
|
158
|
+
await fh.close();
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
}
|