switch from WSGI using uWSGI to ASGI using custom event loop based on uvicorn
This commit is contained in:
parent
b103205dfe
commit
6b3cc4c168
15 changed files with 610 additions and 8 deletions
130
core/server.py
Normal file
130
core/server.py
Normal file
|
@ -0,0 +1,130 @@
|
|||
#!/usr/bin/env python3
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import uvicorn
|
||||
from aiosmtpd.controller import Controller, UnixSocketController
|
||||
from aiosmtpd.lmtp import LMTP
|
||||
|
||||
|
||||
async def handle_echo(reader, writer):
|
||||
# session = Session()
|
||||
data = await reader.read(100)
|
||||
message = data.decode()
|
||||
addr = writer.get_extra_info('peername')
|
||||
|
||||
print(f"Received {message!r} from {addr!r}")
|
||||
|
||||
print(f"Send: {message!r}")
|
||||
writer.write(data)
|
||||
await writer.drain()
|
||||
|
||||
print("Close the connection")
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
|
||||
|
||||
class ExampleHandler:
|
||||
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
|
||||
if not address.endswith('@example.com'):
|
||||
return '550 not relaying to that domain'
|
||||
envelope.rcpt_tos.append(address)
|
||||
return '250 OK'
|
||||
|
||||
async def handle_DATA(self, server, session, envelope):
|
||||
print('Message from %s' % envelope.mail_from)
|
||||
print('Message for %s' % envelope.rcpt_tos)
|
||||
print('Message data:\n')
|
||||
for ln in envelope.content.decode('utf8', errors='replace').splitlines():
|
||||
print(f'> {ln}'.strip())
|
||||
print()
|
||||
print('End of message')
|
||||
return '250 Message accepted for delivery'
|
||||
|
||||
|
||||
class LTMPController(Controller):
|
||||
def factory(self):
|
||||
return LMTP(self.handler)
|
||||
|
||||
|
||||
class UnixSocketLMTPController(UnixSocketController):
|
||||
def factory(self):
|
||||
return LMTP(self.handler)
|
||||
|
||||
|
||||
class UvicornServer(uvicorn.Server):
|
||||
def install_signal_handlers(self):
|
||||
pass
|
||||
|
||||
|
||||
async def web():
|
||||
log_config = uvicorn.config.LOGGING_CONFIG
|
||||
log_config["handlers"]["default"] = {"class": "logging.FileHandler", "filename": "web.log", "formatter": "default"}
|
||||
log_config["handlers"]["access"] = {"class": "logging.FileHandler", "filename": "web-access.log",
|
||||
"formatter": "access"}
|
||||
config = uvicorn.Config("core.asgi:application", uds="web.sock", log_config=log_config)
|
||||
server = UvicornServer(config=config)
|
||||
await server.serve()
|
||||
|
||||
|
||||
async def tcp():
|
||||
log = logging.getLogger('test')
|
||||
log.info("Starting TCP server")
|
||||
server = await asyncio.start_unix_server(handle_echo, path='test.sock')
|
||||
|
||||
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
|
||||
log.info(f'Serving on {addrs}')
|
||||
|
||||
async with server:
|
||||
await server.serve_forever()
|
||||
log.info("TCP done")
|
||||
|
||||
|
||||
async def lmtp():
|
||||
log = logging.getLogger('lmtp')
|
||||
log.info("Starting LMTP server")
|
||||
cont = UnixSocketLMTPController(ExampleHandler(), unix_socket='lmtp.sock')
|
||||
cont.start()
|
||||
log.info("LMTP done")
|
||||
|
||||
|
||||
async def shutdown(sig, loop):
|
||||
log = logging.getLogger()
|
||||
log.info(f"Received exit signal {sig.name}...")
|
||||
tasks = [t for t in asyncio.all_tasks() if t is not
|
||||
asyncio.current_task()]
|
||||
[task.cancel() for task in tasks]
|
||||
log.info(f"Cancelling {len(tasks)} outstanding tasks")
|
||||
await asyncio.wait_for(loop.shutdown_asyncgens(), timeout=10)
|
||||
loop.stop()
|
||||
log.info("Shutdown complete.")
|
||||
|
||||
|
||||
def main():
|
||||
import sdnotify
|
||||
import signal
|
||||
import setproctitle
|
||||
setproctitle.setproctitle("c3lf-sys3")
|
||||
logging.basicConfig(filename='server.log', level=logging.DEBUG, encoding='utf-8')
|
||||
logging.basicConfig(filename='test.log', level=logging.DEBUG, encoding='utf-8')
|
||||
logging.basicConfig(filename='lmtp.log', level=logging.DEBUG, encoding='utf-8')
|
||||
log = logging.getLogger()
|
||||
log.info("Starting server")
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.add_signal_handler(signal.SIGTERM, lambda: asyncio.create_task(shutdown(signal.SIGTERM, loop)))
|
||||
loop.add_signal_handler(signal.SIGINT, lambda: asyncio.create_task(shutdown(signal.SIGINT, loop)))
|
||||
loop.create_task(web())
|
||||
loop.create_task(tcp())
|
||||
loop.create_task(lmtp())
|
||||
n = sdnotify.SystemdNotifier()
|
||||
n.notify("READY=1")
|
||||
log.info("Server ready")
|
||||
try:
|
||||
loop.run_forever()
|
||||
finally:
|
||||
loop.close()
|
||||
logging.info("Server stopped")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue