Как легко написать бота для 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 мая.

Если у вас есть вопросы, с удовольствием отвечу в комментариях.
Теги:
telegram bots, c#, .net, telegram

Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.