sanic/sanic/server/async_server.py
2022-06-28 15:25:46 +03:00

123 lines
3.2 KiB
Python

from __future__ import annotations
import asyncio
from typing import TYPE_CHECKING
from sanic.exceptions import SanicException
if TYPE_CHECKING:
from sanic import Sanic
class AsyncioServer:
"""
Wraps an asyncio server with functionality that might be useful to
a user who needs to manage the server lifecycle manually.
"""
__slots__ = ("app", "connections", "loop", "serve_coro", "server")
def __init__(
self,
app: Sanic,
loop,
serve_coro,
connections,
):
# Note, Sanic already called "before_server_start" events
# before this helper was even created. So we don't need it here.
self.app = app
self.connections = connections
self.loop = loop
self.serve_coro = serve_coro
self.server = None
def startup(self):
"""
Trigger "before_server_start" events
"""
return self.app._startup()
def before_start(self):
"""
Trigger "before_server_start" events
"""
return self._server_event("init", "before")
def after_start(self):
"""
Trigger "after_server_start" events
"""
return self._server_event("init", "after")
def before_stop(self):
"""
Trigger "before_server_stop" events
"""
return self._server_event("shutdown", "before")
def after_stop(self):
"""
Trigger "after_server_stop" events
"""
return self._server_event("shutdown", "after")
def is_serving(self) -> bool:
if self.server:
return self.server.is_serving()
return False
def wait_closed(self):
if self.server:
return self.server.wait_closed()
def close(self):
if self.server:
self.server.close()
coro = self.wait_closed()
task = asyncio.ensure_future(coro, loop=self.loop)
return task
def start_serving(self):
return self._serve(self.server.start_serving)
def serve_forever(self):
return self._serve(self.server.serve_forever)
def _serve(self, serve_func):
if self.server:
if not self.app.state.is_started:
raise SanicException(
"Cannot run Sanic server without first running "
"await server.startup()"
)
try:
return serve_func()
except AttributeError:
name = serve_func.__name__
raise NotImplementedError(
f"server.{name} not available in this version "
"of asyncio or uvloop."
)
def _server_event(self, concern: str, action: str):
if not self.app.state.is_started:
raise SanicException(
"Cannot dispatch server event without "
"first running await server.startup()"
)
return self.app._server_event(concern, action, loop=self.loop)
def __await__(self):
"""
Starts the asyncio server, returns AsyncServerCoro
"""
task = asyncio.ensure_future(self.serve_coro)
while not task.done():
yield
self.server = task.result()
return self