aboutsummaryrefslogtreecommitdiffstats
path: root/bot/bot.py
diff options
context:
space:
mode:
Diffstat (limited to 'bot/bot.py')
-rw-r--r--bot/bot.py166
1 files changed, 14 insertions, 152 deletions
diff --git a/bot/bot.py b/bot/bot.py
index c7b87a65..221bfd62 100644
--- a/bot/bot.py
+++ b/bot/bot.py
@@ -1,24 +1,20 @@
-import asyncio
import logging
-import socket
-from contextlib import suppress
from typing import Optional
import discord
-from aiohttp import AsyncResolver, ClientSession, TCPConnector
-from async_rediscache import RedisSession
-from discord import DiscordException, Embed, Forbidden, Thread
+from botcore import BotBase
+from botcore.utils import scheduling
+from discord import DiscordException, Embed
from discord.ext import commands
-from discord.ext.commands import Cog, when_mentioned_or
-from bot import constants
+from bot import constants, exts
log = logging.getLogger(__name__)
-__all__ = ("Bot", "bot")
+__all__ = ("Bot", )
-class Bot(commands.Bot):
+class Bot(BotBase):
"""
Base bot instance.
@@ -29,16 +25,6 @@ class Bot(commands.Bot):
name = constants.Client.name
- def __init__(self, redis_session: RedisSession, **kwargs):
- super().__init__(**kwargs)
- self.http_session = ClientSession(
- connector=TCPConnector(resolver=AsyncResolver(), family=socket.AF_INET)
- )
- self._guild_available = asyncio.Event()
- self.redis_session = redis_session
- self.loop.create_task(self.check_channels())
- self.loop.create_task(self.send_log(self.name, "Connected!"))
-
@property
def member(self) -> Optional[discord.Member]:
"""Retrieves the guild member object for the bot."""
@@ -47,60 +33,6 @@ class Bot(commands.Bot):
return None
return guild.me
- @Cog.listener()
- async def on_thread_join(self, thread: Thread) -> None:
- """
- Try to join newly created threads.
-
- Despite the event name being misleading, this is dispatched when new threads are created.
- We want our bots to automatically join threads in order to answer commands using their prefixes.
- """
- if thread.me:
- # Already in this thread, return early
- return
-
- with suppress(Forbidden):
- await thread.join()
-
- async def close(self) -> None:
- """Close Redis session when bot is shutting down."""
- await super().close()
-
- if self.http_session:
- await self.http_session.close()
-
- if self.redis_session:
- await self.redis_session.close()
-
- def add_cog(self, cog: commands.Cog) -> None:
- """
- Delegate to super to register `cog`.
-
- This only serves to make the info log, so that extensions don't have to.
- """
- super().add_cog(cog)
- log.info(f"Cog loaded: {cog.qualified_name}")
-
- def add_command(self, command: commands.Command) -> None:
- """Add `command` as normal and then add its root aliases to the bot."""
- super().add_command(command)
- self._add_root_aliases(command)
-
- def remove_command(self, name: str) -> Optional[commands.Command]:
- """
- Remove a command/alias as normal and then remove its root aliases from the bot.
-
- Individual root aliases cannot be removed by this function.
- To remove them, either remove the entire command or manually edit `bot.all_commands`.
- """
- command = super().remove_command(name)
- if command is None:
- # Even if it's a root alias, there's no way to get the Bot instance to remove the alias.
- return
-
- self._remove_root_aliases(command)
- return command
-
async def on_command_error(self, context: commands.Context, exception: DiscordException) -> None:
"""Check command errors for UserInputError and reset the cooldown if thrown."""
if isinstance(exception, commands.UserInputError):
@@ -144,84 +76,14 @@ class Bot(commands.Bot):
await devlog.send(embed=embed)
- async def on_guild_available(self, guild: discord.Guild) -> None:
- """
- Set the internal `_guild_available` event when PyDis guild becomes available.
+ async def setup_hook(self) -> None:
+ """Default async initialisation method for discord.py."""
+ await super().setup_hook()
- If the cache appears to still be empty (no members, no channels, or no roles), the event
- will not be set.
- """
- if guild.id != constants.Client.guild:
- return
-
- if not guild.roles or not guild.members or not guild.channels:
- log.warning("Guild available event was dispatched but the cache appears to still be empty!")
- return
+ await self.check_channels()
- self._guild_available.set()
-
- async def on_guild_unavailable(self, guild: discord.Guild) -> None:
- """Clear the internal `_guild_available` event when PyDis guild becomes unavailable."""
- if guild.id != constants.Client.guild:
- return
+ # This is not awaited to avoid a deadlock with any cogs that have
+ # wait_until_guild_available in their cog_load method.
+ scheduling.create_task(self.load_extensions(exts))
- self._guild_available.clear()
-
- async def wait_until_guild_available(self) -> None:
- """
- Wait until the PyDis guild becomes available (and the cache is ready).
-
- The on_ready event is inadequate because it only waits 2 seconds for a GUILD_CREATE
- gateway event before giving up and thus not populating the cache for unavailable guilds.
- """
- await self._guild_available.wait()
-
- def _add_root_aliases(self, command: commands.Command) -> None:
- """Recursively add root aliases for `command` and any of its subcommands."""
- if isinstance(command, commands.Group):
- for subcommand in command.commands:
- self._add_root_aliases(subcommand)
-
- for alias in getattr(command, "root_aliases", ()):
- if alias in self.all_commands:
- raise commands.CommandRegistrationError(alias, alias_conflict=True)
-
- self.all_commands[alias] = command
-
- def _remove_root_aliases(self, command: commands.Command) -> None:
- """Recursively remove root aliases for `command` and any of its subcommands."""
- if isinstance(command, commands.Group):
- for subcommand in command.commands:
- self._remove_root_aliases(subcommand)
-
- for alias in getattr(command, "root_aliases", ()):
- self.all_commands.pop(alias, None)
-
-
-_allowed_roles = [discord.Object(id_) for id_ in constants.MODERATION_ROLES]
-
-_intents = discord.Intents.default() # Default is all intents except for privileged ones (Members, Presences, ...)
-_intents.bans = False
-_intents.integrations = False
-_intents.invites = False
-_intents.typing = False
-_intents.webhooks = False
-
-redis_session = RedisSession(
- address=(constants.RedisConfig.host, constants.RedisConfig.port),
- password=constants.RedisConfig.password,
- minsize=1,
- maxsize=20,
- use_fakeredis=constants.RedisConfig.use_fakeredis,
- global_namespace="sir-lancebot"
-)
-loop = asyncio.get_event_loop()
-loop.run_until_complete(redis_session.connect())
-
-bot = Bot(
- redis_session=redis_session,
- command_prefix=when_mentioned_or(constants.Client.prefix),
- activity=discord.Game(name=f"Commands: {constants.Client.prefix}help"),
- allowed_mentions=discord.AllowedMentions(everyone=False, roles=_allowed_roles),
- intents=_intents,
-)
+ await self.send_log(self.name, "Connected!")