"""`GET /api/events`: the server-sent event stream (session required; locked sessions allowed).""" from __future__ import annotations from fastapi import APIRouter, Query, Request from fastapi.responses import StreamingResponse from starlette.concurrency import run_in_threadpool from ..auth.groups import SCREENS from ..events import EventHub, stream from .deps import resolve_standalone, settings_of router = APIRouter(prefix="/api", tags=["events"]) SSE_HEADERS = {"Cache-Control": "no-cache", "X-Accel-Buffering": "no", "Connection": "keep-alive"} @router.get("/events") async def events( request: Request, screen: str | None = Query(None, max_length=32), packet_id: int | None = Query(None, ge=1, le=2**62), ) -> StreamingResponse: """The event stream. `packet_id` is the packet the page has open; presence carries it, so the packet page can show who else is looking at the same packet. The client reopens the stream when the open packet changes.""" # The session check runs on its own pooled connection, returned before the stream starts p = await run_in_threadpool(resolve_standalone, request) hub: EventHub = request.app.state.events sub = hub.subscribe( session_id=p.session_id, user_id=p.user_id, display_name=p.user["display_name"], screen=screen if screen in SCREENS and screen in p.screens else None, packet_id=packet_id, ) hello = {"session_id": str(p.session_id), "build": settings_of(request).ps_build} return StreamingResponse( stream(hub, sub, hello=hello, is_disconnected=request.is_disconnected), media_type="text/event-stream", headers=SSE_HEADERS, )