Доброго времени суток! В Telegram существует два вида API: Telegram Bot API (обыкновенный бот с пометкой "бот") и Telegram API (клиент и юзербот, который обладает больше функционалом, чем просто бот). В этой статье пойдет речь о втором виде, а именно: что требуется для взаимодействия с Telegram API, какие средства нужны для написания кода своего юзербота на языке C#, как их правильно установить, а также каким образом использовать их.
Введение
Администраторам групп и чатов порой необходимо пользоваться таким полезным инструментом как боты, а кому-то и вовсе требуется свой клиент для запросов серверу Telegram. Для взаимодействия с ботами существует немалое количество готовых библиотек для различных языков и платформ, но если требуется написать собственную программу или библиотеку (возможно, написанные другими людьми библиотеки ограничены и не содержат требуемых вам функций), то для этого Telegram имеет собственный API.
Telegram поддерживает два варианта API: Telegram Bot API (обычный бот) и Telegram API (собственный клиент или юзербот). В сегодняшнем материале речь пойдет о втором случае, когда нужно свой аккаунт использовать как бота или же для каких-либо иных действий. Например, с помощью Telegram API можно написать полностью свой клиент, который будет работать точно также как и основной "телеграммовский" клиент, можно реализовать отображение реального времени на вашей аватарке, можно использовать своего юзербота как сканер для защиты вашего чата от спама, флуда, "рейдов" и т. д. В общем, применений найдется много.
Для реализации юзербота потребуются две вещи: библиотека TDLib и любой язык, который способен выполнять функции языка C (в нашем случае используем C#).
Сборка и подключение библиотеки TDLib
Чтобы обеспечить взаимодействие между вашим клиентом и сервером Telegram, используется кроссплатформенная библиотека TDLib (Telegram Database Library). Будем устанавливать ее для Visual Studio (нужна версия от 2015 и выше, а также CMake в консоли).
Обратите внимание, что библиотека TDLib, устанавливаемая через NuGet, и библиотека Telegram.Td.dll, собираемая через CMake — это разные вещи, обладающие несколько разными интерфейсами. В нашем случае мы используем собираемый через CMake вариант.
TDLib имеет следующие зависимости, т. е. на вашем компьютере это должно быть:
- компилятор C++14 (Visual Studio имеет свой компилятор MSVC);
- Библиотека OpenSSL;
- Библиотека zlib;
- gperf (только сборка);
- CMake (3.0.2+, только сборка).
Для установки необходимых зависимостей, выполните следующие команды в командной строке (обратите внимание, что требуется git):
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
git checkout 1b1ae50e1a69f7c659bd7d731e80b358d21c86ad
.\bootstrap-vcpkg.bat
.\vcpkg.exe install gperf:x64-windows gperf:x86-windows openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
Далее скачиваем саму библиотеку и собираем её для .NET-проектов:
Переходим в папку (в командной строке) /example/csharp, т.е. туда, где будем собирать нашу библиотеку
Создаём папку, куда будем собирать библиотеку, и переходим в неё:
mkdir build cd build
Настраиваем сборку библиотеки в зависимости от разрядности системы (x32 или x64); где "...path to vcpkg...", указываем путь до скачанного ранее vcpkg:
- Для x32:
cmake -A Win32 -DTD_ENABLE_DOTNET=ON -DCMAKE_TOOLCHAIN_FILE=<path to vcpkg>/scripts/buildsystems/vcpkg.cmake ../../..
- Для x64:
cmake -A x64 -DTD_ENABLE_DOTNET=ON -DCMAKE_TOOLCHAIN_FILE=<path to vcpkg>/scripts/buildsystems/vcpkg.cmake ../../..
- Для x32:
Собираем библиотеку в зависимости от требуемой конфигурации (Release или Debug):
- Для Release:
cmake --build . --config Release
- Для Debug:
cmake --build . --config Debug
- Для Release:
Готово! Теперь в папке build/Release или build/Debug (в зависимости от того, что вы выбрали) находится готовый файл Telegram.Td.dll, который и нужно использовать в своем проекте.
Давайте теперь подключим её в Visual Studio:
Добавляем ссылку на наш файл Telegram.Td.dll, это можно сделать по следующему пути:
Проект -> Добавить -> Ссылка на проект -> Обзор -> Обзор
Ставим галочку напротив нашей библиотеки.
Запускаем проект, для того, чтобы создать папку с exe- и dll-файлами нашей программы, и туда докидываем следующие dll, которые можно взять из той же папки, где мы получили собранную библиотеку Telegram.Td.dll: libcrypto-1_1-x64.dll, libssl-1_1-x64.dll, zlib1.dll.
Должен получиться похожий набор файлов, но главное, чтобы все 4 dll-файла для нашей библиотеки были вместе, включая саму библиотеку:
Теперь мы можем подключать библиотеку в коде:
using Td = Telegram.Td;
using TdApi = Telegram.Td.Api;
Получение API Id и API Hash
Перед тем, как полноценно использовать библиотеку, нужно получить id и hash — своеобразная защита, чтобы пользоваться юзерботом можно было только с вашего разрешения. Их можно получить здесь:
Войдите, пройдите небольшую аутентификацию и создайте новое приложение (поля URL и Description можно оставить пустыми, в Platform выберите Desktop):
В разделе App Configuration найдите два поля: App api_id и App api_hash. Скопируйте их, они понадобятся для дальнейшей работы с TDLib.
Использование библиотеки TDLib
Рассмотрим готовый вариант использования, находящийся в самой папке библиотеки, которую мы скачали до этого: ...\TDLib\td-master\example\csharp\TdExample.cs
Перед тем, как запускать для проверки этот пример в коде, в методе OnAuthorizationStateUpdated, содержащем все необходимое для авторизации, включая обработки текущих стадий авторизации, стоит исправить эти две строки на ваш api_id и api_hash, которые мы получили до этого:
request.ApiId = /*api_id*/;
request.ApiHash = /*api_hash*/;
Разберемся с основным методом Main, где до основного цикла происходит процедура создания клиента:
Td.Client.Execute(new TdApi.SetLogVerbosityLevel(0));
if (Td.Client.Execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false))) is TdApi.Error) {
throw new System.IO.IOException("Write access to the current directory is required");
}
new Thread(() => {
Thread.CurrentThread.IsBackground = true;
Td.Client.Run();
}).Start();
_client = CreateTdClient();
_defaultHandler.OnResult(Td.Client.Execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test")));
В целом, эту часть трогать не стоит, она необходима, чтобы Ваш клиент работал правильно и вообще работал.
Далее идёт основной цикл:
while (!_needQuit) {
// Ожидание авторизации
_gotAuthorization.Reset();
_gotAuthorization.WaitOne();
// Предзагрузка чатов
_client.Send(new TdApi.LoadChats(null, 100), _defaultHandler);
// Пока пользователь авторизован, происходит обработка команд в консоли.
// Если же окажется, что пользователь разлогинился (метод GetCommand содержит данную
// возможность), то авторизация происходит снова.
// Выход из цикла организуется, когда пользователь выходит из клиента
// (опять же метод GetCommand содержит данную возможность).
while (_haveAuthorization)
{
GetCommand();
}
}
Пример содержит также два достаточно важных класса: DefaultHandler и UpdateHandler. В них происходит обработка всех пришедших данных от сервера Telegram.
UpdateHandler нужен, когда происходит какое-то обновление (новые сообщения, информация, что пользователь в текущем клиенте разлогинился, и т. д.).
Например, можно написать следующее:
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
{
if (@object is TdApi.UpdateAuthorizationState)
{
OnAuthorizationStateUpdated((@object as TdApi.UpdateAuthorizationState).AuthorizationState);
}
else if (@object is TdApi.UpdateNewMessage)
{
// Здесь - вызов собственного метода, где в качестве аргумента можно указать (@object as TdApi.UpdateNewMessage).Message,
// чтобы обрабатывать сообщения, которые пришли.
// Таким образом, можно реализовать бота, отвечающего на различные команды в чате.
}
}
DefaultHandler нужен, когда мы где-то в коде посылаем команду-запрос с помощью метода Send:
_client.Send(new /*метод*/, _defaultHandler);
При этом ответ на этот запрос обрабатывается в DefaultHandler:
private class DefaultHandler : Td.ClientResultHandler
{
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
{
// Здесь происходит обработка @object, который и является ответом на наш запрос.
// @object может быть любым классом, который в документации указан в качестве
// возвращаемого к методу, сделавшему запрос
}
}
Все доступные методы и описание можно найти здесь, все классы — здесь.
Вашу собственную программу удобно строить поверх этого примера или все взаимодействие клиент-сервер можно спокойно реализовать в качестве отдельного класса.
Заключение
TDLib является удобным инструментом для реализации собственного клиента на .NET-платформе, но, к сожалению, для других систем, кроме тех, что на базе Windows, этот вариант создания своего клиента не подходит, поэтому можно воспользоваться JSON-интерфейсом через P/Invoke, если нужен именно C#.