feat(api): add game:ready message for client state sync
- WsGameReadySchema added to shared schemas and WsClientMessageSchema - handleGameReady sends current game:question directly to requesting client socket (not broadcast) — foundation for reconnection slice - router dispatches game:ready to handleGameReady handler
This commit is contained in:
parent
4d4715b4ee
commit
6975384751
3 changed files with 38 additions and 2 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import type { WebSocket } from "ws";
|
||||
import type { User } from "better-auth";
|
||||
import type { WsGameAnswer } from "@lila/shared";
|
||||
import type { WsGameAnswer, WsGameReady } from "@lila/shared";
|
||||
import { finishGame, getLobbyByCodeWithPlayers } from "@lila/db";
|
||||
import { broadcastToLobby, getConnections } from "../connections.js";
|
||||
import { lobbyGameStore, timers } from "../gameState.js";
|
||||
|
|
@ -52,6 +52,32 @@ export const handleGameAnswer = async (
|
|||
}
|
||||
};
|
||||
|
||||
export const handleGameReady = async (
|
||||
ws: WebSocket,
|
||||
msg: WsGameReady,
|
||||
_user: User,
|
||||
): Promise<void> => {
|
||||
const state = await lobbyGameStore.get(msg.lobbyId);
|
||||
if (!state) throw new NotFoundError("Game not found");
|
||||
|
||||
const currentQuestion = state.questions[state.currentIndex];
|
||||
if (!currentQuestion) throw new NotFoundError("No active question");
|
||||
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "game:question",
|
||||
question: {
|
||||
questionId: currentQuestion.questionId,
|
||||
prompt: currentQuestion.prompt,
|
||||
gloss: currentQuestion.gloss,
|
||||
options: currentQuestion.options,
|
||||
},
|
||||
questionNumber: state.currentIndex + 1,
|
||||
totalQuestions: state.questions.length,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
export const resolveRound = async (
|
||||
lobbyId: string,
|
||||
questionIndex: number,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
handleLobbyLeave,
|
||||
handleLobbyStart,
|
||||
} from "./handlers/lobbyHandlers.js";
|
||||
import { handleGameAnswer } from "./handlers/gameHandlers.js";
|
||||
import { handleGameAnswer, handleGameReady } from "./handlers/gameHandlers.js";
|
||||
import { AppError } from "../errors/AppError.js";
|
||||
|
||||
export type AuthenticatedUser = { session: Session; user: User };
|
||||
|
|
@ -60,6 +60,9 @@ export const handleMessage = async (
|
|||
case "game:answer":
|
||||
await handleGameAnswer(ws, msg, auth.user);
|
||||
break;
|
||||
case "game:ready":
|
||||
await handleGameReady(ws, msg, auth.user);
|
||||
break;
|
||||
default:
|
||||
assertExhaustive(msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ export const WsLobbyStartSchema = z.object({
|
|||
|
||||
export type WsLobbyStart = z.infer<typeof WsLobbyStartSchema>;
|
||||
|
||||
export const WsGameReadySchema = z.object({
|
||||
type: z.literal("game:ready"),
|
||||
lobbyId: z.uuid(),
|
||||
});
|
||||
export type WsGameReady = z.infer<typeof WsGameReadySchema>;
|
||||
|
||||
export const WsGameAnswerSchema = z.object({
|
||||
type: z.literal("game:answer"),
|
||||
lobbyId: z.uuid(),
|
||||
|
|
@ -66,6 +72,7 @@ export const WsClientMessageSchema = z.discriminatedUnion("type", [
|
|||
WsLobbyLeaveSchema,
|
||||
WsLobbyStartSchema,
|
||||
WsGameAnswerSchema,
|
||||
WsGameReadySchema,
|
||||
]);
|
||||
export type WsClientMessage = z.infer<typeof WsClientMessageSchema>;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue