wspromisify 2.9.4 → 2.10.1
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 +7 -4
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.ts +2 -2
- package/dist/bundle.mjs +1 -1
- package/package.json +10 -10
- package/rollup.config.js +3 -5
- package/src/WSC.ts +32 -38
- package/src/types.ts +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ const responseData = await ws.send({catSaid: 'Meow!'})
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
// If you detected some bug, want some stuff to be added, feel free to open an issue!
|
|
14
|
-
Large data support (chunking), plugins
|
|
14
|
+
Large data support (chunking), plugins and different server-side implementations are coming.
|
|
15
15
|
To see a Node.js server-side part example, please, take a look on test/mock in github repo.
|
|
16
16
|
|
|
17
17
|
|
|
@@ -21,6 +21,7 @@ Features (almost all are tunable via constructor config below.)
|
|
|
21
21
|
- ES-module and commonjs built-in.
|
|
22
22
|
- Types (d.ts) included.
|
|
23
23
|
- Automatically reconnects.
|
|
24
|
+
- Streams are supported. For example, you can stream your AI response.
|
|
24
25
|
- Supports existent native WebSocket or ws-like implementation (ws npm package) via `socket` property.
|
|
25
26
|
- And provide your own socket instance via socket config prop.
|
|
26
27
|
- Any id and data keys to negotiate with your back-end.
|
|
@@ -71,7 +72,7 @@ Default constructor config is
|
|
|
71
72
|
socket: null,
|
|
72
73
|
// You can set your own middleware here.
|
|
73
74
|
adapter: ((host, protocols) => new WebSocket(host, protocols)),
|
|
74
|
-
// You can replace original serialisation to your own or even binary stuff.
|
|
75
|
+
// You can replace original serialisation to your own or even binary stuff. Eg MessagePack or CBOR.
|
|
75
76
|
encode: (message_id, message_data, config) => data,
|
|
76
77
|
// You can replace original deserialisation to your own or even
|
|
77
78
|
// making the message object from binary data.
|
|
@@ -106,14 +107,16 @@ Methods:
|
|
|
106
107
|
ready()
|
|
107
108
|
// sends any type of message and returns a Promise.
|
|
108
109
|
send(message),
|
|
110
|
+
// Streams as async generator, resolving in chunks.
|
|
111
|
+
// The server must send the same id for chunks then add done: true in the last one.
|
|
112
|
+
*stream(message),
|
|
109
113
|
// .addEventListener with optional predicate that works after reconnections.
|
|
110
114
|
on(event_name, handler, predicate = (WebSocketEvent) => true),
|
|
111
115
|
// Closes the connection and free up memory. Returns Promise that it has been done.
|
|
112
116
|
close()
|
|
113
|
-
|
|
114
117
|
```
|
|
115
118
|
|
|
116
|
-
Example:
|
|
119
|
+
Example (more in `tests` dir in the repo):
|
|
117
120
|
```javascript
|
|
118
121
|
|
|
119
122
|
import WSP from 'wspromisify' // or const WSP = require('wspromisify') in Node.
|
package/dist/bundle.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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(),i=n.length;let r=i,l=0;for(;r&&l<s;l++)o[l]===e&&(o[l]=n[i-r],r--);for(l=s;r;l++,r--)o[l]=n[i-r];return o},s=(e,o,i)=>{const r=e.length-o.length-t(i);if(r<1)return e(...n(o,i));{const t=(...t)=>s(e,n(o,i),t);return t.$args_left=r,t}},o=e=>(...n)=>e.length>t(n)?s(e,[],n):e(...n);function i(t){return function(n,s){const o=n===e,i=arguments.length;if(1===i&&o)throw new Error("Senseless placeholder usage.");return i>1?o?(t=>function(n){return n===e?t:t(n)})((e=>t(e,s))):t(n,s):e=>t(n,e)}}function r(e){return o(e)}const l=void 0,c=1/0,a=e=>typeof e,u=e=>null===e,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=e=>{const t=a(e);return"object"===t?u(e)?"Null":e.constructor.name:h[t[0]]+t.slice(1)},g=e=>e.length,p=i(((e,t)=>e===t)),m=i(((e,t)=>{const n=d(e);if(p(n,d(t))&&(p(n,"Object")||p(n,"Array"))){if(u(e)||u(t))return p(e,t);if(p(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(p(n,t)&&s in e||p(n,e)&&s in t&&m(e[s],t[s])))return!1;return!0}return p(e,t)})),y=i(((e,t)=>(t.push(e),t))),w=r(((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 i=g(t)-1;i>-1;i--)o?(o=!1,s=t[i](...n)):s=s===e?t[i]():t[i](s);return s},S=i(((e,t)=>t[e])),k=r(((e,t,n)=>n.slice(e,(e=>"number"==a(e))(t)?t:c))),P=S(0);k(1,c);const v=i(((e,t)=>t.find(e))),E=e=>()=>e,N=i(((e,t)=>t.split(e))),q=E(!0),A=E(!1),W=i(((e,t)=>w(((t,n)=>v((t=>e(n,t)),t)?t:y(n,t)),[],t)))(m),$=r(((e,t,n)=>g(t)?(e=>u(e)||(e=>e===l)(e))(n)?e:b((s=>s in n?$(e,k(1,c,t),n[s]):e),P)(t):n));$(l),b(_(m(f),A,q),$(f));const j=i(((e,t)=>t.map(e))),{floor:z}=Math,C="0123456789abcdefghijklmnopqrstuvwxyz",Q=b((e=>Object.fromEntries(e)),j(((e,t)=>[e,t])),N(""));class O{abc;abclen;c2pos;standard;setABC(e){if(!b(m(g(t=e)),g,W,N(""))(t))throw new Error("Not all chars are unique!");var t;this.abc=e,this.abclen=e.length,this.standard=C.startsWith(e),this.c2pos=Q(e)}zip(e){const{abc:t,abclen:n}=this;let s="";for(;e>0;)s=t[e%n]+s,e=z(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 i=0;for(let t=0;t<o;t++)i+=s[e[t]]*n**(o-t-1);return i}constructor(e){this.setABC(e||C+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new O;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),x=(e,t,n)=>e.addEventListener(t,n),B=(e,t)=>setTimeout(t,e),I={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:{}}},M=Symbol("Placeholder"),D=e=>{let t=0;for(const n of e)n!==M&&t++;return t},L=(e,t)=>{const n=e.length,s=e.slice(),o=t.length;let i=o,r=0;for(;i&&r<n;r++)s[r]===M&&(s[r]=t[o-i],i--);for(r=n;i;r++,i--)s[r]=t[o-i];return s},U=(e,t,n)=>{const s=e.length-t.length-D(n);if(s<1)return e(...L(t,n));{const o=(...s)=>U(e,L(t,n),s);return o.$args_left=s,o}},F=e=>(...t)=>e.length>D(t)?U(e,[],t):e(...t);function J(e){return function(t,n){const s=t===M,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(e=>function(t){return t===M?e:e(t)})((t=>e(t,n))):e(t,n):n=>e(t,n)}}function G(e){return F(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=J(((e,t)=>se(t)===e)),ie=e=>e.length,re=J(((e,t)=>e===t)),le=J(((e,t)=>{const n=se(e);if(re(n,se(t))&&(re(n,"Object")||re(n,"Array")||(e=>H.test(e))(n))){if(Y(e)||Y(t))return re(e,t);if(re(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(re(n,t)&&s in e||re(n,e)&&s in t&&le(e[s],t[s])))return!1;return!0}return re(e,t)})),ce=J(((e,t)=>(t.push(e),t))),ae=G(((e,t,n)=>n.reduce(e,t))),ue=J(((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=F(((e,t,n,s)=>e(s)?t(s):n(s))),fe=(...e)=>(...t)=>{let n,s=!0;for(let o=ie(e)-1;o>-1;o--)s?(s=!1,n=e[o](...t)):n=n===M?e[o]():e[o](n);return n},de=J(((e,t)=>t[e])),ge=G(((e,t,n)=>n.slice(e,Z(t)?t:V))),pe=de(0);ge(1,V);const me=J(((e,t)=>t.find(e))),ye=e=>()=>e,we=J(((e,t)=>(e(t),t))),_e=ye(!0),be=ye(!1),Se=J(((e,t)=>t(...e))),ke=e=>(...t)=>{const n=e(...t),s=function(e){return"function"===X(e)}(n);return!s||s&&n.$args_left<=0?(e=>!e)(n):ke(n)},Pe=J(((e,t)=>ae(((t,n)=>me((t=>e(n,t)),t)?t:ce(n,t)),[],t)));Pe(le);const ve=e=>{let t,n=!1;return function(...s){return n?t:(n=!0,t=e(...s))}},Ee=G(((e,t,n)=>ie(t)?ee(n)?e:fe((s=>s in n?Ee(e,ge(1,V,t),n[s]):e),pe)(t):n));Ee(K),fe(he(le(ne),be,_e),Ee(ne));const Ne=G(((e,t,n)=>t(n)&&e(n))),qe=ke,{random:Ae}=Math,We=new O,$e=Se([]),je=Ne(oe("Number"),qe(isNaN)),ze={_is_ping:!0},Ce=e=>e&&clearTimeout(e),Qe=e=>{const t=We.zip(2147483637*Ae()|0);return t in e?Qe(e):t};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(){ue(be,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=B(1e3*e.interval,(async()=>{const{ping_timer:t,opened:n}=this;n?(await this.send(e.content,ze),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=B(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(),x(e,"close",(async(...e)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach($e),this.onCloseQueue.splice(0),this.call("close",...e);let{reconnect:t,reconnection_attempts:s}=n;if(je(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()}})),x(e,"message",(e=>{try{const t=n.decode(e.data);if(this.call("message",{...e,data:t}),s in t){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()}))}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=ve((t=>{this.opening=!1,e(t)}));x(n,"error",ve((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)):x(n,"open",ve((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((e=>{this.config.lazy||this.opened?e():this.onReadyQueue.push(e)}))}on(e,t,n=_e,s=!1){const o=e=>n(e)&&t(e);return s?x(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 prepareMessage(e,t={}){this.log(t._is_ping?"ping":"send",e);const{config:n,queue:s}=this,{pipes:o,server:{data_key:i}}=n,{top:r,_is_ping:l}=t,c=Qe(s);if("object"==typeof r&&r[i])throw new Error(`Attempting to set data key/token via ${t._is_ping?"ping":"send"}() options!`);for(const t of o)e=t(e);const[a,u]=await Promise.all([n.encode(c,e,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);this.opened&&(this.ws.send(a),this.resetPing(),l||this.resetIdle());const h=we((()=>delete this.queue[c]));return{message_id:c,msg:a,timeout:t=>B(n.timeout,(()=>{c in s&&(this.call("timeout",e),t({"Websocket timeout expired":n.timeout,"for the message":e}),h())})),cleanup:h}}async send(e,t={}){const{message_id:n,msg:s,timeout:o,cleanup:i}=await this.prepareMessage(e,t),{queue:r,config:l}=this;return new Promise(((e,t)=>{const i=o(t);r[n]={msg:s,data_type:l.data_type,sent_time:l.timer?Date.now():null,ff(t){Ce(i),e(t)}}})).finally(i)}async*stream(e,t={}){const{message_id:n,msg:s,timeout:o,cleanup:i}=await this.prepareMessage(e,t),{queue:r,config:l}=this;let c,a=!1,u=null;for(r[n]={msg:s,ff:e=>{c(e),e?.done&&(i(),a=!0)},data_type:l.data_type,sent_time:l.timer?Date.now():null};!a;)yield await new Promise(((e,t)=>{u=o(t),c=e})).catch((e=>i(e))).finally((()=>{Ce(u),u=null}))}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({},I,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()}};
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const t=Symbol("Placeholder"),e=e=>{let n=0;for(const s of e)s!==t&&n++;return n},n=(e,n)=>{const s=e.length,i=e.slice(),o=n.length;let r=o,l=0;for(;r&&l<s;l++)i[l]===t&&(i[l]=n[o-r],r--);for(l=s;r;l++,r--)i[l]=n[o-r];return i},s=(t,i,o)=>{const r=t.length-i.length-e(o);if(r<1)return t(...n(i,o));{const e=(...e)=>s(t,n(i,o),e);return e.$args_left=r,e}},i=t=>(...n)=>t.length>e(n)?s(t,[],n):t(...n);function o(e){return function(n,...s){return s.length>0?n===t?(e=>function(n){return n===t?e:e(n)})((t=>e(t,s[0]))):e(n,s[0]):t=>e(n,t)}}function r(t){return i(t)}const l=t=>t.length,c=/^(.*?)(8|16|32|64)(Clamped)?Array$/,u=void 0,a=1/0,h=t=>typeof t,d=t=>null===t,f=t=>"number"==h(t);const p=t=>d(t)||(t=>t===u)(t),g={u:"U",b:"B",n:"N",s:"S",f:"F"},m=Symbol(),y=t=>{const e=h(t);return"object"===e?d(t)?"Null":t.constructor.name:g[e[0]]+e.slice(1)},_=o(((t,e)=>y(e)===t)),w=o(((t,e)=>t===e)),b=o(((t,e)=>{const n=y(t);if(w(n,y(e))&&(w(n,"Object")||w(n,"Array")||(t=>c.test(t))(n))){if(d(t)||d(e))return w(t,e);if(w(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(w(n,e)&&s in t||w(n,t)&&s in e&&b(t[s],e[s])))return!1;return!0}return w(t,e)})),k=o(((t,e)=>(e.push(t),e))),S=r(((t,e,n)=>n.reduce(t,e))),P=o(((t,e)=>{const n=(t=>Array.isArray(t))(e);let s,i;n&&(s=0,i=[]);for(let s in e)t(e[s],s)||(n?i.push(+s):delete e[s]);if(n)for(const t of i)e.splice(t-s++,1);return e})),v=i(((t,e,n,s)=>t(s)?e(s):n(s))),E=(...e)=>(...n)=>{let s,i=!0;for(let o=l(e)-1;o>-1;o--)i?(i=!1,s=e[o](...n)):s=s===t?e[o]():e[o](s);return s},A=o(((t,e)=>e[t])),C=r(((t,e,n)=>n.slice(t,f(e)?e:a))),j=A(0);C(1,a);const N=o(((t,e)=>e.find(t))),W=t=>()=>t,$=o(((t,e)=>(t(e),e))),q=W(!0),O=W(!1),T=o(((t,e)=>e(...t))),x=t=>(...e)=>{const n=t(...e),s=function(t){return"function"===h(t)}(n);return s&&n.$args_left?x(n):(t=>!t)(n)},z=o(((t,e)=>S(((e,n)=>N((e=>t(n,e)),e)?e:k(n,e)),[],e)));z(b);const Q=t=>{let e,n=!1;return function(...s){return n?e:(n=!0,e=t(...s))}},R=(t,e,n)=>l(e)?p(n)?t:E((s=>s in n?R(t,C(1,a,e),n[s]):t),j)(e):n,B=r(R);B(u),E(v(b(m),O,q),B(m));const M=r(((t,e,n)=>e(n)&&t(n))),I=x,D=Symbol("Placeholder"),L=t=>{let e=0;for(const n of t)n!==D&&e++;return e},U=(t,e)=>{const n=t.length,s=t.slice(),i=e.length;let o=i,r=0;for(;o&&r<n;r++)s[r]===D&&(s[r]=e[i-o],o--);for(r=n;o;r++,o--)s[r]=e[i-o];return s},F=(t,e,n)=>{const s=t.length-e.length-L(n);if(s<1)return t(...U(e,n));{const i=(...s)=>F(t,U(e,n),s);return i.$args_left=s,i}},J=t=>(...e)=>t.length>L(e)?F(t,[],e):t(...e);function G(t){return function(e,...n){return n.length>0?e===D?(t=>function(e){return e===D?t:t(e)})((e=>t(e,n[0]))):t(e,n[0]):n=>t(e,n)}}function H(t){return J(t)}const K=t=>t.length,V=/^(.*?)(8|16|32|64)(Clamped)?Array$/,X=void 0,Y=1/0,Z=t=>typeof t,tt=t=>null===t,et={u:"U",b:"B",n:"N",s:"S",f:"F"},nt=Symbol(),st=t=>{const e=Z(t);return"object"===e?tt(t)?"Null":t.constructor.name:et[e[0]]+e.slice(1)},it=G(((t,e)=>st(e)===t)),ot=G(((t,e)=>t===e)),rt=G(((t,e)=>{const n=st(t);if(ot(n,st(e))&&(ot(n,"Object")||ot(n,"Array")||(s=n,V.test(s)))){if(tt(t)||tt(e))return ot(t,e);if(ot(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(ot(n,e)&&s in t||ot(n,t)&&s in e&&rt(t[s],e[s])))return!1;return!0}var s;return ot(t,e)})),lt=G(((t,e)=>(e.push(t),e))),ct=H(((t,e,n)=>n.reduce(t,e))),ut=J(((t,e,n,s)=>t(s)?e(s):n(s))),at=H(((t,e,n)=>ut(t,e,yt,n))),ht=(...t)=>(...e)=>{let n,s=!0;for(let i=K(t)-1;i>-1;i--)s?(s=!1,n=t[i](...e)):n=n===D?t[i]():t[i](n);return n},dt=G(((t,e)=>e[t])),ft=H(((t,e,n)=>n.slice(t,(t=>"number"==Z(t))(e)?e:Y))),pt=dt(0);ft(1,Y);const gt=G(((t,e)=>e.find(t))),mt=t=>()=>t,yt=t=>t,_t=G(((t,e)=>e.split(t))),wt=mt(!0),bt=mt(!1),kt=G(((t,e)=>ct(((e,n)=>gt((e=>t(n,e)),e)?e:lt(n,e)),[],e)))(rt),St=(t,e,n)=>K(e)?(t=>tt(t)||(t=>t===X)(t))(n)?t:ht((s=>s in n?St(t,ft(1,Y,e),n[s]):t),pt)(e):n,Pt=H(St);Pt(X),ht(ut(rt(nt),bt,wt),Pt(nt));const vt=G(((t,e)=>e.map(t))),{floor:Et}=Math,At="0123456789abcdefghijklmnopqrstuvwxyz",Ct=it("String"),jt=at(Ct,_t("")),Nt=ht((t=>Object.fromEntries(t)),vt(((t,e)=>[t,e])),jt);class Wt{is_str;delim;abc;abclen;c2pos;standard;setABC(t,e=""){if(this.is_str=Ct(t),this.delim=e,!ht(ot(K(n=t)),K,kt,jt)(n))throw new Error("Not all chars are unique!");var n;this.abc=t,this.abclen=K(t),this.standard=!!this.is_str&&At.startsWith(t),this.c2pos=Nt(t)}zip(t){const{abc:e,abclen:n,delim:s}=this;let i="",o=!0;for(;t>0;)i=e[t%n]+(o?"":s)+i,t=Et(t/n),o=!1;return i||"0"}unzip(t){const{standard:e,abclen:n,c2pos:s,delim:i,is_str:o}=this;if("0"===t)return 0;if(e)return parseInt(t,n);const r=o?t:t.split(i),l=K(r);let c=0;for(let t=0;t<l;t++)c+=s[r[t]]*n**(l-t-1);return c}constructor(t,e){e?this.setABC(t,e):this.setABC(t||At+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const $t=new Wt;$t.setABC.bind($t),$t.zip.bind($t),$t.unzip.bind($t);const qt=(()=>{try{return WebSocket||null}catch{return null}})(),Ot=(t,e,n)=>t.addEventListener(e,n),Tt=(t,e)=>setTimeout(e,t),xt={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:(t,e)=>new WebSocket(t,e),encode:(t,e,{server:n})=>JSON.stringify({[n.id_key]:t,[n.data_key]:e}),decode:t=>JSON.parse(t),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},{random:zt}=Math,Qt=new Wt,Rt=T([]),Bt=M(_("Number"),I(isNaN)),Mt={_is_ping:!0},It=t=>t&&clearTimeout(t),Dt=t=>{const e=Qt.zip(2147483637*zt()|0);return e in t?Dt(t):e};class Lt{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(){P(O,this.queue)}call(t,...e){for(const n of this.handlers[t])n(...e)}log(t,e=null,n=null){const{config:s}=this;setTimeout((()=>{null===n?s.timer?s.log(t,null,e):s.log(t,e):s.log(t,n,e)}))}resetPing(){const{config:{ping:t},ping_timer:e}=this;t&&(p(e)||clearTimeout(e),this.ping_timer=Tt(1e3*t.interval,(async()=>{const{ping_timer:e,opened:n}=this;n?(await this.send(t.content,Mt),this.resetPing()):clearTimeout(e)})))}resetIdle(){const{config:{max_idle_time:t},idle_timer:e}=this;t!==1/0&&(p(e)||clearTimeout(e),this.idle_timer=Tt(1e3*t,(()=>this.opened&&this.close())))}initSocket(t){const{queue:e,config:n}=this;this.ws=t,this.onReadyQueue.forEach((t=>t())),this.onReadyQueue.splice(0);const{id_key:s,data_key:i}=n.server;this.call("open",t);for(const n in e)t.send(e[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),this.resetIdle(),Ot(t,"close",(async(...t)=>{this.ws=null,this.onCloseQueue.forEach(Rt),this.onCloseQueue.splice(0),this.call("close",...t);let{reconnect:e,reconnection_attempts:s}=n;if(Bt(e)){const t=async()=>{if(this.intentionally_closed||!s)return;s--,this.log("reconnect"),p(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();p(n)||(this.reconnect_timeout=setTimeout(t,1e3*e))};t()}})),Ot(t,"message",(t=>{try{const e=n.decode(t.data);this.call("message",{...t,data:e});let o=!1;if(_("Object",e)&&s in e){const t=this.queue[e[s]];if(t){const n=t.sent_time?Date.now()-t.sent_time:null;this.log("message",e[i],n),t.ff(e[i]),o=!0}}o||this.log("message-ext",e)}catch(e){console.error(e,`WSP: Decode error. Got: ${t.data}`)}this.resetPing()}))}opening=!1;connect(){return new Promise((t=>{if(this.opened||this.opening)return t(null);this.opening=!0;const e=this.config,n=e.socket||e.adapter(e.url,e.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),t(2);const s=Q((e=>{this.opening=!1,t(e)}));Ot(n,"error",Q((t=>{this.ws=null,this.log("error","status 3. Err: "+t.message),this.call("error",t),s(3)}))),n.readyState?(this.initSocket(n),s(null)):Ot(n,"open",Q((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((t=>{this.config.lazy||this.opened?t():this.onReadyQueue.push(t)}))}on(t,e,n=q,s=!1){const i=t=>n(t)&&e(t);return s?Ot(this.ws,t,i):this.handlers[t].push(i),i}off(t,e,n=!1){if(n)return((t,e,n)=>t.removeEventListener(e,n))(this.ws,t,e);const s=this.handlers[t],i=s.indexOf(e);~i&&s.splice(i,1)}async close(){return new Promise(((t,e)=>{null===this.ws?e("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),t(null)})),this.ws.close(),this.ws=null,this.intentionally_closed=!0)}))}open(){if(!this.opened)return this.intentionally_closed=!1,this.connect()}async prepareMessage(t,e={}){this.log(e._is_ping?"ping":"send",t);const{config:n,queue:s}=this,{pipes:i,server:{data_key:o}}=n,{top:r,_is_ping:l}=e,c=Dt(s);if("object"==typeof r&&r[o])throw new Error(`Attempting to set data key/token via ${e._is_ping?"ping":"send"}() options!`);for(const e of i)t=e(t);const[u,a]=await Promise.all([n.encode(c,t,n),this.connect()]);if(a)throw new Error("ERR while opening connection #"+a);const h=$((()=>delete this.queue[c]));return this.opened&&(Tt(0,(()=>this.ws.send(u))),this.resetPing(),l||this.resetIdle()),{id:c,msg:u,timeout:e=>Tt(n.timeout,(()=>{c in s&&(this.call("timeout",t),e({"Websocket timeout expired":n.timeout,"for the message":t}),h())})),cleanup:h}}async send(t,e={}){const{id:n,msg:s,timeout:i,cleanup:o}=await this.prepareMessage(t,e),{queue:r,config:l}=this;return new Promise(((t,e)=>{const o=i(e);r[n]={msg:s,data_type:l.data_type,sent_time:l.timer?Date.now():null,ff(e){It(o),t(e)}}})).finally(o)}async*stream(t,e={}){const{id:n,msg:s,timeout:i,cleanup:o}=await this.prepareMessage(t,e),{queue:r,config:l}=this;let c,u=!1,a=null;for(r[n]={msg:s,ff:t=>{t?.done&&(delete t.done,u=!0,setTimeout(o)),c(t)},data_type:l.data_type,sent_time:l.timer?Date.now():null};!u;)yield await new Promise(((t,e)=>{a=i(e),c=t})).catch((t=>o(t))).finally((()=>{It(a),a=null}))}constructor(t={}){this.config=(t=>{if(null===qt&&!("adapter"in t))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 e=Object.assign({},xt,t),n=e.url;if("/"==n[0])try{const t=location.protocol.includes("s:")?"wss":"ws";e.url=`${t}://${location.hostname}:${location.port}${n}`}catch(t){throw new Error("WSP: URL starting with / in non-browser environment!")}return e})(t),this.config.lazy||this.connect()}}exports.WebSocketClient=Lt,exports.default=Lt;
|
package/dist/bundle.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ declare namespace wsc {
|
|
|
4
4
|
interface DataObject {
|
|
5
5
|
[key: string]: any;
|
|
6
6
|
}
|
|
7
|
-
type WSEvent = "open" | "message" | "close" | "error" | "timeout";
|
|
7
|
+
type WSEvent = "open" | "message" | "message-ext" | "close" | "error" | "timeout" | "reconnect" | "send" | "ping";
|
|
8
8
|
/** Minimal socket-like interface. */
|
|
9
9
|
interface Socket {
|
|
10
10
|
readyState: number;
|
|
@@ -58,7 +58,7 @@ declare namespace wsc {
|
|
|
58
58
|
sent_time: number | null;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
declare class WebSocketClient {
|
|
61
|
+
export declare class WebSocketClient {
|
|
62
62
|
private ws;
|
|
63
63
|
private intentionally_closed;
|
|
64
64
|
private reconnect_timeout;
|
package/dist/bundle.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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(),i=n.length;let r=i,l=0;for(;r&&l<s;l++)o[l]===e&&(o[l]=n[i-r],r--);for(l=s;r;l++,r--)o[l]=n[i-r];return o},s=(e,o,i)=>{const r=e.length-o.length-t(i);if(r<1)return e(...n(o,i));{const t=(...t)=>s(e,n(o,i),t);return t.$args_left=r,t}},o=e=>(...n)=>e.length>t(n)?s(e,[],n):e(...n);function i(t){return function(n,s){const o=n===e,i=arguments.length;if(1===i&&o)throw new Error("Senseless placeholder usage.");return i>1?o?(t=>function(n){return n===e?t:t(n)})((e=>t(e,s))):t(n,s):e=>t(n,e)}}function r(e){return o(e)}const l=void 0,c=1/0,a=e=>typeof e,u=e=>null===e,h={u:"U",b:"B",n:"N",s:"S",f:"F"},f=Symbol(),d=e=>{const t=a(e);return"object"===t?u(e)?"Null":e.constructor.name:h[t[0]]+t.slice(1)},g=e=>e.length,p=i(((e,t)=>e===t)),m=i(((e,t)=>{const n=d(e);if(p(n,d(t))&&(p(n,"Object")||p(n,"Array"))){if(u(e)||u(t))return p(e,t);if(p(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(p(n,t)&&s in e||p(n,e)&&s in t&&m(e[s],t[s])))return!1;return!0}return p(e,t)})),y=i(((e,t)=>(t.push(e),t))),w=r(((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 i=g(t)-1;i>-1;i--)o?(o=!1,s=t[i](...n)):s=s===e?t[i]():t[i](s);return s},S=i(((e,t)=>t[e])),k=r(((e,t,n)=>n.slice(e,(e=>"number"==a(e))(t)?t:c))),P=S(0);k(1,c);const v=i(((e,t)=>t.find(e))),E=e=>()=>e,N=i(((e,t)=>t.split(e))),q=E(!0),A=E(!1),W=i(((e,t)=>w(((t,n)=>v((t=>e(n,t)),t)?t:y(n,t)),[],t)))(m),$=r(((e,t,n)=>g(t)?(e=>u(e)||(e=>e===l)(e))(n)?e:b((s=>s in n?$(e,k(1,c,t),n[s]):e),P)(t):n));$(l),b(_(m(f),A,q),$(f));const j=i(((e,t)=>t.map(e))),{floor:z}=Math,C="0123456789abcdefghijklmnopqrstuvwxyz",Q=b((e=>Object.fromEntries(e)),j(((e,t)=>[e,t])),N(""));class O{abc;abclen;c2pos;standard;setABC(e){if(!b(m(g(t=e)),g,W,N(""))(t))throw new Error("Not all chars are unique!");var t;this.abc=e,this.abclen=e.length,this.standard=C.startsWith(e),this.c2pos=Q(e)}zip(e){const{abc:t,abclen:n}=this;let s="";for(;e>0;)s=t[e%n]+s,e=z(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 i=0;for(let t=0;t<o;t++)i+=s[e[t]]*n**(o-t-1);return i}constructor(e){this.setABC(e||C+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const R=new O;R.setABC.bind(R),R.zip.bind(R),R.unzip.bind(R);const T=(()=>{try{return WebSocket||null}catch{return null}})(),x=(e,t,n)=>e.addEventListener(t,n),B=(e,t)=>setTimeout(t,e),I={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:{}}},M=Symbol("Placeholder"),D=e=>{let t=0;for(const n of e)n!==M&&t++;return t},L=(e,t)=>{const n=e.length,s=e.slice(),o=t.length;let i=o,r=0;for(;i&&r<n;r++)s[r]===M&&(s[r]=t[o-i],i--);for(r=n;i;r++,i--)s[r]=t[o-i];return s},U=(e,t,n)=>{const s=e.length-t.length-D(n);if(s<1)return e(...L(t,n));{const o=(...s)=>U(e,L(t,n),s);return o.$args_left=s,o}},F=e=>(...t)=>e.length>D(t)?U(e,[],t):e(...t);function J(e){return function(t,n){const s=t===M,o=arguments.length;if(1===o&&s)throw new Error("Senseless placeholder usage.");return o>1?s?(e=>function(t){return t===M?e:e(t)})((t=>e(t,n))):e(t,n):n=>e(t,n)}}function G(e){return F(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=J(((e,t)=>se(t)===e)),ie=e=>e.length,re=J(((e,t)=>e===t)),le=J(((e,t)=>{const n=se(e);if(re(n,se(t))&&(re(n,"Object")||re(n,"Array")||(e=>H.test(e))(n))){if(Y(e)||Y(t))return re(e,t);if(re(e,t))return!0;for(const n of[e,t])for(const s in n)if(!(re(n,t)&&s in e||re(n,e)&&s in t&&le(e[s],t[s])))return!1;return!0}return re(e,t)})),ce=J(((e,t)=>(t.push(e),t))),ae=G(((e,t,n)=>n.reduce(e,t))),ue=J(((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=F(((e,t,n,s)=>e(s)?t(s):n(s))),fe=(...e)=>(...t)=>{let n,s=!0;for(let o=ie(e)-1;o>-1;o--)s?(s=!1,n=e[o](...t)):n=n===M?e[o]():e[o](n);return n},de=J(((e,t)=>t[e])),ge=G(((e,t,n)=>n.slice(e,Z(t)?t:V))),pe=de(0);ge(1,V);const me=J(((e,t)=>t.find(e))),ye=e=>()=>e,we=J(((e,t)=>(e(t),t))),_e=ye(!0),be=ye(!1),Se=J(((e,t)=>t(...e))),ke=e=>(...t)=>{const n=e(...t),s=function(e){return"function"===X(e)}(n);return!s||s&&n.$args_left<=0?(e=>!e)(n):ke(n)},Pe=J(((e,t)=>ae(((t,n)=>me((t=>e(n,t)),t)?t:ce(n,t)),[],t)));Pe(le);const ve=e=>{let t,n=!1;return function(...s){return n?t:(n=!0,t=e(...s))}},Ee=G(((e,t,n)=>ie(t)?ee(n)?e:fe((s=>s in n?Ee(e,ge(1,V,t),n[s]):e),pe)(t):n));Ee(K),fe(he(le(ne),be,_e),Ee(ne));const Ne=G(((e,t,n)=>t(n)&&e(n))),qe=ke,{random:Ae}=Math,We=new O,$e=Se([]),je=Ne(oe("Number"),qe(isNaN)),ze={_is_ping:!0},Ce=e=>e&&clearTimeout(e),Qe=e=>{const t=We.zip(2147483637*Ae()|0);return t in e?Qe(e):t};class Oe{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(){ue(be,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=B(1e3*e.interval,(async()=>{const{ping_timer:t,opened:n}=this;n?(await this.send(e.content,ze),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=B(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(),x(e,"close",(async(...e)=>{this.log("close"),this.ws=null,this.onCloseQueue.forEach($e),this.onCloseQueue.splice(0),this.call("close",...e);let{reconnect:t,reconnection_attempts:s}=n;if(je(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()}})),x(e,"message",(e=>{try{const t=n.decode(e.data);if(this.call("message",{...e,data:t}),s in t){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()}))}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=ve((t=>{this.opening=!1,e(t)}));x(n,"error",ve((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)):x(n,"open",ve((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((e=>{this.config.lazy||this.opened?e():this.onReadyQueue.push(e)}))}on(e,t,n=_e,s=!1){const o=e=>n(e)&&t(e);return s?x(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 prepareMessage(e,t={}){this.log(t._is_ping?"ping":"send",e);const{config:n,queue:s}=this,{pipes:o,server:{data_key:i}}=n,{top:r,_is_ping:l}=t,c=Qe(s);if("object"==typeof r&&r[i])throw new Error(`Attempting to set data key/token via ${t._is_ping?"ping":"send"}() options!`);for(const t of o)e=t(e);const[a,u]=await Promise.all([n.encode(c,e,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);this.opened&&(this.ws.send(a),this.resetPing(),l||this.resetIdle());const h=we((()=>delete this.queue[c]));return{message_id:c,msg:a,timeout:t=>B(n.timeout,(()=>{c in s&&(this.call("timeout",e),t({"Websocket timeout expired":n.timeout,"for the message":e}),h())})),cleanup:h}}async send(e,t={}){const{message_id:n,msg:s,timeout:o,cleanup:i}=await this.prepareMessage(e,t),{queue:r,config:l}=this;return new Promise(((e,t)=>{const i=o(t);r[n]={msg:s,data_type:l.data_type,sent_time:l.timer?Date.now():null,ff(t){Ce(i),e(t)}}})).finally(i)}async*stream(e,t={}){const{message_id:n,msg:s,timeout:o,cleanup:i}=await this.prepareMessage(e,t),{queue:r,config:l}=this;let c,a=!1,u=null;for(r[n]={msg:s,ff:e=>{c(e),e?.done&&(i(),a=!0)},data_type:l.data_type,sent_time:l.timer?Date.now():null};!a;)yield await new Promise(((e,t)=>{u=o(t),c=e})).catch((e=>i(e))).finally((()=>{Ce(u),u=null}))}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({},I,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{Oe as default};
|
|
1
|
+
const t=Symbol("Placeholder"),e=e=>{let n=0;for(const s of e)s!==t&&n++;return n},n=(e,n)=>{const s=e.length,i=e.slice(),o=n.length;let r=o,l=0;for(;r&&l<s;l++)i[l]===t&&(i[l]=n[o-r],r--);for(l=s;r;l++,r--)i[l]=n[o-r];return i},s=(t,i,o)=>{const r=t.length-i.length-e(o);if(r<1)return t(...n(i,o));{const e=(...e)=>s(t,n(i,o),e);return e.$args_left=r,e}},i=t=>(...n)=>t.length>e(n)?s(t,[],n):t(...n);function o(e){return function(n,...s){return s.length>0?n===t?(e=>function(n){return n===t?e:e(n)})((t=>e(t,s[0]))):e(n,s[0]):t=>e(n,t)}}function r(t){return i(t)}const l=t=>t.length,c=/^(.*?)(8|16|32|64)(Clamped)?Array$/,a=void 0,u=1/0,h=t=>typeof t,d=t=>null===t,f=t=>"number"==h(t);const p=t=>d(t)||(t=>t===a)(t),g={u:"U",b:"B",n:"N",s:"S",f:"F"},m=Symbol(),y=t=>{const e=h(t);return"object"===e?d(t)?"Null":t.constructor.name:g[e[0]]+e.slice(1)},_=o(((t,e)=>y(e)===t)),w=o(((t,e)=>t===e)),b=o(((t,e)=>{const n=y(t);if(w(n,y(e))&&(w(n,"Object")||w(n,"Array")||(t=>c.test(t))(n))){if(d(t)||d(e))return w(t,e);if(w(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(w(n,e)&&s in t||w(n,t)&&s in e&&b(t[s],e[s])))return!1;return!0}return w(t,e)})),k=o(((t,e)=>(e.push(t),e))),S=r(((t,e,n)=>n.reduce(t,e))),P=o(((t,e)=>{const n=(t=>Array.isArray(t))(e);let s,i;n&&(s=0,i=[]);for(let s in e)t(e[s],s)||(n?i.push(+s):delete e[s]);if(n)for(const t of i)e.splice(t-s++,1);return e})),v=i(((t,e,n,s)=>t(s)?e(s):n(s))),E=(...e)=>(...n)=>{let s,i=!0;for(let o=l(e)-1;o>-1;o--)i?(i=!1,s=e[o](...n)):s=s===t?e[o]():e[o](s);return s},A=o(((t,e)=>e[t])),C=r(((t,e,n)=>n.slice(t,f(e)?e:u))),N=A(0);C(1,u);const $=o(((t,e)=>e.find(t))),j=t=>()=>t,q=o(((t,e)=>(t(e),e))),T=j(!0),W=j(!1),z=o(((t,e)=>e(...t))),O=t=>(...e)=>{const n=t(...e),s=function(t){return"function"===h(t)}(n);return s&&n.$args_left?O(n):(t=>!t)(n)},Q=o(((t,e)=>S(((e,n)=>$((e=>t(n,e)),e)?e:k(n,e)),[],e)));Q(b);const R=t=>{let e,n=!1;return function(...s){return n?e:(n=!0,e=t(...s))}},x=(t,e,n)=>l(e)?p(n)?t:E((s=>s in n?x(t,C(1,u,e),n[s]):t),N)(e):n,B=r(x);B(a),E(v(b(m),W,T),B(m));const I=r(((t,e,n)=>e(n)&&t(n))),M=O,D=Symbol("Placeholder"),L=t=>{let e=0;for(const n of t)n!==D&&e++;return e},U=(t,e)=>{const n=t.length,s=t.slice(),i=e.length;let o=i,r=0;for(;o&&r<n;r++)s[r]===D&&(s[r]=e[i-o],o--);for(r=n;o;r++,o--)s[r]=e[i-o];return s},F=(t,e,n)=>{const s=t.length-e.length-L(n);if(s<1)return t(...U(e,n));{const i=(...s)=>F(t,U(e,n),s);return i.$args_left=s,i}},J=t=>(...e)=>t.length>L(e)?F(t,[],e):t(...e);function G(t){return function(e,...n){return n.length>0?e===D?(t=>function(e){return e===D?t:t(e)})((e=>t(e,n[0]))):t(e,n[0]):n=>t(e,n)}}function H(t){return J(t)}const K=t=>t.length,V=/^(.*?)(8|16|32|64)(Clamped)?Array$/,X=void 0,Y=1/0,Z=t=>typeof t,tt=t=>null===t,et={u:"U",b:"B",n:"N",s:"S",f:"F"},nt=Symbol(),st=t=>{const e=Z(t);return"object"===e?tt(t)?"Null":t.constructor.name:et[e[0]]+e.slice(1)},it=G(((t,e)=>st(e)===t)),ot=G(((t,e)=>t===e)),rt=G(((t,e)=>{const n=st(t);if(ot(n,st(e))&&(ot(n,"Object")||ot(n,"Array")||(s=n,V.test(s)))){if(tt(t)||tt(e))return ot(t,e);if(ot(t,e))return!0;for(const n of[t,e])for(const s in n)if(!(ot(n,e)&&s in t||ot(n,t)&&s in e&&rt(t[s],e[s])))return!1;return!0}var s;return ot(t,e)})),lt=G(((t,e)=>(e.push(t),e))),ct=H(((t,e,n)=>n.reduce(t,e))),at=J(((t,e,n,s)=>t(s)?e(s):n(s))),ut=H(((t,e,n)=>at(t,e,yt,n))),ht=(...t)=>(...e)=>{let n,s=!0;for(let i=K(t)-1;i>-1;i--)s?(s=!1,n=t[i](...e)):n=n===D?t[i]():t[i](n);return n},dt=G(((t,e)=>e[t])),ft=H(((t,e,n)=>n.slice(t,(t=>"number"==Z(t))(e)?e:Y))),pt=dt(0);ft(1,Y);const gt=G(((t,e)=>e.find(t))),mt=t=>()=>t,yt=t=>t,_t=G(((t,e)=>e.split(t))),wt=mt(!0),bt=mt(!1),kt=G(((t,e)=>ct(((e,n)=>gt((e=>t(n,e)),e)?e:lt(n,e)),[],e)))(rt),St=(t,e,n)=>K(e)?(t=>tt(t)||(t=>t===X)(t))(n)?t:ht((s=>s in n?St(t,ft(1,Y,e),n[s]):t),pt)(e):n,Pt=H(St);Pt(X),ht(at(rt(nt),bt,wt),Pt(nt));const vt=G(((t,e)=>e.map(t))),{floor:Et}=Math,At="0123456789abcdefghijklmnopqrstuvwxyz",Ct=it("String"),Nt=ut(Ct,_t("")),$t=ht((t=>Object.fromEntries(t)),vt(((t,e)=>[t,e])),Nt);class jt{is_str;delim;abc;abclen;c2pos;standard;setABC(t,e=""){if(this.is_str=Ct(t),this.delim=e,!ht(ot(K(n=t)),K,kt,Nt)(n))throw new Error("Not all chars are unique!");var n;this.abc=t,this.abclen=K(t),this.standard=!!this.is_str&&At.startsWith(t),this.c2pos=$t(t)}zip(t){const{abc:e,abclen:n,delim:s}=this;let i="",o=!0;for(;t>0;)i=e[t%n]+(o?"":s)+i,t=Et(t/n),o=!1;return i||"0"}unzip(t){const{standard:e,abclen:n,c2pos:s,delim:i,is_str:o}=this;if("0"===t)return 0;if(e)return parseInt(t,n);const r=o?t:t.split(i),l=K(r);let c=0;for(let t=0;t<l;t++)c+=s[r[t]]*n**(l-t-1);return c}constructor(t,e){e?this.setABC(t,e):this.setABC(t||At+"ABCDEFGHIJKLMNOPQRSTUVWXYZ")}}const qt=new jt;qt.setABC.bind(qt),qt.zip.bind(qt),qt.unzip.bind(qt);const Tt=(()=>{try{return WebSocket||null}catch{return null}})(),Wt=(t,e,n)=>t.addEventListener(e,n),zt=(t,e)=>setTimeout(e,t),Ot={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:(t,e)=>new WebSocket(t,e),encode:(t,e,{server:n})=>JSON.stringify({[n.id_key]:t,[n.data_key]:e}),decode:t=>JSON.parse(t),protocols:[],pipes:[],server:{id_key:"id",data_key:"data"},ping:{interval:55,content:{}}},{random:Qt}=Math,Rt=new jt,xt=z([]),Bt=I(_("Number"),M(isNaN)),It={_is_ping:!0},Mt=t=>t&&clearTimeout(t),Dt=t=>{const e=Rt.zip(2147483637*Qt()|0);return e in t?Dt(t):e};class Lt{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(){P(W,this.queue)}call(t,...e){for(const n of this.handlers[t])n(...e)}log(t,e=null,n=null){const{config:s}=this;setTimeout((()=>{null===n?s.timer?s.log(t,null,e):s.log(t,e):s.log(t,n,e)}))}resetPing(){const{config:{ping:t},ping_timer:e}=this;t&&(p(e)||clearTimeout(e),this.ping_timer=zt(1e3*t.interval,(async()=>{const{ping_timer:e,opened:n}=this;n?(await this.send(t.content,It),this.resetPing()):clearTimeout(e)})))}resetIdle(){const{config:{max_idle_time:t},idle_timer:e}=this;t!==1/0&&(p(e)||clearTimeout(e),this.idle_timer=zt(1e3*t,(()=>this.opened&&this.close())))}initSocket(t){const{queue:e,config:n}=this;this.ws=t,this.onReadyQueue.forEach((t=>t())),this.onReadyQueue.splice(0);const{id_key:s,data_key:i}=n.server;this.call("open",t);for(const n in e)t.send(e[n].msg);null!==this.reconnect_timeout&&(clearInterval(this.reconnect_timeout),this.reconnect_timeout=null),this.resetPing(),this.resetIdle(),Wt(t,"close",(async(...t)=>{this.ws=null,this.onCloseQueue.forEach(xt),this.onCloseQueue.splice(0),this.call("close",...t);let{reconnect:e,reconnection_attempts:s}=n;if(Bt(e)){const t=async()=>{if(this.intentionally_closed||!s)return;s--,this.log("reconnect"),p(this.ws)||(this.ws.close(),this.ws=null);const n=await this.connect();p(n)||(this.reconnect_timeout=setTimeout(t,1e3*e))};t()}})),Wt(t,"message",(t=>{try{const e=n.decode(t.data);this.call("message",{...t,data:e});let o=!1;if(_("Object",e)&&s in e){const t=this.queue[e[s]];if(t){const n=t.sent_time?Date.now()-t.sent_time:null;this.log("message",e[i],n),t.ff(e[i]),o=!0}}o||this.log("message-ext",e)}catch(e){console.error(e,`WSP: Decode error. Got: ${t.data}`)}this.resetPing()}))}opening=!1;connect(){return new Promise((t=>{if(this.opened||this.opening)return t(null);this.opening=!0;const e=this.config,n=e.socket||e.adapter(e.url,e.protocols);if(!n||n.readyState>1)return this.opening=!1,this.ws=null,this.log("error","ready() on closing or closed state! status 2."),t(2);const s=R((e=>{this.opening=!1,t(e)}));Wt(n,"error",R((t=>{this.ws=null,this.log("error","status 3. Err: "+t.message),this.call("error",t),s(3)}))),n.readyState?(this.initSocket(n),s(null)):Wt(n,"open",R((()=>{this.log("open"),this.initSocket(n),s(null)})))}))}get socket(){return this.ws}async ready(){return new Promise((t=>{this.config.lazy||this.opened?t():this.onReadyQueue.push(t)}))}on(t,e,n=T,s=!1){const i=t=>n(t)&&e(t);return s?Wt(this.ws,t,i):this.handlers[t].push(i),i}off(t,e,n=!1){if(n)return((t,e,n)=>t.removeEventListener(e,n))(this.ws,t,e);const s=this.handlers[t],i=s.indexOf(e);~i&&s.splice(i,1)}async close(){return new Promise(((t,e)=>{null===this.ws?e("WSP: closing a non-inited socket!"):(this.onCloseQueue.push((()=>{this.init_flush(),t(null)})),this.ws.close(),this.ws=null,this.intentionally_closed=!0)}))}open(){if(!this.opened)return this.intentionally_closed=!1,this.connect()}async prepareMessage(t,e={}){this.log(e._is_ping?"ping":"send",t);const{config:n,queue:s}=this,{pipes:i,server:{data_key:o}}=n,{top:r,_is_ping:l}=e,c=Dt(s);if("object"==typeof r&&r[o])throw new Error(`Attempting to set data key/token via ${e._is_ping?"ping":"send"}() options!`);for(const e of i)t=e(t);const[a,u]=await Promise.all([n.encode(c,t,n),this.connect()]);if(u)throw new Error("ERR while opening connection #"+u);const h=q((()=>delete this.queue[c]));return this.opened&&(zt(0,(()=>this.ws.send(a))),this.resetPing(),l||this.resetIdle()),{id:c,msg:a,timeout:e=>zt(n.timeout,(()=>{c in s&&(this.call("timeout",t),e({"Websocket timeout expired":n.timeout,"for the message":t}),h())})),cleanup:h}}async send(t,e={}){const{id:n,msg:s,timeout:i,cleanup:o}=await this.prepareMessage(t,e),{queue:r,config:l}=this;return new Promise(((t,e)=>{const o=i(e);r[n]={msg:s,data_type:l.data_type,sent_time:l.timer?Date.now():null,ff(e){Mt(o),t(e)}}})).finally(o)}async*stream(t,e={}){const{id:n,msg:s,timeout:i,cleanup:o}=await this.prepareMessage(t,e),{queue:r,config:l}=this;let c,a=!1,u=null;for(r[n]={msg:s,ff:t=>{t?.done&&(delete t.done,a=!0,setTimeout(o)),c(t)},data_type:l.data_type,sent_time:l.timer?Date.now():null};!a;)yield await new Promise(((t,e)=>{u=i(e),c=t})).catch((t=>o(t))).finally((()=>{Mt(u),u=null}))}constructor(t={}){this.config=(t=>{if(null===Tt&&!("adapter"in t))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 e=Object.assign({},Ot,t),n=e.url;if("/"==n[0])try{const t=location.protocol.includes("s:")?"wss":"ws";e.url=`${t}://${location.hostname}:${location.port}${n}`}catch(t){throw new Error("WSP: URL starting with / in non-browser environment!")}return e})(t),this.config.lazy||this.connect()}}export{Lt as WebSocketClient,Lt as default};
|
package/package.json
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"prod": "npm run gentypes && npm run prod:es && npm run prod:cjs",
|
|
42
42
|
"all": "npm run dev && npm run prod"
|
|
43
43
|
},
|
|
44
|
-
"version": "2.
|
|
44
|
+
"version": "2.10.1",
|
|
45
45
|
"type": "module",
|
|
46
46
|
"exports": {
|
|
47
47
|
".": {
|
|
@@ -52,28 +52,28 @@
|
|
|
52
52
|
"./src": "./src/*"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@rollup/plugin-commonjs": "^29.0.
|
|
55
|
+
"@rollup/plugin-commonjs": "^29.0.2",
|
|
56
56
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
57
57
|
"@rollup/plugin-replace": "^6.0.3",
|
|
58
|
-
"@rollup/plugin-terser": "^0.
|
|
58
|
+
"@rollup/plugin-terser": "^1.0.0",
|
|
59
59
|
"@types/express": "^5.0.6",
|
|
60
|
-
"@types/node": "^25.0
|
|
60
|
+
"@types/node": "^25.4.0",
|
|
61
61
|
"@types/ws": "^8.18.1",
|
|
62
|
-
"codecov": "^3.6.
|
|
62
|
+
"codecov": "^3.6.3",
|
|
63
63
|
"cross-env": "^10.1.0",
|
|
64
64
|
"dts-bundle-generator": "^9.5.1",
|
|
65
|
-
"nyc": "^
|
|
66
|
-
"rollup": "^4.
|
|
65
|
+
"nyc": "^18.0.0",
|
|
66
|
+
"rollup": "^4.59.0",
|
|
67
67
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
68
68
|
"ts-node": "^10.9.2",
|
|
69
69
|
"tsx": "^4.21.0",
|
|
70
70
|
"typescript": "^5.9.3",
|
|
71
71
|
"uvu": "^0.5.6",
|
|
72
|
-
"ws": "^8.
|
|
72
|
+
"ws": "^8.19.0"
|
|
73
73
|
},
|
|
74
74
|
"types": "./dist/bundle.d.ts",
|
|
75
75
|
"dependencies": {
|
|
76
|
-
"pepka": "^1.6.
|
|
77
|
-
"zipnum": "^2.
|
|
76
|
+
"pepka": "^1.6.23",
|
|
77
|
+
"zipnum": "^2.1.3"
|
|
78
78
|
}
|
|
79
79
|
}
|
package/rollup.config.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import commonjs from '@rollup/plugin-commonjs'
|
|
2
2
|
import resolve from '@rollup/plugin-node-resolve'
|
|
3
|
-
import typescript from 'rollup-plugin-typescript2'
|
|
4
|
-
import terser from '@rollup/plugin-terser'
|
|
5
3
|
import replace from '@rollup/plugin-replace'
|
|
4
|
+
import terser from '@rollup/plugin-terser'
|
|
5
|
+
import typescript from 'rollup-plugin-typescript2'
|
|
6
6
|
import tsc from 'typescript'
|
|
7
7
|
|
|
8
8
|
export default {
|
|
@@ -32,9 +32,7 @@ export default {
|
|
|
32
32
|
process.env.NODE_ENV!='development' && terser(),
|
|
33
33
|
replace({
|
|
34
34
|
preventAssignment: true,
|
|
35
|
-
values: {
|
|
36
|
-
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
|
|
37
|
-
}
|
|
35
|
+
values: { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) }
|
|
38
36
|
})
|
|
39
37
|
]
|
|
40
38
|
}
|
package/src/WSC.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import '
|
|
1
|
+
import { AnyFunc, AnyObject, both, callWith, F, isNil, notf, once, qfilter, T, tap, typeIs } from 'pepka'
|
|
2
2
|
import { Zipnum } from 'zipnum'
|
|
3
|
-
import { add_event, rm_event, sett } from './utils'
|
|
4
3
|
import { processConfig } from './config'
|
|
5
|
-
import
|
|
4
|
+
import './types'
|
|
5
|
+
import { add_event, rm_event, sett } from './utils'
|
|
6
6
|
|
|
7
7
|
const MAX_32 = 2**31 - 1
|
|
8
8
|
const { random } = Math
|
|
@@ -25,7 +25,7 @@ const genid = (q: AnyObject) => {
|
|
|
25
25
|
return id in q ? genid(q) : id
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
class WebSocketClient {
|
|
28
|
+
export class WebSocketClient {
|
|
29
29
|
private ws: wsc.Socket|null = null
|
|
30
30
|
private intentionally_closed = false
|
|
31
31
|
private reconnect_timeout: NodeJS.Timeout|null = null
|
|
@@ -45,16 +45,16 @@ class WebSocketClient {
|
|
|
45
45
|
private call(event_name: wsc.WSEvent, ...args: any[]) {
|
|
46
46
|
for(const h of this.handlers[event_name]) h(...args)
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
private log(event: string, message: any = null, time: number|null = null): void {
|
|
48
|
+
private log(event: wsc.WSEvent, message: any = null, time: number|null = null): void {
|
|
50
49
|
const {config} = this
|
|
51
|
-
|
|
52
|
-
if(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
if(time === null)
|
|
52
|
+
if(config.timer) config.log(event, null, message)
|
|
53
|
+
else config.log(event, message)
|
|
54
|
+
else
|
|
55
|
+
config.log(event, time, message)
|
|
56
|
+
})
|
|
56
57
|
}
|
|
57
|
-
|
|
58
58
|
private resetPing() {
|
|
59
59
|
const {config: {ping}, ping_timer} = this
|
|
60
60
|
if(ping) {
|
|
@@ -70,7 +70,7 @@ class WebSocketClient {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
//
|
|
73
|
+
// FIXME: Make some version where it could work faster (for streaming).
|
|
74
74
|
private resetIdle() {
|
|
75
75
|
const {config: {max_idle_time: time}, idle_timer} = this
|
|
76
76
|
if(time!==Infinity) {
|
|
@@ -94,7 +94,6 @@ class WebSocketClient {
|
|
|
94
94
|
}
|
|
95
95
|
this.resetPing(); this.resetIdle()
|
|
96
96
|
add_event(ws, 'close', async (...e) => {
|
|
97
|
-
this.log('close')
|
|
98
97
|
this.ws = null
|
|
99
98
|
this.onCloseQueue.forEach(callit)
|
|
100
99
|
this.onCloseQueue.splice(0)
|
|
@@ -122,8 +121,9 @@ class WebSocketClient {
|
|
|
122
121
|
add_event(ws, 'message', (e) => {
|
|
123
122
|
try {
|
|
124
123
|
const data = config.decode(e.data)
|
|
125
|
-
this.call('message', {...e, data})
|
|
126
|
-
|
|
124
|
+
this.call('message', {...e, data}) // TODO: Breaking: make message-ext another handler.
|
|
125
|
+
let internal = false
|
|
126
|
+
if(typeIs('Object', data) && id_key in data) {
|
|
127
127
|
const q = this.queue[data[id_key]]
|
|
128
128
|
if(q) {
|
|
129
129
|
// Debug, Log.
|
|
@@ -131,15 +131,16 @@ class WebSocketClient {
|
|
|
131
131
|
this.log('message', data[data_key], time)
|
|
132
132
|
// Play.
|
|
133
133
|
q.ff(data[data_key])
|
|
134
|
+
internal = true
|
|
134
135
|
}
|
|
135
136
|
}
|
|
137
|
+
if(!internal) this.log('message-ext', data)
|
|
136
138
|
} catch (err) {
|
|
137
139
|
console.error(err, `WSP: Decode error. Got: ${e.data}`)
|
|
138
140
|
}
|
|
139
141
|
this.resetPing()
|
|
140
142
|
})
|
|
141
143
|
}
|
|
142
|
-
|
|
143
144
|
private opening = false
|
|
144
145
|
private connect() { // returns status if won't open or null if ok.
|
|
145
146
|
return new Promise<null|number>((ff) => {
|
|
@@ -177,8 +178,7 @@ class WebSocketClient {
|
|
|
177
178
|
public get socket() { return this.ws }
|
|
178
179
|
public async ready() {
|
|
179
180
|
return new Promise<void>((ff) => {
|
|
180
|
-
if(this.config.lazy) ff() // FIXME: (possibly) breaking change ?? At least minor ver bump with a notice!!!
|
|
181
|
-
else if(this.opened) ff()
|
|
181
|
+
if(this.config.lazy || this.opened) ff() // FIXME: (possibly) breaking change ?? At least minor ver bump with a notice!!!
|
|
182
182
|
else this.onReadyQueue.push(ff)
|
|
183
183
|
})
|
|
184
184
|
}
|
|
@@ -204,7 +204,6 @@ class WebSocketClient {
|
|
|
204
204
|
const i = handlers.indexOf(handler)
|
|
205
205
|
if(~i) handlers.splice(i, 1)
|
|
206
206
|
}
|
|
207
|
-
|
|
208
207
|
public async close(): wsc.AsyncErrCode {
|
|
209
208
|
return new Promise((ff, rj) => {
|
|
210
209
|
if(this.ws === null) {
|
|
@@ -220,17 +219,15 @@ class WebSocketClient {
|
|
|
220
219
|
}
|
|
221
220
|
})
|
|
222
221
|
}
|
|
223
|
-
|
|
224
222
|
public open() {
|
|
225
223
|
if(!this.opened) {
|
|
226
224
|
this.intentionally_closed = false
|
|
227
225
|
return this.connect()
|
|
228
226
|
}
|
|
229
227
|
}
|
|
230
|
-
|
|
231
228
|
// TODO: Сделать сэттер элементов конфигурации чтобы двигать таймауты.
|
|
232
229
|
// И эвент, когда схема наша, а соответствующего элемента очереди не ма.
|
|
233
|
-
// Или добавить флажок к эвенту 'message'.
|
|
230
|
+
// Или добавить флажок к эвенту 'message'.F
|
|
234
231
|
// И событие 'line' со значением on: boolean. Критерии?
|
|
235
232
|
private async prepareMessage<RequestDataType = any>(
|
|
236
233
|
message_data: RequestDataType,
|
|
@@ -252,11 +249,6 @@ class WebSocketClient {
|
|
|
252
249
|
this.connect()
|
|
253
250
|
])
|
|
254
251
|
if(err) throw new Error('ERR while opening connection #'+err)
|
|
255
|
-
if(this.opened) {
|
|
256
|
-
this.ws!.send(msg)
|
|
257
|
-
this.resetPing()
|
|
258
|
-
if(!_is_ping) this.resetIdle()
|
|
259
|
-
}
|
|
260
252
|
const cleanup = tap(() => delete this.queue[id])
|
|
261
253
|
const timeout = (rj: AnyFunc) => sett(config.timeout, () => {
|
|
262
254
|
if(id in queue) {
|
|
@@ -265,9 +257,13 @@ class WebSocketClient {
|
|
|
265
257
|
cleanup()
|
|
266
258
|
}
|
|
267
259
|
})
|
|
268
|
-
|
|
260
|
+
if(this.opened) {
|
|
261
|
+
sett(0, () => this.ws!.send(msg))
|
|
262
|
+
this.resetPing()
|
|
263
|
+
if(!_is_ping) this.resetIdle()
|
|
264
|
+
}
|
|
265
|
+
return { id, msg, timeout, cleanup }
|
|
269
266
|
}
|
|
270
|
-
|
|
271
267
|
/** .send(your_data) wraps request to server with {id: `hash`, data: `actually your data`},
|
|
272
268
|
returns a Promise that will be rejected after a timeout or
|
|
273
269
|
resolved if server returns the same signature: {id: `same_hash`, data: `response data`}.
|
|
@@ -276,12 +272,11 @@ class WebSocketClient {
|
|
|
276
272
|
message_data: RequestDataType,
|
|
277
273
|
opts = <wsc.SendOptions>{}
|
|
278
274
|
): Promise<ResponseDataType> {
|
|
279
|
-
const {
|
|
275
|
+
const {id, msg, timeout, cleanup} = await this.prepareMessage(message_data, opts)
|
|
280
276
|
const {queue, config} = this
|
|
281
|
-
|
|
282
277
|
return new Promise<ResponseDataType>((ff, rj) => {
|
|
283
278
|
const to = timeout(rj)
|
|
284
|
-
queue[
|
|
279
|
+
queue[id] = {
|
|
285
280
|
msg,
|
|
286
281
|
data_type: config.data_type,
|
|
287
282
|
sent_time: config.timer ? Date.now() : null,
|
|
@@ -292,19 +287,19 @@ class WebSocketClient {
|
|
|
292
287
|
}
|
|
293
288
|
}).finally(cleanup)
|
|
294
289
|
}
|
|
295
|
-
|
|
290
|
+
// FIXME: rejects into ff somehow.
|
|
296
291
|
public async *stream<RequestDataType = any, ResponseDataType = any>(
|
|
297
292
|
message_data: RequestDataType,
|
|
298
293
|
opts = <wsc.SendOptions>{}
|
|
299
294
|
): AsyncGenerator<ResponseDataType, void, unknown> {
|
|
300
|
-
const {
|
|
295
|
+
const {id, msg, timeout, cleanup} = await this.prepareMessage(message_data, opts)
|
|
301
296
|
const {queue, config} = this
|
|
302
297
|
let done = false, fulfill: AnyFunc, to: NodeJS.Timeout|null = null
|
|
303
|
-
queue[
|
|
298
|
+
queue[id] = {
|
|
304
299
|
msg,
|
|
305
300
|
ff: (msg: ResponseDataType&{done?: boolean}) => {
|
|
301
|
+
if(msg?.done) { delete msg.done; done=true; setTimeout(cleanup) }
|
|
306
302
|
fulfill(msg)
|
|
307
|
-
if(msg?.done) { cleanup(); done=true }
|
|
308
303
|
},
|
|
309
304
|
data_type: config.data_type,
|
|
310
305
|
sent_time: config.timer ? Date.now() : null
|
|
@@ -313,7 +308,6 @@ class WebSocketClient {
|
|
|
313
308
|
to=timeout(rj); fulfill=ff
|
|
314
309
|
}).catch((e) => cleanup(e)).finally(() => {clearTO(to); to=null})
|
|
315
310
|
}
|
|
316
|
-
|
|
317
311
|
// TODO: Add .on handlers to config!
|
|
318
312
|
constructor(user_config: wsc.UserConfig = {}) {
|
|
319
313
|
this.config = processConfig(user_config)
|
package/src/types.ts
CHANGED
|
@@ -4,7 +4,7 @@ declare namespace wsc {
|
|
|
4
4
|
[key: string]: any
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export type WSEvent = 'open' | 'message' | 'close' | 'error' | 'timeout'
|
|
7
|
+
export type WSEvent = 'open' | 'message' | 'message-ext' | 'close' | 'error' | 'timeout' | 'reconnect' | 'send' | 'ping'
|
|
8
8
|
|
|
9
9
|
/** Minimal socket-like interface. */
|
|
10
10
|
interface Socket {
|