From ba0d062512f136e6e4861427cdeb5f8887b9176c Mon Sep 17 00:00:00 2001 From: Holly Date: Wed, 8 May 2024 01:02:18 +0100 Subject: [PATCH] defend against the client crapping out --- client/Terminal-00-Multiuser.user.js | 58 +++++++++++++++------------- server/index.ts | 11 ++++-- server/objects/RemoteUser.ts | 8 +++- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/client/Terminal-00-Multiuser.user.js b/client/Terminal-00-Multiuser.user.js index e443009..d3e49df 100644 --- a/client/Terminal-00-Multiuser.user.js +++ b/client/Terminal-00-Multiuser.user.js @@ -461,35 +461,39 @@ kbd { let timeLastFrame = performance.now(); let frameDeltaTime = 0; let timeSinceLastPingReset = performance.now(); - function animate() { - frameDeltaTime = (performance.now() - timeLastFrame) * 0.001; - - if (ws && ready) { - if (currentMouseX !== oldMouseX || currentMouseY !== oldMouseY) { - if ((performance.now() - lastSendTime) >= 41) { - lastSendTime = performance.now(); - oldMouseX = currentMouseX; - oldMouseY = currentMouseY; - ws.send(createWriter(Endian.LE, 9).writeByte(MessageType.CursorPos).writeFloat(oldMouseX / clientWidth).writeInt(currentMouseY).toBuffer()); + try { + function animate() { + frameDeltaTime = (performance.now() - timeLastFrame) * 0.001; + + if (ws && ready) { + if (currentMouseX !== oldMouseX || currentMouseY !== oldMouseY) { + if ((performance.now() - lastSendTime) >= 41) { + lastSendTime = performance.now(); + oldMouseX = currentMouseX; + oldMouseY = currentMouseY; + ws.send(createWriter(Endian.LE, 9).writeByte(MessageType.CursorPos).writeFloat(oldMouseX / clientWidth).writeInt(currentMouseY).toBuffer()); + } } } + + if ((performance.now() - timeSinceLastPingReset) >= 1000) { + allowedPings = 10; + timeSinceLastPingReset = performance.now(); + } + + remoteClients.forEach(remoteUser => { + remoteUser.actualX = lerp(remoteUser.actualX, remoteUser.targetX, 20 * frameDeltaTime); + remoteUser.actualY = lerp(remoteUser.actualY, remoteUser.targetY, 20 * frameDeltaTime); + remoteUser.updateCursor(); + }); + + requestAnimationFrame(animate); + timeLastFrame = performance.now(); } - - if ((performance.now() - timeSinceLastPingReset) >= 1000) { - allowedPings = 10; - timeSinceLastPingReset = performance.now(); - } - - remoteClients.forEach(remoteUser => { - remoteUser.actualX = lerp(remoteUser.actualX, remoteUser.targetX, 20 * frameDeltaTime); - remoteUser.actualY = lerp(remoteUser.actualY, remoteUser.targetY, 20 * frameDeltaTime); - remoteUser.updateCursor(); - }); - - requestAnimationFrame(animate); - timeLastFrame = performance.now(); + animate(); + } catch (e) { + console.error(e); } - animate(); let windowContainer = null; @@ -622,7 +626,9 @@ kbd { setTimeout(() => doConnect(localStorage["mpapikey"]), 5000); } ws.onclose = onCloseAndError; - ws.onerror = onCloseAndError; + ws.onerror = (e) => { + console.error(e); + } } function createOnlineDialog() { diff --git a/server/index.ts b/server/index.ts index 641d8a1..bffe474 100644 --- a/server/index.ts +++ b/server/index.ts @@ -411,10 +411,13 @@ websocketServer.on("connection", (socket) => { 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 < 1024) { switch (reader.readByte()) { + case MessageType.KeepAlive: + { + user.lastKeepAliveTime = Date.now(); + break; + } case MessageType.ClientDetails: { if (user !== undefined) { @@ -449,9 +452,9 @@ websocketServer.on("connection", (socket) => { usersToSend.writeUInt(otherUser.id).writeShortString(otherUser.username).writeFloat(otherUser.cursorX).writeInt(otherUser.cursorY); } if (dbParty) { - user = users.set(myUUID, new RemoteUser(socket, dbUser.Username, page, rawURL, dbUser.Id, dbParty.Id, dbParty.Name)); + user = users.set(myUUID, new RemoteUser(socket, myUUID, dbUser.Username, page, rawURL, dbUser.Id, dbParty.Id, dbParty.Name)); } else { - user = users.set(myUUID, new RemoteUser(socket, dbUser.Username, page, rawURL, dbUser.Id, Number.MIN_VALUE, "")); + user = users.set(myUUID, new RemoteUser(socket, myUUID, dbUser.Username, page, rawURL, dbUser.Id, Number.MIN_VALUE, "")); } sendToAllButSelf(user, createWriter(Endian.LE, 6 + dbUser.Username.length).writeByte(MessageType.ClientJoined).writeUInt(user.id).writeShortString(dbUser.Username).toBuffer()); user.send(usersToSend.toBuffer()); diff --git a/server/objects/RemoteUser.ts b/server/objects/RemoteUser.ts index 24b15a6..c590768 100644 --- a/server/objects/RemoteUser.ts +++ b/server/objects/RemoteUser.ts @@ -3,7 +3,8 @@ import { WebSocket } from "ws"; export default class RemoteUser { private static USER_IDS = 0; - private readonly socket:WebSocket; + public readonly socket:WebSocket; + public readonly connectionUUID:string; public readonly id:number; public readonly username:string; public readonly currentURL:string; @@ -15,9 +16,11 @@ export default class RemoteUser { public userId:number; public groupId:number = Number.MIN_VALUE; public groupName:string; + public lastKeepAliveTime:number; - constructor(socket:WebSocket, username:string, currentURL:string, rawURL:string, userId:number, groupId:number, groupName:string) { + constructor(socket:WebSocket, connectionUUID:string, username:string, currentURL:string, rawURL:string, userId:number, groupId:number, groupName:string) { this.socket = socket; + this.connectionUUID = connectionUUID; this.id = RemoteUser.USER_IDS++; this.username = username; this.currentURL = currentURL; @@ -27,6 +30,7 @@ export default class RemoteUser { this.userId = userId; this.groupId = groupId; this.groupName = groupName; + this.lastKeepAliveTime = Date.now(); } send(data:Buffer) {