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.

53 lines
1.4 KiB

2 years ago
  1. from dataclasses import dataclass
  2. from typing import List, Optional
  3. MAX_MESSAGE_SIZE = 512
  4. class ParsingError(Exception):
  5. message: Optional[str]
  6. def __init__(self, message: Optional[str] = None) -> None:
  7. self.message = message
  8. @dataclass
  9. class Message:
  10. cmd: str
  11. args: List[str]
  12. prefix: str = "localhost"
  13. def encode(self) -> bytes:
  14. prefix = self.prefix
  15. if prefix != "":
  16. prefix = f":{prefix} "
  17. # TODO: Raise exception if formatted message exceeds 512 bytes
  18. return f"{prefix}{self.cmd} {' '.join(self.args)}\r\n".encode("utf-8")
  19. def parse_message(raw: bytes) -> Message:
  20. if len(raw) > MAX_MESSAGE_SIZE:
  21. raise ParsingError(
  22. f"Message is {len(raw)} bytes, larger than allowed {MAX_MESSAGE_SIZE}"
  23. )
  24. if not raw.endswith(b"\r\n"):
  25. raise ParsingError("Message does not terminate in CRLF")
  26. tokens: List[str] = []
  27. raw_tokens: List[str] = raw.decode("utf-8").split(" ")
  28. for i, token in enumerate(raw_tokens):
  29. if token.startswith(":"):
  30. trailing = token[1:] + " " + " ".join(raw_tokens[i + 1 :])
  31. tokens.append(trailing)
  32. break
  33. tokens.append(token)
  34. if len(tokens) == 0:
  35. raise ParsingError("Message has no command")
  36. cmd = tokens[0].upper()
  37. tokens[-1] = tokens[-1].strip()
  38. return Message(cmd=cmd, args=tokens[1:])