iosignal 3.0.0 → 3.1.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.ko.md +566 -0
- package/README.md +561 -2
- package/dist/io.d.ts +481 -0
- package/dist/io.js +3 -3
- package/dist/io.js.map +1 -1
- package/dist/io.min.js +3 -3
- package/dist/io.min.js.map +1 -1
- package/dist/iosignal.js +558 -104
- package/dist/types/client/IOCore.d.ts +408 -0
- package/dist/types/client/browser/IOWebSocket.d.ts +75 -0
- package/dist/types/common/constants.d.ts +169 -0
- package/dist/types/common/payload.d.ts +6 -0
- package/dist/types/common/quotaTable.d.ts +47 -0
- package/examples/react-chat-js/dist/assets/index-Cy4qaVcJ.js +56 -0
- package/examples/react-chat-js/dist/assets/index-NETrjYhz.css +1 -0
- package/examples/react-chat-js/dist/index.html +14 -0
- package/examples/react-chat-js/index.html +13 -0
- package/examples/react-chat-js/package-lock.json +1723 -0
- package/examples/react-chat-js/package.json +20 -0
- package/examples/react-chat-js/src/App.css +61 -0
- package/examples/react-chat-js/src/App.jsx +125 -0
- package/examples/react-chat-js/src/index.css +13 -0
- package/examples/react-chat-js/src/main.jsx +13 -0
- package/examples/react-chat-js/src/shared_io.js +12 -0
- package/examples/react-chat-js/vite.config.js +7 -0
- package/examples/server/index.js +12 -0
- package/examples/server/package-lock.json +47 -0
- package/examples/server/package.json +12 -0
- package/examples/svelte-chat-js/.devtools +3 -0
- package/examples/svelte-chat-js/README.md +38 -0
- package/examples/svelte-chat-js/package-lock.json +1505 -0
- package/examples/svelte-chat-js/package.json +22 -0
- package/examples/svelte-chat-js/src/app.css +105 -0
- package/examples/svelte-chat-js/src/app.d.ts +13 -0
- package/examples/svelte-chat-js/src/app.html +12 -0
- package/examples/svelte-chat-js/src/lib/images/github.svg +1 -0
- package/examples/svelte-chat-js/src/lib/images/svelte-logo.svg +1 -0
- 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 +12 -0
- package/examples/svelte-chat-js/src/routes/+layout.svelte +9 -0
- package/examples/svelte-chat-js/src/routes/+page.js +3 -0
- package/examples/svelte-chat-js/src/routes/+page.svelte +162 -0
- package/examples/svelte-chat-js/static/favicon.svg +1 -0
- package/examples/svelte-chat-js/static/global.css +19 -0
- package/examples/svelte-chat-js/static/robots.txt +3 -0
- package/examples/svelte-chat-js/svelte.config.js +15 -0
- package/examples/svelte-chat-js/vite.config.js +6 -0
- package/package.json +9 -3
- package/rollup.config.js +11 -4
- package/src/client/IOCongSocket.js +20 -9
- package/src/client/IOCore.js +437 -79
- package/src/client/IOWS.js +12 -15
- package/src/client/browser/IOWebSocket.js +101 -17
- package/src/common/constants.js +91 -1
- package/tsconfig.json +24 -0
- package/docs/README.kr.md +0 -230
package/dist/iosignal.js
CHANGED
|
@@ -13,7 +13,7 @@ import require$$2 from 'os';
|
|
|
13
13
|
import require$$0$1 from 'buffer';
|
|
14
14
|
import { memoryUsage } from 'process';
|
|
15
15
|
|
|
16
|
-
var version = "3.
|
|
16
|
+
var version = "3.1.0";
|
|
17
17
|
|
|
18
18
|
var t$1,e$1={},r$1={};var n$1,i$1,o$1={};
|
|
19
19
|
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */function f$1(){return n$1||(n$1=1,o$1.read=function(t,e,r,n,i){var o,f,u=8*i-n-1,s=(1<<u)-1,h=s>>1,a=-7,c=r?i-1:0,l=r?-1:1,p=t[e+c];for(c+=l,o=p&(1<<-a)-1,p>>=-a,a+=u;a>0;o=256*o+t[e+c],c+=l,a-=8);for(f=o&(1<<-a)-1,o>>=-a,a+=n;a>0;f=256*f+t[e+c],c+=l,a-=8);if(0===o)o=1-h;else {if(o===s)return f?NaN:1/0*(p?-1:1);f+=Math.pow(2,n),o-=h;}return (p?-1:1)*f*Math.pow(2,o-n)},o$1.write=function(t,e,r,n,i,o){var f,u,s,h=8*o-i-1,a=(1<<h)-1,c=a>>1,l=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,p=n?0:o-1,y=n?1:-1,g=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(u=isNaN(e)?1:0,f=a):(f=Math.floor(Math.log(e)/Math.LN2),e*(s=Math.pow(2,-f))<1&&(f--,s*=2),(e+=f+c>=1?l/s:l*Math.pow(2,1-c))*s>=2&&(f++,s/=2),f+c>=a?(u=0,f=a):f+c>=1?(u=(e*s-1)*Math.pow(2,i),f+=c):(u=e*Math.pow(2,c-1)*Math.pow(2,i),f=0));i>=8;t[r+p]=255&u,p+=y,u/=256,i-=8);for(f=f<<i|u,h+=i;h>0;t[r+p]=255&f,p+=y,f/=256,h-=8);t[r+p-y]|=128*g;}),o$1}
|
|
@@ -378,6 +378,18 @@ function requireEventemitter3 () {
|
|
|
378
378
|
var eventemitter3Exports = requireEventemitter3();
|
|
379
379
|
var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
|
|
380
380
|
|
|
381
|
+
/**
|
|
382
|
+
* @typedef {object} STATES
|
|
383
|
+
* @property {number} OPENING
|
|
384
|
+
* @property {number} OPEN
|
|
385
|
+
* @property {number} CLOSING
|
|
386
|
+
* @property {number} CLOSED
|
|
387
|
+
* @property {number} SERVER_READY
|
|
388
|
+
* @property {number} AUTH_FAIL
|
|
389
|
+
* @property {number} AUTH_READY
|
|
390
|
+
* @property {number} READY
|
|
391
|
+
* @property {number} REDIRECTING
|
|
392
|
+
*/
|
|
381
393
|
// Client STATES: name and number
|
|
382
394
|
const STATES = {
|
|
383
395
|
OPENING: 0,
|
|
@@ -392,7 +404,17 @@ const STATES = {
|
|
|
392
404
|
};
|
|
393
405
|
for (let c in STATES) { STATES[STATES[c]] = c; }
|
|
394
406
|
|
|
395
|
-
|
|
407
|
+
/**
|
|
408
|
+
* @typedef {object} CLIENT_STATE
|
|
409
|
+
* @property {number} INIT
|
|
410
|
+
* @property {number} SENT_SERVER_READY
|
|
411
|
+
* @property {number} RECV_AUTH_REQ
|
|
412
|
+
* @property {number} SENT_SERVER_NONCE
|
|
413
|
+
* @property {number} RECV_AUTH_HMAC
|
|
414
|
+
* @property {number} AUTH_FAIL
|
|
415
|
+
* @property {number} AUTH_READY
|
|
416
|
+
* @property {number} CID_READY
|
|
417
|
+
*/
|
|
396
418
|
const CLIENT_STATE = {
|
|
397
419
|
INIT: 0,
|
|
398
420
|
SENT_SERVER_READY: 1,
|
|
@@ -405,6 +427,12 @@ const CLIENT_STATE = {
|
|
|
405
427
|
};
|
|
406
428
|
for (let c in CLIENT_STATE) { CLIENT_STATE[CLIENT_STATE[c]] = c; }
|
|
407
429
|
|
|
430
|
+
/**
|
|
431
|
+
* @typedef {object} ENC_MODE
|
|
432
|
+
* @property {number} NO
|
|
433
|
+
* @property {number} YES
|
|
434
|
+
* @property {number} AUTO
|
|
435
|
+
*/
|
|
408
436
|
let ENC_MODE = {
|
|
409
437
|
NO: 0,
|
|
410
438
|
YES: 1,
|
|
@@ -414,6 +442,15 @@ let ENC_MODE = {
|
|
|
414
442
|
for (let c in ENC_MODE) { ENC_MODE[ENC_MODE[c]] = c; }
|
|
415
443
|
|
|
416
444
|
|
|
445
|
+
/**
|
|
446
|
+
* @typedef {object} SIZE_LIMIT
|
|
447
|
+
* @property {number} TAG_LEN1
|
|
448
|
+
* @property {number} TAG_LEN2
|
|
449
|
+
* @property {number} CONNECTION_CHECKER_PERIOD
|
|
450
|
+
* @property {number} PROMISE_TIMEOUT
|
|
451
|
+
* @property {number} DID
|
|
452
|
+
* @property {number} CID
|
|
453
|
+
*/
|
|
417
454
|
const SIZE_LIMIT = {
|
|
418
455
|
TAG_LEN1: 255,
|
|
419
456
|
TAG_LEN2: 65535,
|
|
@@ -423,6 +460,15 @@ const SIZE_LIMIT = {
|
|
|
423
460
|
CID: 12
|
|
424
461
|
};
|
|
425
462
|
|
|
463
|
+
/**
|
|
464
|
+
* @typedef {object} PAYLOAD_TYPE
|
|
465
|
+
* @property {number} EMPTY
|
|
466
|
+
* @property {number} TEXT
|
|
467
|
+
* @property {number} BINARY
|
|
468
|
+
* @property {number} OBJECT
|
|
469
|
+
* @property {number} MJSON
|
|
470
|
+
* @property {number} MBA
|
|
471
|
+
*/
|
|
426
472
|
let PAYLOAD_TYPE = {
|
|
427
473
|
EMPTY: 0,
|
|
428
474
|
TEXT: 1,
|
|
@@ -434,6 +480,40 @@ let PAYLOAD_TYPE = {
|
|
|
434
480
|
for (let c in PAYLOAD_TYPE) { PAYLOAD_TYPE[PAYLOAD_TYPE[c]] = c; }
|
|
435
481
|
|
|
436
482
|
|
|
483
|
+
/**
|
|
484
|
+
* @typedef {object} IOMsg
|
|
485
|
+
* @property {number} SERVER_READY
|
|
486
|
+
* @property {number} CID_REQ
|
|
487
|
+
* @property {number} CID_RES
|
|
488
|
+
* @property {number} QUOTA_LEVEL
|
|
489
|
+
* @property {number} SERVER_CLEAR_AUTH
|
|
490
|
+
* @property {number} SERVER_REDIRECT
|
|
491
|
+
* @property {number} LOOP
|
|
492
|
+
* @property {number} ECHO
|
|
493
|
+
* @property {number} PING
|
|
494
|
+
* @property {number} PONG
|
|
495
|
+
* @property {number} CLOSE
|
|
496
|
+
* @property {number} SIGNAL
|
|
497
|
+
* @property {number} SIGNAL_REQ
|
|
498
|
+
* @property {number} SIGNAL_E2E
|
|
499
|
+
* @property {number} SUBSCRIBE
|
|
500
|
+
* @property {number} SUBSCRIBE_REQ
|
|
501
|
+
* @property {number} UNSUBSCRIBE
|
|
502
|
+
* @property {number} SERVER_SIGNAL
|
|
503
|
+
* @property {number} IAM
|
|
504
|
+
* @property {number} IAM_RES
|
|
505
|
+
* @property {number} SET
|
|
506
|
+
* @property {number} RESPONSE_CODE
|
|
507
|
+
* @property {number} RESPONSE_MBP
|
|
508
|
+
* @property {number} REQUEST
|
|
509
|
+
* @property {number} RESPONSE
|
|
510
|
+
* @property {number} FLOW_MODE
|
|
511
|
+
* @property {number} WAIT
|
|
512
|
+
* @property {number} RESUME
|
|
513
|
+
* @property {number} TIME_OUT
|
|
514
|
+
* @property {number} OVER_SIZE
|
|
515
|
+
* @property {number} OVER_FLOW
|
|
516
|
+
*/
|
|
437
517
|
// IO message's one-byte headers.
|
|
438
518
|
let IOMsg = {
|
|
439
519
|
|
|
@@ -513,11 +593,21 @@ let IOMsg = {
|
|
|
513
593
|
for (let c in IOMsg) { IOMsg[IOMsg[c]] = c; }
|
|
514
594
|
// console.log( IOMsg );
|
|
515
595
|
|
|
596
|
+
/**
|
|
597
|
+
* @typedef {object} API_TYPE
|
|
598
|
+
* @property {string} REQUEST_RESPONSE
|
|
599
|
+
* @property {string} ONE_WAY
|
|
600
|
+
*/
|
|
516
601
|
const API_TYPE = {
|
|
517
602
|
'REQUEST_RESPONSE': 'requet_response',
|
|
518
603
|
'ONE_WAY': 'one_way'
|
|
519
604
|
};
|
|
520
605
|
|
|
606
|
+
/**
|
|
607
|
+
* @typedef {object} STATUS
|
|
608
|
+
* @property {number} OK
|
|
609
|
+
* @property {number} ERROR
|
|
610
|
+
*/
|
|
521
611
|
// api response status code
|
|
522
612
|
const STATUS$1 = {
|
|
523
613
|
OK: 0,
|
|
@@ -691,6 +781,19 @@ const t=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1
|
|
|
691
781
|
* @license MIT
|
|
692
782
|
*/var V=(K||(K=1,function(t){const e=function(){if(j)return D;j=1,D.byteLength=function(t){var e=o(t),r=e[0],n=e[1];return 3*(r+n)/4-n},D.toByteArray=function(t){var n,i,f=o(t),s=f[0],u=f[1],h=new r(function(t,e,r){return 3*(e+r)/4-r}(0,s,u)),a=0,c=u>0?s-4:s;for(i=0;i<c;i+=4)n=e[t.charCodeAt(i)]<<18|e[t.charCodeAt(i+1)]<<12|e[t.charCodeAt(i+2)]<<6|e[t.charCodeAt(i+3)],h[a++]=n>>16&255,h[a++]=n>>8&255,h[a++]=255&n;return 2===u&&(n=e[t.charCodeAt(i)]<<2|e[t.charCodeAt(i+1)]>>4,h[a++]=255&n),1===u&&(n=e[t.charCodeAt(i)]<<10|e[t.charCodeAt(i+1)]<<4|e[t.charCodeAt(i+2)]>>2,h[a++]=n>>8&255,h[a++]=255&n),h},D.fromByteArray=function(e){for(var r,n=e.length,i=n%3,o=[],s=16383,u=0,h=n-i;u<h;u+=s)o.push(f(e,u,u+s>h?h:u+s));return 1===i?(r=e[n-1],o.push(t[r>>2]+t[r<<4&63]+"==")):2===i&&(r=(e[n-2]<<8)+e[n-1],o.push(t[r>>10]+t[r>>4&63]+t[r<<2&63]+"=")),o.join("")};for(var t=[],e=[],r="undefined"!=typeof Uint8Array?Uint8Array:Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",i=0;i<64;++i)t[i]=n[i],e[n.charCodeAt(i)]=i;function o(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");return -1===r&&(r=e),[r,r===e?0:4-r%4]}function f(e,r,n){for(var i,o,f=[],s=r;s<n;s+=3)i=(e[s]<<16&16711680)+(e[s+1]<<8&65280)+(255&e[s+2]),f.push(t[(o=i)>>18&63]+t[o>>12&63]+t[o>>6&63]+t[63&o]);return f.join("")}return e["-".charCodeAt(0)]=62,e["_".charCodeAt(0)]=63,D}(),r=G(),n="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;t.Buffer=f,t.SlowBuffer=function(t){return +t!=t&&(t=0),f.alloc(+t)},t.INSPECT_MAX_BYTES=50;const i=2147483647;function o(t){if(t>i)throw new RangeError('The value "'+t+'" is invalid for option "size"');const e=new Uint8Array(t);return Object.setPrototypeOf(e,f.prototype),e}function f(t,e,r){if("number"==typeof t){if("string"==typeof e)throw new TypeError('The "string" argument must be of type string. Received type number');return h(t)}return s(t,e,r)}function s(t,e,r){if("string"==typeof t)return function(t,e){if("string"==typeof e&&""!==e||(e="utf8"),!f.isEncoding(e))throw new TypeError("Unknown encoding: "+e);const r=0|p(t,e);let n=o(r);const i=n.write(t,e);return i!==r&&(n=n.slice(0,i)),n}(t,e);if(ArrayBuffer.isView(t))return function(t){if(Q(t,Uint8Array)){const e=new Uint8Array(t);return c(e.buffer,e.byteOffset,e.byteLength)}return a(t)}(t);if(null==t)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t);if(Q(t,ArrayBuffer)||t&&Q(t.buffer,ArrayBuffer))return c(t,e,r);if("undefined"!=typeof SharedArrayBuffer&&(Q(t,SharedArrayBuffer)||t&&Q(t.buffer,SharedArrayBuffer)))return c(t,e,r);if("number"==typeof t)throw new TypeError('The "value" argument must not be of type number. Received type number');const n=t.valueOf&&t.valueOf();if(null!=n&&n!==t)return f.from(n,e,r);const i=function(t){if(f.isBuffer(t)){const e=0|l(t.length),r=o(e);return 0===r.length||t.copy(r,0,0,e),r}return void 0!==t.length?"number"!=typeof t.length||X(t.length)?o(0):a(t):"Buffer"===t.type&&Array.isArray(t.data)?a(t.data):void 0}(t);if(i)return i;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof t[Symbol.toPrimitive])return f.from(t[Symbol.toPrimitive]("string"),e,r);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof t)}function u(t){if("number"!=typeof t)throw new TypeError('"size" argument must be of type number');if(t<0)throw new RangeError('The value "'+t+'" is invalid for option "size"')}function h(t){return u(t),o(t<0?0:0|l(t))}function a(t){const e=t.length<0?0:0|l(t.length),r=o(e);for(let n=0;n<e;n+=1)r[n]=255&t[n];return r}function c(t,e,r){if(e<0||t.byteLength<e)throw new RangeError('"offset" is outside of buffer bounds');if(t.byteLength<e+(r||0))throw new RangeError('"length" is outside of buffer bounds');let n;return n=void 0===e&&void 0===r?new Uint8Array(t):void 0===r?new Uint8Array(t,e):new Uint8Array(t,e,r),Object.setPrototypeOf(n,f.prototype),n}function l(t){if(t>=i)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i.toString(16)+" bytes");return 0|t}function p(t,e){if(f.isBuffer(t))return t.length;if(ArrayBuffer.isView(t)||Q(t,ArrayBuffer))return t.byteLength;if("string"!=typeof t)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof t);const r=t.length,n=arguments.length>2&&true===arguments[2];if(!n&&0===r)return 0;let i=false;for(;;)switch(e){case "ascii":case "latin1":case "binary":return r;case "utf8":case "utf-8":return q(t).length;case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":return 2*r;case "hex":return r>>>1;case "base64":return V(t).length;default:if(i)return n?-1:q(t).length;e=(""+e).toLowerCase(),i=true;}}function y(t,e,r){let n=false;if((void 0===e||e<0)&&(e=0),e>this.length)return "";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return "";if((r>>>=0)<=(e>>>=0))return "";for(t||(t="utf8");;)switch(t){case "hex":return T(this,e,r);case "utf8":case "utf-8":return U(this,e,r);case "ascii":return L(this,e,r);case "latin1":case "binary":return v(this,e,r);case "base64":return _(this,e,r);case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":return S(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=true;}}function g(t,e,r){const n=t[e];t[e]=t[r],t[r]=n;}function d(t,e,r,n,i){if(0===t.length)return -1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),X(r=+r)&&(r=i?0:t.length-1),r<0&&(r=t.length+r),r>=t.length){if(i)return -1;r=t.length-1;}else if(r<0){if(!i)return -1;r=0;}if("string"==typeof e&&(e=f.from(e,n)),f.isBuffer(e))return 0===e.length?-1:b(t,e,r,n,i);if("number"==typeof e)return e&=255,"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(t,e,r):Uint8Array.prototype.lastIndexOf.call(t,e,r):b(t,[e],r,n,i);throw new TypeError("val must be string, number or Buffer")}function b(t,e,r,n,i){let o,f=1,s=t.length,u=e.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(t.length<2||e.length<2)return -1;f=2,s/=2,u/=2,r/=2;}function h(t,e){return 1===f?t[e]:t.readUInt16BE(e*f)}if(i){let n=-1;for(o=r;o<s;o++)if(h(t,o)===h(e,-1===n?0:o-n)){if(-1===n&&(n=o),o-n+1===u)return n*f}else -1!==n&&(o-=o-n),n=-1;}else for(r+u>s&&(r=s-u),o=r;o>=0;o--){let r=true;for(let n=0;n<u;n++)if(h(t,o+n)!==h(e,n)){r=false;break}if(r)return o}return -1}function w(t,e,r,n){r=Number(r)||0;const i=t.length-r;n?(n=Number(n))>i&&(n=i):n=i;const o=e.length;let f;for(n>o/2&&(n=o/2),f=0;f<n;++f){const n=parseInt(e.substr(2*f,2),16);if(X(n))return f;t[r+f]=n;}return f}function B(t,e,r,n){return J(q(e,t.length-r),t,r,n)}function m(t,e,r,n){return J(function(t){const e=[];for(let r=0;r<t.length;++r)e.push(255&t.charCodeAt(r));return e}(e),t,r,n)}function E(t,e,r,n){return J(V(e),t,r,n)}function A(t,e,r,n){return J(function(t,e){let r,n,i;const o=[];for(let f=0;f<t.length&&!((e-=2)<0);++f)r=t.charCodeAt(f),n=r>>8,i=r%256,o.push(i),o.push(n);return o}(e,t.length-r),t,r,n)}function _(t,r,n){return 0===r&&n===t.length?e.fromByteArray(t):e.fromByteArray(t.slice(r,n))}function U(t,e,r){r=Math.min(t.length,r);const n=[];let i=e;for(;i<r;){const e=t[i];let o=null,f=e>239?4:e>223?3:e>191?2:1;if(i+f<=r){let r,n,s,u;switch(f){case 1:e<128&&(o=e);break;case 2:r=t[i+1],128==(192&r)&&(u=(31&e)<<6|63&r,u>127&&(o=u));break;case 3:r=t[i+1],n=t[i+2],128==(192&r)&&128==(192&n)&&(u=(15&e)<<12|(63&r)<<6|63&n,u>2047&&(u<55296||u>57343)&&(o=u));break;case 4:r=t[i+1],n=t[i+2],s=t[i+3],128==(192&r)&&128==(192&n)&&128==(192&s)&&(u=(15&e)<<18|(63&r)<<12|(63&n)<<6|63&s,u>65535&&u<1114112&&(o=u));}}null===o?(o=65533,f=1):o>65535&&(o-=65536,n.push(o>>>10&1023|55296),o=56320|1023&o),n.push(o),i+=f;}return function(t){const e=t.length;if(e<=I)return String.fromCharCode.apply(String,t);let r="",n=0;for(;n<e;)r+=String.fromCharCode.apply(String,t.slice(n,n+=I));return r}(n)}t.kMaxLength=i,f.TYPED_ARRAY_SUPPORT=function(){try{const t=new Uint8Array(1),e={foo:function(){return 42}};return Object.setPrototypeOf(e,Uint8Array.prototype),Object.setPrototypeOf(t,e),42===t.foo()}catch(t){return false}}(),f.TYPED_ARRAY_SUPPORT||"undefined"==typeof console||"function"!=typeof console.error||console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."),Object.defineProperty(f.prototype,"parent",{enumerable:true,get:function(){if(f.isBuffer(this))return this.buffer}}),Object.defineProperty(f.prototype,"offset",{enumerable:true,get:function(){if(f.isBuffer(this))return this.byteOffset}}),f.poolSize=8192,f.from=function(t,e,r){return s(t,e,r)},Object.setPrototypeOf(f.prototype,Uint8Array.prototype),Object.setPrototypeOf(f,Uint8Array),f.alloc=function(t,e,r){return function(t,e,r){return u(t),t<=0?o(t):void 0!==e?"string"==typeof r?o(t).fill(e,r):o(t).fill(e):o(t)}(t,e,r)},f.allocUnsafe=function(t){return h(t)},f.allocUnsafeSlow=function(t){return h(t)},f.isBuffer=function(t){return null!=t&&true===t._isBuffer&&t!==f.prototype},f.compare=function(t,e){if(Q(t,Uint8Array)&&(t=f.from(t,t.offset,t.byteLength)),Q(e,Uint8Array)&&(e=f.from(e,e.offset,e.byteLength)),!f.isBuffer(t)||!f.isBuffer(e))throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array');if(t===e)return 0;let r=t.length,n=e.length;for(let i=0,o=Math.min(r,n);i<o;++i)if(t[i]!==e[i]){r=t[i],n=e[i];break}return r<n?-1:n<r?1:0},f.isEncoding=function(t){switch(String(t).toLowerCase()){case "hex":case "utf8":case "utf-8":case "ascii":case "latin1":case "binary":case "base64":case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":return true;default:return false}},f.concat=function(t,e){if(!Array.isArray(t))throw new TypeError('"list" argument must be an Array of Buffers');if(0===t.length)return f.alloc(0);let r;if(void 0===e)for(e=0,r=0;r<t.length;++r)e+=t[r].length;const n=f.allocUnsafe(e);let i=0;for(r=0;r<t.length;++r){let e=t[r];if(Q(e,Uint8Array))i+e.length>n.length?(f.isBuffer(e)||(e=f.from(e)),e.copy(n,i)):Uint8Array.prototype.set.call(n,e,i);else {if(!f.isBuffer(e))throw new TypeError('"list" argument must be an Array of Buffers');e.copy(n,i);}i+=e.length;}return n},f.byteLength=p,f.prototype._isBuffer=true,f.prototype.swap16=function(){const t=this.length;if(t%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let e=0;e<t;e+=2)g(this,e,e+1);return this},f.prototype.swap32=function(){const t=this.length;if(t%4!=0)throw new RangeError("Buffer size must be a multiple of 32-bits");for(let e=0;e<t;e+=4)g(this,e,e+3),g(this,e+1,e+2);return this},f.prototype.swap64=function(){const t=this.length;if(t%8!=0)throw new RangeError("Buffer size must be a multiple of 64-bits");for(let e=0;e<t;e+=8)g(this,e,e+7),g(this,e+1,e+6),g(this,e+2,e+5),g(this,e+3,e+4);return this},f.prototype.toString=function(){const t=this.length;return 0===t?"":0===arguments.length?U(this,0,t):y.apply(this,arguments)},f.prototype.toLocaleString=f.prototype.toString,f.prototype.equals=function(t){if(!f.isBuffer(t))throw new TypeError("Argument must be a Buffer");return this===t||0===f.compare(this,t)},f.prototype.inspect=function(){let e="";const r=t.INSPECT_MAX_BYTES;return e=this.toString("hex",0,r).replace(/(.{2})/g,"$1 ").trim(),this.length>r&&(e+=" ... "),"<Buffer "+e+">"},n&&(f.prototype[n]=f.prototype.inspect),f.prototype.compare=function(t,e,r,n,i){if(Q(t,Uint8Array)&&(t=f.from(t,t.offset,t.byteLength)),!f.isBuffer(t))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof t);if(void 0===e&&(e=0),void 0===r&&(r=t?t.length:0),void 0===n&&(n=0),void 0===i&&(i=this.length),e<0||r>t.length||n<0||i>this.length)throw new RangeError("out of range index");if(n>=i&&e>=r)return 0;if(n>=i)return -1;if(e>=r)return 1;if(this===t)return 0;let o=(i>>>=0)-(n>>>=0),s=(r>>>=0)-(e>>>=0);const u=Math.min(o,s),h=this.slice(n,i),a=t.slice(e,r);for(let t=0;t<u;++t)if(h[t]!==a[t]){o=h[t],s=a[t];break}return o<s?-1:s<o?1:0},f.prototype.includes=function(t,e,r){return -1!==this.indexOf(t,e,r)},f.prototype.indexOf=function(t,e,r){return d(this,t,e,r,true)},f.prototype.lastIndexOf=function(t,e,r){return d(this,t,e,r,false)},f.prototype.write=function(t,e,r,n){if(void 0===e)n="utf8",r=this.length,e=0;else if(void 0===r&&"string"==typeof e)n=e,r=this.length,e=0;else {if(!isFinite(e))throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");e>>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0);}const i=this.length-e;if((void 0===r||r>i)&&(r=i),t.length>0&&(r<0||e<0)||e>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");let o=false;for(;;)switch(n){case "hex":return w(this,t,e,r);case "utf8":case "utf-8":return B(this,t,e,r);case "ascii":case "latin1":case "binary":return m(this,t,e,r);case "base64":return E(this,t,e,r);case "ucs2":case "ucs-2":case "utf16le":case "utf-16le":return A(this,t,e,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=true;}},f.prototype.toJSON=function(){return {type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const I=4096;function L(t,e,r){let n="";r=Math.min(t.length,r);for(let i=e;i<r;++i)n+=String.fromCharCode(127&t[i]);return n}function v(t,e,r){let n="";r=Math.min(t.length,r);for(let i=e;i<r;++i)n+=String.fromCharCode(t[i]);return n}function T(t,e,r){const n=t.length;(!e||e<0)&&(e=0),(!r||r<0||r>n)&&(r=n);let i="";for(let n=e;n<r;++n)i+=W[t[n]];return i}function S(t,e,r){const n=t.slice(e,r);let i="";for(let t=0;t<n.length-1;t+=2)i+=String.fromCharCode(n[t]+256*n[t+1]);return i}function R(t,e,r){if(t%1!=0||t<0)throw new RangeError("offset is not uint");if(t+e>r)throw new RangeError("Trying to access beyond buffer length")}function O(t,e,r,n,i,o){if(!f.isBuffer(t))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>i||e<o)throw new RangeError('"value" argument is out of bounds');if(r+n>t.length)throw new RangeError("Index out of range")}function M(t,e,r,n,i){F(e,n,i,t,r,7);let o=Number(e&BigInt(4294967295));t[r++]=o,o>>=8,t[r++]=o,o>>=8,t[r++]=o,o>>=8,t[r++]=o;let f=Number(e>>BigInt(32)&BigInt(4294967295));return t[r++]=f,f>>=8,t[r++]=f,f>>=8,t[r++]=f,f>>=8,t[r++]=f,r}function C(t,e,r,n,i){F(e,n,i,t,r,7);let o=Number(e&BigInt(4294967295));t[r+7]=o,o>>=8,t[r+6]=o,o>>=8,t[r+5]=o,o>>=8,t[r+4]=o;let f=Number(e>>BigInt(32)&BigInt(4294967295));return t[r+3]=f,f>>=8,t[r+2]=f,f>>=8,t[r+1]=f,f>>=8,t[r]=f,r+8}function N(t,e,r,n,i,o){if(r+n>t.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function x(t,e,n,i,o){return e=+e,n>>>=0,o||N(t,0,n,4),r.write(t,e,n,i,23,4),n+4}function k(t,e,n,i,o){return e=+e,n>>>=0,o||N(t,0,n,8),r.write(t,e,n,i,52,8),n+8}f.prototype.slice=function(t,e){const r=this.length;(t=~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),(e=void 0===e?r:~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),e<t&&(e=t);const n=this.subarray(t,e);return Object.setPrototypeOf(n,f.prototype),n},f.prototype.readUintLE=f.prototype.readUIntLE=function(t,e,r){t>>>=0,e>>>=0,r||R(t,e,this.length);let n=this[t],i=1,o=0;for(;++o<e&&(i*=256);)n+=this[t+o]*i;return n},f.prototype.readUintBE=f.prototype.readUIntBE=function(t,e,r){t>>>=0,e>>>=0,r||R(t,e,this.length);let n=this[t+--e],i=1;for(;e>0&&(i*=256);)n+=this[t+--e]*i;return n},f.prototype.readUint8=f.prototype.readUInt8=function(t,e){return t>>>=0,e||R(t,1,this.length),this[t]},f.prototype.readUint16LE=f.prototype.readUInt16LE=function(t,e){return t>>>=0,e||R(t,2,this.length),this[t]|this[t+1]<<8},f.prototype.readUint16BE=f.prototype.readUInt16BE=function(t,e){return t>>>=0,e||R(t,2,this.length),this[t]<<8|this[t+1]},f.prototype.readUint32LE=f.prototype.readUInt32LE=function(t,e){return t>>>=0,e||R(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},f.prototype.readUint32BE=f.prototype.readUInt32BE=function(t,e){return t>>>=0,e||R(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},f.prototype.readBigUInt64LE=Z((function(t){z(t>>>=0,"offset");const e=this[t],r=this[t+7];void 0!==e&&void 0!==r||Y(t,this.length-8);const n=e+256*this[++t]+65536*this[++t]+this[++t]*2**24,i=this[++t]+256*this[++t]+65536*this[++t]+r*2**24;return BigInt(n)+(BigInt(i)<<BigInt(32))})),f.prototype.readBigUInt64BE=Z((function(t){z(t>>>=0,"offset");const e=this[t],r=this[t+7];void 0!==e&&void 0!==r||Y(t,this.length-8);const n=e*2**24+65536*this[++t]+256*this[++t]+this[++t],i=this[++t]*2**24+65536*this[++t]+256*this[++t]+r;return (BigInt(n)<<BigInt(32))+BigInt(i)})),f.prototype.readIntLE=function(t,e,r){t>>>=0,e>>>=0,r||R(t,e,this.length);let n=this[t],i=1,o=0;for(;++o<e&&(i*=256);)n+=this[t+o]*i;return i*=128,n>=i&&(n-=Math.pow(2,8*e)),n},f.prototype.readIntBE=function(t,e,r){t>>>=0,e>>>=0,r||R(t,e,this.length);let n=e,i=1,o=this[t+--n];for(;n>0&&(i*=256);)o+=this[t+--n]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*e)),o},f.prototype.readInt8=function(t,e){return t>>>=0,e||R(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},f.prototype.readInt16LE=function(t,e){t>>>=0,e||R(t,2,this.length);const r=this[t]|this[t+1]<<8;return 32768&r?4294901760|r:r},f.prototype.readInt16BE=function(t,e){t>>>=0,e||R(t,2,this.length);const r=this[t+1]|this[t]<<8;return 32768&r?4294901760|r:r},f.prototype.readInt32LE=function(t,e){return t>>>=0,e||R(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},f.prototype.readInt32BE=function(t,e){return t>>>=0,e||R(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},f.prototype.readBigInt64LE=Z((function(t){z(t>>>=0,"offset");const e=this[t],r=this[t+7];void 0!==e&&void 0!==r||Y(t,this.length-8);const n=this[t+4]+256*this[t+5]+65536*this[t+6]+(r<<24);return (BigInt(n)<<BigInt(32))+BigInt(e+256*this[++t]+65536*this[++t]+this[++t]*2**24)})),f.prototype.readBigInt64BE=Z((function(t){z(t>>>=0,"offset");const e=this[t],r=this[t+7];void 0!==e&&void 0!==r||Y(t,this.length-8);const n=(e<<24)+65536*this[++t]+256*this[++t]+this[++t];return (BigInt(n)<<BigInt(32))+BigInt(this[++t]*2**24+65536*this[++t]+256*this[++t]+r)})),f.prototype.readFloatLE=function(t,e){return t>>>=0,e||R(t,4,this.length),r.read(this,t,true,23,4)},f.prototype.readFloatBE=function(t,e){return t>>>=0,e||R(t,4,this.length),r.read(this,t,false,23,4)},f.prototype.readDoubleLE=function(t,e){return t>>>=0,e||R(t,8,this.length),r.read(this,t,true,52,8)},f.prototype.readDoubleBE=function(t,e){return t>>>=0,e||R(t,8,this.length),r.read(this,t,false,52,8)},f.prototype.writeUintLE=f.prototype.writeUIntLE=function(t,e,r,n){t=+t,e>>>=0,r>>>=0,n||O(this,t,e,r,Math.pow(2,8*r)-1,0);let i=1,o=0;for(this[e]=255&t;++o<r&&(i*=256);)this[e+o]=t/i&255;return e+r},f.prototype.writeUintBE=f.prototype.writeUIntBE=function(t,e,r,n){t=+t,e>>>=0,r>>>=0,n||O(this,t,e,r,Math.pow(2,8*r)-1,0);let i=r-1,o=1;for(this[e+i]=255&t;--i>=0&&(o*=256);)this[e+i]=t/o&255;return e+r},f.prototype.writeUint8=f.prototype.writeUInt8=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,1,255,0),this[e]=255&t,e+1},f.prototype.writeUint16LE=f.prototype.writeUInt16LE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,2,65535,0),this[e]=255&t,this[e+1]=t>>>8,e+2},f.prototype.writeUint16BE=f.prototype.writeUInt16BE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,2,65535,0),this[e]=t>>>8,this[e+1]=255&t,e+2},f.prototype.writeUint32LE=f.prototype.writeUInt32LE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,4,4294967295,0),this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t,e+4},f.prototype.writeUint32BE=f.prototype.writeUInt32BE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,4,4294967295,0),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},f.prototype.writeBigUInt64LE=Z((function(t,e=0){return M(this,t,e,BigInt(0),BigInt("0xffffffffffffffff"))})),f.prototype.writeBigUInt64BE=Z((function(t,e=0){return C(this,t,e,BigInt(0),BigInt("0xffffffffffffffff"))})),f.prototype.writeIntLE=function(t,e,r,n){if(t=+t,e>>>=0,!n){const n=Math.pow(2,8*r-1);O(this,t,e,r,n-1,-n);}let i=0,o=1,f=0;for(this[e]=255&t;++i<r&&(o*=256);)t<0&&0===f&&0!==this[e+i-1]&&(f=1),this[e+i]=(t/o|0)-f&255;return e+r},f.prototype.writeIntBE=function(t,e,r,n){if(t=+t,e>>>=0,!n){const n=Math.pow(2,8*r-1);O(this,t,e,r,n-1,-n);}let i=r-1,o=1,f=0;for(this[e+i]=255&t;--i>=0&&(o*=256);)t<0&&0===f&&0!==this[e+i+1]&&(f=1),this[e+i]=(t/o|0)-f&255;return e+r},f.prototype.writeInt8=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,1,127,-128),t<0&&(t=255+t+1),this[e]=255&t,e+1},f.prototype.writeInt16LE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,2,32767,-32768),this[e]=255&t,this[e+1]=t>>>8,e+2},f.prototype.writeInt16BE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,2,32767,-32768),this[e]=t>>>8,this[e+1]=255&t,e+2},f.prototype.writeInt32LE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,4,2147483647,-2147483648),this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24,e+4},f.prototype.writeInt32BE=function(t,e,r){return t=+t,e>>>=0,r||O(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t,e+4},f.prototype.writeBigInt64LE=Z((function(t,e=0){return M(this,t,e,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),f.prototype.writeBigInt64BE=Z((function(t,e=0){return C(this,t,e,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),f.prototype.writeFloatLE=function(t,e,r){return x(this,t,e,true,r)},f.prototype.writeFloatBE=function(t,e,r){return x(this,t,e,false,r)},f.prototype.writeDoubleLE=function(t,e,r){return k(this,t,e,true,r)},f.prototype.writeDoubleBE=function(t,e,r){return k(this,t,e,false,r)},f.prototype.copy=function(t,e,r,n){if(!f.isBuffer(t))throw new TypeError("argument should be a Buffer");if(r||(r=0),n||0===n||(n=this.length),e>=t.length&&(e=t.length),e||(e=0),n>0&&n<r&&(n=r),n===r)return 0;if(0===t.length||0===this.length)return 0;if(e<0)throw new RangeError("targetStart out of bounds");if(r<0||r>=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),t.length-e<n-r&&(n=t.length-e+r);const i=n-r;return this===t&&"function"==typeof Uint8Array.prototype.copyWithin?this.copyWithin(e,r,n):Uint8Array.prototype.set.call(t,this.subarray(r,n),e),i},f.prototype.fill=function(t,e,r,n){if("string"==typeof t){if("string"==typeof e?(n=e,e=0,r=this.length):"string"==typeof r&&(n=r,r=this.length),void 0!==n&&"string"!=typeof n)throw new TypeError("encoding must be a string");if("string"==typeof n&&!f.isEncoding(n))throw new TypeError("Unknown encoding: "+n);if(1===t.length){const e=t.charCodeAt(0);("utf8"===n&&e<128||"latin1"===n)&&(t=e);}}else "number"==typeof t?t&=255:"boolean"==typeof t&&(t=Number(t));if(e<0||this.length<e||this.length<r)throw new RangeError("Out of range index");if(r<=e)return this;let i;if(e>>>=0,r=void 0===r?this.length:r>>>0,t||(t=0),"number"==typeof t)for(i=e;i<r;++i)this[i]=t;else {const o=f.isBuffer(t)?t:f.from(t,n),s=o.length;if(0===s)throw new TypeError('The value "'+t+'" is invalid for argument "value"');for(i=0;i<r-e;++i)this[i+e]=o[i%s];}return this};const P={};function $(t,e,r){P[t]=class extends r{constructor(){super(),Object.defineProperty(this,"message",{value:e.apply(this,arguments),writable:true,configurable:true}),this.name=`${this.name} [${t}]`,this.stack,delete this.name;}get code(){return t}set code(t){Object.defineProperty(this,"code",{configurable:true,enumerable:true,value:t,writable:true});}toString(){return `${this.name} [${t}]: ${this.message}`}};}function H(t){let e="",r=t.length;const n="-"===t[0]?1:0;for(;r>=n+4;r-=3)e=`_${t.slice(r-3,r)}${e}`;return `${t.slice(0,r)}${e}`}function F(t,e,r,n,i,o){if(t>r||t<e){const r="bigint"==typeof e?"n":"";let n;throw n=0===e||e===BigInt(0)?`>= 0${r} and < 2${r} ** ${8*(o+1)}${r}`:`>= -(2${r} ** ${8*(o+1)-1}${r}) and < 2 ** ${8*(o+1)-1}${r}`,new P.ERR_OUT_OF_RANGE("value",n,t)}!function(t,e,r){z(e,"offset"),void 0!==t[e]&&void 0!==t[e+r]||Y(e,t.length-(r+1));}(n,i,o);}function z(t,e){if("number"!=typeof t)throw new P.ERR_INVALID_ARG_TYPE(e,"number",t)}function Y(t,e,r){if(Math.floor(t)!==t)throw z(t,r),new P.ERR_OUT_OF_RANGE("offset","an integer",t);if(e<0)throw new P.ERR_BUFFER_OUT_OF_BOUNDS;throw new P.ERR_OUT_OF_RANGE("offset",`>= 0 and <= ${e}`,t)}$("ERR_BUFFER_OUT_OF_BOUNDS",(function(t){return t?`${t} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"}),RangeError),$("ERR_INVALID_ARG_TYPE",(function(t,e){return `The "${t}" argument must be of type number. Received type ${typeof e}`}),TypeError),$("ERR_OUT_OF_RANGE",(function(t,e,r){let n=`The value of "${t}" is out of range.`,i=r;return Number.isInteger(r)&&Math.abs(r)>2**32?i=H(String(r)):"bigint"==typeof r&&(i=String(r),(r>BigInt(2)**BigInt(32)||r<-(BigInt(2)**BigInt(32)))&&(i=H(i)),i+="n"),n+=` It must be ${e}. Received ${i}`,n}),RangeError);const K=/[^+/0-9A-Za-z-_]/g;function q(t,e){let r;e=e||1/0;const n=t.length;let i=null;const o=[];for(let f=0;f<n;++f){if(r=t.charCodeAt(f),r>55295&&r<57344){if(!i){if(r>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(f+1===n){(e-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(r<56320){(e-=3)>-1&&o.push(239,191,189),i=r;continue}r=65536+(i-55296<<10|r-56320);}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,r<128){if((e-=1)<0)break;o.push(r);}else if(r<2048){if((e-=2)<0)break;o.push(r>>6|192,63&r|128);}else if(r<65536){if((e-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128);}else {if(!(r<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128);}}return o}function V(t){return e.toByteArray(function(t){if((t=(t=t.split("=")[0]).trim().replace(K,"")).length<2)return "";for(;t.length%4!=0;)t+="=";return t}(t))}function J(t,e,r,n){let i;for(i=0;i<n&&!(i+r>=e.length||i>=t.length);++i)e[i+r]=t[i];return i}function Q(t,e){return t instanceof e||null!=t&&null!=t.constructor&&null!=t.constructor.name&&t.constructor.name===e.name}function X(t){return t!=t}const W=function(){const t="0123456789abcdef",e=new Array(256);for(let r=0;r<16;++r){const n=16*r;for(let i=0;i<16;++i)e[n+i]=t[r]+t[i];}return e}();function Z(t){return "undefined"==typeof BigInt?tt:t}function tt(){throw new Error("BigInt not supported")}}(z)),z);let J={AUTH_REQ:176,AUTH_NONCE:177,AUTH_HMAC:178,AUTH_ACK:179,AUTH_FAIL:180,AUTH_EXT:181,ENC_PACK:182,ENC_E2E:183,ENC_488:184};for(let t in J)J[J[t]]=t;const Q={AUTH_REQ:H.meta(H.MB("header","8",0),H.MB("reserved","8",0)),AUTH_NONCE:H.meta(H.MB("header","8",0),H.MB("unixTime","32L",0),H.MB("milTime","32L",0),H.MB("nonce",V.Buffer.alloc(4))),AUTH_HMAC:H.meta(H.MB("header","8",0),H.MB("id8",V.Buffer.alloc(8)),H.MB("nonce",V.Buffer.alloc(4)),H.MB("hmac32",V.Buffer.alloc(32))),AUTH_ACK:H.meta(H.MB("header","8",0),H.MB("hmac32",V.Buffer.alloc(32))),ENC_PACK:H.meta(H.MB("type","8",0),H.MB("len","32L",0),H.MB("salt12",V.Buffer.alloc(12)),H.MB("hmac",8,0)),ENC_488:H.meta(H.MB("type","8",0),H.MB("len","32L",0),H.MB("otpSrc8",V.Buffer.alloc(8)),H.MB("hmac8",V.Buffer.alloc(8)))};function X(t){let e=t[t.length-1];return e[2]+e[3]}const W={AUTH_REQ:X(Q.AUTH_REQ),AUTH_NONCE:X(Q.AUTH_NONCE),AUTH_HMAC:X(Q.AUTH_HMAC),AUTH_ACK:X(Q.AUTH_ACK),ENC_PACK:X(Q.ENC_PACK),ENC_488:X(Q.ENC_488)};function Z(t){return globalThis.crypto.getRandomValues(V.Buffer.alloc(t))}class tt{constructor(){this._id8=V.Buffer.alloc(8),this._otpSrc44=V.Buffer.alloc(44),this._otp36=V.Buffer.alloc(36),this._hmac=V.Buffer.alloc(32),this.auth_salt12=V.Buffer.alloc(12),this.localNonce=V.Buffer.alloc(4),this.remoteNonce=V.Buffer.alloc(4),this.isAuthorized=false;}clearAuth(){this._id8.fill(0),this._otpSrc44.fill(0),this._otp36.fill(0),this._hmac.fill(0),this.auth_salt12.fill(0),this.localNonce.fill(0),this.remoteNonce.fill(0),this.isAuthorized=false;}set_hash_id8(t){H.B8(F.hash(t)).copy(this._id8,0,0,8);}set_id8(t){let e=H.B8(t);this._id8.fill(0),e.copy(this._id8,0,0,8);}set_key(t){H.B8(F.hash(t)).copy(this._otpSrc44,0,0,32);}set_id_key(t){let e=t.indexOf(".");if(-1==e)return;let r=t.substring(0,e),n=t.substring(e+1);this.set_id8(r),this.set_key(n);}copy_id8(t){t.copy(this._id8,0,0,8);}copy_key(t){t.copy(this._otpSrc44,0,0,32);}sha256_n(t,e){let r=F.hash(t);for(let t=0;t<e;t++)r=F.hash(r);return r}set_clock_rand(){let t=Date.now(),e=parseInt(t/1e3);t%=4294967295;V.Buffer.concat([H.NB("32L",e),H.NB("32L",t),Z(4)]).copy(this._otpSrc44,32);}set_clock_nonce(t){let e=Date.now(),r=parseInt(e/1e3);e%=4294967295;V.Buffer.concat([H.NB("32L",r),H.NB("32L",e),t]).copy(this._otpSrc44,32);}set_salt12(t){t.copy(this._otpSrc44,32);}resetOTP(){H.B8(F.hash(this._otpSrc44)).copy(this._otp36,0,0,32);}getIndexOTP(t){return this._otp36.writeUInt32LE(t,32),F.hash(this._otp36)}generateHMAC(t){let e=V.Buffer.concat([this._otpSrc44,t]);this._hmac=H.B8(F.hash(e));}getHMAC8(t){let e=V.Buffer.concat([this._otpSrc44,t]);return this._hmac=H.B8(F.hash(e)),this._hmac.subarray(0,8)}xotp(t,e=0,r=false){let n=(t=H.B8(t,r)).byteLength,i=e,o=0,f=0;for(;n>0;){f=n<32?n:32;let e=this.getIndexOTP(++i);for(let r=0;r<f;r++)t[o++]^=e[r];n-=32;}return t}auth_req(){return H.pack(H.MB("#type","8",J.AUTH_REQ),H.MB("#reserved","8",0))}auth_nonce(){let t=Date.now(),e=Math.floor(t/1e3),r=t%1e3;return this.localNonce=Z(4),this.auth_salt12=V.Buffer.concat([H.NB("32L",e),H.NB("32L",r),this.localNonce]),V.Buffer.concat([H.NB("8",J.AUTH_NONCE),this.auth_salt12])}auth_hmac(t){let e=H.unpack(t,Q.AUTH_NONCE);if(e){let t=V.Buffer.concat([H.NB("32L",e.unixTime),H.NB("32L",e.milTime),e.nonce]);return this.set_salt12(t),this.localNonce=Z(4),this.generateHMAC(this.localNonce),this.remoteNonce=e.nonce,H.pack(H.MB("#header","8",J.AUTH_HMAC),H.MB("#id8",this._id8),H.MB("#nonce",this.localNonce),H.MB("#hmac32",this._hmac))}return false}check_auth_hmac(t){let e;if(t instanceof Uint8Array){if(e=H.unpack(t,Q.AUTH_HMAC),!e)return}else e=t;this.set_salt12(this.auth_salt12),this.generateHMAC(e.nonce);let r=this._hmac;if(H.equal(e.hmac32,r)){this.remoteNonce=e.nonce;let t=V.Buffer.concat([this.localNonce,this.remoteNonce,this.localNonce]);this.set_salt12(t),this.generateHMAC(e.nonce);let r=this._hmac,n=H.rawPack(H.MB("header","8",J.AUTH_ACK),H.MB("hmac32",r));return this.isAuthorized=true,n}return false}check_auth_ack_hmac(t){let e=H.unpack(t,Q.AUTH_ACK);if(e){let t=V.Buffer.concat([this.remoteNonce,this.localNonce,this.remoteNonce]);this.set_salt12(t),this.generateHMAC(this.localNonce);let r=this._hmac;if(H.equal(r,e.hmac32))return this.isAuthorized=true,true}}encrypt_488(t){if(!this.isAuthorized)return;t=H.B8(t),this.set_clock_nonce(this.remoteNonce),this.resetOTP();let e=this.getHMAC8(t),r=this.xotp(t);return H.pack(H.MB("#type","8",J.ENC_488),H.MB("#len","32L",t.byteLength),H.MB("#otpSrc8",this._otpSrc44.subarray(32,40)),H.MB("#hmac8",e),H.MB("#xdata",r))}decrypt_488(t){t=H.B8(t);let e=H.unpack(t,Q.ENC_488);if(e){let t=V.Buffer.concat([e.otpSrc8,this.localNonce]);this.set_salt12(t),this.resetOTP();let r=e.$OTHERS.subarray(0,e.len),n=this.xotp(r),i=this.getHMAC8(n);if(H.equal(i,e.hmac8))return n}}encryptPack(t){t=H.B8(t),this.set_clock_rand(),this.resetOTP();let e=this.getHMAC8(t),r=this.xotp(t);return H.pack(H.MB("#type","8",J.ENC_PACK),H.MB("#len","32L",t.byteLength),H.MB("#salt12",this._otpSrc44.subarray(32)),H.MB("#hmac8",e),H.MB("#xdata",r))}decryptPack(t){if(t[0]!==J.ENC_PACK)return;if(t.readUint32LE(1)==t.byteLength-W.ENC_PACK)try{let e=H.unpack(t,Q.ENC_PACK);if(!e)return;this.set_salt12(e.salt12),this.resetOTP();let r=e.$OTHERS,n=this.xotp(r),i=this.getHMAC8(n);if(H.equal(e.hmac,i))return e.data=n,e}catch(t){}}encrypt_e2e(t,e){let r=V.Buffer.alloc(32);r.set(this._otpSrc44.subarray(0,32)),this.set_key(e);let n=this.encryptPack(t);return this._otpSrc44.set(r),n}decrypt_e2e(t,e){let r=V.Buffer.alloc(32);r.set(this._otpSrc44.subarray(0,32)),this.set_key(e);let n=this.decryptPack(t);return this._otpSrc44.set(r),n}}tt.RAND=Z,tt.BohoMsg=J,tt.Meta=Q,tt.MetaSize=W,tt.sha256=F,tt.MBP=H,tt.Buffer=V.Buffer;
|
|
693
783
|
|
|
784
|
+
/**
|
|
785
|
+
* @typedef {import('meta-buffer-pack').MBP} MBP
|
|
786
|
+
* @typedef {import('../common/constants.js').IOMsg} IOMsg
|
|
787
|
+
* @typedef {import('../common/constants.js').PAYLOAD_TYPE} PAYLOAD_TYPE
|
|
788
|
+
* @typedef {import('../common/constants.js').SIZE_LIMIT} SIZE_LIMIT
|
|
789
|
+
* @typedef {import('../common/constants.js').ENC_MODE} ENC_MODE
|
|
790
|
+
* @typedef {import('../common/constants.js').STATES} STATES
|
|
791
|
+
* @typedef {import('../common/quotaTable.js').quotaTable} quotaTable
|
|
792
|
+
|
|
793
|
+
* @typedef {import('boho').Boho} Boho
|
|
794
|
+
* @typedef {import('boho').Buffer} Buffer
|
|
795
|
+
*/
|
|
796
|
+
|
|
694
797
|
const Buffer$1 = M$1.Buffer;
|
|
695
798
|
const encoder$1 = new TextEncoder();
|
|
696
799
|
const decoder$4 = new TextDecoder();
|
|
@@ -704,76 +807,292 @@ function byteToUrl(buffer) {
|
|
|
704
807
|
return address + ':' + port.toString()
|
|
705
808
|
}
|
|
706
809
|
|
|
810
|
+
/**
|
|
811
|
+
* Core class for handling WebSocket communication.
|
|
812
|
+
* @augments {EventEmitter}
|
|
813
|
+
*/
|
|
707
814
|
class IOCore extends EventEmitter {
|
|
815
|
+
/**
|
|
816
|
+
* @param {string} url - The WebSocket URL to connect to.
|
|
817
|
+
*/
|
|
708
818
|
constructor(url) {
|
|
709
819
|
super();
|
|
820
|
+
/**
|
|
821
|
+
* Client ID received from the server.
|
|
822
|
+
* @type {string}
|
|
823
|
+
*/
|
|
710
824
|
this.cid = ""; // get from the server CID_RES
|
|
825
|
+
/**
|
|
826
|
+
* IP address received from the server.
|
|
827
|
+
* @type {string}
|
|
828
|
+
*/
|
|
711
829
|
this.ip = ""; // get from the server IAM_RES message.
|
|
830
|
+
/**
|
|
831
|
+
* The WebSocket instance.
|
|
832
|
+
* @type {WebSocket | null}
|
|
833
|
+
*/
|
|
712
834
|
this.socket = null;
|
|
835
|
+
/**
|
|
836
|
+
* The default server URL.
|
|
837
|
+
* @type {string}
|
|
838
|
+
*/
|
|
713
839
|
this.url = url; // init default server url
|
|
840
|
+
/**
|
|
841
|
+
* Current connection state (number).
|
|
842
|
+
* @type {number}
|
|
843
|
+
*/
|
|
714
844
|
this.state = STATES.CLOSED; // Number type
|
|
845
|
+
/**
|
|
846
|
+
* Current connection state (string).
|
|
847
|
+
* @type {string}
|
|
848
|
+
*/
|
|
715
849
|
this.stateName = this.getStateName(); // String type
|
|
716
850
|
|
|
851
|
+
/**
|
|
852
|
+
* Transmitted message counter.
|
|
853
|
+
* @type {number}
|
|
854
|
+
*/
|
|
717
855
|
this.txCounter = 0;
|
|
856
|
+
/**
|
|
857
|
+
* Received message counter.
|
|
858
|
+
* @type {number}
|
|
859
|
+
*/
|
|
718
860
|
this.rxCounter = 0;
|
|
861
|
+
/**
|
|
862
|
+
* Transmitted bytes counter.
|
|
863
|
+
* @type {number}
|
|
864
|
+
*/
|
|
719
865
|
this.txBytes = 0;
|
|
866
|
+
/**
|
|
867
|
+
* Received bytes counter.
|
|
868
|
+
* @type {number}
|
|
869
|
+
*/
|
|
720
870
|
this.rxBytes = 0;
|
|
721
871
|
|
|
872
|
+
/**
|
|
873
|
+
* Last transmit/receive time.
|
|
874
|
+
* @type {number}
|
|
875
|
+
*/
|
|
722
876
|
this.lastTxRxTime = Date.now();
|
|
877
|
+
/**
|
|
878
|
+
* Period for connection checker.
|
|
879
|
+
* @type {number}
|
|
880
|
+
*/
|
|
723
881
|
this.connectionCheckerPeriod = SIZE_LIMIT.CONNECTION_CHECKER_PERIOD;
|
|
882
|
+
/**
|
|
883
|
+
* Interval ID for connection checker.
|
|
884
|
+
* @type {NodeJS.Timeout | null}
|
|
885
|
+
*/
|
|
724
886
|
this.connectionCheckerIntervalID = null;
|
|
725
887
|
|
|
888
|
+
/**
|
|
889
|
+
* Boho instance for encryption/decryption.
|
|
890
|
+
* @type {Boho}
|
|
891
|
+
*/
|
|
726
892
|
this.boho = new tt();
|
|
893
|
+
/**
|
|
894
|
+
* Indicates if the connection is TLS (wss).
|
|
895
|
+
* @type {boolean}
|
|
896
|
+
*/
|
|
727
897
|
this.TLS = false; // true if protocol is wss(TLS)
|
|
898
|
+
/**
|
|
899
|
+
* Encryption mode.
|
|
900
|
+
* @type {number}
|
|
901
|
+
*/
|
|
728
902
|
this.encMode = ENC_MODE.AUTO;
|
|
903
|
+
/**
|
|
904
|
+
* Indicates if authentication is used.
|
|
905
|
+
* @type {boolean}
|
|
906
|
+
*/
|
|
729
907
|
this.useAuth = false;
|
|
730
908
|
|
|
909
|
+
/**
|
|
910
|
+
* Nickname.
|
|
911
|
+
* @type {string}
|
|
912
|
+
*/
|
|
731
913
|
this.nick = "";
|
|
914
|
+
/**
|
|
915
|
+
* Set of subscribed channels.
|
|
916
|
+
* @type {Set<string>}
|
|
917
|
+
*/
|
|
732
918
|
this.channels = new Set();
|
|
919
|
+
/**
|
|
920
|
+
* Map of promises for message responses.
|
|
921
|
+
* @type {Map<number, Array<Function>>}
|
|
922
|
+
*/
|
|
733
923
|
this.promiseMap = new Map();
|
|
924
|
+
/**
|
|
925
|
+
* Timeout for message promises.
|
|
926
|
+
* @type {number}
|
|
927
|
+
*/
|
|
734
928
|
this.promiseTimeOut = SIZE_LIMIT.PROMISE_TIMEOUT;
|
|
929
|
+
/**
|
|
930
|
+
* Message ID for promises.
|
|
931
|
+
* @type {number}
|
|
932
|
+
*/
|
|
735
933
|
this.mid = 0; // promise message id
|
|
736
934
|
|
|
935
|
+
/**
|
|
936
|
+
* Quota level.
|
|
937
|
+
* @type {number}
|
|
938
|
+
*/
|
|
737
939
|
this.level = 3; // also defaultQuotaLevel
|
|
940
|
+
/**
|
|
941
|
+
* Quota table for current level.
|
|
942
|
+
* @type {object}
|
|
943
|
+
*/
|
|
738
944
|
this.quota = quotaTable[this.level];
|
|
945
|
+
/**
|
|
946
|
+
* Server settings.
|
|
947
|
+
* @type {object}
|
|
948
|
+
*/
|
|
739
949
|
this.serverSet = {};
|
|
950
|
+
/**
|
|
951
|
+
* Map of linked channels.
|
|
952
|
+
* @type {Map<string, Set<string>>}
|
|
953
|
+
*/
|
|
740
954
|
this.linkMap = new Map();
|
|
741
955
|
|
|
956
|
+
/**
|
|
957
|
+
* Indicates if auto-reconnect is enabled.
|
|
958
|
+
* @type {boolean}
|
|
959
|
+
* @default true
|
|
960
|
+
* */
|
|
961
|
+
this.autoReconnect = true; // default true
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* A flag to prevent duplicate close operations.
|
|
965
|
+
* @type {boolean}
|
|
966
|
+
* @private
|
|
967
|
+
*/
|
|
968
|
+
this._closed = false; // 중복 close 방지
|
|
969
|
+
|
|
742
970
|
this.on('open', this.onOpen.bind(this));
|
|
743
971
|
this.on('close', this.onClose.bind(this));
|
|
744
972
|
this.on('socket_data', this.onData.bind(this));
|
|
745
973
|
}
|
|
746
974
|
|
|
747
975
|
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Performs common cleanup for the connection. It clears pending promises,
|
|
979
|
+
* resets the socket reference, and sets the state to closed.
|
|
980
|
+
* This method is guarded to only run once.
|
|
981
|
+
* If autoReconnect is false, it also clears the keep-alive timer.
|
|
982
|
+
*/
|
|
983
|
+
close() {
|
|
984
|
+
if (this._closed) return;
|
|
985
|
+
this._closed = true;
|
|
986
|
+
|
|
987
|
+
// If auto-reconnect is disabled, we must stop the keep-alive timer.
|
|
988
|
+
if (this.autoReconnect === false) {
|
|
989
|
+
clearInterval(this.connectionCheckerIntervalID);
|
|
990
|
+
this.connectionCheckerIntervalID = null;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// socket clean
|
|
994
|
+
if (this.socket) {
|
|
995
|
+
// For WebSockets, readyState are: 0-CONNECTING, 1-OPEN, 2-CLOSING, 3-CLOSED
|
|
996
|
+
// Calling close() on a CONNECTING socket will cause a browser error.
|
|
997
|
+
if (this.socket.readyState === 0) { // 0 is WebSocket.CONNECTING
|
|
998
|
+
// To avoid the error, we wait for the connection to open, then immediately close it.
|
|
999
|
+
// We also clear other handlers to prevent any other logic from running.
|
|
1000
|
+
const socket = this.socket;
|
|
1001
|
+
socket.onopen = () => { if(socket) socket.close(); };
|
|
1002
|
+
socket.onmessage = null;
|
|
1003
|
+
socket.onerror = null;
|
|
1004
|
+
socket.onclose = null;
|
|
1005
|
+
} else {
|
|
1006
|
+
try {
|
|
1007
|
+
// For other sockets (like TCP) or other WebSocket states, close directly.
|
|
1008
|
+
this.socket.close?.();
|
|
1009
|
+
} catch {}
|
|
1010
|
+
}
|
|
1011
|
+
this.socket = null;
|
|
1012
|
+
}
|
|
1013
|
+
this.promiseMap.clear();
|
|
1014
|
+
this.emit('closed');
|
|
1015
|
+
this.stateChange('closed');
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Disables auto-reconnect and closes the current connection.
|
|
1020
|
+
* The instance can be re-opened manually later. For complete cleanup, use destroy().
|
|
1021
|
+
*/
|
|
1022
|
+
stop() {
|
|
1023
|
+
this.autoReconnect = false;
|
|
1024
|
+
this.close();
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Permanently destroys the instance, cleaning up all resources.
|
|
1029
|
+
* The instance will not be usable after this.
|
|
1030
|
+
*/
|
|
1031
|
+
destroy() {
|
|
1032
|
+
this.stop();
|
|
1033
|
+
this.removeAllListeners();
|
|
1034
|
+
|
|
1035
|
+
this.channels.clear();
|
|
1036
|
+
this.linkMap.clear();
|
|
1037
|
+
|
|
1038
|
+
// Help GC
|
|
1039
|
+
this.boho = null;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* The core keep-alive logic. It checks if auto-reconnect is enabled.
|
|
1044
|
+
* The actual check for the socket's state is implemented in the child classes.
|
|
1045
|
+
*/
|
|
1046
|
+
keepAlive() {
|
|
1047
|
+
if (!this.autoReconnect) return;
|
|
1048
|
+
// The specific logic for checking the socket's state and reconnecting
|
|
1049
|
+
// is implemented in the child classes (IOWS, IOCongSocket, etc.).
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Redirects the connection to a new URL.
|
|
1054
|
+
* @param {string} url2 - The new URL to redirect to.
|
|
1055
|
+
*/
|
|
748
1056
|
redirect(url2) {
|
|
749
1057
|
this.close();
|
|
750
1058
|
this.stateChange('redirecting');
|
|
751
1059
|
this.createConnection(url2);
|
|
752
1060
|
}
|
|
753
1061
|
|
|
1062
|
+
/**
|
|
1063
|
+
* Opens the WebSocket connection.
|
|
1064
|
+
* @param {string} [url] - Optional URL to connect to. If not provided, uses the instance's URL.
|
|
1065
|
+
*/
|
|
754
1066
|
open(url) {
|
|
755
|
-
|
|
1067
|
+
// If a connection is already active or in progress, calling open() implies a reconnect.
|
|
1068
|
+
// Close the existing socket first to ensure a clean state.
|
|
1069
|
+
if (this.socket) {
|
|
1070
|
+
this.close();
|
|
1071
|
+
}
|
|
756
1072
|
|
|
757
1073
|
if (url) {
|
|
758
|
-
|
|
759
|
-
this.url = url;
|
|
760
|
-
} else if (url !== this.url) { // default host url change
|
|
761
|
-
this.url = url;
|
|
762
|
-
if (this.socket) {
|
|
763
|
-
this.close();
|
|
764
|
-
return
|
|
765
|
-
}
|
|
766
|
-
}
|
|
1074
|
+
this.url = url;
|
|
767
1075
|
}
|
|
768
1076
|
|
|
1077
|
+
if (!this.url) {
|
|
1078
|
+
this.emit('error', new Error('URL is not set.'));
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// The actual connection is created here.
|
|
769
1083
|
this.createConnection(this.url);
|
|
770
1084
|
|
|
1085
|
+
// Ensure the keep-alive timer is running.
|
|
771
1086
|
if (!this.connectionCheckerIntervalID) {
|
|
772
1087
|
this.connectionCheckerIntervalID = setInterval(this.keepAlive.bind(this), this.connectionCheckerPeriod);
|
|
773
1088
|
}
|
|
774
1089
|
}
|
|
775
1090
|
|
|
1091
|
+
/**
|
|
1092
|
+
* Handles the 'open' event of the WebSocket. Resets the closed flag and sets the state to open.
|
|
1093
|
+
*/
|
|
776
1094
|
onOpen() {
|
|
1095
|
+
this._closed = false;
|
|
777
1096
|
if (this.url.includes("wss://")) {
|
|
778
1097
|
this.TLS = true;
|
|
779
1098
|
} else {
|
|
@@ -782,39 +1101,40 @@ class IOCore extends EventEmitter {
|
|
|
782
1101
|
this.stateChange('open');
|
|
783
1102
|
}
|
|
784
1103
|
|
|
1104
|
+
/**
|
|
1105
|
+
* Handles the 'close' event of the WebSocket.
|
|
1106
|
+
*/
|
|
785
1107
|
onClose() {
|
|
786
1108
|
this.boho.isAuthorized = false;
|
|
787
1109
|
this.cid = "";
|
|
788
1110
|
this.stateChange('closed');
|
|
789
1111
|
}
|
|
790
1112
|
|
|
791
|
-
|
|
1113
|
+
/**
|
|
1114
|
+
* Manually logs in with provided ID and key.
|
|
1115
|
+
* @param {string} id - The user ID.
|
|
1116
|
+
* @param {string} key - The user key.
|
|
1117
|
+
* @returns {boolean}
|
|
1118
|
+
*/
|
|
792
1119
|
login(id, key) {
|
|
793
|
-
if (!id
|
|
794
|
-
console.log('no id and key.');
|
|
795
|
-
return
|
|
796
|
-
}
|
|
797
|
-
console.log('manual login: ', id);
|
|
1120
|
+
if (!this.auth(id, key)) return false;
|
|
798
1121
|
|
|
799
|
-
if (!key && id.includes('.')) {
|
|
800
|
-
this.boho.set_id_key(id);
|
|
801
|
-
} else if (id && key) {
|
|
802
|
-
this.boho.set_id8(id);
|
|
803
|
-
this.boho.set_key(key);
|
|
804
|
-
} else {
|
|
805
|
-
console.log('no id or key.');
|
|
806
|
-
return
|
|
807
|
-
}
|
|
808
1122
|
this.useAuth = true;
|
|
809
1123
|
let auth_pack = this.boho.auth_req();
|
|
810
1124
|
this.send(auth_pack);
|
|
1125
|
+
return true
|
|
811
1126
|
}
|
|
812
1127
|
|
|
813
|
-
|
|
1128
|
+
/**
|
|
1129
|
+
* Sets up authentication for auto-login.
|
|
1130
|
+
* @param {string} id - The user ID.
|
|
1131
|
+
* @param {string} key - The user key.
|
|
1132
|
+
* @returns {boolean}
|
|
1133
|
+
*/
|
|
814
1134
|
auth(id, key) {
|
|
815
1135
|
if (!id && !key) {
|
|
816
|
-
|
|
817
|
-
return
|
|
1136
|
+
this.emit('error', new Error('auth failed. no id and key.'));
|
|
1137
|
+
return false
|
|
818
1138
|
}
|
|
819
1139
|
|
|
820
1140
|
if (!key && id.includes('.')) {
|
|
@@ -823,12 +1143,17 @@ class IOCore extends EventEmitter {
|
|
|
823
1143
|
this.boho.set_id8(id);
|
|
824
1144
|
this.boho.set_key(key);
|
|
825
1145
|
} else {
|
|
826
|
-
|
|
827
|
-
return
|
|
1146
|
+
this.emit('error', new Error('auth failed. no id or key.'));
|
|
1147
|
+
return false
|
|
828
1148
|
}
|
|
829
1149
|
this.useAuth = true;
|
|
1150
|
+
return true
|
|
830
1151
|
}
|
|
831
1152
|
|
|
1153
|
+
/**
|
|
1154
|
+
* Handles incoming data from the WebSocket.
|
|
1155
|
+
* @param {Buffer} buffer - The incoming data buffer.
|
|
1156
|
+
*/
|
|
832
1157
|
onData(buffer) {
|
|
833
1158
|
let msgType = buffer[0];
|
|
834
1159
|
let decoded;
|
|
@@ -847,8 +1172,8 @@ class IOCore extends EventEmitter {
|
|
|
847
1172
|
// console.log( 'ENC_E2E decoded ', decoded )
|
|
848
1173
|
msgType = decoded[0];
|
|
849
1174
|
// decoded has msg_header only.
|
|
850
|
-
buffer.set(decoded, tt.MetaSize.ENC_488); // set decoded signal_e2e headaer.
|
|
851
|
-
buffer = buffer.subarray(tt.MetaSize.ENC_488); // reset offset.
|
|
1175
|
+
buffer.set(decoded, tt.MetaSize.ENC_488); // set decoded signal_e2e headaer.
|
|
1176
|
+
buffer = buffer.subarray(tt.MetaSize.ENC_488); // reset offset.
|
|
852
1177
|
// console.log('DECODED MsgType:', IOMsg[ msgType ] )
|
|
853
1178
|
} else {
|
|
854
1179
|
// console.log('488 DEC_FAIL', buffer)
|
|
@@ -886,10 +1211,8 @@ class IOCore extends EventEmitter {
|
|
|
886
1211
|
if (jsonInfo.ip) {
|
|
887
1212
|
this.ip = jsonInfo.ip;
|
|
888
1213
|
}
|
|
889
|
-
console.log('<IAM_RES>', JSON.stringify(jsonInfo));
|
|
890
|
-
// console.log('<IAM_RES>', JSON.stringify(jsonInfo,null,2))
|
|
891
1214
|
} catch (error) {
|
|
892
|
-
|
|
1215
|
+
this.emit('error', new Error('IAM_RES data error'));
|
|
893
1216
|
}
|
|
894
1217
|
break;
|
|
895
1218
|
|
|
@@ -953,7 +1276,7 @@ class IOCore extends EventEmitter {
|
|
|
953
1276
|
}
|
|
954
1277
|
|
|
955
1278
|
} catch (error) {
|
|
956
|
-
|
|
1279
|
+
this.emit('error', new Error('SERVER_SIGNAL parsing error'));
|
|
957
1280
|
}
|
|
958
1281
|
break;
|
|
959
1282
|
|
|
@@ -964,7 +1287,7 @@ class IOCore extends EventEmitter {
|
|
|
964
1287
|
this.emit(setPack.topic, ...setPack.args);
|
|
965
1288
|
}
|
|
966
1289
|
} catch (error) {
|
|
967
|
-
|
|
1290
|
+
this.emit('error', new Error('SET parsing error'));
|
|
968
1291
|
}
|
|
969
1292
|
break;
|
|
970
1293
|
|
|
@@ -993,7 +1316,10 @@ class IOCore extends EventEmitter {
|
|
|
993
1316
|
case PAYLOAD_TYPE.TEXT:
|
|
994
1317
|
// !! Must remove null char before decode in JS.
|
|
995
1318
|
// string payload contains null char for the c/cpp devices.
|
|
996
|
-
let payloadStringWithoutNull = payloadBuffer
|
|
1319
|
+
let payloadStringWithoutNull = payloadBuffer;
|
|
1320
|
+
if (payloadBuffer[payloadBuffer.byteLength - 1] === 0) {
|
|
1321
|
+
payloadStringWithoutNull = payloadBuffer.subarray(0, payloadBuffer.byteLength - 1);
|
|
1322
|
+
}
|
|
997
1323
|
let oneString = decoder$4.decode(payloadStringWithoutNull);
|
|
998
1324
|
if (tag.indexOf('@') === 0) this.emit('@', oneString, tag);
|
|
999
1325
|
if (tag !== '@') this.emit(tag, oneString, tag);
|
|
@@ -1029,7 +1355,7 @@ class IOCore extends EventEmitter {
|
|
|
1029
1355
|
}
|
|
1030
1356
|
|
|
1031
1357
|
} catch (err) {
|
|
1032
|
-
|
|
1358
|
+
this.emit('error', new Error('signal parse err'));
|
|
1033
1359
|
}
|
|
1034
1360
|
break;
|
|
1035
1361
|
|
|
@@ -1073,6 +1399,10 @@ class IOCore extends EventEmitter {
|
|
|
1073
1399
|
}
|
|
1074
1400
|
}
|
|
1075
1401
|
|
|
1402
|
+
/**
|
|
1403
|
+
* Sends an IAM (I Am) message to the server.
|
|
1404
|
+
* @param {string} [title] - Optional title for the IAM message.
|
|
1405
|
+
*/
|
|
1076
1406
|
iam(title) {
|
|
1077
1407
|
// console.log('iam', title)
|
|
1078
1408
|
if (title) {
|
|
@@ -1088,17 +1418,25 @@ class IOCore extends EventEmitter {
|
|
|
1088
1418
|
}
|
|
1089
1419
|
|
|
1090
1420
|
|
|
1421
|
+
/**
|
|
1422
|
+
* Sends a PING message to the server.
|
|
1423
|
+
*/
|
|
1091
1424
|
ping() {
|
|
1092
1425
|
this.send(Buffer$1.from([IOMsg.PING]));
|
|
1093
1426
|
}
|
|
1094
1427
|
|
|
1428
|
+
/**
|
|
1429
|
+
* Sends a PONG message to the server.
|
|
1430
|
+
*/
|
|
1095
1431
|
pong() {
|
|
1096
1432
|
this.send(Buffer$1.from([IOMsg.PONG]));
|
|
1097
1433
|
}
|
|
1098
1434
|
|
|
1099
1435
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1436
|
+
/**
|
|
1437
|
+
* Sends an ECHO message to the server.
|
|
1438
|
+
* @param {*} [args] - Optional arguments to echo.
|
|
1439
|
+
*/
|
|
1102
1440
|
echo(args) {
|
|
1103
1441
|
if (args) {
|
|
1104
1442
|
console.log('echo args:', args);
|
|
@@ -1113,10 +1451,18 @@ class IOCore extends EventEmitter {
|
|
|
1113
1451
|
}
|
|
1114
1452
|
|
|
1115
1453
|
|
|
1454
|
+
/**
|
|
1455
|
+
* Sends binary data.
|
|
1456
|
+
* @param {...any} data - Data to send.
|
|
1457
|
+
*/
|
|
1116
1458
|
bin(...data) {
|
|
1117
1459
|
this.send(M$1.U8pack(...data));
|
|
1118
1460
|
}
|
|
1119
1461
|
|
|
1462
|
+
/**
|
|
1463
|
+
* Sends data over the WebSocket.
|
|
1464
|
+
* @param {Buffer} data - The data buffer to send.
|
|
1465
|
+
*/
|
|
1120
1466
|
send(data) {
|
|
1121
1467
|
if (data.byteLength > this.quota.signalSize) {
|
|
1122
1468
|
this.emit('over_size');
|
|
@@ -1127,22 +1473,10 @@ class IOCore extends EventEmitter {
|
|
|
1127
1473
|
this.socket_send(data);
|
|
1128
1474
|
}
|
|
1129
1475
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
NO. if connection using TLS line.
|
|
1135
|
-
// ex. wss://url connection.
|
|
1136
|
-
YES. if no TLS line.
|
|
1137
|
-
// ex. ws://url connection.
|
|
1138
|
-
|
|
1139
|
-
if encMode == YES
|
|
1140
|
-
YES. encrypt the message.
|
|
1141
|
-
|
|
1142
|
-
if encMode == NO
|
|
1143
|
-
NO. do not ecnrypt message.
|
|
1144
|
-
|
|
1145
|
-
*/
|
|
1476
|
+
/**
|
|
1477
|
+
* Determines if encryption should be used based on current mode and TLS status.
|
|
1478
|
+
* @returns {boolean}
|
|
1479
|
+
*/
|
|
1146
1480
|
getEncryptionMode() {
|
|
1147
1481
|
if (this.encMode === ENC_MODE.YES ||
|
|
1148
1482
|
this.encMode === ENC_MODE.AUTO &&
|
|
@@ -1154,6 +1488,11 @@ class IOCore extends EventEmitter {
|
|
|
1154
1488
|
}
|
|
1155
1489
|
}
|
|
1156
1490
|
|
|
1491
|
+
/**
|
|
1492
|
+
* Sends data with encryption based on the encryption mode.
|
|
1493
|
+
* @param {Buffer} data - The data buffer to send.
|
|
1494
|
+
* @param {boolean} [useEncryption] - Optional. Force encryption or not. If undefined, uses default policy.
|
|
1495
|
+
*/
|
|
1157
1496
|
send_enc_mode(data, useEncryption) {
|
|
1158
1497
|
|
|
1159
1498
|
// use default policy.
|
|
@@ -1182,6 +1521,11 @@ class IOCore extends EventEmitter {
|
|
|
1182
1521
|
}
|
|
1183
1522
|
|
|
1184
1523
|
|
|
1524
|
+
/**
|
|
1525
|
+
* Sets a message promise for a given message ID.
|
|
1526
|
+
* @param {number} mid - The message ID.
|
|
1527
|
+
* @returns {Promise<any>}
|
|
1528
|
+
*/
|
|
1185
1529
|
setMsgPromise(mid) {
|
|
1186
1530
|
return new Promise((resolve, reject) => {
|
|
1187
1531
|
this.promiseMap.set(mid, [resolve, reject]);
|
|
@@ -1194,6 +1538,10 @@ class IOCore extends EventEmitter {
|
|
|
1194
1538
|
})
|
|
1195
1539
|
}
|
|
1196
1540
|
|
|
1541
|
+
/**
|
|
1542
|
+
* Tests and resolves/rejects a promise based on the incoming buffer.
|
|
1543
|
+
* @param {Buffer} buffer - The incoming data buffer.
|
|
1544
|
+
*/
|
|
1197
1545
|
testPromise(buffer) {
|
|
1198
1546
|
|
|
1199
1547
|
let res = M$1.unpack(buffer);
|
|
@@ -1218,11 +1566,21 @@ class IOCore extends EventEmitter {
|
|
|
1218
1566
|
}
|
|
1219
1567
|
|
|
1220
1568
|
|
|
1569
|
+
/**
|
|
1570
|
+
* Publishes a signal.
|
|
1571
|
+
* @param {...any} args - Arguments for the signal.
|
|
1572
|
+
*/
|
|
1221
1573
|
publish(...args) {
|
|
1222
1574
|
this.signal(...args);
|
|
1223
1575
|
}
|
|
1224
1576
|
|
|
1225
1577
|
|
|
1578
|
+
/**
|
|
1579
|
+
* Sends a signal with a tag and arguments.
|
|
1580
|
+
* @param {string} tag - The signal tag.
|
|
1581
|
+
* @param {...any} args - Arguments for the signal.
|
|
1582
|
+
* @throws {TypeError} If tag is not a string.
|
|
1583
|
+
*/
|
|
1226
1584
|
signal(tag, ...args) {
|
|
1227
1585
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1228
1586
|
|
|
@@ -1230,10 +1588,23 @@ class IOCore extends EventEmitter {
|
|
|
1230
1588
|
this.send_enc_mode(signalPack);
|
|
1231
1589
|
}
|
|
1232
1590
|
|
|
1591
|
+
/**
|
|
1592
|
+
* Decrypts E2E data.
|
|
1593
|
+
* @param {Buffer} data - The encrypted data.
|
|
1594
|
+
* @param {string} key - The decryption key.
|
|
1595
|
+
* @returns {Buffer}
|
|
1596
|
+
*/
|
|
1233
1597
|
decrypt_e2e(data, key) {
|
|
1234
1598
|
return this.boho.decrypt_e2e(data, key)
|
|
1235
1599
|
}
|
|
1236
1600
|
|
|
1601
|
+
/**
|
|
1602
|
+
* Sends an E2E (End-to-End) encrypted signal.
|
|
1603
|
+
* @param {string} tag - The signal tag.
|
|
1604
|
+
* @param {Buffer} data - The data to encrypt and send.
|
|
1605
|
+
* @param {string} key - The encryption key.
|
|
1606
|
+
* @throws {TypeError} If tag is not a string.
|
|
1607
|
+
*/
|
|
1237
1608
|
signal_e2e(tag, data, key) {
|
|
1238
1609
|
|
|
1239
1610
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
@@ -1257,6 +1628,12 @@ class IOCore extends EventEmitter {
|
|
|
1257
1628
|
|
|
1258
1629
|
|
|
1259
1630
|
|
|
1631
|
+
/**
|
|
1632
|
+
* Sets a value in the store.
|
|
1633
|
+
* @param {string} storeName - The name of the store.
|
|
1634
|
+
* @param {...any} args - Arguments to set.
|
|
1635
|
+
* @returns {Promise<any>}
|
|
1636
|
+
*/
|
|
1260
1637
|
set(storeName, ...args) {
|
|
1261
1638
|
if (!storeName || args.length == 0) {
|
|
1262
1639
|
return Promise.reject(new Error('set need storeName and value)'))
|
|
@@ -1264,6 +1641,11 @@ class IOCore extends EventEmitter {
|
|
|
1264
1641
|
return this.req('store', 'set', storeName, ...args)
|
|
1265
1642
|
}
|
|
1266
1643
|
|
|
1644
|
+
/**
|
|
1645
|
+
* Gets a value from the store.
|
|
1646
|
+
* @param {string} storeName - The name of the store.
|
|
1647
|
+
* @returns {Promise<any>}
|
|
1648
|
+
*/
|
|
1267
1649
|
async get(storeName) {
|
|
1268
1650
|
if (!storeName) {
|
|
1269
1651
|
return Promise.reject(new Error('store get need storeName)'))
|
|
@@ -1274,6 +1656,13 @@ class IOCore extends EventEmitter {
|
|
|
1274
1656
|
}
|
|
1275
1657
|
|
|
1276
1658
|
|
|
1659
|
+
/**
|
|
1660
|
+
* Sends a request to a target and topic.
|
|
1661
|
+
* @param {string} target - The target of the request.
|
|
1662
|
+
* @param {string} topic - The topic of the request.
|
|
1663
|
+
* @param {...any} args - Optional arguments for the request.
|
|
1664
|
+
* @returns {Promise<any>}
|
|
1665
|
+
*/
|
|
1277
1666
|
req(target, topic, ...args) {
|
|
1278
1667
|
if (!target || !topic)
|
|
1279
1668
|
return Promise.reject(new Error('request need target and topic)'))
|
|
@@ -1299,6 +1688,11 @@ class IOCore extends EventEmitter {
|
|
|
1299
1688
|
}
|
|
1300
1689
|
|
|
1301
1690
|
|
|
1691
|
+
/**
|
|
1692
|
+
* Subscribes to a channel or channels.
|
|
1693
|
+
* @param {string} tag - The tag(s) of the channel(s) to subscribe to (comma-separated).
|
|
1694
|
+
* @throws {TypeError} If tag is not a string or exceeds length limit.
|
|
1695
|
+
*/
|
|
1302
1696
|
subscribe(tag) {
|
|
1303
1697
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1304
1698
|
if (this.state !== STATES.READY) return
|
|
@@ -1318,6 +1712,12 @@ class IOCore extends EventEmitter {
|
|
|
1318
1712
|
tagEncoded]));
|
|
1319
1713
|
}
|
|
1320
1714
|
|
|
1715
|
+
/**
|
|
1716
|
+
* Subscribes to a channel or channels with a promise.
|
|
1717
|
+
* @param {string} tag - The tag(s) of the channel(s) to subscribe to (comma-separated).
|
|
1718
|
+
* @returns {Promise<any>}
|
|
1719
|
+
* @throws {TypeError} If tag is not a string or exceeds length limit.
|
|
1720
|
+
*/
|
|
1321
1721
|
subscribe_promise(tag) {
|
|
1322
1722
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1323
1723
|
if (this.state !== STATES.READY) {
|
|
@@ -1336,6 +1736,9 @@ class IOCore extends EventEmitter {
|
|
|
1336
1736
|
return this.setMsgPromise(this.mid)
|
|
1337
1737
|
}
|
|
1338
1738
|
|
|
1739
|
+
/**
|
|
1740
|
+
* Subscribes to channels stored in memory (local cache).
|
|
1741
|
+
*/
|
|
1339
1742
|
subscribe_memory_channels() { //local cache . auto_resubscribe
|
|
1340
1743
|
if (this.channels.size == 0) return
|
|
1341
1744
|
let chList = Array.from(this.channels).join(',');
|
|
@@ -1349,6 +1752,11 @@ class IOCore extends EventEmitter {
|
|
|
1349
1752
|
|
|
1350
1753
|
}
|
|
1351
1754
|
|
|
1755
|
+
/**
|
|
1756
|
+
* Unsubscribes from a channel or channels.
|
|
1757
|
+
* @param {string} [tag=""] - The tag(s) of the channel(s) to unsubscribe from (comma-separated). If empty, unsubscribes from all.
|
|
1758
|
+
* @throws {TypeError} If tag is not a string or exceeds length limit.
|
|
1759
|
+
*/
|
|
1352
1760
|
unsubscribe(tag = "") {
|
|
1353
1761
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1354
1762
|
|
|
@@ -1371,6 +1779,12 @@ class IOCore extends EventEmitter {
|
|
|
1371
1779
|
}
|
|
1372
1780
|
|
|
1373
1781
|
|
|
1782
|
+
/**
|
|
1783
|
+
* Listens for signals on a specific tag.
|
|
1784
|
+
* @param {string} tag - The tag to listen on.
|
|
1785
|
+
* @param {Function} handler - The callback function to handle the signal.
|
|
1786
|
+
* @throws {TypeError} If tag is not a string, handler is not a function, or tag length is invalid.
|
|
1787
|
+
*/
|
|
1374
1788
|
listen(tag, handler) {
|
|
1375
1789
|
if (typeof tag !== 'string') throw TypeError('tag should be string.')
|
|
1376
1790
|
if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
|
|
@@ -1387,6 +1801,13 @@ class IOCore extends EventEmitter {
|
|
|
1387
1801
|
|
|
1388
1802
|
|
|
1389
1803
|
|
|
1804
|
+
/**
|
|
1805
|
+
* Links a local target to a remote tag and sets up a handler.
|
|
1806
|
+
* @param {string} to - The local link target.
|
|
1807
|
+
* @param {string} tag - The remote tag.
|
|
1808
|
+
* @param {Function} handler - The callback function to handle the signal.
|
|
1809
|
+
* @throws {TypeError} If 'to' or 'tag' are not strings, handler is not a function, or tag length is invalid.
|
|
1810
|
+
*/
|
|
1390
1811
|
link(to, tag, handler) {
|
|
1391
1812
|
if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
|
|
1392
1813
|
if (typeof tag !== 'string') throw TypeError('tag is not a string.')
|
|
@@ -1412,44 +1833,54 @@ class IOCore extends EventEmitter {
|
|
|
1412
1833
|
}
|
|
1413
1834
|
|
|
1414
1835
|
|
|
1836
|
+
/**
|
|
1837
|
+
* Unlinks a specific tag from a local target.
|
|
1838
|
+
* @param {string} to - The local link target.
|
|
1839
|
+
* @param {string} tag - The tag to unlink.
|
|
1840
|
+
* @throws {TypeError} If 'to' or 'tag' are not strings or tag length is invalid.
|
|
1841
|
+
*/
|
|
1415
1842
|
unlink(to, tag) {
|
|
1416
1843
|
if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
|
|
1417
1844
|
if (typeof tag !== 'string') throw TypeError('tag is not a string.')
|
|
1418
1845
|
if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
|
|
1419
1846
|
|
|
1420
|
-
|
|
1847
|
+
const linkSet = this.linkMap.get(to);
|
|
1848
|
+
if (!linkSet || !linkSet.has(tag)) return;
|
|
1421
1849
|
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
if (tags[i] == tag) {
|
|
1426
|
-
this.unsubscribe(tag);
|
|
1427
|
-
this.removeAllListeners(tag);
|
|
1428
|
-
linkSet.delete(tag);
|
|
1429
|
-
this.linkMap.set(to, linkSet);
|
|
1430
|
-
break;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1850
|
+
this.unsubscribe(tag);
|
|
1851
|
+
this.removeAllListeners(tag);
|
|
1852
|
+
linkSet.delete(tag);
|
|
1433
1853
|
|
|
1854
|
+
if (linkSet.size === 0) {
|
|
1855
|
+
this.linkMap.delete(to);
|
|
1856
|
+
}
|
|
1434
1857
|
}
|
|
1435
1858
|
|
|
1859
|
+
/**
|
|
1860
|
+
* Unlinks all tags from a local target.
|
|
1861
|
+
* @param {string} to - The local link target.
|
|
1862
|
+
* @throws {TypeError} If 'to' is not a string.
|
|
1863
|
+
*/
|
|
1436
1864
|
unlinkAll(to) {
|
|
1437
1865
|
if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
for (
|
|
1443
|
-
this.unsubscribe(
|
|
1444
|
-
this.removeAllListeners(
|
|
1445
|
-
linkSet.delete(tags[i]);
|
|
1866
|
+
|
|
1867
|
+
const linkSet = this.linkMap.get(to);
|
|
1868
|
+
if (!linkSet) return;
|
|
1869
|
+
|
|
1870
|
+
for (const tag of linkSet) {
|
|
1871
|
+
this.unsubscribe(tag);
|
|
1872
|
+
this.removeAllListeners(tag);
|
|
1446
1873
|
}
|
|
1447
|
-
this.linkMap.delete(to);
|
|
1448
1874
|
|
|
1875
|
+
this.linkMap.delete(to);
|
|
1449
1876
|
}
|
|
1450
1877
|
|
|
1451
1878
|
|
|
1452
1879
|
|
|
1880
|
+
/**
|
|
1881
|
+
* Gets connection metrics.
|
|
1882
|
+
* @returns {{tx: number, rx: number, txb: number, rxb: number, last: number}}
|
|
1883
|
+
*/
|
|
1453
1884
|
getMetric() {
|
|
1454
1885
|
return {
|
|
1455
1886
|
tx: this.txCounter,
|
|
@@ -1461,10 +1892,18 @@ class IOCore extends EventEmitter {
|
|
|
1461
1892
|
|
|
1462
1893
|
}
|
|
1463
1894
|
|
|
1895
|
+
/**
|
|
1896
|
+
* Gets the current connection state.
|
|
1897
|
+
* @returns {number}
|
|
1898
|
+
*/
|
|
1464
1899
|
getState() {
|
|
1465
1900
|
return this.state
|
|
1466
1901
|
}
|
|
1467
1902
|
|
|
1903
|
+
/**
|
|
1904
|
+
* Gets the current connection state name.
|
|
1905
|
+
* @returns {string}
|
|
1906
|
+
*/
|
|
1468
1907
|
getStateName() {
|
|
1469
1908
|
//state <number>
|
|
1470
1909
|
//value of constant STATES.NAME < number >
|
|
@@ -1473,6 +1912,10 @@ class IOCore extends EventEmitter {
|
|
|
1473
1912
|
return (STATES[this.state]).toLowerCase()
|
|
1474
1913
|
}
|
|
1475
1914
|
|
|
1915
|
+
/**
|
|
1916
|
+
* Gets security-related information.
|
|
1917
|
+
* @returns {{useAuth: boolean, isTLS: boolean, isAuthorized: boolean, encMode: number, usingEncryption: boolean}}
|
|
1918
|
+
*/
|
|
1476
1919
|
getSecurity() {
|
|
1477
1920
|
return {
|
|
1478
1921
|
useAuth: this.useAuth,
|
|
@@ -1483,6 +1926,11 @@ class IOCore extends EventEmitter {
|
|
|
1483
1926
|
}
|
|
1484
1927
|
}
|
|
1485
1928
|
|
|
1929
|
+
/**
|
|
1930
|
+
* Changes the connection state and emits events.
|
|
1931
|
+
* @param {string} state - The new state name (e.g., 'ready', 'closed').
|
|
1932
|
+
* @param {string} [emitEventAndMessage] - Optional message to emit with the state change event.
|
|
1933
|
+
*/
|
|
1486
1934
|
stateChange(state, emitEventAndMessage) {
|
|
1487
1935
|
// STATES constant name : string upperCase
|
|
1488
1936
|
// eventName, .stateName : string lowerCase
|
|
@@ -1642,20 +2090,30 @@ class IOCongSocket extends IOCore {
|
|
|
1642
2090
|
if (url) this.open();
|
|
1643
2091
|
}
|
|
1644
2092
|
|
|
2093
|
+
/**
|
|
2094
|
+
* Closes TCP socket and cleans resources.
|
|
2095
|
+
*/
|
|
1645
2096
|
close() {
|
|
1646
|
-
this.socket
|
|
1647
|
-
|
|
2097
|
+
if (this.socket) {
|
|
2098
|
+
if (this.congRx) {
|
|
2099
|
+
this.socket.unpipe(this.congRx);
|
|
2100
|
+
this.congRx.destroy(); // Use destroy() for complete stream cleanup
|
|
2101
|
+
this.congRx = null;
|
|
2102
|
+
}
|
|
2103
|
+
this.socket.removeAllListeners();
|
|
2104
|
+
if (!this.socket.destroyed) {
|
|
2105
|
+
this.socket.destroy(); // destroy() is sufficient for forceful closing
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
super.close();
|
|
1648
2109
|
}
|
|
1649
2110
|
|
|
1650
|
-
|
|
1651
|
-
this.close();
|
|
1652
|
-
clearInterval(this.connectionCheckerIntervalID);
|
|
1653
|
-
this.connectionCheckerIntervalID = null;
|
|
1654
|
-
}
|
|
2111
|
+
|
|
1655
2112
|
|
|
1656
2113
|
keepAlive() {
|
|
1657
|
-
|
|
1658
|
-
if
|
|
2114
|
+
if (!this.autoReconnect) return;
|
|
2115
|
+
// Reconnect only if the socket is fully destroyed and the state is closed.
|
|
2116
|
+
if ((!this.socket || this.socket.destroyed) && this.state === STATES.CLOSED) {
|
|
1659
2117
|
this.open();
|
|
1660
2118
|
}
|
|
1661
2119
|
}
|
|
@@ -7065,32 +7523,28 @@ class IOWS extends IOCore {
|
|
|
7065
7523
|
|
|
7066
7524
|
|
|
7067
7525
|
|
|
7526
|
+
/**
|
|
7527
|
+
* Closes ws WebSocket and cleans resources.
|
|
7528
|
+
*/
|
|
7068
7529
|
close() {
|
|
7069
7530
|
if (this.socket) {
|
|
7070
|
-
this.socket.
|
|
7071
|
-
this.socket.
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
this.socket = null;
|
|
7531
|
+
this.socket.removeAllListeners();
|
|
7532
|
+
if (this.socket.readyState !== WebSocket.CLOSED) {
|
|
7533
|
+
this.socket.close();
|
|
7534
|
+
}
|
|
7075
7535
|
}
|
|
7076
|
-
|
|
7536
|
+
super.close();
|
|
7077
7537
|
}
|
|
7078
7538
|
|
|
7079
7539
|
|
|
7080
|
-
|
|
7081
|
-
stop() {
|
|
7082
|
-
this.close();
|
|
7083
|
-
clearInterval(this.connectionCheckerIntervalID);
|
|
7084
|
-
this.connectionCheckerIntervalID = null;
|
|
7085
|
-
}
|
|
7086
|
-
|
|
7087
7540
|
keepAlive() {
|
|
7088
|
-
if (!this.
|
|
7541
|
+
if (!this.autoReconnect) return;
|
|
7542
|
+
// Reconnect only if the socket is closed and the state reflects that.
|
|
7543
|
+
if ((!this.socket || this.socket.readyState === WebSocket.CLOSED) && this.state === STATES.CLOSED) {
|
|
7089
7544
|
this.open();
|
|
7090
7545
|
}
|
|
7091
7546
|
}
|
|
7092
7547
|
|
|
7093
|
-
|
|
7094
7548
|
createConnection(url) {
|
|
7095
7549
|
// node WebSocket
|
|
7096
7550
|
this.socket = new WebSocket(url);
|