a
This commit is contained in:
parent
216a779f22
commit
a376236b17
|
@ -7,16 +7,17 @@ import traceback
|
|||
|
||||
from functools import partial
|
||||
from http_router import Router, MethodNotAllowed, NotFound
|
||||
from izzylib import DotDict, Path, logging, signal_handler
|
||||
from izzylib import DotDict, Path, convert_to_boolean, logging, signal_handler
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
from threading import Event, Thread
|
||||
|
||||
from . import http_methods, error, __file__ as module_root
|
||||
from . import http_methods, error
|
||||
from .config import Config
|
||||
from .response import ServerResponse
|
||||
#from .router import Router
|
||||
from .view import Static, Manifest, Robots, Style
|
||||
|
||||
from .. import __file__ as module_root
|
||||
from ..exceptions import MethodNotHandledException, NoBlueprintForPath
|
||||
from ..utils import AsyncTransport
|
||||
from ..template import Template
|
||||
|
@ -27,7 +28,7 @@ except ImportError:
|
|||
Database = NotImplementedError('Failed to import SQL database class')
|
||||
|
||||
|
||||
frontend = Path(module_root).join('../../frontend').resolve()
|
||||
frontend = Path(module_root).join('../frontend').resolve()
|
||||
|
||||
|
||||
class ApplicationBase:
|
||||
|
@ -190,6 +191,7 @@ class Application(ApplicationBase):
|
|||
loop = asyncio.new_event_loop()
|
||||
|
||||
self.loop = loop
|
||||
self.template = None
|
||||
asyncio.set_event_loop(self.loop)
|
||||
|
||||
self.client = self.cfg.client_class(loop, *self.cfg.client_args, **self.cfg.client_kwargs)
|
||||
|
@ -221,8 +223,9 @@ class Application(ApplicationBase):
|
|||
self.add_view(Style)
|
||||
self.add_static('/framework/static/', frontend.join('static'))
|
||||
|
||||
else:
|
||||
self.template = None
|
||||
|
||||
def __repr__(self):
|
||||
return f'Application({self.name}, listen={self.cfg.listen}, port={self.cfg.port})'
|
||||
|
||||
|
||||
@property
|
||||
|
@ -230,6 +233,15 @@ class Application(ApplicationBase):
|
|||
return self._running.is_set()
|
||||
|
||||
|
||||
@running.setter
|
||||
def running(self, value):
|
||||
if convert_to_boolean(value):
|
||||
self._running.set()
|
||||
|
||||
else:
|
||||
self._running.clear()
|
||||
|
||||
|
||||
def add_task(self, state, callback, *args, **kwargs):
|
||||
assert state in ['startup', 'shutdown']
|
||||
assert asyncio.iscoroutinefunction(callback)
|
||||
|
@ -278,65 +290,19 @@ class Application(ApplicationBase):
|
|||
return self.template.render(*args, **kwargs)
|
||||
|
||||
|
||||
async def create_task(self, log=True):
|
||||
if self.cfg.socket:
|
||||
if log:
|
||||
logging.info(f'Starting server on {self.cfg.socket}')
|
||||
|
||||
return await asyncio.start_unix_server(
|
||||
self.handle_client,
|
||||
path = self.cfg.socket
|
||||
)
|
||||
|
||||
else:
|
||||
if log:
|
||||
logging.info(f'Starting server on {self.cfg.listen}:{self.cfg.port}')
|
||||
|
||||
return await asyncio.start_server(
|
||||
self.handle_client,
|
||||
host = self.cfg.listen,
|
||||
port = self.cfg.port,
|
||||
family = socket.AF_INET,
|
||||
reuse_address = True,
|
||||
reuse_port = True
|
||||
)
|
||||
|
||||
|
||||
def run(self):
|
||||
task = self.start()
|
||||
|
||||
while not task.done():
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def start(self, log=True):
|
||||
if self._server:
|
||||
return
|
||||
|
||||
if self.cfg.socket:
|
||||
if log:
|
||||
logging.info(f'Starting server on {self.cfg.socket}')
|
||||
signal_handler(self.stop)
|
||||
return asyncio.run(self.handle_run_server())
|
||||
|
||||
server = asyncio.start_unix_server(
|
||||
self.handle_client,
|
||||
path = self.cfg.socket
|
||||
)
|
||||
|
||||
else:
|
||||
if log:
|
||||
logging.info(f'Starting server on {self.cfg.listen}:{self.cfg.port}')
|
||||
|
||||
server = asyncio.start_server(
|
||||
self.handle_client,
|
||||
host = self.cfg.listen,
|
||||
port = self.cfg.port,
|
||||
family = socket.AF_INET,
|
||||
reuse_address = True,
|
||||
reuse_port = True
|
||||
)
|
||||
def start(self):
|
||||
if self._server:
|
||||
return
|
||||
|
||||
signal_handler(self.stop)
|
||||
self._server = self.loop.run_until_complete(server)
|
||||
return asyncio.ensure_future(self.handle_run_server())
|
||||
|
||||
|
||||
|
@ -345,19 +311,35 @@ class Application(ApplicationBase):
|
|||
print('server not running')
|
||||
return
|
||||
|
||||
self._running.clear()
|
||||
#self._server.close()
|
||||
|
||||
self.loop.run_until_complete(self.handle_stop_server())
|
||||
self.running = False
|
||||
|
||||
if self.cfg.sig_handler:
|
||||
self.cfg.sig_handler(self, *self.cfg.sig_handler_args, **self.cfg.sig_handler_kwargs)
|
||||
|
||||
signal_handler(None)
|
||||
|
||||
|
||||
async def handle_run_server(self):
|
||||
self._running.set()
|
||||
## Create _server object
|
||||
if self.cfg.socket:
|
||||
logging.info(f'Starting server on {self.cfg.socket}')
|
||||
|
||||
self._server = await asyncio.start_unix_server(
|
||||
self.handle_client,
|
||||
path = self.cfg.socket
|
||||
)
|
||||
|
||||
else:
|
||||
logging.info(f'Starting server on {self.cfg.listen}:{self.cfg.port}')
|
||||
|
||||
self._server = await asyncio.start_server(
|
||||
self.handle_client,
|
||||
host = self.cfg.listen,
|
||||
port = self.cfg.port,
|
||||
family = socket.AF_INET,
|
||||
reuse_address = True,
|
||||
reuse_port = True
|
||||
)
|
||||
|
||||
self.running = True
|
||||
|
||||
## Run startup tasks
|
||||
for callback, args, kwargs in self._callbacks['startup']:
|
||||
|
@ -368,12 +350,14 @@ class Application(ApplicationBase):
|
|||
while self._server.is_serving() and self.running:
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
self._server.close()
|
||||
await self._server.wait_closed()
|
||||
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
self._running.clear()
|
||||
self.running = False
|
||||
signal_handler(None)
|
||||
|
||||
## Run shutdown tasks
|
||||
for callback, args, kwargs in self._callbacks['shutdown']:
|
||||
|
@ -397,26 +381,6 @@ class Application(ApplicationBase):
|
|||
logging.info('Server stopped')
|
||||
|
||||
|
||||
async def handle_stop_server(self):
|
||||
for callback, args, kwargs in self._callbacks['shutdown']:
|
||||
if asyncio.iscoroutinefunction(callback):
|
||||
await asyncio.wait_for(callback(self, *args, **kwargs), 10)
|
||||
|
||||
else:
|
||||
callback(self, *args, **kwargs)
|
||||
|
||||
for task in self._tasks:
|
||||
task.cancel()
|
||||
|
||||
try:
|
||||
await task
|
||||
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
self._tasks = []
|
||||
|
||||
|
||||
async def handle_client(self, reader, writer):
|
||||
transport = AsyncTransport(reader, writer, self.cfg.timeout)
|
||||
request = None
|
||||
|
@ -471,7 +435,7 @@ class Application(ApplicationBase):
|
|||
response.headers.update(self.cfg.default_headers)
|
||||
await transport.write(response.compile())
|
||||
|
||||
if request and request.log and not request.path.startswith('/framework'):
|
||||
if self.cfg.access_log and request and request.log and not request.path.startswith('/framework'):
|
||||
logging.info(f'{request.remote} {request.method} {request.path} {response.status} {len(response.body)} {request.agent}')
|
||||
|
||||
except:
|
||||
|
|
Loading…
Reference in a new issue