"""SSE-поток обновлений прогресса: GET /api/events.""" from __future__ import annotations import asyncio from fastapi import APIRouter, Depends, Request from sse_starlette.sse import EventSourceResponse from app.api.deps import get_events from app.core.events import EventBus router = APIRouter(tags=["events"]) # Если за это время не было ни одного события — шлём комментарий-пинг, # чтобы прокси/браузер не закрыли «висящее» соединение. _KEEPALIVE_SECONDS = 15.0 @router.get("/api/events") async def events_stream( request: Request, events: EventBus = Depends(get_events), ) -> EventSourceResponse: async def generator(): async with events.subscribe() as queue: while True: if await request.is_disconnected(): break try: event = await asyncio.wait_for(queue.get(), timeout=_KEEPALIVE_SECONDS) except asyncio.TimeoutError: yield {"event": "ping", "data": "{}"} continue yield {"event": event.type, "data": event.model_dump_json()} return EventSourceResponse(generator())