"""SSE 推送路由""" from __future__ import annotations import asyncio from typing import Optional from fastapi import APIRouter, Query, Request from fastapi.responses import StreamingResponse from src.daemon.sse import SSEBroker router = APIRouter(prefix="/api/events", tags=["sse"]) _broker: Optional[SSEBroker] = None def get_broker() -> SSEBroker: global _broker if _broker is None: _broker = SSEBroker() return _broker def set_broker(broker: SSEBroker) -> None: global _broker _broker = broker @router.get("") async def event_stream( request: Request, project: Optional[str] = Query(None, description="Filter by project ID"), ): """SSE 端点 — 实时推送黑板事件""" broker = get_broker() async def generate(): cid, queue = broker.subscribe() try: while True: if await request.is_disconnected(): break try: event = await asyncio.wait_for(queue.get(), timeout=30.0) yield event.to_sse() except asyncio.TimeoutError: yield ": heartbeat\n\n" finally: broker.unsubscribe(cid) return StreamingResponse(generate(), media_type="text/event-stream")