EQUENOS / dislash.py

A Python wrapper for discord slash-commands and buttons, designed to extend discord.py.
https://dislashpy.readthedocs.io/en/latest
MIT License
167 stars 29 forks source link

Slash command interaction is expired on arrival #39

Closed diogoriba closed 3 years ago

diogoriba commented 3 years ago

When testing a simple slash command using dislash, when i get to the callback that handles the slash command, the interaction is already expired. The code i'm using to test this:

    @slash_commands.command(
        name="maybe_this_works",
        description="testing slash commands",
        guild_ids=[GUILD_ID]
    )
    async def maybe_this_works(self, inter:Interaction):
        logger.debug(inter)
        logger.debug("snowflake time: " + inter.created_at.isoformat())
        logger.debug("current time: " + dt.datetime.utcnow().isoformat())
        logger.debug("is expired: " + str(inter.expired))
        logger.debug("is sent: " + str(inter._sent))
        await inter.reply("hello!")

Output in discord: image Output in logs:

    vote     | maybe_this_works |   47 | DEBUG    | snowflake time: 2021-08-04T15:21:41.611000
    vote     | maybe_this_works |   48 | DEBUG    | current time: 2021-08-04T18:21:41.803420
    vote     | maybe_this_works |   49 | DEBUG    | is expired: True
    vote     | maybe_this_works |   50 | DEBUG    | is sent: False

Result of the logs show that the time being reported by interaction.created_at is not calculated as UTC.

It seems interaction.expired uses interaction.created_at which in turn uses a dislash.py specific implementation of snowflake_time that does not force the timestamp to be created in UTC+0: https://github.com/EQUENOS/dislash.py/blob/5b6d6b19ec078c914c9110b8c1a6a333145ec785/dislash/interactions/interaction.py#L15-L18 https://github.com/EQUENOS/dislash.py/blob/5b6d6b19ec078c914c9110b8c1a6a333145ec785/dislash/interactions/interaction.py#L98-L110

This differs from discord.py's implementation, which forces the timestamp to be calculated in UTC+0:

def snowflake_time(id: int) -> datetime.datetime:
    """
    Parameters
    -----------
    id: :class:`int`
        The snowflake ID.
    Returns
    --------
    :class:`datetime.datetime`
        An aware datetime in UTC representing the creation time of the snowflake.
    """
    timestamp = ((id >> 22) + DISCORD_EPOCH) / 1000
    return datetime.datetime.fromtimestamp(timestamp, tz=datetime.timezone.utc)

If I change dislash's function to use either datetime.datetime.utcfromtimestamp, or discord.py's implementation of snowflake_time, the problem goes away and the interaction is no longer considered expired on arrival.

I can make a pull request to fix that if it would help, I just needed to know which route would you rather use to fix that (change dislash.py's implementation or adopt discord.py's function instead).

EQUENOS commented 3 years ago

Seems like I messed up while making a custom snowflake_time function... I added this function in order to avoid some problems with dpy 2.0 utils subpackage, thanks for sharing this issue, you can make the PR of course

EQUENOS commented 3 years ago

I noticed that on some devices snowflake_time seems to offset the timestamp a little bit (3-4 seconds to the past), which causes the self.expired property to fail. I decided to solve this problem by creating an extra attribute for BaseInteraction called received_at. I just call datetime.utcnow() in __init__ an that's all. I understand that this method may lead to some inaccuracies in detecting the expiration of an interaction, but I believe it will be practically more useful than the old unstable method

diogoriba commented 3 years ago

thank you for the quick response, and for sharing the other updates to BaseInteraction @EQUENOS! i'm already downloading the new version here, these changes are going to be super helpful!

EQUENOS commented 3 years ago

You're welcome