Которые сложно или невозможно понять из документации.
Возьмем пример: Как создать бота в Telegram
Если вы когда нибудь читали документацию Яндекс облака, вы в курсе. Для остальных могу пояснить. Возьмите лапидарный текст, удалите из него ясность и чёткость и вы получите документацию Яндекс облака.
В статье я хочу поделиться теми моментами, которые всплыли при разработке бота в телеграм, не описаны в документации и понять их можно только путём длительной и очень неудобной отладки через переусложненные логи вызова.
Последовательность шагов понятна из документации. Делаем API, на него вебхуком телеграмм присылает обновления в формате json, API дёргает бессерверную функцию и отдаёт в неё json, парсим json как обычно, отправляем ответ ботом telegram.bot.
Удобство в том, что бессерверная функция это небольшой компьютер, который включается на момент обработки запроса и уничтожается после выполнения или по таймауту. Никаких докеров и к8, всё автоматически настроено. Но не всё так радужно, есть и подвохи.
Подвох 1. Полностью проигнорирована безопасность
Предлагается создать публичную функцию и выдать функции публичный доступ. Крайне не рекомендую так делать. Создайте сервисный аккаунт, дайте ему роли в каталоге editor, serverless.functions.invoker, functions.functionInvoker. В код:
/fshtb-function:
post:
x-yc-apigateway-integration:
type: cloud_functions
function_id: <идентификатор_функции>
operationId: fshtb-function
добавьте id сервисного аккаунта:
/fshtb-function:
post:
x-yc-apigateway-integration:
type: cloud_functions
function_id: <идентификатор_функции>
service_account_id: <Идентификатор_сервисного_аккаунта>
operationId: fshtb-function
Это единственное изменение, которое потребуется. Делать функцию и/или бакет публичным крайне не рекомендую.
Подвох 2. Из примера можно подумать, что есть полный доступ к бакету
На самом деле с бакета можно только читать, записать ничего не получится, подключить бакет к функции тоже невозможно, хотя об этом вы узнаете только после того, как полностью заполните всю форму на подключение бакета (фича в стадии preview, доступ не дают, кнопку "добавить" замазывают сереньким прям в момент заполнения последнего поля формы, нажать её нельзя).
Подвох 3. Как читать данные с секретами
После активного курения мануалов вы поймете, что секреты добавляются переменными окружения и нигде не описан способ их прочитать. Для некоторых сред, таких как Питон и СиДиез, я нашел примеры в других разделах документации, для R никаких примеров нет. Поэтому делюсь тут. Чтобы прочитать переменную, указанную в настройках как bot_token нужно выполнить код:
Sys.getenv("bot_token")
например, так:
bot <- Bot(token = Sys.getenv("bot_token"))
Подвох 4. Вам понадобится документация по API telegram, но ссылки на него нигде нет
Лично мне хватило того, что описано тут.
Где хорошо и понятно описана структура объекта, который возвращает вебхуком.
И тут.
А фраза в документации "Выполните запрос в терминале: " вообще ничего не объясняет.
На самом деле именно этот запрос и заставит API телеграма отсылать все обновления к шлюзу Яндекса, в шлюзе вы как раз и пропишите, какая бессерверная функция для обработки запроса запускается. И еще, после выполнения запроса вы полностью теряете возможность вручную запросить обновление у бота через API. Сохранил вам пол дня поисков и бесплодных попыток отладки через getUpdates, не благодарите.
Подвох 5. До ответа telegram API вы всё равно не доберетесь так, как описано в документациях
Самый не очевидный момент, когда бот настроен и работает, как расширять его функциональность и добраться до вожделенного update$message.
Запросы к шлюзу API рандомным образом шифруются или не шифруются через base64. Узнать заранее, будет ли зашифровано body запроса шлюза, невозможно. Шлюз отдаёт 2 объекта event и context, они описаны в документации, не буду описывать их структуру. Информация, передаваемая вебхуком вся в элементе event$body (это совсем не очевидно сразу). Поэтому поступаем так:
#$body ответа api telegram завернуто в $body api шлюза.
# вот так вот разворачиваем эту цепочку и получаем струтуру из документации к библиотеке telegram.bot.
library(telegram.bot)
library(httr) #модуль есть по умолчанию в функции, отдельно устанавливать не надо, тут как пример.
library(jsonlite)
handler <- function(event, context) {
# bot_token прописать в переменные окружения при создании функции, вместе с другими секретами
bot <- Bot(token = Sys.getenv("bot_token"))
if (event$isBase64Encoded) {
handler_update_body <- base64_dec(event$body)
} else {
handler_update_body <- event$body
}
handler_update_body_parsed <- fromJSON(handler_update_body)
# вот тут уже всё работает, как описано в документации. Например:
text <- handler_update_body_parsed$message$text
current_user <- handler_update_body_parsed$message$from$id
bot$sendMessage(chat_id = handler_update_body_parsed$message$chat$id,
text = sprintf("Hello %s!", handler_update_body_parsed$message$from$username))
if (startsWith(text, "/start")) {
start(bot,handler_update_body_parsed)
}
}