core-3nweb-client-lib 0.44.0 → 0.44.2
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 +8 -8
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +3 -2
- package/build/core/storage/index.d.ts +1 -0
- package/build/core/storage/index.js +4 -1
- package/build/core/storage/synced/storage.d.ts +1 -0
- package/build/core/storage/synced/storage.js +4 -1
- package/build/core-ipc/fs.js +31 -9
- package/build/lib-client/asmail/recipient.js +4 -2
- package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
- package/build/lib-client/cryptor/cryptor.wasm +0 -0
- package/build/lib-client/ws-utils.js +2 -7
- package/build/lib-client/xsp-fs/common.d.ts +2 -0
- package/build/lib-client/xsp-fs/common.js +2 -1
- package/build/lib-client/xsp-fs/folder-node.js +39 -25
- package/build/lib-client/xsp-fs/fs.js +1 -16
- package/build/lib-common/ipc/generic-ipc.js +33 -28
- package/build/lib-common/ipc/ws-ipc.d.ts +2 -0
- package/build/lib-common/ipc/ws-ipc.js +35 -8
- package/build/lib-common/map-of-sets.d.ts +1 -0
- package/build/lib-common/map-of-sets.js +3 -0
- package/build/protos/asmail.proto.js +149 -378
- package/build/protos/fs.proto.js +149 -378
- package/package.json +1 -1
- package/protos/fs.proto +5 -9
|
Binary file
|
|
@@ -46,21 +46,16 @@ function openSocket(url, sessionId) {
|
|
|
46
46
|
ws.on('error', initOnError);
|
|
47
47
|
ws.on('unexpected-response', onNonOkReply);
|
|
48
48
|
ws.once('open', () => {
|
|
49
|
-
|
|
49
|
+
opening === null || opening === void 0 ? void 0 : opening.resolve({
|
|
50
50
|
url,
|
|
51
51
|
method: 'GET',
|
|
52
52
|
status: 200,
|
|
53
53
|
data: ws
|
|
54
|
-
};
|
|
55
|
-
opening === null || opening === void 0 ? void 0 : opening.resolve(okReply);
|
|
54
|
+
});
|
|
56
55
|
opening = undefined;
|
|
57
56
|
ws.removeListener('error', initOnError);
|
|
58
57
|
ws.removeListener('unexpected-response', onNonOkReply);
|
|
59
58
|
});
|
|
60
|
-
ws.on('error', err => {
|
|
61
|
-
// XXX we need
|
|
62
|
-
console.error(`Error in ${ws.url} connection`, err);
|
|
63
|
-
});
|
|
64
59
|
return opening.promise;
|
|
65
60
|
}
|
|
66
61
|
Object.freeze(exports);
|
|
@@ -2,6 +2,7 @@ import type { ScryptGenParams } from '../key-derivation';
|
|
|
2
2
|
import type { AsyncSBoxCryptor, Subscribe, ObjSource } from 'xsp-files';
|
|
3
3
|
import type { Observable } from 'rxjs';
|
|
4
4
|
import type { LogError } from '../logging/log-to-file';
|
|
5
|
+
import { StorageConnectionStatus } from '../../core/storage/synced/remote-events';
|
|
5
6
|
export type { AsyncSBoxCryptor } from 'xsp-files';
|
|
6
7
|
export type { FolderInJSON } from './folder-node';
|
|
7
8
|
type StorageType = web3n.files.FSType;
|
|
@@ -119,6 +120,7 @@ export interface SyncedStorage extends Storage {
|
|
|
119
120
|
getNumOfBytesNeedingDownload(objId: ObjId, version: number): Promise<number | 'unknown'>;
|
|
120
121
|
suspendNetworkActivity(): void;
|
|
121
122
|
resumeNetworkActivity(): void;
|
|
123
|
+
connectionEvent$: Observable<StorageConnectionStatus>;
|
|
122
124
|
}
|
|
123
125
|
export interface SyncedObjStatus extends LocalObjStatus {
|
|
124
126
|
syncStatus(): SyncStatus;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2017, 2019 - 2020, 2022, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2017, 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
|
|
@@ -126,6 +126,7 @@ function wrapSyncStorageImplementation(impl) {
|
|
|
126
126
|
wrap.suspendNetworkActivity = impl.suspendNetworkActivity.bind(impl);
|
|
127
127
|
wrap.resumeNetworkActivity = impl.resumeNetworkActivity.bind(impl);
|
|
128
128
|
wrap.getNumOfBytesNeedingDownload = impl.getNumOfBytesNeedingDownload.bind(impl);
|
|
129
|
+
wrap.connectionEvent$ = impl.connectionEvent$;
|
|
129
130
|
return Object.freeze(wrap);
|
|
130
131
|
}
|
|
131
132
|
function isSyncedStorage(storage) {
|
|
@@ -1096,13 +1096,11 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1096
1096
|
const nodes = state.nodes;
|
|
1097
1097
|
const remoteNodes = remote.folderInfo.nodes;
|
|
1098
1098
|
const events = [];
|
|
1099
|
-
if (removed) {
|
|
1100
|
-
for (const
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
events.push(this.makeEntryRemovalEvent(newVersion, 'sync', node));
|
|
1105
|
-
}
|
|
1099
|
+
if (removed === null || removed === void 0 ? void 0 : removed.inRemote) {
|
|
1100
|
+
for (const name of removed.inRemote) {
|
|
1101
|
+
const node = nodes[name];
|
|
1102
|
+
delete nodes[name];
|
|
1103
|
+
events.push(this.makeEntryRemovalEvent(newVersion, 'sync', node));
|
|
1106
1104
|
}
|
|
1107
1105
|
}
|
|
1108
1106
|
if (renamed) {
|
|
@@ -1122,19 +1120,17 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1122
1120
|
}
|
|
1123
1121
|
}
|
|
1124
1122
|
}
|
|
1125
|
-
if (added) {
|
|
1126
|
-
for (const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
node.name = `${node.name}${opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps}`;
|
|
1133
|
-
}
|
|
1123
|
+
if (added === null || added === void 0 ? void 0 : added.inRemote) {
|
|
1124
|
+
for (const name of added.inRemote) {
|
|
1125
|
+
const node = remoteNodes[name];
|
|
1126
|
+
(0, assert_1.assert)(!!node);
|
|
1127
|
+
if (nameOverlaps === null || nameOverlaps === void 0 ? void 0 : nameOverlaps.includes(name)) {
|
|
1128
|
+
while (nodes[node.name]) {
|
|
1129
|
+
node.name = `${node.name}${opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps}`;
|
|
1134
1130
|
}
|
|
1135
|
-
nodes[node.name] = node;
|
|
1136
|
-
events.push(this.makeEntryAdditionEvent(newVersion, 'sync', node));
|
|
1137
1131
|
}
|
|
1132
|
+
nodes[node.name] = node;
|
|
1133
|
+
events.push(this.makeEntryAdditionEvent(newVersion, 'sync', node));
|
|
1138
1134
|
}
|
|
1139
1135
|
}
|
|
1140
1136
|
return events;
|
|
@@ -1188,9 +1184,9 @@ function addToTransitionState(state, f, key) {
|
|
|
1188
1184
|
function diffNodes(current, remote, synced) {
|
|
1189
1185
|
const currentNodesById = orderByIds(current.nodes);
|
|
1190
1186
|
const syncedNodesById = orderByIds(synced.nodes);
|
|
1191
|
-
const removed = [];
|
|
1187
|
+
const removed = { inLocal: [], inRemote: [] };
|
|
1192
1188
|
const renamed = [];
|
|
1193
|
-
const added = [];
|
|
1189
|
+
const added = { inLocal: [], inRemote: [] };
|
|
1194
1190
|
const rekeyed = [];
|
|
1195
1191
|
const nameOverlaps = [];
|
|
1196
1192
|
for (const remoteNode of Object.values(remote.nodes)) {
|
|
@@ -1229,10 +1225,10 @@ function diffNodes(current, remote, synced) {
|
|
|
1229
1225
|
else {
|
|
1230
1226
|
const syncedNode = syncedNodesById.get(remoteNode.objId);
|
|
1231
1227
|
if (syncedNode) {
|
|
1232
|
-
removed.push(
|
|
1228
|
+
removed.inLocal.push(remoteNode.name);
|
|
1233
1229
|
}
|
|
1234
1230
|
else {
|
|
1235
|
-
added.push(
|
|
1231
|
+
added.inRemote.push(remoteNode.name);
|
|
1236
1232
|
}
|
|
1237
1233
|
if (current.nodes[remoteNode.name]) {
|
|
1238
1234
|
nameOverlaps.push(remoteNode.name);
|
|
@@ -1242,13 +1238,13 @@ function diffNodes(current, remote, synced) {
|
|
|
1242
1238
|
for (const localNode of currentNodesById.values()) {
|
|
1243
1239
|
const syncedNode = syncedNodesById.get(localNode.objId);
|
|
1244
1240
|
if (!syncedNode) {
|
|
1245
|
-
added.push(
|
|
1241
|
+
added.inLocal.push(localNode.name);
|
|
1246
1242
|
}
|
|
1247
1243
|
}
|
|
1248
1244
|
return {
|
|
1249
|
-
removed: (
|
|
1245
|
+
removed: reduceEmptyIn(removed),
|
|
1250
1246
|
renamed: ((renamed.length > 0) ? renamed : undefined),
|
|
1251
|
-
added: (
|
|
1247
|
+
added: reduceEmptyIn(added),
|
|
1252
1248
|
rekeyed: ((rekeyed.length > 0) ? rekeyed : undefined),
|
|
1253
1249
|
nameOverlaps: ((nameOverlaps.length > 0) ? nameOverlaps : undefined),
|
|
1254
1250
|
};
|
|
@@ -1291,4 +1287,22 @@ function identifyChanges(originalNodes, newNodes) {
|
|
|
1291
1287
|
}
|
|
1292
1288
|
return { addedNodes, removedNodes, renamedNodes };
|
|
1293
1289
|
}
|
|
1290
|
+
function reduceEmptyIn(c) {
|
|
1291
|
+
if (c.inLocal.length > 0) {
|
|
1292
|
+
if (c.inRemote.length > 0) {
|
|
1293
|
+
return c;
|
|
1294
|
+
}
|
|
1295
|
+
else {
|
|
1296
|
+
return { inLocal: c.inLocal };
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
if (c.inRemote.length > 0) {
|
|
1301
|
+
return { inRemote: c.inRemote };
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1294
1308
|
Object.freeze(exports);
|
|
@@ -859,24 +859,9 @@ class S {
|
|
|
859
859
|
throw (0, file_1.makeFileException)('notDirectory', `${path}/${remoteItemName}`);
|
|
860
860
|
}
|
|
861
861
|
}
|
|
862
|
-
// async adoptAllRemoteItems(
|
|
863
|
-
// path: string, opts?: OptionsToAdoptAllRemoteItems
|
|
864
|
-
// ): Promise<number|undefined> {
|
|
865
|
-
// const folderNode = await this.getFolderNode(path);
|
|
866
|
-
// return await folderNode.adoptItemsFromRemoteVersion(opts);
|
|
867
|
-
// }
|
|
868
862
|
async mergeFolderCurrentAndRemoteVersions(path, opts) {
|
|
869
863
|
const folderNode = await this.getFolderNode(path);
|
|
870
|
-
|
|
871
|
-
if (newLocalVersion && (newLocalVersion < 0)) {
|
|
872
|
-
const { folderPath } = split(path);
|
|
873
|
-
if (folderPath.length > 0) {
|
|
874
|
-
const parent = await this.n.get(folderPath.join('/'));
|
|
875
|
-
// XXX removing folder in parent -- what happens with children?
|
|
876
|
-
await parent.removeChild(folderNode);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
return newLocalVersion;
|
|
864
|
+
return await folderNode.mergeCurrentAndRemoteVersions(opts);
|
|
880
865
|
}
|
|
881
866
|
}
|
|
882
867
|
Object.freeze(S.prototype);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2016 - 2017, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2016 - 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
|
|
@@ -504,6 +504,7 @@ class EventsReceivingSide extends RequestingSide {
|
|
|
504
504
|
* @param err
|
|
505
505
|
*/
|
|
506
506
|
completeEvent(ipcChannel, err) {
|
|
507
|
+
var _a, _b, _c, _d;
|
|
507
508
|
const listeners = this.listeners.get(ipcChannel);
|
|
508
509
|
if (!listeners) {
|
|
509
510
|
return;
|
|
@@ -512,14 +513,10 @@ class EventsReceivingSide extends RequestingSide {
|
|
|
512
513
|
for (const listener of listeners) {
|
|
513
514
|
try {
|
|
514
515
|
if (err === undefined) {
|
|
515
|
-
|
|
516
|
-
listener.observer.complete();
|
|
517
|
-
}
|
|
516
|
+
(_b = (_a = listener.observer).complete) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
518
517
|
}
|
|
519
518
|
else {
|
|
520
|
-
|
|
521
|
-
listener.observer.error(err);
|
|
522
|
-
}
|
|
519
|
+
(_d = (_c = listener.observer).error) === null || _d === void 0 ? void 0 : _d.call(_c, err);
|
|
523
520
|
}
|
|
524
521
|
}
|
|
525
522
|
catch (err2) {
|
|
@@ -528,7 +525,24 @@ class EventsReceivingSide extends RequestingSide {
|
|
|
528
525
|
}
|
|
529
526
|
}
|
|
530
527
|
handleCompletion(err) {
|
|
528
|
+
var _a, _b, _c, _d, _e;
|
|
531
529
|
super.handleCompletion(err);
|
|
530
|
+
for (const ipcChannel of this.listeners.keys()) {
|
|
531
|
+
const listeners = (_a = this.listeners.get(ipcChannel)) !== null && _a !== void 0 ? _a : [];
|
|
532
|
+
for (const listener of listeners) {
|
|
533
|
+
try {
|
|
534
|
+
if (err === undefined) {
|
|
535
|
+
(_c = (_b = listener.observer).complete) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
(_e = (_d = listener.observer).error) === null || _e === void 0 ? void 0 : _e.call(_d, err);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
catch (err2) {
|
|
542
|
+
console.error(err2);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
532
546
|
this.listeners.clear();
|
|
533
547
|
}
|
|
534
548
|
subscribe(channel, observer) {
|
|
@@ -635,37 +649,31 @@ class MultiObserverWrap {
|
|
|
635
649
|
return () => { this.obs.delete(obs); };
|
|
636
650
|
}
|
|
637
651
|
next(o) {
|
|
652
|
+
var _a;
|
|
638
653
|
if (this.isDone) {
|
|
639
654
|
return;
|
|
640
655
|
}
|
|
641
656
|
for (const obs of this.obs) {
|
|
642
|
-
|
|
643
|
-
continue;
|
|
644
|
-
}
|
|
645
|
-
obs.next(o);
|
|
657
|
+
(_a = obs.next) === null || _a === void 0 ? void 0 : _a.call(obs, o);
|
|
646
658
|
}
|
|
647
659
|
}
|
|
648
660
|
error(err) {
|
|
661
|
+
var _a;
|
|
649
662
|
if (this.isDone) {
|
|
650
663
|
return;
|
|
651
664
|
}
|
|
652
665
|
for (const obs of this.obs) {
|
|
653
|
-
|
|
654
|
-
continue;
|
|
655
|
-
}
|
|
656
|
-
obs.error(err);
|
|
666
|
+
(_a = obs.error) === null || _a === void 0 ? void 0 : _a.call(obs, err);
|
|
657
667
|
}
|
|
658
668
|
this.setDone();
|
|
659
669
|
}
|
|
660
670
|
complete() {
|
|
671
|
+
var _a;
|
|
661
672
|
if (this.isDone) {
|
|
662
673
|
return;
|
|
663
674
|
}
|
|
664
675
|
for (const obs of this.obs) {
|
|
665
|
-
|
|
666
|
-
continue;
|
|
667
|
-
}
|
|
668
|
-
obs.complete();
|
|
676
|
+
(_a = obs.complete) === null || _a === void 0 ? void 0 : _a.call(obs);
|
|
669
677
|
}
|
|
670
678
|
this.setDone();
|
|
671
679
|
}
|
|
@@ -697,29 +705,26 @@ class SingleObserverWrap {
|
|
|
697
705
|
this.obs = obs;
|
|
698
706
|
}
|
|
699
707
|
next(o) {
|
|
708
|
+
var _a, _b;
|
|
700
709
|
if (this.isDone || !this.obs) {
|
|
701
710
|
return;
|
|
702
711
|
}
|
|
703
|
-
|
|
704
|
-
this.obs.next(o);
|
|
705
|
-
}
|
|
712
|
+
(_b = (_a = this.obs) === null || _a === void 0 ? void 0 : _a.next) === null || _b === void 0 ? void 0 : _b.call(_a, o);
|
|
706
713
|
}
|
|
707
714
|
error(err) {
|
|
715
|
+
var _a, _b;
|
|
708
716
|
if (this.isDone) {
|
|
709
717
|
return;
|
|
710
718
|
}
|
|
711
|
-
|
|
712
|
-
this.obs.error(err);
|
|
713
|
-
}
|
|
719
|
+
(_b = (_a = this.obs) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.call(_a, err);
|
|
714
720
|
this.setDone();
|
|
715
721
|
}
|
|
716
722
|
complete() {
|
|
723
|
+
var _a, _b;
|
|
717
724
|
if (this.isDone) {
|
|
718
725
|
return;
|
|
719
726
|
}
|
|
720
|
-
|
|
721
|
-
this.obs.complete();
|
|
722
|
-
}
|
|
727
|
+
(_b = (_a = this.obs) === null || _a === void 0 ? void 0 : _a.complete) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
723
728
|
this.setDone();
|
|
724
729
|
}
|
|
725
730
|
setDone() {
|
|
@@ -10,6 +10,7 @@ export interface WSException extends web3n.RuntimeException {
|
|
|
10
10
|
}
|
|
11
11
|
export declare function makeWSException(params: Partial<WSException>, flags?: Partial<WSException>): WSException;
|
|
12
12
|
export interface ConnectionStatus {
|
|
13
|
+
type: 'heartbeat' | 'heartbeat-skip' | 'disconnected' | 'connected';
|
|
13
14
|
url: string;
|
|
14
15
|
/**
|
|
15
16
|
* ping number is a number of millisecond between previous and current data receiving from server.
|
|
@@ -19,6 +20,7 @@ export interface ConnectionStatus {
|
|
|
19
20
|
* This mirrors a "slow socket" exception, thrown to data sending process.
|
|
20
21
|
*/
|
|
21
22
|
slowSocket?: true;
|
|
23
|
+
missingPongsFromServer?: number;
|
|
22
24
|
socketClosed?: true;
|
|
23
25
|
error?: any;
|
|
24
26
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2017, 2025 3NSoft Inc.
|
|
3
|
+
Copyright (C) 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
|
|
@@ -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.WebSocketListening = exports.makeEventfulServer = void 0;
|
|
19
20
|
exports.makeWSException = makeWSException;
|
|
@@ -30,6 +31,7 @@ function makeWSException(params, flags) {
|
|
|
30
31
|
return (0, runtime_1.makeRuntimeException)('websocket', params, flags !== null && flags !== void 0 ? flags : {});
|
|
31
32
|
}
|
|
32
33
|
const MAX_TXT_BUFFER = 64 * 1024;
|
|
34
|
+
const CLIENT_SIDE_PING_PERIOD = 10 * 1000;
|
|
33
35
|
/**
|
|
34
36
|
* This creates a json communication point on a given web socket.
|
|
35
37
|
* Point may have many listeners, allowing for single parsing of incoming
|
|
@@ -39,6 +41,21 @@ const MAX_TXT_BUFFER = 64 * 1024;
|
|
|
39
41
|
function makeJsonCommPoint(ws) {
|
|
40
42
|
const observers = new generic_ipc_1.MultiObserverWrap();
|
|
41
43
|
const { heartbeat, healthyBeat, otherBeat } = makeHeartbeat(ws.url);
|
|
44
|
+
let outstandingPongs = 0;
|
|
45
|
+
let closedByPingProc = false;
|
|
46
|
+
const pingRepeat = setInterval(() => {
|
|
47
|
+
if (outstandingPongs >= 2) {
|
|
48
|
+
ws.close();
|
|
49
|
+
closedByPingProc = true;
|
|
50
|
+
clearInterval(pingRepeat);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (outstandingPongs > 0) {
|
|
54
|
+
otherBeat('heartbeat-skip', { missingPongsFromServer: outstandingPongs });
|
|
55
|
+
}
|
|
56
|
+
ws.ping();
|
|
57
|
+
outstandingPongs += 1;
|
|
58
|
+
}, CLIENT_SIDE_PING_PERIOD);
|
|
42
59
|
ws.on('message', data => {
|
|
43
60
|
if (observers.done) {
|
|
44
61
|
return;
|
|
@@ -49,7 +66,8 @@ function makeJsonCommPoint(ws) {
|
|
|
49
66
|
}
|
|
50
67
|
catch (err) {
|
|
51
68
|
ws.close();
|
|
52
|
-
|
|
69
|
+
clearInterval(pingRepeat);
|
|
70
|
+
otherBeat('disconnected', err, true);
|
|
53
71
|
observers.error(err);
|
|
54
72
|
return;
|
|
55
73
|
}
|
|
@@ -57,12 +75,13 @@ function makeJsonCommPoint(ws) {
|
|
|
57
75
|
healthyBeat();
|
|
58
76
|
});
|
|
59
77
|
ws.on('close', (code, reason) => {
|
|
78
|
+
clearInterval(pingRepeat);
|
|
60
79
|
if (code === 1000) {
|
|
61
|
-
otherBeat({ socketClosed: true }, true);
|
|
80
|
+
otherBeat('disconnected', { socketClosed: true }, true);
|
|
62
81
|
observers.complete();
|
|
63
82
|
}
|
|
64
83
|
else {
|
|
65
|
-
otherBeat({ error: { code, reason } }, true);
|
|
84
|
+
otherBeat('disconnected', { error: { code, reason } }, true);
|
|
66
85
|
observers.error(makeWSException({
|
|
67
86
|
socketClosed: true,
|
|
68
87
|
cause: { code, reason }
|
|
@@ -70,24 +89,30 @@ function makeJsonCommPoint(ws) {
|
|
|
70
89
|
}
|
|
71
90
|
});
|
|
72
91
|
ws.on('error', (err) => {
|
|
73
|
-
otherBeat(err, true);
|
|
92
|
+
otherBeat('disconnected', err, true);
|
|
74
93
|
observers.error(makeWSException({ cause: err }));
|
|
94
|
+
clearInterval(pingRepeat);
|
|
75
95
|
ws.close();
|
|
76
96
|
});
|
|
77
97
|
ws.on('ping', () => {
|
|
78
98
|
ws.pong();
|
|
79
99
|
healthyBeat();
|
|
80
100
|
});
|
|
101
|
+
ws.on('pong', () => {
|
|
102
|
+
healthyBeat();
|
|
103
|
+
outstandingPongs = 0;
|
|
104
|
+
});
|
|
81
105
|
const comm = {
|
|
82
106
|
subscribe: obs => observers.add(obs),
|
|
83
107
|
postMessage(env) {
|
|
84
108
|
if (ws.bufferedAmount > MAX_TXT_BUFFER) {
|
|
85
|
-
otherBeat({ slowSocket: true });
|
|
109
|
+
otherBeat('heartbeat', { slowSocket: true });
|
|
86
110
|
throw makeWSException({ socketSlow: true });
|
|
87
111
|
}
|
|
88
112
|
ws.send(JSON.stringify(env));
|
|
89
113
|
}
|
|
90
114
|
};
|
|
115
|
+
otherBeat('connected', {});
|
|
91
116
|
return { comm, heartbeat };
|
|
92
117
|
}
|
|
93
118
|
function makeHeartbeat(url) {
|
|
@@ -96,13 +121,15 @@ function makeHeartbeat(url) {
|
|
|
96
121
|
function healthyBeat() {
|
|
97
122
|
const now = Date.now();
|
|
98
123
|
status.next({
|
|
124
|
+
type: 'heartbeat',
|
|
99
125
|
url,
|
|
100
126
|
ping: now - lastInfo
|
|
101
127
|
});
|
|
102
128
|
lastInfo = now;
|
|
103
129
|
}
|
|
104
|
-
function otherBeat(params, end = false) {
|
|
130
|
+
function otherBeat(type, params, end = false) {
|
|
105
131
|
status.next({
|
|
132
|
+
type,
|
|
106
133
|
url,
|
|
107
134
|
...params
|
|
108
135
|
});
|