EQUENOS / dislash.py

A Python wrapper for discord slash-commands and buttons, designed to extend discord.py.

Home Page:https://dislashpy.readthedocs.io/en/latest

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Slash command interaction is expired on arrival

diogoriba opened this issue · comments

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:

def snowflake_time(ID):
return datetime.datetime.fromtimestamp(((ID >> 22) + DISCORD_EPOCH) / 1000)

@property
def created_at(self):
return snowflake_time(self.id)
@property
def expired(self):
utcnow = datetime.datetime.utcnow()
if self._sent:
return utcnow - self.created_at > datetime.timedelta(minutes=15)
else:
return utcnow - self.created_at > datetime.timedelta(seconds=3)

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).

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

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

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!

You're welcome