Files
lst_v3/backend/socket.io/serverSetup.ts
2026-03-27 18:30:50 -05:00

141 lines
3.3 KiB
TypeScript

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",
});
};