core-3nweb-client-lib 0.44.5 → 0.44.6

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.
@@ -1201,7 +1201,7 @@ declare namespace web3n.files {
1201
1201
  syncStatus: SyncStatus;
1202
1202
  }
1203
1203
 
1204
- type UploadEvent = UploadStartEvent | UploadProgressEvent | UploadDoneEvent;
1204
+ type UploadEvent = UploadStartEvent | UploadProgressEvent | UploadDisconnectedEvent | UploadDoneEvent;
1205
1205
 
1206
1206
  interface UploadEventBase extends FSEvent {
1207
1207
  uploadTaskId: number;
@@ -1220,6 +1220,10 @@ declare namespace web3n.files {
1220
1220
  bytesLeftToUpload: number;
1221
1221
  }
1222
1222
 
1223
+ interface UploadDisconnectedEvent extends UploadEventBase {
1224
+ type: 'upload-disconnected';
1225
+ }
1226
+
1223
1227
  interface UploadDoneEvent extends UploadEventBase {
1224
1228
  type: 'upload-done';
1225
1229
  }
@@ -31,8 +31,10 @@ export declare class InboxEvents {
31
31
  readonly connectionEvent$: Observable<InboxConnectionStatus>;
32
32
  private readonly wsProc;
33
33
  private disconnectedAt;
34
+ private connection;
34
35
  constructor(msgReceiver: MailRecipient, getMsg: (msgId: string) => Promise<IncomingMessage>, listNewMsgs: (fromTS: number) => Promise<MsgInfo[]>, rmMsg: (msgId: string) => Promise<void>, logError: LogError);
35
36
  private makeProc;
37
+ whenConnected(): Promise<void>;
36
38
  private getMessage;
37
39
  subscribe<T>(event: InboxEventType, observer: Observer<T>): () => void;
38
40
  close(): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2017, 2019, 2022, 2024 - 2025 3NSoft Inc.
3
+ Copyright (C) 2017, 2019, 2022, 2024 - 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
@@ -22,6 +22,7 @@ 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");
25
26
  function toInboxConnectionStatus(status, params) {
26
27
  return (0, ws_ipc_1.addToStatus)(status, {
27
28
  service: 'inbox',
@@ -52,6 +53,7 @@ class InboxEvents {
52
53
  this.connectionEvents = new rxjs_1.Subject();
53
54
  this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
54
55
  this.disconnectedAt = undefined;
56
+ this.connection = new awaitable_state_1.AwaitableState();
55
57
  this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
56
58
  this.wsProc.startListening();
57
59
  Object.seal(this);
@@ -60,7 +62,15 @@ class InboxEvents {
60
62
  const proc$ = (0, rxjs_1.from)(this.msgReceiver.openEventSource().then(({ client, heartbeat }) => {
61
63
  const channel = retrieval_1.msgRecievedCompletely.EVENT_NAME;
62
64
  heartbeat.subscribe({
63
- next: ev => this.connectionEvents.next(toInboxConnectionStatus(ev))
65
+ next: ev => {
66
+ this.connectionEvents.next(toInboxConnectionStatus(ev));
67
+ if (ev.type === 'heartbeat') {
68
+ this.connection.setState();
69
+ }
70
+ else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
71
+ this.connection.clearState();
72
+ }
73
+ }
64
74
  });
65
75
  return new rxjs_1.Observable(obs => client.subscribe(channel, obs));
66
76
  }))
@@ -76,6 +86,9 @@ class InboxEvents {
76
86
  this.listMsgsFromDisconnectedPeriod();
77
87
  return proc$;
78
88
  }
89
+ async whenConnected() {
90
+ return this.connection.whenStateIsSet();
91
+ }
79
92
  async getMessage(msgId) {
80
93
  try {
81
94
  return await this.getMsg(msgId);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2015 - 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2015 - 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
@@ -58,12 +58,13 @@ 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, () => inbox.inboxEvents.whenConnected());
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);
65
65
  await (0, fs_sync_utils_1.uploadFolderChangesIfAny)(syncedFS);
66
- return new InboxOnServer(r.correspondents, msgReceiver, r.getStorages, r.cryptor, downloader, cache, index, r.logError);
66
+ const inbox = new InboxOnServer(r.correspondents, msgReceiver, r.getStorages, r.cryptor, downloader, cache, index, r.logError);
67
+ return inbox;
67
68
  }
68
69
  catch (err) {
69
70
  throw (0, error_1.errWithCause)(err, 'Failed to initialize Inbox');
@@ -3,8 +3,9 @@ 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;
6
7
  private readonly runner;
7
- constructor(msgReceiver: MailRecipient);
8
+ constructor(msgReceiver: MailRecipient, whenConnected: () => Promise<void>);
8
9
  getMsgMeta(msgId: string): Promise<MsgMeta>;
9
10
  getObjDownloader(msgId: string): ObjDownloader;
10
11
  private getLayoutWithHeaderAndFirstSegs;
@@ -21,8 +21,9 @@ 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, whenConnected) {
25
25
  this.msgReceiver = msgReceiver;
26
+ this.whenConnected = whenConnected;
26
27
  this.runner = new obj_on_disk_1.DownloadsRunner();
27
28
  Object.freeze(this);
28
29
  }
@@ -34,7 +35,8 @@ class MsgDownloader {
34
35
  getLayoutWithHeaderAndFirstSegs: (objId, v) => this.getLayoutWithHeaderAndFirstSegs(msgId, objId),
35
36
  getSegs: (objId, v, start, end) => this.getSegs(msgId, objId, start, end),
36
37
  splitSegsDownloads: (start, end) => (0, obj_on_disk_1.splitSegsDownloads)(start, end, MAX_GETTING_CHUNK),
37
- schedule: this.runner.schedule.bind(this.runner)
38
+ schedule: this.runner.schedule.bind(this.runner),
39
+ whenConnected: this.whenConnected
38
40
  };
39
41
  }
40
42
  async getLayoutWithHeaderAndFirstSegs(msgId, objId) {
@@ -3,8 +3,9 @@ import { ObjId } from '../../../lib-client/xsp-fs/common';
3
3
  import { ObjDownloader, InitDownloadParts, Section, Download } from '../../../lib-client/objs-on-disk/obj-on-disk';
4
4
  export declare class Downloader implements ObjDownloader {
5
5
  private readonly remoteStorage;
6
+ readonly whenConnected: () => Promise<void>;
6
7
  private readonly runner;
7
- constructor(remoteStorage: StorageOwner);
8
+ constructor(remoteStorage: StorageOwner, whenConnected: () => Promise<void>);
8
9
  getLayoutWithHeaderAndFirstSegs(objId: ObjId, version: number): Promise<InitDownloadParts>;
9
10
  schedule(download: Download): void;
10
11
  getSegs(objId: ObjId, version: number, start: number, end: number): Promise<Uint8Array>;
@@ -21,8 +21,9 @@ 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 Downloader {
24
- constructor(remoteStorage) {
24
+ constructor(remoteStorage, whenConnected) {
25
25
  this.remoteStorage = remoteStorage;
26
+ this.whenConnected = whenConnected;
26
27
  this.runner = new obj_on_disk_1.DownloadsRunner();
27
28
  Object.seal(this);
28
29
  }
@@ -27,7 +27,7 @@ export declare class ObjFiles {
27
27
  private readonly downloader;
28
28
  private readonly gc;
29
29
  private constructor();
30
- static makeFor(path: string, remote: RemoteStorage, logError: LogError): Promise<ObjFiles>;
30
+ static makeFor(path: string, remote: RemoteStorage, whenConnected: () => Promise<void>, logError: LogError): Promise<ObjFiles>;
31
31
  private canMoveObjToDeeperCache;
32
32
  findObj(objId: ObjId): Promise<SyncedObj | undefined>;
33
33
  getObjInCache(objId: ObjId): SyncedObj | undefined;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2016 - 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2016 - 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
@@ -42,12 +42,12 @@ exports.REMOTE_FILE_NAME_EXT = 'v';
42
42
  * SyncedObj's.
43
43
  */
44
44
  class ObjFiles {
45
- constructor(folders, remote, logError) {
45
+ constructor(folders, remote, whenConnected, logError) {
46
46
  this.folders = folders;
47
47
  this.logError = logError;
48
48
  this.objs = (0, timed_cache_1.makeTimedCache)(60 * 1000);
49
49
  this.sync = makeSynchronizer();
50
- this.downloader = new downloader_1.Downloader(remote);
50
+ this.downloader = new downloader_1.Downloader(remote, whenConnected);
51
51
  this.gc = new obj_files_gc_1.GC(this.sync, obj => {
52
52
  if (this.objs.get(obj.objId) === obj) {
53
53
  this.objs.delete(obj.objId);
@@ -55,10 +55,10 @@ class ObjFiles {
55
55
  }, objId => this.folders.removeFolderOf(objId));
56
56
  Object.freeze(this);
57
57
  }
58
- static async makeFor(path, remote, logError) {
58
+ static async makeFor(path, remote, whenConnected, logError) {
59
59
  const canMove = (objId, objFolderPath) => objFiles.canMoveObjToDeeperCache(objId, objFolderPath);
60
60
  const folders = await obj_folders_1.ObjFolders.makeWithGenerations(path, canMove, logError);
61
- const objFiles = new ObjFiles(folders, remote, logError);
61
+ const objFiles = new ObjFiles(folders, remote, whenConnected, logError);
62
62
  return objFiles;
63
63
  }
64
64
  async canMoveObjToDeeperCache(objId, objFolderPath) {
@@ -19,13 +19,12 @@ export declare class RemoteEvents {
19
19
  private readonly connectionEvents;
20
20
  readonly connectionEvent$: Observable<StorageConnectionStatus>;
21
21
  private readonly wsProc;
22
- private deferredConnection;
22
+ private connection;
23
23
  constructor(remoteStorage: StorageOwner, files: ObjFiles, broadcastNodeEvent: Storage['broadcastNodeEvent'], logError: LogError);
24
24
  private makeProc;
25
25
  startListening(): void;
26
26
  close(): Promise<void>;
27
27
  whenConnected(): Promise<void>;
28
- private signalConnected;
29
28
  private absorbObjChange;
30
29
  private absorbObjRemoval;
31
30
  private absorbObjVersionArchival;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2019 - 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2019 - 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
@@ -21,7 +21,7 @@ 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 deferred_1 = require("../../../lib-common/processes/deferred");
24
+ const awaitable_state_1 = require("../../../lib-common/awaitable-state");
25
25
  function toStorageConnectionStatus(status, params) {
26
26
  return (0, ws_ipc_1.addToStatus)(status, {
27
27
  service: 'storage',
@@ -41,23 +41,21 @@ class RemoteEvents {
41
41
  this.logError = logError;
42
42
  this.connectionEvents = new rxjs_1.Subject();
43
43
  this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
44
- this.deferredConnection = (0, deferred_1.defer)();
44
+ this.connection = new awaitable_state_1.AwaitableState();
45
45
  this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
46
46
  Object.seal(this);
47
47
  }
48
48
  makeProc() {
49
49
  return (0, rxjs_1.from)(this.remoteStorage.openEventSource().then(({ client, heartbeat }) => {
50
- this.signalConnected();
50
+ this.connection.setState();
51
51
  heartbeat.subscribe({
52
52
  next: ev => {
53
53
  this.connectionEvents.next(toStorageConnectionStatus(ev));
54
54
  if (ev.type === 'heartbeat') {
55
- this.signalConnected();
55
+ this.connection.setState();
56
56
  }
57
57
  else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
58
- if (!this.deferredConnection) {
59
- this.deferredConnection = (0, deferred_1.defer)();
60
- }
58
+ this.connection.clearState();
61
59
  }
62
60
  }
63
61
  });
@@ -79,14 +77,7 @@ class RemoteEvents {
79
77
  this.wsProc.close();
80
78
  }
81
79
  async whenConnected() {
82
- var _a;
83
- return (_a = this.deferredConnection) === null || _a === void 0 ? void 0 : _a.promise;
84
- }
85
- signalConnected() {
86
- if (this.deferredConnection) {
87
- this.deferredConnection.resolve();
88
- this.deferredConnection = undefined;
89
- }
80
+ return this.connection.whenStateIsSet();
90
81
  }
91
82
  absorbObjChange(client) {
92
83
  return (new rxjs_1.Observable(obs => client.subscribe(owner_1.events.objChanged.EVENT_NAME, obs)))
@@ -40,12 +40,12 @@ 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.logError);
43
+ this.uploader = new upsyncer_1.UpSyncer(this.remoteStorage, this.whenConnected.bind(this), this.logError);
44
44
  Object.seal(this);
45
45
  }
46
46
  static async makeAndStart(path, user, getSigner, getStorages, cryptor, remoteServiceUrl, net, logError) {
47
47
  const remote = storage_owner_1.StorageOwner.make(user, getSigner, remoteServiceUrl, net);
48
- const objFiles = await obj_files_1.ObjFiles.makeFor(path, remote, logError);
48
+ const objFiles = await obj_files_1.ObjFiles.makeFor(path, remote, () => s.whenConnected(), logError);
49
49
  const s = new SyncedStore(objFiles, remote, getStorages, cryptor, logError);
50
50
  s.uploader.start();
51
51
  return {
@@ -57,7 +57,7 @@ class SyncedStore {
57
57
  }
58
58
  static async makeAndStartWithoutRemote(path, user, getStorages, cryptor, remoteServiceUrl, net, logError) {
59
59
  const { remote, setMid } = storage_owner_1.StorageOwner.makeBeforeMidSetup(user, remoteServiceUrl, net);
60
- const objFiles = await obj_files_1.ObjFiles.makeFor(path, remote, logError);
60
+ const objFiles = await obj_files_1.ObjFiles.makeFor(path, remote, () => s.whenConnected(), logError);
61
61
  const s = new SyncedStore(objFiles, remote, getStorages, cryptor, logError);
62
62
  return {
63
63
  syncedStore: (0, common_1.wrapSyncStorageImplementation)(s),
@@ -8,19 +8,15 @@ 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;
11
12
  private readonly logError;
12
13
  private readonly execPools;
13
14
  private readonly tasksByObjIds;
14
15
  private readonly tasksByIds;
15
16
  private readonly syncedUploadStarts;
16
- constructor(remoteStorage: StorageOwner, logError: LogError);
17
+ constructor(remoteStorage: StorageOwner, whenConnected: () => Promise<void>, logError: LogError);
17
18
  start(): void;
18
19
  stop(): Promise<void>;
19
- /**
20
- * Creates an rxjs operator to tap saving process, starting upload while
21
- * writing is ongoing.
22
- */
23
- tapFileWrite(obj: SyncedObj, isNew: boolean, newVersion: number, baseVersion?: number): FileWriteTapOperator;
24
20
  removeCurrentVersionOf(obj: SyncedObj): Promise<void>;
25
21
  startUploadFromDisk(obj: SyncedObj, localVersion: number, uploadVersion: number, uploadHeader: UploadHeaderChange | undefined, createOnRemote: boolean, eventSink: UploadEventSink | undefined): Promise<{
26
22
  completion: Promise<void>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 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
@@ -27,8 +27,9 @@ 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, logError) {
30
+ constructor(remoteStorage, whenConnected, logError) {
31
31
  this.remoteStorage = remoteStorage;
32
+ this.whenConnected = whenConnected;
32
33
  this.logError = logError;
33
34
  this.tasksByObjIds = new Map();
34
35
  this.tasksByIds = new Map();
@@ -45,25 +46,19 @@ class UpSyncer {
45
46
  async stop() {
46
47
  await this.execPools.stop(); // implicitly cancels all upsync tasks
47
48
  }
48
- /**
49
- * Creates an rxjs operator to tap saving process, starting upload while
50
- * writing is ongoing.
51
- */
52
- tapFileWrite(obj, isNew, newVersion, baseVersion) {
53
- throw new Error('UpSyncer.tapFileWrite() not implemented');
54
- // const objUploads = this.getOrMakeUploadsFor(obj);
55
- // return objUploads.tapFileWrite(isNew, newVersion, baseVersion);
56
- }
57
49
  async removeCurrentVersionOf(obj) {
58
50
  try {
59
51
  await this.remoteStorage.deleteObj(obj.objId);
60
52
  }
61
53
  catch (exc) {
62
- // XXX
63
- // - we need to distinguish errors and put this work somewhere
64
- // to run when we go online, for example.
65
- await this.logError(exc, `Uploading of obj removal failed.`);
66
- return;
54
+ if (exc.type === 'connect') {
55
+ await this.whenConnected();
56
+ return this.removeCurrentVersionOf(obj);
57
+ }
58
+ else {
59
+ await this.logError(exc, `Uploading of obj removal failed.`);
60
+ return;
61
+ }
67
62
  }
68
63
  await obj.recordRemovalUploadAndGC();
69
64
  }
@@ -88,7 +83,7 @@ class UpSyncer {
88
83
  if (uploadHeader) {
89
84
  await obj.saveUploadHeaderFile(uploadHeader);
90
85
  }
91
- const task = await UploadTask.for(obj, localVersion, uploadVersion, uploadHeader === null || uploadHeader === void 0 ? void 0 : uploadHeader.uploadHeader, syncedBase, createOnRemote, uploadTaskId, eventSink, this.remoteStorage, async () => {
86
+ const task = await UploadTask.for(obj, localVersion, uploadVersion, uploadHeader === null || uploadHeader === void 0 ? void 0 : uploadHeader.uploadHeader, syncedBase, createOnRemote, uploadTaskId, eventSink, this.remoteStorage, this.whenConnected, async () => {
92
87
  if (this.tasksByIds.delete(task.taskId)) {
93
88
  this.tasksByObjIds.delete(task.objId);
94
89
  }
@@ -113,9 +108,10 @@ exports.UpSyncer = UpSyncer;
113
108
  Object.freeze(UpSyncer.prototype);
114
109
  Object.freeze(UpSyncer);
115
110
  class UploadTask {
116
- constructor(taskId, remoteStorage, objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink) {
111
+ constructor(taskId, remoteStorage, whenConnected, objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink) {
117
112
  this.taskId = taskId;
118
113
  this.remoteStorage = remoteStorage;
114
+ this.whenConnected = whenConnected;
119
115
  this.objId = objId;
120
116
  this.objStatus = objStatus;
121
117
  this.src = src;
@@ -129,7 +125,7 @@ class UploadTask {
129
125
  this.emitUploadEvent('upload-started', { totalBytesToUpload: this.totalBytesToUpload });
130
126
  Object.seal(this);
131
127
  }
132
- static async for(obj, localVersion, uploadVersion, uploadHeader, syncedBase, createObj, taskId, eventSink, remoteStorage, doAtCompletion) {
128
+ static async for(obj, localVersion, uploadVersion, uploadHeader, syncedBase, createObj, taskId, eventSink, remoteStorage, whenConnected, doAtCompletion) {
133
129
  const src = await obj.getObjSrcFromLocalAndSyncedBranch(localVersion);
134
130
  let needUpload;
135
131
  if (syncedBase) {
@@ -148,7 +144,7 @@ class UploadTask {
148
144
  };
149
145
  const objStatus = obj.statusObj();
150
146
  await objStatus.recordUploadStart(info);
151
- return new UploadTask(taskId, remoteStorage, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink);
147
+ return new UploadTask(taskId, remoteStorage, whenConnected, obj.objId, objStatus, src, info, uploadHeader, doAtCompletion, eventSink);
152
148
  }
153
149
  neededExecutor() {
154
150
  return (!this.info.needUpload ? undefined : this.execLabel);
@@ -213,14 +209,21 @@ class UploadTask {
213
209
  }
214
210
  }
215
211
  catch (exc) {
216
- this.info.needUpload = undefined;
217
- this.uploadCompletion.reject((0, exceptions_1.makeFSSyncException)(`obj-upload`, {
218
- message: `Fail to upload local version ${this.info.uploadVersion}`,
219
- localVersion: this.info.uploadVersion,
220
- cause: exc
221
- }));
222
- await this.objStatus.recordUploadCancellation(this.info);
223
- return true;
212
+ if (exc.type === 'connect') {
213
+ this.emitUploadEvent('upload-disconnected', {});
214
+ await this.whenConnected();
215
+ return false;
216
+ }
217
+ else {
218
+ this.info.needUpload = undefined;
219
+ this.uploadCompletion.reject((0, exceptions_1.makeFSSyncException)(`obj-upload`, {
220
+ message: `Fail to upload local version ${this.info.uploadVersion}`,
221
+ localVersion: this.info.uploadVersion,
222
+ cause: exc
223
+ }));
224
+ await this.objStatus.recordUploadCancellation(this.info);
225
+ return true;
226
+ }
224
227
  }
225
228
  }
226
229
  async startOrderedUpload(upload) {
@@ -73,6 +73,7 @@ export interface ObjDownloader {
73
73
  getSegs: (objId: ObjId, version: number, start: number, end: number) => Promise<Uint8Array>;
74
74
  splitSegsDownloads: (start: number, end: number) => Section[];
75
75
  schedule: (download: Download) => void;
76
+ whenConnected: () => Promise<void>;
76
77
  }
77
78
  export interface InitDownloadParts {
78
79
  layout: Layout;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /*
3
- Copyright (C) 2018 - 2020, 2022, 2025 3NSoft Inc.
3
+ Copyright (C) 2018 - 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
@@ -423,7 +423,12 @@ class Download {
423
423
  this.inBkgrnd.runData.currentDownload.deferred.resolve(bytes);
424
424
  }
425
425
  catch (exc) {
426
- this.inBkgrnd.runData.currentDownload.deferred.reject(exc);
426
+ if (exc.type === 'connect') {
427
+ await this.downloader.whenConnected();
428
+ }
429
+ else {
430
+ this.inBkgrnd.runData.currentDownload.deferred.reject(exc);
431
+ }
427
432
  }
428
433
  finally {
429
434
  this.inBkgrnd.runData.currentDownload = undefined;
@@ -818,6 +818,19 @@ class S {
818
818
  throw (0, common_1.setPathInExc)(exc, path);
819
819
  }
820
820
  }
821
+ // XXX WIP
822
+ // async compareLocalAndRemoteFileItems(
823
+ // path: string, itemName: string, remoteVersion?: number
824
+ // ): Promise<FileDiff> {
825
+ // const folderNode = await this.getFolderNode(path);
826
+ // const localChild = (await folderNode.getFile(itemName))!;
827
+ // const remoteChild = await folderNode.getRemoteItemNode(itemName, remoteVersion);
828
+ // if (remoteChild.type === 'file') {
829
+ // return await localChild.compareWithRemote(remoteChild);
830
+ // } else {
831
+ // throw makeFileException('notFile', `${path}/${itemName}`);
832
+ // }
833
+ // }
821
834
  async adoptRemoteFolderItem(path, itemName, opts) {
822
835
  const node = await this.getFolderNode(path);
823
836
  try {
@@ -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.asyncIteration = asyncIteration;
19
20
  exports.asyncFind = asyncFind;
@@ -0,0 +1,7 @@
1
+ export declare class AwaitableState {
2
+ private deferredStateSetPoint;
3
+ constructor();
4
+ setState(): void;
5
+ clearState(): void;
6
+ whenStateIsSet(): Promise<void>;
7
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /*
3
+ Copyright (C) 2017 3NSoft Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU General Public License as published by the Free Software
7
+ Foundation, either version 3 of the License, or (at your option) any later
8
+ version.
9
+
10
+ This program is distributed in the hope that it will be useful, but
11
+ WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
+ See the GNU General Public License for more details.
14
+
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/>.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.AwaitableState = void 0;
20
+ const deferred_1 = require("./processes/deferred");
21
+ class AwaitableState {
22
+ constructor() {
23
+ this.deferredStateSetPoint = (0, deferred_1.defer)();
24
+ Object.seal(this);
25
+ }
26
+ setState() {
27
+ if (this.deferredStateSetPoint) {
28
+ this.deferredStateSetPoint.resolve();
29
+ this.deferredStateSetPoint = undefined;
30
+ }
31
+ }
32
+ clearState() {
33
+ if (!this.deferredStateSetPoint) {
34
+ this.deferredStateSetPoint = (0, deferred_1.defer)();
35
+ }
36
+ }
37
+ async whenStateIsSet() {
38
+ var _a;
39
+ return (_a = this.deferredStateSetPoint) === null || _a === void 0 ? void 0 : _a.promise;
40
+ }
41
+ }
42
+ exports.AwaitableState = AwaitableState;
43
+ Object.freeze(exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-3nweb-client-lib",
3
- "version": "0.44.5",
3
+ "version": "0.44.6",
4
4
  "description": "3NWeb client core library, embeddable into different environments",
5
5
  "main": "build/lib-index.js",
6
6
  "types": "build/lib-index.d.ts",