c3lf-system-3/core/server.py

130 lines
4 KiB
Python

#!/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()