Source

socket/websocket-server.js

import { globalLogger } from "@config/logger";
import { WebSocketServer } from "ws";
import { handleWebSocketConnection } from "./websocket-handlers";
/**
 * Create a general-purpose WebSocket server for Unity WebGL and other platforms
 * @param {HTTPServer} httpServer - HTTP server instance to attach WebSocket server to
 * @returns {WebSocketServer} WebSocketServer instance
 */
export function createWebSocketServer(httpServer) {
    const wss = new WebSocketServer({
        server: httpServer,
        path: "/ws",
        perMessageDeflate: false, // Lower latency
        maxPayload: 1 * 1024 * 1024, // 1MB limit
    });
    wss.on("connection", (ws, request) => {
        const socket = ws;
        socket.isAlive = true;
        ws.on("pong", () => {
            socket.isAlive = true;
            globalLogger.debug({ remoteAddress: request.socket.remoteAddress }, "WebSocket pong");
        });
        ws.on("error", (error) => {
            globalLogger.error({ error }, "WebSocket connection error");
        });
        ws.on("close", (code, reason) => {
            globalLogger.info({ code, reason: reason?.toString("utf8") }, "WebSocket connection closed");
        });
        handleWebSocketConnection(ws, request);
    });
    const heartbeat = setInterval(() => {
        wss.clients.forEach((client) => {
            const socket = client;
            if (socket.isAlive === false) {
                globalLogger.warn("WebSocket heartbeat failed, terminating client");
                socket.terminate();
                return;
            }
            socket.isAlive = false;
            globalLogger.debug("WebSocket ping");
            socket.ping();
        });
    }, 30000);
    wss.on("close", () => {
        clearInterval(heartbeat);
    });
    wss.on("error", (error) => {
        globalLogger.error({ error }, "WebSocket server error");
    });
    globalLogger.info("General-purpose WebSocket server initialized on /ws");
    return wss;
}