types.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. from dataclasses import dataclass, field
  2. from datetime import datetime
  3. from collections.abc import Callable, Coroutine, Container
  4. from typing import Union, Any, Optional
  5. from aiosqlite.core import Connection
  6. @dataclass
  7. class Attachment:
  8. name: str
  9. body: Union[str, bytes]
  10. @dataclass
  11. class Message:
  12. origin_id: str
  13. channel_id: str
  14. sender_id: str
  15. timestamp: datetime
  16. origin_admin: bool
  17. channel_admin: bool
  18. text: Optional[str] = None
  19. attachments: list[Attachment] = field(default_factory=list)
  20. def __post_init__(self):
  21. self.command = None
  22. @dataclass
  23. class Command:
  24. bang: str
  25. name: str
  26. args: str
  27. @staticmethod
  28. def from_text(text: str) -> Optional["Command"]:
  29. cleaned = text.lstrip()
  30. if len(cleaned) < 2:
  31. return None
  32. parts = cleaned[1:].lstrip().split(maxsplit=1)
  33. if len(parts) == 0:
  34. return None
  35. return Command(
  36. bang=cleaned[0],
  37. name=parts[0],
  38. args=parts[1] if len(parts) > 1 else "",
  39. )
  40. @dataclass
  41. class Response:
  42. origin_id: str
  43. channel_id: str
  44. text: Optional[str] = None
  45. attachments: Optional[list[Attachment]] = None
  46. @staticmethod
  47. def from_message(
  48. msg: Message, text: Optional[str] = None, attachments: list[Attachment] = None
  49. ) -> "Response":
  50. return Response(
  51. origin_id=msg.origin_id,
  52. channel_id=msg.channel_id,
  53. text=text,
  54. attachments=attachments or [],
  55. )
  56. @dataclass
  57. class Context:
  58. config: Callable[[str], Any]
  59. respond: Callable[[], Coroutine[None, None, None]]
  60. database: Callable[[], Coroutine[None, None, Connection]]
  61. CommandType = Callable[[Message, Context], Coroutine[None, None, None]]
  62. StartupShutdownType = Callable[[Context], Coroutine[None, None, None]]
  63. @dataclass
  64. class CommandConfiguration:
  65. commands: dict[str, CommandType] = field(default_factory=dict)
  66. call_and_response: dict[str, str] = field(default_factory=dict)
  67. aliases: dict[str, str] = field(default_factory=dict)
  68. bangs: Container[str] = ("!",)
  69. startup: list[StartupShutdownType] = field(default_factory=list)
  70. shutdown: list[StartupShutdownType] = field(default_factory=list)
  71. def extend(self, other: "CommandConfiguration") -> "CommandConfiguration":
  72. return CommandConfiguration(
  73. commands={
  74. **self.commands,
  75. **other.commands,
  76. },
  77. call_and_response={
  78. **self.call_and_response,
  79. **other.call_and_response,
  80. },
  81. aliases={
  82. **self.aliases,
  83. **other.aliases,
  84. },
  85. bangs=(*self.bangs, *other.bangs),
  86. startup=[*self.startup, *other.startup],
  87. shutdown=[*self.shutdown, *other.shutdown],
  88. )