const { WebSocketServer } = require("ws"); const PORT = 3000; const wss = new WebSocketServer({ port: PORT }); // rooms: { roomId: { host: WebSocket, viewer: WebSocket } } const rooms = {}; console.log(`Pulsar signalling server listening on ws://localhost:${PORT}`); wss.on("connection", (ws) => { ws.roomId = null; ws.role = null; // "host" or "viewer" ws.on("message", (raw) => { let msg; try { msg = JSON.parse(raw); } catch { return; } const { type, roomId, data } = msg; switch (type) { case "create": { if (!roomId) return; if (rooms[roomId]) { ws.send(JSON.stringify({ type: "error", message: "Room already exists" })); return; } rooms[roomId] = { host: ws, viewer: null }; ws.roomId = roomId; ws.role = "host"; ws.send(JSON.stringify({ type: "created", roomId })); console.log(`Room created: ${roomId}`); break; } case "join": { if (!roomId || !rooms[roomId]) { ws.send(JSON.stringify({ type: "error", message: "Room not found" })); return; } const room = rooms[roomId]; if (room.viewer) { ws.send(JSON.stringify({ type: "error", message: "Room full" })); return; } room.viewer = ws; ws.roomId = roomId; ws.role = "viewer"; ws.send(JSON.stringify({ type: "joined", roomId })); room.host.send(JSON.stringify({ type: "peer_joined" })); console.log(`Viewer joined room: ${roomId}`); break; } case "signal": { if (!ws.roomId || !rooms[ws.roomId]) return; const room = rooms[ws.roomId]; const target = ws.role === "host" ? room.viewer : room.host; if (target && target.readyState === 1) { target.send(JSON.stringify({ type: "signal", data })); } break; } default: break; } }); ws.on("close", () => { if (!ws.roomId || !rooms[ws.roomId]) return; const room = rooms[ws.roomId]; if (ws.role === "host") { // notify viewer if connected if (room.viewer && room.viewer.readyState === 1) { room.viewer.send(JSON.stringify({ type: "host_disconnected" })); } delete rooms[ws.roomId]; console.log(`Room closed: ${ws.roomId}`); } else if (ws.role === "viewer") { room.viewer = null; if (room.host && room.host.readyState === 1) { room.host.send(JSON.stringify({ type: "peer_disconnected" })); } console.log(`Viewer left room: ${ws.roomId}`); } }); ws.on("error", (err) => { console.error("WebSocket error:", err.message); }); });