diff options
author | 2022-02-21 02:12:19 +0000 | |
---|---|---|
committer | 2022-02-24 20:07:37 +0000 | |
commit | 3e16dfc1b64ecfb4aa12aebc60e119dd620ef315 (patch) | |
tree | 50f07bcf1046d64394f34d8d46b9d4b02438b4d3 /botcore | |
parent | Change discord API wrapper to disnake (diff) |
Add disnake monkey patches
This covers the monkeypatches for Commands and Groups to allow for root aliases, along with a monkey patch for typing events, in case discord decides to raise 403s again.
Co-authored-by: Mark <[email protected]>
Co-authored-by: Hassan Abouelela <[email protected]>
Diffstat (limited to 'botcore')
-rw-r--r-- | botcore/utils/__init__.py | 3 | ||||
-rw-r--r-- | botcore/utils/monkey_patches.py | 83 |
2 files changed, 85 insertions, 1 deletions
diff --git a/botcore/utils/__init__.py b/botcore/utils/__init__.py index 71354334..671ef49f 100644 --- a/botcore/utils/__init__.py +++ b/botcore/utils/__init__.py @@ -1,6 +1,6 @@ """Useful utilities and tools for discord bot development.""" -from botcore.utils import (caching, channel, extensions, logging, members, regex, scheduling) +from botcore.utils import (caching, channel, extensions, logging, members, monkey_patches, regex, scheduling) __all__ = [ caching, @@ -8,6 +8,7 @@ __all__ = [ extensions, logging, members, + monkey_patches, regex, scheduling, ] diff --git a/botcore/utils/monkey_patches.py b/botcore/utils/monkey_patches.py new file mode 100644 index 00000000..abbb37a5 --- /dev/null +++ b/botcore/utils/monkey_patches.py @@ -0,0 +1,83 @@ +"""Contains all common monkey patches, used to alter disnake to fit our needs.""" + +import logging +from datetime import datetime, timedelta +from functools import partial, partialmethod + +from disnake import Forbidden, http +from disnake.ext import commands + +log = logging.getLogger(__name__) + + +class _Command(commands.Command): + """ + A :obj:`disnake.ext.commands.Command` subclass which supports root aliases. + + A ``root_aliases`` keyword argument is added, which is a sequence of alias names that will act as + top-level commands rather than being aliases of the command's group. It's stored as an attribute + also named ``root_aliases``. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.root_aliases = kwargs.get("root_aliases", []) + + if not isinstance(self.root_aliases, (list, tuple)): + raise TypeError("Root aliases of a command must be a list or a tuple of strings.") + + +class _Group(commands.Group, _Command): + """ + A :obj:`disnake.ext.commands.Group` subclass which supports root aliases. + + A ``root_aliases`` keyword argument is added, which is a sequence of alias names that will act as + top-level groups rather than being aliases of the command's group. It's stored as an attribute + also named ``root_aliases``. + """ + + +def _patch_typing() -> None: + """ + Sometimes Discord turns off typing events by throwing 403s. + + Handle those issues by patching disnake's internal ``send_typing`` method so it ignores 403s in general. + """ + log.debug("Patching send_typing, which should fix things breaking when Discord disables typing events. Stay safe!") + + original = http.HTTPClient.send_typing + last_403 = None + + async def honeybadger_type(self, channel_id: int) -> None: # noqa: ANN001 + nonlocal last_403 + if last_403 and (datetime.utcnow() - last_403) < timedelta(minutes=5): + log.warning("Not sending typing event, we got a 403 less than 5 minutes ago.") + return + try: + await original(self, channel_id) + except Forbidden: + last_403 = datetime.utcnow() + log.warning("Got a 403 from typing event!") + + http.HTTPClient.send_typing = honeybadger_type + + +def apply_monkey_patches() -> None: + """ + Applies all common monkey patches for our bots. + + Patches :obj:`disnake.ext.commands.Command` and :obj:`disnake.ext.commands.Group` to support root aliases. + A ``root_aliases`` keyword argument is added to these two objects, which is a sequence of alias names + that will act as top-level groups rather than being aliases of the command's group. + + It's stored as an attribute also named ``root_aliases`` + + Patches disnake's internal ``send_typing`` method so that it ignores 403 errors from Discord. + When under heavy load Discord has added a CloudFlare worker to this route, which causes 403 errors to be thrown. + """ + commands.command = partial(commands.command, cls=_Command) + commands.GroupMixin.command = partialmethod(commands.GroupMixin.command, cls=_Command) + + commands.group = partial(commands.group, cls=_Group) + commands.GroupMixin.group = partialmethod(commands.GroupMixin.group, cls=_Group) + _patch_typing() |