core-3nweb-client-lib 0.41.10 → 0.41.12
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/core/asmail/inbox/inbox-events.d.ts +5 -0
- package/build/core/asmail/inbox/inbox-events.js +12 -2
- package/build/core/storage/synced/remote-events.js +1 -1
- package/build/lib-client/3nstorage/storage-owner.d.ts +2 -1
- package/build/lib-client/3nstorage/storage-owner.js +2 -2
- package/build/lib-client/asmail/recipient.d.ts +2 -1
- package/build/lib-client/asmail/recipient.js +2 -2
- package/build/lib-client/server-events.d.ts +4 -2
- package/build/lib-client/server-events.js +9 -3
- package/build/lib-client/ws-utils.js +2 -2
- package/build/lib-common/ipc/generic-ipc.js +32 -25
- package/build/lib-common/ipc/ws-ipc.d.ts +3 -1
- package/build/lib-common/ipc/ws-ipc.js +62 -28
- package/package.json +1 -1
- package/test-data-1-1759430800070/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-10-1759430836227/util/logs/2025-10-02.log.txt +11 -0
- package/test-data-11-1759430836227/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-12-1759430839895/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-13-1759430840691/util/logs/2025-10-02.log.txt +11 -0
- package/test-data-2-1759430800073/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-3-1759430804613/util/logs/2025-10-02.log.txt +11 -0
- package/test-data-4-1759430810570/util/logs/2025-10-02.log.txt +11 -0
- package/test-data-5-1759430819813/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-6-1759430821685/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-7-1759430823627/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-8-1759430832141/util/logs/2025-10-02.log.txt +6 -0
- package/test-data-9-1759430832943/util/logs/2025-10-02.log.txt +11 -0
|
@@ -7,6 +7,11 @@ type Observer<T> = web3n.Observer<T>;
|
|
|
7
7
|
* Instance of this class handles event subscription from UI side. It observes
|
|
8
8
|
* inbox server events, handles them, and generates respective events for UI
|
|
9
9
|
* side.
|
|
10
|
+
*
|
|
11
|
+
* Event stream should hide complexity of going offline, may be sleeping and
|
|
12
|
+
* waking. Consumer should see messages coming, and internally this needs to
|
|
13
|
+
* be opportunistically connected, as long as there are subscribers to messages.
|
|
14
|
+
* Hence, this should do restarts to server around wakeup events.
|
|
10
15
|
*/
|
|
11
16
|
export declare class InboxEvents {
|
|
12
17
|
constructor(msgReceiver: MailRecipient, getMsg: (msgId: string) => Promise<IncomingMessage>, logError: LogError);
|
|
@@ -25,12 +25,22 @@ const SERVER_EVENTS_RESTART_WAIT_SECS = 30;
|
|
|
25
25
|
* Instance of this class handles event subscription from UI side. It observes
|
|
26
26
|
* inbox server events, handles them, and generates respective events for UI
|
|
27
27
|
* side.
|
|
28
|
+
*
|
|
29
|
+
* Event stream should hide complexity of going offline, may be sleeping and
|
|
30
|
+
* waking. Consumer should see messages coming, and internally this needs to
|
|
31
|
+
* be opportunistically connected, as long as there are subscribers to messages.
|
|
32
|
+
* Hence, this should do restarts to server around wakeup events.
|
|
28
33
|
*/
|
|
29
34
|
class InboxEvents {
|
|
30
35
|
constructor(msgReceiver, getMsg, logError) {
|
|
31
|
-
const serverEvents = new server_events_1.ServerEvents(() => msgReceiver.openEventSource(), SERVER_EVENTS_RESTART_WAIT_SECS);
|
|
36
|
+
const serverEvents = new server_events_1.ServerEvents(() => msgReceiver.openEventSource(logError), SERVER_EVENTS_RESTART_WAIT_SECS, logError);
|
|
32
37
|
this.newMsg$ = serverEvents.observe(retrieval_1.msgRecievedCompletely.EVENT_NAME)
|
|
33
|
-
.pipe(
|
|
38
|
+
.pipe(
|
|
39
|
+
// XXX tap to log more details
|
|
40
|
+
(0, operators_1.tap)({
|
|
41
|
+
complete: () => logError({}, `InboxEvents.newMsg$ completes`),
|
|
42
|
+
error: err => logError(err, `InboxEvents.newMsg$ has error`)
|
|
43
|
+
}), (0, operators_1.mergeMap)(async (ev) => {
|
|
34
44
|
try {
|
|
35
45
|
const msg = await getMsg(ev.msgId);
|
|
36
46
|
return msg;
|
|
@@ -36,7 +36,7 @@ class RemoteEvents {
|
|
|
36
36
|
Object.seal(this);
|
|
37
37
|
}
|
|
38
38
|
startAbsorbingRemoteEvents() {
|
|
39
|
-
const serverEvents = new server_events_1.ServerEvents(() => this.remoteStorage.openEventSource(), SERVER_EVENTS_RESTART_WAIT_SECS);
|
|
39
|
+
const serverEvents = new server_events_1.ServerEvents(() => this.remoteStorage.openEventSource(this.logError), SERVER_EVENTS_RESTART_WAIT_SECS, this.logError);
|
|
40
40
|
this.absorbingRemoteEventsProc = (0, rxjs_1.merge)(this.absorbObjChange(serverEvents), this.absorbObjRemoval(serverEvents), this.absorbObjVersionArchival(serverEvents), this.absorbArchVersionRemoval(serverEvents))
|
|
41
41
|
.subscribe({
|
|
42
42
|
next: noop,
|
|
@@ -4,6 +4,7 @@ import { ServiceUser, IGetMailerIdSigner } from '../user-with-mid-session';
|
|
|
4
4
|
import * as keyGen from '../key-derivation';
|
|
5
5
|
import { SubscribingClient } from '../../lib-common/ipc/ws-ipc';
|
|
6
6
|
import { ObjId } from '../xsp-fs/common';
|
|
7
|
+
import { LogError } from '../logging/log-to-file';
|
|
7
8
|
export type FirstSaveReqOpts = api.PutObjFirstQueryOpts;
|
|
8
9
|
export type FollowingSaveReqOpts = api.PutObjSecondQueryOpts;
|
|
9
10
|
export declare class StorageOwner extends ServiceUser {
|
|
@@ -86,5 +87,5 @@ export declare class StorageOwner extends ServiceUser {
|
|
|
86
87
|
* @return a promise, resolvable, when an object is deleted.
|
|
87
88
|
*/
|
|
88
89
|
deleteObj(objId: string): Promise<void>;
|
|
89
|
-
openEventSource(): Promise<SubscribingClient>;
|
|
90
|
+
openEventSource(log: LogError): Promise<SubscribingClient>;
|
|
90
91
|
}
|
|
@@ -329,10 +329,10 @@ class StorageOwner extends user_with_mid_session_1.ServiceUser {
|
|
|
329
329
|
throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
|
-
async openEventSource() {
|
|
332
|
+
async openEventSource(log) {
|
|
333
333
|
const rep = await this.openWS(api.wsEventChannel.URL_END);
|
|
334
334
|
if (rep.status === api.wsEventChannel.SC.ok) {
|
|
335
|
-
return (0, ws_ipc_1.makeSubscriber)(rep.data, undefined);
|
|
335
|
+
return (0, ws_ipc_1.makeSubscriber)(rep.data, undefined, log);
|
|
336
336
|
}
|
|
337
337
|
else {
|
|
338
338
|
throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
|
|
@@ -2,6 +2,7 @@ import { NetClient } from '../request-utils';
|
|
|
2
2
|
import * as api from '../../lib-common/service-api/asmail/retrieval';
|
|
3
3
|
import { ServiceUser, IGetMailerIdSigner } from '../user-with-mid-session';
|
|
4
4
|
import { SubscribingClient } from '../../lib-common/ipc/ws-ipc';
|
|
5
|
+
import { LogError } from '../logging/log-to-file';
|
|
5
6
|
type InboxException = web3n.asmail.InboxException;
|
|
6
7
|
export declare function makeMsgNotFoundException(msgId: string): InboxException;
|
|
7
8
|
export declare function makeObjNotFoundException(msgId: string, objId: string): InboxException;
|
|
@@ -36,6 +37,6 @@ export declare class MailRecipient extends ServiceUser {
|
|
|
36
37
|
*/
|
|
37
38
|
getObjSegs(msgId: string, objId: string, start: number, end: number): Promise<Uint8Array>;
|
|
38
39
|
removeMsg(msgId: string): Promise<void>;
|
|
39
|
-
openEventSource(): Promise<SubscribingClient>;
|
|
40
|
+
openEventSource(log: LogError): Promise<SubscribingClient>;
|
|
40
41
|
}
|
|
41
42
|
export {};
|
|
@@ -192,10 +192,10 @@ class MailRecipient extends user_with_mid_session_1.ServiceUser {
|
|
|
192
192
|
throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
-
async openEventSource() {
|
|
195
|
+
async openEventSource(log) {
|
|
196
196
|
const rep = await this.openWS(api.wsEventChannel.URL_END);
|
|
197
197
|
if (rep.status === api.wsEventChannel.SC.ok) {
|
|
198
|
-
return (0, ws_ipc_1.makeSubscriber)(rep.data, undefined);
|
|
198
|
+
return (0, ws_ipc_1.makeSubscriber)(rep.data, undefined, log);
|
|
199
199
|
}
|
|
200
200
|
else {
|
|
201
201
|
throw (0, request_utils_1.makeException)(rep, 'Unexpected status');
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { SubscribingClient } from '../lib-common/ipc/generic-ipc';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
+
import { LogError } from './logging/log-to-file';
|
|
3
4
|
export declare class ServerEvents<N extends string, T> {
|
|
4
|
-
private subscribeToServer;
|
|
5
|
+
private readonly subscribeToServer;
|
|
5
6
|
private restartWaitSecs;
|
|
7
|
+
private readonly logError;
|
|
6
8
|
private server;
|
|
7
9
|
private openningServer;
|
|
8
|
-
constructor(subscribeToServer: () => Promise<SubscribingClient>, restartWaitSecs: number);
|
|
10
|
+
constructor(subscribeToServer: () => Promise<SubscribingClient>, restartWaitSecs: number, logError: LogError);
|
|
9
11
|
/**
|
|
10
12
|
* This method creates an observable of server's events.
|
|
11
13
|
* @param event is an event on server, to which to subscribe.
|
|
@@ -23,9 +23,10 @@ const sleep_1 = require("../lib-common/processes/sleep");
|
|
|
23
23
|
const operators_1 = require("rxjs/operators");
|
|
24
24
|
const error_1 = require("../lib-common/exceptions/error");
|
|
25
25
|
class ServerEvents {
|
|
26
|
-
constructor(subscribeToServer, restartWaitSecs) {
|
|
26
|
+
constructor(subscribeToServer, restartWaitSecs, logError) {
|
|
27
27
|
this.subscribeToServer = subscribeToServer;
|
|
28
28
|
this.restartWaitSecs = restartWaitSecs;
|
|
29
|
+
this.logError = logError;
|
|
29
30
|
this.server = undefined;
|
|
30
31
|
this.openningServer = new synced_1.SingleProc();
|
|
31
32
|
Object.seal(this);
|
|
@@ -72,13 +73,18 @@ class ServerEvents {
|
|
|
72
73
|
}
|
|
73
74
|
};
|
|
74
75
|
})
|
|
75
|
-
.pipe(
|
|
76
|
+
.pipe(
|
|
77
|
+
// XXX tap to log more details
|
|
78
|
+
(0, operators_1.tap)({
|
|
79
|
+
complete: () => this.logError({}, `ServerEvents.observe stream completes`),
|
|
80
|
+
error: err => this.logError(err, `ServerEvents.observe stream has error`)
|
|
81
|
+
}), (0, operators_1.catchError)(err => {
|
|
76
82
|
if (this.shouldRestartAfterErr(err)) {
|
|
77
83
|
console.error((0, error_1.stringifyErr)(err));
|
|
78
84
|
return this.restartObservation(event);
|
|
79
85
|
}
|
|
80
86
|
else {
|
|
81
|
-
return (0, rxjs_1.throwError)(err);
|
|
87
|
+
return (0, rxjs_1.throwError)(() => err);
|
|
82
88
|
}
|
|
83
89
|
}));
|
|
84
90
|
return event$;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2017, 2019 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2017, 2019, 2025 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
|
|
@@ -29,7 +29,7 @@ function openSocket(url, sessionId) {
|
|
|
29
29
|
headers[request_utils_1.SESSION_ID_HEADER] = sessionId;
|
|
30
30
|
const ws = new WebSocket(url, { headers, agent: https_1.globalAgent });
|
|
31
31
|
const opening = (0, deferred_1.defer)();
|
|
32
|
-
const initOnError = err => opening.reject((0, http_1.makeConnectionException)(url, undefined, `Cannot open websocket connection due to error: ${err.message}`));
|
|
32
|
+
const initOnError = (err) => opening.reject((0, http_1.makeConnectionException)(url, undefined, `Cannot open websocket connection due to error: ${err.message}`));
|
|
33
33
|
const onNonOkReply = (req, res) => {
|
|
34
34
|
const errReply = {
|
|
35
35
|
url,
|
|
@@ -13,15 +13,20 @@
|
|
|
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.SingleObserverWrap = exports.MultiObserverWrap = void 0;
|
|
19
20
|
exports.makeRequestingClient = makeRequestingClient;
|
|
20
21
|
exports.makeRequestServer = makeRequestServer;
|
|
21
22
|
exports.makeEventfulServer = makeEventfulServer;
|
|
22
23
|
exports.makeSubscribingClient = makeSubscribingClient;
|
|
24
|
+
const runtime_1 = require("../exceptions/runtime");
|
|
23
25
|
const map_of_sets_1 = require("../map-of-sets");
|
|
24
26
|
const synced_1 = require("../processes/synced");
|
|
27
|
+
function makeEventException(params) {
|
|
28
|
+
return (0, runtime_1.makeRuntimeException)('events', params, {});
|
|
29
|
+
}
|
|
25
30
|
function toTransferrableError(e) {
|
|
26
31
|
if (e.runtimeException) {
|
|
27
32
|
return e;
|
|
@@ -142,7 +147,14 @@ class RequestingSide extends MessageHandler {
|
|
|
142
147
|
}
|
|
143
148
|
this.replyDeferreds.clear();
|
|
144
149
|
}
|
|
145
|
-
makeRequest(name, req, notifyCallback) {
|
|
150
|
+
async makeRequest(name, req, notifyCallback) {
|
|
151
|
+
if (!this.rawDuplex) {
|
|
152
|
+
throw makeEventException({
|
|
153
|
+
channel: this.channel,
|
|
154
|
+
duplexDisconnected: true,
|
|
155
|
+
request: name
|
|
156
|
+
});
|
|
157
|
+
}
|
|
146
158
|
this.counter += 1;
|
|
147
159
|
if (this.counter === Number.MAX_SAFE_INTEGER) {
|
|
148
160
|
this.counter = Number.MIN_SAFE_INTEGER;
|
|
@@ -225,26 +237,21 @@ class ReplyingSide extends MessageHandler {
|
|
|
225
237
|
}
|
|
226
238
|
}
|
|
227
239
|
errorReply(env, err) {
|
|
228
|
-
|
|
240
|
+
return {
|
|
229
241
|
type: 'reply',
|
|
230
242
|
reqName: env.name,
|
|
231
243
|
reqCount: env.count,
|
|
232
|
-
rep: null
|
|
244
|
+
rep: null,
|
|
245
|
+
err: (err.runtimeException ?
|
|
246
|
+
err : toTransferrableError(err))
|
|
233
247
|
};
|
|
234
|
-
if (err.runtimeException) {
|
|
235
|
-
reply.err = err;
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
reply.err = toTransferrableError(err);
|
|
239
|
-
}
|
|
240
|
-
return reply;
|
|
241
248
|
}
|
|
242
249
|
normalReply(env, rep, isInProgress = false) {
|
|
243
250
|
const reply = {
|
|
244
251
|
type: 'reply',
|
|
245
252
|
reqName: env.name,
|
|
246
253
|
reqCount: env.count,
|
|
247
|
-
rep
|
|
254
|
+
rep,
|
|
248
255
|
};
|
|
249
256
|
if (isInProgress) {
|
|
250
257
|
reply.isInProgress = true;
|
|
@@ -283,14 +290,6 @@ Object.freeze(ReplyingSide);
|
|
|
283
290
|
function makeRequestServer(channel, comm) {
|
|
284
291
|
return (new ReplyingSide(channel, comm)).wrap();
|
|
285
292
|
}
|
|
286
|
-
function makeUnknownEventException(message) {
|
|
287
|
-
return {
|
|
288
|
-
runtimeException: true,
|
|
289
|
-
type: 'events',
|
|
290
|
-
unknownEvent: true,
|
|
291
|
-
message
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
293
|
const SUBSCRIBE_REQ_NAME = 'subscribe';
|
|
295
294
|
const UNSUBSCRIBE_REQ_NAME = 'unsubscribe';
|
|
296
295
|
class EventsSendingSide extends ReplyingSide {
|
|
@@ -313,7 +312,12 @@ class EventsSendingSide extends ReplyingSide {
|
|
|
313
312
|
const event = env.req;
|
|
314
313
|
const gr = this.findGroup(event);
|
|
315
314
|
if (!gr) {
|
|
316
|
-
throw
|
|
315
|
+
throw makeEventException({
|
|
316
|
+
channel: this.channel,
|
|
317
|
+
unknownEvent: true,
|
|
318
|
+
event,
|
|
319
|
+
message: `Events' channel ${event} is not found in handling subscribe`
|
|
320
|
+
});
|
|
317
321
|
}
|
|
318
322
|
this.subscribedEvents.add(event);
|
|
319
323
|
await gr.subscribe(event);
|
|
@@ -322,7 +326,12 @@ class EventsSendingSide extends ReplyingSide {
|
|
|
322
326
|
const event = env.req;
|
|
323
327
|
const gr = this.findGroup(event);
|
|
324
328
|
if (!gr) {
|
|
325
|
-
throw
|
|
329
|
+
throw makeEventException({
|
|
330
|
+
channel: this.channel,
|
|
331
|
+
unknownEvent: true,
|
|
332
|
+
event,
|
|
333
|
+
message: `Events' channel ${event} is not found in handling unsubscribe`
|
|
334
|
+
});
|
|
326
335
|
}
|
|
327
336
|
this.subscribedEvents.delete(event);
|
|
328
337
|
if (gr.unsubscribe) {
|
|
@@ -442,9 +451,7 @@ class EventsReceivingSide extends RequestingSide {
|
|
|
442
451
|
* name, to which listener is attached.
|
|
443
452
|
*/
|
|
444
453
|
this.listeners = new map_of_sets_1.MapOfSets();
|
|
445
|
-
this.channels = new IpcEventChannels((ipcChannel) => this.makeRequest(
|
|
446
|
-
.catch(err => this.completeEvent(ipcChannel, err)), (ipcChannel) => this.makeRequest(UNSUBSCRIBE_REQ_NAME, ipcChannel)
|
|
447
|
-
.catch(_ => { }));
|
|
454
|
+
this.channels = new IpcEventChannels(ipcChannel => this.makeRequest(SUBSCRIBE_REQ_NAME, ipcChannel).catch(err => this.completeEvent(ipcChannel, err)), ipcChannel => this.makeRequest(UNSUBSCRIBE_REQ_NAME, ipcChannel).catch(_ => { }));
|
|
448
455
|
}
|
|
449
456
|
handleMsg(env) {
|
|
450
457
|
if (env.type === 'event') {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LogError } from '../../lib-client/logging/log-to-file';
|
|
1
2
|
import { SubscribingClient } from './generic-ipc';
|
|
2
3
|
import * as WebSocket from 'ws';
|
|
3
4
|
export { RequestEnvelope, RequestHandler, EventfulServer, makeEventfulServer, SubscribingClient } from './generic-ipc';
|
|
@@ -6,4 +7,5 @@ export interface WSException extends web3n.RuntimeException {
|
|
|
6
7
|
socketSlow?: true;
|
|
7
8
|
socketClosed?: true;
|
|
8
9
|
}
|
|
9
|
-
export declare function
|
|
10
|
+
export declare function makeWSException(params: Partial<WSException>, flags?: Partial<WSException>): WSException;
|
|
11
|
+
export declare function makeSubscriber(ws: WebSocket, ipcChannel: string | undefined, log: LogError): SubscribingClient;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2017 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2017, 2025 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
|
|
@@ -16,10 +16,15 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.makeEventfulServer = void 0;
|
|
19
|
+
exports.makeWSException = makeWSException;
|
|
19
20
|
exports.makeSubscriber = makeSubscriber;
|
|
21
|
+
const runtime_1 = require("../exceptions/runtime");
|
|
20
22
|
const generic_ipc_1 = require("./generic-ipc");
|
|
21
23
|
var generic_ipc_2 = require("./generic-ipc");
|
|
22
24
|
Object.defineProperty(exports, "makeEventfulServer", { enumerable: true, get: function () { return generic_ipc_2.makeEventfulServer; } });
|
|
25
|
+
function makeWSException(params, flags) {
|
|
26
|
+
return (0, runtime_1.makeRuntimeException)('websocket', params, flags !== null && flags !== void 0 ? flags : {});
|
|
27
|
+
}
|
|
23
28
|
const MAX_TXT_BUFFER = 64 * 1024;
|
|
24
29
|
/**
|
|
25
30
|
* This creates a json communication point on a given web socket.
|
|
@@ -27,22 +32,18 @@ const MAX_TXT_BUFFER = 64 * 1024;
|
|
|
27
32
|
* messages.
|
|
28
33
|
* @param ws
|
|
29
34
|
*/
|
|
30
|
-
function makeJsonCommPoint(ws) {
|
|
35
|
+
function makeJsonCommPoint(ws, log) {
|
|
31
36
|
const observers = new generic_ipc_1.MultiObserverWrap();
|
|
32
|
-
|
|
33
|
-
ws.on('
|
|
34
|
-
ws.on('
|
|
35
|
-
ws.on('
|
|
37
|
+
const resetTimer = makeSignalsTimeObserver(ws.url, log);
|
|
38
|
+
ws.on('message', onTxtMessage(ws, observers, resetTimer));
|
|
39
|
+
ws.on('close', onClose(observers, resetTimer));
|
|
40
|
+
ws.on('error', onError(ws, observers, resetTimer));
|
|
41
|
+
ws.on('ping', onPing(ws, resetTimer));
|
|
36
42
|
const commPoint = {
|
|
37
43
|
subscribe: obs => observers.add(obs),
|
|
38
44
|
postMessage(env) {
|
|
39
45
|
if (ws.bufferedAmount > MAX_TXT_BUFFER) {
|
|
40
|
-
|
|
41
|
-
runtimeException: true,
|
|
42
|
-
type: 'websocket',
|
|
43
|
-
socketSlow: true
|
|
44
|
-
};
|
|
45
|
-
throw exc;
|
|
46
|
+
throw makeWSException({ socketSlow: true });
|
|
46
47
|
}
|
|
47
48
|
ws.send(JSON.stringify(env));
|
|
48
49
|
}
|
|
@@ -54,7 +55,7 @@ function makeJsonCommPoint(ws) {
|
|
|
54
55
|
* @param ws
|
|
55
56
|
* @param observers
|
|
56
57
|
*/
|
|
57
|
-
function onTxtMessage(ws, observers) {
|
|
58
|
+
function onTxtMessage(ws, observers, resetTimer) {
|
|
58
59
|
return (data) => {
|
|
59
60
|
if (typeof data !== 'string') {
|
|
60
61
|
return;
|
|
@@ -72,25 +73,25 @@ function onTxtMessage(ws, observers) {
|
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
74
75
|
observers.next(env);
|
|
76
|
+
resetTimer();
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
79
|
/**
|
|
78
80
|
* This generates an on-close callback for a web socket.
|
|
79
81
|
* @param observers
|
|
80
82
|
*/
|
|
81
|
-
function onClose(observers) {
|
|
83
|
+
function onClose(observers, resetTimer) {
|
|
82
84
|
return (code, reason) => {
|
|
83
85
|
if (code === 1000) {
|
|
86
|
+
resetTimer(true);
|
|
84
87
|
observers.complete();
|
|
85
88
|
}
|
|
86
89
|
else {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
type: 'websocket',
|
|
90
|
+
resetTimer(true, { code, reason });
|
|
91
|
+
observers.error(makeWSException({
|
|
90
92
|
socketClosed: true,
|
|
91
93
|
cause: { code, reason }
|
|
92
|
-
};
|
|
93
|
-
observers.error(exc);
|
|
94
|
+
}));
|
|
94
95
|
}
|
|
95
96
|
};
|
|
96
97
|
}
|
|
@@ -99,19 +100,52 @@ function onClose(observers) {
|
|
|
99
100
|
* @param ws
|
|
100
101
|
* @param observers
|
|
101
102
|
*/
|
|
102
|
-
function onError(ws, observers) {
|
|
103
|
+
function onError(ws, observers, closeTimer) {
|
|
103
104
|
return (err) => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
type: 'websocket',
|
|
107
|
-
cause: err
|
|
108
|
-
};
|
|
109
|
-
observers.error(exc);
|
|
105
|
+
closeTimer(true, err);
|
|
106
|
+
observers.error(makeWSException({ cause: err }));
|
|
110
107
|
ws.close();
|
|
111
108
|
};
|
|
112
109
|
}
|
|
113
|
-
function
|
|
114
|
-
|
|
110
|
+
function onPing(ws, resetTimer) {
|
|
111
|
+
return () => {
|
|
112
|
+
resetTimer();
|
|
113
|
+
ws.pong();
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function makeSignalsTimeObserver(url, log) {
|
|
117
|
+
const serverPingSettings = 2 * 60 * 1000;
|
|
118
|
+
let lastMoment = Date.now();
|
|
119
|
+
let int = undefined;
|
|
120
|
+
function resetWait(setNew = true) {
|
|
121
|
+
lastMoment = Date.now();
|
|
122
|
+
if (int) {
|
|
123
|
+
clearInterval(int);
|
|
124
|
+
int = undefined;
|
|
125
|
+
}
|
|
126
|
+
if (setNew) {
|
|
127
|
+
int = setInterval(() => {
|
|
128
|
+
log(`Ping/data from ${url} is not observed in last ${Math.floor((Date.now() - lastMoment) / 1000)} seconds`);
|
|
129
|
+
}, serverPingSettings * 1.5).unref();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return (done, err) => {
|
|
133
|
+
if (done) {
|
|
134
|
+
if (err) {
|
|
135
|
+
log(`WebSocket to ${url} closed with error`, err);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
log(`WebSocket to ${url} closed`);
|
|
139
|
+
}
|
|
140
|
+
resetWait(false);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
resetWait();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function makeSubscriber(ws, ipcChannel, log) {
|
|
148
|
+
const comm = makeJsonCommPoint(ws, log);
|
|
115
149
|
return (0, generic_ipc_1.makeSubscribingClient)(ipcChannel, comm);
|
|
116
150
|
}
|
|
117
151
|
Object.freeze(exports);
|
package/package.json
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
Thu Oct 02 2025 14:47:19 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
3
|
+
Core version 0.41.12
|
|
4
|
+
Log level: error.
|
|
5
|
+
[object Object]
|
|
6
|
+
WebSocket to wss://localhost:8088/asmail/retrieval/events closed with error
|
|
7
|
+
Thu Oct 02 2025 14:47:19 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
8
|
+
Core version 0.41.12
|
|
9
|
+
Log level: error.
|
|
10
|
+
[object Object]
|
|
11
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
Thu Oct 02 2025 14:47:22 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
3
|
+
Core version 0.41.12
|
|
4
|
+
Log level: error.
|
|
5
|
+
[object Object]
|
|
6
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
7
|
+
Thu Oct 02 2025 14:47:22 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
8
|
+
Core version 0.41.12
|
|
9
|
+
Log level: error.
|
|
10
|
+
[object Object]
|
|
11
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
Thu Oct 02 2025 14:46:50 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
3
|
+
Core version 0.41.12
|
|
4
|
+
Log level: error.
|
|
5
|
+
[object Object]
|
|
6
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
7
|
+
Thu Oct 02 2025 14:46:50 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
8
|
+
Core version 0.41.12
|
|
9
|
+
Log level: error.
|
|
10
|
+
[object Object]
|
|
11
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
Thu Oct 02 2025 14:46:56 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
3
|
+
Core version 0.41.12
|
|
4
|
+
Log level: error.
|
|
5
|
+
[object Object]
|
|
6
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
7
|
+
Thu Oct 02 2025 14:46:56 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
8
|
+
Core version 0.41.12
|
|
9
|
+
Log level: error.
|
|
10
|
+
[object Object]
|
|
11
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
|
|
2
|
+
Thu Oct 02 2025 14:47:16 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
3
|
+
Core version 0.41.12
|
|
4
|
+
Log level: error.
|
|
5
|
+
[object Object]
|
|
6
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|
|
7
|
+
Thu Oct 02 2025 14:47:16 GMT-0400 (Eastern Daylight Saving Time) ==================================
|
|
8
|
+
Core version 0.41.12
|
|
9
|
+
Log level: error.
|
|
10
|
+
[object Object]
|
|
11
|
+
WebSocket to wss://localhost:8088/3nstorage/owner/events closed with error
|