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

Reply to Telegram requests directly in webhook mode

Open zhulik opened this issue 7 years ago • 7 comments

Due to official FAQ https://core.telegram.org/bots/faq#how-can-i-make-requests-in-response-to-updates, it's possible to reply direcly to Telegram requests in webhook mode. It's a preferrable way for highly-loadded bots because of reducing API calls.

As I can see, there is no way to work in such mode with your library.

I suggest to implement render method in UpdatesController and allow users to respond to Telegram requests direcly. It will solve few problems:

  • Reduce overall count of requests to Telegram API(do you remember about 429?)
  • Allow users to move bot logic from controller to their own handlers/classes/etc without pain and test it the their own manner

In poller mode render method can work as respond_with and use API call

zhulik avatar Jan 05 '18 13:01 zhulik

Does it support multiple responses? It's usual to make 2 api requests for callback queries: edit message with new content and telegram requires answer_callback_query to stop showing spinner.

It's also not clear how this should work when poller fetches multiple updates at a time. Do you have a link to detailed explanation of "Reply directly and give method as JSON payload in the reply"?

printercu avatar Jan 05 '18 14:01 printercu

It does not support multiple responses, so sometimes it's needed to use API. But, it allows to overcome telegram API restrictions such as 429 responses.

About callback_queries: spinner is hiding when you update the message, so the answer_callback_query isn't required. UPD: seems like it's platform-dependent, I still see the spinners on my Android phone, but they are hiding on my Linux laptop

For poller mode there is no difference if it fetches multiple updates, render should just be mapped to respond_with.

Example can be found in FAQ: https://core.telegram.org/bots/samples/hellobot

zhulik avatar Jan 05 '18 14:01 zhulik

For poller mode there is no difference

Yep, I've messed all together - it's not related to poller mode where multiple updates may appear within single request.

For now I don't want to keep separate apis for responding within and outside webhook, I'll think more about it. I think about some wrapper like webhook_response { bot.some_action(...) } which will also work with all existing helpers: webhook_response { respond_with :message, text: '...' }. This also may be implemented smart, so it would respond to webhook with one of multiple actions and make api calls for the rest.

I hope you can use this small patch to give this feature a try in production and share feedback:

# in controller
def dispatch
  super
  @_response
end

protected def render(result)
  @_response = result.to_json
end

# sample usage
def smth(*)
  render method: :sendMessage, text: '....'
  # bot.any_additional_api_calls
end

# and modified middleware
Telegram::Bot::Middleware.class_eval do
  def call(env)
    request = ActionDispatch::Request.new(env)
    update = request.request_parameters
    response = controller.dispatch(bot, update)
    if response
      [200, {'Content-Type' => 'application/json'}, [response]]      
    else
      [200, {}, ['']]
    end
  end
end

UPD. updated middleware to set content-type for json responses.

printercu avatar Jan 05 '18 15:01 printercu

Thank you, will try ASAP

zhulik avatar Jan 05 '18 15:01 zhulik

I've updated middleware in my snippet, please use updated version.

printercu avatar Jan 05 '18 15:01 printercu

Have you tried suggested solution? I appreciate any feedback on responses to http hooks (issues in production, limitations, etc.).

printercu avatar Mar 04 '18 10:03 printercu

Oh, sorry, I have no time to check it=(

zhulik avatar Mar 04 '18 21:03 zhulik