コード例 #1
0
    async def stream_response(self, send) -> None:
        await send({
            "type": "http.response.start",
            "status": self.status_code,
            "headers": self.raw_headers,
        })

        self._ping_task = self._loop.create_task(
            self._ping(send))  # type: ignore

        async for data in self.body_iterator:
            if isinstance(data, dict):
                chunk = ServerSentEvent(**data).encode()
            else:
                chunk = ServerSentEvent(str(data), sep=self.sep).encode()
            _log.debug(f"chunk: {chunk.decode()}")
            await send({
                "type": "http.response.body",
                "body": chunk,
                "more_body": True
            })
        await send({
            "type": "http.response.body",
            "body": b"",
            "more_body": False
        })
コード例 #2
0
 async def wait(self) -> None:
     """EventSourceResponse object is used for streaming data to the client,
     this method returns future, so we can wait until connection will
     be closed or other task explicitly call ``stop_streaming`` method.
     """
     if self._ping_task is None:
         raise RuntimeError("Response is not started")
     with contextlib.suppress(asyncio.CancelledError):
         await self._ping_task
         _log.debug(f"SSE ping stopped.")  # pragma: no cover
コード例 #3
0
ファイル: sse.py プロジェクト: alairock/sse-starlette
 async def _ping(self, send: Send) -> None:
     # Legacy proxy servers are known to, in certain cases, drop HTTP connections after a short timeout.
     # To protect against such proxy servers, authors can send a custom (ping) event
     # every 15 seconds or so.
     # Alternatively one can send periodically a comment line
     # (one starting with a ':' character)
     while self.active:
         await asyncio.sleep(self._ping_interval)
         ping = ServerSentEvent(datetime.utcnow(), event="ping").encode()
         _log.debug(f"ping: {ping.decode()}")
         await send({"type": "http.response.body", "body": ping, "more_body": True})
コード例 #4
0
ファイル: sse.py プロジェクト: alairock/sse-starlette
    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
        await run_until_first_complete(
            (self.stream_response, {"send": send}),
            (self.listen_for_disconnect, {"receive": receive}),
        )

        self.stop_streaming()
        await self.wait()
        _log.debug(f"streaming stopped.")

        if self.background is not None:  # pragma: no cover, tested in StreamResponse
            await self.background()
コード例 #5
0
 async def listen_for_disconnect(receive: Receive) -> None:
     while True:
         message = await receive()
         if message["type"] == "http.disconnect":
             _log.debug(f"Got event: http.disconnect. Stop streaming.")
             break
コード例 #6
0
    from uvicorn.config import logger as _log  # TODO: remove
    from uvicorn.main import Server

    original_handler = Server.handle_exit
    Server.handle_exit = AppStatus.handle_exit

    def unpatch_uvicorn_signal_handler():
        """restores original signal-handler and rolls back monkey-patching.
        Normally this should not be necessary.
        """
        Server.handle_exit = original_handler

except ModuleNotFoundError as e:
    _log = logging.getLogger(__name__)
    # logging.basicConfig(level=logging.INFO)
    _log.debug(f"Uvicorn not used, falling back to python standard logging.")


class SseState(enum.Enum):
    CONNECTING = 0
    OPENED = 1
    CLOSED = 2


class ServerSentEvent:
    def __init__(
        self,
        data: Any,
        *,
        event: Optional[str] = None,
        id: Optional[int] = None,