- PVSM.RU - https://www.pvsm.ru -
Сперва я рассказывал простые вещи о Telegram Bot API и делал интересных ботов — виртуальную подругу и друга для заказа шавермы. Затем коснулся тестовых серверов и юзерботов. И наконец, пришла пора заглянуть глубже — узнать, как сделать свой клиент для Telegram. Что такое TL-схема и TDLib? Об этом мы сегодня и узнаем.
Данная статья не только поможет тем, кто решил написать свой клиент для Telegram, но и немного расширит кругозор остальным: MTProto — это не приевшийся JSON API. Добро пожаловать под кат!
Готовы показать свои знания в IT? Примите участие в IT-кроссворде [1] Selectel, выиграйте 10 000 рублей на аренду серверов и эксклюзивный мерч Selectel.
Telegram поощряет, ну или по крайней мере не наказывает, за разработку пользовательских клиентов. Для создания клиента необходимо придерживаться следующих правил [2]:
Нарушение этих правил приведет к предупреждению, а его игнорирование — к отключению API для вашего приложения. Также команда Telegram может запросить удалить ваше приложение из магазинов.
Также не стоит забывать, что деструктивные действия, такие как спам и распространение незаконного контента, вне зависимости от клиента являются нарушением [4] и могут привести к бану аккаунта.
Когда смотришь на количество «фич» в современном Telegram-клиенте, невольно представляешь себе поезд прогресса, у которого отказали тормоза. Быстро написать «с нуля» что-то сравнимое по функциональности с официальными клиентами практически невозможно. Поэтому энтузиасты делают то, что официальный Telegram не дает. В первую очередь вспоминаются юзерботы — их можно разделить на две категории.
Классические боты в «шкуре» пользователя
У обычных ботов в Telegram очень мало прав. У них по умолчанию нет возможности посмотреть историю сообщений в чате, даже если есть разрешение на доступ к переписке.
За доступ к истории чатов придется «заплатить» — вы не сможете создавать кнопки и использовать особые сообщения, например, выставлять счета. Нехорошие люди используют такой вид ботов для спама в публичных чатах.
Автоматизация действий пользователя
В этом варианте «бот» — это программа, которая использует основной аккаунт пользователя и реализует функциональность, недоступную в официальном приложении. Например, есть расширение PMPermit, которое автоматически отправляет в черный список незнакомцев, которые вам пишут.
Использование такого вида ботов — интересный процесс. Пользователь пишет команду в чат, где хочет выполнить действие. Сообщение отправляется на серверы Telegram, а оттуда «прилетает» обновлением в «клиент» юзербота. Бот удаляет сообщение-команду из чата и выполняет заданное действие.
На GitHub есть много [5] юзербот-проектов, но большинство из них на Python и используют фреймворки Telethon [6] или Pyrogram [7]. Для реализации своих задумок обычно достаточно использовать готового юзербота или написать личного на указанных фреймворках.
Функции и классы обычно имеют исчерпывающую документацию, которая доступна для среды разработки. Но почему у проектов такая хорошая документация? Пришла пора поговорить о TL-схемах.
TL — это от словосочетания «Type Language». Если коротко, то это особый язык описания типов и функций. Для Telegram существует несколько схем: организация шифрования для MTProto [8], основное API [9], e2e-шифрование и секретные чаты [10].
Рассмотрим описание одного конструктора для класса User:
user#d23c81a3 id:int first_name:string last_name:string = User;
Что в этой строке есть:
user
— человеко-читаемое имя конструктора.d23c81a3
— машинное представление конструктора. Считается как CRC32 от строки.id:int first_name:string last_name:string
— имена аргументов и их типы.User
— человеко-читаемое имя класса, которому принадлежит конструкторв.
Описание функций выглядит аналогично, но находится после строки ---functions---
. Рассмотрим объявление функции.
getUser#b0f732d5 id:int = User;
Отличия от описания типа:
getUser
— это имя функции.User
— это возвращаемое значение. Обратите внимание, что функции могут вернуть ошибку вместо значения — и это никак не отображается в схеме.Telegram выкладывает обновления в виде слоев (layer). Каждый слой API имеет полную TL-схему и определяет поддерживаемую функциональность приложения.
Type Language — это не совсем оригинальное детище Telegram. В TL-парсере можно встретить [11] упоминание ВК. В первых опубликованных исходниках kPHP находится [12] оригинальный парсер. Вторая попытка [13] открыть исходный код kPHP принесла документацию, в том числе по Type Language. Документация ссылается [14]… на сайт Telegram!
В идеальном мире TL-схема — это исчерпывающее описание интерфейса Telegram. В реальности же есть нюансы. На момент подготовки этой статьи Telegram выпустил обновление [15] от 29 октября с персональными цветами, цитатами и подсветкой синтаксиса. Это 166 слой схемы. На официальном сайте же доступен [9] только слой 158 — общие папки и выбор обоев в чате [16] от 21 апреля.
На corefork-поддомене [17] (как его нашли?) есть слой 164 с историями каналов [18] от 22 сентября. Актуальную схему можно найти в репозитории [19] Telegram Desktop.
Сам файл схемы не содержит документации, за объяснением и возможными ошибками необходимо идти на отдельную страницу [20] Telegram. Но повторюсь: там может не быть актуальной схемы.
Кроме того, в 2019 году nuclight [21] написал лонгрид [22], посвященный
костылямвызовам, которые встречаются при попытке реализовать MTProto с нуля по документации. И там очень много интересного.
К счастью, у Telegram есть решение на случай, если вы не хотите разбираться в тонкостях MTProto — TDLib.
Если вам интересно читать топики о программировании, Telegram и других технологиях, подписывайтесь на мой канал [23], где периодически пишу на разные темы.
TDLib (Telegram Database Library) [24] — это библиотека, которая абстрагирует разработчика от тонкостей работы с MTProto. Библиотека написана на С++ и имеет несколько интерфейсов:
Компиляция библиотеки долгая, но не вызывает трудностей. В документации есть блок [26], посвященный сборке, а также доступен генератор инструкций [27] для различных языков программирования и операционных систем.
Как и любое другое приложение Telegram, TDLib использует схему для взаимодействия с API. Возникает вопрос: а как в этом проекте с актуальностью? Здесь есть хорошая и плохая новости.
Плохая новость заключается в том, что TDLib все еще на шаг позади и использует слой 165. Актуальный, напомню, 166. Хорошая же новость — это документация интерфейсов TDLib. Библиотека приносит четвертую TL-схему — td_api.tl [28], которая содержит документацию в комментариях:
// @description Represents a user
// @id User identifier
// @first_name First name of the user
// @last_name Last name of the user
// @usernames Usernames of the user; may be null
// @phone_number Phone number of the user
// @status Current online status of the user
// @profile_photo Profile photo of the user; may be null
// @emoji_status Emoji status to be shown instead of the default Telegram Premium badge; may be null. For Telegram Premium users only
// @is_contact The user is a contact of the current user
// @is_mutual_contact The user is a contact of the current user and the current user is a contact of the user
// @is_close_friend The user is a close friend of the current user; implies that the user is a contact
// @is_verified True, if the user is verified
// @is_premium True, if the user is a Telegram Premium user
// @is_support True, if the user is Telegram support account
// @restriction_reason If non-empty, it contains a human-readable description of the reason why access to this user must be restricted
// @is_scam True, if many users reported this user as a scam
// @is_fake True, if many users reported this user as a fake account
// @has_active_stories True, if the user has non-expired stories available to the current user
// @has_unread_active_stories True, if the user has unread non-expired stories available to the current user
// @have_access If false, the user is inaccessible, and the only information known about the user is inside this class. Identifier of the user can't be passed to any method
// @type Type of the user
// @language_code IETF language tag of the user's language; only available to bots
// @added_to_attachment_menu True, if the user added the current bot to attachment menu; only available to bots
user id:int53 first_name:string last_name:string usernames:usernames phone_number:string status:UserStatus profile_photo:profilePhoto emoji_status:emojiStatus is_contact:Bool is_mutual_contact:Bool is_close_friend:Bool is_verified:Bool is_premium:Bool is_support:Bool restriction_reason:string is_scam:Bool is_fake:Bool has_active_stories:Bool has_unread_active_stories:Bool have_access:Bool type:UserType language_code:string added_to_attachment_menu:Bool = User;
–--functions---
@description Returns information about a user by their identifier. This is an offline request if the current user is not a bot @user_id User identifier
getUser user_id:int53 = User;
Достаточно подробно. Имена полей совпадают с полями в JSON, а имя конструктора (user) передается в поле с именем @type
:
{
"@type": "user",
"id": 777000,
"first_name": "Telegram",
"last_name": "Notifications",
"phone_number": "42777",
"status": {
"@type": "userStatusOnline",
"expires": 2147483647
},
"is_contact": false,
"is_mutual_contact": false,
"is_close_friend": false,
"is_verified": true,
"is_premium": false,
"is_support": true,
"restriction_reason": "",
"is_scam": false,
"is_fake": false,
"has_active_stories": false,
"has_unread_active_stories": false,
"have_access": true,
"type": {
"@type": "userTypeRegular"
},
"language_code": "",
"added_to_attachment_menu": false
}
Есть нюанс при работе с типами. Telegram различает целочисленные типы разной длины — int32, int53 и int64. Для JSON это все один целочисленный тип. Второй особенный тип — bytes. В JSON-интерфейсе это base64-строка.
С функциями все аналогично. В поле @type
нужно передать имя функции, а остальное — как прописано в схеме:
{
"@type": "getUser",
"user_id": 777000
}
TDLib — это асинхронная библиотека, в которой практически отсутствуют блокирующие вызовы:
// Создаем инстанс TdJson
void* td = td_json_client_create();
// Ожидаем ответ от TdJson в течение одной секунды.
// Если библиотека ничего не отдала, то указатель будет NULL.
// Эту функцию следует вызывать исключительно в одном потоке.
const char* res = td_json_client_receive(td, 1);
// Отправляем запрос в TdJson. Этот метод потокобезопасный.
const char* payload = "{"@type": "getUser", "user_id": 777000}";
td_json_client_send(td, payload);
// Прибираем за собой при завершении программы.
td_json_client_destroy(td);
Асинхронность подразумевает, что функция td_json_client_receive
может получать результаты в произвольном порядке. Более того, вместо результата может прийти ошибка:
{
"@type": "error",
"code": 404,
"message": "Not Found",
}
Как разобраться, к какому запросу относится ответ? Решение гениально и кроется в поле @extra
. При вызове функции можно дополнить запрос полем, которое будет перенесено в ответ!
Содержимое этого поля может быть любым — числовым, строковым или даже словарем. TDLib перенесет его в ответ как есть:
// Запрос
{
"@type": "getUser",
"user_id": 777000,
"@extra": {
"request_id": "4a05c088-525f-4464-a501-017f1060fcc5"
}
}
// Ответ
{
"@type": "error",
"code": 404,
"message": "Not Found",
"@extra": {
"request_id": "4a05c088-525f-4464-a501-017f1060fcc5"
}
}
Важный момент: дополнительное поле «пробрасывается» только в ответ на запрос. Например, есть функция loadChats
, которая делает следующее:
updateChat
по одному на каждый чат. При этом обновления (update) неотличимы от обычных обновлений.ok
или error
. Только этот ответ содержит поле @extra
.
Сейчас существует множество проектов, «улучшающих» взаимодействие с Telegram. Среди них — готовые юзерботы, которые можно расширять до «суровых» фреймворков. Интересно, как получить безграничную свободу в работе с Telegram API? Тогда следите за обновлениями в нашем блоге на Хабре!
Автор: Владимир
Источник [32]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/selectel/388045
Ссылки в тексте:
[1] участие в IT-кроссворде: https://slc.tl/harq6
[2] правил: https://core.telegram.org/api/terms
[3] правилам безопасности: https://core.telegram.org/mtproto/security_guidelines
[4] нарушением: https://telegram.org/tos/ru
[5] много: https://github.com/topics/telegram-userbot
[6] Telethon: https://github.com/LonamiWebs/Telethon/
[7] Pyrogram: https://docs.pyrogram.org/
[8] организация шифрования для MTProto: https://core.telegram.org/schema/mtproto
[9] основное API: https://core.telegram.org/schema
[10] e2e-шифрование и секретные чаты: https://core.telegram.org/schema/end-to-end
[11] можно встретить: https://github.com/tdlib/td/blob/master/td/generate/tl-parser/tl-parser.h
[12] находится: https://github.com/vk-com/kphp-kdb/blob/master/TL/tl-parser-new.h
[13] Вторая попытка: https://habr.com/ru/companies/vk/articles/527420/
[14] ссылается: https://vkcom.github.io/kphp/kphp-client/tl-schema-and-rpc/tl-schema-basics.html
[15] обновление: https://telegram.org/blog/reply-revolution/ru?ln=a
[16] общие папки и выбор обоев в чате: https://telegram.org/blog/shareable-folders-custom-wallpapers/ru
[17] corefork-поддомене: https://corefork.telegram.org/schema
[18] историями каналов: https://telegram.org/blog/channel-stories/ru
[19] репозитории: https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/SourceFiles/mtproto/scheme/api.tl
[20] отдельную страницу: https://core.telegram.org/methods
[21] nuclight: https://habr.com/ru/users/nuclight/
[22] лонгрид: https://habr.com/ru/articles/472970/
[23] канал: https://t.me/%2BVzpLr5pam-MxODEy
[24] TDLib (Telegram Database Library): https://github.com/tdlib/td
[25] JNI (Java Native Interface): https://github.com/tdlib/td/tree/master/example/java
[26] блок: https://core.telegram.org/tdlib/docs/index.html%23building
[27] генератор инструкций: https://tdlib.github.io/td/build.html
[28] td_api.tl: https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl
[29] Как сделать бота для заказа шавермы и оставить голодными лишь 1,1% коллег: https://slc.tl/et7wo
[30] Как создать мод для Cyberpunk 2077 и какие инструменты выбрать: https://slc.tl/xtv4x
[31] Как и зачем у нас появился статический анализатор типов для Python: https://slc.tl/hke0u
[32] Источник: https://habr.com/ru/companies/selectel/articles/771496/?utm_source=habrahabr&utm_medium=rss&utm_campaign=771496
Нажмите здесь для печати.