Source

socket/websocket-handlers.js

import { globalLogger } from "@config/logger";
import { ObjectId } from "mongodb";
import { randomUUID } from "node:crypto";
import { setupPhysicsHandlers } from "./handlers/physics";
import { WebSocketClient } from "./websocket-client";
/**
 * Handle new WebSocket connections
 * @param {WebSocket} ws - WebSocket instance
 * @param {IncomingMessage} request - HTTP request
 */
export function handleWebSocketConnection(ws, request) {
    const connectionId = randomUUID();
    const logger = globalLogger.child({ connectionId, transport: "websocket" });
    // Parse query parameters
    const url = new URL(request.url || "", "ws://localhost");
    const userId = url.searchParams.get("userId");
    const investigationId = url.searchParams.get("investigationId");
    const userName = url.searchParams.get("userName");
    // Validate userId
    if (!userId || !ObjectId.isValid(userId)) {
        logger.warn({ userId }, "Invalid userId");
        ws.send(JSON.stringify({ type: "error", data: { message: "Invalid userId parameter" } }));
        ws.close(1008, "Invalid userId");
        return;
    }
    // Create client
    const client = new WebSocketClient(ws, connectionId, userId, investigationId, logger);
    // Use dev-stage physics engine when connecting via api.dev-stage.k12.aaic.dev; otherwise default env host
    const requestHost = request.headers.host ?? "";
    const physicsEngineHost = requestHost.includes("api.dev-stage.k12.aaic.dev")
        ? "34.123.93.40"
        : undefined;
    logger.info({ userId, investigationId, userName }, "WebSocket client connected");
    // Setup handlers
    setupPhysicsHandlers(client, { physicsEngineHost });
    // Handle errors
    ws.on("error", (error) => {
        logger.error({ error }, "WebSocket error");
    });
    // Send connection ack
    client.send("connected", { connectionId, userId });
    logger.debug({ connectionId }, "WebSocket handlers registered");
}