refactor(socket.io): complete rewrite to manage dynamic rooms and seeding better

This commit is contained in:
2026-06-10 16:25:48 -05:00
parent a2d9a6c127
commit 9440b44f3b
7 changed files with 271 additions and 315 deletions

View File

@@ -1,33 +1,16 @@
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 { auth } from "../utils/auth.utils.js";
import { allowedOrigins } from "../utils/cors.utils.js";
import { registerEmitter } from "./roomEmitter.socket.js";
import {
createRoomEmitter,
preseedRoom,
registerRoomService,
} from "./roomService.socket.js";
import { registerHasRoomMembers } from "./socket.manager.js";
import { isRoomKey, roomConfigs } from "./socket.roomConfig.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 { getRoomConfig } 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`,
@@ -37,12 +20,16 @@ export const setupSocketIORoutes = (baseUrl: string, server: HttpServer) => {
},
});
// manage members of the rooms.
registerRoomService(io);
registerHasRoomMembers((roomId) => {
return (io.sockets.adapter.rooms.get(roomId)?.size ?? 0) > 0;
});
// ✅ Create emitter instance
const { addDataToRoom } = createRoomEmitter(io);
registerEmitter(addDataToRoom);
registerEmitter((roomId, payloads) => {
io.to(roomId).emit("room-update", {
roomId,
payloads,
});
});
io.use(async (socket, next) => {
try {
@@ -85,79 +72,95 @@ export const setupSocketIORoutes = (baseUrl: string, server: HttpServer) => {
version: "1.0.0",
});
// s.on("join-room", async (rn) => {
// const config = protectedRooms[rn];
s.on("join-room", async ({ room, params }) => {
if (!isRoomKey(room)) return;
// 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];
// //if (config?.role && s.user?.role !== config.role) {
// if (config?.role && !roles.includes(s.user?.role)) {
// return s.emit("room-error", {
// roomId: 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("join-room", async (rn: string) => {
const config = getRoomConfig(rn);
const config = roomConfigs[room];
if (!config) {
return s.emit("room-error", {
roomId: rn,
message: `Unknown room: ${rn}`,
roomId: room,
message: `Unknown room: ${room}`,
});
}
if (config.requiresAuth && !s.user) {
const actualRoom = config.buildRoom
? config.buildRoom(params)
: (room as any);
const allowed = config.canJoin
? await config.canJoin({
socket: s,
user: s.user,
room,
actualRoom,
params,
})
: true;
if (!allowed) {
return s.emit("room-error", {
roomId: rn,
message: "Authentication required",
roomId: room,
message: `Not authorized to be in room: ${room}`,
});
}
const roles = Array.isArray(config.role) ? config.role : [];
await s.join(actualRoom);
if (roles.length > 0 && !roles.includes(s.user?.role)) {
return s.emit("room-error", {
roomId: rn,
message: `Not authorized to be in room: ${rn}`,
});
}
s.join(rn);
const history = await preseedRoom(rn as any);
log.info({}, `User joined ${rn}: ${s.id}`);
s.emit("room-update", {
roomId: rn,
payloads: history,
initial: true,
s.emit("room-joined", {
room,
roomId: actualRoom,
params,
});
if (config.seed) {
const payloads = await config.seed({
room,
actualRoom,
params,
user: s.user,
});
s.emit("room-update", {
room,
roomId: actualRoom,
type: "snapshot",
payloads,
});
}
log.info(
{ room, actualRoom, params },
`User joined ${actualRoom}: ${s.id}`,
);
});
s.on("leave-room", (room) => {
s.leave(room);
log.info({}, `${s.id} left room: ${room}`);
// s.on("leave-room", (room) => {
// s.leave(room);
// log.info({}, `${s.id} left room: ${JSON.stringify(room)}`);
// });
s.on("leave-room", async ({ room, params }) => {
if (!isRoomKey(room)) return;
const config = roomConfigs[room];
if (!config) return;
const actualRoom = config.buildRoom
? config.buildRoom(params)
: (room as any);
await s.leave(actualRoom);
s.emit("room-left", {
room,
roomId: actualRoom,
params,
});
log.info(
{ room, actualRoom, params },
`${s.id} left room: ${actualRoom}`,
);
});
});