Closed jiajunhuang closed 3 months ago
You can't show an alert out of nowhere, you have to respond to the user's action like pressing a callback button.
But I don't see any difference between c.Respond
and bot.Respond
, as c.Respond
is just an wrapper:
func (c *nativeContext) Respond(resp ...*CallbackResponse) error {
if c.u.Callback == nil {
return errors.New("telebot: context callback is nil")
}
return c.b.Respond(c.u.Callback, resp...)
}
// where c.b is a *Bot instance
and bot.Respond
is just calling answerCallbackQuery
with callback.ID
:
// Respond sends a response for a given callback query. A callback can
// only be responded to once, subsequent attempts to respond to the same callback
// will result in an error.
//
// Example:
//
// b.Respond(c)
// b.Respond(c, response)
func (b *Bot) Respond(c *Callback, resp ...*CallbackResponse) error {
var r *CallbackResponse
if resp == nil {
r = &CallbackResponse{}
} else {
r = resp[0]
}
r.CallbackID = c.ID
_, err := b.Raw("answerCallbackQuery", r)
return err
}
So it should work if I call the Respond
method of bot instance directly like
bot, err := tb.NewBot(...)
err = bot.Respond(
&tb.Callback{ID: req.CallbackID},
&tb.CallbackResponse{Text: req.Text, ShowAlert: req.ShowAlert},
)
I've check the response from server by enable verbose mode, which returns ok, but the alert dialog does not appear. I've check the response from server when I directly call c.Respond
too, which returns ok, but the alert dialog appears, but the question is both the request and response structure has no difference, where cause the different behavior?
Here is a testing script by using python-telegram-bot
, it works like code above:
import asyncio
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
from telegram.ext import (ApplicationBuilder, CallbackContext,
CallbackQueryHandler, CommandHandler, Updater)
async def start(update: Update, context: CallbackContext) -> None:
keyboard = [
[InlineKeyboardButton("Click me!", callback_data='welcome')],
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text('Welcome!', reply_markup=reply_markup)
async def another_coroutine_alert(bot, query):
await asyncio.sleep(5)
await bot.answer_callback_query(query.id, text="aha", show_alert=True)
async def button(update: Update, context: CallbackContext) -> None:
query = update.callback_query
# run in another coroutine and do not await it
asyncio.ensure_future(another_coroutine_alert(context.bot, query))
def main() -> None:
# Create the Updater and pass it your bot's token.
bot = ApplicationBuilder().token('<YOUR BOT TOKEN HERE>').build()
bot.add_handler(CommandHandler('start', start))
bot.add_handler(CallbackQueryHandler(button))
# Start the Bot
bot.run_polling()
if __name__ == '__main__':
main()
ensure_future let's us execute a coroutine in the background, without explicitly waiting for it to finish, and in the another_coroutine_alert
, we wait for 5 seconds to let the button
coroutine to be finished.
I've test it, and it works, the bot show an alert dialog after 5 seconds.
Finally, I've found the reason. a callback can't be respond more than once. I've add a empty c.Respond
in middleware to ensure that every button will be respond(so the client will not show a progress bar too long), after remove the empty c.Respond
, I can send respond async, and the client will show an alert dialog.
In normal case, we can send alert by:
c.Respond()
to send an alert, but as the QPS increase higher, I need to queue the respond and send the respond later, how can I send it?I've tried to do it like this:
first, save the message_id & callback_id from
c
:the API does not return any error, but the alert dialog does not appear, too.