iosignal 4.0.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/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.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} 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
@@ -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: 3000,
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} SERVER_CLEAR_AUTH
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
- SERVER_CLEAR_AUTH: 0xC4,
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').STATES} STATES
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 = STATES.CLOSED; // Number type
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
- stop() {
1025
- this.autoReconnect = false;
1026
- this.close();
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 {boolean}
1107
+ * @returns {this}
1120
1108
  */
1121
1109
  login(id, key) {
1122
- if (!this.auth(id, key)) return false;
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 true
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 {boolean}
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 true
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,7 +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
- this.emit('iam_res', str );
1212
+ this.emit('iam_res', str);
1228
1213
  } catch (error) {
1229
1214
  this.emit('error', new Error('IAM_RES data error'));
1230
1215
  }
@@ -1235,22 +1220,22 @@ class IOCore extends EventEmitter {
1235
1220
  this.cid = cidStr;
1236
1221
 
1237
1222
  // **IMPORTANT** change state before subscribe.
1238
- this.stateChange('ready', 'cid_ready');
1239
- this.subscribe_memory_channels();
1223
+ this.stateChange('ready', 'cid_ready');
1224
+ this.subscribe_memory_channels(); // tags registered by listen() or link().
1240
1225
  break;
1241
1226
 
1242
1227
  case IOMsg.QUOTA_LEVEL:
1243
1228
  let quotaLevel = buffer[1];
1244
1229
  this.level = quotaLevel;
1245
1230
  this.quota = quotaTable[quotaLevel];
1246
- console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota));
1231
+ // console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota))
1247
1232
  break;
1248
1233
 
1249
- case IOMsg.SERVER_CLEAR_AUTH:
1234
+ case IOMsg.AUTH_CLEAR:
1250
1235
  this.useAuth = false;
1251
1236
  this.boho.clearAuth();
1237
+ this.stateChange('auth_clear', 'server request auth_clear.');
1252
1238
  this.stop();
1253
- console.log('[SERVER_CLEAR_AUTH] io stop.');
1254
1239
  break;
1255
1240
 
1256
1241
  case IOMsg.SERVER_REDIRECT:
