65 lines
2.1 KiB
Python
65 lines
2.1 KiB
Python
from urllib.parse import parse_qs
|
|
|
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
|
|
|
from fupogfakta.models import GameSession, Player
|
|
|
|
|
|
class GameConsumer(AsyncJsonWebsocketConsumer):
|
|
"""
|
|
WebSocket consumer for a game session.
|
|
|
|
URL: ws/game/<session_code>/
|
|
|
|
Query params:
|
|
- session_token: player session token (players only)
|
|
- role=host: skip token check for host in MVP
|
|
"""
|
|
|
|
async def connect(self):
|
|
self.session_code = self.scope["url_route"]["kwargs"]["session_code"].upper()
|
|
self.group_name = f"game_{self.session_code}"
|
|
|
|
query_string = self.scope.get("query_string", b"").decode()
|
|
params = parse_qs(query_string)
|
|
|
|
role = params.get("role", [None])[0]
|
|
session_token = params.get("session_token", [None])[0]
|
|
|
|
if role == "host":
|
|
if not await GameSession.objects.filter(code=self.session_code).aexists():
|
|
await self.close(code=4004)
|
|
return
|
|
self.player = None
|
|
else:
|
|
if not session_token:
|
|
await self.close(code=4001)
|
|
return
|
|
|
|
try:
|
|
self.player = await Player.objects.aget(
|
|
session_token=session_token,
|
|
session__code=self.session_code,
|
|
)
|
|
except Player.DoesNotExist:
|
|
await self.close(code=4003)
|
|
return
|
|
await self.channel_layer.group_add(self.group_name, self.channel_name)
|
|
await self.accept()
|
|
|
|
async def disconnect(self, close_code):
|
|
if hasattr(self, "group_name"):
|
|
await self.channel_layer.group_discard(self.group_name, self.channel_name)
|
|
|
|
async def receive_json(self, content, **kwargs):
|
|
if content.get("type") == "ping":
|
|
await self.send_json({"type": "pong"})
|
|
|
|
# --- Group message handlers ---
|
|
|
|
async def phase_event(self, event):
|
|
"""Forward any phase_event broadcast to the WebSocket client."""
|
|
payload = dict(event.get("payload") or {})
|
|
payload["type"] = event["event_type"]
|
|
await self.send_json(payload)
|