from typing import AsyncIterator from pydantic import BaseModel import asyncio class CommandModel(BaseModel): password: str cmd: str class LogsModel(BaseModel): password: str def sse_event(data: str, event: str | None = None, id: str | None = None) -> bytes: parts = [] if id is not None: parts.append(f"id: {id}") if event is not None: parts.append(f"event: {event}") for line in data.rstrip("\n").split("\n"): parts.append(f"data: {line}") parts.append("") return ("\n".join(parts) + "\n").encode("utf-8") async def sse_from_iterator(iterator: AsyncIterator[str], keep_alive: float = 15): ait = iterator.__aiter__() while True: try: item = await asyncio.wait_for(ait.__anext__(), timeout=keep_alive) except asyncio.TimeoutError: yield b": keep-alive\n\n" continue except StopAsyncIteration: break yield sse_event(item) yield sse_event("stream closed", event="close")