Fix really weird bug where clients just don't visit / when they visit /, somehow. I worked around it by having new WS connections to non-existent games just create the game.

This commit is contained in:
sepia 2025-07-29 20:06:50 -05:00
parent 55b16f6712
commit fcc2bdd5f0
3 changed files with 123 additions and 9 deletions

114
src/.fuse_hidden0000421900000085 Executable file
View File

@ -0,0 +1,114 @@
import { Elysia, t } from 'elysia';
import { html } from '@elysiajs/html';
import { staticPlugin } from '@elysiajs/static';
import { cookie } from '@elysiajs/cookie';
import { WebSocketHandler } from './web-socket-handler';
import { ElysiaWS } from 'elysia/dist/ws';
import { createStoneSvg } from './view/board-renderer';
const wsHandler = new WebSocketHandler();
export type WS = ElysiaWS<{ query: { playerId: string; gameId: string } }>;
const app = new Elysia()
.use(
staticPlugin({
assets: './public',
prefix: '/',
}),
)
.use(cookie())
.use(html())
.ws('/ws', {
query: t.Object({
gameId: t.String(),
playerId: t.String(),
}),
open(ws) {
wsHandler.handleConnection(ws);
},
message(ws, message) {
wsHandler.handleMessage(ws, message);
},
close(ws) {
wsHandler.handleDisconnect(ws);
},
})
.get('/', async ({ query, cookie, request: _request }) => {
let playerId: string;
const existingPlayerId = cookie.playerId?.value;
if (existingPlayerId) {
playerId = existingPlayerId;
console.log(`Using existing playerId from cookie: ${playerId}`);
} else {
playerId = `player-${Math.random().toString(36).substring(2, 9)}`;
cookie.playerId.set({
value: playerId,
httpOnly: true,
path: '/',
maxAge: 30 * 24 * 60 * 60,
});
console.log(`Generated new playerId and set cookie: ${playerId}`);
}
let gameId = query.gameId as string | undefined;
let gameIdInitialized = false;
if (gameId) {
if (!wsHandler.hasGame(gameId)) {
wsHandler.createGame(gameId);
console.log(`Created new game with provided ID: ${gameId}`);
}
} else {
gameId = wsHandler.createGame();
gameIdInitialized = true;
console.log(`Created new game without specific ID: ${gameId}`);
}
if (gameIdInitialized) {
return new Response(null, {
status: 302,
headers: { Location: `/?gameId=${gameId}` },
});
}
const displayName = wsHandler.getPlayerName(playerId);
const htmlTemplate = await Bun.file('./public/index.html').text();
let finalHtml = htmlTemplate
.replace(
'<meta name="gameId" content="" />',
`<meta name="gameId" content="${gameId}" />`,
)
.replace(
'<meta name="playerId" content="" />',
`<meta name="playerId" content="${playerId}" />`,
)
.replace(
'<meta name="displayName" content="" />',
`<meta name="displayName" content="${displayName}" />`,
);
return new Response(finalHtml, {
headers: { 'Content-Type': 'text/html' },
status: 200,
});
})
.get('/black-stone.svg', () => {
const stoneSvg = createStoneSvg('black', false);
return new Response(String(stoneSvg), {
headers: { 'Content-Type': 'image/svg+xml' },
status: 200,
});
})
.get('/white-stone.svg', () => {
const stoneSvg = createStoneSvg('white', false);
return new Response(String(stoneSvg), {
headers: { 'Content-Type': 'image/svg+xml' },
status: 200,
});
});
const port = Number(process.env.PORT || 3000);
app.listen(port, () => {
console.log(`🦊 Elysia is running at ${app.server?.hostname}:${port}`);
});

View File

@ -51,19 +51,18 @@ const app = new Elysia()
}
let gameId = query.gameId as string | undefined;
let gameIdInitialized = false;
if (gameId) {
if (!wsHandler.hasGame(gameId)) {
wsHandler.createGame(gameId);
console.log(`Created new game with provided ID: ${gameId}`);
} else {
console.log(`Player ${playerId} visited existing game ${gameId}`);
}
} else {
gameId = wsHandler.createGame();
gameIdInitialized = true;
console.log(`Created new game without specific ID: ${gameId}`);
}
if (gameIdInitialized) {
console.log(
`Player ${playerId} came without a gameId. Redirecting them to new game ${gameId}.`,
);
return new Response(null, {
status: 302,
headers: { Location: `/?gameId=${gameId}` },

View File

@ -13,13 +13,14 @@ export class WebSocketHandler {
}
public handleConnection(ws: WS): void {
const { gameId } = ws.data.query;
const { gameId, playerId } = ws.data.query;
console.log(`Player ${playerId} is opening a connection to game ${gameId}`);
if (this.games.has(gameId)) {
const game = this.games.get(gameId)!;
game.handleConnection(ws);
} else {
ws.send('Error: game not found');
ws.close();
this.createGame(gameId);
this.games.get(gameId)!.handleConnection(ws);
}
}