Introduction
Most of the tutorials use Python for writing bots because it is rather simple and also almost everyone knows Python. But what about other languages? Maybe someone doesn't like Python or it is slow for some tasks? In this tutorial I'll show how to build a telegram bot with Go and deploy it on Heroku.
Install the things
All the instructions will be for Linux based distros because the author uses Linux (Ubuntu)
You need to install Go:
# Debian / Ubuntu
sudo add-apt-repository ppa:longsleep/golang-backports
sudo apt-get update
sudo apt-get install golang-go
# Fedora
sudo dnf install golang
# Arch
sudo pacman -S go
# OpenSUSE
sudo zypper install golang
For other platforms, see Download page.
Once Golang is set up, let's create a new project.
First, we should create a repo on GitHub, then initialize go module and then download telebot (go library for writing bots) and create our golang code file:
git clone https://github.com/<USER>/golang-tg-bot
cd golang-tg-bot
# Enter github URL of ur repo or any random name
go mod init github.com/<USER>/golang-tg-bot
go get -u -v gopkg.in/tucnak/telebot.v2
touch main.go
Getting Telegram Bot Token
Open Telegram app, search for @BotFather and start the chat. Send /newbot
command and follow the instructions. After completing the initial steps, you’ll get —
- your TOKEN
- telegram bot URL
- link on docs
If you click the link (e.g. telegram bot URL) you'll see something like this:
Of course not with these wallpapers but you'll definetely see bot name, and a button "Start". If you press /start
you'll launch a bot client and nothing will happen. Because we haven't done anything yet! So let's start writing the bot.
Setting up Heroku
On Heroku, create a new app. Then choose production environment.
After clicking on item in this menu, you'll see something like this:
You won't see any logs because we haven't setup our bot.
Go to Settings, there connect your repository to Heroku app:
Now we should add our telegram token and app url to Config Vars. Put your token and name of the app (e.g. <NAME_OF_YOUR_APP>.herokuapp.com
) there.
We'll need them when setting webhooks so our bot will behave like a web server.
Configuration is done here, let's go to code!
Configuring Bot
Webhook
We grab environment variables, then setup webhook that will be running on Heroku's app URL.
package main
import (
"os"
tb "gopkg.in/tucnak/telebot.v2"
)
func main() {
var (
port = os.Getenv("PORT") // sets automatically
publicURL = os.Getenv("PUBLIC_URL") // you must add it to your config vars
token = os.Getenv("TOKEN") // you must add it to your config vars
)
webhook := &tb.Webhook{
Listen: ":" + port,
Endpoint: &tb.WebhookEndpoint{PublicURL: publicURL},
}
}
Configuring telebot
After webhook being set up we can create an instance of our bot. Here we use our webhook as a Poller, a thing that looks for updates.
package main
import (
"log"
"os"
tb "gopkg.in/tucnak/telebot.v2"
)
func main() {
var (
port = os.Getenv("PORT")
publicURL = os.Getenv("PUBLIC_URL") // you must add it to your config vars
token = os.Getenv("TOKEN") // you must add it to your config vars
)
webhook := &tb.Webhook{
Listen: ":" + port,
Endpoint: &tb.WebhookEndpoint{PublicURL: publicURL},
}
pref := tb.Settings{
Token: token,
Poller: webhook,
}
b, err := tb.NewBot(pref)
if err != nil {
log.Fatal(err)
}
}
Writing handlers
Handlers for commands are pretty much similar to middleware in Node.js but instead of routes we handle commands, like /hello
, or /get_apples 10
.
Hello World
Our first handler will be "Hello World":
b.Handle("/hello", func(m *tb.Message) {
b.Send(m.Sender, "Hi!")
})
Let's deploy our bot to check if it works. Push your changes to repository, then go to Heroku and check if app is deployed.
If it is succeeded, then go to Telegram bot and entering /hello
. It will output "Hi!".
Getting user input
To get user input, we need to grab m.Text
- text of a message. You can also get other info from message struct, check GoDoc.
b.Handle("/hello", func(m *tb.Message) {
b.Send(m.Sender, "You entered "+m.Text)
})
If you try it, it will output something like:
Any text after the command will also be shown. For text without a command, use Payload
:
b.Handle("/hello", func(m *tb.Message) {
b.Send(m.Sender, "You entered "+m.Payload)
})
Buttons
Telegram bots have different types of buttons, Inline, they are attached to some message, and Reply buttons which appear on your message panel.
We will implement first ones because they are easier to write.
First, let's define the buttons. telebot
has a special struct for it, called tb.InlineButton
:
inlineBtn1 := tb.InlineButton{
Unique: "moon",
Text: "Moon 🌚",
}
inlineBtn2 := tb.InlineButton{
Unique: "sun",
Text: "Sun 🌞",
}
After defining the buttons, we should write handlers for them. In Telegram API, you need to write a response callback to each button, even if it doesn't show any alerts or anything else. If you don't write callbacks, button callback will be endlessly loading.
b.Handle(&inlineBtn1, func(c *tb.Callback) {
// Required for proper work
b.Respond(c, &tb.CallbackResponse{
ShowAlert: false,
})
// Send messages here
b.Send(c.Sender, "Moon says 'Hi'!")
})
Let's do the same for second button:
b.Handle(&inlineBtn2, func(c *tb.Callback) {
b.Respond(c, &tb.CallbackResponse{
ShowAlert: false,
})
b.Send(c.Sender, "Sun says 'Hi'!")
})
Cool, now we need to defne a keyboard for buttons. It is a "set" of them that are attached to a message. Even if you have only button you still need to define a keyboard:
inlineKeys := [][]tb.InlineButton{
[]tb.InlineButton{inlineBtn1, inlineBtn2},
}
Here we created an array of arrays of tb.InlineButton
which contains one array with type tb.InlineButton
which contains our buttons.
One small thing left - a handler for a command, say /pick_time
:
b.Handle("/pick_time", func(m *tb.Message) {
b.Send(
m.Sender,
"Day or night, you choose",
&tb.ReplyMarkup{InlineKeyboard: inlineKeys})
})
Our command is ready, let's test it (you need to push code for Heroku to update the app)!
b.Start()
Conclusion
As you can see our bot is working and has some nice buttons. For other options, such as stickers and sending files, visit repo readme and godoc.
Discussion (10)
just an update you will need to add
b.Start()
to actually start listening on the port.ah yes, forgot to add, sorry
Привет! Сделал все по вашейинструкции, но при deploy на heroku ловлю такую ошибку
App not compatible with buildpack, поиски в гугле результатов не дали.
Может вы сталкивались с этим?
Возможно вы выбрали не тот язык для приложения на Heroku. Его можно переключить в настройках
В смысле buildpack?
Попробовал все что нашел, все равно не работает.
да
Great post! I was struggling with how to handle replies from an inlineButton, thx for your post!
glad that my post helped you!
Thanks. But can you tell me the name of the game in your wallpaper
Hyper Light Drifter