You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
69 lines
2.2 KiB
69 lines
2.2 KiB
from typing import Any
|
|
from fastapi import status
|
|
from starlette.types import Send
|
|
from sse_starlette.sse import ensure_bytes, EventSourceResponse, ServerSentEvent
|
|
|
|
class StreamingResponse(EventSourceResponse):
|
|
"""`Response` class for streaming server-sent events.
|
|
|
|
Follows the
|
|
[EventSource protocol](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events#interfaces)
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
content: Any = iter(()),
|
|
*args: Any,
|
|
**kwargs: dict[str, Any],
|
|
) -> None:
|
|
"""Constructor method.
|
|
|
|
Args:
|
|
content: The content to stream.
|
|
"""
|
|
super().__init__(content=content, *args, **kwargs)
|
|
|
|
async def stream_response(self, send: Send) -> None:
|
|
"""Streams data chunks to client by iterating over `content`.
|
|
|
|
If an exception occurs while iterating over `content`, an
|
|
internal server error is sent to the client.
|
|
|
|
Args:
|
|
send: The send function from the ASGI framework.
|
|
"""
|
|
await send(
|
|
{
|
|
"type": "http.response.start",
|
|
"status": self.status_code,
|
|
"headers": self.raw_headers,
|
|
}
|
|
)
|
|
|
|
try:
|
|
async for data in self.body_iterator:
|
|
chunk = ensure_bytes(data, self.sep)
|
|
with open("log.txt", "a") as log_file:
|
|
log_file.write(f"chunk: {chunk.decode()}\n")
|
|
await send(
|
|
{"type": "http.response.body", "body": chunk, "more_body": True}
|
|
)
|
|
except Exception as e:
|
|
with open("log.txt", "a") as log_file:
|
|
log_file.write(f"body iterator error: {e}\n")
|
|
chunk = ServerSentEvent(
|
|
data=dict(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="Internal Server Error",
|
|
),
|
|
event="error",
|
|
)
|
|
await send(
|
|
{
|
|
"type": "http.response.body",
|
|
"body": ensure_bytes(chunk, None),
|
|
"more_body": True,
|
|
}
|
|
)
|
|
|
|
await send({"type": "http.response.body", "body": b"", "more_body": False}) |