feat: add backend FastAPI structure and Supabase schema
This commit is contained in:
55
server/app/services/ws_manager.py
Normal file
55
server/app/services/ws_manager.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Gestor de conexiones WebSocket.
|
||||
Mantiene un registro de qué clientes están conectados y a qué zona pertenecen.
|
||||
El simulador llama a broadcast_zona() para empujar eventos sin polling.
|
||||
"""
|
||||
import json
|
||||
from collections import defaultdict
|
||||
|
||||
from fastapi import WebSocket
|
||||
|
||||
|
||||
class WebSocketManager:
|
||||
def __init__(self):
|
||||
# zona_id -> lista de WebSockets activos
|
||||
self._conexiones: dict[str, list[WebSocket]] = defaultdict(list)
|
||||
|
||||
async def conectar(self, websocket: WebSocket, zona_id: str) -> None:
|
||||
await websocket.accept()
|
||||
self._conexiones[zona_id].append(websocket)
|
||||
|
||||
def desconectar(self, websocket: WebSocket, zona_id: str) -> None:
|
||||
conexiones = self._conexiones.get(zona_id, [])
|
||||
if websocket in conexiones:
|
||||
conexiones.remove(websocket)
|
||||
|
||||
async def broadcast_zona(self, zona_id: str, payload: dict) -> None:
|
||||
"""Envía un mensaje a todos los clientes de una zona."""
|
||||
mensaje = json.dumps(payload, ensure_ascii=False)
|
||||
muertos: list[WebSocket] = []
|
||||
|
||||
for ws in self._conexiones.get(zona_id, []):
|
||||
try:
|
||||
await ws.send_text(mensaje)
|
||||
except Exception:
|
||||
muertos.append(ws)
|
||||
|
||||
for ws in muertos:
|
||||
self.desconectar(ws, zona_id)
|
||||
|
||||
async def broadcast_ruta(self, ruta_id: str, payload: dict) -> None:
|
||||
"""
|
||||
Envía a TODAS las zonas de una ruta.
|
||||
El filtro real de privacidad está en el backend (RBAC del endpoint REST).
|
||||
Aquí simplemente distribuimos por zona registrada.
|
||||
"""
|
||||
for zona_id, conexiones in self._conexiones.items():
|
||||
if conexiones:
|
||||
await self.broadcast_zona(zona_id, payload)
|
||||
|
||||
def zonas_activas(self) -> list[str]:
|
||||
return [z for z, ws in self._conexiones.items() if ws]
|
||||
|
||||
|
||||
# Singleton global compartido por el simulador y el router de WebSocket
|
||||
ws_manager = WebSocketManager()
|
||||
Reference in New Issue
Block a user