///
export function startServer(
hostname: string = "localhost",
port: number = 8042,
): () => Promise {
let nextId = 1;
const clientsMap = new Map();
const clientRoomMap = new Map();
const roomsMap = new Map();
const broadcast = (room: string, message: string): void => {
const members = roomsMap.get(room)!;
for (const member of members) {
const socket = clientsMap.get(member);
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(message);
}
}
};
const commands = {
join: (id: number, args: string[]) => {
const room = args[0];
if (roomsMap.has(room)) {
roomsMap.get(room)!.push(id);
} else {
roomsMap.set(room, [id]);
}
clientRoomMap.getOrInsert(id, room); // not sure about that
broadcast(room, `${id} has joined!`);
},
} as const;
const handleConnection = (socket: WebSocket): void => {
const id = nextId++;
socket.onopen = () => {
clientsMap.set(id, socket);
socket.send(`Welcome ${id}, type /join .`);
};
socket.onclose = () => {
const room = clientRoomMap.get(id);
if (room) {
clientRoomMap.delete(id);
const members = roomsMap.get(room)!;
members.splice(members.indexOf(id), 1);
broadcast(room, `${id} has left!`);
}
clientsMap.delete(id);
};
socket.onmessage = (message: MessageEvent) => {
const text = String(message.data);
if (text.startsWith("/")) {
const [command, ...args] = text.substring(1).split(" ");
try {
// @ts-ignore
commands[command](id, args);
} catch (error) {
socket.send(JSON.stringify(error));
}
}
};
socket.onerror = console.error;
};
const ac = new AbortController();
const server = Deno.serve(
{ hostname, port, signal: ac.signal },
(request) => {
if (request.headers.get("upgrade") !== "websocket") {
return new Response("Upgrade Required", { status: 426 });
}
const { socket, response } = Deno.upgradeWebSocket(request);
handleConnection(socket);
return response;
},
);
return () => {
ac.abort();
return server.finished;
};
}