import json from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends, Query from sqlalchemy.orm import Session from app.core.database import get_db from app.models import Project, ProjectSong router = APIRouter(prefix="/ws", tags=["websocket"]) class ConnectionManager: def __init__(self): # project_id -> liste af aktive forbindelser self.rooms: dict[str, list[WebSocket]] = {} async def connect(self, project_id: str, ws: WebSocket): await ws.accept() self.rooms.setdefault(project_id, []).append(ws) def disconnect(self, project_id: str, ws: WebSocket): if project_id in self.rooms: self.rooms[project_id].discard(ws) if hasattr(self.rooms[project_id], 'discard') else None try: self.rooms[project_id].remove(ws) except ValueError: pass async def broadcast(self, project_id: str, message: dict): dead = [] for ws in self.rooms.get(project_id, []): try: await ws.send_text(json.dumps(message)) except Exception: dead.append(ws) for ws in dead: self.disconnect(project_id, ws) manager = ConnectionManager() @router.websocket("/{project_id}") async def project_live( project_id: str, websocket: WebSocket, db: Session = Depends(get_db), ): project = db.query(Project).filter(Project.id == project_id).first() if not project: await websocket.close(code=4004) return await manager.connect(project_id, websocket) # Send nuværende tilstand med det samme ved opkobling songs = db.query(ProjectSong).filter_by(project_id=project_id).order_by(ProjectSong.position).all() await websocket.send_text(json.dumps({ "event": "state", "project_id": project_id, "songs": [ {"id": ps.id, "position": ps.position, "status": ps.status, "song_id": ps.song_id} for ps in songs ], })) try: while True: await websocket.receive_text() # hold forbindelsen åben except WebSocketDisconnect: manager.disconnect(project_id, websocket) async def notify_status_change(project_id: str, project_song_id: str, new_status: str): """Kaldes fra projects-router når en sangs status ændres.""" await manager.broadcast(project_id, { "event": "status_update", "project_song_id": project_song_id, "status": new_status, })