telegram.bot icon indicating copy to clipboard operation
telegram.bot copied to clipboard

Async execution

Open hmeleiro opened this issue 2 years ago • 2 comments

I'm wondering if there is a way to write a bot that could handle simultaneous user petitions like in the python version of this library. Or maybe implement from outside with coro package? Would this be possible?

I have a basic understanding of concurrency and async functions, so I would not know where to start, but I'm going to give it a try with coro package and if it is possible write some kind of minimal example.

hmeleiro avatar Sep 20 '23 09:09 hmeleiro

I was not able to implement coro::async() function to telegram.bot handlers. But I managed to implement the async execution using Telegram API directly. Here is a simple example code:

library(httr)
library(jsonlite)
library(coro)

APIKEY <- ""
getUpdates <- function(){
  url <- sprintf("https://api.telegram.org/bot%s/getupdates", APIKEY)
  res <- GET(url)
  if(res$status_code == 200) {
    body <- content(res)
    
    return(body$result)
    
  } else {
    return(NULL)
  }
}

sendMessage <- async(
  function(update) {
    chat_id <- update$message$chat$id
    msg <- as.numeric(update$message$text)

    url <- sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&text=Sleeping_%s_seconds", APIKEY, chat_id, msg)
    GET(url)
    await(async_sleep(msg))
    
    url <- sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&text=Done_%s", APIKEY, chat_id, msg)
    GET(url)
  }
)

# The bot waits for the seconds you tell it to wait and sends you a message back when it has stopped waiting.
# Send two Telegram messages to the bot, first a high number (like 5) and then a lower one (1).
# Then run this code below
updates <- getUpdates()
for (update in updates) {
  sendMessage(update)
}

hmeleiro avatar Sep 20 '23 13:09 hmeleiro

I've been experimenting with the future package.

I have configured parallel processing of commands, but for some reason it only works once.

In my example, if you run a slow and fast function, the bot will process them in parallel. But when they are called again, the updates do not reach the bot.

How can this be fixed?

library(telegram.bot)
library(promises)
library(future)

future::plan(multisession, workers = 2)

bot_token <- ""

updater <- Updater(token = bot_token )

start <- function(bot, update) {
    
    RKM <- ReplyKeyboardMarkup(
        keyboard = list(
            list(
                KeyboardButton("Button"))
        ),
        resize_keyboard = TRUE,
        one_time_keyboard = FALSE
    )
    
    bot$sendMessage(update$message$chat_id,
                    text = "Hello",
                    reply_markup = RKM)
    }

start_hendler <- CommandHandler('start', start)

updater$dispatcher$add_handler(start_hendler)

MessageFilters$button <- BaseFilter(function(message) {
    message$text == "Button"
})


ikm_button <- function(bot, update) {
   
    IKM <- InlineKeyboardMarkup(
        inline_keyboard = list(
            list(
                InlineKeyboardButton(text = 'Slow', callback_data = 'slow')),
            list(
                InlineKeyboardButton(text = 'Fast', callback_data = 'fast'))
        )
    )
    
    bot$sendMessage(chat_id = update$message$chat_id, 
                    text = "Select function", 
                    reply_markup = IKM)
}

ikm_button_hendler <- MessageHandler(ikm_button, filters = MessageFilters$button)

updater$dispatcher$add_handler(ikm_button_hendler)

flow_fun <- function(bot, update) { 
    
    promises::future_promise({
        
        bot$answerCallbackQuery(callback_query_id = update$callback_query$id)
       
        bot$sendMessage(chat_id = update$from_chat_id(),
                        text = "start slow calc...")
        Sys.sleep(5)
        
        bot$sendMessage(chat_id = update$from_chat_id(),
                        text = "slow calc complete...")
    })
    
}

flow_fun_handler <- CallbackQueryHandler(flow_fun, pattern = "slow")

updater$dispatcher$add_handler(flow_fun_handler)

fast_fun <- function(bot, update) { 
    
    promises::future_promise({
        
        bot$answerCallbackQuery(callback_query_id = update$callback_query$id)
        
        bot$sendMessage(chat_id = update$from_chat_id(),
                        text = "start fast calc....")
        
        Sys.sleep(1)
        
        bot$sendMessage(chat_id = update$from_chat_id(),
                        text = "fast calc complete...")
    })
}

fast_fun_handler <- CallbackQueryHandler(fast_fun, pattern = "fast")

updater$dispatcher$add_handler(fast_fun_handler)

updater$start_polling(verbose = TRUE, clean = TRUE)

RKonstantinR avatar Oct 02 '23 14:10 RKonstantinR

Hi, thanks for the comment, right now this fuctionality is not developed in-package.

ebeneditos avatar Apr 08 '24 10:04 ebeneditos