104 lines
2.7 KiB
JavaScript
104 lines
2.7 KiB
JavaScript
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);
|
|
});
|
|
});
|