bot.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. from dataclasses import dataclass
  2. from typing import Any, Generic, TypeVar
  3. import asyncio
  4. import logging
  5. import aiosqlite
  6. import aiohttp
  7. from .types import CommandConfiguration, Message, Response, Context, Command
  8. RawMsg = TypeVar("RawMsg")
  9. @dataclass
  10. class Rollbot(Generic[RawMsg]):
  11. command_config: CommandConfiguration
  12. database_file: str
  13. def __post_init__(self):
  14. self.context = Context(
  15. config=self.read_config,
  16. respond=self.respond,
  17. request=aiohttp.ClientSession(),
  18. database=lambda: aiosqlite.connect(self.database_file),
  19. logger=logging.getLogger(),
  20. )
  21. def read_config(self, key: str) -> Any:
  22. raise NotImplementedError("Must be implemented by driver")
  23. def parse(self, incoming: RawMsg) -> Message:
  24. raise NotImplementedError("Must be implemented by driver")
  25. async def respond(self, response: Response):
  26. raise NotImplementedError("Must be implemented by driver")
  27. async def on_startup(self):
  28. await asyncio.gather(*[task(self.context) for task in self.command_config.startup])
  29. async def on_shutdown(self):
  30. await asyncio.gather(*[task(self.context) for task in self.command_config.shutdown])
  31. await self.context.request.close()
  32. async def on_message(self, incoming: RawMsg):
  33. message = self.parse(incoming)
  34. if message.text is None:
  35. return
  36. message.command = Command.from_text(message.text)
  37. if message.command is None or message.command.bang not in self.command_config.bangs:
  38. return
  39. command = self.command_config.aliases.get(message.command.name, message.command.name)
  40. res = self.command_config.call_and_response.get(command, None)
  41. if res is not None:
  42. await self.respond(Response.from_message(message, res))
  43. return
  44. command_call = self.command_config.commands.get(command, None)
  45. if command_call is None:
  46. await self.respond(
  47. Response.from_message(message, f"Sorry! I don't know the command {command}.")
  48. )
  49. return
  50. await command_call(message, self.context)