79 lines
2.5 KiB
Python
79 lines
2.5 KiB
Python
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,
|
|
})
|