image
Доброго времени суток! В 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

Обратите внимание, что библиотека 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-проектов:


  1. Переходим в папку (в командной строке) /example/csharp, т.е. туда, где будем собирать нашу библиотеку


  2. Создаём папку, куда будем собирать библиотеку, и переходим в неё:


    mkdir build
    cd build

  3. Настраиваем сборку библиотеки в зависимости от разрядности системы (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 ../../..

  4. Собираем библиотеку в зависимости от требуемой конфигурации (Release или Debug):


    • Для Release:
      cmake --build . --config Release
    • Для Debug:
      cmake --build . --config Debug


Готово! Теперь в папке build/Release или build/Debug (в зависимости от того, что вы выбрали) находится готовый файл Telegram.Td.dll, который и нужно использовать в своем проекте.


Давайте теперь подключим её в Visual Studio:


  1. Добавляем ссылку на наш файл Telegram.Td.dll, это можно сделать по следующему пути:
    Проект -> Добавить -> Ссылка на проект -> Обзор -> Обзор
    Ставим галочку напротив нашей библиотеки.
    image


  2. Запускаем проект, для того, чтобы создать папку с exe- и dll-файлами нашей программы, и туда докидываем следующие dll, которые можно взять из той же папки, где мы получили собранную библиотеку Telegram.Td.dll: libcrypto-1_1-x64.dll, libssl-1_1-x64.dll, zlib1.dll.
    Должен получиться похожий набор файлов, но главное, чтобы все 4 dll-файла для нашей библиотеки были вместе, включая саму библиотеку:
    image



Теперь мы можем подключать библиотеку в коде:


using Td = Telegram.Td;
using TdApi = Telegram.Td.Api;

Получение API Id и API Hash


Перед тем, как полноценно использовать библиотеку, нужно получить id и hash — своеобразная защита, чтобы пользоваться юзерботом можно было только с вашего разрешения. Их можно получить здесь:


  1. Войдите, пройдите небольшую аутентификацию и создайте новое приложение (поля URL и Description можно оставить пустыми, в Platform выберите Desktop):
    image


  2. В разделе App Configuration найдите два поля: App api_id и App api_hash. Скопируйте их, они понадобятся для дальнейшей работы с TDLib.
    image



Использование библиотеки 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#.


Комментарии (3)


  1. LouieAusserhalb Автор
    17.06.2023 18:33
    +1

    Сам Telegram.Td.dll (наша библиотека TDLib) зависит от некоторых файлов и без них программа работать не сможет, поэтому если возникает исключение при запуске наподобие "Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly", то проверьте наличие следующих файлов:

    -  libcrypto-1_1-x64.dll (должен лежать в папке вместе с Telegram.Td.dll)

    -  libssl-1_1-x64.dll (должен лежать в папке вместе с Telegram.Td.dll)

    -  zlib1.dll (должен лежать в папке вместе с Telegram.Td.dll)

    -  Следующие системные файлы: ws2_32.dll, crypt32.dll, kernel32.dll, msvcp140.dll, vcruntime140.dll, vcruntime140_1.dll, api-ms-win-crt-runtime-l1-1-0.dll, api-ms-win-crt-heap-l1-1-0.dll, api-ms-win-crt-stdio-l1-1-0.dll, api-ms-win-crt-time-l1-1-0.dll, api-ms-win-crt-math-l1-1-0.dll, api-ms-win-crt-convert-l1-1-0.dll, api-ms-win-crt-string-l1-1-0.dll, normaliz.dll, mscoree.dll

    Если какие-то из системных файлов отсутствуют (скорее всего это будет происходить, если Вы запускаете собранный dll- или exe-файл, зависимый от Telegram.Td.dll, на другом компьютере), то попробуйте доустановить библиотеки среды выполнения Microsoft C и C++ (MSVC).


  1. breninsul
    17.06.2023 18:33

    Что-то я когда пытался разобраться с ужасом обнаружил, что документации и онлайн - гайдов нет (для java/kotlin, но не суть). Банально есть эвенты, но нет способа узнать полный список и что за что отвечает, кроме как бегать по коду.

    Это удручает


    1. korvint
      17.06.2023 18:33

      Лично я методом научного тыка разбирался. И да, было нетривиально. Особенно загрузить фоточки. Возможно, если будет настроение, статью запилю. Так куча нюансов весьма неочевидных.


  1. LouieAusserhalb Автор
    17.06.2023 18:33
    +1

    Сам Telegram.Td.dll (наша библиотека TDLib) зависит от некоторых файлов и без них программа работать не сможет, поэтому если возникает исключение при запуске наподобие "Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly", то проверьте наличие следующих файлов:

    -  libcrypto-1_1-x64.dll (должен лежать в папке вместе с Telegram.Td.dll)

    -  libssl-1_1-x64.dll (должен лежать в папке вместе с Telegram.Td.dll)

    -  zlib1.dll (должен лежать в папке вместе с Telegram.Td.dll)

    -  Следующие системные файлы: ws2_32.dll, crypt32.dll, kernel32.dll, msvcp140.dll, vcruntime140.dll, vcruntime140_1.dll, api-ms-win-crt-runtime-l1-1-0.dll, api-ms-win-crt-heap-l1-1-0.dll, api-ms-win-crt-stdio-l1-1-0.dll, api-ms-win-crt-time-l1-1-0.dll, api-ms-win-crt-math-l1-1-0.dll, api-ms-win-crt-convert-l1-1-0.dll, api-ms-win-crt-string-l1-1-0.dll, normaliz.dll, mscoree.dll

    Если какие-то из системных файлов отсутствуют (скорее всего это будет происходить, если Вы запускаете собранный dll- или exe-файл, зависимый от Telegram.Td.dll, на другом компьютере), то попробуйте доустановить библиотеки среды выполнения Microsoft C и C++ (MSVC).