From 999980093a55edc99d7e49ae0c22e428dc2f082d Mon Sep 17 00:00:00 2001 From: Leo dev Date: Mon, 9 Feb 2026 00:37:40 +0100 Subject: [PATCH] typescript server.ts --- package.json | 7 ++-- server.mjs | 8 ++--- server.ts | 86 ++++++++++++++++++++++++++++++++++++++++++++ server.tsconfig.json | 16 +++++++++ 4 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 server.ts create mode 100644 server.tsconfig.json diff --git a/package.json b/package.json index c1ebad0..365da54 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,10 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "node server.mjs", - "build": "next build", - "start": "NODE_ENV=production node server.mjs" + "dev": "npm run buildserver && node ./.next/server.js", + "build": "npm run buildserver && next build", + "start": "npm run buildserver && NODE_ENV=production node ./.next/server.js", + "buildserver": "tsc -p server.tsconfig.json" }, "dependencies": { "@codemirror/lang-go": "^6.0.1", diff --git a/server.mjs b/server.mjs index add4783..988b8c6 100644 --- a/server.mjs +++ b/server.mjs @@ -11,7 +11,7 @@ app.prepare().then(() => { handle(req, res); }); - const clients = {}; + const runs = {}; const wss = new WebSocketServer({ noServer: true }); @@ -19,8 +19,8 @@ app.prepare().then(() => { wss.on('connection', (ws, req) => { ws.on('message', (msg) => { const runId = msg.toString(); - if (!clients[runId]) clients[runId] = [] - clients[runId].push(ws); + if (!runs[runId]) runs[runId] = { clients: [] } + runs[runId].clients.push(ws); }); }); @@ -33,7 +33,7 @@ app.prepare().then(() => { req.on('end', () => { const move = JSON.parse(body); - clients[move.runId]?.forEach(client => { + runs[move.runId]?.clients.forEach(client => { if (client.readyState === client.OPEN) { client.send(JSON.stringify(move.moves)); } diff --git a/server.ts b/server.ts new file mode 100644 index 0000000..56f1e16 --- /dev/null +++ b/server.ts @@ -0,0 +1,86 @@ +import { createServer, IncomingMessage } from "http"; +import next from "next"; +import { WebSocketServer, WebSocket } from "ws"; + +const dev = process.env.NODE_ENV !== "production"; +const app = next({ dev }); +const handle = app.getRequestHandler(); + +/** + * One run = many websocket clients + */ +type LiveRun = { + clients: Set; +}; + +const runs: Record = {}; + +app.prepare().then(() => { + const server = createServer((req, res) => { + handle(req, res); + }); + + const wss = new WebSocketServer({ noServer: true }); + + // WebSocket connections + wss.on("connection", (ws: WebSocket, req: IncomingMessage) => { + ws.on("message", (msg: Buffer) => { + const runId = msg.toString(); + + if (!runs[runId]) { + runs[runId] = { clients: new Set() }; + } + + runs[runId].clients.add(ws); + + ws.once("close", () => { + runs[runId]?.clients.delete(ws); + }); + }); + }); + + // Handle POST requests + server.on("request", (req, res) => { + if (req.method === "POST" && req.url === "/api/run/move") { + let body = ""; + + req.on("data", (chunk: Buffer) => { + body += chunk.toString(); + }); + + req.on("end", () => { + try { + const move: { + runId: string; + moves: unknown; + } = JSON.parse(body); + + runs[move.runId]?.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(move.moves)); + } + }); + + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ status: "ok" })); + } catch (err) { + res.writeHead(400); + res.end("Invalid JSON"); + } + }); + } + }); + + // Upgrade HTTP → WebSocket + server.on("upgrade", (req, socket, head) => { + if (req.url === "/api/view-run") { + wss.handleUpgrade(req, socket, head, (ws) => { + wss.emit("connection", ws, req); + }); + } + }); + + server.listen(3000, () => { + console.log("Server running on http://localhost:3000"); + }); +}); diff --git a/server.tsconfig.json b/server.tsconfig.json new file mode 100644 index 0000000..aaced07 --- /dev/null +++ b/server.tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "outDir": "./.next", + "target": "ES2020", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2020"], + "types": ["node"], + "skipLibCheck": true, + "incremental": false, + "composite": false + }, + "include": ["server.ts"] +}