iosignal 4.0.0 → 4.6.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/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 = "4.0.0";
16
+ var version$1 = "4.6.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} STATES
385
- * @property {number} OPENING
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} AUTH_FAIL
391
- * @property {number} AUTH_READY
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 STATES: name and number
396
- const STATES = {
397
- OPENING: 0,
398
- OPEN: 1,
399
- CLOSING: 2,
400
- CLOSED: 3,
401
- SERVER_READY: 4,
402
- AUTH_FAIL: 5,
403
- AUTH_READY: 6,
404
- READY: 7,
405
- REDIRECTING: 8
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 STATES) { STATES[STATES[c]] = c; }
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
@@ -449,6 +437,7 @@ for (let c in ENC_MODE) { ENC_MODE[ENC_MODE[c]] = c; }
449
437
  * @property {number} TAG_LEN1
450
438
  * @property {number} TAG_LEN2
451
439
  * @property {number} CONNECTION_CHECKER_PERIOD
440
+ * @property {number} CLIENT_PING_PERIOD
452
441
  * @property {number} PROMISE_TIMEOUT
453
442
  * @property {number} DID
454
443
  * @property {number} CID
@@ -457,6 +446,7 @@ const SIZE_LIMIT = {
457
446
  TAG_LEN1: 255,
458
447
  TAG_LEN2: 65535,
459
448
  CONNECTION_CHECKER_PERIOD: 3000,
449
+ CLIENT_PING_PERIOD: 40000,
460
450
  PROMISE_TIMEOUT: 5000,
461
451
  DID: 8,
462
452
  CID: 12
@@ -488,7 +478,7 @@ for (let c in PAYLOAD_TYPE) { PAYLOAD_TYPE[PAYLOAD_TYPE[c]] = c; }
488
478
  * @property {number} CID_REQ
489
479
  * @property {number} CID_RES
490
480
  * @property {number} QUOTA_LEVEL
491
- * @property {number} SERVER_CLEAR_AUTH
481
+ * @property {number} AUTH_CLEAR
492
482
  * @property {number} SERVER_REDIRECT
493
483
  * @property {number} LOOP
494
484
  * @property {number} ECHO
@@ -546,9 +536,8 @@ let IOMsg = {
546
536
  CID_REQ: 0xC1,
547
537
  CID_RES: 0xC2,
548
538
  QUOTA_LEVEL: 0xC3,
549
- SERVER_CLEAR_AUTH: 0xC4,
539
+ AUTH_CLEAR: 0xC4,
550
540
  SERVER_REDIRECT: 0xC5,
551
-
552
541
  // ..
553
542
  LOOP: 0xCB,
554
543
  ECHO: 0xCC,
@@ -789,7 +778,7 @@ const t=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1
789
778
  * @typedef {import('../common/constants.js').PAYLOAD_TYPE} PAYLOAD_TYPE
790
779
  * @typedef {import('../common/constants.js').SIZE_LIMIT} SIZE_LIMIT
791
780
  * @typedef {import('../common/constants.js').ENC_MODE} ENC_MODE
792
- * @typedef {import('../common/constants.js').STATES} STATES
781
+ * @typedef {import('../common/constants.js').STATE} STATE
793
782
  * @typedef {import('../common/quotaTable.js').quotaTable} quotaTable
794
783
 
795
784
  * @typedef {import('boho').Boho} Boho
@@ -843,7 +832,7 @@ class IOCore extends EventEmitter {
843
832
  * Current connection state (number).
844
833
  * @type {number}
845
834
  */
846
- this.state = STATES.CLOSED; // Number type
835
+ this.state = STATE.CLOSED; // Number type
847
836
  /**
848
837
  * Current connection state (string).
849
838
  * @type {string}
@@ -985,7 +974,7 @@ class IOCore extends EventEmitter {
985
974
  close() {
986
975
  if (this._closed) return;
987
976
  this._closed = true;
988
- // console.log('####### IOCOre.js close() called')
977
+ // console.log('####### IOCOre.js close() called')
989
978
  // If auto-reconnect is disabled, we must stop the keep-alive timer.
990
979
  if (this.autoReconnect === false) {
991
980
  clearInterval(this.connectionCheckerIntervalID);
@@ -1000,7 +989,7 @@ class IOCore extends EventEmitter {
1000
989
  // To avoid the error, we wait for the connection to open, then immediately close it.
1001
990
  // We also clear other handlers to prevent any other logic from running.
1002
991
  const socket = this.socket;
1003
- socket.onopen = () => { if(socket) socket.close(); };
992
+ socket.onopen = () => { if (socket) socket.close(); };
1004
993
  socket.onmessage = null;
1005
994
  socket.onerror = null;
1006
995
  socket.onclose = null;
@@ -1008,7 +997,7 @@ class IOCore extends EventEmitter {
1008
997
  try {
1009
998
  // For other sockets (like TCP) or other WebSocket states, close directly.
1010
999
  this.socket.close?.();
1011
- } catch {}
1000
+ } catch { }
1012
1001
  }
1013
1002
  this.socket = null;
1014
1003
  }
@@ -1016,14 +1005,15 @@ class IOCore extends EventEmitter {
1016
1005
  this.emit('closed');
1017
1006
  this.stateChange('closed');
1018
1007
  }
1019
-
1008
+
1020
1009
  /**
1021
1010
  * Disables auto-reconnect and closes the current connection.
1022
1011
  * The instance can be re-opened manually later. For complete cleanup, use destroy().
1023
- */
1024
- stop() {
1025
- this.autoReconnect = false;
1026
- this.close();
1012
+ */
1013
+ stop() {
1014
+ this.autoReconnect = false;
1015
+ this.close();
1016
+ this.stateChange('stop','stop');
1027
1017
  }
1028
1018
 
1029
1019
  /**
@@ -1039,16 +1029,18 @@ class IOCore extends EventEmitter {
1039
1029
 
1040
1030
  // Help GC
1041
1031
  this.boho = null;
1042
- }
1032
+ }
1043
1033
 
1044
1034
  /**
1045
- * The core keep-alive logic. It checks if auto-reconnect is enabled.
1046
- * The actual check for the socket's state is implemented in the child classes.
1035
+ * The core keep-alive logic.
1036
+ * The specific logic for checking the socket's state and reconnecting
1037
+ * is implemented keepConnection() in the child classes (IOWS, IOCongSocket, etc.).
1047
1038
  */
1048
1039
  keepAlive() {
1049
- if (!this.autoReconnect) return;
1050
- // The specific logic for checking the socket's state and reconnecting
1051
- // is implemented in the child classes (IOWS, IOCongSocket, etc.).
1040
+ this.keepConnection();
1041
+ if( Date.now() - this.lastTxRxTime > SIZE_LIMIT.CLIENT_PING_PERIOD ){
1042
+ this.ping();
1043
+ }
1052
1044
  }
1053
1045
 
1054
1046
  /**
@@ -1056,8 +1048,8 @@ class IOCore extends EventEmitter {
1056
1048
  * @param {string} url2 - The new URL to redirect to.
1057
1049
  */
1058
1050
  redirect(url2) {
1051
+ this.stateChange('redirecting','redirecting');
1059
1052
  this.close();
1060
- this.stateChange('redirecting');
1061
1053
  this.createConnection(url2);
1062
1054
  }
1063
1055
 
@@ -1114,29 +1106,27 @@ class IOCore extends EventEmitter {
1114
1106
 
1115
1107
  /**
1116
1108
  * Manually logs in with provided ID and key.
1117
- * @param {string} id - The user ID.
1109
+ * @param {string} id - The user ID. or 'id.key'
1118
1110
  * @param {string} key - The user key.
1119
- * @returns {boolean}
1111
+ * @returns {this}
1120
1112
  */
1121
1113
  login(id, key) {
1122
- if (!this.auth(id, key)) return false;
1123
-
1114
+ this.auth(id, key);
1124
1115
  this.useAuth = true;
1125
1116
  let auth_pack = this.boho.auth_req();
1126
1117
  this.send(auth_pack);
1127
- return true
1118
+ return this
1128
1119
  }
1129
1120
 
1130
1121
  /**
1131
1122
  * Sets up authentication for auto-login.
1132
- * @param {string} id - The user ID.
1123
+ * @param {string} id - The user ID. or 'id.Key'
1133
1124
  * @param {string} key - The user key.
1134
- * @returns {boolean}
1125
+ * @returns {this}
1135
1126
  */
1136
1127
  auth(id, key) {
1137
1128
  if (!id && !key) {
1138
1129
  this.emit('error', new Error('auth failed. no id and key.'));
1139
- return false
1140
1130
  }
1141
1131
 
1142
1132
  if (!key && id.includes('.')) {
@@ -1146,10 +1136,9 @@ class IOCore extends EventEmitter {
1146
1136
  this.boho.set_key(key);
1147
1137
  } else {
1148
1138
  this.emit('error', new Error('auth failed. no id or key.'));
1149
- return false
1150
1139
  }
1151
1140
  this.useAuth = true;
1152
- return true
1141
+ return this
1153
1142
  }
1154
1143
 
1155
1144
  /**
@@ -1209,13 +1198,13 @@ class IOCore extends EventEmitter {
1209
1198
  case IOMsg.ECHO:
1210
1199
  try {
1211
1200
  let str = decoder$4.decode(buffer.subarray(1));
1212
-
1201
+
1213
1202
  this.emit('echo', str);
1214
1203
  } catch (error) {
1215
1204
  this.emit('error', new Error('ECHO data error'));
1216
1205
  }
1217
1206
  break;
1218
-
1207
+
1219
1208
  case IOMsg.IAM_RES:
1220
1209
  try {
1221
1210
  let str = decoder$4.decode(buffer.subarray(1));
@@ -1224,7 +1213,7 @@ class IOCore extends EventEmitter {
1224
1213
  if (jsonInfo.nick) { this.nick = jsonInfo.nick; }
1225
1214
  if (jsonInfo.did) { this.did = jsonInfo.did; }
1226
1215
  if (jsonInfo.uid) { this.uid = jsonInfo.uid; }
1227
- this.emit('iam_res', str );
1216
+ this.emit('iam_res', str);
1228
1217
  } catch (error) {
1229
1218
  this.emit('error', new Error('IAM_RES data error'));
1230
1219
  }
@@ -1235,22 +1224,22 @@ class IOCore extends EventEmitter {
1235
1224
  this.cid = cidStr;
1236
1225
 
1237
1226
  // **IMPORTANT** change state before subscribe.
1238
- this.stateChange('ready', 'cid_ready');
1239
- this.subscribe_memory_channels();
1227
+ this.stateChange('ready', 'cid_ready');
1228
+ this.subscribe_memory_channels(); // tags registered by listen() or link().
1240
1229
  break;
1241
1230
 
1242
1231
  case IOMsg.QUOTA_LEVEL:
1243
1232
  let quotaLevel = buffer[1];
1244
1233
  this.level = quotaLevel;
1245
1234
  this.quota = quotaTable[quotaLevel];
1246
- console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota));
1235
+ // console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota))
1247
1236
  break;
1248
1237
 
1249
- case IOMsg.SERVER_CLEAR_AUTH:
1238
+ case IOMsg.AUTH_CLEAR:
1250
1239
  this.useAuth = false;
1251
1240
  this.boho.clearAuth();
1241
+ this.stateChange('auth_clear', 'server request auth_clear.');
1252
1242
  this.stop();
1253
- console.log('[SERVER_CLEAR_AUTH] io stop.');
1254
1243
  break;
1255
1244
 
1256
1245
  case IOMsg.SERVER_REDIRECT:
@@ -1327,7 +1316,7 @@ class IOCore extends EventEmitter {
1327
1316
  if (tag.indexOf('@') === 0) this.emit('@', tag, null);
1328
1317
  else {
1329
1318
  this.emit(tag, tag, null);
1330
- this.emit('message', tag, null );
1319
+ this.emit('message', tag, null);
1331
1320
  }
1332
1321
  break;
1333
1322
 
@@ -1340,7 +1329,7 @@ class IOCore extends EventEmitter {
1340
1329
  }
1341
1330
  let oneString = decoder$4.decode(payloadStringWithoutNull);
1342
1331
  if (tag.indexOf('@') === 0) this.emit('@', tag, oneString);
1343
- if (tag !== '@'){
1332
+ if (tag !== '@') {
1344
1333
  this.emit(tag, tag, oneString);
1345
1334
  this.emit('message', tag, oneString);
1346
1335
  }
@@ -1348,39 +1337,39 @@ class IOCore extends EventEmitter {
1348
1337
 
1349
1338
  case PAYLOAD_TYPE.BINARY:
1350
1339
  if (tag.indexOf('@') === 0) this.emit('@', tag, payloadBuffer);
1351
- if (tag !== '@'){
1340
+ if (tag !== '@') {
1352
1341
  this.emit(tag, tag, payloadBuffer);
1353
1342
  this.emit('message', tag, payloadBuffer);
1354
- }
1343
+ }
1355
1344
  break;
1356
1345
 
1357
1346
  case PAYLOAD_TYPE.OBJECT:
1358
1347
  let oneObjectBuffer = decoder$4.decode(payloadBuffer);
1359
1348
  let oneJSONObject = JSON.parse(oneObjectBuffer);
1360
1349
  if (tag.indexOf('@') === 0) this.emit('@', tag, oneJSONObject);
1361
- if (tag !== '@'){
1350
+ if (tag !== '@') {
1362
1351
  this.emit(tag, tag, oneJSONObject);
1363
1352
  this.emit('message', tag, oneJSONObject);
1364
- }
1353
+ }
1365
1354
  break;
1366
1355
 
1367
1356
  case PAYLOAD_TYPE.MJSON:
1368
1357
  let mjsonBuffer = decoder$4.decode(payloadBuffer);
1369
1358
  let mjson = JSON.parse(mjsonBuffer);
1370
1359
  if (tag.indexOf('@') === 0) this.emit('@', tag, ...mjson);
1371
- if (tag !== '@'){
1360
+ if (tag !== '@') {
1372
1361
  this.emit(tag, tag, ...mjson);
1373
1362
  this.emit('message', tag, ...mjson);
1374
- }
1363
+ }
1375
1364
  break;
1376
1365
 
1377
1366
  case PAYLOAD_TYPE.MBA:
1378
1367
  let mbaObject = M$1.unpack(payloadBuffer);
1379
1368
  if (tag.indexOf('@') === 0) this.emit('@', tag, ...mbaObject.args);
1380
- if (tag !== '@'){
1369
+ if (tag !== '@') {
1381
1370
  this.emit(tag, tag, ...mbaObject.args);
1382
- this.emit('message', tag, ...mbaObject.args );
1383
- }
1371
+ this.emit('message', tag, ...mbaObject.args);
1372
+ }
1384
1373
  break;
1385
1374
 
1386
1375
  default:
@@ -1388,7 +1377,8 @@ class IOCore extends EventEmitter {
1388
1377
  }
1389
1378
 
1390
1379
  } catch (err) {
1391
- this.emit('error', new Error('signal parse err'));
1380
+ // this.emit('error', new Error('IOCore IOMsg.SIGNAL parser err', err))
1381
+ console.log('IOCore IOMsg.SIGNAL parser err', err);
1392
1382
  }
1393
1383
  break;
1394
1384
 
@@ -1397,24 +1387,25 @@ class IOCore extends EventEmitter {
1397
1387
  break;
1398
1388
 
1399
1389
  case tt.BohoMsg.AUTH_NONCE:
1390
+ this.stateChange('auth_nonce','server sent auth_nonce.');
1400
1391
  let auth_hmac = this.boho.auth_hmac(buffer);
1401
1392
  if (auth_hmac) {
1402
1393
  this.send(auth_hmac);
1403
1394
  } else {
1404
- this.stateChange('auth_fail', 'Invalid local auth_hmac.');
1395
+ this.stateChange('auth_fail', 'boho.auth_hmac() invalid auth_nonce.');
1405
1396
  }
1406
1397
  break;
1407
1398
 
1408
1399
  case tt.BohoMsg.AUTH_FAIL:
1409
- this.stateChange('auth_fail', 'server reject auth.');
1400
+ this.stateChange('auth_fail', 'auth_fail from server.');
1410
1401
  break;
1411
1402
 
1412
1403
  case tt.BohoMsg.AUTH_ACK:
1413
1404
  if (this.boho.check_auth_ack_hmac(buffer)) {
1414
- this.stateChange('auth_ready', 'server sent auth_ack');
1405
+ this.stateChange('auth_ack', 'server sent auth_ack');
1415
1406
  this.send(Buffer$1.from([IOMsg.CID_REQ]));
1416
1407
  } else {
1417
- this.stateChange('auth_fail', 'invalid server_hmac');
1408
+ this.stateChange('auth_fail', 'check_auth_ack_hmac() invalid server_hmac');
1418
1409
  }
1419
1410
  break;
1420
1411
 
@@ -1601,14 +1592,15 @@ class IOCore extends EventEmitter {
1601
1592
 
1602
1593
 
1603
1594
  /**
1604
- * Publishes a signal.
1595
+ * alias of signal()
1596
+ * Sends a signal with a tag and arguments.
1597
+ * @param {string} tag - The signal tag.
1605
1598
  * @param {...any} args - Arguments for the signal.
1606
1599
  */
1607
- publish(...args) {
1608
- this.signal(...args);
1600
+ publish(tag, ...args) {
1601
+ this.signal(tag, ...args);
1609
1602
  }
1610
1603
 
1611
-
1612
1604
  /**
1613
1605
  * Sends a signal with a tag and arguments.
1614
1606
  * @param {string} tag - The signal tag.
@@ -1617,7 +1609,6 @@ class IOCore extends EventEmitter {
1617
1609
  */
1618
1610
  signal(tag, ...args) {
1619
1611
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1620
-
1621
1612
  let signalPack = getSignalPack(tag, ...args);
1622
1613
  this.send_enc_mode(signalPack);
1623
1614
  }
@@ -1661,7 +1652,6 @@ class IOCore extends EventEmitter {
1661
1652
  }
1662
1653
 
1663
1654
 
1664
-
1665
1655
  /**
1666
1656
  * Sets a value in the store.
1667
1657
  * @param {string} storeName - The name of the store.
@@ -1729,8 +1719,8 @@ class IOCore extends EventEmitter {
1729
1719
  */
1730
1720
  subscribe(tag) {
1731
1721
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1732
- if (tag.length > SIZE_LIMIT.TAG_LEN1) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN1)
1733
- if (this.state !== STATES.READY) return
1722
+ if (tag.length > SIZE_LIMIT.TAG_LEN1) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN1)
1723
+ if (this.state !== STATE.READY) return
1734
1724
 
1735
1725
  // subscribe 사용시, 사용 'ready' 이벤트시 메뉴얼 등록되므로 여기에 등록하면 2중 호출된다.
1736
1726
  // 즉, channels 등록은 listen 같은 자동화 구독시만 사용.
@@ -1739,7 +1729,7 @@ class IOCore extends EventEmitter {
1739
1729
  // this.channels.add(tag)
1740
1730
  // })
1741
1731
 
1742
- try {
1732
+ try {
1743
1733
  let tagEncoded = encoder$1.encode(tag);
1744
1734
  this.send_enc_mode(
1745
1735
  Buffer$1.concat([
@@ -1759,12 +1749,12 @@ class IOCore extends EventEmitter {
1759
1749
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1760
1750
  if (tag.length > SIZE_LIMIT.TAG_LEN2) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN2)
1761
1751
 
1762
- if (this.state !== STATES.READY) {
1752
+ if (this.state !== STATE.READY) {
1763
1753
  return Promise.reject('subscribe_promise:: connection is not ready')
1764
1754
  }
1765
1755
 
1766
1756
  try {
1767
- let tagEncoded = encoder$1.encode(tag);
1757
+ let tagEncoded = encoder$1.encode(tag);
1768
1758
  this.send_enc_mode(
1769
1759
  Buffer$1.concat([
1770
1760
  M$1.NB('8', IOMsg.SUBSCRIBE_REQ),
@@ -1834,7 +1824,7 @@ class IOCore extends EventEmitter {
1834
1824
  }
1835
1825
  this.on(tag, handler);
1836
1826
  // do not subscribe now.
1837
- // will subscribe when receive CID_RES signal from server.
1827
+ // will subscribe when io state is 'ready'. (receive CID_RES from server)
1838
1828
 
1839
1829
  }
1840
1830
 
@@ -1945,10 +1935,10 @@ class IOCore extends EventEmitter {
1945
1935
  */
1946
1936
  getStateName() {
1947
1937
  //state <number>
1948
- //value of constant STATES.NAME < number >
1949
- //type of constant STATES.NAME name < string uppercase >
1938
+ //value of constant STATE.NAME < number >
1939
+ //type of constant STATE.NAME name < string uppercase >
1950
1940
  //stateName,eventName <string lowercase>
1951
- return (STATES[this.state]).toLowerCase()
1941
+ return (STATE[this.state]).toLowerCase()
1952
1942
  }
1953
1943
 
1954
1944
  /**
@@ -1976,14 +1966,14 @@ class IOCore extends EventEmitter {
1976
1966
  * 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
1977
1967
  */
1978
1968
  stateChange(state, emitEventAndMessage) {
1979
- // STATES constant name <string> upperCase
1969
+ // STATE constant name <string> upperCase
1980
1970
  // eventName and .stateName <string> lowerCase
1981
1971
  // .state <number>
1982
1972
  // console.log('### stateChange reason:', emitEventAndMessage )
1983
1973
  let eventName = state.toLowerCase();
1984
- this.state = STATES[state.toUpperCase()]; // state: number
1974
+ this.state = STATE[state.toUpperCase()]; // state: number
1985
1975
 
1986
- if (emitEventAndMessage){
1976
+ if (emitEventAndMessage) {
1987
1977
  this.emit(eventName, emitEventAndMessage);
1988
1978
  }
1989
1979
 
@@ -2160,10 +2150,10 @@ class IOCongSocket extends IOCore {
2160
2150
 
2161
2151
 
2162
2152
 
2163
- keepAlive() {
2153
+ keepConnection() {
2164
2154
  if (!this.autoReconnect) return;
2165
2155
  // Reconnect only if the socket is fully destroyed and the state is closed.
2166
- if ((!this.socket || this.socket.destroyed) && this.state === STATES.CLOSED) {
2156
+ if ((!this.socket || this.socket.destroyed)) {
2167
2157
  this.open();
2168
2158
  }
2169
2159
  }
@@ -2176,7 +2166,7 @@ class IOCongSocket extends IOCore {
2176
2166
  urlObj = new URL('cong://' + url);
2177
2167
  }
2178
2168
  this.socket = net.createConnection(urlObj.port, urlObj.hostname);
2179
- this.stateChange('opening');
2169
+ this.stateChange('connecting','connecting');
2180
2170
 
2181
2171
  this.socket.on('connect', () => {
2182
2172
  this.congRx = new CongRx();
@@ -7586,19 +7576,20 @@ class IOWS extends IOCore {
7586
7576
  super.close();
7587
7577
  }
7588
7578
 
7589
-
7590
- keepAlive() {
7579
+ keepConnection() {
7591
7580
  if (!this.autoReconnect) return;
7592
7581
  // Reconnect only if the socket is closed and the state reflects that.
7593
- if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) && this.state === STATES.CLOSED) {
7582
+ if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) ) {
7594
7583
  this.open();
7595
7584
  }
7596
7585
  }
7597
7586
 
7587
+
7588
+
7598
7589
  createConnection(url) {
7599
7590
  // node WebSocket
7600
7591
  this.socket = new WebSocket(url);
7601
- this.stateChange('opening');
7592
+ this.stateChange('connecting','connecting');
7602
7593
 
7603
7594
  this.socket.onopen = () => {
7604
7595
  this.socket.on('message', this.onWebSocketMessage.bind(this));
@@ -7724,7 +7715,7 @@ class RemoteCore {
7724
7715
 
7725
7716
  this.state;
7726
7717
  this.stateLog = [];
7727
- this.setState(CLIENT_STATE.INIT);
7718
+ this.setState(STATE.OPEN);
7728
7719
 
7729
7720
  }
7730
7721
 
@@ -7733,9 +7724,12 @@ class RemoteCore {
7733
7724
  setState(state) {
7734
7725
  this.state = state;
7735
7726
  if (serverOption.debug.showAuthInfo) {
7736
- // let s = state + ":" + CLIENT_STATE[ state]
7737
- this.stateLog.push( state );
7738
- console.log(this.stateLog.join('>'));
7727
+ this.stateLog.push( state + ":" + STATE[ state] );
7728
+ if( state == STATE.AUTH_ACK){
7729
+ console.log('[auth success]', this.cid, this.stateLog.join('>'));
7730
+ }else if( state == STATE.AUTH_FAIL){
7731
+ console.log('[auth_fail]',this.stateLog.join('>'));
7732
+ }
7739
7733
  }
7740
7734
  }
7741
7735
 
@@ -7744,24 +7738,30 @@ class RemoteCore {
7744
7738
  }
7745
7739
 
7746
7740
  getStateName() { // <String>
7747
- return (CLIENT_STATE[this.state]).toLowerCase()
7741
+ return (STATE[this.state]).toLowerCase()
7748
7742
  }
7749
7743
 
7750
7744
 
7751
7745
  showMessageLog(message, isBinary) {
7752
- let from = this.boho.isAuthorized ? `[FROM]did: ${this.did} cid:${this.cid}` : `[FROM]cid:${this.cid}`;
7746
+ let h = '->S ';
7747
+ let from = this.boho.isAuthorized ? ` did: ${this.did} cid: ${this.cid}` : ` cid: ${this.cid}`;
7748
+ let prnLimit = 20;
7753
7749
  if (isBinary) {
7754
7750
  let msgTypeName = IOMsg[message[0]];
7755
7751
  if (!msgTypeName) msgTypeName = tt.BohoMsg[message[0]];
7756
- msgTypeName = ' [' + msgTypeName + ']';
7757
- if (message.byteLength > 40) {
7758
- console.log(from + msgTypeName + ' LEN:', message.length);
7752
+
7753
+ msgTypeName = '[' + msgTypeName + ']';
7754
+ let size = message.byteLength;
7755
+ if (size < prnLimit) {
7756
+ console.log( h + msgTypeName + from +` [${size}]`, message);
7759
7757
  } else {
7760
- console.log(from + msgTypeName, message);
7758
+ let elseLen = size - prnLimit;
7759
+ let some = message.subarray(0,prnLimit);
7760
+ console.log( h + msgTypeName + from +` [${size}]` , some , ' ... else: ', elseLen);
7761
7761
  }
7762
7762
 
7763
7763
  } else {
7764
- console.log(from + ' [TEXT] %s', message);
7764
+ console.log( h + ' [TEXT] %s' + from, message);
7765
7765
  }
7766
7766
  }
7767
7767
 
@@ -7844,7 +7844,7 @@ class RemoteCore {
7844
7844
  break;
7845
7845
 
7846
7846
  case IOMsg.CID_REQ:
7847
- if (this.state < CLIENT_STATE.SENT_SERVER_READY) {
7847
+ if (this.state < STATE.SERVER_READY) {
7848
7848
  // Protocol violation: CID_REQ was sent before receiving the SERVER_READY signal.
7849
7849
  console.log('CID_REQ before SERVER_READY');
7850
7850
  this.close();
@@ -7861,7 +7861,7 @@ class RemoteCore {
7861
7861
  MB('#cid', this.cid)
7862
7862
  ));
7863
7863
 
7864
- this.setState(CLIENT_STATE.CID_READY);
7864
+ this.setState(STATE.CID_RES);
7865
7865
  break;
7866
7866
 
7867
7867
  case IOMsg.ECHO:
@@ -7967,24 +7967,24 @@ class RemoteCore {
7967
7967
  // Auth
7968
7968
  case tt.BohoMsg.AUTH_REQ:
7969
7969
  if (!this.manager.authManager) return
7970
- if (this.state < CLIENT_STATE.SENT_SERVER_READY) {
7970
+ if (this.state < STATE.SERVER_READY) {
7971
7971
  console.log('protocol error. auth_req before server_ready');
7972
7972
  this.close();
7973
7973
  }
7974
- this.setState(CLIENT_STATE.RECV_AUTH_REQ);
7974
+ this.setState(STATE.AUTH_REQ);
7975
7975
  let auth_nonce_pack = this.boho.auth_nonce();
7976
7976
  // console.log('## auth_nonce_pack', auth_nonce_pack )
7977
7977
  this.send(auth_nonce_pack);
7978
- this.setState(CLIENT_STATE.SENT_SERVER_NONCE);
7978
+ this.setState(STATE.AUTH_NONCE);
7979
7979
  break;
7980
7980
 
7981
7981
  case tt.BohoMsg.AUTH_HMAC:
7982
7982
  if (!this.manager.authManager) return
7983
- if (this.state < CLIENT_STATE.SENT_SERVER_NONCE) {
7983
+ if (this.state < STATE.AUTH_NONCE) {
7984
7984
  console.log('protocol error. auth_hmac before server_nonce');
7985
7985
  this.close();
7986
7986
  }
7987
- this.setState(CLIENT_STATE.RECV_AUTH_HMAC);
7987
+ this.setState(STATE.AUTH_HMAC);
7988
7988
  //async
7989
7989
  this.manager.authManager.verify_auth_hmac(message, this)
7990
7990
  .then(authInfo => {
@@ -8134,11 +8134,42 @@ function isPrivateIP(ip) {
8134
8134
  return false
8135
8135
  }
8136
8136
 
8137
+ function numberWithCommas(x) {
8138
+ return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
8139
+ }
8140
+
8137
8141
  function getIPv4HexString(ipStr) {
8138
8142
  let ipv4 = ipStr.split('.');
8139
8143
  return Buffer.from(ipv4).toString('hex')
8140
8144
  }
8141
8145
 
8146
+ function getLocalAddress() {
8147
+ const nets = networkInterfaces();
8148
+ // console.log(nets)
8149
+ const results = Object.create(null); // Or just '{}', an empty object
8150
+ let localAddress = '';
8151
+ for (const name of Object.keys(nets)) {
8152
+ for (const net of nets[name]) {
8153
+ // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
8154
+ // 'IPv4' is in Node <= 17, from 18 it's a number 4 or 6
8155
+ const familyV4Value = typeof net.family === 'string' ? 'IPv4' : 4;
8156
+ if (net.family === familyV4Value && !net.internal) {
8157
+ if (!results[name]) {
8158
+ results[name] = [];
8159
+ }
8160
+ results[name].push(net.address);
8161
+ localAddress = net.address;
8162
+ }
8163
+ }
8164
+ }
8165
+
8166
+ // console.log('localAddress:', localAddress)
8167
+ return localAddress
8168
+ }
8169
+
8170
+
8171
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
8172
+
8142
8173
  const decoder$2 = new TextDecoder();
8143
8174
 
8144
8175
  class Remote extends RemoteCore {
@@ -8310,6 +8341,7 @@ class Remote extends RemoteCore {
8310
8341
  }
8311
8342
  }
8312
8343
 
8344
+ // node.js server side remote.
8313
8345
  send(message, isBinary) {
8314
8346
  this.manager.txBytes += message.byteLength;
8315
8347
  this.socket.txCounter++;
@@ -8321,13 +8353,15 @@ class Remote extends RemoteCore {
8321
8353
  this.socket.send(message);
8322
8354
  }
8323
8355
  } else {
8356
+ console.log('server(ws)Remote.send() called. not open state. current readyState:', this.socket.readyState );
8324
8357
  this.close(true);
8325
8358
  }
8326
-
8359
+
8327
8360
  } else { //CongSocket
8328
8361
  if (this.socket.readyState == 'open') {
8329
8362
  this.socket.write(pack(message));
8330
8363
  } else {
8364
+ console.log('server(cong)Remote.send() called. not open state. current readyState:', this.socket.readyState );
8331
8365
  this.close(true);
8332
8366
  }
8333
8367
  }
@@ -8583,7 +8617,7 @@ class Manager {
8583
8617
  let remote = new Remote(socket, req, this);
8584
8618
  this.remotes.add(remote);
8585
8619
  remote.send(Buffer.from([IOMsg.SERVER_READY]));
8586
- remote.setState(CLIENT_STATE.SENT_SERVER_READY);
8620
+ remote.setState(STATE.SERVER_READY);
8587
8621
  this.lastSSID = remote.ssid;
8588
8622
  let connectionInfo = `+ IP:${remote.ip} #${remote.ssid} ${socket.socketType === 'websocket' ? "WS" : "CS"} `;
8589
8623
  // console.log( connectionInfo)
@@ -8698,8 +8732,8 @@ class Manager {
8698
8732
 
8699
8733
  sender(tag, remote, message) {
8700
8734
  if (serverOption.membersOnly && !remote.boho.isAuthorized) {
8701
- console.log("[membersOnly] unAuthorized remote.",tag );
8702
- remote.send(Buffer.from([IOMsg.SERVER_CLEAR_AUTH]));
8735
+ // console.log("### server reject client signal reason: [membersOnly]" ,tag, remote.cid )
8736
+ remote.send(Buffer.from([IOMsg.AUTH_CLEAR]));
8703
8737
  remote.close();
8704
8738
  return ['err', 'unAuthorized']
8705
8739
  }
@@ -9027,7 +9061,7 @@ class Server extends require$$0$3 {
9027
9061
 
9028
9062
  this.wss.once('listening', () => {
9029
9063
  this.port = this.wss.address().port;
9030
- console.log('wss server bound port:', this.port );
9064
+ // console.log('wss server bound port:', this.port );
9031
9065
  this.listeningServerCount++;
9032
9066
  if (this.listeningServerCount === this.serverCountToListen) {
9033
9067
  this.emit('ready');
@@ -9043,7 +9077,7 @@ class Server extends require$$0$3 {
9043
9077
  });
9044
9078
 
9045
9079
  this.wss.on('close', () => {
9046
- console.log('### WS server is closed.');
9080
+ // console.log('### WS server is closed.')
9047
9081
  });
9048
9082
 
9049
9083
  this.wss.on('connection', (ws, req) => {
@@ -9064,10 +9098,10 @@ class Server extends require$$0$3 {
9064
9098
  process.exit();
9065
9099
  }
9066
9100
  }).on('close', () => {
9067
- console.log('### congsocket server is closed.');
9101
+ // console.log('### congsocket server is closed.')
9068
9102
  }).listen(this.congPort, () => {
9069
9103
  this.congPort = this.congServer.address().port;
9070
- console.log('congsocket server bound port:', this.congPort );
9104
+ // console.log('congsocket server bound port:', this.congPort );
9071
9105
  this.listeningServerCount++;
9072
9106
  if (this.listeningServerCount === this.serverCountToListen) {
9073
9107
  this.emit('ready');
@@ -9102,7 +9136,7 @@ class Server extends require$$0$3 {
9102
9136
  return
9103
9137
  }
9104
9138
  if( api.commands.includes( req.topic )){
9105
- console.log('server api req', req );
9139
+ // console.log('server api req', req )
9106
9140
  await api.request(remote, req);
9107
9141
  }else {
9108
9142
  remote.response(req.mid, STATUS.ERROR, "UNKNOWN_COMMAND");
@@ -9132,7 +9166,7 @@ class Server extends require$$0$3 {
9132
9166
  });
9133
9167
  }
9134
9168
  this.apiNames.add(target);
9135
- console.log(`[API registed: ${target} ] accept commands: ${api.commands}`);
9169
+ // console.log(`[API registed: ${target} ] accept commands: ${api.commands}`)
9136
9170
  return this
9137
9171
  }
9138
9172
 
@@ -9172,7 +9206,7 @@ class Server extends require$$0$3 {
9172
9206
 
9173
9207
  if (this.congServer) {
9174
9208
  this.congServer.close((err) => {
9175
- if (err) console.error('congServer close error', err);
9209
+ // if (err) console.error('congServer close error', err)
9176
9210
  // console.log('cong server closed.')
9177
9211
  onClosed();
9178
9212
  });
@@ -9183,7 +9217,12 @@ class Server extends require$$0$3 {
9183
9217
 
9184
9218
  const decoder = new TextDecoder();
9185
9219
  class BohoAuth {
9186
- constructor() {
9220
+ constructor(keyProvider) {
9221
+ if (!keyProvider) {
9222
+ throw new Error('BohoAuth must be initialized with a keyProvider.');
9223
+ }
9224
+ this.keyProvider = keyProvider;
9225
+
9187
9226
  this.authLogger;
9188
9227
  if (serverOption.fileLogger.auth.use) {
9189
9228
  this.authLogger = new FileLogger(serverOption.fileLogger.auth.path);
@@ -9197,11 +9236,11 @@ class BohoAuth {
9197
9236
  this.authLogger.log(peerInfo);
9198
9237
  }
9199
9238
  // console.log('##### AUTH_FAIL reason: ', reason)
9200
- peer.setState(CLIENT_STATE.AUTH_FAIL);
9239
+ peer.setState(STATE.AUTH_FAIL);
9240
+ peer.send(Buffer.from([tt.BohoMsg.AUTH_FAIL]));
9201
9241
  // add some delay time.
9202
- setTimeout(e => {
9203
- peer.send(Buffer.from([tt.BohoMsg.AUTH_FAIL]));
9204
- }, serverOption.auth.delay_auth_fail);
9242
+ // setTimeout(e => {
9243
+ // }, serverOption.auth.delay_auth_fail)
9205
9244
  }
9206
9245
 
9207
9246
  async verify_auth_hmac(auth_hmac, peer) {
@@ -9222,7 +9261,7 @@ class BohoAuth {
9222
9261
  }
9223
9262
 
9224
9263
  //2. get key of id from DB
9225
- let authInfo = await this.getAuth(id);
9264
+ let authInfo = await this.keyProvider.getAuth(id);
9226
9265
 
9227
9266
  if (!authInfo) {
9228
9267
  this.send_auth_fail(peer, 'NO ID:' + id);
@@ -9273,9 +9312,13 @@ class BohoAuth {
9273
9312
  console.log('## trying RELOGIN with SAME ID. ignored.');
9274
9313
  return
9275
9314
  }
9276
- console.log('### clear_auth and close old connection:', old.cid);
9277
- old.send(Buffer.from([IOMsg.SERVER_CLEAR_AUTH]));
9278
- old.close();
9315
+ console.log('### DUPLICATE_LOGIN detected.', old.cid);
9316
+ let sigPack = M$1.pack(
9317
+ M$1.MB('#MsgType', '8', IOMsg.AUTH_CLEAR),
9318
+ M$1.MB('#reason', 'duplicate login.')
9319
+ );
9320
+ old.send( sigPack);
9321
+ // old.close() client will close and stop.
9279
9322
  peer.close(); // auto relogin
9280
9323
  return
9281
9324
  }
@@ -9322,7 +9365,7 @@ class BohoAuth {
9322
9365
  // console.log("LOGIN: ", `id: ${ peer.did}(${peer.cid})` )
9323
9366
  //10. send ack.
9324
9367
  peer.send(auth_ack);
9325
- peer.setState(CLIENT_STATE.AUTH_READY);
9368
+ peer.setState(STATE.AUTH_ACK);
9326
9369
  if (this.authLogger) {
9327
9370
  let peerInfo = `OK #${peer.ssid} cid: ${peer.cid} did:${peer.did}`;
9328
9371
  if (peer.isAdmin) peerInfo = "#ADMIN# " + peerInfo;
@@ -9335,12 +9378,39 @@ class BohoAuth {
9335
9378
 
9336
9379
  }
9337
9380
 
9381
+ async getAuth(id) {
9382
+ return this.keyProvider.getAuth(id);
9383
+ }
9384
+
9385
+ async getAuthIdList() {
9386
+ if (typeof this.keyProvider.getAuthIdList === 'function') {
9387
+ return this.keyProvider.getAuthIdList();
9388
+ }
9389
+ }
9390
+
9391
+ async addAuth(id, keyStr, cid, level = 0) {
9392
+ if (typeof this.keyProvider.addAuth === 'function') {
9393
+ return this.keyProvider.addAuth(id, keyStr, cid, level);
9394
+ }
9395
+ }
9396
+
9397
+ async delAuth(id) {
9398
+ if (typeof this.keyProvider.delAuth === 'function') {
9399
+ return this.keyProvider.delAuth(id);
9400
+ }
9401
+ }
9402
+
9403
+ async save() {
9404
+ if (typeof this.keyProvider.save === 'function') {
9405
+ return this.keyProvider.save();
9406
+ }
9407
+ }
9408
+
9338
9409
 
9339
9410
  }
9340
9411
 
9341
- class Auth_File extends BohoAuth {
9412
+ class FileKeyProvider {
9342
9413
  constructor(_path) {
9343
- super();
9344
9414
  this.AUTH = new Map();
9345
9415
  let pathObj = path.parse(_path);
9346
9416
  this.path = path.resolve(_path);
@@ -9358,20 +9428,9 @@ class Auth_File extends BohoAuth {
9358
9428
  }
9359
9429
  }
9360
9430
 
9361
-
9362
- async getAuth(id) {
9363
- return this.AUTH.get(id)
9364
- }
9365
-
9366
- async getAuthIdList() {
9367
- return Array.from(this.AUTH.keys())
9368
- }
9369
-
9370
9431
  //loaded when server start.
9371
9432
  loadAuthInfoFile_JS(path) {
9372
-
9373
9433
  import(path).then((file) => {
9374
-
9375
9434
  console.log(file.authInfo);
9376
9435
  file.authInfo.forEach(item => {
9377
9436
  this.addAuth(...item);
@@ -9380,8 +9439,6 @@ class Auth_File extends BohoAuth {
9380
9439
  }).catch(e => {
9381
9440
  console.log(e);
9382
9441
  });
9383
-
9384
-
9385
9442
  }
9386
9443
 
9387
9444
  loadAuthInfoFile_JSON(path) {
@@ -9392,81 +9449,12 @@ class Auth_File extends BohoAuth {
9392
9449
  this.addAuth(...item);
9393
9450
  });
9394
9451
  console.log('total AUTH INFO size: ', this.AUTH.size);
9395
-
9396
- }
9397
-
9398
- addAuth(id, keyStr, cid, level = 0) {
9399
- let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
9400
- this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
9401
- }
9402
-
9403
-
9404
-
9405
- }
9406
-
9407
- /**
9408
- * Auth_Env.js
9409
- *
9410
- * You can use environment variable BOHO_AUTH.
9411
- *
9412
- * BOHO_AUTH=id1.key1.level,id2:key2.level
9413
- *
9414
- * or constructor parameter.
9415
- *
9416
- *
9417
- * [ authInfo ]
9418
- * id: <String> max 8chars
9419
- * key: <String>
9420
- * level: <Numbrer> range: 0~255
9421
- * separator: ','
9422
- *
9423
- * example => process.env.BOHO_AUTH=id1.key1.255,id2.key2.200
9424
- */
9425
-
9426
-
9427
- class Auth_Env extends BohoAuth {
9428
- constructor(authInfo) {
9429
- super();
9430
- let id_keys;
9431
- if (authInfo) {
9432
- id_keys = authInfo.split(',');
9433
- } else if (process.env.BOHO_AUTH) {
9434
- authInfo = process.env.BOHO_AUTH;
9435
- id_keys = process.env.BOHO_AUTH.split(',');
9436
- } else {
9437
- console.log("Auth_Env: None of process.env.BOHO_AUTH or authInfo");
9438
- process.exit();
9439
- }
9440
-
9441
- this.AUTH = new Map();
9442
-
9443
- if (id_keys.length >= 1) {
9444
- id_keys.forEach(v => {
9445
-
9446
- let did = v.split('.')[0];
9447
- let key = v.split('.')[1];
9448
- let level = v.split('.')[2];
9449
- level = parseInt(level);
9450
-
9451
- if (did && key && typeof level == 'number') {
9452
- let cid = did;
9453
- this.addAuth(did, key, cid, level);
9454
- } else {
9455
- console.log("Wrong process.env.BOHO_AUTH authentication value.", id, key, level);
9456
- process.exit();
9457
- }
9458
- });
9459
-
9460
- } else {
9461
- console.log("Wrong process.env.BOHO_AUTH authentication value.");
9462
- process.exit();
9463
- }
9464
-
9465
9452
  }
9466
9453
 
9467
9454
  async getAuth(id) {
9468
9455
  return this.AUTH.get(id)
9469
9456
  }
9457
+
9470
9458
  async getAuthIdList() {
9471
9459
  return Array.from(this.AUTH.keys())
9472
9460
  }
@@ -9475,16 +9463,14 @@ class Auth_Env extends BohoAuth {
9475
9463
  let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
9476
9464
  this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
9477
9465
  }
9478
-
9479
9466
  }
9480
9467
 
9481
9468
  const DEVICE_PREFIX = "device:";
9482
9469
 
9483
- class Auth_Redis extends BohoAuth {
9470
+ class RedisKeyProvider {
9484
9471
  constructor(redisClient) {
9485
- super();
9486
9472
  if (!redisClient) {
9487
- throw new Error("AuthRedis constructor: no redisClient")
9473
+ throw new Error("RedisKeyProvider constructor: no redisClient")
9488
9474
  }
9489
9475
  this.redis = redisClient;
9490
9476
  }
@@ -9493,7 +9479,8 @@ class Auth_Redis extends BohoAuth {
9493
9479
  async getAuth(id) {
9494
9480
  try {
9495
9481
  let result = await this.redis.hGetAll(DEVICE_PREFIX + id);
9496
- if (result.key) return result
9482
+ if (result && result.key) return result
9483
+ else return null;
9497
9484
  } catch (error) {
9498
9485
  console.log('getAuth', error);
9499
9486
  }
@@ -9522,7 +9509,60 @@ class Auth_Redis extends BohoAuth {
9522
9509
  async save(id) {
9523
9510
  return this.redis.save()
9524
9511
  }
9512
+ }
9513
+
9514
+ /**
9515
+ * StringKeyProvider.js
9516
+ *
9517
+ * authInfo <String>
9518
+ * id: max 8chars
9519
+ * key: ~44 base64 chars recomended
9520
+ * cid:
9521
+ * level: range: 0~255
9522
+ * separator: ',' for multiple devices.
9523
+ *
9524
+ * example => authInfo = 'id1.key1.cid1.255,id2.key2.cid2.200'
9525
+ */
9526
+
9527
+
9528
+ class StringKeyProvider {
9529
+ constructor(authInfo) {
9530
+
9531
+ if (!authInfo) {
9532
+ throw TypeError("StringKeyProvider constructor() missing authInfo.")
9533
+ }
9534
+
9535
+ let id_keys = authInfo.split(',');
9536
+
9537
+ this.AUTH = new Map();
9538
+
9539
+ if (id_keys.length >= 1) {
9540
+ id_keys.forEach(v => {
9541
+ let [ did, key, cid, level ] = v.split('.');
9542
+ level = parseInt(level);
9543
+ if (did && key && cid && typeof level == 'number') {
9544
+ this.addAuth(did, key, cid, level);
9545
+ } else {
9546
+ throw TypeError("StringKeyProvider invalid authInfo.")
9547
+ }
9548
+ });
9549
+ } else {
9550
+ throw TypeError("StringKeyProvider invalid authInfo.")
9551
+ }
9552
+
9553
+ }
9525
9554
 
9555
+ async getAuth(id) {
9556
+ return this.AUTH.get(id)
9557
+ }
9558
+ async getAuthIdList() {
9559
+ return Array.from(this.AUTH.keys())
9560
+ }
9561
+
9562
+ addAuth(id, keyStr, cid, level = 0) {
9563
+ let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
9564
+ this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
9565
+ }
9526
9566
  }
9527
9567
 
9528
9568
  const commands$1 = ['echo', 'date', 'unixtime'];
@@ -9707,4 +9747,4 @@ class RedisAPI {
9707
9747
 
9708
9748
  const version = pkg.version;
9709
9749
 
9710
- export { API_TYPE, Auth_Env, Auth_File, Auth_Redis, tt as Boho, BohoAuth, CLIENT_STATE, CongRx, ENC_MODE, FileLogger, IOWS as IO, IOCongSocket, IOMsg, M$1 as MBP, PAYLOAD_TYPE, RedisAPI, SIZE_LIMIT, STATES, STATUS$1 as STATUS, Server, api_reply, api_sudo, getPayloadFromSignalPack, getSignalPack, pack, parsePayload, serverOption, version };
9750
+ 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 };