t00-multiuser/server/index.ts

116 lines
3.9 KiB
TypeScript
Raw Normal View History

2024-04-18 23:18:49 +01:00
import { createReader, createWriter, Endian } from "bufferstuff";
import { WebSocketServer } from "ws";
import Config from "./objects/Config";
import FunkyArray from "./objects/FunkyArray";
2024-04-21 15:35:47 +01:00
import RemoteUser from "./objects/RemoteUser";
2024-04-18 23:18:49 +01:00
import { MessageType } from "./enums/MessageType";
2024-04-21 15:35:47 +01:00
import Database from "./objects/Database";
2024-04-22 02:01:14 +01:00
import { Console } from "hsconsole";
Console.customHeader(`MultiProbe server started at ${new Date()}`);
2024-04-18 23:18:49 +01:00
2024-04-21 15:35:47 +01:00
const users = new FunkyArray<string, RemoteUser>();
new Database(Config.database.address, Config.database.port, Config.database.username, Config.database.password, Config.database.name);
2024-04-18 23:18:49 +01:00
const server = new WebSocketServer({
port: Config.port
2024-04-22 02:01:14 +01:00
}, () => Console.printInfo(`Server listening at ${Config.port}`));
2024-04-18 23:18:49 +01:00
2024-04-21 15:35:47 +01:00
function sendToAllButSelf(user:RemoteUser, data:Buffer) {
2024-04-18 23:18:49 +01:00
users.forEach(otherUser => {
if (otherUser.id !== user.id && otherUser.currentURL === user.currentURL) {
otherUser.send(data);
}
});
}
2024-04-21 15:35:47 +01:00
function sendToAll(user:RemoteUser, data:Buffer) {
users.forEach(otherUser => {
if (otherUser.currentURL === user.currentURL) {
otherUser.send(data);
}
});
}
2024-04-18 23:18:49 +01:00
server.on("connection", (socket) => {
const myUUID = crypto.randomUUID();
2024-04-21 15:35:47 +01:00
let user:RemoteUser;
2024-04-18 23:18:49 +01:00
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();
const rawURL = reader.readString();
let page = rawURL.toLowerCase().replace(".htm", "").replace(".html", "");
2024-04-18 23:18:49 +01:00
if (page === "index") {
page = "";
}
let lengthOfUsernames = 0;
2024-04-21 15:35:47 +01:00
const usersOnPage = new Array<RemoteUser>();
2024-04-18 23:18:49 +01:00
await users.forEach(otherUser => {
if (otherUser.currentURL === page) {
usersOnPage.push(otherUser);
lengthOfUsernames += otherUser.username.length + 1; // + 1 for length byte
}
2024-04-18 23:18:49 +01:00
});
const usersToSend = createWriter(Endian.LE, 3 + (usersOnPage.length * 12) + lengthOfUsernames).writeByte(MessageType.Clients).writeUShort(usersOnPage.length);
for (const otherUser of usersOnPage) {
usersToSend.writeUInt(otherUser.id).writeShortString(otherUser.username).writeFloat(otherUser.cursorX).writeInt(otherUser.cursorY);
}
2024-04-21 15:35:47 +01:00
user = users.set(myUUID, new RemoteUser(socket, username, page, rawURL));
2024-04-18 23:18:49 +01:00
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;
}
user.cursorX = reader.readFloat();
user.cursorY = reader.readInt();
sendToAllButSelf(user, createWriter(Endian.LE, 13).writeByte(MessageType.CursorPos).writeUInt(user.id).writeFloat(user.cursorX).writeInt(user.cursorY).toBuffer());
2024-04-18 23:18:49 +01:00
break;
}
case MessageType.Ping:
{
if (user === undefined) {
return;
}
if ((Date.now() - user.lastPingReset) >= 1000) {
user.allowedPings = 10;
}
if (user.allowedPings > 0) {
user.allowedPings--;
const cursorX = reader.readFloat();
const cursorY = reader.readInt();
const packet = createWriter(Endian.LE, 9).writeByte(MessageType.Ping).writeFloat(cursorX).writeInt(cursorY).toBuffer();
sendToAll(user, packet);
}
2024-04-18 23:18:49 +01:00
break;
}
}
}
});
});