aboutsummaryrefslogtreecommitdiffstats
path: root/backend/src/websocket
diff options
context:
space:
mode:
authorLeonardo Bishop <me@leonardobishop.com>2023-11-09 00:17:03 +0000
committerLeonardo Bishop <me@leonardobishop.com>2023-11-09 00:17:03 +0000
commit1f101fe7cc5cc31c66146a1e226fa4bae805fdd4 (patch)
treee1d533f686741bf0c7a446ba8ada1ac66a2051ef /backend/src/websocket
parent28f705fc4aa2f3c62e7fe7d95557494bedcb8d1c (diff)
Refactor websockets
Diffstat (limited to 'backend/src/websocket')
-rw-r--r--backend/src/websocket/coop.ts142
-rw-r--r--backend/src/websocket/game.ts97
-rw-r--r--backend/src/websocket/websocket-router.ts18
3 files changed, 160 insertions, 97 deletions
diff --git a/backend/src/websocket/coop.ts b/backend/src/websocket/coop.ts
new file mode 100644
index 0000000..ce8bfa0
--- /dev/null
+++ b/backend/src/websocket/coop.ts
@@ -0,0 +1,142 @@
+import {
+ addSessionClient,
+ createNewSession,
+ getSession,
+ setSessionState,
+} from "../config/coop-session-store.js";
+import { WebSocketServer } from "ws";
+import { v4 as uuidv4 } from "uuid";
+import { IncomingMessage } from "http";
+import { CoopWebSocket } from "../model/websocket.js";
+import { parse } from "url";
+import {
+ ClientJoinedCoopSessionMessage,
+ CoopSessionCreatedMessage,
+ CoopSessionMessage,
+ CoopSessionMoveMessage,
+ CoopSessionMoveTimeoutMessage,
+ CoopSessionStateChangeMessage,
+} from "../model/actions/coop.js";
+
+export const wss = new WebSocketServer({ noServer: true });
+
+const sendMessageToClient = (
+ client: CoopWebSocket,
+ message: CoopSessionMessage
+) => {
+ if (client.readyState === client.OPEN) {
+ client.send(JSON.stringify(message));
+ console.log(
+ `Sent message to client ${client.clientId}: ${JSON.stringify(message)}}`
+ );
+ }
+};
+
+wss.on("connection", (ws: CoopWebSocket, req: IncomingMessage) => {
+ ws.clientId = uuidv4();
+
+ const url = parse(req.url!, true);
+
+ if (url.query.action === "create") {
+ const session = createNewSession(ws);
+ sendMessageToClient(ws, <CoopSessionCreatedMessage>{
+ type: "create",
+ payload: {
+ sessionId: session.id,
+ },
+ });
+ ws.sessionId = session.id;
+ } else if (url.query.action === "join") {
+ const session = getSession(url.query.sessionId as string);
+ if (!session) {
+ ws.close();
+ return;
+ }
+
+ addSessionClient(url.query.sessionId as string, ws);
+
+ sendMessageToClient(session.host, <ClientJoinedCoopSessionMessage>{
+ type: "join",
+ payload: {
+ numberOfClients: session.clients.length,
+ },
+ });
+ sendMessageToClient(ws, <CoopSessionStateChangeMessage>{
+ type: "state",
+ payload: {
+ state: session.state,
+ },
+ });
+
+ ws.sessionId = session.id;
+ } else {
+ ws.close();
+ return;
+ }
+
+ ws.on("message", (message) => {
+ console.log(`Received message from client ${ws.clientId}: ${message}`);
+ let data: any;
+ try {
+ data = JSON.parse(message.toString());
+ } catch (e) {
+ return;
+ }
+
+ const session = getSession(ws.sessionId);
+ if (!session) {
+ return;
+ }
+
+ const type = data.type as string;
+ const payload = data.payload as any;
+
+ if (!type || !payload) {
+ return;
+ }
+
+ if (type === "move") {
+ if (Date.now() - ws.nextMoveTimestamp < 0) {
+ return;
+ }
+
+ sendMessageToClient(session.host, <CoopSessionMoveMessage>{
+ type: "move",
+ payload: {
+ move: payload.move,
+ },
+ });
+
+ ws.nextMoveTimestamp = Date.now() + 1000;
+
+ sendMessageToClient(ws, <CoopSessionMoveTimeoutMessage>{
+ type: "timeout",
+ payload: {
+ timeoutUntil: ws.nextMoveTimestamp,
+ },
+ });
+ } else if (type === "start") {
+ session.state = "playing";
+
+ [session.host, ...session.clients].forEach((client) => {
+ sendMessageToClient(client, <CoopSessionStateChangeMessage>{
+ type: "state",
+ payload: {
+ state: "playing",
+ },
+ });
+ });
+ } else if (type === "end") {
+ session.state = "finished";
+
+ [session.host, ...session.clients].forEach((client) => {
+ sendMessageToClient(client, <CoopSessionStateChangeMessage>{
+ type: "state",
+ payload: {
+ state: "finished",
+ },
+ });
+ });
+ }
+ });
+});
diff --git a/backend/src/websocket/game.ts b/backend/src/websocket/game.ts
deleted file mode 100644
index c37b1c5..0000000
--- a/backend/src/websocket/game.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { Server } from "http";
-import { addSessionClient, getSession, setSessionHost, setSessionState } from "../config/session-store.js";
-import { WebSocketServer } from "ws";
-import { v4 as uuidv4 } from "uuid";
-
-const wss = new WebSocketServer({ noServer: true });
-
-const sendToClient = (clientId: string, message: any) => {
- wss.clients.forEach((client: any) => {
- if (client.clientId === clientId) {
- client.send(JSON.stringify(message));
- }
- });
-};
-
-const broadcastToClients = (clientIds: string[], message: any) => {
- wss.clients.forEach((client: any) => {
- if (clientIds.includes(client.clientId)) {
- client.send(JSON.stringify(message));
- }
- });
-};
-
-export const createWebsocketServer = (server: Server): WebSocketServer => {
- server.on("upgrade", (req, socket, head) => {
- wss.handleUpgrade(req, socket, head, (ws) => {
- wss.emit("connection", ws, req);
- });
- });
-
- wss.on("connection", (ws: any) => {
- ws.clientId = uuidv4();
-
- ws.on("message", (message) => {
- console.log("received: %s", message);
- let data;
- try {
- data = JSON.parse(message.toString());
- } catch (e) {
- console.log("Invalid JSON");
- return;
- }
-
- if (data.action === "host") {
- setSessionHost(data.sessionId, ws.clientId);
- } else if (data.action === "move") {
- const session = getSession(data.sessionId);
- if (!session) {
- return;
- }
-
- sendToClient(session.host!, {
- action: "move",
- move: data.move,
- });
- } else if (data.action === "join") {
- const session = getSession(data.sessionId);
- if (!session) {
- return;
- }
-
- addSessionClient(data.sessionId, ws.clientId);
-
- sendToClient(session.host!, {
- action: "join",
- clients: session.clients.length,
- });
-
- ws.send(JSON.stringify({
- action: "state",
- state: session.state,
- }));
- } else if (data.action === "start") {
- const session = getSession(data.sessionId);
- if (!session) {
- return;
- }
-
- setSessionState(data.sessionId, "playing");
-
- sendToClient(session.host!, {
- action: "state",
- state: "playing",
- });
-
- broadcastToClients(session.clients, {
- action: "state",
- state: "playing",
- });
- }
- });
- });
-
- return wss;
-};
-
-export default createWebsocketServer;
diff --git a/backend/src/websocket/websocket-router.ts b/backend/src/websocket/websocket-router.ts
new file mode 100644
index 0000000..0b11985
--- /dev/null
+++ b/backend/src/websocket/websocket-router.ts
@@ -0,0 +1,18 @@
+import { Server } from "http";
+import { wss as gameServer } from "./coop.js";
+
+export const createWebsocketServer = (server: Server) => {
+
+ server.on("upgrade", (req, socket, head) => {
+ if (req.url?.startsWith("/coop")) {
+ gameServer.handleUpgrade(req, socket, head, (ws) => {
+ gameServer.emit("connection", ws, req);
+ });
+ } else {
+ socket.destroy();
+ }
+ });
+
+};
+
+export default createWebsocketServer;