python ircd using asyncio
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

66 lines
1.8 KiB

  1. from asyncio import create_task, run, start_server, IncompleteReadError
  2. from asyncio.streams import StreamReader, StreamWriter
  3. from logging import basicConfig, info, INFO
  4. import logging
  5. from os import getenv
  6. from sys import exc_info
  7. from dotenv import load_dotenv
  8. load_dotenv("../.env")
  9. from paircd.client import Client # noqa: E402
  10. from paircd.handlers import handle_cmd, register_cmd_handlers # noqa: E402
  11. from paircd.message import parse_message # noqa: E402
  12. from paircd.server import Server # noqa: E402
  13. basicConfig(format="%(asctime)s [%(levelname)s] - %(message)s", level=INFO)
  14. async def read_forever(server: Server, client: Client) -> None:
  15. while not client.closed:
  16. try:
  17. raw_msg = await client.reader.readuntil(b"\r\n")
  18. except IncompleteReadError:
  19. logging.warning("client connection closed", exc_info=exc_info())
  20. await client.quit(server, "Connection reset by peer")
  21. break
  22. msg = parse_message(raw_msg)
  23. await handle_cmd(server, client, msg)
  24. async def serve() -> None:
  25. bind_addr = getenv("BIND_ADDR") or "0.0.0.0"
  26. port = getenv("PORT") or 6667
  27. irc_server = Server()
  28. register_cmd_handlers()
  29. async def register_client(reader: StreamReader, writer: StreamWriter) -> None:
  30. client = Client(
  31. hostname=writer.get_extra_info("peername")[0],
  32. reader=reader,
  33. writer=writer,
  34. )
  35. create_task(read_forever(irc_server, client))
  36. create_task(client.write_until_closed(irc_server))
  37. server = await start_server(
  38. register_client,
  39. bind_addr,
  40. port,
  41. reuse_port=True,
  42. )
  43. info(f"Listening on {bind_addr}:{port}")
  44. async with server:
  45. await server.serve_forever()
  46. def main() -> None:
  47. run(serve())
  48. if __name__ == "__main__":
  49. main()