Files
Luncher/server/src/minigames.ts
T
mates 35cf2ca9d7
CI / Server unit tests (push) Successful in 26s
CI / Generate TypeScript types (push) Successful in 10s
CI / Build server (push) Successful in 28s
CI / Build client (push) Successful in 41s
CI / Playwright E2E tests (push) Successful in 2m24s
CI / Build and push Docker image (push) Successful in 44s
CI / Notify (push) Successful in 2s
feat: vytržení miniher do samostatného projektu
2026-10-22 12:42:49 +02:00

63 lines
2.1 KiB
TypeScript

import { Socket } from "socket.io";
import { getLogin } from "./auth";
/** Pomůcky pro websocketové minihry (kreslení). Ostatní minihry jsou v samostatné aplikaci Lobby. */
/** Chyba určená hráči — posílá se zpět klientovi, nic se neloguje. */
export class GameError extends Error { }
/** Hodiny a náhoda vyčleněné kvůli testům. */
export type Clock = {
now: () => number,
setTimeout: (fn: () => void, ms: number) => unknown,
clearTimeout: (handle: unknown) => void,
random: () => number,
};
export const defaultClock: Clock = {
now: () => Date.now(),
setTimeout: (fn, ms) => setTimeout(fn, ms),
clearTimeout: handle => clearTimeout(handle as NodeJS.Timeout),
random: () => Math.random(),
};
/** Ověří token z eventu a vrátí login, jinak vyhodí chybu. */
export function loginFromPayload(payload: unknown): string {
const token = (payload as { token?: unknown } | undefined)?.token;
if (typeof token !== 'string') {
throw new GameError('Chybí přihlášení.');
}
try {
const login = getLogin(token);
if (!login) throw new Error();
return login;
} catch {
throw new GameError('Neplatné přihlášení.');
}
}
/**
* Vytvoří handler websocket eventu, který ověří přihlášení a herní chyby
* pošle zpět jen danému klientovi jako `errorEvent`.
*/
export function gameHandler(socket: Socket, errorEvent: string, action: (login: string, payload: unknown) => void | Promise<void>) {
const onError = (e: unknown) => {
if (e instanceof GameError) {
socket.emit(errorEvent, e.message);
} else {
console.error(`Chyba minihry (${errorEvent})`, e);
}
};
return (payload: unknown) => {
try {
const result = action(loginFromPayload(payload), payload);
if (result instanceof Promise) result.catch(onError);
} catch (e) {
onError(e);
}
};
}
/** Minimální počet hráčů — lokálně lze hrát i sám. */
export const minPlayersForEnv = (prod: number) => process.env.NODE_ENV === 'development' ? 1 : prod;