import type { Server as HttpServer } from "node:http"; //import { dirname, join } from "node:path"; //import { fileURLToPath } from "node:url"; import { instrument } from "@socket.io/admin-ui"; import { Server } from "socket.io"; import { createLogger } from "../logger/logger.controller.js"; import { allowedOrigins } from "../utils/cors.utils.js"; import { registerEmitter } from "./roomEmitter.socket.js"; import { createRoomEmitter, preseedRoom } from "./roomService.socket.js"; //const __filename = fileURLToPath(import.meta.url); //const __dirname = dirname(__filename); const log = createLogger({ module: "socket.io", subModule: "setup" }); import { auth } from "../utils/auth.utils.js"; //import type { Session, User } from "better-auth"; // adjust if needed import { protectedRooms } from "./roomDefinitions.socket.js"; // declare module "socket.io" { // interface Socket { // user?: User | any; // session?: Session; // } // } export const setupSocketIORoutes = (baseUrl: string, server: HttpServer) => { const io = new Server(server, { path: `${baseUrl}/api/socket.io`, cors: { origin: allowedOrigins, credentials: true, }, }); // ✅ Create emitter instance const { addDataToRoom } = createRoomEmitter(io); registerEmitter(addDataToRoom); io.use(async (socket, next) => { try { //const cookieHeader = socket.handshake.headers.cookie; const headers = new Headers(); for (const [key, value] of Object.entries(socket.request.headers)) { if (typeof value === "string") { headers.set(key, value); } else if (Array.isArray(value)) { headers.set(key, value.join(", ")); } } const session = await auth.api.getSession({ headers, }); if (!session) { return next(); // allow connection, but no auth } if (session) { socket.user = session.user; socket.session = session as any; } next(); } catch (err) { next(); } }); io.on("connection", (s) => { log.info({}, `User connected: ${s.id}`); s.emit("welcome", { serverTime: Date.now(), availableRooms: ["logs", "labels"], version: "1.0.0", }); s.on("join-room", async (rn) => { const config = protectedRooms[rn]; if (config?.requiresAuth && !s.user) { return s.emit("room-error", { room: rn, message: "Authentication required", }); } const roles = Array.isArray(config.role) ? config.role : [config.role]; console.log(roles, s.user.role); //if (config?.role && s.user?.role !== config.role) { if (config?.role && !roles.includes(s.user?.role)) { return s.emit("room-error", { room: rn, message: `Not authorized to be in room: ${rn}`, }); } s.join(rn); // get room seeded const history = await preseedRoom(rn); log.info({}, `User joined ${rn}: ${s.id}`); // send the intial data s.emit("room-update", { roomId: rn, payloads: history, initial: true, }); }); s.on("leave-room", (room) => { s.leave(room); log.info({}, `${s.id} left room: ${room}`); }); }); io.on("disconnect", (s) => { log.info({}, "User disconnected:", s.id); }); // admin stuff const admin = io.of("/admin"); admin.on("connection", (s) => { log.info({}, `User connected: ${s.id}`); }); admin.on("disconnect", (s) => { log.info({}, "User disconnected:", s.id); }); instrument(io, { auth: false, //namespaceName: "/admin", }); };