fix rusenie hier ked vsetkych odpoji
This commit is contained in:
+29
-10
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
@@ -273,19 +274,37 @@ async def send_error(sid: str, message: str):
|
||||
await sio.emit("error", {"error": message}, to=sid)
|
||||
|
||||
|
||||
# Ako dlho prezije nezacata hra, ked su vsetci hraci naraz offline. Na mobile
|
||||
# sa socket bezne strati uz pri zamknuti obrazovky, takze okamzite zmazanie
|
||||
# hry rusilo lobby, v ktorom hraci len cakali so zhasnutym telefonom.
|
||||
LOBBY_ABANDON_GRACE_SECONDS = 10 * 60
|
||||
|
||||
|
||||
async def _cleanup_abandoned_lobby(gid: str):
|
||||
"""Po grace periode zmaz nezacatu hru, ak sa medzitym nikto nevratil.
|
||||
Podmienka sa overuje az po uplynuti casu, takze pri navrate hraca je
|
||||
task neskodny no-op (netreba nic rusit)."""
|
||||
await asyncio.sleep(LOBBY_ABANDON_GRACE_SECONDS)
|
||||
game = games.get(gid)
|
||||
if game is not None and not game.started and not any(p.connected for p in game.players):
|
||||
del games[gid]
|
||||
await broadcast_lobby()
|
||||
|
||||
|
||||
async def _mark_player_offline(game: "Game", player: "Player"):
|
||||
"""Mark player disconnected. An unstarted game with nobody left is cleaned
|
||||
up; a started game is kept in memory so it stays in the lobby and can be
|
||||
resumed (it's torn down only by end_game)."""
|
||||
"""Mark player disconnected. An unstarted game with nobody left gets a
|
||||
delayed cleanup (mobile sockets drop on screen lock, so an immediate
|
||||
delete would kill lobbies where everyone is just waiting); a started game
|
||||
is kept in memory so it stays in the lobby and can be resumed (it's torn
|
||||
down only by end_game)."""
|
||||
player.connected = False
|
||||
if not any(p.connected for p in game.players) and not game.started:
|
||||
del games[game.gid]
|
||||
else:
|
||||
await sio.emit(
|
||||
"player_connection",
|
||||
{"order": player.order, "connected": False},
|
||||
room=game.gid,
|
||||
)
|
||||
asyncio.create_task(_cleanup_abandoned_lobby(game.gid))
|
||||
await sio.emit(
|
||||
"player_connection",
|
||||
{"order": player.order, "connected": False},
|
||||
room=game.gid,
|
||||
)
|
||||
|
||||
|
||||
def _active_game(sid: str) -> "tuple[Game, dict] | None":
|
||||
|
||||
@@ -132,6 +132,9 @@ export function setupSocketListeners() {
|
||||
|
||||
// Surface connection failures instead of silently buffering emits.
|
||||
socket.on('connect_error', (err: Error) => {
|
||||
// `active` = klient sa automaticky pokusi znova (typicky prebudeny mobil,
|
||||
// kym sa siet zobudi) -- prechodne, netreba strasit toastom.
|
||||
if (socket.active) return;
|
||||
useGameStore.getState().setError(`Spojenie so serverom zlyhalo: ${err.message}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useGameStore } from '../store/gameStore';
|
||||
import { emit } from '../lib/socket';
|
||||
@@ -8,6 +9,8 @@ export default function Lobby() {
|
||||
const navigate = useNavigate();
|
||||
const myPlayer = useGameStore((s) => s.myPlayer);
|
||||
const games = useGameStore((s) => s.games);
|
||||
const [showCopied, setShowCopied] = useState(false);
|
||||
const copiedTimeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
|
||||
const game = games.find((g) => g.gid === gid);
|
||||
const players = game?.players ?? [];
|
||||
@@ -17,11 +20,25 @@ export default function Lobby() {
|
||||
const handleLeave = () => leaveGame(navigate);
|
||||
|
||||
const handleCopyCode = () => {
|
||||
if (gid) navigator.clipboard.writeText(`${window.location.origin}/lobby/${gid}`);
|
||||
if (!gid) return;
|
||||
navigator.clipboard.writeText(`${window.location.origin}/lobby/${gid}`);
|
||||
setShowCopied(true);
|
||||
clearTimeout(copiedTimeout.current);
|
||||
copiedTimeout.current = setTimeout(() => setShowCopied(false), 1800);
|
||||
};
|
||||
|
||||
useEffect(() => () => clearTimeout(copiedTimeout.current), []);
|
||||
|
||||
return (
|
||||
<div className="max-w-md mx-auto p-4 pt-8 min-h-screen">
|
||||
<div
|
||||
className={`fixed top-4 left-1/2 -translate-x-1/2 px-4 py-2 rounded-lg bg-header border border-gold/30 text-gold text-sm shadow-lg transition-opacity duration-300 z-50 ${
|
||||
showCopied ? 'opacity-100' : 'opacity-0 pointer-events-none'
|
||||
}`}
|
||||
>
|
||||
Odkaz na hru skopírovaný
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<h1 className="font-serif text-2xl text-gold">{game?.name ?? 'Hra'}</h1>
|
||||
<button onClick={handleLeave} className="text-sm text-green-dim hover:text-gold">
|
||||
@@ -38,7 +55,7 @@ export default function Lobby() {
|
||||
onClick={handleCopyCode}
|
||||
className="ml-3 px-3 py-1 rounded-lg text-sm border border-gold/30 text-gold hover:bg-gold hover:text-table transition-colors"
|
||||
>
|
||||
Kopírovať
|
||||
Kopírovať URL
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user