iosignal 0.0.1 → 1.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.
Files changed (47) hide show
  1. package/README.md +170 -0
  2. package/auth_file.json +13 -0
  3. package/auth_file.mjs +23 -0
  4. package/dist/iosignal.cjs +2 -0
  5. package/dist/iosignal.esm.js +3 -0
  6. package/dist/iosignal.esm.js.map +1 -0
  7. package/dist/iosignal.min.js +3 -0
  8. package/dist/iosignal.min.js.map +1 -0
  9. package/img/iosignal_stack.png +0 -0
  10. package/index.js +19 -0
  11. package/indexWebBrowser.js +13 -0
  12. package/package.json +48 -6
  13. package/rollup.config.js +69 -0
  14. package/src/api/RedisAPI.js +68 -0
  15. package/src/api/api_constant.js +7 -0
  16. package/src/api/api_reply.js +34 -0
  17. package/src/api/api_sudo.js +96 -0
  18. package/src/auth/Auth_Env.js +78 -0
  19. package/src/auth/Auth_File.js +75 -0
  20. package/src/auth/Auth_Redis.js +50 -0
  21. package/src/auth/BohoAuth.js +168 -0
  22. package/src/client/CongPacket.js +150 -0
  23. package/src/client/IOCongSocket.js +88 -0
  24. package/src/client/IOCore.js +959 -0
  25. package/src/client/IOWS.js +81 -0
  26. package/src/client/IOWebSocket.js +96 -0
  27. package/src/common/constants.js +159 -0
  28. package/src/common/quotaTable.js +61 -0
  29. package/src/common/util.js +61 -0
  30. package/src/server/FileLogger.js +30 -0
  31. package/src/server/Manager.js +521 -0
  32. package/src/server/Metric.js +154 -0
  33. package/src/server/Server.js +136 -0
  34. package/src/server/ServerRemote.js +235 -0
  35. package/src/server/ServerRemoteCore.js +467 -0
  36. package/src/server/serverOption.js +55 -0
  37. package/test-browser/favicon.ico +0 -0
  38. package/test-browser/index.html +93 -0
  39. package/test-browser/server.js +8 -0
  40. package/test-client-nodejs/client.cjs +17 -0
  41. package/test-client-nodejs/client.mjs +17 -0
  42. package/test-server/server-commonjs.cjs +8 -0
  43. package/test-server/server-esm.mjs +19 -0
  44. package/test-server/test-Auth_Env.js +17 -0
  45. package/test-server/test-Auth_File.js +9 -0
  46. package/test-server/test-api_reply.js +10 -0
  47. package/test-server/test-api_sudo.js +11 -0
