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