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