iosignal 6.1.0 → 6.1.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/README.ko.md +269 -0
- package/README.md +176 -57
- package/dist/browser/esm/io.d.ts +5 -1
- package/dist/browser/esm/io.js +3 -3
- package/dist/browser/esm/io.js.map +1 -1
- package/dist/browser/iife/io.js +3 -3
- package/dist/browser/iife/io.js.map +1 -1
- package/dist/node/iosignal.cjs +74 -35
- package/dist/node/iosignal.js +74 -35
- package/dist/types/client/IOCore.d.ts +5 -1
- package/package.json +1 -1
package/dist/node/iosignal.js
CHANGED
|
@@ -14,7 +14,7 @@ import fs, { readFileSync } from 'fs';
|
|
|
14
14
|
import { memoryUsage } from 'process';
|
|
15
15
|
import path from 'path';
|
|
16
16
|
|
|
17
|
-
var version$1 = "6.1.
|
|
17
|
+
var version$1 = "6.1.2";
|
|
18
18
|
var pkg = {
|
|
19
19
|
version: version$1};
|
|
20
20
|
|
|
@@ -832,6 +832,7 @@ class IOCore extends EventEmitter {
|
|
|
832
832
|
* @type {string}
|
|
833
833
|
*/
|
|
834
834
|
this.stateName = this.getStateName(); // String type
|
|
835
|
+
this._stateRevision = 0;
|
|
835
836
|
|
|
836
837
|
/**
|
|
837
838
|
* Transmitted message counter.
|
|
@@ -968,14 +969,14 @@ class IOCore extends EventEmitter {
|
|
|
968
969
|
* If autoReconnect is false, it also clears the keep-alive timer.
|
|
969
970
|
*/
|
|
970
971
|
close() {
|
|
971
|
-
if (this._closed) return;
|
|
972
|
-
this._closed = true;
|
|
973
972
|
// console.log('####### IOCOre.js close() called')
|
|
974
973
|
// If auto-reconnect is disabled, we must stop the keep-alive timer.
|
|
975
974
|
if (this.autoReconnect === false) {
|
|
976
975
|
clearInterval(this.connectionCheckerIntervalID);
|
|
977
976
|
this.connectionCheckerIntervalID = null;
|
|
978
977
|
}
|
|
978
|
+
if (this._closed) return;
|
|
979
|
+
this._closed = true;
|
|
979
980
|
|
|
980
981
|
// socket clean
|
|
981
982
|
if (this.socket) {
|
|
@@ -998,8 +999,11 @@ class IOCore extends EventEmitter {
|
|
|
998
999
|
this.socket = null;
|
|
999
1000
|
}
|
|
1000
1001
|
this.promiseMap.clear();
|
|
1001
|
-
this.
|
|
1002
|
-
this.
|
|
1002
|
+
this.cid = '';
|
|
1003
|
+
if (this.boho) this.boho.isAuthorized = false;
|
|
1004
|
+
if (this.state !== STATE.STOP && this.stateChange('closed')) {
|
|
1005
|
+
this.emit('closed');
|
|
1006
|
+
}
|
|
1003
1007
|
}
|
|
1004
1008
|
|
|
1005
1009
|
/**
|
|
@@ -1072,6 +1076,7 @@ class IOCore extends EventEmitter {
|
|
|
1072
1076
|
|
|
1073
1077
|
// The actual connection is created here.
|
|
1074
1078
|
this.createConnection(this.url);
|
|
1079
|
+
if (this._closed) return; // A connecting listener may have stopped the client.
|
|
1075
1080
|
|
|
1076
1081
|
// Ensure the keep-alive timer is running.
|
|
1077
1082
|
if (!this.connectionCheckerIntervalID) {
|
|
@@ -1096,9 +1101,7 @@ class IOCore extends EventEmitter {
|
|
|
1096
1101
|
* Handles the 'close' event of the WebSocket.
|
|
1097
1102
|
*/
|
|
1098
1103
|
onClose() {
|
|
1099
|
-
this.
|
|
1100
|
-
this.cid = "";
|
|
1101
|
-
this.stateChange('closed');
|
|
1104
|
+
this.close();
|
|
1102
1105
|
}
|
|
1103
1106
|
|
|
1104
1107
|
/**
|
|
@@ -1109,11 +1112,11 @@ class IOCore extends EventEmitter {
|
|
|
1109
1112
|
*/
|
|
1110
1113
|
login(id, key) {
|
|
1111
1114
|
if( this.serverTimeNonce ){
|
|
1112
|
-
console.log('iosignal.login serverTimeNonce', this.serverTimeNonce);
|
|
1113
1115
|
this.auth(id, key);
|
|
1114
1116
|
this.useAuth = true;
|
|
1115
1117
|
let auth_pack = this.boho.auth_req(this.serverTimeNonce );
|
|
1116
1118
|
this.send(auth_pack);
|
|
1119
|
+
this.stateChange('auth_req', 'auth_req');
|
|
1117
1120
|
}
|
|
1118
1121
|
return this
|
|
1119
1122
|
}
|
|
@@ -1259,14 +1262,13 @@ class IOCore extends EventEmitter {
|
|
|
1259
1262
|
break;
|
|
1260
1263
|
|
|
1261
1264
|
case it.BohoMsg.SERVER_TIME_NONCE: // SERVER_READY
|
|
1262
|
-
this.
|
|
1265
|
+
buffer.copy(this.serverTimeNonce);
|
|
1266
|
+
if (!this.stateChange('server_ready', 'server_ready')) break;
|
|
1263
1267
|
if (this.useAuth) {
|
|
1264
1268
|
this.send(this.boho.auth_req(buffer));
|
|
1265
1269
|
this.stateChange('auth_req','auth_req');
|
|
1266
1270
|
// CID_REQ will be called, after auth_res.
|
|
1267
1271
|
} else {
|
|
1268
|
-
// keep server_time_nonce for manual login()
|
|
1269
|
-
buffer.copy( this.serverTimeNonce);
|
|
1270
1272
|
// CID_REQ here, if not using auth.
|
|
1271
1273
|
this.send(Buffer$1.from([IOMsg.CID_REQ]));
|
|
1272
1274
|
}
|
|
@@ -1391,14 +1393,16 @@ class IOCore extends EventEmitter {
|
|
|
1391
1393
|
break;
|
|
1392
1394
|
|
|
1393
1395
|
case it.BohoMsg.AUTH_FAIL:
|
|
1396
|
+
this.boho.isAuthorized = false;
|
|
1394
1397
|
this.stateChange('auth_fail', 'auth_fail from server.');
|
|
1395
1398
|
break;
|
|
1396
1399
|
|
|
1397
1400
|
case it.BohoMsg.AUTH_RES:
|
|
1398
1401
|
if (this.boho.verify_auth_res(buffer)) {
|
|
1399
|
-
this.stateChange('auth_res', 'server sent auth_res');
|
|
1402
|
+
if (!this.stateChange('auth_res', 'server sent auth_res')) break;
|
|
1400
1403
|
this.send(Buffer$1.from([IOMsg.CID_REQ]));
|
|
1401
1404
|
} else {
|
|
1405
|
+
this.boho.isAuthorized = false;
|
|
1402
1406
|
this.stateChange('auth_fail', 'verify_auth_res() invalid server_hmac');
|
|
1403
1407
|
}
|
|
1404
1408
|
break;
|
|
@@ -1935,6 +1939,9 @@ class IOCore extends EventEmitter {
|
|
|
1935
1939
|
* 1. 상태가 변경 될 때만 'change' 이벤트 호출된다.
|
|
1936
1940
|
* 2. emitEventAndMessage 옵션 값이 지정되야 해당 이벤트 이름이 호출된다.
|
|
1937
1941
|
* 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
|
|
1942
|
+
* 3. 두 상태값 갱신 후 change, 개별 이벤트 순서로 호출한다.
|
|
1943
|
+
* 콜백에서 다른 상태로 전이하면 이전 상태의 개별 이벤트는 생략한다.
|
|
1944
|
+
* @returns {boolean} Whether this transition is still current after callbacks.
|
|
1938
1945
|
*/
|
|
1939
1946
|
stateChange(state, emitEventAndMessage) {
|
|
1940
1947
|
// STATE constant name <string> upperCase
|
|
@@ -1942,16 +1949,19 @@ class IOCore extends EventEmitter {
|
|
|
1942
1949
|
// .state <number>
|
|
1943
1950
|
// console.log('### stateChange reason:', emitEventAndMessage )
|
|
1944
1951
|
let eventName = state.toLowerCase();
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1952
|
+
const nextState = STATE[state.toUpperCase()];
|
|
1953
|
+
if (typeof nextState !== 'number') throw new TypeError('Unknown state: ' + state);
|
|
1954
|
+
const changed = this.state !== nextState;
|
|
1955
|
+
this.state = nextState;
|
|
1956
|
+
this.stateName = eventName;
|
|
1957
|
+
if (changed) this._stateRevision++;
|
|
1958
|
+
const revision = this._stateRevision;
|
|
1959
|
+
if (changed) {
|
|
1953
1960
|
this.emit('change', eventName);
|
|
1954
1961
|
}
|
|
1962
|
+
if (revision !== this._stateRevision) return false;
|
|
1963
|
+
if (emitEventAndMessage) this.emit(eventName, emitEventAndMessage);
|
|
1964
|
+
return revision === this._stateRevision;
|
|
1955
1965
|
}
|
|
1956
1966
|
|
|
1957
1967
|
}
|
|
@@ -2112,6 +2122,7 @@ class IOCongSocket extends IOCore {
|
|
|
2112
2122
|
this.congRx = null;
|
|
2113
2123
|
}
|
|
2114
2124
|
this.socket.removeAllListeners();
|
|
2125
|
+
this.socket.on('error', () => {});
|
|
2115
2126
|
if (!this.socket.destroyed) {
|
|
2116
2127
|
this.socket.destroy(); // destroy() is sufficient for forceful closing
|
|
2117
2128
|
}
|
|
@@ -2136,23 +2147,29 @@ class IOCongSocket extends IOCore {
|
|
|
2136
2147
|
if (urlObj.protocol != "cong:") {
|
|
2137
2148
|
urlObj = new URL('cong://' + url);
|
|
2138
2149
|
}
|
|
2139
|
-
this.socket = net.createConnection(urlObj.port, urlObj.hostname);
|
|
2140
|
-
this.
|
|
2150
|
+
const socket = this.socket = net.createConnection(urlObj.port, urlObj.hostname);
|
|
2151
|
+
this._closed = false;
|
|
2141
2152
|
|
|
2142
2153
|
this.socket.on('connect', () => {
|
|
2154
|
+
if (this.socket !== socket) return;
|
|
2143
2155
|
this.congRx = new CongRx();
|
|
2144
2156
|
this.socket.pipe(this.congRx);
|
|
2145
|
-
this.congRx.on(
|
|
2157
|
+
this.congRx.on('data', data => {
|
|
2158
|
+
if (this.socket === socket) this.onTCPSocketMessage(data);
|
|
2159
|
+
});
|
|
2146
2160
|
this.emit('open');
|
|
2147
2161
|
});
|
|
2148
2162
|
|
|
2149
2163
|
this.socket.on('error', e => {
|
|
2164
|
+
if (this.socket !== socket) return;
|
|
2150
2165
|
this.emit('error', e);
|
|
2151
2166
|
});
|
|
2152
2167
|
|
|
2153
2168
|
this.socket.on('close', () => {
|
|
2169
|
+
if (this.socket !== socket) return;
|
|
2154
2170
|
this.emit('close');
|
|
2155
2171
|
});
|
|
2172
|
+
this.stateChange('connecting','connecting');
|
|
2156
2173
|
|
|
2157
2174
|
}
|
|
2158
2175
|
|
|
@@ -7242,6 +7259,8 @@ class IOWS extends IOCore {
|
|
|
7242
7259
|
close() {
|
|
7243
7260
|
if (this.socket) {
|
|
7244
7261
|
this.socket.removeAllListeners();
|
|
7262
|
+
// Closing a connecting ws can emit an asynchronous error after detachment.
|
|
7263
|
+
this.socket.on('error', () => {});
|
|
7245
7264
|
if (this.socket.readyState !== WebSocket.CLOSED) {
|
|
7246
7265
|
this.socket.close();
|
|
7247
7266
|
}
|
|
@@ -7261,21 +7280,27 @@ class IOWS extends IOCore {
|
|
|
7261
7280
|
|
|
7262
7281
|
createConnection(url) {
|
|
7263
7282
|
// node WebSocket
|
|
7264
|
-
this.socket = new WebSocket(url);
|
|
7265
|
-
this.
|
|
7283
|
+
const socket = this.socket = new WebSocket(url);
|
|
7284
|
+
this._closed = false;
|
|
7266
7285
|
|
|
7267
7286
|
this.socket.onopen = () => {
|
|
7268
|
-
this.socket
|
|
7287
|
+
if (this.socket !== socket) return;
|
|
7288
|
+
socket.on('message', data => {
|
|
7289
|
+
if (this.socket === socket) this.onWebSocketMessage(data);
|
|
7290
|
+
});
|
|
7269
7291
|
this.emit('open');
|
|
7270
7292
|
};
|
|
7271
7293
|
|
|
7272
7294
|
this.socket.onerror = (e) => {
|
|
7295
|
+
if (this.socket !== socket) return;
|
|
7273
7296
|
this.emit('error', e);
|
|
7274
7297
|
};
|
|
7275
7298
|
|
|
7276
7299
|
this.socket.onclose = () => {
|
|
7300
|
+
if (this.socket !== socket) return;
|
|
7277
7301
|
this.emit('close');
|
|
7278
7302
|
};
|
|
7303
|
+
this.stateChange('connecting','connecting');
|
|
7279
7304
|
}
|
|
7280
7305
|
|
|
7281
7306
|
onWebSocketMessage(data) {
|
|
@@ -7394,7 +7419,9 @@ class RemoteCore {
|
|
|
7394
7419
|
static ssid = 1;
|
|
7395
7420
|
|
|
7396
7421
|
setState(state) {
|
|
7422
|
+
const previous = this.state;
|
|
7397
7423
|
this.state = state;
|
|
7424
|
+
if (previous !== state) this.manager.server?.emit('remote:state', this, previous);
|
|
7398
7425
|
if (serverOption.debug.showAuthInfo) {
|
|
7399
7426
|
this.stateLog.push( state + ":" + STATE[ state] );
|
|
7400
7427
|
if( state == STATE.AUTH_RES){
|
|
@@ -7463,6 +7490,8 @@ class RemoteCore {
|
|
|
7463
7490
|
// CongSocket or WebSocket
|
|
7464
7491
|
onSocketMessage(message, isBinary = true) {
|
|
7465
7492
|
|
|
7493
|
+
if (this._closing || this.state === STATE.CLOSED) return;
|
|
7494
|
+
|
|
7466
7495
|
this.receiveMonitor(); // rx-data, ping/pong and timeout check
|
|
7467
7496
|
if (!this.rxQuotaChecker(message)) return
|
|
7468
7497
|
|
|
@@ -7516,10 +7545,11 @@ class RemoteCore {
|
|
|
7516
7545
|
break;
|
|
7517
7546
|
|
|
7518
7547
|
case IOMsg.CID_REQ:
|
|
7519
|
-
if (
|
|
7548
|
+
if (![STATE.SERVER_READY, STATE.AUTH_RES, STATE.AUTH_FAIL, STATE.CID_RES].includes(this.state)) {
|
|
7520
7549
|
// Protocol violation: CID_REQ was sent before receiving the SERVER_READY signal.
|
|
7521
7550
|
console.log('CID_REQ before SERVER_READY');
|
|
7522
7551
|
this.close();
|
|
7552
|
+
return;
|
|
7523
7553
|
}
|
|
7524
7554
|
|
|
7525
7555
|
if (!this.cid) {
|
|
@@ -7639,9 +7669,12 @@ class RemoteCore {
|
|
|
7639
7669
|
// client's auth requst
|
|
7640
7670
|
case it.BohoMsg.AUTH_REQ:
|
|
7641
7671
|
if (!this.manager.authManager) return
|
|
7642
|
-
|
|
7672
|
+
// Do not start overlapping verification on the same connection.
|
|
7673
|
+
if (this.state === STATE.AUTH_REQ) return;
|
|
7674
|
+
if (![STATE.SERVER_READY, STATE.AUTH_RES, STATE.AUTH_FAIL, STATE.CID_RES].includes(this.state)) {
|
|
7643
7675
|
console.log('protocol error. must called auth_req after server_ready');
|
|
7644
7676
|
this.close();
|
|
7677
|
+
return;
|
|
7645
7678
|
}
|
|
7646
7679
|
this.setState(STATE.AUTH_REQ);
|
|
7647
7680
|
//async
|
|
@@ -7990,6 +8023,7 @@ class Remote extends RemoteCore {
|
|
|
7990
8023
|
}
|
|
7991
8024
|
|
|
7992
8025
|
close(terminateNow = false) {
|
|
8026
|
+
this._closing = true;
|
|
7993
8027
|
this.getTraffic();
|
|
7994
8028
|
if (this.socketType === 'websocket') {
|
|
7995
8029
|
if (terminateNow) this.socket.terminate();
|
|
@@ -8255,6 +8289,7 @@ class Manager {
|
|
|
8255
8289
|
if (socket.isAlive === false) {
|
|
8256
8290
|
console.log('## timeout. cid:', remo.cid);
|
|
8257
8291
|
remo.close();
|
|
8292
|
+
return;
|
|
8258
8293
|
}
|
|
8259
8294
|
|
|
8260
8295
|
socket.txCounter++;
|
|
@@ -8294,6 +8329,9 @@ class Manager {
|
|
|
8294
8329
|
|
|
8295
8330
|
removeRemote(remote) {
|
|
8296
8331
|
|
|
8332
|
+
remote._closing = true;
|
|
8333
|
+
remote.setState(STATE.CLOSED);
|
|
8334
|
+
|
|
8297
8335
|
let remoteInfo = `- IP:${remote.ip} #${remote.ssid} cid:${remote.cid} ${remote?.socket.socketType === 'websocket' ? "WS" : "CS"} `;
|
|
8298
8336
|
if (this.connectionLogger) this.connectionLogger.log(remoteInfo);
|
|
8299
8337
|
this.deligateSignal(remote, '@state', 'close');
|
|
@@ -8903,6 +8941,7 @@ class BohoAuth {
|
|
|
8903
8941
|
}
|
|
8904
8942
|
|
|
8905
8943
|
send_auth_fail(peer, reason) {
|
|
8944
|
+
if (peer._closing || peer.state === STATE.CLOSED) return;
|
|
8906
8945
|
peer.boho.isAuthorized = false;
|
|
8907
8946
|
if (this.authLogger) {
|
|
8908
8947
|
let peerInfo = `FAIL #${peer.ssid} reason:${reason} `;
|
|
@@ -8912,7 +8951,9 @@ class BohoAuth {
|
|
|
8912
8951
|
peer.setState(STATE.AUTH_FAIL);
|
|
8913
8952
|
// add some delay time.
|
|
8914
8953
|
setTimeout(e => {
|
|
8915
|
-
peer.
|
|
8954
|
+
if (!peer._closing && peer.state === STATE.AUTH_FAIL) {
|
|
8955
|
+
peer.send(Buffer.from([it.BohoMsg.AUTH_FAIL]));
|
|
8956
|
+
}
|
|
8916
8957
|
}, serverOption.auth.delay_auth_fail);
|
|
8917
8958
|
}
|
|
8918
8959
|
|
|
@@ -8935,6 +8976,7 @@ class BohoAuth {
|
|
|
8935
8976
|
|
|
8936
8977
|
//2. get key of id from DB
|
|
8937
8978
|
let authInfo = await this.keyProvider.getAuth(id);
|
|
8979
|
+
if (peer._closing || peer.state === STATE.CLOSED) return;
|
|
8938
8980
|
if (!authInfo) {
|
|
8939
8981
|
this.send_auth_fail(peer, 'NO ID:' + id);
|
|
8940
8982
|
return
|
|
@@ -8967,14 +9009,10 @@ class BohoAuth {
|
|
|
8967
9009
|
//4. get info
|
|
8968
9010
|
|
|
8969
9011
|
//5. check duplicate login.
|
|
8970
|
-
if (peer.manager.cid2remote.has(authInfo.cid)) {
|
|
9012
|
+
if (peer.manager.cid2remote.has(authInfo.cid) && peer.manager.cid2remote.get(authInfo.cid) !== peer) {
|
|
8971
9013
|
let old = peer.manager.cid2remote.get(authInfo.cid);
|
|
8972
9014
|
console.log('[WARN]DUPLICATE_LOGIN detected.', old.cid);
|
|
8973
9015
|
old.ping(); // check the connection.
|
|
8974
|
-
if (old == peer) {
|
|
8975
|
-
console.log('## trying to RELOGIN after login.');
|
|
8976
|
-
return
|
|
8977
|
-
}
|
|
8978
9016
|
|
|
8979
9017
|
let authClearSignal = $$1.pack(
|
|
8980
9018
|
$$1.MB('#MsgType', '8', IOMsg.AUTH_CLEAR),
|
|
@@ -8987,6 +9025,7 @@ class BohoAuth {
|
|
|
8987
9025
|
if( peer.socketType == 'websocket'){
|
|
8988
9026
|
this.send_auth_fail(peer, 'duplicate login');
|
|
8989
9027
|
}else {
|
|
9028
|
+
peer.setState(STATE.AUTH_FAIL);
|
|
8990
9029
|
peer.close(); //arduino
|
|
8991
9030
|
}
|
|
8992
9031
|
} else {
|
|
@@ -37,6 +37,7 @@ export class IOCore {
|
|
|
37
37
|
* @type {string}
|
|
38
38
|
*/
|
|
39
39
|
stateName: string;
|
|
40
|
+
_stateRevision: number;
|
|
40
41
|
/**
|
|
41
42
|
* Transmitted message counter.
|
|
42
43
|
* @type {number}
|
|
@@ -404,8 +405,11 @@ export class IOCore {
|
|
|
404
405
|
* 1. 상태가 변경 될 때만 'change' 이벤트 호출된다.
|
|
405
406
|
* 2. emitEventAndMessage 옵션 값이 지정되야 해당 이벤트 이름이 호출된다.
|
|
406
407
|
* 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
|
|
408
|
+
* 3. 두 상태값 갱신 후 change, 개별 이벤트 순서로 호출한다.
|
|
409
|
+
* 콜백에서 다른 상태로 전이하면 이전 상태의 개별 이벤트는 생략한다.
|
|
410
|
+
* @returns {boolean} Whether this transition is still current after callbacks.
|
|
407
411
|
*/
|
|
408
|
-
stateChange(state: string, emitEventAndMessage?: string):
|
|
412
|
+
stateChange(state: string, emitEventAndMessage?: string): boolean;
|
|
409
413
|
}
|
|
410
414
|
export type MBP = import("meta-buffer-pack").MBP;
|
|
411
415
|
export type IOMsg = import("../common/constants.js").IOMsg;
|