import { createReader, createWriter, Endian } from "bufferstuff"; import { WebSocketServer } from "ws"; import Config from "./objects/Config"; import FunkyArray from "./objects/FunkyArray"; import User from "./objects/User"; import { MessageType } from "./enums/MessageType"; const users = new FunkyArray(); const server = new WebSocketServer({ port: Config.port }, () => console.log(`Server listening at ${Config.port}`)); function sendToAllButSelf(user:User, data:Buffer) { users.forEach(otherUser => { if (otherUser.id !== user.id && otherUser.currentURL === user.currentURL) { otherUser.send(data); } }); } server.on("connection", (socket) => { const myUUID = crypto.randomUUID(); let user:User; function closeOrError() { if (users.has(myUUID)) { users.remove(myUUID); const userLeftPacket = createWriter(Endian.LE, 5).writeByte(MessageType.ClientLeft).writeUInt(user.id).toBuffer(); users.forEach(otherUser => otherUser.send(userLeftPacket)); } } socket.on("close", closeOrError); socket.on("error", closeOrError); socket.on("message", async (data) => { const reader = createReader(Endian.LE, data as Buffer); // There is absolutely no reason we should ever get // more than 50 bytes legit. if (reader.length > 0 && reader.length < 50) { switch (reader.readUByte()) { case MessageType.ClientDetails: if (user !== undefined) { return; } const username = reader.readShortString(); let page = reader.readString().toLowerCase().replace(".htm", "").replace(".html", ""); if (page === "index") { page = ""; } let lengthOfUsernames = 0; await users.forEach(otherUser => { lengthOfUsernames += otherUser.username.length + 1; // + 1 for length byte }); const usersToSend = createWriter(Endian.LE, 3 + (users.length * 4) + lengthOfUsernames).writeByte(MessageType.Clients).writeUShort(users.length); await users.forEach(otherUser => { usersToSend.writeUInt(otherUser.id).writeShortString(otherUser.username); }); user = users.set(myUUID, new User(socket, username, page)); sendToAllButSelf(user, createWriter(Endian.LE, 6 + username.length).writeByte(MessageType.ClientJoined).writeUInt(user.id).writeShortString(username).toBuffer()); user.send(usersToSend.toBuffer()); break; case MessageType.CursorPos: { if (user === undefined) { return; } const cursorX = reader.readFloat(); const cursorY = reader.readInt(); sendToAllButSelf(user, createWriter(Endian.LE, 13).writeByte(MessageType.CursorPos).writeUInt(user.id).writeFloat(cursorX).writeInt(cursorY).toBuffer()); break; } case MessageType.Ping: { const cursorX = reader.readFloat(); const cursorY = reader.readInt(); const packet = createWriter(Endian.LE, 9).writeByte(MessageType.Ping).writeFloat(cursorX).writeInt(cursorY).toBuffer(); users.forEach(otherUser => { otherUser.send(packet); }); break; } } } }); });