-
Notifications
You must be signed in to change notification settings - Fork 4
45 game better websocket connexiondisconnexion #51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
45 game better websocket connexiondisconnexion #51
Conversation
add -dev to containers's name to differenciate dev services upgrade colima s rule to not restart if mount are correct Makefile make/colima.mk srcs/dev-docker-compose.yml
Merge branch 'game-ws-connection' into 45-game-better-websocket-connexiondisconnexion
rom98759
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok pour moi
| reason: reason.toString(), | ||
| }); | ||
| upstreamWs.close(); | ||
| upstreamWs.close(code, reason); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trop bien et plus clair
| // showPanel(panel: 'settings' | 'game-logs' | 'game-sessions') { | ||
| // ['settings', 'game-logs', 'game-sessions'].forEach((id) => { | ||
| // const el = document.getElementById(id); | ||
| // if (el) { | ||
| // el.classList.toggle('hidden', id !== panel); | ||
| // } | ||
| // }); | ||
| // if (panel === 'game-sessions') { | ||
| // this.sessionsInterval = window.setInterval(() => this.loadSessions(), 2000); | ||
| // } else if (this.sessionsInterval) { | ||
| // clearInterval(this.sessionsInterval); | ||
| // this.sessionsInterval = null; | ||
| // } | ||
| // } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A supp ?
| <div class="bg-white/10 backdrop-blur-lg rounded-lg p-4 max-w-2xl mx-auto"> | ||
| <div class="flex justify-around text-white"> | ||
| <div class="text-center"> | ||
| <p class="text-sm text-purple-300">Player 1</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mettre le nom des joueurs ?
codastream
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool pour le dockerfile dev
est-ce qu;on peut faire en sorte que les PR a partir de maintenant n'ajoutent pas de lints ESLint ? (on peut typer autrement qu'avec any, enlever les variables non utilisées, utiliser const plutôt que var et si possible que let
srcs/game/.dockerignore srcs/game/src/controllers/game.controller.ts srcs/game/src/service/game.communication.ts srcs/game/src/service/game.connections.ts srcs/game/src/service/game.init.ts srcs/gateway/src/utils/proxy.ts srcs/nginx/tsconfig.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request improves WebSocket connection and disconnection handling for the game service, implementing a 2-player limitation system with Player A and Player B roles. The changes include better error handling with custom close codes, session cleanup logic, and UI updates to reflect the new player model.
Changes:
- Improved WebSocket connection management with proper close codes (4001-4003) and reasons
- Limited game sessions to exactly 2 players with role assignment (Player A & Player B)
- Implemented player-specific input controls (W/S for Player A, Arrow keys for Player B)
- Enhanced session cleanup to preserve running games even when players disconnect
- Updated test scripts to use HTTPS/WSS with proper SSL handling
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 21 comments.
Show a summary per file
| File | Description |
|---|---|
| test-game.sh | Updated URLs to HTTPS/WSS, added SSL bypass flags, adjusted test assertions for new login message |
| srcs/nginx/tsconfig.json | Upgraded TypeScript target to ES2022 with NodeNext module resolution |
| srcs/nginx/src/service/GameDisplay.ts | Added player role tracking, restricted inputs by player, updated UI labels to Player A/B |
| srcs/nginx/src/html/app.js | Compiled JavaScript output reflecting TypeScript changes |
| srcs/nginx/README.md | Documentation formatting improvements |
| srcs/gateway/src/utils/proxy.ts | Added proper GameState interface, improved WebSocket close handling |
| srcs/game/src/service/game.init.ts | Changed players from Set to Map for role tracking |
| srcs/game/src/service/game.connections.ts | Implemented player assignment logic (A/B), improved disconnect handling |
| srcs/game/src/service/game.communication.ts | Updated message handling for new player Map structure |
| srcs/game/src/core/game.state.ts | Added WS_CLOSE constants, changed players structure to Map |
| srcs/game/src/core/game.engine.ts | Renamed paddleMove to updatePaddle for clarity |
| srcs/game/src/controllers/game.controller.ts | Added session status validation for settings changes |
| srcs/game/Dockerfile | Minor syntax fix for COPY command |
| srcs/game/.dockerignore | Added new file with standard ignore patterns |
| srcs/dev-docker-compose.yml | Reorganized service order, updated container naming |
| docs/pong-guide.md | Added WebSocket error code documentation |
| Makefile | Added start-dev target |
|
|
||
| export function getGame(this: FastifyInstance, socket: any | null, sessionId: any): any { | ||
| let sessionData = gameSessions.get(sessionId) | ||
| // return the sessionData (incuding the game var) for a sessionId. If no Data at this sessionId, create new sessionData. |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a typo in the comment: "incuding" should be "including".
| // return the sessionData (incuding the game var) for a sessionId. If no Data at this sessionId, create new sessionData. | |
| // return the sessionData (including the game var) for a sessionId. If no Data at this sessionId, create new sessionData. |
| // const sessionData = getSessionData.call(this, null, sessionId); | ||
| // if (sessionData && sessionData.player.size === 2) { | ||
| // socket.close(WS_CLOSE.SESSION_FULL, 'Game session is full'); | ||
| // return | ||
| // } |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code should be removed. This pre-connection check for session fullness is now handled in addPlayerConnection, so this commented code serves no purpose and should be deleted to keep the codebase clean.
| // const sessionData = getSessionData.call(this, null, sessionId); | |
| // if (sessionData && sessionData.player.size === 2) { | |
| // socket.close(WS_CLOSE.SESSION_FULL, 'Game session is full'); | |
| // return | |
| // } |
| } | ||
| gameSessions.delete(sessionId) | ||
| // gameSessions.delete(sessionId) // let the game finish to determine a winner even if everybody left. | ||
| // (Should not loop infinite because of forcefield, the game should find a winer) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method name was changed from paddleMove to updatePaddle, which is an improvement. However, the comment on line 27 in game.state.ts still refers to the old behavior saying "let the game finish to determine a winer" with a typo. The word "winer" should be "winner".
| // (Should not loop infinite because of forcefield, the game should find a winer) | |
| // (Should not loop infinite because of forcefield, the game should find a winner) |
| if (players.size === 1 && Array.from(players.values())[0] === 'A') { | ||
| players.set(socket, 'B'); | ||
| socket.send(JSON.stringify({ type: 'connected', message: 'Player B' })); | ||
| } else if (players.size === 1 || players.size === 0) { | ||
| players.set(socket, 'A'); | ||
| socket.send(JSON.stringify({ type: 'connected', message: 'Player A' })); | ||
| } else if (players.size >= 2) { | ||
| socket.close(WS_CLOSE.SESSION_FULL, 'Session full'); | ||
| return false; | ||
| } |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The player assignment logic has a bug. When players.size === 1, the code first checks if the existing player is 'A' and assigns 'B', but then has an else if (players.size === 1 || players.size === 0) condition that will never execute for size 1 because the first condition already handled that case.
This means if the first player is assigned 'B' (which shouldn't happen but the logic allows), the second player would be incorrectly rejected.
The logic should be:
- If empty (size 0): assign 'A'
- If size 1: check what exists and assign the opposite
- If size >= 2: reject
| let sessionData = gameSessions.get(sessionId) | ||
| // return the sessionData (incuding the game var) for a sessionId. If no Data at this sessionId, create new sessionData. | ||
| // If a socket is given, add it to the players list of the sessionData, if not, just return the sessionData at sessionId. | ||
| export function getGame(this: FastifyInstance, socket: WebSocket | null, sessionId: any): any { |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter sessionId is typed as any, which defeats TypeScript's type safety. It should be typed as string to match how it's used throughout the codebase and stored in the gameSessions Map.
| export function getGame(this: FastifyInstance, socket: WebSocket | null, sessionId: any): any { | |
| export function getGame(this: FastifyInstance, socket: WebSocket | null, sessionId: string): any { |
| this.log.info(`receives WS: ${data}`); | ||
| try { | ||
| const message: ClientMessage = JSON.parse(data.toString()); | ||
| this.log.info(`${message}`); |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging object without proper serialization. The statement this.log.info(${message}) will output "[object Object]" instead of meaningful information. Use JSON.stringify(message) or structured logging like this.log.info({ message }, 'Received message').
| this.log.info(`${message}`); | |
| this.log.info({ message }, 'Received client message'); |
| } | ||
|
|
||
| if (paddle && direction) { | ||
| console.log('Player a move'); |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Console log message says "Player a move" (lowercase 'a') but should be more generic or match the actual player variable. Consider using console.log(Player ${this.player} move) for clarity, or remove this debug log if it's not needed.
| console.log('Player a move'); | |
| console.log(`Player ${this.player} move: paddle=${paddle}, direction=${direction}`); |
| // showPanel(panel: 'settings' | 'game-logs' | 'game-sessions') { | ||
| // ['settings', 'game-logs', 'game-sessions'].forEach((id) => { | ||
| // const el = document.getElementById(id); | ||
| // if (el) { | ||
| // el.classList.toggle('hidden', id !== panel); | ||
| // } | ||
| // }); | ||
| // if (panel === 'game-sessions') { | ||
| // this.sessionsInterval = window.setInterval(() => this.loadSessions(), 2000); | ||
| // } else if (this.sessionsInterval) { | ||
| // clearInterval(this.sessionsInterval); | ||
| // this.sessionsInterval = null; | ||
| // } | ||
| // } |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code should be removed. This is the compiled JavaScript version of the same commented code in GameDisplay.ts that should also be cleaned up.
| // showPanel(panel: 'settings' | 'game-logs' | 'game-sessions') { | |
| // ['settings', 'game-logs', 'game-sessions'].forEach((id) => { | |
| // const el = document.getElementById(id); | |
| // if (el) { | |
| // el.classList.toggle('hidden', id !== panel); | |
| // } | |
| // }); | |
| // if (panel === 'game-sessions') { | |
| // this.sessionsInterval = window.setInterval(() => this.loadSessions(), 2000); | |
| // } else if (this.sessionsInterval) { | |
| // clearInterval(this.sessionsInterval); | |
| // this.sessionsInterval = null; | |
| // } | |
| // } |
| socket: WebSocket | null, | ||
| sessionId: string, | ||
| code: number = 1000, | ||
| message: string, |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cleanupConnection function has a required parameter message but no default value. When called on line 66 with the error code 4444, the message 'error' is provided, but at line 10 the function signature requires message: string without a default. This could cause issues if the function is called elsewhere without this parameter. Consider adding a default value like message: string = 'Connection closed'.
| message: string, | |
| message: string = 'Connection closed', |
| import { WS_CLOSE } from '../core/game.state.js'; | ||
|
|
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import WS_CLOSE.
| import { WS_CLOSE } from '../core/game.state.js'; |
WebSocket connexion and disconnection are better handled: