38 lines
1.3 KiB
Python
38 lines
1.3 KiB
Python
"""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())
|