signaling/index.ts
2025-05-08 23:08:22 +02:00

96 lines
2.6 KiB
TypeScript

import { WebSocket, WebSocketServer } from 'ws';
import { ulid } from 'ulid';
const wss = new WebSocketServer({ port: 8080 });
const rooms = new Map<string, Set<string>>();
const sockets = new Map<string, WebSocket>();
wss.on('connection', (ws) => {
let peerId = ulid();
const join = (room: string) => {
if (!rooms.has(room)) {
rooms.set(room, new Set([peerId]));
} else {
rooms.get(room)!.add(peerId);
}
};
const unjoinAll = () => {
rooms.entries().forEach(([room, peers]) => {
peers.delete(peerId);
if (!peers.size) rooms.delete(room);
});
};
ws.on('message', (message) => {
try {
const text = message.toString('utf8');
const data = JSON.parse(text);
if (data.type === 'self') {
ws.send(JSON.stringify({
type: 'self',
id: peerId.toString(),
}));
return;
}
if (data.type === 'join' && typeof data.room === 'string') {
unjoinAll();
join(data.room);
const peers = rooms.get(data.room) ?? [];
peers.forEach((peer) => {
sockets.get(peer)!.send(JSON.stringify({
type: 'peers',
peers: peers,
}));
});
return;
}
if (data.type === 'offer' && typeof data.peer === 'string' && typeof data.offer === 'object') {
const otherWS = sockets.get(data.peer);
if (!otherWS) return;
otherWS.send(JSON.stringify({
type: 'offer',
from: peerId,
offer: data.offer,
}));
return;
}
if (data.type === 'accept' && typeof data.peer === 'string' && typeof data.counterOffer === 'object') {
const otherWS = sockets.get(data.peer);
if (!otherWS) return;
otherWS.send(JSON.stringify({
type: 'accept',
from: peerId,
counterOffer: data.counterOffer,
}));
return;
}
throw 0;
} catch (e) {
ws.send(JSON.stringify({
type: 'error',
message: 'Bad Request',
}));
}
});
ws.on('close', () => {
unjoinAll();
sockets.delete(peerId);
});
});