12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- from __future__ import annotations
- import io
- import asyncio
- import logging.config
- import os
- import toml
- import discord
- import rollbot
- from commands import config
- logging.config.fileConfig("logging.conf", disable_existing_loggers=False)
- with open(os.environ.get("SECRET_FILE", "secrets.toml"), "r") as sfile:
- secrets = toml.load(sfile)
- database_file = os.environ.get("DATABASE_FILE", secrets["database_file"])
- class DiscordBot(rollbot.Rollbot[discord.Message]):
- def __init__(self, client):
- super().__init__(config.extend(rollbot.CommandConfiguration(bangs=("!",))), database_file)
- self.discord_client = client
- client.event(self.on_message)
- def read_config(self, key: str) -> Any:
- cfg = secrets
- for part in key.split("."):
- cfg = cfg.get(part, None)
- if cfg is None:
- return None
- return cfg
- async def parse(self, msg: discord.Message) -> rollbot.Message:
- return rollbot.Message(
- origin_id="DISCORD",
- channel_id=str(msg.channel.id),
- sender_id=str(msg.author.id),
- timestamp=msg.created_at,
- origin_admin="RollbotAdmin" in [r.name for r in msg.author.roles],
- channel_admin=False, # TODO - implement this if discord allows it
- sender_name=msg.author.name,
- text=msg.content,
- # TODO might be nice to only read attachments once we're sure we need to
- attachments=[rollbot.Attachment(
- name=att.filename,
- body=await att.read(),
- ) for att in msg.attachments],
- )
- async def respond(self, response: rollbot.Response):
- if response.origin_id != "DISCORD":
- self.context.logger.error(f"Unable to respond to {response.origin_id}")
- return
-
- channel = await self.discord_client.fetch_channel(response.channel_id)
- content=response.text or ""
- # TODO this implementation is wrong - attaches files instead of embedding an image
- # I *think* the right call is to send multiple messages since there's only one embed each
- # but I want to do a little more research before implementing that
- files = []
- if response.attachments is not None:
- for att in response.attachments:
- if att.name == "image":
- if isinstance(att.body, bytes):
- files.append(discord.File(io.BytesIO(att.body)))
- else:
- content += "\n" + att.body
- await channel.send(content=content, files=files)
- if __name__ == "__main__":
- loop = asyncio.get_event_loop()
- client = discord.Client(loop=loop)
- bot = DiscordBot(client)
- try:
- loop.run_until_complete(bot.on_startup())
- loop.run_until_complete(client.start(secrets["discord"]["token"]))
- except KeyboardInterrupt:
- loop.run_until_complete(client.close())
- finally:
- loop.run_until_complete(bot.on_shutdown())
|