@utsp/network-client
Version:
UTSP Network Client - Client-side communication adapters
2 lines (1 loc) • 5.33 kB
JavaScript
var g=Object.defineProperty;var f=(i,t,e)=>t in i?g(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e;var a=(i,t)=>g(i,"name",{value:t,configurable:!0});var s=(i,t,e)=>(f(i,typeof t!="symbol"?t+"":t,e),e);import{NetworkState as E}from"@utsp/types";import{io as k}from"socket.io-client";import{NetworkState as o}from"@utsp/types";var h=class h{constructor(t){s(this,"socket",null);s(this,"options");s(this,"_state",o.Disconnected);s(this,"pingTimestamp",0);s(this,"latency",0);s(this,"pingInterval",null);if(!t.url||typeof t.url!="string")throw new Error("SocketIOClient: Invalid URL - must be a non-empty string");try{if(!new globalThis.URL(t.url).protocol)throw new Error("Invalid protocol")}catch{throw new Error(`SocketIOClient: Invalid URL format - ${t.url}`)}if(t.reconnectDelay!==void 0&&(t.reconnectDelay<0||!Number.isFinite(t.reconnectDelay)))throw new Error(`SocketIOClient: Invalid reconnectDelay - must be a positive number (got ${t.reconnectDelay})`);if(t.maxReconnectAttempts!==void 0&&(!Number.isInteger(t.maxReconnectAttempts)||t.maxReconnectAttempts<0))throw new Error(`SocketIOClient: Invalid maxReconnectAttempts - must be a positive integer (got ${t.maxReconnectAttempts})`);if(t.timeout!==void 0&&(t.timeout<=0||!Number.isFinite(t.timeout)))throw new Error(`SocketIOClient: Invalid timeout - must be a positive number (got ${t.timeout})`);this.options={url:t.url,autoReconnect:t.autoReconnect??!0,reconnectDelay:t.reconnectDelay??1e3,maxReconnectAttempts:t.maxReconnectAttempts??10,timeout:t.timeout??5e3,auth:t.auth??{},debug:t.debug??!1},this.log("Client initialized",{url:this.options.url,autoReconnect:this.options.autoReconnect})}get state(){return this._state}isConnected(){return this._state===o.Connected&&this.socket?.connected===!0}async connect(){if(this.socket&&this.isConnected()){this.log("Already connected");return}return this.log(`Connecting to ${this.options.url}...`),this._state=o.Connecting,new Promise((t,e)=>{this.socket=k(this.options.url,{auth:this.options.auth,reconnection:this.options.autoReconnect,reconnectionDelay:this.options.reconnectDelay,reconnectionAttempts:this.options.maxReconnectAttempts,timeout:this.options.timeout,transports:["websocket"]}),this.socket.on("connect",()=>{this.log(`Connected with ID: ${this.socket?.id}`),this._state=o.Connected,this.startPingMonitor(),t()}),this.socket.on("connect_error",n=>{this.log(`Connection error: ${n.message}`),this._state=o.Error,e(n)}),this.socket.on("disconnect",n=>{this.log(`Disconnected: ${n}`),this._state=o.Disconnected,this.stopPingMonitor()}),this.socket.on("reconnect_attempt",n=>{this.log(`Reconnection attempt ${n}...`),this._state=o.Reconnecting}),this.socket.on("reconnect",n=>{this.log(`Reconnected after ${n} attempts`),this._state=o.Connected,this.startPingMonitor()}),this.socket.on("reconnect_failed",()=>{this.log("Reconnection failed"),this._state=o.Error}),this.socket.on("pong",()=>{this.latency=Date.now()-this.pingTimestamp,this.log(`Ping: ${this.latency}ms`)})})}disconnect(){this.socket&&(this.log("Disconnecting..."),this.stopPingMonitor(),this.socket.disconnect(),this._state=o.Disconnected)}send(t,e){if(!t||typeof t!="string"){this.log(`Cannot send: invalid event name (${typeof t})`);return}if(!this.isConnected()||!this.socket){this.log(`Cannot send '${t}': not connected`);return}try{this.socket.volatile.emit(t,e)}catch(n){this.log(`Error sending '${t}':`,n)}}on(t,e){if(!t||typeof t!="string")throw new Error(`Invalid event name: ${t}`);if(typeof e!="function")throw new Error(`Invalid handler for event '${t}': must be a function`);if(!this.socket){this.log(`Cannot listen to '${t}': socket not initialized`);return}this.socket.on(t,e),this.log(`Listening to '${t}'`)}off(t,e){this.socket&&(this.socket.off(t,e),this.log(`Stopped listening to '${t}'`))}removeAllListeners(t){this.socket&&(t?(this.socket.removeAllListeners(t),this.log(`Removed all listeners for '${t}'`)):(this.socket.removeAllListeners(),this.log("Removed all listeners")))}async request(t,e,n=5e3){if(!t||typeof t!="string")throw new Error(`Invalid event name: ${t}`);if(!Number.isFinite(n)||n<=0)throw new Error(`Invalid timeout: ${n} (must be a positive number)`);if(!this.isConnected())throw new Error("Cannot send request: not connected to server");return new Promise((m,u)=>{let r=`${t}_response`,d=setTimeout(()=>{this.off(r,c),u(new Error(`Request timeout after ${n}ms: ${t}`))},n),c=a(p=>{clearTimeout(d),this.off(r,c),m(p)},"responseHandler");this.on(r,c),this.send(t,e),this.log(`Request sent: ${t} (timeout: ${n}ms)`)})}getPing(){return this.latency}destroy(){this.log("Destroying client..."),this.stopPingMonitor(),this.socket&&(this.socket.removeAllListeners(),this.socket.disconnect(),this.socket=null),this._state=o.Disconnected,this.log("Client destroyed")}startPingMonitor(){this.pingInterval||(this.pingInterval=setInterval(()=>{this.isConnected()&&this.socket&&(this.pingTimestamp=Date.now(),this.socket.emit("ping"))},2e3),this.log("Ping monitor started"))}stopPingMonitor(){this.pingInterval&&(clearInterval(this.pingInterval),this.pingInterval=null,this.log("Ping monitor stopped"))}log(t,e){this.options.debug&&(e!==void 0?console.warn(`[SocketIOClient] ${t}`,e):console.warn(`[SocketIOClient] ${t}`))}};a(h,"SocketIOClient");var l=h;export{E as NetworkState,l as SocketIOClient};