Здравствуйте как и обещал в продолжение моей статьи о Автоматической публикации приложения в Google Play , рассмотрю в деталях процесс написания Telegram Bot`a для оповещения команды тестировщиков о выпуске новой версии.
Просто напишите пользователю @BotFather и следуйте его инструкциям.
Выполните последовательно следующий команды
/start
/newbot
bot_name
В итоге вы должны получить сообщениеИз этого сообщение нам понадобятся собственно
t.me/bot_name – Имя бота по которому мы будем добавлять его в каналы или писать в ЛС
token – это наш ключ для доступа к API
Наш бот будет написан на Java и будет представлять из себя Spring Boot Web приложение, в качестве системы сборки будет использоваться maven
1) Создайте обычный Spring Boot проект, проще всего это сделать через встроенный конфигуратор в IntelliJ IDEA , либо используя Spring Initializr.
Выберите те зависимости которые посчитаете нужными, но для начала нам подойдёт минимальный набор
pom.xml <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
А теперь детальней по каждому классу :
BotConfig – Конфигурация подтягивающая настройки бота из application.properties@Configuration
@Data
@PropertySource("classpath:application.properties")
public class BotConfig {
// Имя бота заданное при регистрации
@Value("${botUserName}")
String botUserName;
// Токен полученный при регистрации
@Value("${token}")
String token;
}
@Component
@Slf4j
public class BotInitializer {
@Autowired
Bot bot;
@EventListener({ContextRefreshedEvent.class})
public void Init() throws TelegramApiException {
TelegramBotsApi telegramBotsApi = new TelegramBotsApi(DefaultBotSession.class);
try {
telegramBotsApi.registerBot(bot);
} catch (TelegramApiRequestException e) {
log.error(exceptionStackTraceToString(e));
}
}
}
Телеграм API должно быть зарегистрировано в системе и делать это нужно уже после поднятия контекста Spring, по этому вешаем слушатель на ContextRefreshedEvent
Bot – Сервис инкапсулирующий в себе реализацию TelegramLongPollingBot,@Component
@Slf4j
/**
* Касс является основным пулом взаимодействия с Telegram
* получение, обработка, отправка сообщений
*/
public class Bot extends TelegramLongPollingBot {
final
BotConfig config;
public Bot(BotConfig config) {
this.config = config;
}
public void onUpdateReceived(Update update) {
update.getUpdateId();
SendMessage.SendMessageBuilder builder =SendMessage.builder();
String messageText;
String chatId;
if (update.getMessage() != null) {
chatId = update.getMessage().getChatId().toString();
builder.chatId(chatId);
messageText = update.getMessage().getText();
} else {
chatId = update.getChannelPost().getChatId().toString();
builder.chatId(chatId);
messageText = update.getChannelPost().getText();
}
if (messageText.contains("/hello")) {
builder.text("Привет");
try {
execute(builder.build());
} catch (TelegramApiException e) {
log.debug(e.toString());
}
}
if (messageText.contains("/chartId")) {
builder.text("ID Канала : " + chatId);
try {
execute(builder.build());
} catch (TelegramApiException e) {
log.debug(e.toString());
}
}
}
public String getBotUsername() {
return config.getBotUserName();
}
public String getBotToken() {
return config.getToken();
}
}
Данный класс представляет из себя основной функционал для взаимодействия с Telegram
метод onUpdateReceived принимает и обрабатывает сообщения пришедшие в личку или в канал где бот администратор
@Slf4j
@RestController
@RequestMapping("/api/public/gitea")
@RequiredArgsConstructor
@PropertySource("classpath:application.properties")
public class WebHook {
Bot bot;
// Канал в который будем слать уведомления
@Value("${chartId}")
String chartId;
// Секретный ключ который придёт в нутри JSON от Gitea,
// что бы левые люди не имели доступа к боту т.к. API публичное без авторизации
@Value("${secret}")
String secret;
@Autowired
public WebHook(Bot bot) {
this.bot = bot;
}
@PostMapping(value = "/webhook")
public ResponseEntity<?> webhook(@RequestBody String json){
Gson gson = new Gson();
GiteaWebHook giteaWebHook = null;
try {
giteaWebHook = gson.fromJson(json, GiteaWebHook.class);
} catch (JsonSyntaxException e) {
log.error(Utils.exceptionStackTraceToString(e));
return new ResponseEntity<>(Utils.exceptionStackTraceToString(e), HttpStatus.BAD_REQUEST);
}
if (validationWebHookContent(giteaWebHook)) {
SendMessage.SendMessageBuilder messageBuilder =SendMessage.builder();
messageBuilder.chatId(chartId);
messageBuilder.parseMode(ParseMode.HTML);
StringBuilder builder = new StringBuilder();
builder.append("<b>Проект</b> : " + giteaWebHook.getRepository().getName()+"n");
for (Commit commit : giteaWebHook.getCommits()) {
builder.append("<b>Автор</b> : " + commit.getAuthor().getName()+"n");
builder.append("<b>Комментарий</b> : " + commit.getMessage()+"n");
}
builder.append("<a href="https://play.google.com/store/apps/details?id=URL_ВАШЕГО_ПРИЛАЖЕНИЯ">Обновление будет доступно в Play Market через пару минут</a>n");
messageBuilder.text(buildToCorrectString(builder));
try {
bot.execute(messageBuilder.build());
} catch (TelegramApiException e) {
log.error(Utils.exceptionStackTraceToString(e));
return new ResponseEntity<>(Utils.exceptionStackTraceToString(e), HttpStatus.INTERNAL_SERVER_ERROR);
}
} else return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(headers, HttpStatus.OK);
}
/**
* Проверка пришедших JSON данных на валидность
* @param giteaWebHook - GiteaWebHook
* @return true - если не null, PUSH в master, совпал секретный ключ
*/
private boolean validationWebHookContent(GiteaWebHook giteaWebHook){
return giteaWebHook != null && // Если вообще что то есть
giteaWebHook.getRef().contains(giteaWebHook.getRepository().getDefaultBranch()) && // Есть был PUSH в /master
giteaWebHook.getSecret().equals(secret); // Если совпал секретный ключ
}
private String buildToCorrectString(StringBuilder builder){
return builder.toString()
.replace("_", "\_")
.replace("*", "\*")
.replace("[", "\[")
.replace("`", "\`")
.replace(" ", " ")
.replace("&frac", " ")
.replaceAll(" \u003c","");
}
}
Данный RestController обслуживает RestAPI с точкой входа http://you_ip:port/api/public/gitea/webhook , сюда наша система контроля версий Gitea будет делать PUSH запрос с JSON данными WebHook возникающего при различных событиях происходящих с вашим репозитарием.
TelegramBotGiteaApplication – Стартовый метод нашего Spring Boot проекта@SpringBootApplication
@AutoConfigurationPackage
public class TelegramBotGiteaApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
new SpringApplicationBuilder(TelegramBotGiteaApplication.class)
.run(args);
}
}
Все те классы что вы наблюдаете в пакете Model , представляют сгенерированную модель GiteaWebHook по JSON-Schema взятому из оф документации по GiteaWebHookApi , удобнее всего это делать при помощи http://www.jsonschema2pojo.org/
Полный исходный код вы можете взять ЗДЕСЬ
Данная статья рассматривает вариант обслуживания API предоставляемое системой контроля версий Gitea но это не значит что вы не сможете сделать оповещение и без неё. Проявив некую долю усердия всё те-же WebHook можно реализовать через .githookspost-update и curl , или некое API GitHub но эти реализации я доверяю вам, и здесь мы рассмотрим лишь вариант с Gitea
1) И так, перейдите в репозитарий вашего проекта и войдите в его Настройки в раздел Автоматическое обновление . Нажмите на кнопку Добавить Webhook , выберете вариант Gitea
2) В качестве URL обработчика укажите URL на котором у нас висит RestController http://you_ip:port/api/public/gitea/webhook
3) Тип содержимого – application/json
3) Секретный ключ – любой набор символов который мы в последующем внесём в наш application.properties
4) На какие события этот webhook должен срабатывать? – выберите PUSH
5) Галочку Активности оставьте включённой.
Всё это хорошо бот написан, Gitea настроена но нашему боту нужно где-то жить.
New customers get $300 in free credits to spend on Google Cloud. All customers get free usage of 20+ products. See offer details.
Такое сообщение мы видим на главной страницы этого сервиса, а именно они дают 300$ бесплатно на год для функционирования нашего приложения у них в облаке, и нам этого вполне себе хватит.
И так приступим, авторизуйтесь в Google Cloud Platform
1) В боковом меню перейдите в раздел Сompute Engine, и дождитесь его инициализации
2) В разделе Экземпляры ВМ, нажмите создать
Выберете конфигурацию инстанса к примеру вот такую, это будет оптимальным решением для нашего не требовательного приложения
Давайте зададим сразу правило Брандмауэра разрешающего трафик по порту 8080
Зайдите Cеть VPS – Брандмауэр
Создайте правило для порта 8080 по аналогии с 80 портом
Подключитесь к VM через SSH , непосредственно через браузер
Теперь мы может перейти к настройке нашей виртуальной машины
Для обновления информации об новейших версиях пакетов вводим
sudo apt update
Установим Java
sudo apt install default-jdk
Проверьте это выполнив
java - version
Если всё прошло хорошо вы должны наблюдать версию Java в консоли SSH
Теперь установим maven
sudo apt install maven
Сделаем clone репозитария с нашим ботом заготовкой
git clone https://legan.by/gitea/leganas/TelegramBotGiteaLesson.git
Сделайте необходимые манипуляции по настройке appliation.properties , укажите валидный bot_name и token
nano ./TelegramBotGiteaLesson/src/main/resources/application.properties
Зайдём в папку с нашим ботом и соберём его при помощи maven
cd TelegramBotGiteaLesson/
mvn package
После того как maven соберёт наш проект
Бот полностью готов к запуску, выполните команду
java -jar ./target/telegrambotgitea-0.0.1-SNAPSHOT.jar
Используя внешний IP указанный в web консоли управления виртуальными машинами, проверьте его работоспособность открыв в браузере страницу http://YOU_IP:8080/
Если наш бот успешно подключился к Telegram мы можем написать ему проверочное сообщение в ЛС /hello , на что он должен ответить нам Привет
И так теперь у нас всё готово для того что бы добавить нашего бота в Telegram канал, дать ему права администратора (что бы он мог читать сообщения) и протестировать оповещение !
Добавил бота в канал и дав ему права , вы можете написать
/chartId
Теперь это ID можно добавить в application.properties и либо пересобрать проект , либо подкинуть этот файл рядом с jar. Внесите необходимые правки IP адреса в WebHook в настройках Gitea и опробуйте вашего бота.
У кого получилось вот так , тот молодец, о том как сделать jar сервисом писать уже не буду, уж очень много про это написано на хабре, а если не найдёте пишите в личку.
Надеюсь моё повествование было достаточно подробным что бы любой смог запустить свою зверушку. 🙂
Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…
Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…
Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…
У частных продавцов на Авито появилась возможность составлять текст объявлений с помощью нейросети. Новый функционал доступен в категории «Обувь, одежда,…
24 апреля 2024 года в Москве состоялась церемония вручения наград международного конкурса Workspace Digital Awards. В этом году участниками стали…
27 июня Яндекс проведет гик-фестиваль Young Con для студентов и молодых специалистов, которые интересуются технологиями и хотят работать в IT.…