Перейти до основного вмісту

Створюємо простого Slack бота на Go

З мовою програмування Go я почав працювати відносно недавно і тепер розширюю площину її застосування. Традиційно, я почав з розробки мікросервісів, наступним етапом були децентралізовані додатки на основі бібліотеки IPFS. Тепер я спробував написати свого простого бота для меседжера Slack. Результатом став цей простий тюторіал. Сподіваюсь, він допоможе комусь із вас написати свого власного бота.

Ідея виникла, коли я випадково натрапив на проект Пятиминутка PHP - бот для Радио-Т на GitHub. Цей бот працює так. Якщо в чаті згадується PHP, то бот повідомляє якийсь цікавий факт про цю мову програмування. Я трохи розширив функціонал: наш Slack бот буде шукати в нових повідомленнях заданий набір ключових слів і, якщо знайде відповідність, у відповідь надішле один з цікавих фактів, який відновиться до цих ключових слів. Таким чином ми не будемо прив'язуватись до PHP і зробимо бота більш гнучким в конфігурації.

Для зручності, я виділив частину функціоналу в окрему бібліотеку, яка буде "знати" факти та вміти шукати їх. При її ініціалізації потрібно вказати де саме зберігаються файли з фактами і все. Далі користуючись методами GetFact(keyword) чи FindFact(message) можна отримувати випадкові факти, відповідно до переданих параметрів. Формат файлів з фактами можна знайти в README файлі самої бібліотеки. Там же описано як приєднати її до вашого проекту.

Slack API

Slack API достатньо великий і містить безліч способів інтеграції вашого додатку в Slack. Ми будемо використовувати тільки невелику його частину для роботи з історією повідомлень в каналі. Для комунікації нашого боту з API будемо використовувати бібліотеку Slack API in Go, яка підтримує більшість, якщо не всі, функції із Slack API.

Реєстрація бота

Що таке Slack-бот можна прочитати тут. Якщо коротко, то це спеціальний тип користувача, який має більшість атрибутів звичайного користувача і може бути доданим в будь-який канал. Головна відмінність бота від користувача це те, що замість взаємодії з командою він буде користуватись не мобільним додатком, а Slack API в автоматичному режимі, також він не може залогінитись і не має паролю.

Замість пароля користувач-бот має токен. Для його отримання потрібно перейти на сторінку https://my.slack.com/services/new/bot і залогінитись в Slack. Після цього ви побачите форму реєстрації бота:


Введіть в поле ім'я вашого боту і натисніть кнопку "Add bot integration". Після цього ви потрапите на сторінку, де зможете додати інші параметри, наприклад, іконку або повне ім'я. На цій же сторінці буде токен, з допомогою якого наш бот буде авторизуватись в системі.

Реалізація

Тепер можемо перейти безпосередньо до реалізацій боту. Тут теж все просто. Наш проект буде побудований на базі інструменту збірки gb (перед початком роботи необхідно встановити gb у ваш $GOPATH), тому структура проекту буде продиктована ним. Вона буде мати приблизно такий вигляд як на малюнку. Теки src/* є обов'язковими:


Для простоти можна проігнорувати створення файлу конфігурації config.xml і вичитування його в момент запуску додатку. Роботу з ним можна подивитись в репозиторій проекту. В прикладах цього проекту ми будемо всі параметри "хардкодити". Також весь код може бути написаний в методі main() проекту, а не розкиданим по пакетах як в репозиторії.

Спочатку ініціюємо бібліотеку з фактами:

package main

import (
    facts "github.com/sheremetat/randfacts-lib"
)

func main() {
    factLib, err := facts.Init("./facts")
    if err != nil {
 log.Errorf("Error in main():  %v", err)
 panic("Error in main(): " + err.Error())
    }
    ...

Тепер напишемо самого бота. Доповнюємо main(). У фрагменті коду є коментарі, які описують, що саме там відбувається:

    ...
    // Initialization of Slack Bot
    api := slack.New("[Your Slack Bot Token]")
    api.SetDebug(true)

    // Open web socket connection
    rtm := api.NewRTM()
    go rtm.ManageConnection()

    // Reading events from Slack
    for msg := range rtm.IncomingEvents {
        log.Print("Event Received: ")
        switch ev := msg.Data.(type) {
        case *slack.HelloEvent:
                // Ignore hello
        case *slack.ConnectedEvent:
            // Ignore connection event
        case *slack.MessageEvent:
            // Processing message in channel
            fact, err := factLib.FindFact(ev.Msg.Text)
            // Check if fact for message found
            if err == nil && len(fact) > 0 {
                // Send message back to channel with fact
                outMsg := rtm.NewOutgoingMessage(fact, ev.Channel)
                outMsg.Channel = ev.Channel
                rtm.SendMessage(outMsg)
     }
        default:
            // Ignore other events..   
        }
    }
}

Залишилось зібрати та запустити нашого простого бота. Для цього в корені виконаємо дві команди з консолі:

~$ gb build
~$ bin/factsbot 

Якщо все запустилось без проблем (а я сподіваюсь, що так і було) то в вашому Slack новий користувач @[ім'я бота] змінить стан на "в мережі". Напишіть йому повідомлення з вашими словами для пошуку і отримаєте цікавий факт у відповідь.

Код бібліотеки та моєї реалізації бота доступні на Github.com.

Програмуйте із задоволенням!

Коментарі