Pull to refresh

Как легко написать бота для Telegram на C#

Не так давно Павел Дуров объявил о конкурсе для разработчиков Telegram ботов. Мне было интересно принять в нем участие и изучить новые технологии. В статье будут рассмотрены принципы работы Telegram API для ботов, пара подводных камней при использовании готовой библиотеки на C#, а также процесс получения сертификата и установки WebHook.

Общие принципы работы API


Telegram API присылает вашему приложению-боту массив в формате JSON — это объект Update.

В нем содержится множество информации — id чата, пользователя, сам текст сообщения, прикрепленные фотографии и другие файлы, может быть местоположение пользователя или карточка контакта из его телефона. Есть два основных способа получения этой информации.

При первом способе ваше приложение каждые 100мс (или реже) соединяется с сервером Telegram и спрашивает, не появилось ли чего нового — это метод getUpdates. Минусы этого подхода в том, что создается большая нагрузка на сервера Telegram, а также иногда при большой нагрузке сервер может отдать 503 ошибку и это нужно обработать в приложении. Зато такой способ проще в реализации.

Второй способ — вы делаете свое приложение в виде «сервера» который слушает определенный порт, и Telegram, при наличии обновлений, отправляет их нашему приложению. Тут минус в том, что нужен SSL-сертификат, хотя бы и самоподписанный, а также желательно наличие доменного имени. Но есть и способы сделать всё очень просто, которые я опишу ниже.

Цель моего бота


У меня была несложная задумка — бот должен принимать от пользователя файлы и загружать их на файлообменник, а также выдавать пользователю хотя бы 10 последних ссылок на закачанные файлы. Также я хотел сделать Inline режим — при упоминании ника бота в чате, он выдает последнюю ссылку на закачанный в файлообменник файл. В качестве файлообменника я выбрал Mega.nz, так как он поддерживает шифрование файлов, там дается 50 ГБ места, и к его API так же нашлась библиотека на C#. В перспективе думаю подключить API Яндекс-диска и Dropbox.

Реализация


В качестве готовой библиотеки я взял решение от MrRoundRobin.
Она хорошо написана, а также есть примеры работы. Пример с Echo с получением обновлений через getUpdate заработал у меня сразу, что вдохновило на дальнейшую разработку. В процессе столкнулся с парой нюансов. Во-первых, иногда приложение выдавало ошибки при билде. Решалось это запуском/перезапуском dnvm через консоль. Во-вторых, Telegram выдавал ошибку, что в ответных сообщениях от приложения при работе в Inline режиме нет поля message_text, а судя по API оно должно быть. Это решилось добавлением поля в InlineQueryResultNew.cs:

[JsonProperty("message_text", Required = Required.Always)]
public string MessageText { get; set; }

С WebHook также получилось работать после получения сертификата, для этого используется Microsoft Owin.

Получение сертификата и ngrok


Когда логика бота более-менее заработала, я решил переписать его через WebHook. Самый легкий путь сделать это — воспользоваться сервисом Ngrok Он выдаст вам https-адрес, и будет перенаправлять пакеты к вам на локальную машину. Но при этом все равно нужно воспользоваться urlacl как написано здесь а в качестве certhash прописать хэш от ngrok — ‎53e6c6860a403880ad77703a8b6d4bd1d4dcc451.

После этого вы сможете запустить бота даже на своей локальной машине, указав в качестве ссылки для SetWebhook ту, что вам даст ngrok.

Я решил пойти более сложным путем и получить свой собственный сертификат. Так вышло, что у меня есть VPS-сервер на WIndows от parking.ru, и я захотел развернуть приложение бота на нем. Я нашел замечательный сервис Startssl. Для начала они мне выдали сертификат на мою почту (Email Validation). Потом я понял что нельзя выпустить сертификат на IP адрес моего сервера, но у меня был доменный адрес. Я сделал поддомен bott.mydomainname.ru и перенаправил его на IP моего сервера с помощью настроек DNS в панели управления доменом. Просто сделал там DNS-запись «bott.mydomainname.ru IN A 1.2.3.4» где указал IP своего сервера. Затем пришлось слегка разобраться с IIS — Startssl выдал мне html файл для подтверждения домена (опция Website control validation), который должен был быть доступен по адресу типа bott.mydomainname.ru/startssl_answer.html. На этом этапе я запустил IIS и сделал статичный сайт из этой самой одной html-странички. После этого мне выдали сертификат на год для моего домена, я его установил и его хэш указал в urlacl для параметра certhash.

Смешно получилось, когда бот запускался, но не получал никакой информации, а оказалось что я забыл открыть порт 8443 в firewall.

Для подключения к Mega.nz я воспользовался библиотекой MegaApiClient. К сожалению, не получилось использовать её в анонимном режиме, и я просто подключился под новым обычным аккаунтом. Это может стать проблемой, если место в 50 ГБ у него кончится, но пока хватает.

Метрики и производительность.


Для сбора метрик есть два хороших сервиса — это Appmetrica от Яндекс а также Botan. В первом случае есть готовая библиотека Nuget, во втором можно использовать простые Http вызовы сервиса Botan.

Я воспользовался решением от Яндекс, но скорее в режиме тестирования — не собираю много информации, и не делаю сложной аналитики.

Насчет производительности, не проверял как мой бот поведет себя под нагрузкой. Он использует кучу сторонних dll — Owin, newtonsoft.Json, Nlog, Yandex.Metrica. Надо бы протестировать, так как в описании конкурса говорилось что бот должен быть реально быстрый. Также я пока не добавлял связь с БД, для хранения расшаренных пользователем ссылок, пока храню в памяти.

Дополнения


Еще был интересен вопрос перевода приложения. Сейчас бот по умолчанию на английском, но планирую сделать и русский интерфейс. Перевод, как оказалось, легко делается через добавление в Visual Studio Resources file со строками, к нему генерируется класс, у которого можно поменять свойство Culture и для разных языков будут выдаваться разные строки. Выбор языка пользователем можно сделать как через команду, так и через отправку ему встроенной клавиатуры с флажками разных стран при старте диалога пользователя и бота. Пока что я еще не экспериментировал со встроенными клавиатурами и редактированием сообщений, которое появилось недавно, 15 мая.

Если у вас есть вопросы, с удовольствием отвечу в комментариях.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.