35 lines
1.3 KiB
Python
35 lines
1.3 KiB
Python
"""`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)) -> StreamingResponse:
|
||
|
|
# 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,
|
||
|
|
)
|
||
|
|
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,
|
||
|
|
)
|