iosignal 4.8.0 → 5.0.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.
@@ -77,6 +77,7 @@ export class IOCore extends EventEmitter<string | symbol, any> {
77
77
  * @type {Boho}
78
78
  */
79
79
  boho: Boho;
80
+ serverTimeNonce: any;
80
81
  /**
81
82
  * Indicates if the connection is TLS (wss).
82
83
  * @type {boolean}
@@ -74,6 +74,6 @@ export default class IO extends IOCore {
74
74
  socket_send(data: BufferSource): void;
75
75
  }
76
76
  export type Boho = import("boho").Boho;
77
- export type MBP = any;
77
+ export type MBP = typeof import("meta-buffer-pack");
78
78
  export type Buffer = import("boho").Buffer;
79
79
  import { IOCore } from "../IOCore.js";
@@ -2,11 +2,14 @@ export type STATE = {
2
2
  CONNECTING: number;
3
3
  OPEN: number;
4
4
  SERVER_READY: number;
5
- AUTH_ACK: number;
6
- CLOSING: number;
7
- READY: number;
5
+ AUTH_REQ: number;
6
+ AUTH_RES: number;
8
7
  AUTH_FAIL: number;
9
8
  AUTH_CLEAR: number;
9
+ CID_REQ: number;
10
+ CID_RES: number;
11
+ READY: number;
12
+ CLOSING: number;
10
13
  CLOSED: number;
11
14
  STOP: number;
12
15
  REDIRECTING: number;
@@ -16,9 +19,7 @@ export namespace STATE {
16
19
  let OPEN: number;
17
20
  let SERVER_READY: number;
18
21
  let AUTH_REQ: number;
19
- let AUTH_NONCE: number;
20
- let AUTH_HMAC: number;
21
- let AUTH_ACK: number;
22
+ let AUTH_RES: number;
22
23
  let AUTH_FAIL: number;
23
24
  let AUTH_CLEAR: number;
24
25
  let CID_REQ: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iosignal",
3
- "version": "4.8.0",
3
+ "version": "5.0.0",
4
4
  "description": "iosignal",
5
5
  "type": "module",
6
6
  "exports": {
@@ -37,7 +37,7 @@
37
37
  "typescript": "^5.8.3"
38
38
  },
39
39
  "dependencies": {
40
- "boho": "^1.1.1",
40
+ "boho": "^2.0.0",
41
41
  "eventemitter3": "^5.0.1",
42
42
  "meta-buffer-pack": "^2.1.0",
43
43
  "ws": "^8.18.3"
@@ -12,7 +12,7 @@ export class BohoAuth {
12
12
  throw new Error('BohoAuth must be initialized with a keyProvider.');
13
13
  }
14
14
  this.keyProvider = keyProvider;
15
-
15
+ this.keepOldConnection = true;
16
16
  this.authLogger;
17
17
  if (serverOption.fileLogger.auth.use) {
18
18
  this.authLogger = new FileLogger(serverOption.fileLogger.auth.path)
@@ -27,42 +27,40 @@ export class BohoAuth {
27
27
  }
28
28
  // console.log('##### AUTH_FAIL reason: ', reason)
29
29
  peer.setState(STATE.AUTH_FAIL)
30
- peer.send(Buffer.from([Boho.BohoMsg.AUTH_FAIL]))
31
30
  // add some delay time.
32
- // setTimeout(e => {
33
- // }, serverOption.auth.delay_auth_fail)
31
+ setTimeout(e => {
32
+ peer.send(Buffer.from([Boho.BohoMsg.AUTH_FAIL]))
33
+ }, serverOption.auth.delay_auth_fail)
34
34
  }
35
35
 
36
- async verify_auth_hmac(auth_hmac, peer) {
36
+
37
+ async verify_auth_req(auth_req, peer) {
37
38
  try {
38
39
  //1. unpack
39
- let infoPack = MBP.unpack(auth_hmac, Boho.Meta.AUTH_HMAC)
40
-
40
+ let infoPack = MBP.unpack(auth_req, Boho.Meta.AUTH_REQ)
41
41
  if (!infoPack) {
42
42
  this.send_auth_fail(peer, 'unpack auth_pack fail');
43
43
  return
44
44
  }
45
-
45
+
46
46
  let id = ""
47
47
  if (infoPack.id8.includes(0)) {
48
48
  id = decoder.decode(infoPack.id8.subarray(0, infoPack.id8.indexOf(0)));
49
49
  } else {
50
50
  id = decoder.decode(infoPack.id8);
51
51
  }
52
-
52
+
53
53
  //2. get key of id from DB
54
54
  let authInfo = await this.keyProvider.getAuth(id)
55
-
56
55
  if (!authInfo) {
57
56
  this.send_auth_fail(peer, 'NO ID:' + id);
58
57
  return
59
58
  }
60
59
 
61
60
  if (serverOption.debug.showAuthInfo) {
62
- console.log('[debug]showAuthInfo',authInfo )
61
+ console.log('[debug]showAuthInfo', authInfo)
63
62
  }
64
63
 
65
- // console.log('db authInfo.key: ', authInfo.key)
66
64
  peer.boho.copy_id8(infoPack.id8)
67
65
  // type of key
68
66
  let authKey;
@@ -77,46 +75,47 @@ export class BohoAuth {
77
75
  }
78
76
 
79
77
  //3. check hmac
80
- // console.log('-- found: authKey of id: ', id, authKey.toString('hex'))
81
- let auth_ack = peer.boho.check_auth_hmac(infoPack)
82
-
83
- // console.log('auth_ack', auth_ack )
84
- if (!auth_ack) {
78
+ let auth_res = peer.boho.verify_auth_req(infoPack)
79
+ if (!auth_res) {
85
80
  this.send_auth_fail(peer, 'hmac dismatched');
86
81
  return
87
82
  }
88
83
 
89
84
  //4. get info
90
- // console.log('#### auth success' )
91
85
 
92
86
  //5. check duplicate login.
93
- // current policy. Deny duplicate login
94
-
95
- // duplicate login policy.
96
- // 1. send clear_auth signal to the old connection.
97
- // 2. close old connection.
98
- // 3. close new connection. retry from begining.
99
87
  if (peer.manager.cid2remote.has(authInfo.cid)) {
100
88
  let old = peer.manager.cid2remote.get(authInfo.cid)
89
+ console.log('[WARN]DUPLICATE_LOGIN detected.', old.cid)
90
+ old.ping(); // check the connection.
101
91
  if (old == peer) {
102
- console.log('## trying RELOGIN with SAME ID. ignored.')
92
+ console.log('## trying to RELOGIN after login.')
103
93
  return
104
94
  }
105
- console.log('### DUPLICATE_LOGIN detected.', old.cid)
106
- let sigPack = MBP.pack(
95
+
96
+ let authClearSignal = MBP.pack(
107
97
  MBP.MB('#MsgType', '8', IOMsg.AUTH_CLEAR),
108
98
  MBP.MB('#reason', 'duplicate login.')
109
99
  )
110
- old.send( sigPack)
111
- // old.close() client will close and stop.
112
- peer.close() // auto relogin
100
+ if (this.keepOldConnection) { // default true
101
+ // keep old connection. reject new connection by sending auth_fail signal.
102
+ // peer.send(authClearSignal)
103
+ if( peer.socketType == 'websocket'){
104
+ this.send_auth_fail(peer, 'duplicate login')
105
+ }else{
106
+ peer.close(); //arduino
107
+ }
108
+ } else {
109
+ // accept new connection. stop the old connection by sending auth_clear signal.
110
+ old.send(authClearSignal)
111
+ peer.close()
112
+ }
113
113
  return
114
114
  }
115
115
 
116
-
117
- //6. delete current (temp rand)cid if exist.
116
+ //6. delete current (or anonymouse)cid if exist.
118
117
  if (peer.cid) {
119
- console.log('duplicate cid')
118
+ // console.log('if peer has cid', peer.cid)
120
119
  peer.manager.cid2remote.delete(peer.cid)
121
120
  }
122
121
 
@@ -124,7 +123,7 @@ export class BohoAuth {
124
123
  peer.did = id
125
124
  peer.cid = authInfo.cid
126
125
  peer.nick = authInfo.cid // temporary: nick as cid
127
- if( authInfo.uid ) peer.uid = authInfo.uid
126
+ if (authInfo.uid) peer.uid = authInfo.uid
128
127
 
129
128
  //8. setting quota level.
130
129
  let quotaLevel = serverOption.defaultQuotaIndex;
@@ -133,7 +132,6 @@ export class BohoAuth {
133
132
  let newQuota = quotaTable[quotaLevel];
134
133
  if (!newQuota) {
135
134
  let err = 'no index quotaTable for auth.level: ' + quotaLevel
136
- console.log('##AUTH:DATA ERROR##', err)
137
135
  this.send_auth_fail(peer, err);
138
136
  return
139
137
  } else {
@@ -145,17 +143,14 @@ export class BohoAuth {
145
143
  console.log('## LOGIN ADMIN CID:', peer.cid)
146
144
  peer.isAdmin = true;
147
145
  }
148
- // console.log('auth: peer.quota', peer.quota )
149
146
  // send quota.level
150
147
  peer.send(Buffer.from([IOMsg.QUOTA_LEVEL, quotaLevel]))
151
148
 
152
149
  //9. set cid2remote
153
150
  peer.manager.cid2remote.set(peer.cid, peer)
154
- // console.log( 'done: cid2remote:', peer.manager.cid2remote.keys() )
155
- // console.log("LOGIN: ", `id: ${ peer.did}(${peer.cid})` )
156
151
  //10. send ack.
157
- peer.send(auth_ack)
158
- peer.setState(STATE.AUTH_ACK)
152
+ peer.send(auth_res)
153
+ peer.setState(STATE.AUTH_RES)
159
154
  if (this.authLogger) {
160
155
  let peerInfo = `OK #${peer.ssid} cid: ${peer.cid} did:${peer.did}`
161
156
  if (peer.isAdmin) peerInfo = "#ADMIN# " + peerInfo
@@ -163,9 +158,9 @@ export class BohoAuth {
163
158
  }
164
159
  return authInfo
165
160
  } catch (error) {
161
+ console.log('verify_auth_req error', error)
166
162
  this.send_auth_fail(peer, '[BohoAuth]caught: unknown error:' + error);
167
163
  }
168
-
169
164
  }
170
165
 
171
166
  async getAuth(id) {
@@ -114,6 +114,8 @@ export class IOCore extends EventEmitter {
114
114
  * @type {Boho}
115
115
  */
116
116
  this.boho = new Boho()
117
+
118
+ this.serverTimeNonce = Buffer.alloc( Boho.MetaSize.SERVER_TIME_NONCE );
117
119
  /**
118
120
  * Indicates if the connection is TLS (wss).
119
121
  * @type {boolean}
@@ -246,6 +248,7 @@ export class IOCore extends EventEmitter {
246
248
  stop() {
247
249
  this.autoReconnect = false;
248
250
  this.close();
251
+ this.cid = ''
249
252
  this.stateChange('stop','stop');
250
253
  }
251
254
 
@@ -344,10 +347,13 @@ export class IOCore extends EventEmitter {
344
347
  * @returns {this}
345
348
  */
346
349
  login(id, key) {
347
- this.auth(id, key)
348
- this.useAuth = true
349
- let auth_pack = this.boho.auth_req()
350
- this.send(auth_pack)
350
+ if( this.serverTimeNonce ){
351
+ console.log('iosignal.login serverTimeNonce', this.serverTimeNonce)
352
+ this.auth(id, key)
353
+ this.useAuth = true
354
+ let auth_pack = this.boho.auth_req(this.serverTimeNonce )
355
+ this.send(auth_pack)
356
+ }
351
357
  return this
352
358
  }
353
359
 
@@ -496,12 +502,15 @@ export class IOCore extends EventEmitter {
496
502
  this.redirect(url)
497
503
  break;
498
504
 
499
- case IOMsg.SERVER_READY:
505
+ case Boho.BohoMsg.SERVER_TIME_NONCE: // SERVER_READY
500
506
  this.stateChange('server_ready', 'server_ready')
501
507
  if (this.useAuth) {
502
- this.send(this.boho.auth_req())
503
- // CID_REQ will be called, after auth_ack.
508
+ this.send(this.boho.auth_req(buffer))
509
+ this.stateChange('auth_req','auth_req')
510
+ // CID_REQ will be called, after auth_res.
504
511
  } else {
512
+ // keep server_time_nonce for manual login()
513
+ buffer.copy( this.serverTimeNonce);
505
514
  // CID_REQ here, if not using auth.
506
515
  this.send(Buffer.from([IOMsg.CID_REQ]))
507
516
  }
@@ -548,6 +557,7 @@ export class IOCore extends EventEmitter {
548
557
  > cid_sub message: tag includes cid and @ both : 'cid@*'
549
558
  > ch_sub message: else.
550
559
  */
560
+ // console.log('payloadType', payloadType )
551
561
  switch (payloadType) {
552
562
 
553
563
  case PAYLOAD_TYPE.EMPTY:
@@ -567,7 +577,7 @@ export class IOCore extends EventEmitter {
567
577
  }
568
578
  let oneString = decoder.decode(payloadStringWithoutNull)
569
579
  if (tag.indexOf('@') === 0) this.emit('@', tag, oneString)
570
- if (tag !== '@') {
580
+ else {
571
581
  this.emit(tag, tag, oneString)
572
582
  this.emit('message', tag, oneString)
573
583
  }
@@ -575,7 +585,7 @@ export class IOCore extends EventEmitter {
575
585
 
576
586
  case PAYLOAD_TYPE.BINARY:
577
587
  if (tag.indexOf('@') === 0) this.emit('@', tag, payloadBuffer)
578
- if (tag !== '@') {
588
+ else {
579
589
  this.emit(tag, tag, payloadBuffer)
580
590
  this.emit('message', tag, payloadBuffer)
581
591
  }
@@ -585,7 +595,7 @@ export class IOCore extends EventEmitter {
585
595
  let oneObjectBuffer = decoder.decode(payloadBuffer)
586
596
  let oneJSONObject = JSON.parse(oneObjectBuffer)
587
597
  if (tag.indexOf('@') === 0) this.emit('@', tag, oneJSONObject)
588
- if (tag !== '@') {
598
+ else {
589
599
  this.emit(tag, tag, oneJSONObject)
590
600
  this.emit('message', tag, oneJSONObject)
591
601
  }
@@ -595,7 +605,7 @@ export class IOCore extends EventEmitter {
595
605
  let mjsonBuffer = decoder.decode(payloadBuffer)
596
606
  let mjson = JSON.parse(mjsonBuffer)
597
607
  if (tag.indexOf('@') === 0) this.emit('@', tag, ...mjson)
598
- if (tag !== '@') {
608
+ else {
599
609
  this.emit(tag, tag, ...mjson)
600
610
  this.emit('message', tag, ...mjson)
601
611
  }
@@ -604,7 +614,7 @@ export class IOCore extends EventEmitter {
604
614
  case PAYLOAD_TYPE.MBA:
605
615
  let mbaObject = MBP.unpack(payloadBuffer)
606
616
  if (tag.indexOf('@') === 0) this.emit('@', tag, ...mbaObject.args)
607
- if (tag !== '@') {
617
+ else {
608
618
  this.emit(tag, tag, ...mbaObject.args)
609
619
  this.emit('message', tag, ...mbaObject.args)
610
620
  }
@@ -624,26 +634,16 @@ export class IOCore extends EventEmitter {
624
634
  this.testPromise(buffer)
625
635
  break;
626
636
 
627
- case Boho.BohoMsg.AUTH_NONCE:
628
- this.stateChange('auth_nonce','server sent auth_nonce.')
629
- let auth_hmac = this.boho.auth_hmac(buffer)
630
- if (auth_hmac) {
631
- this.send(auth_hmac)
632
- } else {
633
- this.stateChange('auth_fail', 'boho.auth_hmac() invalid auth_nonce.')
634
- }
635
- break;
636
-
637
637
  case Boho.BohoMsg.AUTH_FAIL:
638
638
  this.stateChange('auth_fail', 'auth_fail from server.')
639
639
  break;
640
640
 
641
- case Boho.BohoMsg.AUTH_ACK:
642
- if (this.boho.check_auth_ack_hmac(buffer)) {
643
- this.stateChange('auth_ack', 'server sent auth_ack')
641
+ case Boho.BohoMsg.AUTH_RES:
642
+ if (this.boho.verify_auth_res(buffer)) {
643
+ this.stateChange('auth_res', 'server sent auth_res')
644
644
  this.send(Buffer.from([IOMsg.CID_REQ]))
645
645
  } else {
646
- this.stateChange('auth_fail', 'check_auth_ack_hmac() invalid server_hmac')
646
+ this.stateChange('auth_fail', 'verify_auth_res() invalid server_hmac')
647
647
  }
648
648
  break;
649
649
 
@@ -871,6 +871,7 @@ export class IOCore extends EventEmitter {
871
871
  */
872
872
  signal_e2e(tag, data, key) {
873
873
 
874
+ if( !this.boho.isAuthorized ) return;
874
875
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
875
876
  let tagEncoded = encoder.encode(tag)
876
877
  let dataPack = MBP.B8(data)
@@ -4,11 +4,13 @@
4
4
  * @property {number} CONNECTING
5
5
  * @property {number} OPEN
6
6
  * @property {number} SERVER_READY
7
- * @property {number} AUTH_ACK
8
- * @property {number} CLOSING
9
- * @property {number} READY
7
+ * @property {number} AUTH_REQ
8
+ * @property {number} AUTH_RES
10
9
  * @property {number} AUTH_FAIL
11
10
  * @property {number} AUTH_CLEAR
11
+ * @property {number} CID_REQ
12
+ * @property {number} CID_RES
13
+ * @property {number} READY
12
14
  * @property {number} CLOSING
13
15
  * @property {number} CLOSED
14
16
  * @property {number} STOP
@@ -20,11 +22,10 @@ export const STATE = {
20
22
  OPEN: 1,
21
23
  SERVER_READY: 10,
22
24
  AUTH_REQ: 11,
23
- AUTH_NONCE: 12,
24
- AUTH_HMAC: 13,
25
- AUTH_ACK: 14,
26
- AUTH_FAIL: 15,
27
- AUTH_CLEAR: 16,
25
+ AUTH_RES: 12,
26
+ AUTH_FAIL: 13,
27
+ AUTH_CLEAR: 14,
28
+
28
29
  CID_REQ: 17,
29
30
  CID_RES: 18,
30
31
  READY: 19,
@@ -139,15 +140,7 @@ export let IOMsg = {
139
140
 
140
141
  // DO NOT USE: 0xB0~ 0xBF
141
142
  // Boho module using this numbers.
142
- // AUTH_REQ : 0xB0,
143
- // AUTH_NONCE: 0xB1,
144
- // AUTH_HMAC: 0xB2,
145
- // AUTH_ACK: 0xB3,
146
- // AUTH_FAIL: 0xB4,
147
- // AUTH_EXT: 0xB5,
148
- // ENC_PACK : 0xB6,
149
- // ENC_E2E : 0xB7,
150
- // ENC_488 : 0xB8
143
+
151
144
  // reserved ~0xBF
152
145
 
153
146
  // C. IO status contorl.
@@ -4,7 +4,7 @@ import { serverOption } from './serverOption.js'
4
4
  import { IOMsg, STATE } from '../common/constants.js'
5
5
  import { getSignalPack } from '../common/payload.js';
6
6
  import { FileLogger } from './FileLogger.js'
7
- import { Metric } from './Metric.js'
7
+ import { Metrics } from './Metrics.js'
8
8
 
9
9
  const encoder = new TextEncoder()
10
10
  const decoder = new TextDecoder()
@@ -36,7 +36,7 @@ export class Manager {
36
36
  this.channel_map = new Map() // key: channelName -> value: < remote : Set >
37
37
  this.CHANNEL_PREFIX = 'CH:'
38
38
  this.CID_PREFIX = 'CID:'
39
- this.metric = new Metric(this)
39
+ this.metrics = new Metrics(this)
40
40
  this.lastSSID = 0;
41
41
 
42
42
  this.pingIntervalID = setInterval(e => {
@@ -72,7 +72,7 @@ export class Manager {
72
72
  socket.isAlive = true;
73
73
  let remote = new Remote(socket, req, this)
74
74
  this.remotes.add(remote)
75
- remote.send(Buffer.from([IOMsg.SERVER_READY]))
75
+ remote.send( remote.boho.server_time_nonce() )
76
76
  remote.setState(STATE.SERVER_READY)
77
77
  this.lastSSID = remote.ssid;
78
78
  let connectionInfo = `+ IP:${remote.ip} #${remote.ssid} ${socket.socketType === 'websocket' ? "WS" : "CS"} `;
@@ -402,18 +402,18 @@ export class Manager {
402
402
  }
403
403
 
404
404
  if (serverOption.showChannel > 0) {
405
- this.metric.channels(serverOption.showChannel);
405
+ this.metrics.channels(serverOption.showChannel);
406
406
  }
407
407
  let mode = parseInt(serverOption.showMetric)
408
408
  switch (mode) {
409
409
  case 1:
410
- this.metric.oneline(true);
410
+ this.metrics.oneline(true);
411
411
  break;
412
412
  case 2:
413
- this.metric.getRemotes(true);
413
+ this.metrics.getRemotes(true);
414
414
  break;
415
415
  case 3:
416
- this.metric.getChannelList(true);
416
+ this.metrics.getChannelList(true);
417
417
  break;
418
418
  default:
419
419
  }
@@ -0,0 +1,155 @@
1
+ import { memoryUsage } from 'process';
2
+ import { ENC_MODE } from '../common/constants.js'
3
+
4
+ const MAX = 10
5
+ let period = 10000
6
+
7
+ export class Metrics {
8
+ constructor(manager) {
9
+ this.manager = manager;
10
+
11
+ this.metricsPack = {
12
+ remotes: [0],
13
+ channels: [0],
14
+ txBytes: [0],
15
+ rxBytes: [0],
16
+ unixTime: [Math.floor(Date.now() / 1000)],
17
+ period: 0
18
+ }
19
+
20
+ this.tickId = setInterval(e => {
21
+
22
+ this.metricsPack.remotes.push(this.manager.remotes.size)
23
+ if (this.metricsPack.remotes.length > MAX) this.metricsPack.remotes.shift()
24
+
25
+ this.metricsPack.channels.push(this.manager.channel_map.size)
26
+ if (this.metricsPack.channels.length > MAX) this.metricsPack.channels.shift()
27
+
28
+
29
+ this.metricsPack.txBytes.push(this.manager.txBytes)
30
+ if (this.metricsPack.txBytes.length > MAX) this.metricsPack.txBytes.shift()
31
+
32
+ this.metricsPack.rxBytes.push(this.manager.rxBytes)
33
+ if (this.metricsPack.rxBytes.length > MAX) this.metricsPack.rxBytes.shift()
34
+
35
+ this.metricsPack.unixTime = Math.floor(Date.now() / 1000)
36
+ this.metricsPack.period = period;
37
+ this.manager.txBytes = 0
38
+ this.manager.rxBytes = 0
39
+
40
+
41
+ }, 10000)
42
+ }
43
+
44
+
45
+
46
+ oneline(prn) {
47
+ let memoryUse = memoryUsage();
48
+ let memoryInfo = [{
49
+ ...memoryUse
50
+ }]
51
+
52
+ if (prn) console.table(memoryInfo, ['rss', 'heapTotal', 'heapUsed', 'external', 'arrayBuffers']);
53
+
54
+ let metric = [{
55
+ lastSSID: this.manager.lastSSID,
56
+ remotes: this.manager.remotes.size,
57
+ channels: this.manager.channel_map.size,
58
+ txBytes: this.manager.txBytes,
59
+ rxBytes: this.manager.rxBytes,
60
+ }]
61
+
62
+ if (prn) console.table(metric, ['lastSSID', 'remotes', 'channels', 'txBytes', 'rxBytes']);
63
+
64
+ return metric[0]
65
+ }
66
+
67
+ getRemotes(prn) {
68
+ let remoteList = Array.from(this.manager.remotes.values())
69
+ let remoteStates = remoteList.map(v => {
70
+ return "#" + v.ssid + ":" + v.cid + "(" + v.state + ")"
71
+ })
72
+ if (prn) console.table(remoteStates)
73
+ return remoteStates
74
+ }
75
+
76
+ getCIdList(prn) {
77
+ let CIdList = Array.from(this.manager.cid2remote.keys())
78
+ if (prn) console.table(CIdList)
79
+ return CIdList
80
+ }
81
+
82
+ getChannelList(prn) {
83
+ let chList = Array.from(this.manager.channel_map.keys())
84
+ if (prn) console.table(chList)
85
+ return chList
86
+ }
87
+
88
+ getSubscribers(ch) {
89
+ let list = [];
90
+ if (this.manager.channel_map.has(ch)) {
91
+ let subscribers = this.manager.channel_map.get(ch) //set
92
+ subscribers.forEach(c => {
93
+ list.push(c.cid)
94
+ })
95
+ }
96
+ // console.log(list)
97
+ return list
98
+ }
99
+
100
+ getRemoteByCId(cid, mode = 1) {
101
+
102
+ if (this.manager.cid2remote.has(cid)) {
103
+ let remote = this.manager.cid2remote.get(cid)
104
+ if (mode == 1) {
105
+ return {
106
+ ip: remote.ip,
107
+ id: remote.cid,
108
+ ssid: remote.ssid,
109
+ cid: remote.cid,
110
+ uid: remote.uid,
111
+ uptime: Math.trunc((Date.now() - remote.socket.openTime) / 1000),
112
+ tx: remote.socket.txCounter,
113
+ rx: remote.socket.rxCounter,
114
+ txBytes: remote.socket.bytesWritten || remote.socket._socket?.bytesWritten,
115
+ rxBytes: remote.socket.bytesRead || remote.socket._socket?.bytesRead
116
+ }
117
+ } else if (mode == 2) {
118
+ return {
119
+ ip: remote.ip,
120
+ uptime: Math.trunc((Date.now() - remote.socket.openTime) / 1000),
121
+ nick: remote.nick,
122
+ ssid: remote.ssid
123
+ }
124
+ } else if (mode == 3) {
125
+ return {
126
+ ip: remote.ip,
127
+ uptime: Math.trunc((Date.now() - remote.socket.openTime) / 1000),
128
+ nick: remote.nick,
129
+ ssid: remote.ssid,
130
+ isSecure: remote.TLS,
131
+ isAuth: remote.boho.isAuthorized,
132
+ encMode: ENC_MODE[remote.encMode]
133
+ }
134
+ } else if (mode == 4) {
135
+ let channels = Array.from(remote.channels.keys())
136
+ let set_memory = Array.from(remote.memory.keys())
137
+ let retain_signal = Array.from(remote.retain_signal.keys())
138
+ return {
139
+ ip: remote.ip,
140
+ uptime: Math.trunc((Date.now() - remote.socket.openTime) / 1000),
141
+ channels: channels,
142
+ set: set_memory,
143
+ retain: retain_signal
144
+ }
145
+ }
146
+
147
+ } else {
148
+ return { result: "nop" }
149
+ }
150
+
151
+ }
152
+
153
+
154
+ }
155
+