С появлением на нашем хостинге возможности запуска Фоновых процессов, процесс запуска различных ботов, таких как ботов для Telegram, Discord, FB и т.п значительно упростился.
Что такое Фоновые процессы и чем они помогают в запуске бота?
Как правило бот — это отдельный от сайта процесс, который должен работать 24/7, но у которого нет веб-интерфейса и который не должен быть доступен по http(s) снаружи по доменному имени. Но с другой стороны, бот, как и любое программное обеспечение, может содержать ошибки и при возникновении ошибок падать, поэтому очень важно в этом случае его автоматически перезапустить. Кроме того, бот пишет свои логи и к ним необходим прямой доступ, чтобы иметь возможность отслеживать его состояние. Ну и конечно, в случае если сервер хостинга будет перезагружен, либо контейнер для ваших сайтов на хостинге по какой-то причине остановлен, а затем запущен вновь, бот должен незамедлительно стартовать. Все эти вещи обеспечиваются Фоновыми процессами.
Создаем сайт
Фоновые процессы привязаны к сайтам, а сайты располагаются внутри контейнеров. Если нам требуется бот на python, первым делом необходимо создать сайт, который будет работать на python. Ознакомиться с процессом создания сайта на python (django) можно в этой статье.
РАЗМЕЩАЕМ БОТА НА СЕРВЕРЕ | Телеграм боты ч. 5
Далее мы будем считать, что сайт создан и нужная версия python установлена и настроена, вы зашли на сервер по ssh и установили все необходимые базовые пакеты через pip install .
Создаем минимального Discord бота
В этой статье рассматривается создание и запуск бота для Discord, но общий подход для запуска других ботов, например бота для Telegram, ничем не отличается. Для Discord бота нам потребуется установить пакет discord , что мы и сделаем, перейдя в каталог приложения нашего сайта:
cd site.ru/app pip install «discord>=2»
Теперь создадим скрипт, который будет нашим минимальным ботом. Пусть он выглядит так:
Этот бот не делает ничего, кроме того, что если вы напишите сообщение в дискорд сервер, к которому подключен ваш бот, которое начинается с фразы “$hello”, бот ответит вам сообщением “Hello!”. В последней строке кода вместо ‘your token here’ вам необходимо прописать ваш токен для API Discord. Если в итоге файл создан и назван my_bot.py , то запустить его очень просто:
python my_bot.py
Начало положено. Но теперь, если мы закроем ssh-консоль, процесс бота будет завершен и бот перестанет работать. Давайте сделаем так, чтобы бот работал постоянно.
Создаем фоновый процесс для запуска бота
Для этого переходим в раздел Хостинг, далее выбираем контейнер в котором был создан сайт, а в контейнере в списке сайтов выбираем тот сайт, в рамках которого будет запущен процесс бота. И переходим во вкладку “Фоновые процессы”:
Теперь нажимаем на кнопку “Добавить процесс” и перед нами окрывается окно настроек:
Всё что нам осталось сделать для запуска бота, это написать команду, которая будет его запускать. Команда будет выглядеть следующим образом:
cd ~/site.ru/app python my_bot.py
Если в коде бота не было ошибок и все остальное вы сделали по инструкции, после нажатия на кнопку “Добавить и запустить”, процесс бота будет запущен.
Доступ к логам бота
В окне, где мы подключены к серверу по ssh, мы запускаем следующую команду:
ls -l ~/site.ru/log
Нам будет показан список папок с логами. Для фоновых процессов название папок имеет вид service-ID-runlog , где ID — уникальный идентификатор процесса, который для каждого процесса отображается в списке процессов в Личном кабинете. Теперь запустим команду:
tail -f ~/site.ru/log/service-ID-runlog/current
И на экране будет отображаться лог бота, обновляемый в реальном времени.
Перезапуск бота
Когда вы вносите изменения в код бота, по умолчанию процесс бота в памяти о них ничего знать не будет. Чтобы бот подхватил изменения, нужно его перезапустить. Для этого есть несколько способов:
- В личном кабинете в разделе фоновых процессов у нужного процесса нажмите на пункт меню “перезапустить”.
- В ssh консоли сервера запустите команду touch ~/site.ru/reload . Эта команда перезапустит ваш сайт и все фоновые процессы, привязанные к этому сайту.
Источник: www.netangels.ru
Реализация аутентификации в telegram-боте через OAuth2 на примере Box API
Возникла идея простого бота, который будет отправлять переданные ему файлы в облако. Однако для аутентификации сейчас практически везде используется OAuth2. Если в web-приложениях пользоваться OAuth2 все уже научились, то с telegram у меня возникли вопросы.
В этой заметке будет минимальный пример telegram-бота, который работает с box.com через API с аутентификацией через OAuth2.
disclaimer #1: В статье не будет подробного описания работы OAuth2 — только необходимый минимум информации для понимания процесса.
disclaimer #2: Для примера использую облачное хранилище box.com, так как именно в нём лежит моя библиотека электронных книг. При реализации аналогичной функциональности для других облаков проблем возникнуть не должно.
Какой сценарий с точки зрения пользователя получим в конце текущей статьи:
- Пользователь добавляет бота в telegram
- По команде /login пользователь получает ссылку на аутентификацию
- Пользователь переходит по ссылке в браузере на box.com
- Пользователь аутентифицируется на box.com
- Открывается страница бота https://t.me/?start= с предложением отправить ему сообщение по кнопке Send message
- Пользователь нажимает на кнопку Send message
- В telegram открывается диалог с ботом с активной кнопкой Start
- Пользователь нажимает на кнопку Start
- Бот отправляет пользователю его login в box.com
Добавить остальную функциональность — дело техники.
Необходимый минимум об OAuth2
Для реализация аутентификации через OAuth2 необходимо выполнить несколько пунктов:
- Получить client_id и client_secret в консоли разработчика box.com. Подробно процесс описан в приложении в конце статьи
- Сформировать ссылку для аутентификации пользователя https://account.box.com/api/oauth2/authorize?client_id=response_type=code . client_id и redirect_url необходимо скопировать из настроек созданного ранее приложения в консоли box.com
- На адресе redirect_url (по-умолчанию в этой статье — это localhost:8000 ) поднять веб-сервер, который сможет получить код для аутентификации в box.com
- С полученным в п.3 кодом и параметрами client_id и client_secret из п.1 обратиться к endpoint box.com API для получения access_token и refresh_token . access_token в дальнейшем необходимо добавлять во все запросы к API.
Реализация
Шаг 1. Подготовка
Для работы понадобятся три внешних библиотеки:
- python-telegram-bot — для работы с Telegram Bot API
- requests — для выполнения запросов к API
- boxsdk — для работы с API box.com
Библиотеки и их версии прописаны в requirements.txt. Установить всё через pip install -r requirements.txt — ничего необычного. Но лучше для этого создать отдельное виртуальное окружение.
Шаг 2. Продолжаем подготовку
Теперь надо получить токен для бота. Я уже писал об этом ранее.
Шаг 3. Веб-сервис для получения OAuth2-кода
Нужен простой веб-сервис. На URI этого веб-сервиса будет происходить перенаправление со страницы аутентификации box.com. Адрес перенаправления будет содержать параметр code в строке запроса. Этот код используется для получения access_token и refresh_token дальше.
Веб-сервис будет без использования внешних зависимостей. Реализован на встроенном simple http server. Код позаимоствован из gist, но немного модифицирован:
Использовать код выше в настоящем боевом production я бы, конечно, не стал, но для демонстрации идеи подойдёт.
Шаг 4. Минимально работающий бот
Простейший бот с использованием библиотеки python-telegram-bot выглядит так:
from telegram.ext import Updater from telegram.update import Update from telegram.ext.callbackcontext import CallbackContext from telegram.ext import CommandHandler token = ‘TG_BOT_TOKEN’ updater = Updater(token=token, use_context=True) dispatcher = updater.dispatcher def start(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text=»I’m a bot, please talk to me!») start_handler = CommandHandler(‘start’, start) dispatcher.add_handler(start_handler) updater.start_polling()
Этот бот не делает ничего полезного — только отправляет сообщение «I’m a bot, please talk to me!» по команде /start .
Теперь надо добавить самое важное — аутентификацию через OAuth2.
Шаг 4.1. OAuth2-аутентификация
Для аутентификации необходимо перейти по сформированной особым образом ссылке: https://account.box.com/api/oauth2/authorize?client_id=response_type=code , где client_id и redirect_url параметры из настроек созданного ранее приложения в консоли разработчика box.com.
На этой странице будет стандартная форма логина в box.com .
После ввода логина и пароля произойдёт перенаправление на redirect_url . На этом адресе сервис, получив GET-запрос, вычленит из строки запроса code . После чего перенаправит запрос на страницу старта работы с telegram-ботом. В адрес будет добавлен полученный код. Далее должен открыться диалог с ботом с активной кнопкой Start . По клику на кнопку в обработчике команды /start можно будет получить переданный код.
Простейший код как proof of concept:
from telegram.ext import Updater from telegram.update import Update from telegram.ext.callbackcontext import CallbackContext from telegram.ext import CommandHandler import requests import json import boxsdk client_secret: str = ‘CLIENT_SECRET’ client_id: str = ‘CLIENT_ID’ redirect_url: str = ‘REDIRECT_URL’ token = ‘TG_BOT_TOKEN’ updater = Updater(token=token, use_context=True) dispatcher = updater.dispatcher # Обработчик команды /start def start(update: Update, context: CallbackContext): message_text: str = update.message.text # В deep linking параметры из url передаются в сообщении в виде строки «/start code», # где code — строка из url https://t.me/?start=code. message_parts: list[str] = message_text.split(‘ ‘) if len(message_parts) == 2: # Во втором элементе будет содержаться переданный код, # который необходим для получения access_token и refresh_token code: str = message_parts[1] # Формируем запрос к API box.com для получения access_token и refresh_token access_token_url = ‘https://api.box.com/oauth2/token’ headers = ‘Content-Type’: ‘application/x-www-form-urlencoded’> params = < ‘client_id’: client_id, ‘client_secret’: client_secret, ‘code’: code, ‘grant_type’: ‘authorization_code’ > req = requests.post(access_token_url, data=params, headers=headers) data = json.loads(req.text) # Полученный JSON содержит необходимые данные. # Используя их можно инициализировать клиент boxsdk # и начать обращаться к его API. oauth: boxsdk.OAuth2 = boxsdk.OAuth2( client_id, client_secret, access_token=data[‘access_token’], refresh_token=data[‘refresh_token’]) box_client = boxsdk.Client(oauth) # Например, можно получить информацию об аутентифицированном пользователе. user = box_client.user().get() context.bot.send_message(chat_id=update.effective_chat.id, text=user.login) else: show_welcome_message(update, context) # Обработчик команды /login def login(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text=f’response_type=code»>Connect to Box.com’, parse_mode=’HTML’) def show_welcome_message(update: Update, context: CallbackContext): context.bot.send_message(chat_id=update.effective_chat.id, text=»I’m a bot, please talk to me!») start_handler = CommandHandler(‘start’, start) login_handler = CommandHandler(‘login’, login) dispatcher.add_handler(start_handler) dispatcher.add_handler(login_handler) updater.start_polling()
Что дальше
- Привести код бота в порядок: выделить классы, методы,
- Сделать конфигурирование бота более удобным,
- Реализовать загрузку файлов в облако.
О чём-то из этого постараюсь написать позже.
Исходники для этой заметки можно найти на github.
Приложение
Получить client_id и client_secret необходимо в консоли разработчика box.com:
- Cоздать новое приложение с типом Custom app
- В настройках приложения выбрать User Authentication (OAuth2) и указывать App Name
- В разделе Configuration созданного приложения:
- в секции OAuth 2.0 Credentials забрать client_id и client_secret ,
- в секции OAuth 2.0 Redirect URI указать localhost:8000 (или другой адрес, если есть понимание, что это и зачем)
- поставить галочку в чекбоксе Write all files and folders stored in Box
(в этой статье про это говорить не буду)
Если вам понравилась статья, то можете зайти в мой telegram-канал. В канал попадают небольшие заметки о Python, .NET, Go.
Источник: makesomecode.me
Telegram бот через webhook
Я тогда давно написал статью про создание Telegram бота, и обещал дополнить её описанием настройки работы через webhook, но так и не дополнил. Вот только сейчас дошли руки.
Что это такое
Как пишут в документации, общаться с серверами Telegram бот может двумя способами:
- getUpdates — pull: ваш бот постоянно дёргает сервер Telegram и проверяет есть ли новые сообщения;
- setWebhook — push: по мере поступления новых сообщений сервер Telegram отправляет их вашему боту.
Разницу можно изобразить следующим образом:
Очевидно, что второй способ ( setWebhook ) рациональнее для всех участников процесса. Однако в нём присутствует неявная сложность: кто-то должен принимать сообщения от Telegram на стороне бота, то есть необходим веб-сервер или его эквивалент.
Как настроить
Что нужно сделать:
- Заиметь доменное имя для сервера и получить на него сертификат (например, от Let’s Encrypt). Документация также говорит, что в случае самоподписанного сертификата можно обойтись и просто IP адресом, но этого я не пробовал;
- Запилить серверную часть на стороне бота (куда будет ломиться Telegram);
- Зарегистрировать адрес серверной части в Telegram (зацепить webhook на endpoint), чтобы Telegram знал, куда ломиться с сообщениями.
Сертификат
С доменом и сертификатом просто. Домен у меня уже был, а сертификат я получил по этой инструкции.
Вариант с самоподписанным сертификатом на прямой IP адрес я оставляю вам на самостоятельное изучение.
Серверная часть
Серверная часть чуть посложнее. Я переделал текущую реализацию бота на pyTelegramBotAPI, используя пример для AIOHTTP.
Ставим необходимые пакеты:
pip install pyTelegramBotAPI pip install aiohttp pip install cchardet pip install aiodns
И сокращённо код бота теперь такой:
Что здесь происходит: мы запускаем мини-веб-сервер, который слушает порт 8443 и отвечает на запросы через определённый endpoint, который образован токеном бота. Токен используется здесь как достаточно уникальный идентификатор, чтобы какой-нибудь мимокрокодил из интернета не навызывал бота и не натворил дел. Полный адрес endpoint’а будет выглядеть вот так: https://YOUR.DOMAIN:8443/YOUR-TOKEN/ .
Обратите также внимание на отличия от стандартного примера из репозитория:
- в качестве файла сертификата указан fullchain.pem , а не cert.pem ;
- удалён код снятия и установки webhook’а.
Так как бота я запускаю не из-под root’а, сервис начал валиться с такой ошибкой:
python-bot[1824]: Traceback (most recent call last): python-bot[1824]: File «/usr/local/bin/bot/bot.py», line 142, in python-bot[1824]: context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV) python-bot[1824]: PermissionError: [Errno 13] Permission denied systemd[1]: telegram-bot.service: Main process exited, code=exited, status=1/FAILURE systemd[1]: telegram-bot.service: Failed with result ‘exit-code’.
То есть, у пользователя, из-под которого выполняется скрипт, нет доступа к /etc/letsencrypt/ , чтобы открыть файл сертификата. Я попытался дать доступ к каталогу для новой группы, включив в неё этого пользователя:
groupadd letsencrypt usermod -a -G letsencrypt userforbot chgrp -R letsencrypt /etc/letsencrypt/
Но он один фиг не мог открыть файлы оттуда, даже простой ls выдавал ошибку доступа. В общем, или мои познания Linux полный отстой, или одно из двух. Пришлось тупо назначить его владельцем:
chown -R userforbot:letsencrypt /etc/letsencrypt/
Тогда сервис запустился нормально.
Регистрация
Теперь осталось самое, как оказалось, сложное — зарегистрировать endpoint бота в Telegram. Сложности возникли потому, что я сначала неправильно понял принцип составления endpoint’а, а также из-за проблем с проверкой сертификата.
Для установки/регистрации webhook’а нужно выполнить следующий HTTP запрос (можно просто открыть этот URL в браузере):
https://api.telegram.org/botYOUR-TOKEN/setWebhook?url=https://YOUR.DOMAIN:8443/YOUR-TOKEN/
Пока я экспериментировал и разбирался с форматом endpoint’а, Telegram возвращал мне нормальный результат:
«description»: «Webhook was set», «ok»: true, «result»: true >
Но потом я его видимо задолбал, и он стал возвращать мне следующее:
«ok»: false, «error_code»: 504, «description»: «Gateway Timeout» >
Но оказалось, что это ни на что не влияет, и webhook нормально устанавливается, так что можно даже не дожидаться таймаута, а просто отменять запрос через пару секунд.
Проверить статус webhook’а можно таким запросом:
https://api.telegram.org/botYOUR-TOKEN/getWebhookInfo
Если всё нормально, должно вернуть такое:
«ok»: true, «result»: «url»: «https://YOUR.DOMAIN:8443/YOUR-TOKEN/», «has_custom_certificate»: false, «pending_update_count»: 0, «max_connections»: 40 > >
Как видим, в поле url стоит наш endpoint.
Однако, мне оно сейчас возвращает такое:
«ok»: true, «result»: «url»: «https://YOUR.DOMAIN:8443/YOUR-TOKEN/», «has_custom_certificate»: false, «pending_update_count»: 0, «last_error_date»: 1543762687, «last_error_message»: «SSL error «, «max_connections»: 40 > >
Что указывает на некие проблемы с сертификатом. При этом бот работает нормально, то есть эта ошибка ни на что не влияет. Однако, если вместо fullchain.pem оставить cert.pem (как было указано в примере), то бот работать перестанет.
Стоит также отметить, что если вы установили webhook, то опрос Telegram через getUpdates работать больше будет. Чтобы снять webhook, надо отправить тот же самый запрос, что и для установки, но на этот раз без параметра url :
https://api.telegram.org/botYOUR-TOKEN/setWebhook
«ok»: true, «result»: true, «description»: «Webhook was deleted» >
Ну и всё, не так уж и сложно. Если бы в документации (и сторонних манулах из интернетов) была указана такая простая вещь, что для webhook’а всего-то нужен лишь веб-сервер на стороне бота, я бы это сделал уже сто лет назад. Конечно, продвинутым чувакам это скорее всего было очевидно сразу, но мнe — нет.
Note that even if you sign-in with your e-mail or GitHub, you still won’t be subscribed to replies. That is by design of remark42, unfortunately. To get updates about new replies/commends you need to explicitly subscribe to them either via e-mail or RSS.
Источник: decovar.dev