bot.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. if command == "help":
  41. args = message.command.args.split(maxsplit=1)
  42. if len(args) == 0:
  43. help_msg = "Use this command to look up the help info of another command, try !help roll for example!"
  44. else:
  45. cmd = self.command_config.commands.get(args[0], None)
  46. if cmd is None or cmd.__doc__ is None:
  47. help_msg = "Sorry! I don't have any explanation of that command"
  48. else:
  49. help_msg = cmd.__doc__.strip()
  50. await self.respond(Response.from_message(message, help_msg))
  51. return
  52. res = self.command_config.call_and_response.get(command, None)
  53. if res is not None:
  54. await self.respond(Response.from_message(message, res))
  55. return
  56. command_call = self.command_config.commands.get(command, None)
  57. if command_call is None:
  58. await self.respond(
  59. Response.from_message(message, f"Sorry! I don't know the command {command}.")
  60. )
  61. return
  62. await command_call(message, self.context)