Writing a Telegram echo bot in C
Table of Contents
Photo by @ilgmyzin from Unsplash.com
My main programming language is C (even though I’d like to write more Go these days). I’ve been working with it for years, and since I use Telegram daily, I figured: why not write a bot in C? I know there’s already telebot, but I wanted to learn something new.
In this post, we’re going to build a simple echo bot, it replies with whatever you send it. We’ll use libcurl for HTTP and yyjson for parsing the responses.
Requirements
libcurlyyjson- A Telegram bot token (get one from @BotFather)
Understanding Long Polling
Before writing any code, let’s talk about how we’re going to receive messages. Telegram offers two methods: webhooks and long polling. We’re going with long polling, it’s simpler.
Here’s the idea: we open an HTTP connection to Telegram’s API and keep it open for up to 30 seconds, waiting for new updates. If a message arrives, the server responds immediately with the data. If nothing shows up before the timeout, the connection closes and we open a new one.
This is way more efficient than short polling (you are basically spamming their servers with requests every a few second).
The Bot Structure
Let’s start by defining the data structures we’ll use throughout the code:
|
|
The tgbot struct holds everything our bot needs: the curl handle for making requests, the api base URL (https://api.telegram.org/bot<TOKEN>/), and the offset.
The offset is very important, it tells Telegram which updates we’ve already handled. Every time we process an update, we bump the offset so we don’t process the same message twice.
The tgmessage struct is just a better way to pass message data around functions.
Handling Updates
Now let’s handle updates. First, we need a callback function that libcurl will use to write the HTTP response into a buffer:
|
|
And here’s the function we were waiting for:
|
|
Notice the timeout is set to 35 seconds, slightly higher than the 30-second long polling timeout. This gives Telegram enough time to respond before our side gives up.
The JSON Structure
A typical response from the getUpdates endpoint looks like this:
|
|
The result array can contain multiple updates, so we need to iterate through all of them.
Parsing the Response
Let’s pick up where we left off: parsing the JSON and extracting the data we need.
|
|
The key thing here is the offset update. By setting bot->offset to the current update_id, we tell Telegram “I’ve processed everything up to this point.” Next time we poll, we pass offset + 1 to skip past what we’ve already seen.
Sending Messages
We send a request to the sendMessage endpoint with the chat ID and our text:
|
|
Don’t forget to URL-encode the text!
curl_easy_escapehandles that for us andcurl_freereleases the allocated memory.
The Main Loop
|
|
The bot runs in a simple loop: fetch updates, process them, repeat. If handle_updates returns an error, the loop exits and we clean up.
One thing to improve: handle
SIGINT(CTRL+C) so you can shut down the bot cleanly.
Compiling
Compile with:
|
|
Run it:
|
|
Open Telegram, find your bot, and send it a message. If everything went right, it’ll echo whatever you send back to you.
Conclusion
In my free time, I’m working on a more complete library with better error handling and more API methods. You can follow the progress here.