iosignal 3.3.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/README.md +38 -559
- package/dist/io.d.ts +16 -9
- package/dist/io.js +5 -5
- package/dist/io.js.map +1 -1
- package/dist/io.min.js +5 -5
- package/dist/io.min.js.map +1 -1
- package/dist/iosignal.js +339 -268
- package/dist/types/client/IOCore.d.ts +17 -10
- package/dist/types/common/constants.d.ts +27 -37
- package/index.js +4 -3
- package/package.json +3 -4
- package/src/auth/BohoAuth.js +48 -11
- package/src/auth/{Auth_File.js → key_providers/FileKeyProvider.js} +8 -20
- package/src/auth/{Auth_Redis.js → key_providers/RedisKeyProvider.js} +4 -7
- package/src/auth/key_providers/StringKeyProvider.js +54 -0
- package/src/client/IOCongSocket.js +5 -3
- package/src/client/IOCore.js +118 -89
- package/src/client/IOWS.js +5 -3
- package/src/client/browser/IOWebSocket.js +5 -3
- package/src/common/constants.js +31 -44
- package/src/common/util.js +3 -0
- package/src/server/Manager.js +13 -12
- package/src/server/Remote.js +4 -1
- package/src/server/RemoteCore.js +23 -17
- package/src/server/Server.js +7 -7
- package/README.ko.md +0 -566
- package/auth_file.js +0 -23
- package/auth_file.json +0 -13
- package/docs/iosignal_architecture.png +0 -0
- package/examples/react-chat-js/dist/assets/index-Cy4qaVcJ.js +0 -56
- package/examples/react-chat-js/dist/assets/index-NETrjYhz.css +0 -1
- package/examples/react-chat-js/dist/assets/index-e2KOTYW8.js +0 -65
- package/examples/react-chat-js/dist/index.html +0 -14
- package/examples/react-chat-js/index.html +0 -13
- package/examples/react-chat-js/package-lock.json +0 -1723
- package/examples/react-chat-js/package.json +0 -20
- package/examples/react-chat-js/src/App.css +0 -61
- package/examples/react-chat-js/src/App.jsx +0 -125
- package/examples/react-chat-js/src/index.css +0 -13
- package/examples/react-chat-js/src/main.jsx +0 -13
- package/examples/react-chat-js/src/shared_io.js +0 -12
- package/examples/react-chat-js/vite.config.js +0 -7
- package/examples/server/index.js +0 -65
- package/examples/server/package-lock.json +0 -878
- package/examples/server/package.json +0 -13
- package/examples/server/public/index.html +0 -26
- package/examples/svelte-chat-js/.devtools +0 -3
- package/examples/svelte-chat-js/README.md +0 -38
- package/examples/svelte-chat-js/package-lock.json +0 -1421
- package/examples/svelte-chat-js/package.json +0 -23
- package/examples/svelte-chat-js/src/app.css +0 -105
- package/examples/svelte-chat-js/src/app.d.ts +0 -13
- package/examples/svelte-chat-js/src/app.html +0 -13
- package/examples/svelte-chat-js/src/lib/images/github.svg +0 -1
- package/examples/svelte-chat-js/src/lib/images/svelte-logo.svg +0 -1
- package/examples/svelte-chat-js/src/lib/images/svelte-welcome.png +0 -0
- package/examples/svelte-chat-js/src/lib/images/svelte-welcome.webp +0 -0
- package/examples/svelte-chat-js/src/lib/shared_io.js +0 -12
- package/examples/svelte-chat-js/src/routes/+layout.svelte +0 -5
- package/examples/svelte-chat-js/src/routes/+page.js +0 -3
- package/examples/svelte-chat-js/src/routes/+page.svelte +0 -167
- package/examples/svelte-chat-js/static/favicon.svg +0 -1
- package/examples/svelte-chat-js/static/global.css +0 -19
- package/examples/svelte-chat-js/static/robots.txt +0 -3
- package/examples/svelte-chat-js/svelte.config.js +0 -23
- package/examples/svelte-chat-js/vite.config.js +0 -6
- package/src/auth/Auth_Env.js +0 -76
- package/test-browser/favicon.ico +0 -0
- package/test-browser/index.html +0 -95
- package/test-browser/server.js +0 -12
- package/test-nodejs/client-playToggle.js +0 -19
- package/test-nodejs/client.js +0 -17
- package/test-nodejs/client_api_reply.js +0 -15
- package/test-nodejs/server-Auth_Env.js +0 -19
- package/test-nodejs/server-Auth_File.js +0 -12
- package/test-nodejs/server-api_reply.js +0 -6
- package/test-nodejs/server-api_sudo.js +0 -7
- package/test-nodejs/server.js +0 -20
- package/test-nodejs/signalPack.js +0 -34
- package/test-nodejs/signaling.js +0 -61
- package/test-nodejs/simple-server.js +0 -13
package/dist/iosignal.js
CHANGED
|
@@ -9,11 +9,11 @@ import require$$7 from 'url';
|
|
|
9
9
|
import require$$0 from 'zlib';
|
|
10
10
|
import fs, { readFileSync } from 'fs';
|
|
11
11
|
import path from 'path';
|
|
12
|
-
import require$$2 from 'os';
|
|
12
|
+
import require$$2, { networkInterfaces } from 'os';
|
|
13
13
|
import require$$0$1 from 'buffer';
|
|
14
14
|
import { memoryUsage } from 'process';
|
|
15
15
|
|
|
16
|
-
var version$1 = "
|
|
16
|
+
var version$1 = "4.5.0";
|
|
17
17
|
var pkg = {
|
|
18
18
|
version: version$1};
|
|
19
19
|
|
|
@@ -381,53 +381,41 @@ var eventemitter3Exports = requireEventemitter3();
|
|
|
381
381
|
var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
|
|
382
382
|
|
|
383
383
|
/**
|
|
384
|
-
* @typedef {object}
|
|
385
|
-
* @property {number}
|
|
384
|
+
* @typedef {object} STATE
|
|
385
|
+
* @property {number} CONNECTING
|
|
386
386
|
* @property {number} OPEN
|
|
387
|
-
* @property {number} CLOSING
|
|
388
|
-
* @property {number} CLOSED
|
|
389
387
|
* @property {number} SERVER_READY
|
|
390
|
-
* @property {number}
|
|
391
|
-
* @property {number}
|
|
388
|
+
* @property {number} AUTH_ACK
|
|
389
|
+
* @property {number} CLOSING
|
|
392
390
|
* @property {number} READY
|
|
391
|
+
* @property {number} AUTH_FAIL
|
|
392
|
+
* @property {number} AUTH_CLEAR
|
|
393
|
+
* @property {number} CLOSING
|
|
394
|
+
* @property {number} CLOSED
|
|
395
|
+
* @property {number} STOP
|
|
393
396
|
* @property {number} REDIRECTING
|
|
394
397
|
*/
|
|
395
|
-
// Client
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
OPEN:
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
398
|
+
// Client STATE: name and number
|
|
399
|
+
const STATE = {
|
|
400
|
+
CONNECTING: 0,
|
|
401
|
+
OPEN: 1,
|
|
402
|
+
SERVER_READY: 10,
|
|
403
|
+
AUTH_REQ: 11,
|
|
404
|
+
AUTH_NONCE: 12,
|
|
405
|
+
AUTH_HMAC: 13,
|
|
406
|
+
AUTH_ACK: 14,
|
|
407
|
+
AUTH_FAIL: 15,
|
|
408
|
+
AUTH_CLEAR: 16,
|
|
409
|
+
CID_REQ: 17,
|
|
410
|
+
CID_RES: 18,
|
|
411
|
+
READY: 19,
|
|
412
|
+
CLOSING: 2,
|
|
413
|
+
CLOSED: 3,
|
|
414
|
+
STOP: 4,
|
|
415
|
+
REDIRECTING: 5
|
|
406
416
|
};
|
|
407
|
-
for (let c in
|
|
417
|
+
for (let c in STATE) { STATE[STATE[c]] = c; }
|
|
408
418
|
|
|
409
|
-
/**
|
|
410
|
-
* @typedef {object} CLIENT_STATE
|
|
411
|
-
* @property {number} INIT
|
|
412
|
-
* @property {number} SENT_SERVER_READY
|
|
413
|
-
* @property {number} RECV_AUTH_REQ
|
|
414
|
-
* @property {number} SENT_SERVER_NONCE
|
|
415
|
-
* @property {number} RECV_AUTH_HMAC
|
|
416
|
-
* @property {number} AUTH_FAIL
|
|
417
|
-
* @property {number} AUTH_READY
|
|
418
|
-
* @property {number} CID_READY
|
|
419
|
-
*/
|
|
420
|
-
const CLIENT_STATE = {
|
|
421
|
-
INIT: 0,
|
|
422
|
-
SENT_SERVER_READY: 1,
|
|
423
|
-
RECV_AUTH_REQ: 2,
|
|
424
|
-
SENT_SERVER_NONCE: 3,
|
|
425
|
-
RECV_AUTH_HMAC: 4,
|
|
426
|
-
AUTH_FAIL: 5,
|
|
427
|
-
AUTH_READY: 6,
|
|
428
|
-
CID_READY: 7
|
|
429
|
-
};
|
|
430
|
-
for (let c in CLIENT_STATE) { CLIENT_STATE[CLIENT_STATE[c]] = c; }
|
|
431
419
|
|
|
432
420
|
/**
|
|
433
421
|
* @typedef {object} ENC_MODE
|
|
@@ -456,7 +444,7 @@ for (let c in ENC_MODE) { ENC_MODE[ENC_MODE[c]] = c; }
|
|
|
456
444
|
const SIZE_LIMIT = {
|
|
457
445
|
TAG_LEN1: 255,
|
|
458
446
|
TAG_LEN2: 65535,
|
|
459
|
-
CONNECTION_CHECKER_PERIOD:
|
|
447
|
+
CONNECTION_CHECKER_PERIOD: 30000,
|
|
460
448
|
PROMISE_TIMEOUT: 5000,
|
|
461
449
|
DID: 8,
|
|
462
450
|
CID: 12
|
|
@@ -488,7 +476,7 @@ for (let c in PAYLOAD_TYPE) { PAYLOAD_TYPE[PAYLOAD_TYPE[c]] = c; }
|
|
|
488
476
|
* @property {number} CID_REQ
|
|
489
477
|
* @property {number} CID_RES
|
|
490
478
|
* @property {number} QUOTA_LEVEL
|
|
491
|
-
* @property {number}
|
|
479
|
+
* @property {number} AUTH_CLEAR
|
|
492
480
|
* @property {number} SERVER_REDIRECT
|
|
493
481
|
* @property {number} LOOP
|
|
494
482
|
* @property {number} ECHO
|
|
@@ -546,9 +534,8 @@ let IOMsg = {
|
|
|
546
534
|
CID_REQ: 0xC1,
|
|
547
535
|
CID_RES: 0xC2,
|
|
548
536
|
QUOTA_LEVEL: 0xC3,
|
|
549
|
-
|
|
537
|
+
AUTH_CLEAR: 0xC4,
|
|
550
538
|
SERVER_REDIRECT: 0xC5,
|
|
551
|
-
|
|
552
539
|
// ..
|
|
553
540
|
LOOP: 0xCB,
|
|
554
541
|
ECHO: 0xCC,
|
|
@@ -789,7 +776,7 @@ const t=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1
|
|
|
789
776
|
* @typedef {import('../common/constants.js').PAYLOAD_TYPE} PAYLOAD_TYPE
|
|
790
777
|
* @typedef {import('../common/constants.js').SIZE_LIMIT} SIZE_LIMIT
|
|
791
778
|
* @typedef {import('../common/constants.js').ENC_MODE} ENC_MODE
|
|
792
|
-
* @typedef {import('../common/constants.js').
|
|
779
|
+
* @typedef {import('../common/constants.js').STATE} STATE
|
|
793
780
|
* @typedef {import('../common/quotaTable.js').quotaTable} quotaTable
|
|
794
781
|
|
|
795
782
|
* @typedef {import('boho').Boho} Boho
|
|
@@ -843,7 +830,7 @@ class IOCore extends EventEmitter {
|
|
|
843
830
|
* Current connection state (number).
|
|
844
831
|
* @type {number}
|
|
845
832
|
*/
|
|
846
|
-
this.state =
|
|
833
|
+
this.state = STATE.CLOSED; // Number type
|
|
847
834
|
/**
|
|
848
835
|
* Current connection state (string).
|
|
849
836
|
* @type {string}
|
|
@@ -985,7 +972,7 @@ class IOCore extends EventEmitter {
|
|
|
985
972
|
close() {
|
|
986
973
|
if (this._closed) return;
|
|
987
974
|
this._closed = true;
|
|
988
|
-
// console.log('####### IOCOre.js close() called')
|
|
975
|
+
// console.log('####### IOCOre.js close() called')
|
|
989
976
|
// If auto-reconnect is disabled, we must stop the keep-alive timer.
|
|
990
977
|
if (this.autoReconnect === false) {
|
|
991
978
|
clearInterval(this.connectionCheckerIntervalID);
|
|
@@ -1000,7 +987,7 @@ class IOCore extends EventEmitter {
|
|
|
1000
987
|
// To avoid the error, we wait for the connection to open, then immediately close it.
|
|
1001
988
|
// We also clear other handlers to prevent any other logic from running.
|
|
1002
989
|
const socket = this.socket;
|
|
1003
|
-
socket.onopen = () => { if(socket) socket.close(); };
|
|
990
|
+
socket.onopen = () => { if (socket) socket.close(); };
|
|
1004
991
|
socket.onmessage = null;
|
|
1005
992
|
socket.onerror = null;
|
|
1006
993
|
socket.onclose = null;
|
|
@@ -1008,7 +995,7 @@ class IOCore extends EventEmitter {
|
|
|
1008
995
|
try {
|
|
1009
996
|
// For other sockets (like TCP) or other WebSocket states, close directly.
|
|
1010
997
|
this.socket.close?.();
|
|
1011
|
-
} catch {}
|
|
998
|
+
} catch { }
|
|
1012
999
|
}
|
|
1013
1000
|
this.socket = null;
|
|
1014
1001
|
}
|
|
@@ -1016,14 +1003,15 @@ class IOCore extends EventEmitter {
|
|
|
1016
1003
|
this.emit('closed');
|
|
1017
1004
|
this.stateChange('closed');
|
|
1018
1005
|
}
|
|
1019
|
-
|
|
1006
|
+
|
|
1020
1007
|
/**
|
|
1021
1008
|
* Disables auto-reconnect and closes the current connection.
|
|
1022
1009
|
* The instance can be re-opened manually later. For complete cleanup, use destroy().
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1010
|
+
*/
|
|
1011
|
+
stop() {
|
|
1012
|
+
this.autoReconnect = false;
|
|
1013
|
+
this.close();
|
|
1014
|
+
this.stateChange('stop','stop');
|
|
1027
1015
|
}
|
|
1028
1016
|
|
|
1029
1017
|
/**
|
|
@@ -1039,7 +1027,7 @@ class IOCore extends EventEmitter {
|
|
|
1039
1027
|
|
|
1040
1028
|
// Help GC
|
|
1041
1029
|
this.boho = null;
|
|
1042
|
-
}
|
|
1030
|
+
}
|
|
1043
1031
|
|
|
1044
1032
|
/**
|
|
1045
1033
|
* The core keep-alive logic. It checks if auto-reconnect is enabled.
|
|
@@ -1056,8 +1044,8 @@ class IOCore extends EventEmitter {
|
|
|
1056
1044
|
* @param {string} url2 - The new URL to redirect to.
|
|
1057
1045
|
*/
|
|
1058
1046
|
redirect(url2) {
|
|
1047
|
+
this.stateChange('redirecting','redirecting');
|
|
1059
1048
|
this.close();
|
|
1060
|
-
this.stateChange('redirecting');
|
|
1061
1049
|
this.createConnection(url2);
|
|
1062
1050
|
}
|
|
1063
1051
|
|
|
@@ -1114,29 +1102,27 @@ class IOCore extends EventEmitter {
|
|
|
1114
1102
|
|
|
1115
1103
|
/**
|
|
1116
1104
|
* Manually logs in with provided ID and key.
|
|
1117
|
-
* @param {string} id - The user ID.
|
|
1105
|
+
* @param {string} id - The user ID. or 'id.key'
|
|
1118
1106
|
* @param {string} key - The user key.
|
|
1119
|
-
* @returns {
|
|
1107
|
+
* @returns {this}
|
|
1120
1108
|
*/
|
|
1121
1109
|
login(id, key) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1110
|
+
this.auth(id, key);
|
|
1124
1111
|
this.useAuth = true;
|
|
1125
1112
|
let auth_pack = this.boho.auth_req();
|
|
1126
1113
|
this.send(auth_pack);
|
|
1127
|
-
return
|
|
1114
|
+
return this
|
|
1128
1115
|
}
|
|
1129
1116
|
|
|
1130
1117
|
/**
|
|
1131
1118
|
* Sets up authentication for auto-login.
|
|
1132
|
-
* @param {string} id - The user ID.
|
|
1119
|
+
* @param {string} id - The user ID. or 'id.Key'
|
|
1133
1120
|
* @param {string} key - The user key.
|
|
1134
|
-
* @returns {
|
|
1121
|
+
* @returns {this}
|
|
1135
1122
|
*/
|
|
1136
1123
|
auth(id, key) {
|
|
1137
1124
|
if (!id && !key) {
|
|
1138
1125
|
this.emit('error', new Error('auth failed. no id and key.'));
|
|
1139
|
-
return false
|
|
1140
1126
|
}
|
|
1141
1127
|
|
|
1142
1128
|
if (!key && id.includes('.')) {
|
|
@@ -1146,10 +1132,9 @@ class IOCore extends EventEmitter {
|
|
|
1146
1132
|
this.boho.set_key(key);
|
|
1147
1133
|
} else {
|
|
1148
1134
|
this.emit('error', new Error('auth failed. no id or key.'));
|
|
1149
|
-
return false
|
|
1150
1135
|
}
|
|
1151
1136
|
this.useAuth = true;
|
|
1152
|
-
return
|
|
1137
|
+
return this
|
|
1153
1138
|
}
|
|
1154
1139
|
|
|
1155
1140
|
/**
|
|
@@ -1209,13 +1194,13 @@ class IOCore extends EventEmitter {
|
|
|
1209
1194
|
case IOMsg.ECHO:
|
|
1210
1195
|
try {
|
|
1211
1196
|
let str = decoder$4.decode(buffer.subarray(1));
|
|
1212
|
-
|
|
1197
|
+
|
|
1213
1198
|
this.emit('echo', str);
|
|
1214
1199
|
} catch (error) {
|
|
1215
1200
|
this.emit('error', new Error('ECHO data error'));
|
|
1216
1201
|
}
|
|
1217
1202
|
break;
|
|
1218
|
-
|
|
1203
|
+
|
|
1219
1204
|
case IOMsg.IAM_RES:
|
|
1220
1205
|
try {
|
|
1221
1206
|
let str = decoder$4.decode(buffer.subarray(1));
|
|
@@ -1224,8 +1209,7 @@ class IOCore extends EventEmitter {
|
|
|
1224
1209
|
if (jsonInfo.nick) { this.nick = jsonInfo.nick; }
|
|
1225
1210
|
if (jsonInfo.did) { this.did = jsonInfo.did; }
|
|
1226
1211
|
if (jsonInfo.uid) { this.uid = jsonInfo.uid; }
|
|
1227
|
-
|
|
1228
|
-
this.emit('iam_res', str );
|
|
1212
|
+
this.emit('iam_res', str);
|
|
1229
1213
|
} catch (error) {
|
|
1230
1214
|
this.emit('error', new Error('IAM_RES data error'));
|
|
1231
1215
|
}
|
|
@@ -1237,21 +1221,21 @@ class IOCore extends EventEmitter {
|
|
|
1237
1221
|
|
|
1238
1222
|
// **IMPORTANT** change state before subscribe.
|
|
1239
1223
|
this.stateChange('ready', 'cid_ready');
|
|
1240
|
-
this.subscribe_memory_channels();
|
|
1224
|
+
this.subscribe_memory_channels(); // tags registered by listen() or link().
|
|
1241
1225
|
break;
|
|
1242
1226
|
|
|
1243
1227
|
case IOMsg.QUOTA_LEVEL:
|
|
1244
1228
|
let quotaLevel = buffer[1];
|
|
1245
1229
|
this.level = quotaLevel;
|
|
1246
1230
|
this.quota = quotaTable[quotaLevel];
|
|
1247
|
-
console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota))
|
|
1231
|
+
// console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota))
|
|
1248
1232
|
break;
|
|
1249
1233
|
|
|
1250
|
-
case IOMsg.
|
|
1234
|
+
case IOMsg.AUTH_CLEAR:
|
|
1251
1235
|
this.useAuth = false;
|
|
1252
1236
|
this.boho.clearAuth();
|
|
1237
|
+
this.stateChange('auth_clear', 'server request auth_clear.');
|
|
1253
1238
|
this.stop();
|
|
1254
|
-
console.log('[SERVER_CLEAR_AUTH] io stop.');
|
|
1255
1239
|
break;
|
|
1256
1240
|
|
|
1257
1241
|
case IOMsg.SERVER_REDIRECT:
|
|
@@ -1325,8 +1309,11 @@ class IOCore extends EventEmitter {
|
|
|
1325
1309
|
switch (payloadType) {
|
|
1326
1310
|
|
|
1327
1311
|
case PAYLOAD_TYPE.EMPTY:
|
|
1328
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
1329
|
-
else
|
|
1312
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, null);
|
|
1313
|
+
else {
|
|
1314
|
+
this.emit(tag, tag, null);
|
|
1315
|
+
this.emit('message', tag, null);
|
|
1316
|
+
}
|
|
1330
1317
|
break;
|
|
1331
1318
|
|
|
1332
1319
|
case PAYLOAD_TYPE.TEXT:
|
|
@@ -1337,33 +1324,48 @@ class IOCore extends EventEmitter {
|
|
|
1337
1324
|
payloadStringWithoutNull = payloadBuffer.subarray(0, payloadBuffer.byteLength - 1);
|
|
1338
1325
|
}
|
|
1339
1326
|
let oneString = decoder$4.decode(payloadStringWithoutNull);
|
|
1340
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
1341
|
-
if (tag !== '@')
|
|
1327
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, oneString);
|
|
1328
|
+
if (tag !== '@') {
|
|
1329
|
+
this.emit(tag, tag, oneString);
|
|
1330
|
+
this.emit('message', tag, oneString);
|
|
1331
|
+
}
|
|
1342
1332
|
break;
|
|
1343
1333
|
|
|
1344
1334
|
case PAYLOAD_TYPE.BINARY:
|
|
1345
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
1346
|
-
if (tag !== '@')
|
|
1335
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, payloadBuffer);
|
|
1336
|
+
if (tag !== '@') {
|
|
1337
|
+
this.emit(tag, tag, payloadBuffer);
|
|
1338
|
+
this.emit('message', tag, payloadBuffer);
|
|
1339
|
+
}
|
|
1347
1340
|
break;
|
|
1348
1341
|
|
|
1349
1342
|
case PAYLOAD_TYPE.OBJECT:
|
|
1350
1343
|
let oneObjectBuffer = decoder$4.decode(payloadBuffer);
|
|
1351
1344
|
let oneJSONObject = JSON.parse(oneObjectBuffer);
|
|
1352
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
1353
|
-
if (tag !== '@')
|
|
1345
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, oneJSONObject);
|
|
1346
|
+
if (tag !== '@') {
|
|
1347
|
+
this.emit(tag, tag, oneJSONObject);
|
|
1348
|
+
this.emit('message', tag, oneJSONObject);
|
|
1349
|
+
}
|
|
1354
1350
|
break;
|
|
1355
1351
|
|
|
1356
1352
|
case PAYLOAD_TYPE.MJSON:
|
|
1357
1353
|
let mjsonBuffer = decoder$4.decode(payloadBuffer);
|
|
1358
1354
|
let mjson = JSON.parse(mjsonBuffer);
|
|
1359
|
-
if (tag.indexOf('@') === 0) this.emit('@', ...mjson
|
|
1360
|
-
if (tag !== '@')
|
|
1355
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, ...mjson);
|
|
1356
|
+
if (tag !== '@') {
|
|
1357
|
+
this.emit(tag, tag, ...mjson);
|
|
1358
|
+
this.emit('message', tag, ...mjson);
|
|
1359
|
+
}
|
|
1361
1360
|
break;
|
|
1362
1361
|
|
|
1363
1362
|
case PAYLOAD_TYPE.MBA:
|
|
1364
1363
|
let mbaObject = M$1.unpack(payloadBuffer);
|
|
1365
|
-
if (tag.indexOf('@') === 0) this.emit('@', ...mbaObject.args
|
|
1366
|
-
if (tag !== '@')
|
|
1364
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, ...mbaObject.args);
|
|
1365
|
+
if (tag !== '@') {
|
|
1366
|
+
this.emit(tag, tag, ...mbaObject.args);
|
|
1367
|
+
this.emit('message', tag, ...mbaObject.args);
|
|
1368
|
+
}
|
|
1367
1369
|
break;
|
|
1368
1370
|
|
|
1369
1371
|
default:
|
|
@@ -1371,7 +1373,8 @@ class IOCore extends EventEmitter {
|
|
|
1371
1373
|
}
|
|
1372
1374
|
|
|
1373
1375
|
} catch (err) {
|
|
1374
|
-
this.emit('error', new Error('
|
|
1376
|
+
// this.emit('error', new Error('IOCore IOMsg.SIGNAL parser err', err))
|
|
1377
|
+
console.log('IOCore IOMsg.SIGNAL parser err', err);
|
|
1375
1378
|
}
|
|
1376
1379
|
break;
|
|
1377
1380
|
|
|
@@ -1380,24 +1383,25 @@ class IOCore extends EventEmitter {
|
|
|
1380
1383
|
break;
|
|
1381
1384
|
|
|
1382
1385
|
case tt.BohoMsg.AUTH_NONCE:
|
|
1386
|
+
this.stateChange('auth_nonce','server sent auth_nonce.');
|
|
1383
1387
|
let auth_hmac = this.boho.auth_hmac(buffer);
|
|
1384
1388
|
if (auth_hmac) {
|
|
1385
1389
|
this.send(auth_hmac);
|
|
1386
1390
|
} else {
|
|
1387
|
-
this.stateChange('auth_fail', '
|
|
1391
|
+
this.stateChange('auth_fail', 'boho.auth_hmac() invalid auth_nonce.');
|
|
1388
1392
|
}
|
|
1389
1393
|
break;
|
|
1390
1394
|
|
|
1391
1395
|
case tt.BohoMsg.AUTH_FAIL:
|
|
1392
|
-
this.stateChange('auth_fail', '
|
|
1396
|
+
this.stateChange('auth_fail', 'auth_fail from server.');
|
|
1393
1397
|
break;
|
|
1394
1398
|
|
|
1395
1399
|
case tt.BohoMsg.AUTH_ACK:
|
|
1396
1400
|
if (this.boho.check_auth_ack_hmac(buffer)) {
|
|
1397
|
-
this.stateChange('
|
|
1401
|
+
this.stateChange('auth_ack', 'server sent auth_ack');
|
|
1398
1402
|
this.send(Buffer$1.from([IOMsg.CID_REQ]));
|
|
1399
1403
|
} else {
|
|
1400
|
-
this.stateChange('auth_fail', 'invalid server_hmac');
|
|
1404
|
+
this.stateChange('auth_fail', 'check_auth_ack_hmac() invalid server_hmac');
|
|
1401
1405
|
}
|
|
1402
1406
|
break;
|
|
1403
1407
|
|
|
@@ -1584,14 +1588,15 @@ class IOCore extends EventEmitter {
|
|
|
1584
1588
|
|
|
1585
1589
|
|
|
1586
1590
|
/**
|
|
1587
|
-
*
|
|
1591
|
+
* alias of signal()
|
|
1592
|
+
* Sends a signal with a tag and arguments.
|
|
1593
|
+
* @param {string} tag - The signal tag.
|
|
1588
1594
|
* @param {...any} args - Arguments for the signal.
|
|
1589
1595
|
*/
|
|
1590
|
-
publish(...args) {
|
|
1591
|
-
this.signal(...args);
|
|
1596
|
+
publish(tag, ...args) {
|
|
1597
|
+
this.signal(tag, ...args);
|
|
1592
1598
|
}
|
|
1593
1599
|
|
|
1594
|
-
|
|
1595
1600
|
/**
|
|
1596
1601
|
* Sends a signal with a tag and arguments.
|
|
1597
1602
|
* @param {string} tag - The signal tag.
|
|
@@ -1600,7 +1605,6 @@ class IOCore extends EventEmitter {
|
|
|
1600
1605
|
*/
|
|
1601
1606
|
signal(tag, ...args) {
|
|
1602
1607
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1603
|
-
|
|
1604
1608
|
let signalPack = getSignalPack(tag, ...args);
|
|
1605
1609
|
this.send_enc_mode(signalPack);
|
|
1606
1610
|
}
|
|
@@ -1644,7 +1648,6 @@ class IOCore extends EventEmitter {
|
|
|
1644
1648
|
}
|
|
1645
1649
|
|
|
1646
1650
|
|
|
1647
|
-
|
|
1648
1651
|
/**
|
|
1649
1652
|
* Sets a value in the store.
|
|
1650
1653
|
* @param {string} storeName - The name of the store.
|
|
@@ -1712,21 +1715,24 @@ class IOCore extends EventEmitter {
|
|
|
1712
1715
|
*/
|
|
1713
1716
|
subscribe(tag) {
|
|
1714
1717
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1715
|
-
if (
|
|
1718
|
+
if (tag.length > SIZE_LIMIT.TAG_LEN1) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN1)
|
|
1719
|
+
if (this.state !== STATE.READY) return
|
|
1716
1720
|
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
+
// subscribe 사용시, 사용 'ready' 이벤트시 메뉴얼 등록되므로 여기에 등록하면 2중 호출된다.
|
|
1722
|
+
// 즉, channels 등록은 listen 같은 자동화 구독시만 사용.
|
|
1723
|
+
// let tagList = tag.split(',')
|
|
1724
|
+
// tagList.forEach(tag => {
|
|
1725
|
+
// this.channels.add(tag)
|
|
1726
|
+
// })
|
|
1721
1727
|
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1728
|
+
try {
|
|
1729
|
+
let tagEncoded = encoder$1.encode(tag);
|
|
1730
|
+
this.send_enc_mode(
|
|
1731
|
+
Buffer$1.concat([
|
|
1732
|
+
M$1.NB('8', IOMsg.SUBSCRIBE),
|
|
1733
|
+
M$1.NB('8', tagEncoded.byteLength),
|
|
1734
|
+
tagEncoded]));
|
|
1735
|
+
} catch (error) { }
|
|
1730
1736
|
}
|
|
1731
1737
|
|
|
1732
1738
|
/**
|
|
@@ -1737,20 +1743,22 @@ class IOCore extends EventEmitter {
|
|
|
1737
1743
|
*/
|
|
1738
1744
|
subscribe_promise(tag) {
|
|
1739
1745
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1740
|
-
if (
|
|
1746
|
+
if (tag.length > SIZE_LIMIT.TAG_LEN2) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN2)
|
|
1747
|
+
|
|
1748
|
+
if (this.state !== STATE.READY) {
|
|
1741
1749
|
return Promise.reject('subscribe_promise:: connection is not ready')
|
|
1742
1750
|
}
|
|
1743
1751
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1752
|
+
try {
|
|
1753
|
+
let tagEncoded = encoder$1.encode(tag);
|
|
1754
|
+
this.send_enc_mode(
|
|
1755
|
+
Buffer$1.concat([
|
|
1756
|
+
M$1.NB('8', IOMsg.SUBSCRIBE_REQ),
|
|
1757
|
+
M$1.NB('16', ++this.mid),
|
|
1758
|
+
M$1.NB('16', tagEncoded.byteLength),
|
|
1759
|
+
tagEncoded]));
|
|
1760
|
+
return this.setMsgPromise(this.mid)
|
|
1761
|
+
} catch (error) { }
|
|
1754
1762
|
}
|
|
1755
1763
|
|
|
1756
1764
|
/**
|
|
@@ -1812,7 +1820,7 @@ class IOCore extends EventEmitter {
|
|
|
1812
1820
|
}
|
|
1813
1821
|
this.on(tag, handler);
|
|
1814
1822
|
// do not subscribe now.
|
|
1815
|
-
// will subscribe when receive CID_RES
|
|
1823
|
+
// will subscribe when io state is 'ready'. (receive CID_RES from server)
|
|
1816
1824
|
|
|
1817
1825
|
}
|
|
1818
1826
|
|
|
@@ -1923,10 +1931,10 @@ class IOCore extends EventEmitter {
|
|
|
1923
1931
|
*/
|
|
1924
1932
|
getStateName() {
|
|
1925
1933
|
//state <number>
|
|
1926
|
-
//value of constant
|
|
1927
|
-
//type of constant
|
|
1934
|
+
//value of constant STATE.NAME < number >
|
|
1935
|
+
//type of constant STATE.NAME name < string uppercase >
|
|
1928
1936
|
//stateName,eventName <string lowercase>
|
|
1929
|
-
return (
|
|
1937
|
+
return (STATE[this.state]).toLowerCase()
|
|
1930
1938
|
}
|
|
1931
1939
|
|
|
1932
1940
|
/**
|
|
@@ -1947,15 +1955,23 @@ class IOCore extends EventEmitter {
|
|
|
1947
1955
|
* Changes the connection state and emits events.
|
|
1948
1956
|
* @param {string} state - The new state name (e.g., 'ready', 'closed').
|
|
1949
1957
|
* @param {string} [emitEventAndMessage] - Optional message to emit with the state change event.
|
|
1958
|
+
*
|
|
1959
|
+
* 주의.
|
|
1960
|
+
* 1. 상태가 변경 될 때만 'change' 이벤트 호출된다.
|
|
1961
|
+
* 2. emitEventAndMessage 옵션 값이 지정되야 해당 이벤트 이름이 호출된다.
|
|
1962
|
+
* 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
|
|
1950
1963
|
*/
|
|
1951
1964
|
stateChange(state, emitEventAndMessage) {
|
|
1952
|
-
//
|
|
1953
|
-
// eventName
|
|
1954
|
-
// .state
|
|
1965
|
+
// STATE constant name <string> upperCase
|
|
1966
|
+
// eventName and .stateName <string> lowerCase
|
|
1967
|
+
// .state <number>
|
|
1955
1968
|
// console.log('### stateChange reason:', emitEventAndMessage )
|
|
1956
1969
|
let eventName = state.toLowerCase();
|
|
1957
|
-
this.state =
|
|
1958
|
-
|
|
1970
|
+
this.state = STATE[state.toUpperCase()]; // state: number
|
|
1971
|
+
|
|
1972
|
+
if (emitEventAndMessage) {
|
|
1973
|
+
this.emit(eventName, emitEventAndMessage);
|
|
1974
|
+
}
|
|
1959
1975
|
|
|
1960
1976
|
if (this.stateName !== eventName) {
|
|
1961
1977
|
this.stateName = eventName;
|
|
@@ -2133,8 +2149,10 @@ class IOCongSocket extends IOCore {
|
|
|
2133
2149
|
keepAlive() {
|
|
2134
2150
|
if (!this.autoReconnect) return;
|
|
2135
2151
|
// Reconnect only if the socket is fully destroyed and the state is closed.
|
|
2136
|
-
if ((!this.socket || this.socket.destroyed)
|
|
2152
|
+
if ((!this.socket || this.socket.destroyed)) {
|
|
2137
2153
|
this.open();
|
|
2154
|
+
}else {
|
|
2155
|
+
this.ping();
|
|
2138
2156
|
}
|
|
2139
2157
|
}
|
|
2140
2158
|
|
|
@@ -2146,7 +2164,7 @@ class IOCongSocket extends IOCore {
|
|
|
2146
2164
|
urlObj = new URL('cong://' + url);
|
|
2147
2165
|
}
|
|
2148
2166
|
this.socket = net.createConnection(urlObj.port, urlObj.hostname);
|
|
2149
|
-
this.stateChange('
|
|
2167
|
+
this.stateChange('connecting','connecting');
|
|
2150
2168
|
|
|
2151
2169
|
this.socket.on('connect', () => {
|
|
2152
2170
|
this.congRx = new CongRx();
|
|
@@ -7560,15 +7578,17 @@ class IOWS extends IOCore {
|
|
|
7560
7578
|
keepAlive() {
|
|
7561
7579
|
if (!this.autoReconnect) return;
|
|
7562
7580
|
// Reconnect only if the socket is closed and the state reflects that.
|
|
7563
|
-
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED)
|
|
7581
|
+
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) ) {
|
|
7564
7582
|
this.open();
|
|
7583
|
+
}else {
|
|
7584
|
+
this.ping();
|
|
7565
7585
|
}
|
|
7566
7586
|
}
|
|
7567
7587
|
|
|
7568
7588
|
createConnection(url) {
|
|
7569
7589
|
// node WebSocket
|
|
7570
7590
|
this.socket = new WebSocket(url);
|
|
7571
|
-
this.stateChange('
|
|
7591
|
+
this.stateChange('connecting','connecting');
|
|
7572
7592
|
|
|
7573
7593
|
this.socket.onopen = () => {
|
|
7574
7594
|
this.socket.on('message', this.onWebSocketMessage.bind(this));
|
|
@@ -7694,7 +7714,7 @@ class RemoteCore {
|
|
|
7694
7714
|
|
|
7695
7715
|
this.state;
|
|
7696
7716
|
this.stateLog = [];
|
|
7697
|
-
this.setState(
|
|
7717
|
+
this.setState(STATE.OPEN);
|
|
7698
7718
|
|
|
7699
7719
|
}
|
|
7700
7720
|
|
|
@@ -7703,7 +7723,7 @@ class RemoteCore {
|
|
|
7703
7723
|
setState(state) {
|
|
7704
7724
|
this.state = state;
|
|
7705
7725
|
if (serverOption.debug.showAuthInfo) {
|
|
7706
|
-
|
|
7726
|
+
state = state + ":" + STATE[ state];
|
|
7707
7727
|
this.stateLog.push( state );
|
|
7708
7728
|
console.log(this.stateLog.join('>'));
|
|
7709
7729
|
}
|
|
@@ -7714,24 +7734,30 @@ class RemoteCore {
|
|
|
7714
7734
|
}
|
|
7715
7735
|
|
|
7716
7736
|
getStateName() { // <String>
|
|
7717
|
-
return (
|
|
7737
|
+
return (STATE[this.state]).toLowerCase()
|
|
7718
7738
|
}
|
|
7719
7739
|
|
|
7720
7740
|
|
|
7721
7741
|
showMessageLog(message, isBinary) {
|
|
7722
|
-
let
|
|
7742
|
+
let h = '->S ';
|
|
7743
|
+
let from = this.boho.isAuthorized ? ` did: ${this.did} cid: ${this.cid}` : ` cid: ${this.cid}`;
|
|
7744
|
+
let prnLimit = 20;
|
|
7723
7745
|
if (isBinary) {
|
|
7724
7746
|
let msgTypeName = IOMsg[message[0]];
|
|
7725
7747
|
if (!msgTypeName) msgTypeName = tt.BohoMsg[message[0]];
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7748
|
+
|
|
7749
|
+
msgTypeName = '[' + msgTypeName + ']';
|
|
7750
|
+
let size = message.byteLength;
|
|
7751
|
+
if (size < prnLimit) {
|
|
7752
|
+
console.log( h + msgTypeName + from +` [${size}]`, message);
|
|
7729
7753
|
} else {
|
|
7730
|
-
|
|
7754
|
+
let elseLen = size - prnLimit;
|
|
7755
|
+
let some = message.subarray(0,prnLimit);
|
|
7756
|
+
console.log( h + msgTypeName + from +` [${size}]` , some , ' ... else: ', elseLen);
|
|
7731
7757
|
}
|
|
7732
7758
|
|
|
7733
7759
|
} else {
|
|
7734
|
-
console.log(
|
|
7760
|
+
console.log( h + ' [TEXT] %s' + from, message);
|
|
7735
7761
|
}
|
|
7736
7762
|
}
|
|
7737
7763
|
|
|
@@ -7814,7 +7840,7 @@ class RemoteCore {
|
|
|
7814
7840
|
break;
|
|
7815
7841
|
|
|
7816
7842
|
case IOMsg.CID_REQ:
|
|
7817
|
-
if (this.state <
|
|
7843
|
+
if (this.state < STATE.SERVER_READY) {
|
|
7818
7844
|
// Protocol violation: CID_REQ was sent before receiving the SERVER_READY signal.
|
|
7819
7845
|
console.log('CID_REQ before SERVER_READY');
|
|
7820
7846
|
this.close();
|
|
@@ -7831,7 +7857,7 @@ class RemoteCore {
|
|
|
7831
7857
|
MB('#cid', this.cid)
|
|
7832
7858
|
));
|
|
7833
7859
|
|
|
7834
|
-
this.setState(
|
|
7860
|
+
this.setState(STATE.CID_RES);
|
|
7835
7861
|
break;
|
|
7836
7862
|
|
|
7837
7863
|
case IOMsg.ECHO:
|
|
@@ -7937,24 +7963,24 @@ class RemoteCore {
|
|
|
7937
7963
|
// Auth
|
|
7938
7964
|
case tt.BohoMsg.AUTH_REQ:
|
|
7939
7965
|
if (!this.manager.authManager) return
|
|
7940
|
-
if (this.state <
|
|
7966
|
+
if (this.state < STATE.SERVER_READY) {
|
|
7941
7967
|
console.log('protocol error. auth_req before server_ready');
|
|
7942
7968
|
this.close();
|
|
7943
7969
|
}
|
|
7944
|
-
this.setState(
|
|
7970
|
+
this.setState(STATE.AUTH_REQ);
|
|
7945
7971
|
let auth_nonce_pack = this.boho.auth_nonce();
|
|
7946
7972
|
// console.log('## auth_nonce_pack', auth_nonce_pack )
|
|
7947
7973
|
this.send(auth_nonce_pack);
|
|
7948
|
-
this.setState(
|
|
7974
|
+
this.setState(STATE.AUTH_NONCE);
|
|
7949
7975
|
break;
|
|
7950
7976
|
|
|
7951
7977
|
case tt.BohoMsg.AUTH_HMAC:
|
|
7952
7978
|
if (!this.manager.authManager) return
|
|
7953
|
-
if (this.state <
|
|
7979
|
+
if (this.state < STATE.AUTH_NONCE) {
|
|
7954
7980
|
console.log('protocol error. auth_hmac before server_nonce');
|
|
7955
7981
|
this.close();
|
|
7956
7982
|
}
|
|
7957
|
-
this.setState(
|
|
7983
|
+
this.setState(STATE.AUTH_HMAC);
|
|
7958
7984
|
//async
|
|
7959
7985
|
this.manager.authManager.verify_auth_hmac(message, this)
|
|
7960
7986
|
.then(authInfo => {
|
|
@@ -8104,11 +8130,42 @@ function isPrivateIP(ip) {
|
|
|
8104
8130
|
return false
|
|
8105
8131
|
}
|
|
8106
8132
|
|
|
8133
|
+
function numberWithCommas(x) {
|
|
8134
|
+
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
8135
|
+
}
|
|
8136
|
+
|
|
8107
8137
|
function getIPv4HexString(ipStr) {
|
|
8108
8138
|
let ipv4 = ipStr.split('.');
|
|
8109
8139
|
return Buffer.from(ipv4).toString('hex')
|
|
8110
8140
|
}
|
|
8111
8141
|
|
|
8142
|
+
function getLocalAddress() {
|
|
8143
|
+
const nets = networkInterfaces();
|
|
8144
|
+
// console.log(nets)
|
|
8145
|
+
const results = Object.create(null); // Or just '{}', an empty object
|
|
8146
|
+
let localAddress = '';
|
|
8147
|
+
for (const name of Object.keys(nets)) {
|
|
8148
|
+
for (const net of nets[name]) {
|
|
8149
|
+
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
|
8150
|
+
// 'IPv4' is in Node <= 17, from 18 it's a number 4 or 6
|
|
8151
|
+
const familyV4Value = typeof net.family === 'string' ? 'IPv4' : 4;
|
|
8152
|
+
if (net.family === familyV4Value && !net.internal) {
|
|
8153
|
+
if (!results[name]) {
|
|
8154
|
+
results[name] = [];
|
|
8155
|
+
}
|
|
8156
|
+
results[name].push(net.address);
|
|
8157
|
+
localAddress = net.address;
|
|
8158
|
+
}
|
|
8159
|
+
}
|
|
8160
|
+
}
|
|
8161
|
+
|
|
8162
|
+
// console.log('localAddress:', localAddress)
|
|
8163
|
+
return localAddress
|
|
8164
|
+
}
|
|
8165
|
+
|
|
8166
|
+
|
|
8167
|
+
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
8168
|
+
|
|
8112
8169
|
const decoder$2 = new TextDecoder();
|
|
8113
8170
|
|
|
8114
8171
|
class Remote extends RemoteCore {
|
|
@@ -8280,6 +8337,7 @@ class Remote extends RemoteCore {
|
|
|
8280
8337
|
}
|
|
8281
8338
|
}
|
|
8282
8339
|
|
|
8340
|
+
// node.js server side remote.
|
|
8283
8341
|
send(message, isBinary) {
|
|
8284
8342
|
this.manager.txBytes += message.byteLength;
|
|
8285
8343
|
this.socket.txCounter++;
|
|
@@ -8291,13 +8349,15 @@ class Remote extends RemoteCore {
|
|
|
8291
8349
|
this.socket.send(message);
|
|
8292
8350
|
}
|
|
8293
8351
|
} else {
|
|
8352
|
+
console.log('server(ws)Remote.send() called. not open state. current readyState:', this.socket.readyState );
|
|
8294
8353
|
this.close(true);
|
|
8295
8354
|
}
|
|
8296
|
-
|
|
8355
|
+
|
|
8297
8356
|
} else { //CongSocket
|
|
8298
8357
|
if (this.socket.readyState == 'open') {
|
|
8299
8358
|
this.socket.write(pack(message));
|
|
8300
8359
|
} else {
|
|
8360
|
+
console.log('server(cong)Remote.send() called. not open state. current readyState:', this.socket.readyState );
|
|
8301
8361
|
this.close(true);
|
|
8302
8362
|
}
|
|
8303
8363
|
}
|
|
@@ -8553,7 +8613,7 @@ class Manager {
|
|
|
8553
8613
|
let remote = new Remote(socket, req, this);
|
|
8554
8614
|
this.remotes.add(remote);
|
|
8555
8615
|
remote.send(Buffer.from([IOMsg.SERVER_READY]));
|
|
8556
|
-
remote.setState(
|
|
8616
|
+
remote.setState(STATE.SERVER_READY);
|
|
8557
8617
|
this.lastSSID = remote.ssid;
|
|
8558
8618
|
let connectionInfo = `+ IP:${remote.ip} #${remote.ssid} ${socket.socketType === 'websocket' ? "WS" : "CS"} `;
|
|
8559
8619
|
// console.log( connectionInfo)
|
|
@@ -8655,8 +8715,8 @@ class Manager {
|
|
|
8655
8715
|
serverSignalTo(tag, ...args) {
|
|
8656
8716
|
let cid = tag.split('@')[0];
|
|
8657
8717
|
let topic = tag.split('@')[1];
|
|
8658
|
-
let sigPack = getSignalPack('@' + topic, ...args);
|
|
8659
8718
|
if (cid && this.cid2remote.has(cid)) {
|
|
8719
|
+
let sigPack = getSignalPack('@' + topic, ...args);
|
|
8660
8720
|
let targetRemote = this.cid2remote.get(cid);
|
|
8661
8721
|
console.log('target', targetRemote.state, targetRemote.cid);
|
|
8662
8722
|
targetRemote.send_enc_mode(sigPack);
|
|
@@ -8668,8 +8728,8 @@ class Manager {
|
|
|
8668
8728
|
|
|
8669
8729
|
sender(tag, remote, message) {
|
|
8670
8730
|
if (serverOption.membersOnly && !remote.boho.isAuthorized) {
|
|
8671
|
-
console.log("[membersOnly]
|
|
8672
|
-
remote.send(Buffer.from([IOMsg.
|
|
8731
|
+
// console.log("### server reject client signal reason: [membersOnly]" ,tag, remote.cid )
|
|
8732
|
+
remote.send(Buffer.from([IOMsg.AUTH_CLEAR]));
|
|
8673
8733
|
remote.close();
|
|
8674
8734
|
return ['err', 'unAuthorized']
|
|
8675
8735
|
}
|
|
@@ -8753,13 +8813,18 @@ class Manager {
|
|
|
8753
8813
|
// console.log('## null remote' )
|
|
8754
8814
|
break;
|
|
8755
8815
|
}
|
|
8756
|
-
|
|
8816
|
+
// change: from v4.x allow receiveSelfMessages.
|
|
8817
|
+
// if (c !== remote) {
|
|
8757
8818
|
c.send_enc_mode(message);
|
|
8758
8819
|
sentCounter++;
|
|
8759
|
-
}
|
|
8820
|
+
// }
|
|
8760
8821
|
}
|
|
8761
8822
|
|
|
8762
|
-
if (serverOption.useQuota.publishCounter)
|
|
8823
|
+
// if (serverOption.useQuota.publishCounter) {
|
|
8824
|
+
// // console.log(`pub >> [${tag}] sent: ${sentCounter} [use quota limit: ${remote.quota.publishCounter }] total: ${remotes.size} subscribers. ` )
|
|
8825
|
+
// } else {
|
|
8826
|
+
// // console.log(`pub >> [${tag}] sent: ${sentCounter} [no quota limit] total: ${remotes.size} subscribers. ` )
|
|
8827
|
+
// }
|
|
8763
8828
|
return ['ok', sentCounter]
|
|
8764
8829
|
}
|
|
8765
8830
|
}
|
|
@@ -8992,7 +9057,7 @@ class Server extends require$$0$3 {
|
|
|
8992
9057
|
|
|
8993
9058
|
this.wss.once('listening', () => {
|
|
8994
9059
|
this.port = this.wss.address().port;
|
|
8995
|
-
console.log('wss server bound port:', this.port );
|
|
9060
|
+
// console.log('wss server bound port:', this.port );
|
|
8996
9061
|
this.listeningServerCount++;
|
|
8997
9062
|
if (this.listeningServerCount === this.serverCountToListen) {
|
|
8998
9063
|
this.emit('ready');
|
|
@@ -9008,7 +9073,7 @@ class Server extends require$$0$3 {
|
|
|
9008
9073
|
});
|
|
9009
9074
|
|
|
9010
9075
|
this.wss.on('close', () => {
|
|
9011
|
-
console.log('### WS server is closed.')
|
|
9076
|
+
// console.log('### WS server is closed.')
|
|
9012
9077
|
});
|
|
9013
9078
|
|
|
9014
9079
|
this.wss.on('connection', (ws, req) => {
|
|
@@ -9029,10 +9094,10 @@ class Server extends require$$0$3 {
|
|
|
9029
9094
|
process.exit();
|
|
9030
9095
|
}
|
|
9031
9096
|
}).on('close', () => {
|
|
9032
|
-
console.log('### congsocket server is closed.')
|
|
9097
|
+
// console.log('### congsocket server is closed.')
|
|
9033
9098
|
}).listen(this.congPort, () => {
|
|
9034
9099
|
this.congPort = this.congServer.address().port;
|
|
9035
|
-
console.log('congsocket server bound port:', this.congPort );
|
|
9100
|
+
// console.log('congsocket server bound port:', this.congPort );
|
|
9036
9101
|
this.listeningServerCount++;
|
|
9037
9102
|
if (this.listeningServerCount === this.serverCountToListen) {
|
|
9038
9103
|
this.emit('ready');
|
|
@@ -9067,7 +9132,7 @@ class Server extends require$$0$3 {
|
|
|
9067
9132
|
return
|
|
9068
9133
|
}
|
|
9069
9134
|
if( api.commands.includes( req.topic )){
|
|
9070
|
-
console.log('server api req', req )
|
|
9135
|
+
// console.log('server api req', req )
|
|
9071
9136
|
await api.request(remote, req);
|
|
9072
9137
|
}else {
|
|
9073
9138
|
remote.response(req.mid, STATUS.ERROR, "UNKNOWN_COMMAND");
|
|
@@ -9097,7 +9162,7 @@ class Server extends require$$0$3 {
|
|
|
9097
9162
|
});
|
|
9098
9163
|
}
|
|
9099
9164
|
this.apiNames.add(target);
|
|
9100
|
-
console.log(`[API registed: ${target} ] accept commands: ${api.commands}`)
|
|
9165
|
+
// console.log(`[API registed: ${target} ] accept commands: ${api.commands}`)
|
|
9101
9166
|
return this
|
|
9102
9167
|
}
|
|
9103
9168
|
|
|
@@ -9137,7 +9202,7 @@ class Server extends require$$0$3 {
|
|
|
9137
9202
|
|
|
9138
9203
|
if (this.congServer) {
|
|
9139
9204
|
this.congServer.close((err) => {
|
|
9140
|
-
if (err) console.error('congServer close error', err)
|
|
9205
|
+
// if (err) console.error('congServer close error', err)
|
|
9141
9206
|
// console.log('cong server closed.')
|
|
9142
9207
|
onClosed();
|
|
9143
9208
|
});
|
|
@@ -9148,7 +9213,12 @@ class Server extends require$$0$3 {
|
|
|
9148
9213
|
|
|
9149
9214
|
const decoder = new TextDecoder();
|
|
9150
9215
|
class BohoAuth {
|
|
9151
|
-
constructor() {
|
|
9216
|
+
constructor(keyProvider) {
|
|
9217
|
+
if (!keyProvider) {
|
|
9218
|
+
throw new Error('BohoAuth must be initialized with a keyProvider.');
|
|
9219
|
+
}
|
|
9220
|
+
this.keyProvider = keyProvider;
|
|
9221
|
+
|
|
9152
9222
|
this.authLogger;
|
|
9153
9223
|
if (serverOption.fileLogger.auth.use) {
|
|
9154
9224
|
this.authLogger = new FileLogger(serverOption.fileLogger.auth.path);
|
|
@@ -9162,11 +9232,11 @@ class BohoAuth {
|
|
|
9162
9232
|
this.authLogger.log(peerInfo);
|
|
9163
9233
|
}
|
|
9164
9234
|
// console.log('##### AUTH_FAIL reason: ', reason)
|
|
9165
|
-
peer.setState(
|
|
9235
|
+
peer.setState(STATE.AUTH_FAIL);
|
|
9236
|
+
peer.send(Buffer.from([tt.BohoMsg.AUTH_FAIL]));
|
|
9166
9237
|
// add some delay time.
|
|
9167
|
-
setTimeout(e => {
|
|
9168
|
-
|
|
9169
|
-
}, serverOption.auth.delay_auth_fail);
|
|
9238
|
+
// setTimeout(e => {
|
|
9239
|
+
// }, serverOption.auth.delay_auth_fail)
|
|
9170
9240
|
}
|
|
9171
9241
|
|
|
9172
9242
|
async verify_auth_hmac(auth_hmac, peer) {
|
|
@@ -9187,7 +9257,7 @@ class BohoAuth {
|
|
|
9187
9257
|
}
|
|
9188
9258
|
|
|
9189
9259
|
//2. get key of id from DB
|
|
9190
|
-
let authInfo = await this.getAuth(id);
|
|
9260
|
+
let authInfo = await this.keyProvider.getAuth(id);
|
|
9191
9261
|
|
|
9192
9262
|
if (!authInfo) {
|
|
9193
9263
|
this.send_auth_fail(peer, 'NO ID:' + id);
|
|
@@ -9238,9 +9308,13 @@ class BohoAuth {
|
|
|
9238
9308
|
console.log('## trying RELOGIN with SAME ID. ignored.');
|
|
9239
9309
|
return
|
|
9240
9310
|
}
|
|
9241
|
-
console.log('###
|
|
9242
|
-
|
|
9243
|
-
|
|
9311
|
+
console.log('### DUPLICATE_LOGIN detected.', old.cid);
|
|
9312
|
+
let sigPack = M$1.pack(
|
|
9313
|
+
M$1.MB('#MsgType', '8', IOMsg.AUTH_CLEAR),
|
|
9314
|
+
M$1.MB('#reason', 'duplicate login.')
|
|
9315
|
+
);
|
|
9316
|
+
old.send( sigPack);
|
|
9317
|
+
// old.close() client will close and stop.
|
|
9244
9318
|
peer.close(); // auto relogin
|
|
9245
9319
|
return
|
|
9246
9320
|
}
|
|
@@ -9287,7 +9361,7 @@ class BohoAuth {
|
|
|
9287
9361
|
// console.log("LOGIN: ", `id: ${ peer.did}(${peer.cid})` )
|
|
9288
9362
|
//10. send ack.
|
|
9289
9363
|
peer.send(auth_ack);
|
|
9290
|
-
peer.setState(
|
|
9364
|
+
peer.setState(STATE.AUTH_ACK);
|
|
9291
9365
|
if (this.authLogger) {
|
|
9292
9366
|
let peerInfo = `OK #${peer.ssid} cid: ${peer.cid} did:${peer.did}`;
|
|
9293
9367
|
if (peer.isAdmin) peerInfo = "#ADMIN# " + peerInfo;
|
|
@@ -9300,12 +9374,39 @@ class BohoAuth {
|
|
|
9300
9374
|
|
|
9301
9375
|
}
|
|
9302
9376
|
|
|
9377
|
+
async getAuth(id) {
|
|
9378
|
+
return this.keyProvider.getAuth(id);
|
|
9379
|
+
}
|
|
9380
|
+
|
|
9381
|
+
async getAuthIdList() {
|
|
9382
|
+
if (typeof this.keyProvider.getAuthIdList === 'function') {
|
|
9383
|
+
return this.keyProvider.getAuthIdList();
|
|
9384
|
+
}
|
|
9385
|
+
}
|
|
9386
|
+
|
|
9387
|
+
async addAuth(id, keyStr, cid, level = 0) {
|
|
9388
|
+
if (typeof this.keyProvider.addAuth === 'function') {
|
|
9389
|
+
return this.keyProvider.addAuth(id, keyStr, cid, level);
|
|
9390
|
+
}
|
|
9391
|
+
}
|
|
9392
|
+
|
|
9393
|
+
async delAuth(id) {
|
|
9394
|
+
if (typeof this.keyProvider.delAuth === 'function') {
|
|
9395
|
+
return this.keyProvider.delAuth(id);
|
|
9396
|
+
}
|
|
9397
|
+
}
|
|
9398
|
+
|
|
9399
|
+
async save() {
|
|
9400
|
+
if (typeof this.keyProvider.save === 'function') {
|
|
9401
|
+
return this.keyProvider.save();
|
|
9402
|
+
}
|
|
9403
|
+
}
|
|
9404
|
+
|
|
9303
9405
|
|
|
9304
9406
|
}
|
|
9305
9407
|
|
|
9306
|
-
class
|
|
9408
|
+
class FileKeyProvider {
|
|
9307
9409
|
constructor(_path) {
|
|
9308
|
-
super();
|
|
9309
9410
|
this.AUTH = new Map();
|
|
9310
9411
|
let pathObj = path.parse(_path);
|
|
9311
9412
|
this.path = path.resolve(_path);
|
|
@@ -9323,20 +9424,9 @@ class Auth_File extends BohoAuth {
|
|
|
9323
9424
|
}
|
|
9324
9425
|
}
|
|
9325
9426
|
|
|
9326
|
-
|
|
9327
|
-
async getAuth(id) {
|
|
9328
|
-
return this.AUTH.get(id)
|
|
9329
|
-
}
|
|
9330
|
-
|
|
9331
|
-
async getAuthIdList() {
|
|
9332
|
-
return Array.from(this.AUTH.keys())
|
|
9333
|
-
}
|
|
9334
|
-
|
|
9335
9427
|
//loaded when server start.
|
|
9336
9428
|
loadAuthInfoFile_JS(path) {
|
|
9337
|
-
|
|
9338
9429
|
import(path).then((file) => {
|
|
9339
|
-
|
|
9340
9430
|
console.log(file.authInfo);
|
|
9341
9431
|
file.authInfo.forEach(item => {
|
|
9342
9432
|
this.addAuth(...item);
|
|
@@ -9345,8 +9435,6 @@ class Auth_File extends BohoAuth {
|
|
|
9345
9435
|
}).catch(e => {
|
|
9346
9436
|
console.log(e);
|
|
9347
9437
|
});
|
|
9348
|
-
|
|
9349
|
-
|
|
9350
9438
|
}
|
|
9351
9439
|
|
|
9352
9440
|
loadAuthInfoFile_JSON(path) {
|
|
@@ -9357,81 +9445,12 @@ class Auth_File extends BohoAuth {
|
|
|
9357
9445
|
this.addAuth(...item);
|
|
9358
9446
|
});
|
|
9359
9447
|
console.log('total AUTH INFO size: ', this.AUTH.size);
|
|
9360
|
-
|
|
9361
|
-
}
|
|
9362
|
-
|
|
9363
|
-
addAuth(id, keyStr, cid, level = 0) {
|
|
9364
|
-
let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
|
|
9365
|
-
this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
|
|
9366
|
-
}
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
}
|
|
9371
|
-
|
|
9372
|
-
/**
|
|
9373
|
-
* Auth_Env.js
|
|
9374
|
-
*
|
|
9375
|
-
* You can use environment variable BOHO_AUTH.
|
|
9376
|
-
*
|
|
9377
|
-
* BOHO_AUTH=id1.key1.level,id2:key2.level
|
|
9378
|
-
*
|
|
9379
|
-
* or constructor parameter.
|
|
9380
|
-
*
|
|
9381
|
-
*
|
|
9382
|
-
* [ authInfo ]
|
|
9383
|
-
* id: <String> max 8chars
|
|
9384
|
-
* key: <String>
|
|
9385
|
-
* level: <Numbrer> range: 0~255
|
|
9386
|
-
* separator: ','
|
|
9387
|
-
*
|
|
9388
|
-
* example => process.env.BOHO_AUTH=id1.key1.255,id2.key2.200
|
|
9389
|
-
*/
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
class Auth_Env extends BohoAuth {
|
|
9393
|
-
constructor(authInfo) {
|
|
9394
|
-
super();
|
|
9395
|
-
let id_keys;
|
|
9396
|
-
if (authInfo) {
|
|
9397
|
-
id_keys = authInfo.split(',');
|
|
9398
|
-
} else if (process.env.BOHO_AUTH) {
|
|
9399
|
-
authInfo = process.env.BOHO_AUTH;
|
|
9400
|
-
id_keys = process.env.BOHO_AUTH.split(',');
|
|
9401
|
-
} else {
|
|
9402
|
-
console.log("Auth_Env: None of process.env.BOHO_AUTH or authInfo");
|
|
9403
|
-
process.exit();
|
|
9404
|
-
}
|
|
9405
|
-
|
|
9406
|
-
this.AUTH = new Map();
|
|
9407
|
-
|
|
9408
|
-
if (id_keys.length >= 1) {
|
|
9409
|
-
id_keys.forEach(v => {
|
|
9410
|
-
|
|
9411
|
-
let did = v.split('.')[0];
|
|
9412
|
-
let key = v.split('.')[1];
|
|
9413
|
-
let level = v.split('.')[2];
|
|
9414
|
-
level = parseInt(level);
|
|
9415
|
-
|
|
9416
|
-
if (did && key && typeof level == 'number') {
|
|
9417
|
-
let cid = did;
|
|
9418
|
-
this.addAuth(did, key, cid, level);
|
|
9419
|
-
} else {
|
|
9420
|
-
console.log("Wrong process.env.BOHO_AUTH authentication value.", id, key, level);
|
|
9421
|
-
process.exit();
|
|
9422
|
-
}
|
|
9423
|
-
});
|
|
9424
|
-
|
|
9425
|
-
} else {
|
|
9426
|
-
console.log("Wrong process.env.BOHO_AUTH authentication value.");
|
|
9427
|
-
process.exit();
|
|
9428
|
-
}
|
|
9429
|
-
|
|
9430
9448
|
}
|
|
9431
9449
|
|
|
9432
9450
|
async getAuth(id) {
|
|
9433
9451
|
return this.AUTH.get(id)
|
|
9434
9452
|
}
|
|
9453
|
+
|
|
9435
9454
|
async getAuthIdList() {
|
|
9436
9455
|
return Array.from(this.AUTH.keys())
|
|
9437
9456
|
}
|
|
@@ -9440,16 +9459,14 @@ class Auth_Env extends BohoAuth {
|
|
|
9440
9459
|
let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
|
|
9441
9460
|
this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
|
|
9442
9461
|
}
|
|
9443
|
-
|
|
9444
9462
|
}
|
|
9445
9463
|
|
|
9446
9464
|
const DEVICE_PREFIX = "device:";
|
|
9447
9465
|
|
|
9448
|
-
class
|
|
9466
|
+
class RedisKeyProvider {
|
|
9449
9467
|
constructor(redisClient) {
|
|
9450
|
-
super();
|
|
9451
9468
|
if (!redisClient) {
|
|
9452
|
-
throw new Error("
|
|
9469
|
+
throw new Error("RedisKeyProvider constructor: no redisClient")
|
|
9453
9470
|
}
|
|
9454
9471
|
this.redis = redisClient;
|
|
9455
9472
|
}
|
|
@@ -9458,7 +9475,8 @@ class Auth_Redis extends BohoAuth {
|
|
|
9458
9475
|
async getAuth(id) {
|
|
9459
9476
|
try {
|
|
9460
9477
|
let result = await this.redis.hGetAll(DEVICE_PREFIX + id);
|
|
9461
|
-
if (result.key) return result
|
|
9478
|
+
if (result && result.key) return result
|
|
9479
|
+
else return null;
|
|
9462
9480
|
} catch (error) {
|
|
9463
9481
|
console.log('getAuth', error);
|
|
9464
9482
|
}
|
|
@@ -9487,7 +9505,60 @@ class Auth_Redis extends BohoAuth {
|
|
|
9487
9505
|
async save(id) {
|
|
9488
9506
|
return this.redis.save()
|
|
9489
9507
|
}
|
|
9508
|
+
}
|
|
9490
9509
|
|
|
9510
|
+
/**
|
|
9511
|
+
* StringKeyProvider.js
|
|
9512
|
+
*
|
|
9513
|
+
* authInfo <String>
|
|
9514
|
+
* id: max 8chars
|
|
9515
|
+
* key: ~44 base64 chars recomended
|
|
9516
|
+
* cid:
|
|
9517
|
+
* level: range: 0~255
|
|
9518
|
+
* separator: ',' for multiple devices.
|
|
9519
|
+
*
|
|
9520
|
+
* example => authInfo = 'id1.key1.cid1.255,id2.key2.cid2.200'
|
|
9521
|
+
*/
|
|
9522
|
+
|
|
9523
|
+
|
|
9524
|
+
class StringKeyProvider {
|
|
9525
|
+
constructor(authInfo) {
|
|
9526
|
+
|
|
9527
|
+
if (!authInfo) {
|
|
9528
|
+
throw TypeError("StringKeyProvider constructor() missing authInfo.")
|
|
9529
|
+
}
|
|
9530
|
+
|
|
9531
|
+
let id_keys = authInfo.split(',');
|
|
9532
|
+
|
|
9533
|
+
this.AUTH = new Map();
|
|
9534
|
+
|
|
9535
|
+
if (id_keys.length >= 1) {
|
|
9536
|
+
id_keys.forEach(v => {
|
|
9537
|
+
let [ did, key, cid, level ] = v.split('.');
|
|
9538
|
+
level = parseInt(level);
|
|
9539
|
+
if (did && key && cid && typeof level == 'number') {
|
|
9540
|
+
this.addAuth(did, key, cid, level);
|
|
9541
|
+
} else {
|
|
9542
|
+
throw TypeError("StringKeyProvider invalid authInfo.")
|
|
9543
|
+
}
|
|
9544
|
+
});
|
|
9545
|
+
} else {
|
|
9546
|
+
throw TypeError("StringKeyProvider invalid authInfo.")
|
|
9547
|
+
}
|
|
9548
|
+
|
|
9549
|
+
}
|
|
9550
|
+
|
|
9551
|
+
async getAuth(id) {
|
|
9552
|
+
return this.AUTH.get(id)
|
|
9553
|
+
}
|
|
9554
|
+
async getAuthIdList() {
|
|
9555
|
+
return Array.from(this.AUTH.keys())
|
|
9556
|
+
}
|
|
9557
|
+
|
|
9558
|
+
addAuth(id, keyStr, cid, level = 0) {
|
|
9559
|
+
let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
|
|
9560
|
+
this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
|
|
9561
|
+
}
|
|
9491
9562
|
}
|
|
9492
9563
|
|
|
9493
9564
|
const commands$1 = ['echo', 'date', 'unixtime'];
|
|
@@ -9672,4 +9743,4 @@ class RedisAPI {
|
|
|
9672
9743
|
|
|
9673
9744
|
const version = pkg.version;
|
|
9674
9745
|
|
|
9675
|
-
export { API_TYPE,
|
|
9746
|
+
export { API_TYPE, tt as Boho, BohoAuth, CongRx, ENC_MODE, FileKeyProvider, FileLogger, IOWS as IO, IOCongSocket, IOMsg, M$1 as MBP, PAYLOAD_TYPE, RedisAPI, RedisKeyProvider, SIZE_LIMIT, STATE, STATUS$1 as STATUS, Server, StringKeyProvider, api_reply, api_sudo, delay, getIPv4HexString, getLocalAddress, getPayloadFromSignalPack, getSignalPack, isPrivateIP, numberWithCommas, pack, parsePayload, serverOption, version };
|