iosignal 1.1.0 → 1.2.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 +101 -31
- package/dist/iosignal.cjs +2 -2
- package/dist/iosignal.esm.js +1 -1
- package/dist/iosignal.esm.js.map +1 -1
- package/dist/iosignal.min.js +2 -2
- package/dist/iosignal.min.js.map +1 -1
- package/package.json +2 -2
- package/src/client/IOCore.js +461 -569
- package/src/client/IOWebSocket.js +0 -1
- package/src/common/payload.js +77 -0
- package/src/server/Manager.js +3 -84
- package/src/server/Server.js +38 -21
- package/src/server/serverOption.js +2 -2
- package/test-browser/server.js +8 -5
- package/test-client-nodejs/client_api_reply.mjs +15 -0
- package/test-client-nodejs/stateChange.mjs +1 -1
- package/test-server/{test-Auth_Env.js → server-Auth_Env.js} +8 -6
- package/test-server/server-Auth_File.js +12 -0
- package/test-server/server-api_reply.js +6 -0
- package/test-server/server-api_sudo.js +7 -0
- package/test-server/server-commonjs.cjs +8 -7
- package/test-server/server-esm.mjs +7 -7
- package/test-server/simple-server.mjs +12 -0
- package/test-server/test-Auth_File.js +0 -9
- package/test-server/test-api_reply.js +0 -10
- package/test-server/test-api_sudo.js +0 -11
package/src/client/IOCore.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { MBP
|
|
1
|
+
import { MBP, Buffer } from 'meta-buffer-pack'
|
|
2
2
|
import EventEmitter from "eventemitter3";
|
|
3
3
|
import { Boho, BohoMsg, MetaSize } from "boho";
|
|
4
|
+
import { IOMsg, PAYLOAD_TYPE, SIZE_LIMIT, ENC_MODE, STATES } from '../common/constants.js'
|
|
4
5
|
import { quotaTable } from '../common/quotaTable.js'
|
|
5
|
-
import {
|
|
6
|
+
import { getSignalPack } from '../common/payload.js';
|
|
6
7
|
|
|
7
8
|
const encoder = new TextEncoder()
|
|
8
9
|
const decoder = new TextDecoder()
|
|
9
10
|
|
|
10
|
-
function byteToUrl(
|
|
11
|
+
function byteToUrl(buffer) {
|
|
11
12
|
//ipv4(4bytes) , port(2bytes)
|
|
12
|
-
if(buffer.byteLength != 6
|
|
13
|
-
let address = buffer[0].toString() + "."+ buffer[1].toString()
|
|
14
|
-
|
|
15
|
-
let port = (buffer[4] << 8) + buffer[5]
|
|
16
|
-
|
|
17
|
-
return address +':'+ port.toString()
|
|
13
|
+
if (buffer.byteLength != 6) return
|
|
14
|
+
let address = buffer[0].toString() + "." + buffer[1].toString()
|
|
15
|
+
+ "." + buffer[2].toString() + "." + buffer[3].toString();
|
|
16
|
+
let port = (buffer[4] << 8) + buffer[5]
|
|
17
|
+
return address + ':' + port.toString()
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export class IOCore extends EventEmitter{
|
|
21
|
-
constructor(
|
|
20
|
+
export class IOCore extends EventEmitter {
|
|
21
|
+
constructor(url) {
|
|
22
22
|
super();
|
|
23
23
|
this.cid = "" // get from the server CID_RES
|
|
24
24
|
this.ip = "" // get from the server IAM_RES message.
|
|
@@ -31,14 +31,14 @@ export class IOCore extends EventEmitter{
|
|
|
31
31
|
this.rxCounter = 0;
|
|
32
32
|
this.txBytes = 0;
|
|
33
33
|
this.rxBytes = 0;
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
this.lastTxRxTime = Date.now();
|
|
36
|
-
this.connectionCheckerPeriod = SIZE_LIMIT.CONNECTION_CHECKER_PERIOD
|
|
36
|
+
this.connectionCheckerPeriod = SIZE_LIMIT.CONNECTION_CHECKER_PERIOD;
|
|
37
37
|
this.connectionCheckerIntervalID = null;
|
|
38
38
|
|
|
39
39
|
this.boho = new Boho()
|
|
40
40
|
this.TLS = false // true if protocol is wss(TLS)
|
|
41
|
-
this.encMode = ENC_MODE.AUTO;
|
|
41
|
+
this.encMode = ENC_MODE.AUTO;
|
|
42
42
|
this.useAuth = false;
|
|
43
43
|
|
|
44
44
|
this.nick = "";
|
|
@@ -48,440 +48,410 @@ export class IOCore extends EventEmitter{
|
|
|
48
48
|
this.mid = 0 // promise message id
|
|
49
49
|
|
|
50
50
|
this.level = 0; // also defaultQuotaLevel
|
|
51
|
-
this.quota = quotaTable[
|
|
51
|
+
this.quota = quotaTable[this.level];
|
|
52
52
|
this.serverSet = {}
|
|
53
|
-
|
|
54
53
|
this.linkMap = new Map()
|
|
55
54
|
|
|
56
|
-
this.on('open',this.onOpen.bind(this))
|
|
57
|
-
this.on('close',this.onClose.bind(this))
|
|
58
|
-
this.on('socket_data',this.onData.bind(this))
|
|
59
|
-
// this.on('auth_fail',this.onAuthFail.bind(this))
|
|
60
|
-
// this.on('server_signal', this.onServerSignal.bind(this))
|
|
55
|
+
this.on('open', this.onOpen.bind(this))
|
|
56
|
+
this.on('close', this.onClose.bind(this))
|
|
57
|
+
this.on('socket_data', this.onData.bind(this))
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
// }
|
|
66
|
-
|
|
67
|
-
// onServerSignal(event, data ){
|
|
68
|
-
// console.log('onServerSignal', event, data )
|
|
69
|
-
// }
|
|
70
|
-
|
|
71
|
-
redirect(url2){
|
|
61
|
+
redirect(url2) {
|
|
72
62
|
this.close()
|
|
73
63
|
this.stateChange('redirecting')
|
|
74
|
-
this.createConnection(
|
|
64
|
+
this.createConnection(url2)
|
|
75
65
|
}
|
|
76
66
|
|
|
77
|
-
open(url
|
|
78
|
-
if(
|
|
67
|
+
open(url) {
|
|
68
|
+
if (!url && !this.url) return;
|
|
79
69
|
|
|
80
|
-
if(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
70
|
+
if (url) {
|
|
71
|
+
if (!this.url) { // default host url
|
|
72
|
+
this.url = url
|
|
73
|
+
} else if (url !== this.url) { // default host url change
|
|
74
|
+
this.url = url;
|
|
75
|
+
if (this.socket) {
|
|
76
|
+
this.close()
|
|
77
|
+
return
|
|
89
78
|
}
|
|
79
|
+
}
|
|
90
80
|
}
|
|
91
81
|
|
|
92
|
-
this.createConnection(
|
|
93
|
-
|
|
94
|
-
if(!this.connectionCheckerIntervalID){
|
|
82
|
+
this.createConnection(this.url)
|
|
83
|
+
|
|
84
|
+
if (!this.connectionCheckerIntervalID) {
|
|
95
85
|
this.connectionCheckerIntervalID = setInterval(this.keepAlive.bind(this), this.connectionCheckerPeriod);
|
|
96
|
-
}
|
|
86
|
+
}
|
|
97
87
|
}
|
|
98
88
|
|
|
99
|
-
onOpen(
|
|
100
|
-
if(
|
|
89
|
+
onOpen() {
|
|
90
|
+
if (this.url.includes("wss://")) {
|
|
101
91
|
this.TLS = true;
|
|
102
|
-
}else{
|
|
92
|
+
} else {
|
|
103
93
|
this.TLS = false;
|
|
104
94
|
}
|
|
105
|
-
this.stateChange('open'
|
|
95
|
+
this.stateChange('open')
|
|
106
96
|
}
|
|
107
97
|
|
|
108
|
-
onClose(){
|
|
98
|
+
onClose() {
|
|
109
99
|
this.boho.isAuthorized = false;
|
|
110
100
|
this.cid = ""
|
|
111
|
-
this.stateChange('closed'
|
|
101
|
+
this.stateChange('closed')
|
|
112
102
|
}
|
|
113
103
|
|
|
114
104
|
// manual login
|
|
115
|
-
login(
|
|
116
|
-
if(
|
|
105
|
+
login(id, key) {
|
|
106
|
+
if (!id && !key) {
|
|
117
107
|
console.log('no id and key.')
|
|
118
108
|
return
|
|
119
|
-
}
|
|
109
|
+
}
|
|
120
110
|
console.log('manual login: ', id)
|
|
121
111
|
|
|
122
|
-
if(
|
|
112
|
+
if (!key && id.includes('.')) {
|
|
123
113
|
this.boho.set_id_key(id)
|
|
124
|
-
}else if(
|
|
114
|
+
} else if (id && key) {
|
|
125
115
|
this.boho.set_id8(id)
|
|
126
116
|
this.boho.set_key(key)
|
|
127
|
-
}else{
|
|
117
|
+
} else {
|
|
128
118
|
console.log('no id or key.')
|
|
129
119
|
return
|
|
130
120
|
}
|
|
131
121
|
this.useAuth = true
|
|
132
122
|
let auth_pack = this.boho.auth_req()
|
|
133
123
|
// console.log('auth_req_pack', auth_pack )
|
|
134
|
-
this.send(auth_pack
|
|
124
|
+
this.send(auth_pack)
|
|
135
125
|
}
|
|
136
126
|
|
|
137
127
|
// auto login
|
|
138
|
-
auth(
|
|
139
|
-
if(
|
|
128
|
+
auth(id, key) {
|
|
129
|
+
if (!id && !key) {
|
|
140
130
|
console.log('no id and key.')
|
|
141
131
|
return
|
|
142
|
-
}
|
|
143
|
-
// console.log('set auto auth: ', id)
|
|
132
|
+
}
|
|
144
133
|
|
|
145
|
-
if(
|
|
134
|
+
if (!key && id.includes('.')) {
|
|
146
135
|
this.boho.set_id_key(id)
|
|
147
|
-
}else if(
|
|
136
|
+
} else if (id && key) {
|
|
148
137
|
this.boho.set_id8(id)
|
|
149
138
|
this.boho.set_key(key)
|
|
150
|
-
}else{
|
|
139
|
+
} else {
|
|
151
140
|
console.log('no id or key.')
|
|
152
141
|
return
|
|
153
142
|
}
|
|
154
143
|
this.useAuth = true
|
|
155
144
|
}
|
|
156
145
|
|
|
157
|
-
onData(
|
|
146
|
+
onData(buffer) {
|
|
158
147
|
// console.log('remote rcv socket_message', buffer )
|
|
159
148
|
//check first byte (remote message type)
|
|
160
|
-
|
|
161
|
-
|
|
149
|
+
let msgType = buffer[0];
|
|
150
|
+
let decoded;
|
|
162
151
|
|
|
163
|
-
if(
|
|
164
|
-
decoded = this.boho.decrypt_488(
|
|
165
|
-
if(
|
|
166
|
-
|
|
152
|
+
if (msgType === BohoMsg.ENC_488) {
|
|
153
|
+
decoded = this.boho.decrypt_488(buffer)
|
|
154
|
+
if (decoded) {
|
|
155
|
+
// console.log( decoded )
|
|
167
156
|
msgType = decoded[0]
|
|
168
|
-
buffer = decoded
|
|
157
|
+
buffer = decoded
|
|
169
158
|
// console.log('DECODED MsgType:', IOMsg[ msgType ] )
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
159
|
+
} else {
|
|
160
|
+
// console.log('DEC_FAIL', buffer.byteLength)
|
|
161
|
+
}
|
|
162
|
+
} else if (msgType === BohoMsg.ENC_E2E) {
|
|
174
163
|
// console.log('rcv ENC_E2E' )
|
|
175
164
|
|
|
176
|
-
try{
|
|
177
|
-
decoded = this.boho.decrypt_488(
|
|
165
|
+
try {
|
|
166
|
+
decoded = this.boho.decrypt_488(buffer)
|
|
178
167
|
//헤더를 읽고 헤더크기만큼만 해석한다.
|
|
179
|
-
if(
|
|
168
|
+
if (decoded) {
|
|
180
169
|
// console.log( 'ENC_E2E decoded ', decoded )
|
|
181
170
|
msgType = decoded[0]
|
|
182
171
|
// decoded has msg_header only.
|
|
183
|
-
buffer.set(
|
|
184
|
-
buffer = buffer.subarray(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
172
|
+
buffer.set(decoded, MetaSize.ENC_488) // set decoded signal_e2e headaer.
|
|
173
|
+
buffer = buffer.subarray(MetaSize.ENC_488) // reset offset.
|
|
174
|
+
// console.log('DECODED MsgType:', IOMsg[ msgType ] )
|
|
175
|
+
} else {
|
|
176
|
+
// console.log('488 DEC_FAIL', buffer)
|
|
177
|
+
return
|
|
178
|
+
}
|
|
190
179
|
|
|
191
|
-
}catch(err){
|
|
192
|
-
console.log('E2E DEC_FAIL decryption error', err)
|
|
180
|
+
} catch (err) {
|
|
181
|
+
// console.log('E2E DEC_FAIL decryption error', err)
|
|
193
182
|
return
|
|
194
183
|
}
|
|
195
184
|
|
|
196
|
-
|
|
185
|
+
}
|
|
197
186
|
|
|
198
|
-
let type = IOMsg[
|
|
199
|
-
if(
|
|
187
|
+
let type = IOMsg[msgType]
|
|
188
|
+
if (!type) type = BohoMsg[msgType]
|
|
200
189
|
|
|
201
|
-
// console.log( "MsgType: ", type , " LEN ", buffer.byteLength)
|
|
190
|
+
// console.log( "MsgType: ", type , " LEN ", buffer.byteLength)
|
|
202
191
|
|
|
203
|
-
|
|
204
|
-
case IOMsg.OVER_SIZE
|
|
192
|
+
switch (msgType) {
|
|
193
|
+
case IOMsg.OVER_SIZE:
|
|
205
194
|
console.log('## server sent: over_size event.')
|
|
206
|
-
this.emit('over_size','over_size')
|
|
207
|
-
|
|
208
|
-
case IOMsg.PING
|
|
209
|
-
|
|
210
|
-
|
|
195
|
+
this.emit('over_size', 'over_size')
|
|
196
|
+
break;
|
|
197
|
+
case IOMsg.PING:
|
|
198
|
+
this.pong();
|
|
199
|
+
break;
|
|
211
200
|
|
|
212
|
-
case IOMsg.PONG
|
|
213
|
-
|
|
201
|
+
case IOMsg.PONG:
|
|
202
|
+
break;
|
|
214
203
|
|
|
215
204
|
case IOMsg.IAM_RES:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
console.log('<IAM_RES>', JSON.stringify(jsonInfo))
|
|
223
|
-
// console.log('<IAM_RES>', JSON.stringify(jsonInfo,null,2))
|
|
224
|
-
} catch (error) {
|
|
225
|
-
console.log('<IAM_RES> data error')
|
|
205
|
+
try {
|
|
206
|
+
let str = decoder.decode(buffer.subarray(1))
|
|
207
|
+
let jsonInfo = JSON.parse(str)
|
|
208
|
+
if (jsonInfo.ip) {
|
|
209
|
+
this.ip = jsonInfo.ip;
|
|
226
210
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
this.stateChange('ready','cid_ready' )
|
|
234
|
-
// change state before subscribe.
|
|
235
|
-
this.subscribe_memory_channels()
|
|
236
|
-
break;
|
|
237
|
-
|
|
238
|
-
case IOMsg.QUOTA_LEVEL :
|
|
239
|
-
let quotaLevel = buffer[1]
|
|
240
|
-
this.level = quotaLevel;
|
|
241
|
-
this.quota = quotaTable[ quotaLevel ];
|
|
242
|
-
console.log('## QUOTA:', quotaLevel, JSON.stringify(this.quota) )
|
|
243
|
-
break;
|
|
244
|
-
|
|
245
|
-
case IOMsg.SERVER_CLEAR_AUTH :
|
|
246
|
-
this.useAuth = false;
|
|
247
|
-
this.boho.clearAuth();
|
|
248
|
-
this.stop();
|
|
249
|
-
break;
|
|
250
|
-
|
|
251
|
-
case IOMsg.SERVER_REDIRECT :
|
|
252
|
-
// console.log( buffer.toString('hex'))
|
|
253
|
-
let host_port;
|
|
254
|
-
let url;
|
|
255
|
-
let protocol;
|
|
256
|
-
let addressType;
|
|
257
|
-
if( buffer.byteLength == 7){ // ipv4 ,port
|
|
258
|
-
addressType = 'IPV4:PORT'
|
|
259
|
-
host_port = byteToUrl( buffer.subarray(1))
|
|
260
|
-
protocol = 'cong://'
|
|
261
|
-
}else{ // domain url
|
|
262
|
-
addressType= 'URL'
|
|
263
|
-
host_port = decoder.decode( buffer.subarray(1))
|
|
264
|
-
protocol = '' // must included in url
|
|
265
|
-
}
|
|
211
|
+
console.log('<IAM_RES>', JSON.stringify(jsonInfo))
|
|
212
|
+
// console.log('<IAM_RES>', JSON.stringify(jsonInfo,null,2))
|
|
213
|
+
} catch (error) {
|
|
214
|
+
// console.log('<IAM_RES> data error')
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
266
217
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
218
|
+
case IOMsg.CID_RES:
|
|
219
|
+
let cidStr = decoder.decode(buffer.subarray(1))
|
|
220
|
+
// console.log( '>> CID_RES: ' ,cidStr )
|
|
221
|
+
this.cid = cidStr;
|
|
222
|
+
// change state before subscribe.
|
|
223
|
+
this.stateChange('ready', 'cid_ready')
|
|
224
|
+
this.subscribe_memory_channels()
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
case IOMsg.QUOTA_LEVEL:
|
|
228
|
+
let quotaLevel = buffer[1]
|
|
229
|
+
this.level = quotaLevel;
|
|
230
|
+
this.quota = quotaTable[quotaLevel];
|
|
231
|
+
console.log('## QUOTA:', quotaLevel, JSON.stringify(this.quota))
|
|
232
|
+
break;
|
|
233
|
+
|
|
234
|
+
case IOMsg.SERVER_CLEAR_AUTH:
|
|
235
|
+
this.useAuth = false;
|
|
236
|
+
this.boho.clearAuth();
|
|
237
|
+
this.stop();
|
|
238
|
+
break;
|
|
239
|
+
|
|
240
|
+
case IOMsg.SERVER_REDIRECT:
|
|
241
|
+
let host_port;
|
|
242
|
+
let url;
|
|
243
|
+
let protocol;
|
|
244
|
+
let addressType;
|
|
245
|
+
if (buffer.byteLength == 7) { // ipv4 ,port
|
|
246
|
+
addressType = 'IPV4:PORT'
|
|
247
|
+
host_port = byteToUrl(buffer.subarray(1))
|
|
248
|
+
protocol = 'cong://'
|
|
249
|
+
} else { // domain url
|
|
250
|
+
addressType = 'URL'
|
|
251
|
+
host_port = decoder.decode(buffer.subarray(1))
|
|
252
|
+
protocol = ''
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
url = protocol + host_port
|
|
256
|
+
this.redirect(url)
|
|
257
|
+
break;
|
|
258
|
+
|
|
259
|
+
case IOMsg.SERVER_READY:
|
|
260
|
+
this.stateChange('server_ready', 'server_ready')
|
|
261
|
+
if (this.useAuth) {
|
|
262
|
+
this.send(this.boho.auth_req())
|
|
263
|
+
// CID_REQ will be called, after auth_ack.
|
|
264
|
+
} else {
|
|
265
|
+
// CID_REQ here, if not using auth.
|
|
266
|
+
this.send(Buffer.from([IOMsg.CID_REQ]))
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
|
|
270
|
+
case IOMsg.SERVER_SIGNAL:
|
|
286
271
|
try {
|
|
287
|
-
let str = decoder.decode(
|
|
288
|
-
let ss = JSON.parse(str)
|
|
289
|
-
console.log('SERVER_SIGNAL', JSON.stringify(ss))
|
|
272
|
+
let str = decoder.decode(buffer.subarray(1))
|
|
273
|
+
let ss = JSON.parse(str)
|
|
274
|
+
// console.log('SERVER_SIGNAL', JSON.stringify(ss))
|
|
290
275
|
|
|
291
|
-
if(
|
|
276
|
+
if (ss.event && ss.data) {
|
|
292
277
|
this.serverSet = ss.data;
|
|
293
|
-
this.emit(
|
|
278
|
+
this.emit(ss.event, ss.data)
|
|
294
279
|
}
|
|
295
|
-
|
|
280
|
+
|
|
296
281
|
} catch (error) {
|
|
297
|
-
console.log('<SERVER_SIGNAL> parsing error')
|
|
282
|
+
// console.log('<SERVER_SIGNAL> parsing error')
|
|
298
283
|
}
|
|
299
|
-
|
|
284
|
+
break;
|
|
300
285
|
|
|
301
|
-
|
|
286
|
+
case IOMsg.SET:
|
|
302
287
|
try {
|
|
303
288
|
let setPack = MBP.unpack(buffer)
|
|
304
|
-
if(setPack
|
|
305
|
-
console.log('[SET] topic: ',setPack.topic
|
|
306
|
-
this.emit(
|
|
289
|
+
if (setPack) {
|
|
290
|
+
// console.log('[SET] topic: ', setPack.topic)
|
|
291
|
+
this.emit(setPack.topic, ...setPack.args)
|
|
307
292
|
}
|
|
308
293
|
} catch (error) {
|
|
309
|
-
console.log('<SET> parsing error')
|
|
294
|
+
// console.log('<SET> parsing error')
|
|
310
295
|
}
|
|
311
|
-
|
|
296
|
+
break;
|
|
312
297
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
298
|
+
case IOMsg.SIGNAL_E2E:
|
|
299
|
+
case IOMsg.SIGNAL:
|
|
300
|
+
try {
|
|
316
301
|
let tagLen = buffer.readUint8(1)
|
|
317
|
-
let tagBuf = buffer.subarray(2, 2 + tagLen
|
|
302
|
+
let tagBuf = buffer.subarray(2, 2 + tagLen)
|
|
318
303
|
let tag = decoder.decode(tagBuf)
|
|
319
304
|
|
|
320
|
-
let payloadType = buffer.readUint8(
|
|
321
|
-
let payloadBuffer = buffer.subarray(
|
|
322
|
-
|
|
305
|
+
let payloadType = buffer.readUint8(2 + tagLen)
|
|
306
|
+
let payloadBuffer = buffer.subarray(3 + tagLen)
|
|
307
|
+
|
|
323
308
|
/* three types of signal message.
|
|
324
309
|
> unicast message to me: tag includes @, no cid: '@*'
|
|
325
310
|
> cid_sub message: tag includes cid and @ both : 'cid@*'
|
|
326
311
|
> ch_sub message: else.
|
|
327
312
|
*/
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
switch( payloadType ){
|
|
313
|
+
switch (payloadType) {
|
|
331
314
|
|
|
332
315
|
case PAYLOAD_TYPE.EMPTY: // 0
|
|
333
|
-
if(
|
|
334
|
-
|
|
316
|
+
if (tag.indexOf('@') === 0) this.emit('@', null, tag)
|
|
317
|
+
else this.emit(tag, null, tag)
|
|
335
318
|
break;
|
|
336
319
|
|
|
337
320
|
case PAYLOAD_TYPE.TEXT: // 1
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
let payloadStringWithoutNull = payloadBuffer.subarray(0,payloadBuffer.byteLength - 1
|
|
341
|
-
let oneString = decoder.decode(
|
|
342
|
-
if(
|
|
343
|
-
if(
|
|
321
|
+
// !! Must remove null char before decode in JS.
|
|
322
|
+
// string payload contains null char for the c/cpp devices.
|
|
323
|
+
let payloadStringWithoutNull = payloadBuffer.subarray(0, payloadBuffer.byteLength - 1)
|
|
324
|
+
let oneString = decoder.decode(payloadStringWithoutNull)
|
|
325
|
+
if (tag.indexOf('@') === 0) this.emit('@', oneString, tag)
|
|
326
|
+
if (tag !== '@') this.emit(tag, oneString, tag)
|
|
344
327
|
break;
|
|
345
|
-
|
|
328
|
+
|
|
346
329
|
case PAYLOAD_TYPE.BINARY: // 2
|
|
347
|
-
if(
|
|
348
|
-
if(
|
|
330
|
+
if (tag.indexOf('@') === 0) this.emit('@', payloadBuffer, tag)
|
|
331
|
+
if (tag !== '@') this.emit(tag, payloadBuffer, tag)
|
|
349
332
|
break;
|
|
350
333
|
|
|
351
334
|
case PAYLOAD_TYPE.OBJECT:
|
|
352
|
-
let oneObjectBuffer = decoder.decode(
|
|
353
|
-
let oneJSONObject = JSON.parse(
|
|
354
|
-
if(
|
|
355
|
-
if(
|
|
356
|
-
break;
|
|
357
|
-
|
|
358
|
-
case PAYLOAD_TYPE.MJSON:
|
|
359
|
-
let mjsonBuffer = decoder.decode( payloadBuffer )
|
|
360
|
-
// console.log('raw mjson tag', tag)
|
|
361
|
-
// console.log('raw mjson', mjsonBuffer)
|
|
362
|
-
let mjson = JSON.parse( mjsonBuffer )
|
|
363
|
-
// console.log('parsed mjson', mjson)
|
|
364
|
-
if( tag.indexOf('@') === 0 ) this.emit( '@', ...mjson , tag )
|
|
365
|
-
if( tag !== '@') this.emit( tag, ...mjson , tag )
|
|
335
|
+
let oneObjectBuffer = decoder.decode(payloadBuffer)
|
|
336
|
+
let oneJSONObject = JSON.parse(oneObjectBuffer)
|
|
337
|
+
if (tag.indexOf('@') === 0) this.emit('@', oneJSONObject, tag)
|
|
338
|
+
if (tag !== '@') this.emit(tag, oneJSONObject, tag)
|
|
366
339
|
break;
|
|
367
340
|
|
|
368
|
-
case PAYLOAD_TYPE.
|
|
369
|
-
let
|
|
370
|
-
|
|
371
|
-
if(
|
|
341
|
+
case PAYLOAD_TYPE.MJSON:
|
|
342
|
+
let mjsonBuffer = decoder.decode(payloadBuffer)
|
|
343
|
+
let mjson = JSON.parse(mjsonBuffer)
|
|
344
|
+
if (tag.indexOf('@') === 0) this.emit('@', ...mjson, tag)
|
|
345
|
+
if (tag !== '@') this.emit(tag, ...mjson, tag)
|
|
372
346
|
break;
|
|
373
347
|
|
|
374
|
-
|
|
375
|
-
|
|
348
|
+
case PAYLOAD_TYPE.MBA:
|
|
349
|
+
let mbaObject = MBP.unpack(buffer)
|
|
350
|
+
if (tag.indexOf('@') === 0) this.emit('@', ...mbaObject.args, tag)
|
|
351
|
+
if (tag !== '@') this.emit(tag, ...mbaObject.args, tag)
|
|
352
|
+
break;
|
|
376
353
|
|
|
354
|
+
default:
|
|
355
|
+
// console.log('## Unkown payloadtype', payloadType)
|
|
377
356
|
}
|
|
378
357
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
console.log('## signal parse err',err)
|
|
358
|
+
} catch (err) {
|
|
359
|
+
// console.log('## signal parse err', err)
|
|
382
360
|
}
|
|
383
361
|
break;
|
|
384
362
|
|
|
385
|
-
|
|
386
|
-
|
|
387
363
|
case IOMsg.RESPONSE_MBP:
|
|
388
|
-
this.testPromise(
|
|
364
|
+
this.testPromise(buffer)
|
|
389
365
|
break;
|
|
390
366
|
|
|
391
|
-
|
|
392
|
-
|
|
393
367
|
case BohoMsg.AUTH_NONCE:
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
this.stateChange('auth_fail', 'Invalid local auth_hmac.' )
|
|
400
|
-
console.log('auth_fail', 'Invalid local auth_hmac.' )
|
|
368
|
+
let auth_hmac = this.boho.auth_hmac(buffer)
|
|
369
|
+
if (auth_hmac) {
|
|
370
|
+
this.send(auth_hmac)
|
|
371
|
+
} else {
|
|
372
|
+
this.stateChange('auth_fail', 'Invalid local auth_hmac.')
|
|
401
373
|
}
|
|
402
374
|
break;
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
this.stateChange('auth_fail','invalid server_hmac' )
|
|
415
|
-
console.log('auth_fail', 'Invalid server hmac.' )
|
|
375
|
+
|
|
376
|
+
case BohoMsg.AUTH_FAIL:
|
|
377
|
+
this.stateChange('auth_fail', 'server reject auth.')
|
|
378
|
+
break;
|
|
379
|
+
|
|
380
|
+
case BohoMsg.AUTH_ACK:
|
|
381
|
+
if (this.boho.check_auth_ack_hmac(buffer)) {
|
|
382
|
+
this.stateChange('auth_ready', 'server sent auth_ack')
|
|
383
|
+
this.send(Buffer.from([IOMsg.CID_REQ]))
|
|
384
|
+
} else {
|
|
385
|
+
this.stateChange('auth_fail', 'invalid server_hmac')
|
|
416
386
|
}
|
|
417
387
|
break;
|
|
418
|
-
|
|
388
|
+
|
|
419
389
|
default:
|
|
420
390
|
try {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
391
|
+
decoded = decoder.decode(buffer)
|
|
392
|
+
// console.log('text message:', decoded)
|
|
393
|
+
this.emit('text_message', decoded)
|
|
424
394
|
} catch (error) {
|
|
425
|
-
|
|
426
|
-
}
|
|
395
|
+
|
|
396
|
+
}
|
|
427
397
|
|
|
428
398
|
break;
|
|
429
399
|
|
|
430
400
|
}
|
|
431
401
|
}
|
|
432
402
|
|
|
433
|
-
iam(
|
|
403
|
+
iam(title) {
|
|
434
404
|
// console.log('iam', title)
|
|
435
|
-
if(title
|
|
436
|
-
this.send_enc_mode(
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}else{
|
|
441
|
-
this.send_enc_mode(
|
|
442
|
-
|
|
443
|
-
|
|
405
|
+
if (title) {
|
|
406
|
+
this.send_enc_mode(MBP.pack(
|
|
407
|
+
MBP.MB('#MsgType', '8', IOMsg.IAM),
|
|
408
|
+
MBP.MB('#', title)
|
|
409
|
+
))
|
|
410
|
+
} else {
|
|
411
|
+
this.send_enc_mode(MBP.pack(
|
|
412
|
+
MBP.MB('#MsgType', '8', IOMsg.IAM)
|
|
413
|
+
))
|
|
444
414
|
}
|
|
445
415
|
}
|
|
446
416
|
|
|
447
417
|
|
|
448
|
-
ping(){
|
|
449
|
-
this.send(
|
|
418
|
+
ping() {
|
|
419
|
+
this.send(Buffer.from([IOMsg.PING]))
|
|
450
420
|
}
|
|
451
421
|
|
|
452
|
-
pong(){
|
|
453
|
-
this.send(
|
|
422
|
+
pong() {
|
|
423
|
+
this.send(Buffer.from([IOMsg.PONG]))
|
|
454
424
|
}
|
|
455
425
|
|
|
456
426
|
|
|
457
427
|
// application level ping tool.
|
|
458
428
|
// simple message sending and reply.
|
|
459
|
-
echo(
|
|
460
|
-
if(args
|
|
461
|
-
console.log(
|
|
462
|
-
this.send_enc_mode(
|
|
463
|
-
MBP.MB('#MsgType','8', IOMsg.ECHO
|
|
464
|
-
MBP.MB('#msg', args
|
|
429
|
+
echo(args) {
|
|
430
|
+
if (args) {
|
|
431
|
+
console.log('echo args:', args)
|
|
432
|
+
this.send_enc_mode(MBP.pack(
|
|
433
|
+
MBP.MB('#MsgType', '8', IOMsg.ECHO),
|
|
434
|
+
MBP.MB('#msg', args)
|
|
465
435
|
))
|
|
466
|
-
}else{
|
|
436
|
+
} else {
|
|
467
437
|
// # do not encrypt blank echo #
|
|
468
|
-
this.send(
|
|
438
|
+
this.send(Buffer.from([IOMsg.ECHO]))
|
|
469
439
|
}
|
|
470
440
|
}
|
|
471
441
|
|
|
472
442
|
|
|
473
|
-
bin(...data){
|
|
474
|
-
this.send(
|
|
443
|
+
bin(...data) {
|
|
444
|
+
this.send(MBP.U8pack(...data))
|
|
475
445
|
}
|
|
476
446
|
|
|
477
|
-
send(
|
|
478
|
-
if(
|
|
447
|
+
send(data) {
|
|
448
|
+
if (data.byteLength > this.quota.signalSize) {
|
|
479
449
|
this.emit('over_size')
|
|
480
|
-
console.log('## QUOTA LIMIT OVER!! \nsignal message.byteLength: ', data.byteLength
|
|
481
|
-
console.log('## your maximum signalSize(bytes) is:', this.quota.signalSize
|
|
450
|
+
console.log('## QUOTA LIMIT OVER!! \nsignal message.byteLength: ', data.byteLength)
|
|
451
|
+
console.log('## your maximum signalSize(bytes) is:', this.quota.signalSize)
|
|
482
452
|
return
|
|
483
453
|
}
|
|
484
|
-
this.socket_send(
|
|
454
|
+
this.socket_send(data);
|
|
485
455
|
}
|
|
486
456
|
|
|
487
457
|
/*
|
|
@@ -500,385 +470,307 @@ export class IOCore extends EventEmitter{
|
|
|
500
470
|
NO. do not ecnrypt message.
|
|
501
471
|
|
|
502
472
|
*/
|
|
503
|
-
getEncryptionMode(){
|
|
504
|
-
if(
|
|
505
|
-
this.encMode === ENC_MODE.AUTO &&
|
|
473
|
+
getEncryptionMode() {
|
|
474
|
+
if (this.encMode === ENC_MODE.YES ||
|
|
475
|
+
this.encMode === ENC_MODE.AUTO &&
|
|
506
476
|
!this.TLS && this.boho.isAuthorized
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
477
|
+
) {
|
|
478
|
+
return true;
|
|
479
|
+
} else {
|
|
480
|
+
return false
|
|
481
|
+
}
|
|
512
482
|
}
|
|
513
483
|
|
|
514
|
-
send_enc_mode(
|
|
515
|
-
|
|
484
|
+
send_enc_mode(data, useEncryption) {
|
|
485
|
+
|
|
516
486
|
// use default policy.
|
|
517
|
-
if(
|
|
487
|
+
if (useEncryption === undefined) {
|
|
518
488
|
useEncryption = this.getEncryptionMode()
|
|
519
489
|
}
|
|
520
|
-
|
|
521
|
-
if(
|
|
490
|
+
|
|
491
|
+
if (data[0] == IOMsg.SIGNAL_E2E && useEncryption) {
|
|
522
492
|
// input data: signal_header + e2ePayload
|
|
523
493
|
// encrypt signal_header area only. payload is encrypted with e2e key already.
|
|
524
494
|
let tagLen = data[1]
|
|
525
|
-
let encHeader = this.boho.encrypt_488(
|
|
495
|
+
let encHeader = this.boho.encrypt_488(data.subarray(0, 3 + tagLen))
|
|
526
496
|
encHeader[0] = BohoMsg.ENC_E2E
|
|
527
|
-
this.send(
|
|
497
|
+
this.send(Buffer.concat([encHeader, data.subarray(3 + tagLen)]))
|
|
528
498
|
// console.log('<< send_enc_mode [ ENC_E2E ]')
|
|
529
|
-
|
|
530
|
-
}else if(
|
|
499
|
+
|
|
500
|
+
} else if (useEncryption) {
|
|
531
501
|
// console.log('<< send_enc_mode [ ENC_488 ]')
|
|
532
|
-
let encPack = this.boho.encrypt_488(
|
|
533
|
-
this.send(
|
|
534
|
-
}else{
|
|
502
|
+
let encPack = this.boho.encrypt_488(data)
|
|
503
|
+
this.send(encPack)
|
|
504
|
+
} else {
|
|
535
505
|
// console.log('<< send_enc_mode [ PLAIN ]' )
|
|
536
|
-
this.send(
|
|
506
|
+
this.send(data)
|
|
537
507
|
}
|
|
538
508
|
|
|
539
509
|
}
|
|
540
510
|
|
|
541
|
-
|
|
542
|
-
setMsgPromise(mid
|
|
543
|
-
return new Promise(
|
|
544
|
-
this.promiseMap.set(
|
|
511
|
+
|
|
512
|
+
setMsgPromise(mid) {
|
|
513
|
+
return new Promise((resolve, reject) => {
|
|
514
|
+
this.promiseMap.set(mid, [resolve, reject])
|
|
545
515
|
// console.log('set promise. mid, size', mid, this.promiseMap.size)
|
|
546
|
-
setTimeout(
|
|
547
|
-
if(this.promiseMap.has(mid
|
|
516
|
+
setTimeout(e => {
|
|
517
|
+
if (this.promiseMap.has(mid)) {
|
|
548
518
|
reject('timeout');
|
|
549
|
-
this.promiseMap.delete(
|
|
519
|
+
this.promiseMap.delete(mid)
|
|
550
520
|
// console.log('promise timeout. mid, size:', mid, this.promiseMap.size)
|
|
551
521
|
}
|
|
552
522
|
}, this.promiseTimeOut);
|
|
553
523
|
})
|
|
554
524
|
}
|
|
555
525
|
|
|
556
|
-
testPromise(
|
|
526
|
+
testPromise(buffer) {
|
|
557
527
|
// console.log('mbp buffer : ', buffer , buffer.byteLength)
|
|
558
528
|
// let mbp = ( buffer.byteLength > 4 ) ? buffer.subarray(4) : ""
|
|
559
529
|
|
|
560
530
|
let res = MBP.unpack(buffer)
|
|
561
|
-
if(
|
|
531
|
+
if (!res) return
|
|
562
532
|
// console.log( res )
|
|
563
533
|
|
|
564
534
|
// console.log(`RESPONSE_MBP MID: ${mid} status: ${status} ,mbp: ${ buffer.subarray(4)} `)
|
|
565
535
|
|
|
566
|
-
if(
|
|
536
|
+
if (this.promiseMap.has(res.mid)) {
|
|
567
537
|
// console.log('res promise msg', mid)
|
|
568
|
-
let [
|
|
569
|
-
this.promiseMap.delete(
|
|
538
|
+
let [resolve, reject] = this.promiseMap.get(res.mid)
|
|
539
|
+
this.promiseMap.delete(res.mid)
|
|
570
540
|
|
|
571
|
-
if(res.status < 128){
|
|
541
|
+
if (res.status < 128) {
|
|
572
542
|
res.ok = true;
|
|
573
543
|
// console.log( 'unpack meta:', meta)
|
|
574
|
-
resolve(
|
|
575
|
-
} else{
|
|
576
|
-
res.ok = false
|
|
577
|
-
reject
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}else{
|
|
582
|
-
console.log('no promise id')
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
publish( ...args ){
|
|
588
|
-
this.signal( ...args )
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
parsePayload( args ){
|
|
593
|
-
// console.log( 'parsePayload args', args )
|
|
594
|
-
let type, pack;
|
|
595
|
-
if( args.length == 0){
|
|
596
|
-
type = PAYLOAD_TYPE.EMPTY
|
|
597
|
-
pack = null
|
|
598
|
-
}else if( args.length == 1){
|
|
599
|
-
if( typeof args[0] === 'string' || typeof args[0] === 'number'){
|
|
600
|
-
type = PAYLOAD_TYPE.TEXT
|
|
601
|
-
pack = encoder.encode( args[0] + ".") // add null area.
|
|
602
|
-
pack[pack.byteLength - 1 ] = 0 // set null.
|
|
603
|
-
|
|
604
|
-
}else if( ArrayBuffer.isView( args[0]) || args[0] instanceof ArrayBuffer ){ //one buffer
|
|
605
|
-
type = PAYLOAD_TYPE.BINARY
|
|
606
|
-
pack = MBP.B8( args[0 ] )
|
|
607
|
-
}else if(typeof args[0] === 'object'){
|
|
608
|
-
type = PAYLOAD_TYPE.OBJECT
|
|
609
|
-
pack = encoder.encode( JSON.stringify( args[0]) )
|
|
610
|
-
}else{
|
|
611
|
-
//
|
|
612
|
-
console.log('unknown type payload arguments')
|
|
544
|
+
resolve(res)
|
|
545
|
+
} else {
|
|
546
|
+
res.ok = false;
|
|
547
|
+
reject(res)
|
|
613
548
|
}
|
|
614
|
-
}else{ // args 2 and more
|
|
615
|
-
let containsBuffer = false
|
|
616
|
-
args.forEach( item =>{
|
|
617
|
-
if( ArrayBuffer.isView( item ) || item instanceof ArrayBuffer ) containsBuffer = true;
|
|
618
|
-
// console.log('payload item', item )
|
|
619
|
-
})
|
|
620
549
|
|
|
621
|
-
if( containsBuffer ){
|
|
622
|
-
type = PAYLOAD_TYPE.MBA;
|
|
623
|
-
// pack
|
|
624
|
-
}else{
|
|
625
|
-
type = PAYLOAD_TYPE.MJSON;
|
|
626
|
-
// args is array
|
|
627
|
-
pack = encoder.encode( JSON.stringify( args ) )
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
return { type: type, buffer: pack }
|
|
633
550
|
|
|
634
|
-
|
|
551
|
+
} else {
|
|
552
|
+
console.log('no promise id')
|
|
553
|
+
}
|
|
554
|
+
}
|
|
635
555
|
|
|
636
|
-
get_signal_pack( tag, ...args ){
|
|
637
|
-
if( typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
638
|
-
let tagEncoded = encoder.encode( tag)
|
|
639
|
-
let payload = this.parsePayload( args )
|
|
640
556
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
sigPack = MBP.pack(
|
|
644
|
-
MBP.MB('#MsgType','8', IOMsg.SIGNAL) ,
|
|
645
|
-
MBP.MB('#tagLen','8', tagEncoded.byteLength),
|
|
646
|
-
MBP.MB('#tag', tagEncoded),
|
|
647
|
-
MBP.MB('#payloadType', '8', payload.type )
|
|
648
|
-
)
|
|
649
|
-
}else if( payload.type == PAYLOAD_TYPE.MBA ){
|
|
650
|
-
sigPack = MBP.pack(
|
|
651
|
-
MBP.MB('#MsgType','8', IOMsg.SIGNAL) ,
|
|
652
|
-
MBP.MB('#tagLen','8', tagEncoded.byteLength),
|
|
653
|
-
MBP.MB('#tag', tagEncoded),
|
|
654
|
-
MBP.MB('#payloadType', '8', payload.type ),
|
|
655
|
-
MBP.MBA(...args)
|
|
656
|
-
)
|
|
657
|
-
}else {
|
|
658
|
-
sigPack = MBP.pack(
|
|
659
|
-
MBP.MB('#MsgType','8', IOMsg.SIGNAL) ,
|
|
660
|
-
MBP.MB('#tagLen','8', tagEncoded.byteLength),
|
|
661
|
-
MBP.MB('#tag', tagEncoded),
|
|
662
|
-
MBP.MB('#payloadType', '8', payload.type ),
|
|
663
|
-
MBP.MB('#payload', payload.buffer )
|
|
664
|
-
)
|
|
665
|
-
}
|
|
666
|
-
return sigPack
|
|
557
|
+
publish(...args) {
|
|
558
|
+
this.signal(...args)
|
|
667
559
|
}
|
|
668
560
|
|
|
669
561
|
|
|
670
|
-
signal(
|
|
671
|
-
if(
|
|
562
|
+
signal(tag, ...args) {
|
|
563
|
+
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
672
564
|
|
|
673
|
-
let signalPack =
|
|
674
|
-
this.send_enc_mode(
|
|
565
|
+
let signalPack = getSignalPack(tag, ...args)
|
|
566
|
+
this.send_enc_mode(signalPack)
|
|
675
567
|
}
|
|
676
568
|
|
|
677
|
-
decrypt_e2e(
|
|
678
|
-
|
|
569
|
+
decrypt_e2e(data, key) {
|
|
570
|
+
return this.boho.decrypt_e2e(data, key)
|
|
679
571
|
}
|
|
680
572
|
|
|
681
|
-
signal_e2e(
|
|
573
|
+
signal_e2e(tag, data, key) {
|
|
682
574
|
|
|
683
|
-
if(
|
|
684
|
-
let tagEncoded = encoder.encode(
|
|
685
|
-
let dataPack = MBP.B8(
|
|
575
|
+
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
576
|
+
let tagEncoded = encoder.encode(tag)
|
|
577
|
+
let dataPack = MBP.B8(data)
|
|
686
578
|
|
|
687
579
|
//encrypt payload area with key
|
|
688
|
-
let sercretPack = this.boho.encrypt_e2e(
|
|
580
|
+
let sercretPack = this.boho.encrypt_e2e(dataPack, key)
|
|
689
581
|
|
|
690
582
|
//change signal MsgType header into SIGNAL_E2E
|
|
691
|
-
let signalPack = MBP.pack(
|
|
692
|
-
MBP.MB('#MsgType','8', IOMsg.SIGNAL_E2E)
|
|
693
|
-
MBP.MB('#tagLen','8', tagEncoded.byteLength),
|
|
583
|
+
let signalPack = MBP.pack(
|
|
584
|
+
MBP.MB('#MsgType', '8', IOMsg.SIGNAL_E2E),
|
|
585
|
+
MBP.MB('#tagLen', '8', tagEncoded.byteLength),
|
|
694
586
|
MBP.MB('#tag', tagEncoded),
|
|
695
|
-
MBP.MB('#payloadType', '8', PAYLOAD_TYPE.BINARY
|
|
696
|
-
MBP.MB('#payload', sercretPack
|
|
697
|
-
|
|
587
|
+
MBP.MB('#payloadType', '8', PAYLOAD_TYPE.BINARY),
|
|
588
|
+
MBP.MB('#payload', sercretPack)
|
|
589
|
+
)
|
|
698
590
|
|
|
699
|
-
this.send_enc_mode(
|
|
591
|
+
this.send_enc_mode(signalPack)
|
|
700
592
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
set(
|
|
705
|
-
if(
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
set(storeName, ...args) {
|
|
597
|
+
if (!storeName || args.length == 0) {
|
|
706
598
|
return Promise.reject(new Error('set need storeName and value)'))
|
|
707
|
-
}
|
|
708
|
-
return this.req('store', 'set', storeName, ...args
|
|
599
|
+
}
|
|
600
|
+
return this.req('store', 'set', storeName, ...args)
|
|
709
601
|
}
|
|
710
|
-
|
|
711
|
-
async get(
|
|
712
|
-
if(
|
|
602
|
+
|
|
603
|
+
async get(storeName) {
|
|
604
|
+
if (!storeName) {
|
|
713
605
|
return Promise.reject(new Error('store get need storeName)'))
|
|
714
|
-
}
|
|
715
|
-
let pack = await this.req('store', 'get', storeName
|
|
606
|
+
}
|
|
607
|
+
let pack = await this.req('store', 'get', storeName)
|
|
716
608
|
let { $ } = MBP.unpack(pack.body)
|
|
717
609
|
return $
|
|
718
610
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
req(
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
req(target, topic, ...args) {
|
|
722
614
|
// console.log('common_req args', args)
|
|
723
|
-
if(
|
|
615
|
+
if (!target || !topic)
|
|
724
616
|
return Promise.reject(new Error('request need target and topic)'))
|
|
725
617
|
let sigPack;
|
|
726
|
-
if(args.length > 0){
|
|
727
|
-
|
|
728
|
-
MBP.MB('#MsgType','8', IOMsg.REQUEST)
|
|
729
|
-
MBP.MB('mid','16'
|
|
730
|
-
MBP.MB('target', target
|
|
731
|
-
MBP.MB('topic', topic
|
|
732
|
-
MBP.MBA(
|
|
733
|
-
|
|
734
|
-
}else{
|
|
735
|
-
|
|
736
|
-
MBP.MB('#MsgType','8', IOMsg.REQUEST)
|
|
737
|
-
MBP.MB('mid','16'
|
|
738
|
-
MBP.MB('target', target
|
|
739
|
-
MBP.MB('topic', topic
|
|
740
|
-
|
|
618
|
+
if (args.length > 0) {
|
|
619
|
+
sigPack = MBP.pack(
|
|
620
|
+
MBP.MB('#MsgType', '8', IOMsg.REQUEST),
|
|
621
|
+
MBP.MB('mid', '16', ++this.mid),
|
|
622
|
+
MBP.MB('target', target),
|
|
623
|
+
MBP.MB('topic', topic),
|
|
624
|
+
MBP.MBA(...args)
|
|
625
|
+
)
|
|
626
|
+
} else {
|
|
627
|
+
sigPack = MBP.pack(
|
|
628
|
+
MBP.MB('#MsgType', '8', IOMsg.REQUEST),
|
|
629
|
+
MBP.MB('mid', '16', ++this.mid),
|
|
630
|
+
MBP.MB('target', target),
|
|
631
|
+
MBP.MB('topic', topic)
|
|
632
|
+
)
|
|
741
633
|
}
|
|
742
634
|
// console.log('<< adminPack', this.mid, sigPack)
|
|
743
|
-
this.send_enc_mode(
|
|
744
|
-
return this.setMsgPromise(
|
|
635
|
+
this.send_enc_mode(sigPack)
|
|
636
|
+
return this.setMsgPromise(this.mid)
|
|
745
637
|
}
|
|
746
638
|
|
|
747
639
|
|
|
748
|
-
subscribe(tag
|
|
749
|
-
if(
|
|
750
|
-
if(
|
|
640
|
+
subscribe(tag) {
|
|
641
|
+
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
642
|
+
if (this.state !== STATES.READY) return
|
|
751
643
|
|
|
752
644
|
let tagList = tag.split(',')
|
|
753
|
-
tagList.forEach(
|
|
645
|
+
tagList.forEach(tag => {
|
|
754
646
|
this.channels.add(tag)
|
|
755
647
|
})
|
|
756
648
|
|
|
757
|
-
let tagEncoded = encoder.encode(
|
|
758
|
-
if(
|
|
649
|
+
let tagEncoded = encoder.encode(tag)
|
|
650
|
+
if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN1) throw TypeError('please use tag string bytelength below:' + SIZE_LIMIT.TAG_LEN1)
|
|
759
651
|
|
|
760
|
-
this.send_enc_mode(
|
|
761
|
-
Buffer.concat(
|
|
762
|
-
MBP.NB('8',IOMsg.SUBSCRIBE),
|
|
763
|
-
MBP.NB('8', tagEncoded.byteLength),
|
|
764
|
-
tagEncoded
|
|
652
|
+
this.send_enc_mode(
|
|
653
|
+
Buffer.concat([
|
|
654
|
+
MBP.NB('8', IOMsg.SUBSCRIBE),
|
|
655
|
+
MBP.NB('8', tagEncoded.byteLength),
|
|
656
|
+
tagEncoded]))
|
|
765
657
|
}
|
|
766
658
|
|
|
767
|
-
subscribe_promise(tag){
|
|
768
|
-
if(
|
|
769
|
-
if(
|
|
659
|
+
subscribe_promise(tag) {
|
|
660
|
+
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
661
|
+
if (this.state !== STATES.READY) {
|
|
770
662
|
// console.log('not ready state:', this.state )
|
|
771
663
|
return Promise.reject('subscribe_promise:: connection is not ready')
|
|
772
664
|
}
|
|
773
665
|
|
|
774
|
-
let tagEncoded = encoder.encode(
|
|
775
|
-
if(
|
|
666
|
+
let tagEncoded = encoder.encode(tag)
|
|
667
|
+
if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN2) throw TypeError('please use tag string bytelength: ' + SIZE_LIMIT.TAG_LEN2)
|
|
776
668
|
|
|
777
|
-
this.send_enc_mode(
|
|
778
|
-
Buffer.concat(
|
|
779
|
-
MBP.NB('8',IOMsg.SUBSCRIBE_REQ),
|
|
780
|
-
MBP.NB('16', ++this.mid),
|
|
781
|
-
MBP.NB('16', tagEncoded.byteLength),
|
|
782
|
-
tagEncoded
|
|
783
|
-
return this.setMsgPromise(
|
|
669
|
+
this.send_enc_mode(
|
|
670
|
+
Buffer.concat([
|
|
671
|
+
MBP.NB('8', IOMsg.SUBSCRIBE_REQ),
|
|
672
|
+
MBP.NB('16', ++this.mid),
|
|
673
|
+
MBP.NB('16', tagEncoded.byteLength),
|
|
674
|
+
tagEncoded]))
|
|
675
|
+
return this.setMsgPromise(this.mid)
|
|
784
676
|
}
|
|
785
677
|
|
|
786
|
-
subscribe_memory_channels(
|
|
787
|
-
if(this.channels.size == 0) return
|
|
788
|
-
let chList = Array.from(
|
|
678
|
+
subscribe_memory_channels() { //local cache . auto_resubscribe
|
|
679
|
+
if (this.channels.size == 0) return
|
|
680
|
+
let chList = Array.from(this.channels).join(',')
|
|
789
681
|
// console.log('<< subscibe memory channels by cid', chList , this.cid )
|
|
790
682
|
|
|
791
|
-
this.subscribe_promise(
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
683
|
+
this.subscribe_promise(chList)
|
|
684
|
+
.then((res) => {
|
|
685
|
+
// console.log('>> SUBSCRIBE_REQ result', res ) // return code == map.size
|
|
686
|
+
}).catch((e) => {
|
|
687
|
+
console.log('>> SUBSCRIBE FAIL:', e)
|
|
688
|
+
})
|
|
797
689
|
|
|
798
690
|
}
|
|
799
691
|
|
|
800
|
-
unsubscribe(tag = ""){
|
|
692
|
+
unsubscribe(tag = "") {
|
|
801
693
|
// console.log('unsub', tag)
|
|
802
|
-
if(
|
|
803
|
-
|
|
804
|
-
if(tag == ""){
|
|
694
|
+
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
695
|
+
|
|
696
|
+
if (tag == "") {
|
|
805
697
|
// console.log('unsub all')
|
|
806
698
|
this.channels.clear();
|
|
807
|
-
}else{
|
|
699
|
+
} else {
|
|
808
700
|
let tagList = tag.split(',')
|
|
809
|
-
tagList.forEach(
|
|
701
|
+
tagList.forEach(tag => {
|
|
810
702
|
this.channels.delete(tag)
|
|
811
703
|
})
|
|
812
704
|
}
|
|
813
705
|
|
|
814
|
-
let tagEncoded = encoder.encode(
|
|
815
|
-
if(
|
|
706
|
+
let tagEncoded = encoder.encode(tag)
|
|
707
|
+
if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN1) throw TypeError('please use tag string bytelength below:' + SIZE_LIMIT.TAG_LEN1)
|
|
816
708
|
|
|
817
|
-
this.send_enc_mode(
|
|
818
|
-
MBP.NB('8',IOMsg.UNSUBSCRIBE),
|
|
819
|
-
MBP.NB('8', tagEncoded.byteLength),
|
|
820
|
-
tagEncoded
|
|
709
|
+
this.send_enc_mode(Buffer.concat([
|
|
710
|
+
MBP.NB('8', IOMsg.UNSUBSCRIBE),
|
|
711
|
+
MBP.NB('8', tagEncoded.byteLength),
|
|
712
|
+
tagEncoded]))
|
|
821
713
|
}
|
|
822
714
|
|
|
823
715
|
|
|
824
|
-
listen(tag
|
|
825
|
-
if(
|
|
826
|
-
if(
|
|
827
|
-
if(
|
|
828
|
-
|
|
829
|
-
if(
|
|
830
|
-
this.channels.add(tag)
|
|
716
|
+
listen(tag, handler) {
|
|
717
|
+
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
718
|
+
if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
|
|
719
|
+
if (typeof handler !== 'function') throw TypeError('handler is not a function.')
|
|
720
|
+
|
|
721
|
+
if (tag.indexOf('@') !== 0) {
|
|
722
|
+
this.channels.add(tag)
|
|
831
723
|
}
|
|
832
724
|
// console.log('channels:', this.channels )
|
|
833
|
-
this.on(
|
|
725
|
+
this.on(tag, handler)
|
|
834
726
|
// do not subscribe now.
|
|
835
727
|
// will subscribe when receive CID_RES signal from server.
|
|
836
|
-
|
|
728
|
+
|
|
837
729
|
}
|
|
838
730
|
|
|
839
731
|
|
|
840
732
|
|
|
841
|
-
link(
|
|
842
|
-
if(
|
|
843
|
-
if(
|
|
844
|
-
if(
|
|
845
|
-
if(
|
|
846
|
-
|
|
847
|
-
if(
|
|
848
|
-
this.channels.add(tag)
|
|
733
|
+
link(to, tag, handler) {
|
|
734
|
+
if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
|
|
735
|
+
if (typeof tag !== 'string') throw TypeError('tag is not a string.')
|
|
736
|
+
if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
|
|
737
|
+
if (typeof handler !== 'function') throw TypeError('handler is not a function.')
|
|
738
|
+
|
|
739
|
+
if (tag.indexOf('@') !== 0) {
|
|
740
|
+
this.channels.add(tag)
|
|
849
741
|
}
|
|
850
|
-
|
|
742
|
+
|
|
851
743
|
let linkSet;
|
|
852
|
-
if(
|
|
744
|
+
if (this.linkMap.has(to)) {
|
|
853
745
|
linkSet = this.linkMap.get(to)
|
|
854
|
-
}else {
|
|
746
|
+
} else {
|
|
855
747
|
linkSet = new Set()
|
|
856
748
|
}
|
|
857
|
-
|
|
858
|
-
linkSet.add(tag
|
|
859
|
-
this.linkMap.set(
|
|
860
|
-
this.on(
|
|
861
|
-
this.subscribe(
|
|
749
|
+
|
|
750
|
+
linkSet.add(tag)
|
|
751
|
+
this.linkMap.set(to, linkSet)
|
|
752
|
+
this.on(tag, handler)
|
|
753
|
+
this.subscribe(tag)
|
|
862
754
|
// console.log('link [to] linkMap:', to, this.linkMap )
|
|
863
|
-
|
|
755
|
+
|
|
864
756
|
}
|
|
865
|
-
|
|
866
757
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
if(
|
|
870
|
-
if( tag
|
|
871
|
-
|
|
872
|
-
|
|
758
|
+
|
|
759
|
+
unlink(to, tag) {
|
|
760
|
+
if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
|
|
761
|
+
if (typeof tag !== 'string') throw TypeError('tag is not a string.')
|
|
762
|
+
if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
|
|
763
|
+
|
|
764
|
+
if (!this.linkMap.has(to)) return;
|
|
873
765
|
|
|
874
766
|
let linkSet = this.linkMap.get(to)
|
|
875
767
|
let tags = Array.from(linkSet)
|
|
876
|
-
for(let i=0; i< tags.length; i++){
|
|
877
|
-
if(
|
|
878
|
-
this.unsubscribe(
|
|
768
|
+
for (let i = 0; i < tags.length; i++) {
|
|
769
|
+
if (tags[i] == tag) {
|
|
770
|
+
this.unsubscribe(tag)
|
|
879
771
|
this.removeAllListeners(tag)
|
|
880
772
|
linkSet.delete(tag)
|
|
881
|
-
this.linkMap.set(
|
|
773
|
+
this.linkMap.set(to, linkSet)
|
|
882
774
|
break;
|
|
883
775
|
}
|
|
884
776
|
}
|
|
@@ -886,72 +778,72 @@ export class IOCore extends EventEmitter{
|
|
|
886
778
|
// console.log('unlink linkMap result:', this.linkMap )
|
|
887
779
|
}
|
|
888
780
|
|
|
889
|
-
unlinkAll(
|
|
890
|
-
if(
|
|
891
|
-
if(
|
|
781
|
+
unlinkAll(to) {
|
|
782
|
+
if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
|
|
783
|
+
if (!this.linkMap.has(to)) return;
|
|
892
784
|
|
|
893
785
|
let linkSet = this.linkMap.get(to)
|
|
894
|
-
let tags =
|
|
895
|
-
for(let i=0; i< tags.length; i++){
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
786
|
+
let tags = Array.from(linkSet)
|
|
787
|
+
for (let i = 0; i < tags.length; i++) {
|
|
788
|
+
this.unsubscribe(tags[i])
|
|
789
|
+
this.removeAllListeners(tags[i])
|
|
790
|
+
linkSet.delete(tags[i])
|
|
899
791
|
}
|
|
900
|
-
this.linkMap.delete(
|
|
792
|
+
this.linkMap.delete(to)
|
|
901
793
|
|
|
902
794
|
// console.log('unlinkAll linkMap result:', this.linkMap )
|
|
903
795
|
}
|
|
904
796
|
|
|
905
797
|
|
|
906
798
|
|
|
907
|
-
getMetric(){
|
|
908
|
-
return {
|
|
909
|
-
tx: this.txCounter,
|
|
910
|
-
rx: this.rxCounter,
|
|
911
|
-
txb: this.txBytes,
|
|
799
|
+
getMetric() {
|
|
800
|
+
return {
|
|
801
|
+
tx: this.txCounter,
|
|
802
|
+
rx: this.rxCounter,
|
|
803
|
+
txb: this.txBytes,
|
|
912
804
|
rxb: this.rxBytes,
|
|
913
|
-
last: (
|
|
805
|
+
last: (Date.now() - this.lastTxRxTime) / 1000
|
|
914
806
|
}
|
|
915
807
|
|
|
916
808
|
}
|
|
917
809
|
|
|
918
|
-
getState(){
|
|
810
|
+
getState() {
|
|
919
811
|
return this.state
|
|
920
812
|
}
|
|
921
813
|
|
|
922
|
-
getStateName(){
|
|
814
|
+
getStateName() {
|
|
923
815
|
//state <number>
|
|
924
816
|
//value of constant STATES.NAME < number >
|
|
925
817
|
//type of constant STATES.NAME name < string uppercase >
|
|
926
818
|
//stateName,eventName <string lowercase>
|
|
927
|
-
return (
|
|
819
|
+
return (STATES[this.state]).toLowerCase()
|
|
928
820
|
}
|
|
929
821
|
|
|
930
|
-
getSecurity(){
|
|
822
|
+
getSecurity() {
|
|
931
823
|
return {
|
|
932
824
|
useAuth: this.useAuth,
|
|
933
|
-
isTLS: this.TLS,
|
|
825
|
+
isTLS: this.TLS,
|
|
934
826
|
isAuthorized: this.boho.isAuthorized,
|
|
935
827
|
encMode: this.encMode,
|
|
936
828
|
usingEncryption: this.getEncryptionMode()
|
|
937
829
|
}
|
|
938
830
|
}
|
|
939
831
|
|
|
940
|
-
stateChange(state, emitEventAndMessage
|
|
832
|
+
stateChange(state, emitEventAndMessage) {
|
|
941
833
|
// STATES constant name : string upperCase
|
|
942
834
|
// eventName, .stateName : string lowerCase
|
|
943
835
|
// .state : number
|
|
944
836
|
let eventName = state.toLowerCase()
|
|
945
|
-
this.state = STATES[
|
|
946
|
-
if(emitEventAndMessage) this.emit(eventName, emitEventAndMessage)
|
|
947
|
-
|
|
948
|
-
if(
|
|
837
|
+
this.state = STATES[state.toUpperCase()] // state: number
|
|
838
|
+
if (emitEventAndMessage) this.emit(eventName, emitEventAndMessage)
|
|
839
|
+
|
|
840
|
+
if (this.stateName !== eventName) {
|
|
949
841
|
// console.log(`state: ${this.stateName} => ${eventName}` )
|
|
950
842
|
this.stateName = eventName
|
|
951
843
|
this.emit('change', eventName)
|
|
952
|
-
}
|
|
844
|
+
}
|
|
953
845
|
}
|
|
954
|
-
|
|
846
|
+
|
|
955
847
|
}
|
|
956
848
|
|
|
957
849
|
|