@utsp/network-server
Version:
UTSP Network Server - Server-side communication adapters
2 lines (1 loc) • 6.08 kB
JavaScript
var c=Object.defineProperty;var v=(s,e,t)=>e in s?c(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var h=(s,e)=>c(s,"name",{value:e,configurable:!0});var r=(s,e,t)=>(v(s,typeof e!="symbol"?e+"":e,t),t);import{Server as p}from"socket.io";import{createServer as u}from"http";var l=class l{constructor(e){r(this,"io",null);r(this,"httpServer",null);r(this,"options");r(this,"running",!1);r(this,"clients",new Map);r(this,"clientData",new Map);r(this,"connectionHandlers",[]);r(this,"disconnectionHandlers",[]);r(this,"eventHandlers",new Map);r(this,"stats",{totalConnections:0,startTime:0});if(!Number.isInteger(e.port)||e.port<0||e.port>65535)throw new Error(`SocketIOServer: Invalid port ${e.port} - must be an integer between 0 and 65535`);if(e.maxConnections!==void 0&&(!Number.isInteger(e.maxConnections)||e.maxConnections<=0))throw new Error(`SocketIOServer: Invalid maxConnections ${e.maxConnections} - must be a positive integer`);if(e.pingInterval!==void 0&&(!Number.isFinite(e.pingInterval)||e.pingInterval<=0))throw new Error(`SocketIOServer: Invalid pingInterval ${e.pingInterval} - must be a positive number`);if(e.pingTimeout!==void 0&&(!Number.isFinite(e.pingTimeout)||e.pingTimeout<=0))throw new Error(`SocketIOServer: Invalid pingTimeout ${e.pingTimeout} - must be a positive number`);this.options={port:e.port,host:e.host??"0.0.0.0",cors:e.cors??{origin:"*"},maxConnections:e.maxConnections??1e3,pingInterval:e.pingInterval??25e3,pingTimeout:e.pingTimeout??5e3,debug:e.debug??!1},this.log("Server initialized",{port:this.options.port,host:this.options.host,maxConnections:this.options.maxConnections})}isRunning(){return this.running}async start(){if(this.running){this.log("Server already running");return}return this.log(`Starting server on ${this.options.host}:${this.options.port}...`),new Promise((e,t)=>{try{this.httpServer=u(),this.io=new p(this.httpServer,{cors:this.options.cors,pingInterval:this.options.pingInterval,pingTimeout:this.options.pingTimeout,maxHttpBufferSize:1e6}),this.io.on("connection",n=>{this.handleConnection(n)}),this.httpServer.listen(this.options.port,this.options.host,()=>{this.running=!0,this.stats.startTime=Date.now(),this.log(`Server started on ${this.options.host}:${this.options.port}`),e()}),this.httpServer.on("error",n=>{this.log(`Server error: ${n.message}`),t(n)})}catch(n){t(n)}})}async stop(){if(this.running)return this.log("Stopping server..."),new Promise(e=>{this.clients.forEach(t=>{t.disconnect(!0)}),this.clients.clear(),this.clientData.clear(),this.io&&(this.io.close(()=>{this.log("Socket.IO server closed")}),this.io=null),this.httpServer?(this.httpServer.close(()=>{this.log("HTTP server closed"),this.running=!1,e()}),this.httpServer=null):(this.running=!1,e())})}getClients(){return Array.from(this.clients.keys())}getClientInfo(e){let t=this.clients.get(e);return t?{id:e,connectedAt:t.connectedAt||Date.now(),address:t.handshake.address,data:this.clientData.get(e)||{}}:null}sendToClient(e,t,n){let i=this.clients.get(e);if(!i){this.log(`Cannot send to client ${e}: not found`);return}i.emit(t,n)}sendToClientVolatile(e,t,n){let i=this.clients.get(e);if(!i){this.log(`Cannot send volatile to client ${e}: not found`);return}i.compress(!1).emit(t,n)}broadcast(e,t){this.io&&(this.io.emit(e,t),this.log(`Broadcast '${e}' to all clients`))}broadcastVolatile(e,t){this.io&&(this.io.volatile.emit(e,t),this.log(`Broadcast volatile '${e}' to all clients`))}broadcastExcept(e,t,n){let i=this.clients.get(e);i&&(i.broadcast.emit(t,n),this.log(`Broadcast '${t}' except ${e}`))}sendToRoom(e,t,n){this.io&&(this.io.to(e).emit(t,n),this.log(`Sent '${t}' to room '${e}'`))}joinRoom(e,t){let n=this.clients.get(e);n&&(n.join(t),this.log(`Client ${e} joined room '${t}'`))}leaveRoom(e,t){let n=this.clients.get(e);n&&(n.leave(t),this.log(`Client ${e} left room '${t}'`))}getRoomClients(e){if(!this.io)return[];let t=this.io.sockets.adapter.rooms.get(e);return t?Array.from(t):[]}disconnectClient(e,t="Server disconnect"){let n=this.clients.get(e);n&&(n.disconnect(!0),this.log(`Disconnected client ${e}: ${t}`))}on(e,t){let n=this.eventHandlers.get(e)||[];n.push(t),this.eventHandlers.set(e,n),this.log(`Registered handler for '${e}'`)}onConnect(e){this.connectionHandlers.push(e),this.log("Registered connection handler")}onDisconnect(e){this.disconnectionHandlers.push(e),this.log("Registered disconnection handler")}off(e,t){let n=this.eventHandlers.get(e);if(!n)return;let i=n.indexOf(t);i!==-1&&(n.splice(i,1),this.log(`Removed handler for '${e}'`))}setClientData(e,t,n){let i=this.clientData.get(e)||{};i[t]=n,this.clientData.set(e,i)}getClientData(e,t){let n=this.clientData.get(e);return n?n[t]:void 0}getStats(){return{connectedClients:this.clients.size,totalConnections:this.stats.totalConnections,uptime:Date.now()-this.stats.startTime}}async destroy(){await this.stop(),this.connectionHandlers=[],this.disconnectionHandlers=[],this.eventHandlers.clear(),this.log("Server destroyed")}handleConnection(e){let t=e.id;if(this.log(`Client connected: ${t}`),this.clients.size>=this.options.maxConnections){this.log(`Max connections reached, rejecting ${t}`),e.emit("error",{code:"MAX_CONNECTIONS",message:"Server is full"}),e.disconnect(!0);return}this.clients.set(t,e),this.clientData.set(t,{}),e.connectedAt=Date.now(),this.stats.totalConnections++,this.setupClientHandlers(e),this.connectionHandlers.forEach(n=>{try{n(t)}catch(i){this.log(`Error in connection handler: ${i}`)}}),e.on("ping",()=>{e.emit("pong")})}setupClientHandlers(e){let t=e.id;e.on("disconnect",n=>{this.log(`Client disconnected: ${t} (${n})`),this.clients.delete(t),this.clientData.delete(t),this.disconnectionHandlers.forEach(i=>{try{i(t,n)}catch(o){this.log(`Error in disconnection handler: ${o}`)}})}),this.eventHandlers.forEach((n,i)=>{e.on(i,o=>{n.forEach(d=>{try{d(t,o)}catch(g){this.log(`Error in event handler for '${i}': ${g}`)}})})})}log(e,t){this.options.debug&&(t!==void 0?console.warn(`[SocketIOServer] ${e}`,t):console.warn(`[SocketIOServer] ${e}`))}};h(l,"SocketIOServer");var a=l;export{a as SocketIOServer};