from asyncio import create_task, run, start_server, IncompleteReadError from asyncio.streams import StreamReader, StreamWriter from logging import basicConfig, info, INFO import logging from os import getenv from sys import exc_info from dotenv import load_dotenv load_dotenv("../.env") from paircd.client import Client # noqa: E402 from paircd.handlers import handle_cmd, register_cmd_handlers # noqa: E402 from paircd.message import parse_message # noqa: E402 from paircd.server import Server # noqa: E402 basicConfig(format="%(asctime)s [%(levelname)s] - %(message)s", level=INFO) async def read_forever(server: Server, client: Client) -> None: while not client.closed: try: raw_msg = await client.reader.readuntil(b"\r\n") except IncompleteReadError: logging.warning("client connection closed", exc_info=exc_info()) await server.disconnect_client(client.nickname, "Connection reset by peer") break msg = parse_message(raw_msg) await handle_cmd(server, client, msg) async def serve() -> None: bind_addr = getenv("BIND_ADDR") or "0.0.0.0" port = getenv("PORT") or 6667 irc_server = Server() register_cmd_handlers() async def register_client(reader: StreamReader, writer: StreamWriter) -> None: client = Client( hostname=writer.get_extra_info("peername")[0], reader=reader, writer=writer, ) create_task(read_forever(irc_server, client)) create_task(client.write_until_closed(irc_server)) server = await start_server( register_client, bind_addr, port, reuse_port=True, ) info(f"Listening on {bind_addr}:{port}") async with server: await server.serve_forever() def main() -> None: run(serve()) if __name__ == "__main__": main()