iosignal 3.3.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +3 -0
- package/README.md +38 -559
- package/dist/io.d.ts +16 -9
- package/dist/io.js +5 -5
- package/dist/io.js.map +1 -1
- package/dist/io.min.js +5 -5
- package/dist/io.min.js.map +1 -1
- package/dist/iosignal.js +339 -268
- package/dist/types/client/IOCore.d.ts +17 -10
- package/dist/types/common/constants.d.ts +27 -37
- package/index.js +4 -3
- package/package.json +3 -4
- package/src/auth/BohoAuth.js +48 -11
- package/src/auth/{Auth_File.js → key_providers/FileKeyProvider.js} +8 -20
- package/src/auth/{Auth_Redis.js → key_providers/RedisKeyProvider.js} +4 -7
- package/src/auth/key_providers/StringKeyProvider.js +54 -0
- package/src/client/IOCongSocket.js +5 -3
- package/src/client/IOCore.js +118 -89
- package/src/client/IOWS.js +5 -3
- package/src/client/browser/IOWebSocket.js +5 -3
- package/src/common/constants.js +31 -44
- package/src/common/util.js +3 -0
- package/src/server/Manager.js +13 -12
- package/src/server/Remote.js +4 -1
- package/src/server/RemoteCore.js +23 -17
- package/src/server/Server.js +7 -7
- package/README.ko.md +0 -566
- package/auth_file.js +0 -23
- package/auth_file.json +0 -13
- package/docs/iosignal_architecture.png +0 -0
- package/examples/react-chat-js/dist/assets/index-Cy4qaVcJ.js +0 -56
- package/examples/react-chat-js/dist/assets/index-NETrjYhz.css +0 -1
- package/examples/react-chat-js/dist/assets/index-e2KOTYW8.js +0 -65
- package/examples/react-chat-js/dist/index.html +0 -14
- package/examples/react-chat-js/index.html +0 -13
- package/examples/react-chat-js/package-lock.json +0 -1723
- package/examples/react-chat-js/package.json +0 -20
- package/examples/react-chat-js/src/App.css +0 -61
- package/examples/react-chat-js/src/App.jsx +0 -125
- package/examples/react-chat-js/src/index.css +0 -13
- package/examples/react-chat-js/src/main.jsx +0 -13
- package/examples/react-chat-js/src/shared_io.js +0 -12
- package/examples/react-chat-js/vite.config.js +0 -7
- package/examples/server/index.js +0 -65
- package/examples/server/package-lock.json +0 -878
- package/examples/server/package.json +0 -13
- package/examples/server/public/index.html +0 -26
- package/examples/svelte-chat-js/.devtools +0 -3
- package/examples/svelte-chat-js/README.md +0 -38
- package/examples/svelte-chat-js/package-lock.json +0 -1421
- package/examples/svelte-chat-js/package.json +0 -23
- package/examples/svelte-chat-js/src/app.css +0 -105
- package/examples/svelte-chat-js/src/app.d.ts +0 -13
- package/examples/svelte-chat-js/src/app.html +0 -13
- package/examples/svelte-chat-js/src/lib/images/github.svg +0 -1
- package/examples/svelte-chat-js/src/lib/images/svelte-logo.svg +0 -1
- package/examples/svelte-chat-js/src/lib/images/svelte-welcome.png +0 -0
- package/examples/svelte-chat-js/src/lib/images/svelte-welcome.webp +0 -0
- package/examples/svelte-chat-js/src/lib/shared_io.js +0 -12
- package/examples/svelte-chat-js/src/routes/+layout.svelte +0 -5
- package/examples/svelte-chat-js/src/routes/+page.js +0 -3
- package/examples/svelte-chat-js/src/routes/+page.svelte +0 -167
- package/examples/svelte-chat-js/static/favicon.svg +0 -1
- package/examples/svelte-chat-js/static/global.css +0 -19
- package/examples/svelte-chat-js/static/robots.txt +0 -3
- package/examples/svelte-chat-js/svelte.config.js +0 -23
- package/examples/svelte-chat-js/vite.config.js +0 -6
- package/src/auth/Auth_Env.js +0 -76
- package/test-browser/favicon.ico +0 -0
- package/test-browser/index.html +0 -95
- package/test-browser/server.js +0 -12
- package/test-nodejs/client-playToggle.js +0 -19
- package/test-nodejs/client.js +0 -17
- package/test-nodejs/client_api_reply.js +0 -15
- package/test-nodejs/server-Auth_Env.js +0 -19
- package/test-nodejs/server-Auth_File.js +0 -12
- package/test-nodejs/server-api_reply.js +0 -6
- package/test-nodejs/server-api_sudo.js +0 -7
- package/test-nodejs/server.js +0 -20
- package/test-nodejs/signalPack.js +0 -34
- package/test-nodejs/signaling.js +0 -61
- package/test-nodejs/simple-server.js +0 -13
package/src/client/IOCore.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import MBP from 'meta-buffer-pack'
|
|
2
2
|
import EventEmitter from "eventemitter3";
|
|
3
|
-
import { IOMsg, PAYLOAD_TYPE, SIZE_LIMIT, ENC_MODE,
|
|
3
|
+
import { IOMsg, PAYLOAD_TYPE, SIZE_LIMIT, ENC_MODE, STATE } from '../common/constants.js'
|
|
4
4
|
import { quotaTable } from '../common/quotaTable.js'
|
|
5
5
|
import { getSignalPack } from '../common/payload.js';
|
|
6
6
|
import Boho from "boho";
|
|
@@ -11,7 +11,7 @@ import Boho from "boho";
|
|
|
11
11
|
* @typedef {import('../common/constants.js').PAYLOAD_TYPE} PAYLOAD_TYPE
|
|
12
12
|
* @typedef {import('../common/constants.js').SIZE_LIMIT} SIZE_LIMIT
|
|
13
13
|
* @typedef {import('../common/constants.js').ENC_MODE} ENC_MODE
|
|
14
|
-
* @typedef {import('../common/constants.js').
|
|
14
|
+
* @typedef {import('../common/constants.js').STATE} STATE
|
|
15
15
|
* @typedef {import('../common/quotaTable.js').quotaTable} quotaTable
|
|
16
16
|
|
|
17
17
|
* @typedef {import('boho').Boho} Boho
|
|
@@ -65,7 +65,7 @@ export class IOCore extends EventEmitter {
|
|
|
65
65
|
* Current connection state (number).
|
|
66
66
|
* @type {number}
|
|
67
67
|
*/
|
|
68
|
-
this.state =
|
|
68
|
+
this.state = STATE.CLOSED; // Number type
|
|
69
69
|
/**
|
|
70
70
|
* Current connection state (string).
|
|
71
71
|
* @type {string}
|
|
@@ -207,7 +207,7 @@ export class IOCore extends EventEmitter {
|
|
|
207
207
|
close() {
|
|
208
208
|
if (this._closed) return;
|
|
209
209
|
this._closed = true;
|
|
210
|
-
// console.log('####### IOCOre.js close() called')
|
|
210
|
+
// console.log('####### IOCOre.js close() called')
|
|
211
211
|
// If auto-reconnect is disabled, we must stop the keep-alive timer.
|
|
212
212
|
if (this.autoReconnect === false) {
|
|
213
213
|
clearInterval(this.connectionCheckerIntervalID);
|
|
@@ -222,7 +222,7 @@ export class IOCore extends EventEmitter {
|
|
|
222
222
|
// To avoid the error, we wait for the connection to open, then immediately close it.
|
|
223
223
|
// We also clear other handlers to prevent any other logic from running.
|
|
224
224
|
const socket = this.socket;
|
|
225
|
-
socket.onopen = () => { if(socket) socket.close(); };
|
|
225
|
+
socket.onopen = () => { if (socket) socket.close(); };
|
|
226
226
|
socket.onmessage = null;
|
|
227
227
|
socket.onerror = null;
|
|
228
228
|
socket.onclose = null;
|
|
@@ -230,7 +230,7 @@ export class IOCore extends EventEmitter {
|
|
|
230
230
|
try {
|
|
231
231
|
// For other sockets (like TCP) or other WebSocket states, close directly.
|
|
232
232
|
this.socket.close?.();
|
|
233
|
-
} catch {}
|
|
233
|
+
} catch { }
|
|
234
234
|
}
|
|
235
235
|
this.socket = null;
|
|
236
236
|
}
|
|
@@ -238,14 +238,15 @@ export class IOCore extends EventEmitter {
|
|
|
238
238
|
this.emit('closed');
|
|
239
239
|
this.stateChange('closed');
|
|
240
240
|
}
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
/**
|
|
243
243
|
* Disables auto-reconnect and closes the current connection.
|
|
244
244
|
* The instance can be re-opened manually later. For complete cleanup, use destroy().
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
*/
|
|
246
|
+
stop() {
|
|
247
|
+
this.autoReconnect = false;
|
|
248
|
+
this.close();
|
|
249
|
+
this.stateChange('stop','stop');
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
/**
|
|
@@ -261,7 +262,7 @@ export class IOCore extends EventEmitter {
|
|
|
261
262
|
|
|
262
263
|
// Help GC
|
|
263
264
|
this.boho = null;
|
|
264
|
-
}
|
|
265
|
+
}
|
|
265
266
|
|
|
266
267
|
/**
|
|
267
268
|
* The core keep-alive logic. It checks if auto-reconnect is enabled.
|
|
@@ -278,8 +279,8 @@ export class IOCore extends EventEmitter {
|
|
|
278
279
|
* @param {string} url2 - The new URL to redirect to.
|
|
279
280
|
*/
|
|
280
281
|
redirect(url2) {
|
|
282
|
+
this.stateChange('redirecting','redirecting')
|
|
281
283
|
this.close()
|
|
282
|
-
this.stateChange('redirecting')
|
|
283
284
|
this.createConnection(url2)
|
|
284
285
|
}
|
|
285
286
|
|
|
@@ -336,29 +337,27 @@ export class IOCore extends EventEmitter {
|
|
|
336
337
|
|
|
337
338
|
/**
|
|
338
339
|
* Manually logs in with provided ID and key.
|
|
339
|
-
* @param {string} id - The user ID.
|
|
340
|
+
* @param {string} id - The user ID. or 'id.key'
|
|
340
341
|
* @param {string} key - The user key.
|
|
341
|
-
* @returns {
|
|
342
|
+
* @returns {this}
|
|
342
343
|
*/
|
|
343
344
|
login(id, key) {
|
|
344
|
-
|
|
345
|
-
|
|
345
|
+
this.auth(id, key)
|
|
346
346
|
this.useAuth = true
|
|
347
347
|
let auth_pack = this.boho.auth_req()
|
|
348
348
|
this.send(auth_pack)
|
|
349
|
-
return
|
|
349
|
+
return this
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
/**
|
|
353
353
|
* Sets up authentication for auto-login.
|
|
354
|
-
* @param {string} id - The user ID.
|
|
354
|
+
* @param {string} id - The user ID. or 'id.Key'
|
|
355
355
|
* @param {string} key - The user key.
|
|
356
|
-
* @returns {
|
|
356
|
+
* @returns {this}
|
|
357
357
|
*/
|
|
358
358
|
auth(id, key) {
|
|
359
359
|
if (!id && !key) {
|
|
360
360
|
this.emit('error', new Error('auth failed. no id and key.'))
|
|
361
|
-
return false
|
|
362
361
|
}
|
|
363
362
|
|
|
364
363
|
if (!key && id.includes('.')) {
|
|
@@ -368,10 +367,9 @@ export class IOCore extends EventEmitter {
|
|
|
368
367
|
this.boho.set_key(key)
|
|
369
368
|
} else {
|
|
370
369
|
this.emit('error', new Error('auth failed. no id or key.'))
|
|
371
|
-
return false
|
|
372
370
|
}
|
|
373
371
|
this.useAuth = true
|
|
374
|
-
return
|
|
372
|
+
return this
|
|
375
373
|
}
|
|
376
374
|
|
|
377
375
|
/**
|
|
@@ -433,13 +431,13 @@ export class IOCore extends EventEmitter {
|
|
|
433
431
|
case IOMsg.ECHO:
|
|
434
432
|
try {
|
|
435
433
|
let str = decoder.decode(buffer.subarray(1))
|
|
436
|
-
|
|
434
|
+
|
|
437
435
|
this.emit('echo', str)
|
|
438
436
|
} catch (error) {
|
|
439
437
|
this.emit('error', new Error('ECHO data error'))
|
|
440
438
|
}
|
|
441
439
|
break;
|
|
442
|
-
|
|
440
|
+
|
|
443
441
|
case IOMsg.IAM_RES:
|
|
444
442
|
try {
|
|
445
443
|
let str = decoder.decode(buffer.subarray(1))
|
|
@@ -448,8 +446,7 @@ export class IOCore extends EventEmitter {
|
|
|
448
446
|
if (jsonInfo.nick) { this.nick = jsonInfo.nick; }
|
|
449
447
|
if (jsonInfo.did) { this.did = jsonInfo.did; }
|
|
450
448
|
if (jsonInfo.uid) { this.uid = jsonInfo.uid; }
|
|
451
|
-
|
|
452
|
-
this.emit('iam_res', str )
|
|
449
|
+
this.emit('iam_res', str)
|
|
453
450
|
} catch (error) {
|
|
454
451
|
this.emit('error', new Error('IAM_RES data error'))
|
|
455
452
|
}
|
|
@@ -461,21 +458,21 @@ export class IOCore extends EventEmitter {
|
|
|
461
458
|
|
|
462
459
|
// **IMPORTANT** change state before subscribe.
|
|
463
460
|
this.stateChange('ready', 'cid_ready')
|
|
464
|
-
this.subscribe_memory_channels()
|
|
461
|
+
this.subscribe_memory_channels() // tags registered by listen() or link().
|
|
465
462
|
break;
|
|
466
463
|
|
|
467
464
|
case IOMsg.QUOTA_LEVEL:
|
|
468
465
|
let quotaLevel = buffer[1]
|
|
469
466
|
this.level = quotaLevel;
|
|
470
467
|
this.quota = quotaTable[quotaLevel];
|
|
471
|
-
console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota))
|
|
468
|
+
// console.log('[QUOTA_LEVEL]', JSON.stringify(this.quota))
|
|
472
469
|
break;
|
|
473
470
|
|
|
474
|
-
case IOMsg.
|
|
471
|
+
case IOMsg.AUTH_CLEAR:
|
|
475
472
|
this.useAuth = false;
|
|
476
473
|
this.boho.clearAuth();
|
|
474
|
+
this.stateChange('auth_clear', 'server request auth_clear.')
|
|
477
475
|
this.stop();
|
|
478
|
-
console.log('[SERVER_CLEAR_AUTH] io stop.')
|
|
479
476
|
break;
|
|
480
477
|
|
|
481
478
|
case IOMsg.SERVER_REDIRECT:
|
|
@@ -552,8 +549,11 @@ export class IOCore extends EventEmitter {
|
|
|
552
549
|
switch (payloadType) {
|
|
553
550
|
|
|
554
551
|
case PAYLOAD_TYPE.EMPTY:
|
|
555
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
556
|
-
else
|
|
552
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, null)
|
|
553
|
+
else {
|
|
554
|
+
this.emit(tag, tag, null)
|
|
555
|
+
this.emit('message', tag, null)
|
|
556
|
+
}
|
|
557
557
|
break;
|
|
558
558
|
|
|
559
559
|
case PAYLOAD_TYPE.TEXT:
|
|
@@ -564,33 +564,48 @@ export class IOCore extends EventEmitter {
|
|
|
564
564
|
payloadStringWithoutNull = payloadBuffer.subarray(0, payloadBuffer.byteLength - 1)
|
|
565
565
|
}
|
|
566
566
|
let oneString = decoder.decode(payloadStringWithoutNull)
|
|
567
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
568
|
-
if (tag !== '@')
|
|
567
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, oneString)
|
|
568
|
+
if (tag !== '@') {
|
|
569
|
+
this.emit(tag, tag, oneString)
|
|
570
|
+
this.emit('message', tag, oneString)
|
|
571
|
+
}
|
|
569
572
|
break;
|
|
570
573
|
|
|
571
574
|
case PAYLOAD_TYPE.BINARY:
|
|
572
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
573
|
-
if (tag !== '@')
|
|
575
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, payloadBuffer)
|
|
576
|
+
if (tag !== '@') {
|
|
577
|
+
this.emit(tag, tag, payloadBuffer)
|
|
578
|
+
this.emit('message', tag, payloadBuffer)
|
|
579
|
+
}
|
|
574
580
|
break;
|
|
575
581
|
|
|
576
582
|
case PAYLOAD_TYPE.OBJECT:
|
|
577
583
|
let oneObjectBuffer = decoder.decode(payloadBuffer)
|
|
578
584
|
let oneJSONObject = JSON.parse(oneObjectBuffer)
|
|
579
|
-
if (tag.indexOf('@') === 0) this.emit('@',
|
|
580
|
-
if (tag !== '@')
|
|
585
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, oneJSONObject)
|
|
586
|
+
if (tag !== '@') {
|
|
587
|
+
this.emit(tag, tag, oneJSONObject)
|
|
588
|
+
this.emit('message', tag, oneJSONObject)
|
|
589
|
+
}
|
|
581
590
|
break;
|
|
582
591
|
|
|
583
592
|
case PAYLOAD_TYPE.MJSON:
|
|
584
593
|
let mjsonBuffer = decoder.decode(payloadBuffer)
|
|
585
594
|
let mjson = JSON.parse(mjsonBuffer)
|
|
586
|
-
if (tag.indexOf('@') === 0) this.emit('@', ...mjson
|
|
587
|
-
if (tag !== '@')
|
|
595
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, ...mjson)
|
|
596
|
+
if (tag !== '@') {
|
|
597
|
+
this.emit(tag, tag, ...mjson)
|
|
598
|
+
this.emit('message', tag, ...mjson)
|
|
599
|
+
}
|
|
588
600
|
break;
|
|
589
601
|
|
|
590
602
|
case PAYLOAD_TYPE.MBA:
|
|
591
603
|
let mbaObject = MBP.unpack(payloadBuffer)
|
|
592
|
-
if (tag.indexOf('@') === 0) this.emit('@', ...mbaObject.args
|
|
593
|
-
if (tag !== '@')
|
|
604
|
+
if (tag.indexOf('@') === 0) this.emit('@', tag, ...mbaObject.args)
|
|
605
|
+
if (tag !== '@') {
|
|
606
|
+
this.emit(tag, tag, ...mbaObject.args)
|
|
607
|
+
this.emit('message', tag, ...mbaObject.args)
|
|
608
|
+
}
|
|
594
609
|
break;
|
|
595
610
|
|
|
596
611
|
default:
|
|
@@ -598,7 +613,8 @@ export class IOCore extends EventEmitter {
|
|
|
598
613
|
}
|
|
599
614
|
|
|
600
615
|
} catch (err) {
|
|
601
|
-
this.emit('error', new Error('
|
|
616
|
+
// this.emit('error', new Error('IOCore IOMsg.SIGNAL parser err', err))
|
|
617
|
+
console.log('IOCore IOMsg.SIGNAL parser err', err)
|
|
602
618
|
}
|
|
603
619
|
break;
|
|
604
620
|
|
|
@@ -607,24 +623,25 @@ export class IOCore extends EventEmitter {
|
|
|
607
623
|
break;
|
|
608
624
|
|
|
609
625
|
case Boho.BohoMsg.AUTH_NONCE:
|
|
626
|
+
this.stateChange('auth_nonce','server sent auth_nonce.')
|
|
610
627
|
let auth_hmac = this.boho.auth_hmac(buffer)
|
|
611
628
|
if (auth_hmac) {
|
|
612
629
|
this.send(auth_hmac)
|
|
613
630
|
} else {
|
|
614
|
-
this.stateChange('auth_fail', '
|
|
631
|
+
this.stateChange('auth_fail', 'boho.auth_hmac() invalid auth_nonce.')
|
|
615
632
|
}
|
|
616
633
|
break;
|
|
617
634
|
|
|
618
635
|
case Boho.BohoMsg.AUTH_FAIL:
|
|
619
|
-
this.stateChange('auth_fail', '
|
|
636
|
+
this.stateChange('auth_fail', 'auth_fail from server.')
|
|
620
637
|
break;
|
|
621
638
|
|
|
622
639
|
case Boho.BohoMsg.AUTH_ACK:
|
|
623
640
|
if (this.boho.check_auth_ack_hmac(buffer)) {
|
|
624
|
-
this.stateChange('
|
|
641
|
+
this.stateChange('auth_ack', 'server sent auth_ack')
|
|
625
642
|
this.send(Buffer.from([IOMsg.CID_REQ]))
|
|
626
643
|
} else {
|
|
627
|
-
this.stateChange('auth_fail', 'invalid server_hmac')
|
|
644
|
+
this.stateChange('auth_fail', 'check_auth_ack_hmac() invalid server_hmac')
|
|
628
645
|
}
|
|
629
646
|
break;
|
|
630
647
|
|
|
@@ -811,14 +828,15 @@ export class IOCore extends EventEmitter {
|
|
|
811
828
|
|
|
812
829
|
|
|
813
830
|
/**
|
|
814
|
-
*
|
|
831
|
+
* alias of signal()
|
|
832
|
+
* Sends a signal with a tag and arguments.
|
|
833
|
+
* @param {string} tag - The signal tag.
|
|
815
834
|
* @param {...any} args - Arguments for the signal.
|
|
816
835
|
*/
|
|
817
|
-
publish(...args) {
|
|
818
|
-
this.signal(...args)
|
|
836
|
+
publish(tag, ...args) {
|
|
837
|
+
this.signal(tag, ...args)
|
|
819
838
|
}
|
|
820
839
|
|
|
821
|
-
|
|
822
840
|
/**
|
|
823
841
|
* Sends a signal with a tag and arguments.
|
|
824
842
|
* @param {string} tag - The signal tag.
|
|
@@ -827,7 +845,6 @@ export class IOCore extends EventEmitter {
|
|
|
827
845
|
*/
|
|
828
846
|
signal(tag, ...args) {
|
|
829
847
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
830
|
-
|
|
831
848
|
let signalPack = getSignalPack(tag, ...args)
|
|
832
849
|
this.send_enc_mode(signalPack)
|
|
833
850
|
}
|
|
@@ -871,7 +888,6 @@ export class IOCore extends EventEmitter {
|
|
|
871
888
|
}
|
|
872
889
|
|
|
873
890
|
|
|
874
|
-
|
|
875
891
|
/**
|
|
876
892
|
* Sets a value in the store.
|
|
877
893
|
* @param {string} storeName - The name of the store.
|
|
@@ -939,21 +955,24 @@ export class IOCore extends EventEmitter {
|
|
|
939
955
|
*/
|
|
940
956
|
subscribe(tag) {
|
|
941
957
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
942
|
-
if (
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
958
|
+
if (tag.length > SIZE_LIMIT.TAG_LEN1) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN1)
|
|
959
|
+
if (this.state !== STATE.READY) return
|
|
960
|
+
|
|
961
|
+
// subscribe 사용시, 사용 'ready' 이벤트시 메뉴얼 등록되므로 여기에 등록하면 2중 호출된다.
|
|
962
|
+
// 즉, channels 등록은 listen 같은 자동화 구독시만 사용.
|
|
963
|
+
// let tagList = tag.split(',')
|
|
964
|
+
// tagList.forEach(tag => {
|
|
965
|
+
// this.channels.add(tag)
|
|
966
|
+
// })
|
|
967
|
+
|
|
968
|
+
try {
|
|
969
|
+
let tagEncoded = encoder.encode(tag)
|
|
970
|
+
this.send_enc_mode(
|
|
971
|
+
Buffer.concat([
|
|
972
|
+
MBP.NB('8', IOMsg.SUBSCRIBE),
|
|
973
|
+
MBP.NB('8', tagEncoded.byteLength),
|
|
974
|
+
tagEncoded]))
|
|
975
|
+
} catch (error) { }
|
|
957
976
|
}
|
|
958
977
|
|
|
959
978
|
/**
|
|
@@ -964,20 +983,22 @@ export class IOCore extends EventEmitter {
|
|
|
964
983
|
*/
|
|
965
984
|
subscribe_promise(tag) {
|
|
966
985
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
967
|
-
if (
|
|
986
|
+
if (tag.length > SIZE_LIMIT.TAG_LEN2) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN2)
|
|
987
|
+
|
|
988
|
+
if (this.state !== STATE.READY) {
|
|
968
989
|
return Promise.reject('subscribe_promise:: connection is not ready')
|
|
969
990
|
}
|
|
970
991
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
992
|
+
try {
|
|
993
|
+
let tagEncoded = encoder.encode(tag)
|
|
994
|
+
this.send_enc_mode(
|
|
995
|
+
Buffer.concat([
|
|
996
|
+
MBP.NB('8', IOMsg.SUBSCRIBE_REQ),
|
|
997
|
+
MBP.NB('16', ++this.mid),
|
|
998
|
+
MBP.NB('16', tagEncoded.byteLength),
|
|
999
|
+
tagEncoded]))
|
|
1000
|
+
return this.setMsgPromise(this.mid)
|
|
1001
|
+
} catch (error) { }
|
|
981
1002
|
}
|
|
982
1003
|
|
|
983
1004
|
/**
|
|
@@ -1039,7 +1060,7 @@ export class IOCore extends EventEmitter {
|
|
|
1039
1060
|
}
|
|
1040
1061
|
this.on(tag, handler)
|
|
1041
1062
|
// do not subscribe now.
|
|
1042
|
-
// will subscribe when receive CID_RES
|
|
1063
|
+
// will subscribe when io state is 'ready'. (receive CID_RES from server)
|
|
1043
1064
|
|
|
1044
1065
|
}
|
|
1045
1066
|
|
|
@@ -1150,10 +1171,10 @@ export class IOCore extends EventEmitter {
|
|
|
1150
1171
|
*/
|
|
1151
1172
|
getStateName() {
|
|
1152
1173
|
//state <number>
|
|
1153
|
-
//value of constant
|
|
1154
|
-
//type of constant
|
|
1174
|
+
//value of constant STATE.NAME < number >
|
|
1175
|
+
//type of constant STATE.NAME name < string uppercase >
|
|
1155
1176
|
//stateName,eventName <string lowercase>
|
|
1156
|
-
return (
|
|
1177
|
+
return (STATE[this.state]).toLowerCase()
|
|
1157
1178
|
}
|
|
1158
1179
|
|
|
1159
1180
|
/**
|
|
@@ -1174,15 +1195,23 @@ export class IOCore extends EventEmitter {
|
|
|
1174
1195
|
* Changes the connection state and emits events.
|
|
1175
1196
|
* @param {string} state - The new state name (e.g., 'ready', 'closed').
|
|
1176
1197
|
* @param {string} [emitEventAndMessage] - Optional message to emit with the state change event.
|
|
1198
|
+
*
|
|
1199
|
+
* 주의.
|
|
1200
|
+
* 1. 상태가 변경 될 때만 'change' 이벤트 호출된다.
|
|
1201
|
+
* 2. emitEventAndMessage 옵션 값이 지정되야 해당 이벤트 이름이 호출된다.
|
|
1202
|
+
* 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
|
|
1177
1203
|
*/
|
|
1178
1204
|
stateChange(state, emitEventAndMessage) {
|
|
1179
|
-
//
|
|
1180
|
-
// eventName
|
|
1181
|
-
// .state
|
|
1205
|
+
// STATE constant name <string> upperCase
|
|
1206
|
+
// eventName and .stateName <string> lowerCase
|
|
1207
|
+
// .state <number>
|
|
1182
1208
|
// console.log('### stateChange reason:', emitEventAndMessage )
|
|
1183
1209
|
let eventName = state.toLowerCase()
|
|
1184
|
-
this.state =
|
|
1185
|
-
|
|
1210
|
+
this.state = STATE[state.toUpperCase()] // state: number
|
|
1211
|
+
|
|
1212
|
+
if (emitEventAndMessage) {
|
|
1213
|
+
this.emit(eventName, emitEventAndMessage)
|
|
1214
|
+
}
|
|
1186
1215
|
|
|
1187
1216
|
if (this.stateName !== eventName) {
|
|
1188
1217
|
this.stateName = eventName
|
package/src/client/IOWS.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IOCore } from "./IOCore.js";
|
|
2
|
-
import {
|
|
2
|
+
import { STATE } from "../common/constants.js";
|
|
3
3
|
import { WebSocket } from "ws";
|
|
4
4
|
|
|
5
5
|
// Node.js 'ws' websocket
|
|
@@ -28,15 +28,17 @@ export class IOWS extends IOCore {
|
|
|
28
28
|
keepAlive() {
|
|
29
29
|
if (!this.autoReconnect) return;
|
|
30
30
|
// Reconnect only if the socket is closed and the state reflects that.
|
|
31
|
-
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED)
|
|
31
|
+
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) ) {
|
|
32
32
|
this.open();
|
|
33
|
+
}else{
|
|
34
|
+
this.ping();
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
createConnection(url) {
|
|
37
39
|
// node WebSocket
|
|
38
40
|
this.socket = new WebSocket(url);
|
|
39
|
-
this.stateChange('
|
|
41
|
+
this.stateChange('connecting','connecting')
|
|
40
42
|
|
|
41
43
|
this.socket.onopen = () => {
|
|
42
44
|
this.socket.on('message', this.onWebSocketMessage.bind(this));
|
|
@@ -104,13 +104,15 @@ export default class IO extends IOCore {
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
|
-
* Keeps the connection alive by re-
|
|
107
|
+
* Keeps the connection alive by re-connecting if closed.
|
|
108
108
|
*/
|
|
109
109
|
keepAlive() {
|
|
110
110
|
if (!this.autoReconnect) return;
|
|
111
111
|
// Reconnect only if the socket is closed and the state reflects that.
|
|
112
|
-
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED)
|
|
112
|
+
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) ) {
|
|
113
113
|
this.open();
|
|
114
|
+
}else{
|
|
115
|
+
this.ping();
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
|
|
@@ -126,7 +128,7 @@ export default class IO extends IOCore {
|
|
|
126
128
|
this.socket = new WebSocket(url);
|
|
127
129
|
this.socket.binaryType = IO.binaryType
|
|
128
130
|
|
|
129
|
-
this.stateChange('
|
|
131
|
+
this.stateChange('connecting','connecting')
|
|
130
132
|
|
|
131
133
|
this.socket.onopen = () => {
|
|
132
134
|
|
package/src/common/constants.js
CHANGED
|
@@ -1,52 +1,40 @@
|
|
|
1
1
|
|
|
2
2
|
/**
|
|
3
|
-
* @typedef {object}
|
|
4
|
-
* @property {number}
|
|
3
|
+
* @typedef {object} STATE
|
|
4
|
+
* @property {number} CONNECTING
|
|
5
5
|
* @property {number} OPEN
|
|
6
|
-
* @property {number} CLOSING
|
|
7
|
-
* @property {number} CLOSED
|
|
8
6
|
* @property {number} SERVER_READY
|
|
9
|
-
* @property {number}
|
|
10
|
-
* @property {number}
|
|
7
|
+
* @property {number} AUTH_ACK
|
|
8
|
+
* @property {number} CLOSING
|
|
11
9
|
* @property {number} READY
|
|
10
|
+
* @property {number} AUTH_FAIL
|
|
11
|
+
* @property {number} AUTH_CLEAR
|
|
12
|
+
* @property {number} CLOSING
|
|
13
|
+
* @property {number} CLOSED
|
|
14
|
+
* @property {number} STOP
|
|
12
15
|
* @property {number} REDIRECTING
|
|
13
16
|
*/
|
|
14
|
-
// Client
|
|
15
|
-
export const
|
|
16
|
-
|
|
17
|
-
OPEN:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
// Client STATE: name and number
|
|
18
|
+
export const STATE = {
|
|
19
|
+
CONNECTING: 0,
|
|
20
|
+
OPEN: 1,
|
|
21
|
+
SERVER_READY: 10,
|
|
22
|
+
AUTH_REQ: 11,
|
|
23
|
+
AUTH_NONCE: 12,
|
|
24
|
+
AUTH_HMAC: 13,
|
|
25
|
+
AUTH_ACK: 14,
|
|
26
|
+
AUTH_FAIL: 15,
|
|
27
|
+
AUTH_CLEAR: 16,
|
|
28
|
+
CID_REQ: 17,
|
|
29
|
+
CID_RES: 18,
|
|
30
|
+
READY: 19,
|
|
31
|
+
CLOSING: 2,
|
|
32
|
+
CLOSED: 3,
|
|
33
|
+
STOP: 4,
|
|
34
|
+
REDIRECTING: 5
|
|
25
35
|
}
|
|
26
|
-
for (let c in
|
|
36
|
+
for (let c in STATE) { STATE[STATE[c]] = c }
|
|
27
37
|
|
|
28
|
-
/**
|
|
29
|
-
* @typedef {object} CLIENT_STATE
|
|
30
|
-
* @property {number} INIT
|
|
31
|
-
* @property {number} SENT_SERVER_READY
|
|
32
|
-
* @property {number} RECV_AUTH_REQ
|
|
33
|
-
* @property {number} SENT_SERVER_NONCE
|
|
34
|
-
* @property {number} RECV_AUTH_HMAC
|
|
35
|
-
* @property {number} AUTH_FAIL
|
|
36
|
-
* @property {number} AUTH_READY
|
|
37
|
-
* @property {number} CID_READY
|
|
38
|
-
*/
|
|
39
|
-
export const CLIENT_STATE = {
|
|
40
|
-
INIT: 0,
|
|
41
|
-
SENT_SERVER_READY: 1,
|
|
42
|
-
RECV_AUTH_REQ: 2,
|
|
43
|
-
SENT_SERVER_NONCE: 3,
|
|
44
|
-
RECV_AUTH_HMAC: 4,
|
|
45
|
-
AUTH_FAIL: 5,
|
|
46
|
-
AUTH_READY: 6,
|
|
47
|
-
CID_READY: 7
|
|
48
|
-
}
|
|
49
|
-
for (let c in CLIENT_STATE) { CLIENT_STATE[CLIENT_STATE[c]] = c }
|
|
50
38
|
|
|
51
39
|
/**
|
|
52
40
|
* @typedef {object} ENC_MODE
|
|
@@ -75,7 +63,7 @@ for (let c in ENC_MODE) { ENC_MODE[ENC_MODE[c]] = c }
|
|
|
75
63
|
export const SIZE_LIMIT = {
|
|
76
64
|
TAG_LEN1: 255,
|
|
77
65
|
TAG_LEN2: 65535,
|
|
78
|
-
CONNECTION_CHECKER_PERIOD:
|
|
66
|
+
CONNECTION_CHECKER_PERIOD: 30000,
|
|
79
67
|
PROMISE_TIMEOUT: 5000,
|
|
80
68
|
DID: 8,
|
|
81
69
|
CID: 12
|
|
@@ -107,7 +95,7 @@ for (let c in PAYLOAD_TYPE) { PAYLOAD_TYPE[PAYLOAD_TYPE[c]] = c }
|
|
|
107
95
|
* @property {number} CID_REQ
|
|
108
96
|
* @property {number} CID_RES
|
|
109
97
|
* @property {number} QUOTA_LEVEL
|
|
110
|
-
* @property {number}
|
|
98
|
+
* @property {number} AUTH_CLEAR
|
|
111
99
|
* @property {number} SERVER_REDIRECT
|
|
112
100
|
* @property {number} LOOP
|
|
113
101
|
* @property {number} ECHO
|
|
@@ -165,9 +153,8 @@ export let IOMsg = {
|
|
|
165
153
|
CID_REQ: 0xC1,
|
|
166
154
|
CID_RES: 0xC2,
|
|
167
155
|
QUOTA_LEVEL: 0xC3,
|
|
168
|
-
|
|
156
|
+
AUTH_CLEAR: 0xC4,
|
|
169
157
|
SERVER_REDIRECT: 0xC5,
|
|
170
|
-
|
|
171
158
|
// ..
|
|
172
159
|
LOOP: 0xCB,
|
|
173
160
|
ECHO: 0xCC,
|