187 lines
3.8 KiB
TypeScript
187 lines
3.8 KiB
TypeScript
import type { Server as HttpServer } from "node:http";
|
|
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 { registerHasRoomMembers } from "./socket.manager.js";
|
|
import { isRoomKey, roomConfigs } from "./socket.roomConfig.js";
|
|
|
|
const log = createLogger({ module: "socket.io", subModule: "setup" });
|
|
|
|
export const setupSocketIORoutes = (baseUrl: string, server: HttpServer) => {
|
|
const io = new Server(server, {
|
|
path: `${baseUrl}/api/socket.io`,
|
|
cors: {
|
|
origin: allowedOrigins,
|
|
credentials: true,
|
|
},
|
|
});
|
|
|
|
registerHasRoomMembers((roomId) => {
|
|
return (io.sockets.adapter.rooms.get(roomId)?.size ?? 0) > 0;
|
|
});
|
|
|
|
registerEmitter((roomId, payloads) => {
|
|
io.to(roomId).emit("room-update", {
|
|
roomId,
|
|
payloads,
|
|
});
|
|
});
|
|
|
|
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 ({ room, params }) => {
|
|
if (!isRoomKey(room)) return;
|
|
|
|
const config = roomConfigs[room];
|
|
|
|
if (!config) {
|
|
return s.emit("room-error", {
|
|
roomId: room,
|
|
message: `Unknown room: ${room}`,
|
|
});
|
|
}
|
|
|
|
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: room,
|
|
message: `Not authorized to be in room: ${room}`,
|
|
});
|
|
}
|
|
|
|
await s.join(actualRoom);
|
|
|
|
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: ${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}`,
|
|
);
|
|
});
|
|
});
|
|
|
|
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",
|
|
});
|
|
};
|