6
votes

Assuming a command similar to this:

@bot.command()
async def test(ctx):
    def check(r, u):
        return u == ctx.message.author and r.message.channel == ctx.message.channel and str(r.emoji) == '✅'

    await ctx.send("React to this with ✅")
    try:
        reaction, user = await bot.wait_for('reaction_add', timeout=300.0, check=check)
    except asyncio.TimeoutError:
        await ctx.send('Timeout')
    else:
        await ctx.send('Cool, thanks!')

Is there any way to cancel that wait_for if the user sends the same command multiple times before actually reacting to the message? So the bot stop waiting for reactions on previously sent messages and only waits for the last one.

1
Im not sure when stuff is called here, but bot.wait_for is a coroutine, and it can be canceled with .cancel() docs.python.org/3/library/asyncio-task.html#asyncio.Task.cancelRon Serruya
Yes, but I don't know how to get the reference to the actual coroutine in order to cancel it :/YaW

1 Answers

4
votes

Would something like this work for you?

pending_tasks = dict()

async def test(ctx):
    def check(r, u):
        return u == ctx.message.author and r.message.channel == ctx.message.channel and str(r.emoji) == '✅'

    await ctx.send("React to this with ✅")
    try:
        if ctx.message.author in pending_tasks:
            pending_tasks[ctx.message.author].close()
        pending_tasks[ctx.message.author] = bot.wait_for('reaction_add', timeout=300.0, check=check)
        reaction, user = await pending_tasks[ctx.message.author]
    except asyncio.TimeoutError:
        await ctx.send('Timeout')
    else:
        await ctx.send('Cool, thanks!')

You store all of the pending requests in a dict, and before creating another request you check if you are already have an existing task for this user, if you do you cancel it and create a new one