Привет, я Дмитрий и хочу поделиться с вами как я делал свой телеграм-бот для сохранения сообщений из чатов в блокчейн на языке java. Вообще идея была в том, чтобы научиться быстро и удобно увековечивать некоторые особо важные сообщения, так чтобы они оставались без изменений и вне зависимости от того, что будет с чатом где они были размещены или даже с самим Телеграмом.
Чему мы научимся:
-
(1-я часть) писать предупреждающее сообщение когда бот добавляют в чат
-
посылать в чат приветственное сообщение когда боту дают права админа и он начинает работать
-
читать сообщения из чатов или приватных бесед
-
(2-я часть) обрабатывать сообщения из чатов, к которым он подключен или из приватных бесед
-
обрабатывать команды
-
(3-я часть) делать транзакцию для блокчейн и писать ответ на сообщение, что транзакция создана
-
проверять подтверждение транзакции в блокчейн и изменять ранее посланный ответ на новое сообщение
Во-первых, что такое блокчейн? Представьте что есть такая волшебная книга-летопись, и волшебник летописец, который может вносить в нее записи. И что таких летописей множество и у каждой свой летописец. И волшебство в том, что если в одну из них внесена запись, то она магическим образом появляется во всех летописях и ее оттуда уже нельзя удалить или изменить. И все видят эту запись и всегда могут найти ее на заданной странице. К примеру, вы приходите к летописцу и говорите — “у меня есть мое стихотворение, которое я хочу увековечить и подарить миру, но так, чтобы мое авторство было учтено!” Волшебник, говорит — “добро, а сколько строк в твоем стихотворении?” — “100!” — отвечаете вы. “Тогда это будет стоить 5 волшебных монет”, — говорит он. “По рукам!”. Вы отдаете ему монетки, и волшебник вносит ваше стихотворения в волшебную летопись и она сразу появляется во всех волшебных летописях разом на текущей странице — с подписью внесшего её волшебника и с вашей подписью как автора.
Во-вторых, зачем нужно сообщения из чата сохранять в блокчейне? В первую очередь чтобы не зависеть от изменений в чате телеграм — сообщение уже записанное в блокчейн нельзя удалить или изменить. Например (кейс 1), как вы знаете, накануне задержали Павла Дурова во Франции с целью получить доступы к чатам телеграм. А что если к вашему чату будет получен доступ извне и все сообщения будут удалены или искажены? В свою защиту, Вы всегда сможете получить изначальные сообщения, если они сохранялись в блокчейн. Второй момент (кейс 2) — чтобы сохранить для истории, чтобы можно было через года знать что данные остались неизменны.
С блокчейном разобрались, идем дальше…
Сперва создаем учетную запись для своего бота, в которой задаем его имена и получаем ключи доступа. Это можно сделать вызвав официальный менеджер ботов Телеграм — @BotFather.
Теперь начинаем писать код
Для работы с ботом я использовал библиотеку com.pengrad.telegrambot https://github.com/pengrad/java-telegram-bot-api?tab=readme-ov-file#creating-your-bot
Создаем экземпляр бота так:
import com.pengrad.telegrambot.TelegramBot; … TelegramBot bot = new TelegramBot(botToken); // Спросить бота о его настройках: System.out.println(bot.execute(new GetMe()));
где botToken — это ключ доступа, полученный от @BotFather.
Пересылка сообщений в чат
Бот может отсылать сообщения в чат по его уникальному номеру, как простые текстовые, так и красиво отформатированные (например по Markdown). Код такой:
protected BaseResponse sendSimpleText(long chatId, String textToSend) { SendMessage message = new SendMessage(chatId, textToSend); return sendMessage(message); } protected BaseResponse sendMarkdown(long chatId, String textToSend) { SendMessage message = new SendMessage(chatId, textToSend); message.parseMode(ParseMode.Markdown); return sendMessage(message); }
Получение событий из чата
Для того чтобы не заморачиваться с доменным именем, мы будем использовать режим опроса телеграм-сервиса, получая с него все обновления и события из мира телеграм-чатов:
// Подписка на обновления bot.setUpdatesListener(updates -> { // Обработка обновлений try { updates.forEach(update -> onUpdateReceived(update)); // return id of last processed update or confirm them all // Создание Обработчика ошибок } catch (Exception e) { log.error("On TELEGRAM Updates error {}", e.toString()); } return UpdatesListener.CONFIRMED_UPDATES_ALL; }, e -> { if (e.response() != null) { // Ошибка из Телеграма log.warn("TELEGRAM ERR: " + e.response().errorCode() + " - " + e.response().description()); } else { // Как видно проблема сети e.printStackTrace(); } });
Теперь нам нужно задать обработку в функции onUpdateReceived и дело в шляпе!
Давайте сделаем простой обработчик вида:
protected void onUpdateReceived(Update update) { try { Chat chat; Chat origMessageChat; User from; User user; Long chatId; Long userId; String text; Integer updateId = update.updateId(); String lang = "ru"; ////////// MESSAGE Message message = update.message(); String userName; if (message != null) { // сюда приходит если: // или прямой чат пользователя с ботом // или в чате группы/супергруппы (не канал) бот добавлен администратором chat = message.chat(); chatId = chat.id(); chatErrorId = chatId; System.out.println(message.text()); … } } }
Теперь, для того чтобы бот смог читать сообщения в каком-либо чате — его нужно пригласить в этот чат и сделать администратором — только тогда он сможет получать уведомления о событиях и сообщениях в данном чате. Также можно писать команды боту напрямую через приватный чат с этим ботом.
Если мы запустим данную программу и пригласим бота в какой-либо чат и сделаем его админом, то все сообщения из этого чата будут печататься и в системный лог.
Кроме сообщений из чата, вы сможете получать события, такие как наделение правами пользователя, приглашения в чат и т.д.
Давайте теперь научим нашего бота определять — пригласили ли его в чат и наделили ли правами администратора. Для этого в код обработчика вставим:
// приглашения и удаления из групп ChatMemberUpdated myChatMember = update.myChatMember(); if (myChatMember != null) { chat = myChatMember.chat(); // в каком чате действие произошло chatId = chat.id(); chatErrorId = chat.id(); from = myChatMember.from(); // кто это сделал log.warn("User from: " + GSON.toJson(from).toString()); ChatMember newChatMember = myChatMember.newChatMember(); user = newChatMember.user(); ChatMember.Status oldStatus = myChatMember.oldChatMember().status(); ChatMember.Status newStatus = newChatMember.status(); if (oldStatus.equals(newStatus)) return; if (user.username().equals(botUserName)) { if (newStatus.equals(ChatMember.Status.kicked) || newStatus.equals(ChatMember.Status.left)) { // нас удалили из группы Integer untilDate = newChatMember.untilDate(); // 0 - просто удалили log.error("kicked from " + chat.title() + " by User " + from.username()); // Конкретный пользователь известен только когда удаляют администратора! Иначе бот кикает и не понятно кто тебя кикнул if (!from.isBot()) sendSimpleText(from.id(), from.username() + ", спасибо за использование наших услуг в чате \"" + chat.title() + "\". Надеемся на продолжение сотрудничества в будущем."); } else if (newStatus.equals(ChatMember.Status.administrator)) { // нас сделали администратором // Тут известен конкретный пользователь кто пригласил if (!from.isBot()) sendSimpleText(from.id(), from.username() + ", спасибо за допуск меня к работе в чате \"" + chat.title() + "\". Надеюсь быть полезным..."); } else if (newStatus.equals(ChatMember.Status.member)) { // нас внесли в группу или понизили из админа до обычного пользователя if (!from.isBot()) sendSimpleText(from.id(), from.username() + ", моя работа в чате \"" + chat.title() + "\" прекращена. Жду назначения администраторам снова..."); } log.info("status:" + newStatus.name()); } else { // Это не про меня } }
Приватный чат с ботом
Так же можно понять что кто-то общается с ботом в приватной беседе (когда кто-то общается напрямую с ботом). Приватный чат можно определить так:
if (chat.type().equals(Chat.Type.Private))
Обработка пересланных сообщений из каналов
Интересный режим, когда связаны чат для обсуждения и новостной канал. Тогда сообщения из канала автоматически падают в чат обсуждений. Поймать их можно так:
if (Boolean.TRUE.equals(message.isAutomaticForward())) { // это сообщение пришло из канала к которому привязан данный чат (супергруппа) // это основной чат откуда пришло сообщение - с именем и правильным UserName origMessageChat = message.senderChat();
Итак, в первой части статьи мы разобрались как посылать сообщения в чаты, как их читать и как определять что бот добавили в чат и наделили правами администратора.
Полный код телеграм-бота (супер-класс и подкласс, реализующий посылку транзакций в блокчейн) расположен в Gillab репозитории проекта Erachain — внутри ноды блокчейн. Вызвать бот в телеграм-мессенджере можно по имени @blockchain_storage_bot — вы можете посмотреть как он работает, чтобы лучше понять код бота.
В комментах пишите вопросы — будем делать вторую часть статьи
ссылка на оригинал статьи https://habr.com/ru/articles/838430/
Добавить комментарий