Fix V2 race conditions, auth gaps, serialization bugs, and async stats
Phase 1 - Critical Fixes: - Add game_lock (asyncio.Lock) to Room class for serializing mutations - Wrap all game action handlers in lock to prevent race conditions - Split Card.to_dict into to_dict (full data) and to_client_dict (hidden) - Fix CardState.from_dict to handle missing rank/suit gracefully - Fix GameOptions reconstruction in recovery_service (dict -> object) - Extend state cache TTL from 4h to 24h, add touch_game method Phase 2 - Security: - Add optional WebSocket authentication via token query param - Use authenticated user ID/name when available - Add auth support to spectator WebSocket endpoint Phase 3 - Performance: - Make stats processing async (fire-and-forget) to avoid blocking game completion notifications Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -309,6 +309,7 @@ class RecoveryService:
|
||||
Reconstructed game state.
|
||||
"""
|
||||
from models.game_state import GamePhase, PlayerState
|
||||
from game import GameOptions
|
||||
|
||||
state = RebuiltGameState(game_id=d["game_id"])
|
||||
state.room_code = d.get("room_code", "")
|
||||
@@ -318,7 +319,12 @@ class RecoveryService:
|
||||
state.current_player_idx = d.get("current_player_idx", 0)
|
||||
state.player_order = d.get("player_order", [])
|
||||
state.deck_remaining = d.get("deck_remaining", 0)
|
||||
state.options = d.get("options", {})
|
||||
# Reconstruct GameOptions as proper object for attribute access
|
||||
options_dict = d.get("options", {})
|
||||
if isinstance(options_dict, dict):
|
||||
state.options = GameOptions(**options_dict)
|
||||
else:
|
||||
state.options = options_dict
|
||||
state.sequence_num = d.get("sequence_num", 0)
|
||||
state.finisher_id = d.get("finisher_id")
|
||||
state.host_id = d.get("host_id")
|
||||
|
||||
Reference in New Issue
Block a user