wspromisify 2.9.4 → 2.10.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 +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 +30 -35
- 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),x=o(((t,e)=>e(...t))),z=t=>(...e)=>{const n=t(...e),s=function(t){return"function"===h(t)}(n);return s&&n.$args_left?z(n):(t=>!t)(n)},Q=o(((t,e)=>S(((e,n)=>N((e=>t(n,e)),e)?e:k(n,e)),[],e)));Q(b);const T=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=z,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),xt=(t,e)=>setTimeout(e,t),zt={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,Tt=new Wt,Rt=x([]),Bt=M(_("Number"),I(isNaN)),Mt={_is_ping:!0},It=t=>t&&clearTimeout(t),Dt=t=>{const e=Tt.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(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=xt(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=xt(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.log("close"),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=T((e=>{this.opening=!1,t(e)}));Ot(n,"error",T((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",T((()=>{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&&(xt(0,(()=>this.ws.send(u))),this.resetPing(),l||this.resetIdle()),{id:c,msg:u,timeout:e=>xt(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=>{c(t),t?.done&&(o(),u=!0)},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({},zt,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,f=t=>null===t,d=t=>"number"==h(t);const p=t=>f(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?f(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(f(t)||f(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,d(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))),W=j(!0),z=j(!1),O=o(((t,e)=>e(...t))),Q=t=>(...e)=>{const n=t(...e),s=function(t){return"function"===h(t)}(n);return s&&n.$args_left?Q(n):(t=>!t)(n)},T=o(((t,e)=>S(((e,n)=>$((e=>t(n,e)),e)?e:k(n,e)),[],e)));T(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),z,W),B(m));const I=r(((t,e,n)=>e(n)&&t(n))),M=Q,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},ft=G(((t,e)=>e[t])),dt=H(((t,e,n)=>n.slice(t,(t=>"number"==Z(t))(e)?e:Y))),pt=ft(0);dt(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,dt(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 Wt=(()=>{try{return WebSocket||null}catch{return null}})(),zt=(t,e,n)=>t.addEventListener(e,n),Ot=(t,e)=>setTimeout(e,t),Qt={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:Tt}=Math,Rt=new jt,xt=O([]),Bt=I(_("Number"),M(isNaN)),It={_is_ping:!0},Mt=t=>t&&clearTimeout(t),Dt=t=>{const e=Rt.zip(2147483637*Tt()|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(z,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=Ot(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=Ot(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(),zt(t,"close",(async(...t)=>{this.log("close"),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()}})),zt(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)}));zt(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)):zt(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=W,s=!1){const i=t=>n(t)&&e(t);return s?zt(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&&(Ot(0,(()=>this.ws.send(a))),this.resetPing(),l||this.resetIdle()),{id:c,msg:a,timeout:e=>Ot(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=>{c(t),t?.done&&(o(),a=!0)},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===Wt&&!("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({},Qt,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.0",
|
|
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) {
|
|
@@ -123,7 +123,8 @@ class WebSocketClient {
|
|
|
123
123
|
try {
|
|
124
124
|
const data = config.decode(e.data)
|
|
125
125
|
this.call('message', {...e, data})
|
|
126
|
-
|
|
126
|
+
let internal = false
|
|
127
|
+
if(typeIs('Object', data) && id_key in data) {
|
|
127
128
|
const q = this.queue[data[id_key]]
|
|
128
129
|
if(q) {
|
|
129
130
|
// Debug, Log.
|
|
@@ -131,15 +132,16 @@ class WebSocketClient {
|
|
|
131
132
|
this.log('message', data[data_key], time)
|
|
132
133
|
// Play.
|
|
133
134
|
q.ff(data[data_key])
|
|
135
|
+
internal = true
|
|
134
136
|
}
|
|
135
137
|
}
|
|
138
|
+
if(!internal) this.log('message-ext', data)
|
|
136
139
|
} catch (err) {
|
|
137
140
|
console.error(err, `WSP: Decode error. Got: ${e.data}`)
|
|
138
141
|
}
|
|
139
142
|
this.resetPing()
|
|
140
143
|
})
|
|
141
144
|
}
|
|
142
|
-
|
|
143
145
|
private opening = false
|
|
144
146
|
private connect() { // returns status if won't open or null if ok.
|
|
145
147
|
return new Promise<null|number>((ff) => {
|
|
@@ -177,8 +179,7 @@ class WebSocketClient {
|
|
|
177
179
|
public get socket() { return this.ws }
|
|
178
180
|
public async ready() {
|
|
179
181
|
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()
|
|
182
|
+
if(this.config.lazy || this.opened) ff() // FIXME: (possibly) breaking change ?? At least minor ver bump with a notice!!!
|
|
182
183
|
else this.onReadyQueue.push(ff)
|
|
183
184
|
})
|
|
184
185
|
}
|
|
@@ -204,7 +205,6 @@ class WebSocketClient {
|
|
|
204
205
|
const i = handlers.indexOf(handler)
|
|
205
206
|
if(~i) handlers.splice(i, 1)
|
|
206
207
|
}
|
|
207
|
-
|
|
208
208
|
public async close(): wsc.AsyncErrCode {
|
|
209
209
|
return new Promise((ff, rj) => {
|
|
210
210
|
if(this.ws === null) {
|
|
@@ -220,17 +220,15 @@ class WebSocketClient {
|
|
|
220
220
|
}
|
|
221
221
|
})
|
|
222
222
|
}
|
|
223
|
-
|
|
224
223
|
public open() {
|
|
225
224
|
if(!this.opened) {
|
|
226
225
|
this.intentionally_closed = false
|
|
227
226
|
return this.connect()
|
|
228
227
|
}
|
|
229
228
|
}
|
|
230
|
-
|
|
231
229
|
// TODO: Сделать сэттер элементов конфигурации чтобы двигать таймауты.
|
|
232
230
|
// И эвент, когда схема наша, а соответствующего элемента очереди не ма.
|
|
233
|
-
// Или добавить флажок к эвенту 'message'.
|
|
231
|
+
// Или добавить флажок к эвенту 'message'.F
|
|
234
232
|
// И событие 'line' со значением on: boolean. Критерии?
|
|
235
233
|
private async prepareMessage<RequestDataType = any>(
|
|
236
234
|
message_data: RequestDataType,
|
|
@@ -252,11 +250,6 @@ class WebSocketClient {
|
|
|
252
250
|
this.connect()
|
|
253
251
|
])
|
|
254
252
|
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
253
|
const cleanup = tap(() => delete this.queue[id])
|
|
261
254
|
const timeout = (rj: AnyFunc) => sett(config.timeout, () => {
|
|
262
255
|
if(id in queue) {
|
|
@@ -265,9 +258,13 @@ class WebSocketClient {
|
|
|
265
258
|
cleanup()
|
|
266
259
|
}
|
|
267
260
|
})
|
|
268
|
-
|
|
261
|
+
if(this.opened) {
|
|
262
|
+
sett(0, () => this.ws!.send(msg))
|
|
263
|
+
this.resetPing()
|
|
264
|
+
if(!_is_ping) this.resetIdle()
|
|
265
|
+
}
|
|
266
|
+
return { id, msg, timeout, cleanup }
|
|
269
267
|
}
|
|
270
|
-
|
|
271
268
|
/** .send(your_data) wraps request to server with {id: `hash`, data: `actually your data`},
|
|
272
269
|
returns a Promise that will be rejected after a timeout or
|
|
273
270
|
resolved if server returns the same signature: {id: `same_hash`, data: `response data`}.
|
|
@@ -276,12 +273,11 @@ class WebSocketClient {
|
|
|
276
273
|
message_data: RequestDataType,
|
|
277
274
|
opts = <wsc.SendOptions>{}
|
|
278
275
|
): Promise<ResponseDataType> {
|
|
279
|
-
const {
|
|
276
|
+
const {id, msg, timeout, cleanup} = await this.prepareMessage(message_data, opts)
|
|
280
277
|
const {queue, config} = this
|
|
281
|
-
|
|
282
278
|
return new Promise<ResponseDataType>((ff, rj) => {
|
|
283
279
|
const to = timeout(rj)
|
|
284
|
-
queue[
|
|
280
|
+
queue[id] = {
|
|
285
281
|
msg,
|
|
286
282
|
data_type: config.data_type,
|
|
287
283
|
sent_time: config.timer ? Date.now() : null,
|
|
@@ -292,15 +288,15 @@ class WebSocketClient {
|
|
|
292
288
|
}
|
|
293
289
|
}).finally(cleanup)
|
|
294
290
|
}
|
|
295
|
-
|
|
291
|
+
// FIXME: rejects into ff somehow.
|
|
296
292
|
public async *stream<RequestDataType = any, ResponseDataType = any>(
|
|
297
293
|
message_data: RequestDataType,
|
|
298
294
|
opts = <wsc.SendOptions>{}
|
|
299
295
|
): AsyncGenerator<ResponseDataType, void, unknown> {
|
|
300
|
-
const {
|
|
296
|
+
const {id, msg, timeout, cleanup} = await this.prepareMessage(message_data, opts)
|
|
301
297
|
const {queue, config} = this
|
|
302
298
|
let done = false, fulfill: AnyFunc, to: NodeJS.Timeout|null = null
|
|
303
|
-
queue[
|
|
299
|
+
queue[id] = {
|
|
304
300
|
msg,
|
|
305
301
|
ff: (msg: ResponseDataType&{done?: boolean}) => {
|
|
306
302
|
fulfill(msg)
|
|
@@ -313,7 +309,6 @@ class WebSocketClient {
|
|
|
313
309
|
to=timeout(rj); fulfill=ff
|
|
314
310
|
}).catch((e) => cleanup(e)).finally(() => {clearTO(to); to=null})
|
|
315
311
|
}
|
|
316
|
-
|
|
317
312
|
// TODO: Add .on handlers to config!
|
|
318
313
|
constructor(user_config: wsc.UserConfig = {}) {
|
|
319
314
|
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 {
|