Как я Telegram бота на Go писал. Часть первая. Начало.

В этой серии заметок хотел бы немного коснуться данной темы. Серия будет включаться в себя три раздела:

  1. Разработка бота на Go для поиска заклинаний для Dungeon And Dragons
  2. Публикация бота на платформе heroku
  3. Добавление аналитики использования бота

Итак, начнём!

Во-первых, нам потребуется сам список заклинаний DnD. Найти его можете в моём bitbucket-репозитории этого бота.

Во-вторых, создать новую папку. Например, dndspellsbot.

В-третьих, получить ключ для вашего нового бота у служебного аккаунта @BotFatherBot, отправив ему команду /newbot и сохранить полученный в ответ токен в безопасное место.

В-четвертых, чтобы не изобретать велосипед, добавить библиотеку telegram-bot-api:

go get gopkg.in/telegram-bot-api.v4

И, наконец-то, в-пятых, написать код самого бота.

config.json

Создадим пустой Go-файл dndspellsbot.go в папке dndspellsbot. Туда же добавим конфигурационный файл config.json со следующим содержимым:

{
 "TelegramBotToken": "токен-полученный-от-BotFather"
}

Конечно же, можно обойтись без этих усложнений и зашить токен прямо в коде бота, но в случае, если вы случайно зальетё код вашего бота в какой-то публичный репозиторий на github/bitbucket/whatever, то утечёт и токен, а это, согласитесь, неприятно. И это только сейчас у нас такой простой конфиг – в дальнейшем будут добавляться новые свойства и всё будет храниться в одном месте. Удобно, согласитесь?

Получить этот токен из конфигурационного файла довольно просто стандартными средствами Go:

package main

import (
    "fmt"
    "gopkg.in/telegram-bot-api.v4"
    "log"
    "os"
    "encoding/json"
)

type Config struct {
    TelegramBotToken string
}

func main() {
    file, _ := os.Open("config.json")
    decoder := json.NewDecoder(file)
    configuration := Config{}
    err := decoder.Decode(&configuration)
    if err != nil {
       log.Panic(err)
    }
    fmt.Println(configuration.TelegramBotToken)
}

Теперь при добавлении в config.json новых свойств и модификации структуры Config можно получать необходимые параметры конфигурации.

ping?

В репозитории telegram-bot-api есть пример echo-бота – бота, который отвечает вам те же сообщением. Возьмём его за основу:

bot, err := tgbotapi.NewBotAPI(configuration.TelegramBotToken)

if err != nil {
    log.Panic(err)
}

bot.Debug = false

log.Printf("Authorized on account %s", bot.Self.UserName)

u := tgbotapi.NewUpdate(0)
u.Timeout = 60

updates, err := bot.GetUpdatesChan(u)

if err != nil {
    log.Panic(err)
}
// В канал updates будут приходить все новые сообщения.
for update := range updates { 
    // Создав структуру - можно её отправить обратно боту
    msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
    msg.ReplyToMessageID = update.Message.MessageID
    bot.Send(msg)
}

Вы уже добавила вашего бота в свой список контактов? Если нет – сейчас самое время.

Теперь самое интересное – запускаем наше приложение командой go run dndspellsbot.go и пишем что-нибудь нашему боту. Если всё сделано правильно, то бот ответит вам вашим же сообщением:

2016-10-03_21-46-08.png

Однако, мы хотели не этого.

Опустим подробности парсинга XML – пост не об этом (полный код можно будет найти по ссылке в конце статьи).

Будем считать, что у нас есть слайс всех заклинаний и любой запрос пользователя к боту – это запрос на поиск подходящего заклинания по его имени (усложнять можно бесконечно, но на данный момент этого достаточно):

...
query := update.Message.Text
// Получим те заклинания, в имени которых есть искомое слово или фраза
filteredSpells := Filter(spells.Spells, func(spell Spell) bool { 
    return strings.Index(strings.ToLower(spell.Name), strings.ToLower(query)) >= 0
})

// Если не нашлось ни одного заклинания - скажем об этом пользователю
if len(filteredSpells) == 0 {
    msg := tgbotapi.NewMessage(update.Message.Chat.ID, "No one spells matches")
    bot.Send(msg) 
}

// Каждое заклинание отправляем отдельным сообщением
for _, spell := range(filteredSpells) {
    text := ""
    for _, t := range(spell.Texts) {
        text = text + t + "\n"
    }
    
    msg := tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("%s\n%s", spell.Name, text))
    bot.Send(msg)
}
...
// Функция фильтрации слайсов
func Filter(spells []Spell, fn func(spell Spell) bool) []Spell {
    var filtered []Spell
    for _, spell := range(spells) {
        if fn(spell) {
            filtered = append(filtered, spell)
        }
    }
    return filtered
}

Теперь, при любом запросе от пользователя, бот будет возвращать все подходящие заклинания из phb.xml.

В следующей статье немного улучшим нашего бота: добавим форматирование сообщений, inline-режим и добавим пару команд.

Код бота можно найти на bitbucket.

3 thoughts on “Как я Telegram бота на Go писал. Часть первая. Начало.

  1. Pingback: Разработка бота на Go для Telegram. Часть 2 | i can do some code for you

  2. Pingback: Разработка бота на Go для Telegram. Публикация | i can do some code for you

  3. Pingback: Как я Telegram бота на Go писал. Часть четвёртая. Аналитическая. | i can do some code for you

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s