Пишем бота для Telegram и хостим его на heroku

от
Java    heroku, telegram, bot

Всем привет. Наверняка, если вы умеете программировать, и пользуетесь телеграмом, вам приходила в голову мысль написать своего бота, к тому же мессенджер предоставляет свой API для ботов, с хорошей документацией, а туториалов по всему интернету накидано немало. Но даже если вы и написали бота, то возникает следующая проблема: хостинг. Для "легких" проектов отлично подходит heroku, но у новичков нередко случаются проблемы с заливкой своих проектов туда. Об этом и пойдет речь в этой статье.

Для нашего бота я решил взять tgbots-module от @aNNiMON. Т.к. бесплатный аккаунт heroku позволяет создать лишь 5 приложений, то использовать одно приложение для запуска нескольких ботов - отличная идея. Но в данной статье мы рассмотрим лишь одно приложение. Создадим в Intellij IDEA новый gradle-проект. Создадим, согласно гайду на гитхабе (ссылка выше) классы ExampleBot и ExampleBotHandler. Заполним build.gradle:
  1. plugins {
  2.     id 'com.github.johnrengelman.shadow' version '2.0.4'
  3.     id 'java'
  4.     id 'application'
  5. }
  6.  
  7. group 'com.senderman'
  8. version '1.0'
  9. mainClassName = 'com.annimon.tgbotsmodule.Runner'
  10.  
  11. sourceCompatibility = 10
  12.  
  13. repositories {
  14.     mavenCentral()
  15. }
  16.  
  17. dependencies {
  18.     implementation 'com.annimon:tgbots-module:0.1'
  19. }
  20.  
  21. shadowJar {
  22.     mergeServiceFiles()
  23.     exclude 'META-INF/*.DSA'
  24.     exclude 'META-INF/*.RSA'
  25. }

И напишем простого эхобота. Комментировать не буду, код слишком простой и понятный, да и гайд есть.
  1. package com.senderman.examplebot;
  2.  
  3. import com.annimon.tgbotsmodule.BotHandler;
  4. import com.annimon.tgbotsmodule.BotModule;
  5. import com.annimon.tgbotsmodule.Runner;
  6. import com.annimon.tgbotsmodule.beans.Config;
  7.  
  8. import java.util.List;
  9.  
  10. public class ExampleBot implements BotModule {
  11.  
  12.     public static void main(String[] args) {
  13.         final var profile = (args.length >= 1 && !args[0].isEmpty()) ? args[0] : "";
  14.         Runner.run(profile, List.of(new ExampleBot()));
  15.     }
  16.  
  17.     @Override
  18.     public BotHandler botHandler(Config config) {
  19.         return new ExampleBotHandler();
  20.     }
  21. }

  1. package com.senderman.examplebot;
  2.  
  3. import com.annimon.tgbotsmodule.BotHandler;
  4. import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
  5. import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
  6. import org.telegram.telegrambots.meta.api.objects.Message;
  7. import org.telegram.telegrambots.meta.api.objects.Update;
  8. import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
  9. import org.telegram.telegrambots.meta.logging.BotLogger;
  10.  
  11. public class ExampleBotHandler extends BotHandler {
  12.  
  13.     @Override
  14.     public String getBotUsername() {
  15.         return System.getenv("username");
  16.     }
  17.  
  18.     @Override
  19.     public String getBotToken() {
  20.         return System.getenv("token");
  21.     }
  22.  
  23.     @Override
  24.     public BotApiMethod onUpdate(Update update) {
  25.         if (!update.hasMessage()) {
  26.             return null;
  27.         }
  28.  
  29.         Message message = update.getMessage();
  30.         if (!message.hasText()) {
  31.             return null;
  32.         }
  33.  
  34.         String text = message.getText();
  35.         long chatId = message.getChatId();
  36.  
  37.         SendMessage sm = new SendMessage(chatId, text);
  38.         try {
  39.             execute(sm);
  40.         } catch (TelegramApiException e) {
  41.             BotLogger.error("SEND", e.toString());
  42.         }
  43.         return null;
  44.     }
  45. }

Обратите внимание на методы getBotUsername() и getBotToken. В них мы берем токен и ник бота из переменных окружения. Heroku позволяет хранить в закрытом доступе необходимые вам переменные. Но об этом позже.
Далее необходимо создать 2 файла: Procfile (без расширения) и system.properties. Первый нужен, чтобы дать heroku понять, что запускать, а второй - чем запускать. В моем случае это будет выглядеть так:
Procfile:
  1. bot: java -jar build/libs/example_telegram_bot-1.0-all.jar
system.properties:
  1. java.runtime.version=10.0.2
И т.к. мы используем tgbots-module, создаем файл config.yaml с таким содержанием:
  1. log-level: ERROR
  2. modules:
  3.   - com.senderman.examplebot.ExampleBot

Проект к деплою на heroku готов, теперь - заливаем его на гитхаб (Я тоже залил, чтобы при возникновении сложностей вы смогли посмотреть, как надо было сделать), регистрируем в телеграме бота, а в хероку - регистрируемся и регистрируем новое приложение. Идем на вкладку Settings, жмем "reveal config vars" и заполняем переменные окружения:
token - токен бота из телеграма
username - ник бота без @
GRADLE_TASK - в значение вписываем shadowJar. Это необходимо, чтобы heroku знало, как нужно собирать проект.
Переходим на вкладку deploy и жмем connect to github. В поле repo name вводим имя нашего репо с ботом и жмем Search, далее выбираем нужное и жмем Connect. Обновляем страницу. В самом низу страницы появится кнопка Deploy Branch. Так же, вы можете включить автодеплой при каждом коммите (бесплатно). Ждем пока задеплоится, и переходим на вкладку Resources и обновляем страницу. Напротив команды запуска жмем карандашик, переключаем ползунок и жмем Confirm, а затем быстренько жмем More - view logs. И если все хорошо, идем в телеграм и пишем боту!

Screenshot_Telegram_20181010-233603.png
  • +5
  • views 15893