@@ -1327,7 +1312,7 @@ class IOCore extends EventEmitter {
1327
1312
  if (tag.indexOf('@') === 0) this.emit('@', tag, null);
1328
1313
  else {
1329
1314
  this.emit(tag, tag, null);
1330
- this.emit('message', tag, null );
1315
+ this.emit('message', tag, null);
1331
1316
  }
1332
1317
  break;
1333
1318
 
@@ -1340,7 +1325,7 @@ class IOCore extends EventEmitter {
1340
1325
  }
1341
1326
  let oneString = decoder$4.decode(payloadStringWithoutNull);
1342
1327
  if (tag.indexOf('@') === 0) this.emit('@', tag, oneString);
1343
- if (tag !== '@'){
1328
+ if (tag !== '@') {
1344
1329
  this.emit(tag, tag, oneString);
1345
1330
  this.emit('message', tag, oneString);
1346
1331
  }
@@ -1348,39 +1333,39 @@ class IOCore extends EventEmitter {
1348
1333
 
1349
1334
  case PAYLOAD_TYPE.BINARY:
1350
1335
  if (tag.indexOf('@') === 0) this.emit('@', tag, payloadBuffer);
1351
- if (tag !== '@'){
1336
+ if (tag !== '@') {
1352
1337
  this.emit(tag, tag, payloadBuffer);
1353
1338
  this.emit('message', tag, payloadBuffer);
1354
- }
1339
+ }
1355
1340
  break;
1356
1341
 
1357
1342
  case PAYLOAD_TYPE.OBJECT:
1358
1343
  let oneObjectBuffer = decoder$4.decode(payloadBuffer);
1359
1344
  let oneJSONObject = JSON.parse(oneObjectBuffer);
1360
1345
  if (tag.indexOf('@') === 0) this.emit('@', tag, oneJSONObject);
1361
- if (tag !== '@'){
1346
+ if (tag !== '@') {
1362
1347
  this.emit(tag, tag, oneJSONObject);
1363
1348
  this.emit('message', tag, oneJSONObject);
1364
- }
1349
+ }
1365
1350
  break;
1366
1351
 
1367
1352
  case PAYLOAD_TYPE.MJSON:
1368
1353
  let mjsonBuffer = decoder$4.decode(payloadBuffer);
1369
1354
  let mjson = JSON.parse(mjsonBuffer);
1370
1355
  if (tag.indexOf('@') === 0) this.emit('@', tag, ...mjson);
1371
- if (tag !== '@'){
1356
+ if (tag !== '@') {
1372
1357
  this.emit(tag, tag, ...mjson);
1373
1358
  this.emit('message', tag, ...mjson);
1374
- }
1359
+ }
1375
1360
  break;
1376
1361
 
1377
1362
  case PAYLOAD_TYPE.MBA:
1378
1363
  let mbaObject = M$1.unpack(payloadBuffer);
1379
1364
  if (tag.indexOf('@') === 0) this.emit('@', tag, ...mbaObject.args);
1380
- if (tag !== '@'){
1365
+ if (tag !== '@') {
1381
1366
  this.emit(tag, tag, ...mbaObject.args);
1382
- this.emit('message', tag, ...mbaObject.args );
1383
- }
1367
+ this.emit('message', tag, ...mbaObject.args);
1368
+ }
1384
1369
  break;
1385
1370
 
1386
1371
  default:
@@ -1388,7 +1373,8 @@ class IOCore extends EventEmitter {
1388
1373
  }
1389
1374
 
1390
1375
  } catch (err) {
1391
- this.emit('error', new Error('signal parse err'));
1376
+ // this.emit('error', new Error('IOCore IOMsg.SIGNAL parser err', err))
1377
+ console.log('IOCore IOMsg.SIGNAL parser err', err);
1392
1378
  }
1393
1379
  break;
1394
1380
 
@@ -1397,24 +1383,25 @@ class IOCore extends EventEmitter {
1397
1383
  break;
1398
1384
 
1399
1385
  case tt.BohoMsg.AUTH_NONCE:
1386
+ this.stateChange('auth_nonce','server sent auth_nonce.');
1400
1387
  let auth_hmac = this.boho.auth_hmac(buffer);
1401
1388
  if (auth_hmac) {
1402
1389
  this.send(auth_hmac);
1403
1390
  } else {
1404
- this.stateChange('auth_fail', 'Invalid local auth_hmac.');
1391
+ this.stateChange('auth_fail', 'boho.auth_hmac() invalid auth_nonce.');
1405
1392
  }
1406
1393
  break;
1407
1394
 
1408
1395
  case tt.BohoMsg.AUTH_FAIL:
1409
- this.stateChange('auth_fail', 'server reject auth.');
1396
+ this.stateChange('auth_fail', 'auth_fail from server.');
1410
1397
  break;
1411
1398
 
1412
1399
  case tt.BohoMsg.AUTH_ACK:
1413
1400
  if (this.boho.check_auth_ack_hmac(buffer)) {
1414
- this.stateChange('auth_ready', 'server sent auth_ack');
1401
+ this.stateChange('auth_ack', 'server sent auth_ack');
1415
1402
  this.send(Buffer$1.from([IOMsg.CID_REQ]));
1416
1403
  } else {
1417
- this.stateChange('auth_fail', 'invalid server_hmac');
1404
+ this.stateChange('auth_fail', 'check_auth_ack_hmac() invalid server_hmac');
1418
1405
  }
1419
1406
  break;
1420
1407
 
@@ -1601,14 +1588,15 @@ class IOCore extends EventEmitter {
1601
1588
 
1602
1589
 
1603
1590
  /**
1604
- * Publishes a signal.
1591
+ * alias of signal()
1592
+ * Sends a signal with a tag and arguments.
1593
+ * @param {string} tag - The signal tag.
1605
1594
  * @param {...any} args - Arguments for the signal.
1606
1595
  */
1607
- publish(...args) {
1608
- this.signal(...args);
1596
+ publish(tag, ...args) {
1597
+ this.signal(tag, ...args);
1609
1598
  }
1610
1599
 
1611
-
1612
1600
  /**
1613
1601
  * Sends a signal with a tag and arguments.
1614
1602
  * @param {string} tag - The signal tag.
@@ -1617,7 +1605,6 @@ class IOCore extends EventEmitter {
1617
1605
  */
1618
1606
  signal(tag, ...args) {
1619
1607
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1620
-
1621
1608
  let signalPack = getSignalPack(tag, ...args);
1622
1609
  this.send_enc_mode(signalPack);
1623
1610
  }
@@ -1661,7 +1648,6 @@ class IOCore extends EventEmitter {
1661
1648
  }
1662
1649
 
1663
1650
 
1664
-
1665
1651
  /**
1666
1652
  * Sets a value in the store.
1667
1653
  * @param {string} storeName - The name of the store.
@@ -1729,8 +1715,8 @@ class IOCore extends EventEmitter {
1729
1715
  */
1730
1716
  subscribe(tag) {
1731
1717
  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
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
1734
1720
 
1735
1721
  // subscribe 사용시, 사용 'ready' 이벤트시 메뉴얼 등록되므로 여기에 등록하면 2중 호출된다.
1736
1722
  // 즉, channels 등록은 listen 같은 자동화 구독시만 사용.
@@ -1739,7 +1725,7 @@ class IOCore extends EventEmitter {
1739
1725
  // this.channels.add(tag)
1740
1726
  // })
1741
1727
 
1742
- try {
1728
+ try {
1743
1729
  let tagEncoded = encoder$1.encode(tag);
1744
1730
  this.send_enc_mode(
1745
1731
  Buffer$1.concat([
@@ -1759,12 +1745,12 @@ class IOCore extends EventEmitter {
1759
1745
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1760
1746
  if (tag.length > SIZE_LIMIT.TAG_LEN2) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN2)
1761
1747
 
1762
- if (this.state !== STATES.READY) {
1748
+ if (this.state !== STATE.READY) {
1763
1749
  return Promise.reject('subscribe_promise:: connection is not ready')
1764
1750
  }
1765
1751
 
1766
1752
  try {
1767
- let tagEncoded = encoder$1.encode(tag);
1753
+ let tagEncoded = encoder$1.encode(tag);
1768
1754
  this.send_enc_mode(
1769
1755
  Buffer$1.concat([
1770
1756
  M$1.NB('8', IOMsg.SUBSCRIBE_REQ),
@@ -1834,7 +1820,7 @@ class IOCore extends EventEmitter {
1834
1820
  }
1835
1821
  this.on(tag, handler);
1836
1822
  // do not subscribe now.
1837
- // will subscribe when receive CID_RES signal from server.
1823
+ // will subscribe when io state is 'ready'. (receive CID_RES from server)
1838
1824
 
1839
1825
  }
1840
1826
 
@@ -1945,10 +1931,10 @@ class IOCore extends EventEmitter {
1945
1931
  */
1946
1932
  getStateName() {
1947
1933
  //state <number>
1948
- //value of constant STATES.NAME < number >
1949
- //type of constant STATES.NAME name < string uppercase >
1934
+ //value of constant STATE.NAME < number >
1935
+ //type of constant STATE.NAME name < string uppercase >
1950
1936
  //stateName,eventName <string lowercase>
1951
- return (STATES[this.state]).toLowerCase()
1937
+ return (STATE[this.state]).toLowerCase()
1952
1938
  }
1953
1939
 
1954
1940
  /**
@@ -1976,14 +1962,14 @@ class IOCore extends EventEmitter {
1976
1962
  * 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
1977
1963
  */
1978
1964
  stateChange(state, emitEventAndMessage) {
1979
- // STATES constant name <string> upperCase
1965
+ // STATE constant name <string> upperCase
1980
1966
  // eventName and .stateName <string> lowerCase
1981
1967
  // .state <number>
1982
1968
  // console.log('### stateChange reason:', emitEventAndMessage )
1983
1969
  let eventName = state.toLowerCase();
1984
- this.state = STATES[state.toUpperCase()]; // state: number
1970
+ this.state = STATE[state.toUpperCase()]; // state: number
1985
1971
 
1986
- if (emitEventAndMessage){
1972
+ if (emitEventAndMessage) {
1987
1973
  this.emit(eventName, emitEventAndMessage);
1988
1974
  }
1989
1975
 
@@ -2163,8 +2149,10 @@ class IOCongSocket extends IOCore {
2163
2149
  keepAlive() {
2164
2150
  if (!this.autoReconnect) return;
2165
2151
  // Reconnect only if the socket is fully destroyed and the state is closed.
2166
- if ((!this.socket || this.socket.destroyed) && this.state === STATES.CLOSED) {
2152
+ if ((!this.socket || this.socket.destroyed)) {
2167
2153
  this.open();
2154
+ }else {
2155
+ this.ping();
2168
2156
  }
2169
2157
  }
2170
2158
 
@@ -2176,7 +2164,7 @@ class IOCongSocket extends IOCore {
2176
2164
  urlObj = new URL('cong://' + url);
2177
2165
  }
2178
2166
  this.socket = net.createConnection(urlObj.port, urlObj.hostname);
2179
- this.stateChange('opening');
2167
+ this.stateChange('connecting','connecting');
2180
2168
 
2181
2169
  this.socket.on('connect', () => {
2182
2170
  this.congRx = new CongRx();
@@ -7590,15 +7578,17 @@ class IOWS extends IOCore {
7590
7578
  keepAlive() {
7591
7579
  if (!this.autoReconnect) return;
7592
7580
  // 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) {
7581
+ if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) ) {
7594
7582
  this.open();
7583
+ }else {
7584
+ this.ping();
7595
7585
  }
7596
7586
  }
7597
7587
 
7598
7588
  createConnection(url) {
7599
7589
  // node WebSocket
7600
7590
  this.socket = new WebSocket(url);
7601
- this.stateChange('opening');
7591
+ this.stateChange('connecting','connecting');
7602
7592
 
7603
7593
  this.socket.onopen = () => {
7604
7594
  this.socket.on('message', this.onWebSocketMessage.bind(this));
@@ -7724,7 +7714,7 @@ class RemoteCore {
7724
7714
 
7725
7715
  this.state;
7726
7716
  this.stateLog = [];
7727
- this.setState(CLIENT_STATE.INIT);
7717
+ this.setState(STATE.OPEN);
7728
7718
 
7729
7719
  }
7730
7720
 
@@ -7733,7 +7723,7 @@ class RemoteCore {
7733
7723
  setState(state) {
7734
7724
  this.state = state;
7735
7725
  if (serverOption.debug.showAuthInfo) {
7736
- // let s = state + ":" + CLIENT_STATE[ state]
7726
+ state = state + ":" + STATE[ state];
7737
7727
  this.stateLog.push( state );
7738
7728
  console.log(this.stateLog.join('>'));
7739
7729
  }
@@ -7744,24 +7734,30 @@ class RemoteCore {
7744
7734
  }
7745
7735
 
7746
7736
  getStateName() { // <String>
7747
- return (CLIENT_STATE[this.state]).toLowerCase()
7737
+ return (STATE[this.state]).toLowerCase()
7748
7738
  }
7749
7739
 
7750
7740
 
7751
7741
  showMessageLog(message, isBinary) {
7752
- let from = this.boho.isAuthorized ? `[FROM]did: ${this.did} cid:${this.cid}` : `[FROM]cid:${this.cid}`;
7742
+ let h = '->S ';
7743
+ let from = this.boho.isAuthorized ? ` did: ${this.did} cid: ${this.cid}` : ` cid: ${this.cid}`;
7744
+ let prnLimit = 20;
7753
7745
  if (isBinary) {
7754
7746
  let msgTypeName = IOMsg[message[0]];
7755
7747
  if (!msgTypeName) msgTypeName = tt.BohoMsg[message[0]];
7756
- msgTypeName = ' [' + msgTypeName + ']';
7757
- if (message.byteLength > 40) {
7758
- console.log(from + msgTypeName + ' LEN:', message.length);
7748
+
7749
+ msgTypeName = '[' + msgTypeName + ']';
7750
+ let size = message.byteLength;
7751
+ if (size < prnLimit) {
7752
+ console.log( h + msgTypeName + from +` [${size}]`, message);
7759
7753
  } else {
7760
- console.log(from + msgTypeName, message);
7754
+ let elseLen = size - prnLimit;
7755
+ let some = message.subarray(0,prnLimit);
7756
+ console.log( h + msgTypeName + from +` [${size}]` , some , ' ... else: ', elseLen);
7761
7757
  }
7762
7758
 
7763
7759
  } else {
7764
- console.log(from + ' [TEXT] %s', message);
7760
+ console.log( h + ' [TEXT] %s' + from, message);
7765
7761
  }
7766
7762
  }
7767
7763
 
@@ -7844,7 +7840,7 @@ class RemoteCore {
7844
7840
  break;
7845
7841
 
7846
7842
  case IOMsg.CID_REQ:
7847
- if (this.state < CLIENT_STATE.SENT_SERVER_READY) {
7843
+ if (this.state < STATE.SERVER_READY) {
7848
7844
  // Protocol violation: CID_REQ was sent before receiving the SERVER_READY signal.
7849
7845
  console.log('CID_REQ before SERVER_READY');
7850
7846
  this.close();
@@ -7861,7 +7857,7 @@ class RemoteCore {
7861
7857
  MB('#cid', this.cid)
7862
7858
  ));
7863
7859
 
7864
- this.setState(CLIENT_STATE.CID_READY);
7860
+ this.setState(STATE.CID_RES);
7865
7861
  break;
7866
7862
 
7867
7863
  case IOMsg.ECHO:
@@ -7967,24 +7963,24 @@ class RemoteCore {
7967
7963
  // Auth
7968
7964
  case tt.BohoMsg.AUTH_REQ:
7969
7965
  if (!this.manager.authManager) return
7970
- if (this.state < CLIENT_STATE.SENT_SERVER_READY) {
7966
+ if (this.state < STATE.SERVER_READY) {
7971
7967
  console.log('protocol error. auth_req before server_ready');
7972
7968
  this.close();
7973
7969
  }
7974
- this.setState(CLIENT_STATE.RECV_AUTH_REQ);
7970
+ this.setState(STATE.AUTH_REQ);
7975
7971
  let auth_nonce_pack = this.boho.auth_nonce();
7976
7972
  // console.log('## auth_nonce_pack', auth_nonce_pack )
7977
7973
  this.send(auth_nonce_pack);
7978
- this.setState(CLIENT_STATE.SENT_SERVER_NONCE);
7974
+ this.setState(STATE.AUTH_NONCE);
7979
7975
  break;
7980
7976
 
7981
7977
  case tt.BohoMsg.AUTH_HMAC:
7982
7978
  if (!this.manager.authManager) return
7983
- if (this.state < CLIENT_STATE.SENT_SERVER_NONCE) {
7979
+ if (this.state < STATE.AUTH_NONCE) {
7984
7980
  console.log('protocol error. auth_hmac before server_nonce');
7985
7981
  this.close();
7986
7982
  }
7987
- this.setState(CLIENT_STATE.RECV_AUTH_HMAC);
7983
+ this.setState(STATE.AUTH_HMAC);
7988
7984
  //async
7989
7985
  this.manager.authManager.verify_auth_hmac(message, this)
7990
7986
  .then(authInfo => {
@@ -8134,11 +8130,42 @@ function isPrivateIP(ip) {
8134
8130
  return false
8135
8131
  }
8136
8132
 
8133
+ function numberWithCommas(x) {
8134
+ return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
8135
+ }
8136
+
8137
8137
  function getIPv4HexString(ipStr) {
8138
8138
  let ipv4 = ipStr.split('.');
8139
8139
  return Buffer.from(ipv4).toString('hex')
8140
8140
  }
8141
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
+
8142
8169
  const decoder$2 = new TextDecoder();
8143
8170
 
8144
8171
  class Remote extends RemoteCore {
@@ -8310,6 +8337,7 @@ class Remote extends RemoteCore {
8310
8337
  }
8311
8338
  }
8312
8339
 
8340
+ // node.js server side remote.
8313
8341
  send(message, isBinary) {
8314
8342
  this.manager.txBytes += message.byteLength;
8315
8343
  this.socket.txCounter++;
@@ -8321,13 +8349,15 @@ class Remote extends RemoteCore {
8321
8349
  this.socket.send(message);
8322
8350
  }
8323
8351
  } else {
8352
+ console.log('server(ws)Remote.send() called. not open state. current readyState:', this.socket.readyState );
8324
8353
  this.close(true);
8325
8354
  }
8326
-
8355
+
8327
8356
  } else { //CongSocket
8328
8357
  if (this.socket.readyState == 'open') {
8329
8358
  this.socket.write(pack(message));
8330
8359
  } else {
8360
+ console.log('server(cong)Remote.send() called. not open state. current readyState:', this.socket.readyState );
8331
8361
  this.close(true);
8332
8362
  }
8333
8363
  }
@@ -8583,7 +8613,7 @@ class Manager {
8583
8613
  let remote = new Remote(socket, req, this);
8584
8614
  this.remotes.add(remote);
8585
8615
  remote.send(Buffer.from([IOMsg.SERVER_READY]));
8586
- remote.setState(CLIENT_STATE.SENT_SERVER_READY);
8616
+ remote.setState(STATE.SERVER_READY);
8587
8617
  this.lastSSID = remote.ssid;
8588
8618
  let connectionInfo = `+ IP:${remote.ip} #${remote.ssid} ${socket.socketType === 'websocket' ? "WS" : "CS"} `;
8589
8619
  // console.log( connectionInfo)
@@ -8698,8 +8728,8 @@ class Manager {
8698
8728
 
8699
8729
  sender(tag, remote, message) {
8700
8730
  if (serverOption.membersOnly && !remote.boho.isAuthorized) {
8701
- console.log("[membersOnly] unAuthorized remote.",tag );
8702
- remote.send(Buffer.from([IOMsg.SERVER_CLEAR_AUTH]));
8731
+ // console.log("### server reject client signal reason: [membersOnly]" ,tag, remote.cid )
8732
+ remote.send(Buffer.from([IOMsg.AUTH_CLEAR]));
8703
8733
  remote.close();
8704
8734
  return ['err', 'unAuthorized']
8705
8735
  }
@@ -9027,7 +9057,7 @@ class Server extends require$$0$3 {
9027
9057
 
9028
9058
  this.wss.once('listening', () => {
9029
9059
  this.port = this.wss.address().port;
9030
- console.log('wss server bound port:', this.port );
9060
+ // console.log('wss server bound port:', this.port );
9031
9061
  this.listeningServerCount++;
9032
9062
  if (this.listeningServerCount === this.serverCountToListen) {
9033
9063
  this.emit('ready');
@@ -9043,7 +9073,7 @@ class Server extends require$$0$3 {
9043
9073
  });
9044
9074
 
9045
9075
  this.wss.on('close', () => {
9046
- console.log('### WS server is closed.');
9076
+ // console.log('### WS server is closed.')
9047
9077
  });
9048
9078
 
9049
9079
  this.wss.on('connection', (ws, req) => {
@@ -9064,10 +9094,10 @@ class Server extends require$$0$3 {
9064
9094
  process.exit();
9065
9095
  }
9066
9096
  }).on('close', () => {
9067
- console.log('### congsocket server is closed.');
9097
+ // console.log('### congsocket server is closed.')
9068
9098
  }).listen(this.congPort, () => {
9069
9099
  this.congPort = this.congServer.address().port;
9070
- console.log('congsocket server bound port:', this.congPort );
9100
+ // console.log('congsocket server bound port:', this.congPort );
9071
9101
  this.listeningServerCount++;
9072
9102
  if (this.listeningServerCount === this.serverCountToListen) {
9073
9103
  this.emit('ready');
@@ -9102,7 +9132,7 @@ class Server extends require$$0$3 {
9102
9132
  return
9103
9133
  }
9104
9134
  if( api.commands.includes( req.topic )){
9105
- console.log('server api req', req );
9135
+ // console.log('server api req', req )
9106
9136
  await api.request(remote, req);
9107
9137
  }else {
9108
9138
  remote.response(req.mid, STATUS.ERROR, "UNKNOWN_COMMAND");
@@ -9132,7 +9162,7 @@ class Server extends require$$0$3 {
9132
9162
  });
9133
9163
  }
9134
9164
  this.apiNames.add(target);
9135
- console.log(`[API registed: ${target} ] accept commands: ${api.commands}`);
9165
+ // console.log(`[API registed: ${target} ] accept commands: ${api.commands}`)
9136
9166
  return this
9137
9167
  }
9138
9168
 
@@ -9172,7 +9202,7 @@ class Server extends require$$0$3 {
9172
9202
 
9173
9203
  if (this.congServer) {
9174
9204
  this.congServer.close((err) => {
9175
- if (err) console.error('congServer close error', err);
9205
+ // if (err) console.error('congServer close error', err)
9176
9206
  // console.log('cong server closed.')
9177
9207
  onClosed();
9178
9208
  });
@@ -9183,7 +9213,12 @@ class Server extends require$$0$3 {
9183
9213
 
9184
9214
  const decoder = new TextDecoder();
9185
9215
  class BohoAuth {
9186
- constructor() {
9216
+ constructor(keyProvider) {
9217
+ if (!keyProvider) {
9218
+ throw new Error('BohoAuth must be initialized with a keyProvider.');
9219
+ }
9220
+ this.keyProvider = keyProvider;
9221
+
9187
9222
  this.authLogger;
9188
9223
  if (serverOption.fileLogger.auth.use) {
9189
9224
  this.authLogger = new FileLogger(serverOption.fileLogger.auth.path);
@@ -9197,11 +9232,11 @@ class BohoAuth {
9197
9232
  this.authLogger.log(peerInfo);
9198
9233
  }
9199
9234
  // console.log('##### AUTH_FAIL reason: ', reason)
9200
- peer.setState(CLIENT_STATE.AUTH_FAIL);
9235
+ peer.setState(STATE.AUTH_FAIL);
9236
+ peer.send(Buffer.from([tt.BohoMsg.AUTH_FAIL]));
9201
9237
  // add some delay time.
9202
- setTimeout(e => {
9203
- peer.send(Buffer.from([tt.BohoMsg.AUTH_FAIL]));
9204
- }, serverOption.auth.delay_auth_fail);
9238
+ // setTimeout(e => {
9239
+ // }, serverOption.auth.delay_auth_fail)
9205
9240
  }
9206
9241
 
9207
9242
  async verify_auth_hmac(auth_hmac, peer) {
@@ -9222,7 +9257,7 @@ class BohoAuth {
9222
9257
  }
9223
9258
 
9224
9259
  //2. get key of id from DB
9225
- let authInfo = await this.getAuth(id);
9260
+ let authInfo = await this.keyProvider.getAuth(id);
9226
9261
 
9227
9262
  if (!authInfo) {
9228
9263
  this.send_auth_fail(peer, 'NO ID:' + id);
@@ -9273,9 +9308,13 @@ class BohoAuth {
9273
9308
  console.log('## trying RELOGIN with SAME ID. ignored.');
9274
9309
  return
9275
9310
  }
9276
- console.log('### clear_auth and close old connection:', old.cid);
9277
- old.send(Buffer.from([IOMsg.SERVER_CLEAR_AUTH]));
9278
- old.close();
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.
9279
9318
  peer.close(); // auto relogin
9280
9319
  return
9281
9320
  }
@@ -9322,7 +9361,7 @@ class BohoAuth {
9322
9361
  // console.log("LOGIN: ", `id: ${ peer.did}(${peer.cid})` )
9323
9362
  //10. send ack.
9324
9363
  peer.send(auth_ack);
9325
- peer.setState(CLIENT_STATE.AUTH_READY);
9364
+ peer.setState(STATE.AUTH_ACK);
9326
9365
  if (this.authLogger) {
9327
9366
  let peerInfo = `OK #${peer.ssid} cid: ${peer.cid} did:${peer.did}`;
9328
9367
  if (peer.isAdmin) peerInfo = "#ADMIN# " + peerInfo;
@@ -9335,12 +9374,39 @@ class BohoAuth {
9335
9374
 
9336
9375
  }
9337
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
+
9338
9405
 
9339
9406
  }
9340
9407
 
9341
- class Auth_File extends BohoAuth {
9408
+ class FileKeyProvider {
9342
9409
  constructor(_path) {
9343
- super();
9344
9410
  this.AUTH = new Map();
9345
9411
  let pathObj = path.parse(_path);
9346
9412
  this.path = path.resolve(_path);
@@ -9358,20 +9424,9 @@ class Auth_File extends BohoAuth {
9358
9424
  }
9359
9425
  }
9360
9426
 
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
9427
  //loaded when server start.
9371
9428
  loadAuthInfoFile_JS(path) {
9372
-
9373
9429
  import(path).then((file) => {
9374
-
9375
9430
  console.log(file.authInfo);
9376
9431
  file.authInfo.forEach(item => {
9377
9432
  this.addAuth(...item);
@@ -9380,8 +9435,6 @@ class Auth_File extends BohoAuth {
9380
9435
  }).catch(e => {
9381
9436
  console.log(e);
9382
9437
  });
9383
-
9384
-
9385
9438
  }
9386
9439
 
9387
9440
  loadAuthInfoFile_JSON(path) {
@@ -9392,81 +9445,12 @@ class Auth_File extends BohoAuth {
9392
9445
  this.addAuth(...item);
9393
9446
  });
9394
9447
  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
9448
  }
9466
9449
 
9467
9450
  async getAuth(id) {
9468
9451
  return this.AUTH.get(id)
9469
9452
  }
9453
+
9470
9454
  async getAuthIdList() {
9471
9455
  return Array.from(this.AUTH.keys())
9472
9456
  }
@@ -9475,16 +9459,14 @@ class Auth_Env extends BohoAuth {
9475
9459
  let Base64hashKey = Buffer.from(tt.sha256.hash(keyStr)).toString('base64');
9476
9460
  this.AUTH.set(id, { key: Base64hashKey, cid: cid, level: level });
9477
9461
  }
9478
-
9479
9462
  }
9480
9463
 
9481
9464
  const DEVICE_PREFIX = "device:";
9482
9465
 
9483
- class Auth_Redis extends BohoAuth {
9466
+ class RedisKeyProvider {
9484
9467
  constructor(redisClient) {
9485
- super();
9486
9468
  if (!redisClient) {
9487
- throw new Error("AuthRedis constructor: no redisClient")
9469
+ throw new Error("RedisKeyProvider constructor: no redisClient")
9488
9470
  }
9489
9471
  this.redis = redisClient;
9490
9472
  }
@@ -9493,7 +9475,8 @@ class Auth_Redis extends BohoAuth {
9493
9475
  async getAuth(id) {
9494
9476
  try {
9495
9477
  let result = await this.redis.hGetAll(DEVICE_PREFIX + id);
9496
- if (result.key) return result
9478
+ if (result && result.key) return result
9479
+ else return null;
9497
9480
  } catch (error) {
9498
9481
  console.log('getAuth', error);
9499
9482
  }
@@ -9522,7 +9505,60 @@ class Auth_Redis extends BohoAuth {
9522
9505
  async save(id) {
9523
9506
  return this.redis.save()
9524
9507
  }
9508
+ }
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
+ }
9525
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
+ }
9526
9562
  }
9527
9563
 
9528
9564
  const commands$1 = ['echo', 'date', 'unixtime'];
@@ -9707,4 +9743,4 @@ class RedisAPI {
9707
9743
 
9708
9744
  const version = pkg.version;
9709
9745
 
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 };
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 };