Feature #3146
openHomework for Lesson 1: Set up Telegram Bot PHP WebHook
0%
Description
Welcome to your first homework. I am not just teaching you Telegram and giving you random homework, I will be giving you mini-projects so at the end of this course / sprint, you'll have a re-usable framework inside Qbix that you can re-use for many projects, and also have access to the full power of the Qbix platform at the same time :)
The lesson, code samples and related links can be found at https://issues.qbix.com/projects/telegram/wiki
Feel free to refer to that wiki, it will grow.
Information / Discussion¶
Read this: https://issues.qbix.com/projects/telegram/wiki/Telegram_Plugin
Set up Telegram Bot WebHook in PHP¶
For now, just practice setting up a web-server which is accessible from the internet. You have a couple options to make your local computer accessible from the Internet:
1) Dynamic DNS from https://www.duckdns.org/
2) SSH Tunnel simply mapping a remote port to a port on your machine, then have your NGinx listen on that port: https://serverfault.com/questions/1004529/access-an-http-server-as-localhost-from-an-external-pc-over-ssh
Anyway, practice calling setWebhook
method from PHP installer script.
https://core.telegram.org/bots/api#setwebhook
You shouldn't use HTTP (port 80) but rather HTTPS (port 443). Please generate a self-signed certificate, and Post it to setWebhook()
: https://core.telegram.org/bots/self-signed and https://stackoverflow.com/a/44550366
Also please generate and send secret_token
along, which will send along a header X-Telegram-Bot-Api-Secret-Token with each request.
Registering webhook¶
Add a hook plugins/Telegram/handlers/after/Q_Plugin_install.php
analogous to what we already have in Users_after_Q_Plugin_install
or Streams_after_Q_Plugin_install
This hook will run whenever installer runs. It will
$extra = Q_Plugin::extra('Telegram', 'plugin', 'Users'); $apps = Q_Config::get('Users', 'apps', 'telegram', array()); foreach ($apps as $app) { if (!empty($extra[$app])) { continue; // already installed for this app } $extra[$app] = array('setWebhook' => true); $extra = Q_Plugin::extra('Telegram', 'plugin', 'Users', $extra); $token = Q::ifset($app, 'token', null); $secret = Q::ifset($app, 'secret', Q_Config::get('Q', 'internal', 'secret', '')); if (!$token) continue; $cert = Q::ifset($app, 'cert', null); if ($certfile) { $certificate(file_get_contents($cert)); } $url = Q_Request::baseUrl('telegram.php'); $secret_token = "$app\t$secret"; // will come in header X-Telegram-Bot-Api-Secret-Token $result = Telegram_Bot::setWebhook(@compact('token', 'url', 'certificate', 'secret_token')); if ($result['error']) { throw new Telegram_Exception_Webhook(@compact('app', 'url', 'token', 'certificate')); } }
So now it registers webhooks that will call the controller telegram.php
Handling updates¶
Make telegram.php
controller call Telegram_Dispatcher::dispatch($update)
method when a request comes from a telegram bot.
It's similar to how index.php
controller calls Q_Dispatcher::dispatch($uri)
when a web request comes in from a browser, but the dispatcher will be much simpler.
Telegram_Dispatcher::dispatch($update)
should look at header('X-Telegram-Bot-Api-Secret-Token')
and $parts = explode("\t", $header)
to determine $appId = reset($parts)
. Now do $params = compact('appId', 'update')
. And call Q::event("Telegram/update", $params)
similar to how Q_Dispatcher
calls Q::event("Q/response")
.
The handler of Telegram/update"
event, in turn, would determine the update type (from a growing list of types such as "message" and "edited_message"), and then fire Q::event("Telegram/update/$appId/$updatetype)", $params
similar to how Q/response handler fires event "$module/$action/response/$slotname
.
So now, different plugins would be able to add handlers for these events. Suppose I had an app / bot on telegram with appId = "MyCoolBot" and internal appId "Calendars". Then as a developer of "Calendars" plugin module, I would implement events such as:
Telegram/update/Calendars/message
Telegram/update/Calendars/edited_message
Telegram/update/Calendars/callback_query
Artem can help you manually test at least these 3, by using the inline keyboard code from our lesson
Implementing the actual bots¶
Plugins will be able to implement any kind of complex logic to interact with a user. They might use AI
plugin with ChatGPT. They might query a database. They will probably store a context for each user, of what they remember about this user and conversation with him. But for now, we don't care what the plugins will do. We just built the support for them: installer, addWebhook, and handlers.
For the end of this homework, I'd ask you to use Telegram_Bot::sendVideo()
method that Artem will implement. I mean, it's a simple method, that you can implement too. But I gave it to Artem to practice calling sendVideo
, sendDocument
, etc.