@@ -0,0 +1,521 @@
1
+ import { MBP } from 'meta-buffer-pack'
2
+ import { ServerRemote } from './ServerRemote.js'
3
+ import { serverOption } from './serverOption.js'
4
+ import { IOMsg, PAYLOAD_TYPE, CLIENT_STATE } from '../common/constants.js'
5
+ import { FileLogger } from './FileLogger.js'
6
+ import { Metric } from './Metric.js'
7
+
8
+ const encoder = new TextEncoder()
9
+ const decoder = new TextDecoder()
10
+
11
+ export class Manager{
12
+
13
+ constructor( server, authManager , remoteManager ) {
14
+ this.server = server;
15
+ this.txBytes = 0;
16
+ this.rxBytes = 0;
17
+
18
+ this.authManager = authManager;
19
+ // TIP. authManager module is option.
20
+ // if exist: used by ServerRemoteCore for the auth. process.
21
+
22
+ if(remoteManager ){
23
+ this.remoteManager = remoteManager
24
+ remoteManager.manager = this
25
+ }else{
26
+ this.remoteManager = null
27
+ }
28
+
29
+ this.connectionLogger;
30
+ if (serverOption.fileLogger.connection.use) {
31
+ this.connectionLogger = new FileLogger( serverOption.fileLogger.connection.path)
32
+ console.log('Manager: begin file logger [connection]')
33
+ }
34
+
35
+ this.attackLogger;
36
+ if( serverOption.fileLogger.attack.use ){
37
+ this.attackLogger = new FileLogger( serverOption.fileLogger.attack.path )
38
+ console.log('Manager: begin file logger.[attack]')
39
+ }
40
+
41
+ this.remotes = new Set(); // total ServerRemotes
42
+ this.channel_map = new Map() // key: channelName value: < ServerRemote : Set >
43
+ this.CHANNEL_PREFIX = 'CH:'
44
+ this.CID_PREFIX = 'CID:'
45
+ this.cid2remote = new Map(); // map:[ key:cid -> value:remote ]
46
+ this.retain_messages = new Map() // key: tag, data: signalMessage
47
+ this.metric = new Metric(this)
48
+ this.lastSSID = 0;
49
+
50
+ this.pingIntervalID = setInterval(e => {
51
+ this.remotes.forEach(function each(remo) {
52
+ let socket = remo.socket;
53
+ if (socket.isAlive === false) {
54
+ console.log('## timeout. cid:', remo.cid)
55
+ remo.close();
56
+ }
57
+
58
+ socket.txCounter++;
59
+ socket.isAlive = false;
60
+ if (remo.socketType === 'websocket') {
61
+ socket.ping();
62
+ } else {
63
+ remo.ping()
64
+ }
65
+ // console.log('<< PING')
66
+ });
67
+ }, serverOption.timeout);
68
+
69
+ if (serverOption.showMetric) {
70
+ this.monitIntervalID = setInterval((e) => {
71
+ this.monitor()
72
+ }, serverOption.monitorPeriod);
73
+ }
74
+
75
+
76
+ }
77
+
78
+
79
+ addRemote(socket, req) {
80
+ socket.isAlive = true;
81
+ let remote = new ServerRemote(socket, req, this)
82
+ this.remotes.add(remote)
83
+ remote.send(Buffer.from([IOMsg.SERVER_READY]))
84
+ remote.setState(CLIENT_STATE.SENT_SERVER_READY)
85
+ this.lastSSID = remote.ssid;
86
+ let connectionInfo = `+ IP:${remote.ip} #${remote.ssid} ${socket.socketType === 'websocket' ? "WS" : "CS"} `;
87
+ // console.log( connectionInfo)
88
+ if (this.connectionLogger) this.connectionLogger.log(connectionInfo)
89
+ };
90
+
91
+
92
+ removeRemote(remote) {
93
+ // console.log('#### manager.removeRemote()', remote.cid, remote.uid)
94
+ let remoteInfo = `- IP:${remote.ip} #${remote.ssid} cid:${remote.cid} ${remote?.socket.socketType === 'websocket' ? "WS" : "CS"} `
95
+ if (this.connectionLogger) this.connectionLogger.log(remoteInfo)
96
+ this.deligateSignal(remote, '@state', 'close')
97
+ this.deligateSignal(remote, '@$state', 'close')
98
+
99
+ // remove subscriber
100
+ for (let ch of remote.channels.keys()) {
101
+ if (this.channel_map.has(ch)) {
102
+ const remotes = this.channel_map.get(ch)
103
+ // console.log(`-- channel [ ${ch} ] removes subscriber id: ${remote.cid} `)
104
+ remotes.delete(remote)
105
+ if (remotes.size == 0) this.channel_map.delete(ch)
106
+ }else{
107
+ // console.log('no such a ch: ', ch )
108
+ }
109
+ }
110
+
111
+ // retain message policy
112
+ // type 1. keep if authUser, delete if anonymouse.
113
+ if( remote.boho.isAuthorized ){
114
+ //keep retain signal.
115
+ }else{
116
+ // anonymouse: remove the cid publish channel
117
+ for (let ch of remote.retain_signal.keys()) {
118
+ // console.log('cid retain_signal.keys:', ch )
119
+ ch = this.CID_PREFIX + remote.cid + '@' + ch
120
+ if (this.channel_map.has(ch)) {
121
+ this.channel_map.delete(ch)
122
+ // console.log(`-- deleted cid pub ch [ ${ch} ]. cid publisher id: ${remote.cid} `)
123
+ }else{
124
+ // console.log('no such a retain_signal tag: ', ch )
125
+ }
126
+ }
127
+ }
128
+
129
+
130
+ if( remote.uid && this.server.apiNames.has('account')){
131
+ let req = { topic:'detachUserRemote'}
132
+ req.args = ['caller:manager.removeRemote']
133
+ this.server.emit('account', remote, req )
134
+ }
135
+
136
+ this.remotes.delete(remote)
137
+ this.cid2remote.delete(remote.cid)
138
+ remote = null
139
+
140
+ }
141
+
142
+
143
+
144
+ serverSignal(obj) {
145
+ // obj.event obj.data
146
+ console.log('server signal', obj)
147
+ let sigPack = MBP.pack(
148
+ MBP.MB('#MsgType', '8', IOMsg.SERVER_SIGNAL),
149
+ MBP.MB('#signalObject', obj)
150
+ )
151
+
152
+ this.remotes.forEach(remote => {
153
+ remote.send_enc_mode(sigPack)
154
+ })
155
+ }
156
+
157
+ getSignalTag(buffer) {
158
+ let tagLen = buffer.readUint8(1)
159
+ let tagBuf = buffer.subarray(2, 2 + tagLen)
160
+ let tag = decoder.decode(tagBuf)
161
+ return tag
162
+ }
163
+
164
+ getNewSignalTagMessage(buffer, newTag) {
165
+ let msgType = buffer[0]
166
+ let tagLen = buffer.readUint8(1)
167
+ let newTagBuf = encoder.encode(newTag)
168
+ let newTagLen = newTagBuf.byteLength;
169
+ let payloadCunk = buffer.subarray(2 + tagLen)
170
+ let newBuffer = Buffer.concat([Buffer.from([msgType, newTagLen]), newTagBuf, payloadCunk])
171
+ return newBuffer
172
+ }
173
+
174
+
175
+ parsePayload(args) {
176
+ // console.log( 'parsePayload args', args )
177
+ let type, pack;
178
+ if (args.length == 0) {
179
+ type = PAYLOAD_TYPE.EMPTY
180
+ pack = null
181
+ } else if (args.length == 1) {
182
+ if (typeof args[0] === 'string' || typeof args[0] === 'number') {
183
+ type = PAYLOAD_TYPE.TEXT
184
+ pack = encoder.encode(args[0] + ".") // add null area.
185
+ pack[pack.byteLength - 1] = 0 // set null.
186
+
187
+ } else if (ArrayBuffer.isView(args[0]) || args[0] instanceof ArrayBuffer) { //one buffer
188
+ type = PAYLOAD_TYPE.BINARY
189
+ pack = MBP.B8(args[0])
190
+ } else if (typeof args[0] === 'object') {
191
+ type = PAYLOAD_TYPE.OBJECT
192
+ pack = encoder.encode(JSON.stringify(args[0]))
193
+ } else {
194
+ //
195
+ console.log('unknown type payload arguments')
196
+ }
197
+ } else { // args 2 and more
198
+ let containsBuffer = false
199
+ args.forEach(item => {
200
+ if (ArrayBuffer.isView(item) || item instanceof ArrayBuffer) containsBuffer = true;
201
+ // console.log('payload item', item )
202
+ })
203
+
204
+ if (containsBuffer) {
205
+ type = PAYLOAD_TYPE.MBA;
206
+ // pack
207
+ } else {
208
+ type = PAYLOAD_TYPE.MJSON;
209
+ // args is array
210
+ pack = encoder.encode(JSON.stringify(args))
211
+ }
212
+
213
+ }
214
+
215
+ return { type: type, buffer: pack }
216
+
217
+ }
218
+
219
+ get_signal_pack(tag, ...args) {
220
+ if (typeof tag !== 'string') throw TypeError('tag should be string.')
221
+ let tagEncoded = encoder.encode(tag)
222
+ let payload = this.parsePayload(args)
223
+
224
+ let sigPack;
225
+ if (payload.type == PAYLOAD_TYPE.EMPTY) {
226
+ sigPack = MBP.pack(
227
+ MBP.MB('#MsgType', '8', IOMsg.SIGNAL),
228
+ MBP.MB('#tagLen', '8', tagEncoded.byteLength),
229
+ MBP.MB('#tag', tagEncoded),
230
+ MBP.MB('#payloadType', '8', payload.type)
231
+ )
232
+ } else if (payload.type == PAYLOAD_TYPE.MBA) {
233
+ sigPack = MBP.pack(
234
+ MBP.MB('#MsgType', '8', IOMsg.SIGNAL),
235
+ MBP.MB('#tagLen', '8', tagEncoded.byteLength),
236
+ MBP.MB('#tag', tagEncoded),
237
+ MBP.MB('#payloadType', '8', payload.type),
238
+ MBP.MBA(...args)
239
+ )
240
+ } else {
241
+ sigPack = MBP.pack(
242
+ MBP.MB('#MsgType', '8', IOMsg.SIGNAL),
243
+ MBP.MB('#tagLen', '8', tagEncoded.byteLength),
244
+ MBP.MB('#tag', tagEncoded),
245
+ MBP.MB('#payloadType', '8', payload.type),
246
+ MBP.MB('#payload', payload.buffer)
247
+ )
248
+ }
249
+ return sigPack
250
+ }
251
+
252
+
253
+
254
+
255
+ // signaling to the cid subscribers.
256
+ // example. sending cid close signal.
257
+ deligateSignal(remote, tag, ...args) {
258
+ let sigPack = this.get_signal_pack(tag, ...args)
259
+ this.sender(tag, remote, sigPack)
260
+ }
261
+
262
+ adminSignal( cid, message){
263
+ if (this.cid2remote.has(cid)) {
264
+ this.cid2remote.get(cid).send_enc_mode(message)
265
+ // return ['ok', 1]
266
+ return
267
+ }else{
268
+ return "no cid"
269
+ }
270
+ }
271
+
272
+ sender(tag, remote, message) {
273
+ if(serverOption.memberOnly && !remote.boho.isAuthorized){
274
+ // console.log("## MemberOnly, reject unAuthorized remote." )
275
+ remote.send(Buffer.from([IOMsg.SERVER_CLEAR_AUTH]))
276
+ remote.close()
277
+ return ['err', 'not autrized']
278
+ }
279
+
280
+ if( tag.indexOf('$') == 0 ) return ['err', 'prefix $ is reserved for userSet tag.']
281
+
282
+ let cidIndex = tag.indexOf('@');
283
+ if (cidIndex === 0) {
284
+ // ** CID_PUB is not uni-cast but multic-cast.
285
+ // [cid_pub] @topic , @$retainTopic
286
+ // modify signalpack with cid_appneded tag.
287
+ tag = remote.cid + tag;
288
+ message = this.getNewSignalTagMessage(message, tag)
289
+
290
+ // console.log('cid_pub new tag:', tag, this.getSignalTag(message ))
291
+ } else if (cidIndex > 0) {
292
+ // uni-cast.
293
+ // console.log('unicast to:', tag)
294
+ let targetCId = tag.split('@')[0];
295
+ if (this.cid2remote.has(targetCId)) {
296
+ //rm cid from tag.
297
+ let ommitCIdTag = '@' + tag.split('@')[1]
298
+ message = this.getNewSignalTagMessage(message, ommitCIdTag)
299
+ // console.log(`origin tag: ${tag} omitTag: ${this.getSignalTag(message)}`)
300
+ this.cid2remote.get(targetCId).send_enc_mode(message)
301
+ return ['ok', 1]
302
+ }
303
+ return ['err', 'Invalid cid']
304
+ // pub message from cid.
305
+ // you already subscribe the cid.
306
+ } else {
307
+ // console.log('ch_pub tag:', tag)
308
+ //else channel publish message
309
+ }
310
+
311
+
312
+ /**
313
+ * multi-cast:
314
+ * channel_publish
315
+ * or cid_publish
316
+ */
317
+
318
+ // HOME_CHANNEL substitution.
319
+ // (blank)#topic -> home_channel#topic.
320
+ if (tag.indexOf('#') === 0) {
321
+ tag = remote.HOME_CHANNEL + tag;
322
+ } else if( tag.includes('@')){
323
+ tag = this.CID_PREFIX + tag;
324
+ } else {
325
+ tag = this.CHANNEL_PREFIX + tag;
326
+ }
327
+
328
+ // retain signal message
329
+ if (tag.includes('$')
330
+ // && remote.boho.isAuthorized
331
+ && serverOption.retain.isAvailable
332
+ && serverOption.retain.limitCounter > this.retain_messages.size
333
+ && serverOption.retain.limitSize > message.byteLength
334
+ ) {
335
+ // cid retain signal
336
+ if (tag.includes('@')) {
337
+ // cid retain signal stored inside remote.
338
+ let retainTag = tag.split('@')[1]
339
+ remote.retain_signal.set(retainTag, message)
340
+ // console.log('## cid retain tag, size: ', retainTag, remote.retain_signal.size)
341
+ } else {
342
+ // channel retain signal stored inside manager.
343
+ this.retain_messages.set(tag, message)
344
+ // console.log('## channel retain tag, size: ', tag, this.retain_messages.size)
345
+ }
346
+
347
+ } else {
348
+ // console.log('no retain. serverOption.retain:', serverOption.retain )
349
+ }
350
+
351
+ let sentCounter = 0;
352
+ if (this.channel_map.has(tag)) {
353
+ // console.log('raw channel_map matched tag:', tag)
354
+ let remotes = this.channel_map.get(tag);
355
+ if (remotes.size >= 1) {
356
+ let limit;
357
+ if (serverOption.useQuota.publishCounter) {
358
+ limit = Math.min(remote.quota.publishCounter, remotes.size)
359
+ } else {
360
+ limit = remotes.size;
361
+ }
362
+ let peers = remotes.values();
363
+ while (sentCounter < limit) {
364
+ let c = peers.next().value
365
+ if (!c) {
366
+ // console.log('## null remote' )
367
+ break;
368
+ }
369
+ if (c !== remote) {
370
+ c.send_enc_mode(message);
371
+ sentCounter++;
372
+ }
373
+ }
374
+
375
+ if (serverOption.useQuota.publishCounter) {
376
+ // console.log(`pub >> [${tag}] sent: ${sentCounter} [use quota limit: ${remote.quota.publishCounter }] total: ${remotes.size} subscribers. ` )
377
+ } else {
378
+ // console.log(`pub >> [${tag}] sent: ${sentCounter} [no quota limit] total: ${remotes.size} subscribers. ` )
379
+ }
380
+ return ['ok', sentCounter]
381
+ }
382
+ }
383
+ // console.log('-- No subscriber. ch: ' , tag )
384
+ return ['err', 'No subscriber.']
385
+ }
386
+
387
+
388
+
389
+ subscribe(chArr, remote) {
390
+ // console.log('ChannelManager:: subscribe: ',chArr)
391
+ chArr.forEach(tag => {
392
+ if (tag.indexOf('#') === 0) {
393
+ tag = remote.HOME_CHANNEL + tag
394
+ } else if( tag.includes('@')){
395
+ tag = this.CID_PREFIX + tag;
396
+ } else {
397
+ tag = this.CHANNEL_PREFIX + tag
398
+ }
399
+
400
+ // 1. set channel map
401
+ if (this.channel_map.has(tag)) {
402
+ this.channel_map.get(tag).add(remote)
403
+ } else {
404
+ this.channel_map.set(tag, new Set([remote]))
405
+ }
406
+ // console.log('Manager::map:', this.channel_map.keys() )
407
+
408
+ // 2.add to remote channels.
409
+ remote.channels.add(tag)
410
+ // console.log('remote.channels set.', remote.channels )
411
+
412
+ // 3. send retain message if available.
413
+ if (tag.includes('$')
414
+ && serverOption.retain.isAvailable
415
+ ) {
416
+ let retainMessage;
417
+ if (tag.includes('@')) {
418
+ let cid = tag.split('@')[0]
419
+ cid = cid.split(this.CID_PREFIX)[1]
420
+ let retainTag = tag.split('@')[1]
421
+ if (this.cid2remote.has(cid)) {
422
+ retainMessage = this.cid2remote.get(cid).retain_signal.get(retainTag)
423
+ } else {
424
+ // console.log('cid subscribe is rejected. not online:', cid)
425
+ return;
426
+ }
427
+
428
+ } else if (this.retain_messages.has(tag)) {
429
+ retainMessage = this.retain_messages.get(tag)
430
+ }
431
+ // console.log('send retainMessage buffer',retainMessage)
432
+ if(retainMessage) remote.send_enc_mode(retainMessage)
433
+
434
+ }
435
+
436
+ })
437
+ return remote.channels.size;
438
+ }
439
+
440
+ unsubscribe(chArr, remote) {
441
+ //unsubscribe all channels of the remote.
442
+ if (chArr.length == 1 && chArr[0] == "") {
443
+
444
+ remote.channels.forEach(ch => {
445
+ if (this.channel_map.has(ch)) {
446
+ let remotes = this.channel_map.get(ch)
447
+ remotes.delete(remote)
448
+ if (remotes.size == 0) this.channel_map.delete(ch)
449
+ }
450
+ })
451
+ remote.channels.clear();
452
+
453
+ } else {
454
+ // unsubscribe each channels.
455
+ chArr.forEach(ch => {
456
+ // substitution home_channel
457
+ if (ch.indexOf('#') === 0) {
458
+ ch = remote.HOME_CHANNEL + ch;
459
+ } else if( ch.includes('@')){
460
+ ch = this.CID_PREFIX + ch;
461
+ } else {
462
+ ch = this.CHANNEL_PREFIX + ch;
463
+ }
464
+ // console.log('-- Manager::unsubscribe:', ch )
465
+
466
+ // delete manager map.
467
+ if (this.channel_map.has(ch)) {
468
+ let remotes = this.channel_map.get(ch)
469
+ remotes.delete(remote)
470
+ if (remotes.size == 0) this.channel_map.delete(ch)
471
+ } else {
472
+ // console.log('##no such a ch', ch )
473
+ }
474
+ remote.channels.delete(ch)
475
+ })
476
+ }
477
+
478
+ // console.log( '-- result unsub:', remote.channels )
479
+
480
+ }
481
+
482
+
483
+ monitor() {
484
+ if (process.stdout.isTTY) {
485
+ process.stdout.cursorTo(0, 0)
486
+ process.stdout.clearScreenDown()
487
+ }
488
+
489
+ if (serverOption.showChannel > 0) {
490
+ this.metric.channels(serverOption.showChannel);
491
+ }
492
+ let mode = parseInt(serverOption.showMetric)
493
+ console.log('monitor metric type:', mode)
494
+ switch (mode) {
495
+ case 1:
496
+ this.metric.oneline(true);
497
+ break;
498
+ case 2:
499
+ // this.metric.getCIdList(true);
500
+ this.metric.getRemotes(true);
501
+ break;
502
+ case 3:
503
+ this.metric.getChannelList(true);
504
+ break;
505
+ default:
506
+ }
507
+
508
+ }
509
+
510
+
511
+ closeRemoteByCId(cid) {
512
+ if (this.cid2remote.has(cid)) {
513
+ this.cid2remote.get(cid).close()
514
+ return 1
515
+ } else {
516
+ return 0
517
+ }
518
+ }
519
+
520
+
521
+ }
@@ -0,0 +1,154 @@
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 Metric{
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 ) cconsole.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
+ getCIdList( prn ){
76
+ let CIdList = Array.from(this.manager.cid2remote.keys())
77
+ if (prn ) console.table(CIdList)
78
+ return CIdList
79
+ }
80
+
81
+ getChannelList(prn){
82
+ let chList = Array.from(this.manager.channel_map.keys())
83
+ if (prn ) console.table(chList)
84
+ return chList
85
+ }
86
+
87
+ getSubscribers(ch){
88
+ let list = [];
89
+ if( this.manager.channel_map.has(ch)){
90
+ let subscribers = this.manager.channel_map.get(ch) //set
91
+ subscribers.forEach( c =>{
92
+ list.push(c.cid)
93
+ })
94
+ }
95
+ // console.log(list)
96
+ return list
97
+ }
98
+
99
+ getRemoteByCId( cid , mode = 1){
100
+
101
+ if( this.manager.cid2remote.has(cid)){
102
+ let remote = this.manager.cid2remote.get(cid)
103
+ if(mode == 1){
104
+ return {
105
+ ip: remote.ip,
106
+ id: remote.cid,
107
+ ssid: remote.ssid,
108
+ cid: remote.cid,
109
+ uptime: Math.trunc( ( Date.now() - remote.socket.openTime ) / 1000),
110
+ tx: remote.socket.txCounter,
111
+ rx: remote.socket.rxCounter,
112
+ txBytes: remote.socket.bytesWritten || remote.socket._socket?.bytesWritten,
113
+ rxBytes: remote.socket.bytesRead || remote.socket._socket?.bytesRead
114
+ }
115
+ }else if( mode == 2){
116
+ return {
117
+ ip: remote.ip,
118
+ uptime: Math.trunc( ( Date.now() - remote.socket.openTime ) / 1000),
119
+ nick: remote.nick,
120
+ ssid: remote.ssid,
121
+ echo: remote.lastEchoMessage
122
+ }
123
+ }else if( mode == 3){
124
+ return {
125
+ ip: remote.ip,
126
+ uptime: Math.trunc( ( Date.now() - remote.socket.openTime ) / 1000),
127
+ nick: remote.nick,
128
+ ssid: remote.ssid,
129
+ isSecure: remote.TLS,
130
+ isAuth: remote.boho.isAuthorized,
131
+ encMode: ENC_MODE[remote.encMode]
132
+ }
133
+ }else if( mode == 4){
134
+ let channels = Array.from( remote.channels.keys() )
135
+ let set_memory = Array.from( remote.memory.keys() )
136
+ let retain_signal = Array.from( remote.retain_signal.keys() )
137
+ return {
138
+ ip: remote.ip,
139
+ uptime: Math.trunc( ( Date.now() - remote.socket.openTime ) / 1000),
140
+ channels: channels,
141
+ set: set_memory,
142
+ retain: retain_signal
143
+ }
144
+ }
145
+
146
+ }else{
147
+ return { result: "nop" }
148
+ }
149
+
150
+ }
151
+
152
+
153
+ }
154
+