SurPathHub / Dayong

Discord Bot for SurPath Hub's server
https://sph-docs.netlify.app/docs/Dayong
MIT License
6 stars 4 forks source link

Event listeners raising unexpected and unwanted exceptions #2

Closed huenique closed 3 years ago

huenique commented 3 years ago

Dayong's features are contained within cogs, otherwise known as extensions. As such, it makes sense to define an event listener in the cog for certain features. However, due to how discord.py implements event listeners for bots or cogs, overriding an event like on_message is a fatal mistake. Doing so will overwrite any other explicitly defined on_message method or function found somewhere else in the codebase. It may be fine for a bot with a fixed number of features, but for a multipurpose bot, like Dayong, at scale, it's bound to cause a number of issues.

Solution I thought about moving the event listeners in a separate directory with each event having its own module. We only have to overwrite an event listener once. I think this looks OK:

Dayong
├── README.md
└── dayong
    └── listeners
        └── on_message.py
# on_message.py
from dayong.cogs import moderator

@Cog.listener()
async def on_message(self, message):
    # Mod is a cog loaded in another module so it doesn't need to be
    # instantiated here. I would recommend using static methods or
    # functions for features that require the use of event listeners.
    mod = moderator.Mod

    # Run coroutine that checks if there are bad words in the message.
    # delete_vulgar_message() is a static method denoted by the `staticmethod`
    # decorator.
    await mod.delete_vulgar_message(message)
    ...

In the above code, I registered the delete_vulgar_message() feature from the cog moderator.py. The feature takes the Message instance as an argument and does its job on it.

Additional Context External event listeners allow you to hear and handle multiple events from different servers, channels, users, etc. A single listener for a specific event is usually enough to handle different operations.

huenique commented 3 years ago

The proposed solution defeats the purpose of cogs. And you're actually not supposed to use the Cog class and its methods outside its subclass. As for the issue, discord.py already has a feature that prevents these types of problems. Instead of overriding events such as on_message, on_member_join, and on_command_error, supply the name of the event as an argument to Cog.listener(). The listener method has a name parameter, the name of the event being listened to which defaults to function or method's name. Good issue, @huenique, but next time actually read the documentation.