wspromisify 2.7.1 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.ts +5 -2
- package/dist/bundle.mjs +1 -1
- package/package.json +1 -1
- package/src/WSC.ts +33 -29
- package/src/config.ts +1 -0
- package/src/types.ts +1 -0
package/README.md
CHANGED
|
@@ -61,8 +61,10 @@ Default constructor config is
|
|
|
61
61
|
timeout: 1400,
|
|
62
62
|
// Reconnect timeout in seconds or null.
|
|
63
63
|
reconnect: 2,
|
|
64
|
-
// Attempts before silently givin' up.
|
|
65
|
-
reconnection_attempts: 25
|
|
64
|
+
// Attempts before silently givin' up. Defaults to Infinity.
|
|
65
|
+
reconnection_attempts: 25
|
|
66
|
+
// Time in seconds after the connection is closed if nothing was sent explicitly by send(). Defaults to Infinity.
|
|
67
|
+
max_idle_time: 25
|
|
66
68
|
// Lazy connect: connects only if something sent (then sends all of them!)
|
|
67
69
|
lazy: false,
|
|
68
70
|
// Existing socket if you already have one to augment with this force.
|
package/dist/bundle.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const
|
|
1
|
+
"use strict";const e=Symbol("Placeholder"),t=t=>{let n=0;for(const s of t)s!==e&&n++;return n},n=(t,n)=>{const s=t.length,o=t.slice(),r=n.length;let i=r,l=0;for(;i&&l<s;l++)o[l]===e&&(o[l]=n[r-i],i--);for(l=s;i;l++,i--)o[l]=n[r-i];return o},s=(e,o,r)=>{const i=e.length-o.length-t(r);if(i<1)return e(...n(o,r));{const t=(...t)=>s(e,n(o,r),t);return t.$args_left=i,t}},o=e=>(...n)=>e.length>t(n)?s(e,[],n):e(...n);function r(t){return function(n,s){const o=n===e,r=arguments.length;if(1===r&&o)throw new Error("Senseless placeholder usage.");return r>1?o?(t=>function(n){return n===e?t:t(n)})((e=>t(e,s))):t(n,s):e=>t(n,e)}}function i(e){return o(e)}const l=void 0,c=1/0,u=e=>typeof e,a=e=>null===e,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=e=>{const t=u(e);return"object"===t?a(e)?"Null":e.constructor.name:h[t[0]]+t.slice(1)},p=e=>e.length,g=r(((e,t)=>e===t)),m=r(((e,t)=>{const n=d(e);if(g(n,d(t))&&(g(n,"Object")||g(n,"Array"))){if(a(e)||a(t))return g(e,t);if(g(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(g(n,t)&&s in e||g(n,e)&&s in t&&m(e[s],t[s])))return!1;return!0}return g(e,t)})),y=r(((e,t)=>(t.push(e),t))),w=i(((e,t,n)=>n.reduce(e,t))),_=o(((e,t,n,s)=>e(s)?t(s):n(s))),b=(...t)=>(...n)=>{let s,o=!0;for(let r=p(t)-1;r>-1;r--)o?(o=!1,s=t[r](...n)):s=s===e?t[r]():t[r](s);return s},S=r(((e,t)=>t[e])),k=i(((e,t,n)=>n.slice(e,(e=>"number"==u(e))(t)?t:c))),P=S(0);k(1,c);const v=r(((e,t)=>t.find(e))),E=e=>()=>e,N=r(((e,t)=>t.split(e))),j=E(!0),A=E(!1),W=r(((e,t)=>w(((t,n)=>v((t=>e(n,t)),t)?t:y(n,t)),[],t)))(m),q=i(((e,t,n)=>p(t)?(e=>a(e)||(e=>e===l)(e))(n)?e:b((s=>s in n?q(e,k(1,c,t),n[s]):e),P)(t):n));q(l),b(_(m(f),A,j),q(f));const C=r(((e,t)=>t.map(e))),{floor:O}=Math,Q="0123456789abcdefghijklmnopqrstuvwxyz",$=b((e=>Object.fromEntries(e)),C(((e,t)=>[e,t])),N(""));class z{abc;abclen;c2pos;standard;setABC(e){if(!b(m(p(t=e)),p,W,N(""))(t))throw new Error("Not all chars are unique!");var t;this.abc=e,this.abclen=e.length,this.standard=Q.startsWith(e),this.c2pos=$(e)}zip(e){const{abc:t,abclen:n}=this;let s="";for(;e>0;)s=t[e%n]+s,e=O(e/n);return s||"0"}unzip(e){const{standard:t,abclen:n,c2pos:s}=this;if(t)return parseInt(e,n);const o=e.length;let r=0;for(let t=0;t<o;t++)r+=s[e[t]]*n**(o-t-1);return r}constructor(e){this.setABC(e||Q+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new z;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),I=(e,t,n)=>e.addEventListener(t,n),x=(e,t)=>setTimeout(t,e),B={data_type:"json",log:()=>null,timer:!1,url:"localhost",timeout:1400,reconnect:2,reconnection_attempts:1/0,max_idle_time:1/0,lazy:!1,socket:null,adapter:(e,t)=>new WebSocket(e,t),encode:(e,t,{server:n})=>JSON.stringify({[n.id_key]:e,[n.data_key]:t}),decode:e=>JSON.parse(e),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},D=Symbol("Placeholder"),L=e=>{let t=0;for(const n of e)n!==D&&t++;return t},U=(e,t)=>{const n=e.length,s=e.slice(),o=t.length;let r=o,i=0;for(;r&&i<n;i++)s[i]===D&&(s[i]=t[o-r],r--);for(i=n;r;i++,r--)s[i]=t[o-r];return s},F=(e,t,n)=>{const s=e.length-t.length-L(n);if(s<1)return e(...U(t,n));{const o=(...s)=>F(e,U(t,n),s);return o.$args_left=s,o}},J=e=>(...t)=>e.length>L(t)?F(e,[],t):e(...t);function M(e){return function(t,n){const s=t===D,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(e=>function(t){return t===D?e:e(t)})((t=>e(t,n))):e(t,n):n=>e(t,n)}}function G(e){return J(e)}const H=/^(.*?)(8|16|32|64)(Clamped)?Array$/,K=void 0,V=1/0,X=e=>typeof e,Y=e=>null===e,Z=e=>"number"==X(e);const ee=e=>Y(e)||(e=>e===K)(e),te={u:"U",b:"B",n:"N",s:"S",f:"F"},ne=Symbol(),se=e=>{const t=X(e);return"object"===t?Y(e)?"Null":e.constructor.name:te[t[0]]+t.slice(1)},oe=M(((e,t)=>se(t)===e)),re=e=>e.length,ie=M(((e,t)=>e===t)),le=M(((e,t)=>{const n=se(e);if(ie(n,se(t))&&(ie(n,"Object")||ie(n,"Array")||(e=>H.test(e))(n))){if(Y(e)||Y(t))return ie(e,t);if(ie(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(ie(n,t)&&s in e||ie(n,e)&&s in t&&le(e[s],t[s])))return!1;return!0}return ie(e,t)})),ce=M(((e,t)=>(t.push(e),t))),ue=G(((e,t,n)=>n.reduce(e,t))),ae=M(((e,t)=>{const n=(e=>Array.isArray(e))(t);let s,o;n&&(s=0,o=[]);for(let s in t)e(t[s],s)||(n?o.push(+s):delete t[s]);if(n)for(const e of o)t.splice(e-s++,1);return t})),he=J(((e,t,n,s)=>e(s)?t(s):n(s))),fe=(...e)=>(...t)=>{let n,s=!0;for(let o=re(e)-1;o>-1;o--)s?(s=!1,n=e[o](...t)):n=n===D?e[o]():e[o](n);return n},de=M(((e,t)=>t[e])),pe=G(((e,t,n)=>n.slice(e,Z(t)?t:V))),ge=de(0);pe(1,V);const me=M(((e,t)=>t.find(e))),ye=e=>()=>e,we=ye(!0),_e=ye(!1),be=M(((e,t)=>t(...e))),Se=e=>(...t)=>{const n=e(...t),s=function(e){return"function"===X(e)}(n);return!s||s&&n.$args_left<=0?(e=>!e)(n):Se(n)},ke=M(((e,t)=>ue(((t,n)=>me((t=>e(n,t)),t)?t:ce(n,t)),[],t)));ke(le);const Pe=e=>{let t,n=!1;return(...s)=>n?t:(n=!0,t=e(...s))},ve=G(((e,t,n)=>re(t)?ee(n)?e:fe((s=>s in n?ve(e,pe(1,V,t),n[s]):e),ge)(t):n));ve(K),fe(he(le(ne),_e,we),ve(ne));const Ee=G(((e,t,n)=>t(n)&&e(n))),Ne=Se,je=new z,Ae=be([]),We=Ee(oe("Number"),Ne(isNaN));module.exports=class{ws=null;intentionally_closed=!1;reconnect_timeout=null;queue={};onReadyQueue=[];onCloseQueue=[];handlers={open:[],close:[],message:[],error:[],timeout:[]};config={};ping_timer=null;idle_timer=null;get opened(){return 1===this.ws?.readyState}init_flush(){ae(_e,this.queue)}call(e,...t){for(const n of this.handlers[e])n(...t)}log(e,t=null,n=null){const{config:s}=this;null===n?s.timer?s.log(e,null,t):s.log(e,t):s.log(e,n,t)}resetPing(){const{config:{ping:e},ping_timer:t}=this;e&&(ee(t)||clearTimeout(t),this.ping_timer=x(1e3*e.interval,(async()=>{const{ping_timer:t,opened:n}=this;n?(await this.send(e.content),this.resetPing()):clearTimeout(t)})))}resetIdle(){const{config:{max_idle_time:e},idle_timer:t}=this;e!==1/0&&(ee(t)||clearTimeout(t),this.idle_timer=x(1e3*e,(()=>this.opened&&this.close())))}initSocket(e){const{queue:t,config:n}=this;this.ws=e,this.onReadyQueue.forEach((e=>e())),this.onReadyQueue.splice(0);const{id_key:s,data_key:o}=n.server;this.call("open",e);for(const n in t)e.send(t[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),this.resetIdle(),I(e,"close",(async(...e)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach(Ae),this.onCloseQueue.splice(0),this.call("close",...e);let{reconnect:t,reconnection_attempts:s}=n;if(We(t)){const e=async()=>{if(this.intentionally_closed||!s)return;s--,this.log("reconnect"),ee(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();ee(n)||(this.reconnect_timeout=setTimeout(e,1e3*t))};e()}})),I(e,"message",(e=>{try{const t=n.decode(e.data);if(this.call("message",{...e,data:t}),t[s]){const e=this.queue[t[s]];if(e){const n=e.sent_time?Date.now()-e.sent_time:null;this.log("message",t[o],n),e.ff(t[o])}}}catch(t){console.error(t,`WSP: Decode error. Got: ${e.data}`)}this.resetPing(),this.resetIdle()}))}opening=!1;connect(){return new Promise((e=>{if(this.opened||this.opening)return e(null);this.opening=!0;const t=this.config,n=t.socket||t.adapter(t.url,t.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),e(2);const s=Pe((t=>{this.opening=!1,e(t)}));I(n,"error",Pe((e=>{this.ws=null,this.log("error","status 3. Err: "+e.message),this.call("error",e),s(3)}))),n.readyState?(this.initSocket(n),s(null)):I(n,"open",Pe((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((e=>{this.opened?e():this.onReadyQueue.push(e)}))}on(e,t,n=we,s=!1){const o=e=>n(e)&&t(e);return s?I(this.ws,e,o):this.handlers[e].push(o),o}off(e,t,n=!1){if(n)return((e,t,n)=>e.removeEventListener(t,n))(this.ws,e,t);const s=this.handlers[e],o=s.indexOf(t);~o&&s.splice(o,1)}async close(){return new Promise(((e,t)=>{null===this.ws?t("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),e(null)})),this.ws.close(),this.ws=null,this.intentionally_closed=!0)}))}open(){if(!this.opened)return this.intentionally_closed=!1,this.connect()}async send(e,t={}){this.log("send",e);const{config:n,queue:s}=this,o={},{pipes:r,server:{data_key:i}}=n,l=je.zip(2147483637*Math.random()|0);if("object"==typeof t.top){if(t.top[i])throw new Error("Attempting to set data key/token via send() options!");Object.assign(o,t.top)}for(const t of r)e=t(e);const[c,u]=await Promise.all([n.encode(l,e,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);return this.opened&&(this.ws.send(c),this.resetPing(),this.resetIdle()),new Promise(((t,o)=>{this.queue[l]={msg:c,ff(e){clearTimeout(this.timeout),delete s[l],t(e)},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{l in this.queue&&(this.call("timeout",e),o({"Websocket timeout expired":n.timeout,"for the message":e}),delete s[l])}))}}))}constructor(e={}){this.config=(e=>{if(null===T&&!("adapter"in e))throw new Error("\n This platform has no native WebSocket implementation.\n Please use 'ws' package as an adapter.\n See https://github.com/houd1ni/WebsocketPromisify/issues/23\n ");const t=Object.assign({},B,e),n=t.url;if("/"==n[0])try{const e=location.protocol.includes("s:")?"wss":"ws";t.url=`${e}://${location.hostname}:${location.port}${n}`}catch(e){throw new Error("WSP: URL starting with / in non-browser environment!")}return t})(e),this.config.lazy||this.connect()}};
|
package/dist/bundle.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ declare namespace wsc {
|
|
|
26
26
|
timeout: number;
|
|
27
27
|
reconnect: number;
|
|
28
28
|
reconnection_attempts: number;
|
|
29
|
+
max_idle_time: number;
|
|
29
30
|
lazy: boolean;
|
|
30
31
|
socket: Socket | null;
|
|
31
32
|
adapter: (host: string, protocols?: string[]) => Socket;
|
|
@@ -59,19 +60,21 @@ declare namespace wsc {
|
|
|
59
60
|
}
|
|
60
61
|
declare class WebSocketClient {
|
|
61
62
|
private ws;
|
|
62
|
-
private
|
|
63
|
+
private intentionally_closed;
|
|
63
64
|
private reconnect_timeout;
|
|
64
65
|
private queue;
|
|
65
66
|
private onReadyQueue;
|
|
66
67
|
private onCloseQueue;
|
|
67
68
|
private handlers;
|
|
68
69
|
private config;
|
|
69
|
-
private
|
|
70
|
+
private ping_timer;
|
|
71
|
+
private idle_timer;
|
|
70
72
|
private get opened();
|
|
71
73
|
private init_flush;
|
|
72
74
|
private call;
|
|
73
75
|
private log;
|
|
74
76
|
private resetPing;
|
|
77
|
+
private resetIdle;
|
|
75
78
|
private initSocket;
|
|
76
79
|
private opening;
|
|
77
80
|
private connect;
|
package/dist/bundle.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const e=Symbol("Placeholder"),t=t=>{let n=0;for(const s of t)s!==e&&n++;return n},n=(t,n)=>{const s=t.length,o=t.slice(),r=n.length;let i=r,l=0;for(;i&&l<s;l++)o[l]===e&&(o[l]=n[r-i],i--);for(l=s;i;l++,i--)o[l]=n[r-i];return o},s=(e,o,r)=>{const i=e.length-o.length-t(r);if(i<1)return e(...n(o,r));{const t=(...t)=>s(e,n(o,r),t);return t.$args_left=i,t}},o=e=>(...n)=>e.length>t(n)?s(e,[],n):e(...n);function r(t){return function(n,s){const o=n===e,r=arguments.length;if(1===r&&o)throw new Error("Senseless placeholder usage.");return r>1?o?(t=>function(n){return n===e?t:t(n)})((e=>t(e,s))):t(n,s):e=>t(n,e)}}function i(e){return o(e)}const l=void 0,c=1/0,u=e=>typeof e,a=e=>null===e,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=e=>{const t=u(e);return"object"===t?a(e)?"Null":e.constructor.name:h[t[0]]+t.slice(1)},p=e=>e.length,g=r(((e,t)=>e===t)),m=r(((e,t)=>{const n=d(e);if(g(n,d(t))&&(g(n,"Object")||g(n,"Array"))){if(a(e)||a(t))return g(e,t);if(g(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(g(n,t)&&s in e||g(n,e)&&s in t&&m(e[s],t[s])))return!1;return!0}return g(e,t)})),y=r(((e,t)=>(t.push(e),t))),w=i(((e,t,n)=>n.reduce(e,t))),_=o(((e,t,n,s)=>e(s)?t(s):n(s))),b=(...t)=>(...n)=>{let s,o=!0;for(let r=p(t)-1;r>-1;r--)o?(o=!1,s=t[r](...n)):s=s===e?t[r]():t[r](s);return s},S=r(((e,t)=>t[e])),k=i(((e,t,n)=>n.slice(e,(e=>"number"==u(e))(t)?t:c))),P=S(0);k(1,c);const v=r(((e,t)=>t.find(e))),E=e=>()=>e,N=r(((e,t)=>t.split(e))),j=E(!0),A=E(!1),W=r(((e,t)=>w(((t,n)=>v((t=>e(n,t)),t)?t:y(n,t)),[],t)))(m),q=i(((e,t,n)=>p(t)?(e=>a(e)||(e=>e===l)(e))(n)?e:b((s=>s in n?q(e,k(1,c,t),n[s]):e),P)(t):n));q(l),b(_(m(f),A,j),q(f));const C=r(((e,t)=>t.map(e))),{floor:O}=Math,Q="0123456789abcdefghijklmnopqrstuvwxyz",$=b((e=>Object.fromEntries(e)),C(((e,t)=>[e,t])),N(""));class z{abc;abclen;c2pos;standard;setABC(e){if(!b(m(p(t=e)),p,W,N(""))(t))throw new Error("Not all chars are unique!");var t;this.abc=e,this.abclen=e.length,this.standard=Q.startsWith(e),this.c2pos=$(e)}zip(e){const{abc:t,abclen:n}=this;let s="";for(;e>0;)s=t[e%n]+s,e=O(e/n);return s||"0"}unzip(e){const{standard:t,abclen:n,c2pos:s}=this;if(t)return parseInt(e,n);const o=e.length;let r=0;for(let t=0;t<o;t++)r+=s[e[t]]*n**(o-t-1);return r}constructor(e){this.setABC(e||Q+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new z;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),I=(e,t,n)=>e.addEventListener(t,n),x=(e,t)=>setTimeout(t,e),B={data_type:"json",log:()=>null,timer:!1,url:"localhost",timeout:1400,reconnect:2,reconnection_attempts:1/0,max_idle_time:1/0,lazy:!1,socket:null,adapter:(e,t)=>new WebSocket(e,t),encode:(e,t,{server:n})=>JSON.stringify({[n.id_key]:e,[n.data_key]:t}),decode:e=>JSON.parse(e),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},D=Symbol("Placeholder"),L=e=>{let t=0;for(const n of e)n!==D&&t++;return t},U=(e,t)=>{const n=e.length,s=e.slice(),o=t.length;let r=o,i=0;for(;r&&i<n;i++)s[i]===D&&(s[i]=t[o-r],r--);for(i=n;r;i++,r--)s[i]=t[o-r];return s},F=(e,t,n)=>{const s=e.length-t.length-L(n);if(s<1)return e(...U(t,n));{const o=(...s)=>F(e,U(t,n),s);return o.$args_left=s,o}},J=e=>(...t)=>e.length>L(t)?F(e,[],t):e(...t);function M(e){return function(t,n){const s=t===D,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(e=>function(t){return t===D?e:e(t)})((t=>e(t,n))):e(t,n):n=>e(t,n)}}function G(e){return J(e)}const H=/^(.*?)(8|16|32|64)(Clamped)?Array$/,K=void 0,V=1/0,X=e=>typeof e,Y=e=>null===e,Z=e=>"number"==X(e);const ee=e=>Y(e)||(e=>e===K)(e),te={u:"U",b:"B",n:"N",s:"S",f:"F"},ne=Symbol(),se=e=>{const t=X(e);return"object"===t?Y(e)?"Null":e.constructor.name:te[t[0]]+t.slice(1)},oe=M(((e,t)=>se(t)===e)),re=e=>e.length,ie=M(((e,t)=>e===t)),le=M(((e,t)=>{const n=se(e);if(ie(n,se(t))&&(ie(n,"Object")||ie(n,"Array")||(e=>H.test(e))(n))){if(Y(e)||Y(t))return ie(e,t);if(ie(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(ie(n,t)&&s in e||ie(n,e)&&s in t&&le(e[s],t[s])))return!1;return!0}return ie(e,t)})),ce=M(((e,t)=>(t.push(e),t))),ue=G(((e,t,n)=>n.reduce(e,t))),ae=M(((e,t)=>{const n=(e=>Array.isArray(e))(t);let s,o;n&&(s=0,o=[]);for(let s in t)e(t[s],s)||(n?o.push(+s):delete t[s]);if(n)for(const e of o)t.splice(e-s++,1);return t})),he=J(((e,t,n,s)=>e(s)?t(s):n(s))),fe=(...e)=>(...t)=>{let n,s=!0;for(let o=re(e)-1;o>-1;o--)s?(s=!1,n=e[o](...t)):n=n===D?e[o]():e[o](n);return n},de=M(((e,t)=>t[e])),pe=G(((e,t,n)=>n.slice(e,Z(t)?t:V))),ge=de(0);pe(1,V);const me=M(((e,t)=>t.find(e))),ye=e=>()=>e,we=ye(!0),_e=ye(!1),be=M(((e,t)=>t(...e))),Se=e=>(...t)=>{const n=e(...t),s=function(e){return"function"===X(e)}(n);return!s||s&&n.$args_left<=0?(e=>!e)(n):Se(n)},ke=M(((e,t)=>ue(((t,n)=>me((t=>e(n,t)),t)?t:ce(n,t)),[],t)));ke(le);const Pe=e=>{let t,n=!1;return(...s)=>n?t:(n=!0,t=e(...s))},ve=G(((e,t,n)=>re(t)?ee(n)?e:fe((s=>s in n?ve(e,pe(1,V,t),n[s]):e),ge)(t):n));ve(K),fe(he(le(ne),_e,we),ve(ne));const Ee=G(((e,t,n)=>t(n)&&e(n))),Ne=Se,je=new z,Ae=be([]),We=Ee(oe("Number"),Ne(isNaN));class qe{ws=null;intentionally_closed=!1;reconnect_timeout=null;queue={};onReadyQueue=[];onCloseQueue=[];handlers={open:[],close:[],message:[],error:[],timeout:[]};config={};ping_timer=null;idle_timer=null;get opened(){return 1===this.ws?.readyState}init_flush(){ae(_e,this.queue)}call(e,...t){for(const n of this.handlers[e])n(...t)}log(e,t=null,n=null){const{config:s}=this;null===n?s.timer?s.log(e,null,t):s.log(e,t):s.log(e,n,t)}resetPing(){const{config:{ping:e},ping_timer:t}=this;e&&(ee(t)||clearTimeout(t),this.ping_timer=x(1e3*e.interval,(async()=>{const{ping_timer:t,opened:n}=this;n?(await this.send(e.content),this.resetPing()):clearTimeout(t)})))}resetIdle(){const{config:{max_idle_time:e},idle_timer:t}=this;e!==1/0&&(ee(t)||clearTimeout(t),this.idle_timer=x(1e3*e,(()=>this.opened&&this.close())))}initSocket(e){const{queue:t,config:n}=this;this.ws=e,this.onReadyQueue.forEach((e=>e())),this.onReadyQueue.splice(0);const{id_key:s,data_key:o}=n.server;this.call("open",e);for(const n in t)e.send(t[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),this.resetIdle(),I(e,"close",(async(...e)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach(Ae),this.onCloseQueue.splice(0),this.call("close",...e);let{reconnect:t,reconnection_attempts:s}=n;if(We(t)){const e=async()=>{if(this.intentionally_closed||!s)return;s--,this.log("reconnect"),ee(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();ee(n)||(this.reconnect_timeout=setTimeout(e,1e3*t))};e()}})),I(e,"message",(e=>{try{const t=n.decode(e.data);if(this.call("message",{...e,data:t}),t[s]){const e=this.queue[t[s]];if(e){const n=e.sent_time?Date.now()-e.sent_time:null;this.log("message",t[o],n),e.ff(t[o])}}}catch(t){console.error(t,`WSP: Decode error. Got: ${e.data}`)}this.resetPing(),this.resetIdle()}))}opening=!1;connect(){return new Promise((e=>{if(this.opened||this.opening)return e(null);this.opening=!0;const t=this.config,n=t.socket||t.adapter(t.url,t.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),e(2);const s=Pe((t=>{this.opening=!1,e(t)}));I(n,"error",Pe((e=>{this.ws=null,this.log("error","status 3. Err: "+e.message),this.call("error",e),s(3)}))),n.readyState?(this.initSocket(n),s(null)):I(n,"open",Pe((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((e=>{this.opened?e():this.onReadyQueue.push(e)}))}on(e,t,n=we,s=!1){const o=e=>n(e)&&t(e);return s?I(this.ws,e,o):this.handlers[e].push(o),o}off(e,t,n=!1){if(n)return((e,t,n)=>e.removeEventListener(t,n))(this.ws,e,t);const s=this.handlers[e],o=s.indexOf(t);~o&&s.splice(o,1)}async close(){return new Promise(((e,t)=>{null===this.ws?t("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),e(null)})),this.ws.close(),this.ws=null,this.intentionally_closed=!0)}))}open(){if(!this.opened)return this.intentionally_closed=!1,this.connect()}async send(e,t={}){this.log("send",e);const{config:n,queue:s}=this,o={},{pipes:r,server:{data_key:i}}=n,l=je.zip(2147483637*Math.random()|0);if("object"==typeof t.top){if(t.top[i])throw new Error("Attempting to set data key/token via send() options!");Object.assign(o,t.top)}for(const t of r)e=t(e);const[c,u]=await Promise.all([n.encode(l,e,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);return this.opened&&(this.ws.send(c),this.resetPing(),this.resetIdle()),new Promise(((t,o)=>{this.queue[l]={msg:c,ff(e){clearTimeout(this.timeout),delete s[l],t(e)},data_type:n.data_type,sent_time:n.timer?Date.now():null,timeout:x(n.timeout,(()=>{l in this.queue&&(this.call("timeout",e),o({"Websocket timeout expired":n.timeout,"for the message":e}),delete s[l])}))}}))}constructor(e={}){this.config=(e=>{if(null===T&&!("adapter"in e))throw new Error("\n This platform has no native WebSocket implementation.\n Please use 'ws' package as an adapter.\n See https://github.com/houd1ni/WebsocketPromisify/issues/23\n ");const t=Object.assign({},B,e),n=t.url;if("/"==n[0])try{const e=location.protocol.includes("s:")?"wss":"ws";t.url=`${e}://${location.hostname}:${location.port}${n}`}catch(e){throw new Error("WSP: URL starting with / in non-browser environment!")}return t})(e),this.config.lazy||this.connect()}}export{qe as default};
|
package/package.json
CHANGED
package/src/WSC.ts
CHANGED
|
@@ -20,14 +20,15 @@ type EventHandlers = {
|
|
|
20
20
|
|
|
21
21
|
class WebSocketClient {
|
|
22
22
|
private ws: wsc.Socket|null = null
|
|
23
|
-
private
|
|
23
|
+
private intentionally_closed = false
|
|
24
24
|
private reconnect_timeout: NodeJS.Timeout|null = null
|
|
25
25
|
private queue: Record<string, wsc.Message> = {}
|
|
26
26
|
private onReadyQueue: AnyFunc[] = []
|
|
27
27
|
private onCloseQueue: AnyFunc[] = []
|
|
28
28
|
private handlers: EventHandlers = { open: [], close: [], message: [], error: [], timeout: [] }
|
|
29
29
|
private config = <wsc.Config>{}
|
|
30
|
-
private
|
|
30
|
+
private ping_timer: NodeJS.Timeout|null = null
|
|
31
|
+
private idle_timer: NodeJS.Timeout|null = null
|
|
31
32
|
private get opened() { return this.ws?.readyState===1 } // The only opened state.
|
|
32
33
|
|
|
33
34
|
private init_flush(): void {
|
|
@@ -39,30 +40,34 @@ class WebSocketClient {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
private log(event: string, message: any = null, time: number|null = null): void {
|
|
42
|
-
const config = this
|
|
43
|
-
if(time
|
|
43
|
+
const {config} = this
|
|
44
|
+
if(time === null)
|
|
45
|
+
if(config.timer) config.log(event, null, message)
|
|
46
|
+
else config.log(event, message)
|
|
47
|
+
else
|
|
44
48
|
config.log(event, time, message)
|
|
45
|
-
} else {
|
|
46
|
-
if(config.timer) {
|
|
47
|
-
config.log(event, null, message)
|
|
48
|
-
} else {
|
|
49
|
-
config.log(event, message)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
private resetPing() {
|
|
55
|
-
const {config} = this
|
|
56
|
-
if(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.
|
|
60
|
-
|
|
61
|
-
if(
|
|
62
|
-
await this.send(
|
|
52
|
+
const {config: {ping}, ping_timer} = this
|
|
53
|
+
if(ping) {
|
|
54
|
+
if(!isNil(ping_timer))
|
|
55
|
+
clearTimeout(ping_timer as NodeJS.Timeout)
|
|
56
|
+
this.ping_timer = sett(ping.interval*1e3, async () => {
|
|
57
|
+
const {ping_timer, opened} = this
|
|
58
|
+
if(opened) {
|
|
59
|
+
await this.send(ping.content)
|
|
63
60
|
this.resetPing()
|
|
64
|
-
}
|
|
65
|
-
}
|
|
61
|
+
} else clearTimeout(ping_timer!)
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private resetIdle() {
|
|
67
|
+
const {config: {max_idle_time: time}, idle_timer} = this
|
|
68
|
+
if(time!==Infinity) {
|
|
69
|
+
if(!isNil(idle_timer)) clearTimeout(idle_timer!)
|
|
70
|
+
this.idle_timer = sett(time*1e3, () => this.opened && this.close())
|
|
66
71
|
}
|
|
67
72
|
}
|
|
68
73
|
|
|
@@ -79,7 +84,7 @@ class WebSocketClient {
|
|
|
79
84
|
clearInterval(this.reconnect_timeout)
|
|
80
85
|
this.reconnect_timeout = null
|
|
81
86
|
}
|
|
82
|
-
this.resetPing()
|
|
87
|
+
this.resetPing(); this.resetIdle()
|
|
83
88
|
add_event(ws, 'close', async (...e) => {
|
|
84
89
|
this.log('close')
|
|
85
90
|
this.ws = null
|
|
@@ -90,7 +95,7 @@ class WebSocketClient {
|
|
|
90
95
|
let {reconnect, reconnection_attempts} = config
|
|
91
96
|
if(isNumber(reconnect)) {
|
|
92
97
|
const reconnectFunc = async () => {
|
|
93
|
-
if(this.
|
|
98
|
+
if(this.intentionally_closed || !reconnection_attempts) return;
|
|
94
99
|
reconnection_attempts--
|
|
95
100
|
this.log('reconnect')
|
|
96
101
|
if(!isNil(this.ws)) {
|
|
@@ -124,6 +129,7 @@ class WebSocketClient {
|
|
|
124
129
|
console.error(err, `WSP: Decode error. Got: ${e.data}`)
|
|
125
130
|
}
|
|
126
131
|
this.resetPing()
|
|
132
|
+
this.resetIdle()
|
|
127
133
|
})
|
|
128
134
|
}
|
|
129
135
|
|
|
@@ -202,14 +208,14 @@ class WebSocketClient {
|
|
|
202
208
|
})
|
|
203
209
|
this.ws.close()
|
|
204
210
|
this.ws = null
|
|
205
|
-
this.
|
|
211
|
+
this.intentionally_closed = true
|
|
206
212
|
}
|
|
207
213
|
})
|
|
208
214
|
}
|
|
209
215
|
|
|
210
216
|
public open() {
|
|
211
217
|
if(!this.opened) {
|
|
212
|
-
this.
|
|
218
|
+
this.intentionally_closed = false
|
|
213
219
|
return this.connect()
|
|
214
220
|
}
|
|
215
221
|
}
|
|
@@ -223,7 +229,7 @@ class WebSocketClient {
|
|
|
223
229
|
opts = <wsc.SendOptions>{}
|
|
224
230
|
): Promise<ResponseDataType> {
|
|
225
231
|
this.log('send', message_data)
|
|
226
|
-
const {config,
|
|
232
|
+
const {config, queue} = this
|
|
227
233
|
const message = {}
|
|
228
234
|
const {pipes, server: {data_key}} = config
|
|
229
235
|
|
|
@@ -235,9 +241,6 @@ class WebSocketClient {
|
|
|
235
241
|
Object.assign(message, opts.top)
|
|
236
242
|
}
|
|
237
243
|
for(const pipe of pipes) message_data = pipe(message_data)
|
|
238
|
-
|
|
239
|
-
if(forcibly_closed)
|
|
240
|
-
throw new Error('Attempting to send via closed WebSocket connection!')
|
|
241
244
|
const [msg, err] = await Promise.all([
|
|
242
245
|
config.encode(message_id, message_data, config),
|
|
243
246
|
this.connect()
|
|
@@ -246,6 +249,7 @@ class WebSocketClient {
|
|
|
246
249
|
if(this.opened) {
|
|
247
250
|
this.ws!.send(msg)
|
|
248
251
|
this.resetPing()
|
|
252
|
+
this.resetIdle()
|
|
249
253
|
}
|
|
250
254
|
|
|
251
255
|
return new Promise((ff, rj) => {
|
package/src/config.ts
CHANGED
|
@@ -11,6 +11,7 @@ const default_config = <wsc.Config>{
|
|
|
11
11
|
timeout: 1400,
|
|
12
12
|
reconnect: 2, // Reconnect timeout in seconds or null.
|
|
13
13
|
reconnection_attempts: Infinity,
|
|
14
|
+
max_idle_time: Infinity,
|
|
14
15
|
lazy: false,
|
|
15
16
|
socket: null,
|
|
16
17
|
adapter: ((host, protocols) => new WebSocket(host, protocols)),
|