Сейчас телеграм боты крайне популярны, вкратце что они из себя представляют: чтобы создать своего бота нужно получить токен у @BotFather, а потом используя его обращаться в HTTP API для получения обновлений (Update)
Есть два способа получения апдейтов:
getUpdates: обновления пачками приходят через механизм long poll
setWebhook: обновления по одному приходят на какой-то ваш адрес в виде http запроса из телеграма
Теоретически, setWebhook должен быть эффективнее, но на практике long справляется не хуже и не создаёт лишних сложностей в реализации и запуске бота.
Когда апдейт получен, бот просто использует апи, например sendMessage, в общем выполняет свою бизнес-логику.
Требования
Казалось бы, если всё так просто и есть спрос, то наверняка уже сотни библиотек для удобного создания ботов?
Вкратце - нет, если вы захотите написать телеграм бота, то вы (были) вынуждены делать это на python. Библиотеки на других языках непопулярны и зачастую не выполняют даже минимальных требований
Кстати, про минимальные требования. Для создания чего-то серьёзного хотелось бы по крайней мере:
асинхронное обращение к апи
легкое в подключение библиотеки и лёгкость в использовании
-
http2, по причинам схожим с теми, по которым хочется иметь асинхронность (переиспользование соединения)
Итак, по доброй традиции С++, мы не нашли под свои требования существующих библиотек и потому приступили к написанию своей.
TGBM
в TGBM (telegram-bot motherlib) нужно было создать три главных компонента:
генерация api методов и классов на основе документации
json - парсинг ответов и сериализация запросов
http2 и ssl (телеграм требует ssl соединение для работы)
И так как это С++, то перед тем как приступать к коду нужно решить главную проблему - как будут подключать вашу библиотеку. Конечно, CMake вне конкуренции и он точно будет. Но одного его недостаточно для подключения библиотеки с такими зависимостями как openssl (порой поражаешься, насколько сложной в подключении можно сделать библиотеку из кучки .c файлов) и boost.
Все до этого существующие библиотеки телеграм ботов на С++ требовали установить зависимости вручную.
Почему не vcpkg: эта система сборки похожа больше на шутку. Сидит какое-то количество программистов microsoft и вручную добавляет все библиотеки, потом вручную их обновляет, никакой расширяемости. Этот "пакетный менеджер" не умеет в версии библиотек. В него нельзя добавить свою библиотеку. Всё через какие-то странные костыли. И главное, последние несколько лет эта штука даже не развивается.
Они владеют github, у них целая операционная систем и они выпускают вот такие релизы:

Почему не conan: не просто так существует conan2. Очень сложная в использовании система, которая по моему личному мнению проиграет конкуренцию, так что уже сейчас использовать её не нужно. В конце концов, не для того мы пишем на С++ чтобы писать билд скрипты на питоне
Так что мы продолжили поиски пакетного менеджера. Оказалось, что решение есть, но оно (пока) не так популярно
CPM
CPM (cmake package manager). Этот пакетный менеджер как можно понять из названия использует cmake и основан на механизме cmake fetch content. При использовании CPM подключение библиотеки с любыми сложными зависимостями (openssl, boost, HPACK) выглядит просто:
CPMAddPackage(
NAME TGBM
GIT_REPOSITORY https://github.com/bot-motherlib/TGBM
GIT_TAG v1.0.1
OPTIONS "TGBM_ENABLE_EXAMPLES ON"
)
target_link_libraries(MyTargetName tgbmlib)
Думаю, для многих С++ программистов станет открытием, что не обязательно круглосуточно страдать при подключении зависимостей
И только теперь, после решения главной проблемы С++ можно приступать к коду.
Генерация апи
Первой неожиданностью стало то, что телеграм не предоставляет какой-то формальной схемы своего апи. Есть по сути только человекочитаемый текст, из-за чего парсить его и генерировать что-то на его основе не просто мука, а минное поле, учитывая что меняется апи примерно раз в 2 недели.
Так или иначе, с этим можно побороться, всего пару недель парсинга html глазами для выявления закономерностей =)
После этого ещё нужно узнать то, что в документации не написано: какой формат ответа у телеграма, например он не просто присылает status + body, вместо этого там в зависимости от запроса и вероятно расположения духа того кто в тот день это писал может быть
{ "ok" : true, result: "то что ты действительно хотел получить", "description": "", "error_code" }, а иногда оно вместо json может вообще в ответ прислать html, в общем там много мест для исследования методом проб, ошибок и мечтаний о том чтобы тг разраб это написал в документации.

После того как закономерности выявлены, пайплайн генерации таков:
html документация телеграма
скрипт, который создаёт файлы на С++ с структурами и функциями
С++ рефлексия (boost pfr) и несколько шаблонов генерирующие из С++ структур json парсинг и сериализацию запросов
Дальше остаётся "всего лишь" сформировать корректный json, отправить его по сети, получить обратно и распарсить.
Здесь достаточно упомянуть то что вышло в итоге: json парсится потоково, насколько это возможно эффективно, внутри используется boost json. Сериализация возложена на rapid json.
Насчёт http2... В С++ огромное множество библиотек на любую ситуацию. Именно из-за этого наивного мифа в итоге для http2 есть только nghttp2, после взгляда на которую было решено, что легче будет написать с нуля. Ну и написали реализацию http2 с нуля.
echobot
наконец можно посмотреть на какого-то работающего бота. По традиции это будет echobot, который отправляет в ответ то, что ему написал пользователь:
#include <tgbm/bot.hpp>
dd::task<void> main_task(tgbm::bot& bot);
int main() {
tgbm::bot bot{/* YOUR BOT TOKEN */};
main_task(bot).start_and_detach();
bot.run();
return 0;
}
dd::task<void> main_task(tgbm::bot& bot) {
using namespace tgbm::api;
auto updates = bot.updates();
while (Update* u = co_await updates.next()) {
Message* m = u->get_message();
if (!m || !m->text)
continue;
bot.api.sendMessage({.chat_id = m->chat->id, .text = *m->text})
.start_and_detach();
}
}
Первое что бросается в глаза - то что это даже проще в коде, чем аналогичные боты на питоне.
Разберём по строкам то что тут происходит:
создаём бота, передавая токен от BotFather
создаём цикл обработки апдейтов (тут он назван main_task) и запускаем его не блокируясь (start_and_detach)
и запускаем бота (bot.run())
bot.updates() возвращает асинхронный генератор апдейтов, из которого мы их получаем по одному (за этим скрыт один из способов получения апдейтов, long-poll или webHooks). Нам показалась эта схема наиболее гибкой и понятной.
В данном случае, мы просто отправляем в ответ sendMessage с тем же текстом, что прислал юзер (если это вообще был текст), при этом не блокируем ни корутину, ни поток, чтобы тут же начать обрабатывать следующий апдейт (.start_and_detach).
В целом, телеграм апи полностью повторяется в bot.api с такими же именами, причём везде используются структуры для имитации именованных аргументов. В будущем планируется добавить билдеры запросов, но это лишь микрооптимизация.
Команды
Команды это важная часть телеграм бота, каждый бот (по негласной конвенции) должен поддерживать команду /start и вот как добавление команд выглядит в tgbm (это тот же самый бот, но с командой send_cat отправляющей фото кота).
#include <tgbm/bot.hpp>
dd::task<void> main_task(tgbm::bot& bot);
int main() {
tgbm::bot bot{/* YOUR BOT TOKEN */};
bot.commands.add("send_cat", [&bot](tgbm::api::Message msg) {
bot.api.sendPhoto({
.chat_id = msg.chat->id,
.photo = tgbm::api::InputFile::from_file("path/to/cat", "image/jpeg"),
})
.start_and_detach();
});
main_task(bot).start_and_detach();
bot.run();
return 0;
}
dd::task<void> main_task(tgbm::bot& bot) {
using namespace tgbm::api;
auto updates = bot.updates();
while (Update* u = co_await updates.next()) {
Message* m = u->get_message();
if (!m || !m->text)
continue;
bot.api.sendMessage({.chat_id = m->chat->id, .text = *m->text})
.start_and_detach();
}
}
Теперь неплохо бы поговорить о том, что в действительности происходит внутри. Мы старались обойтись без неявностей, так как важно понимать что твой код делает.
Во время обработки цикла (co_await updates.next()) если апдейт был командой (сообщением /send_cat), то вместо того чтобы разбудить корутину ожидающую Update, вызывается обработчик команды.
Внутри запросов api тоже всё прозрачно: формируется json запрос, в зависимости от содержимого запроса либо application/json либо multipart data по требованиям телеграма, кодируется в http2 + ssl, отправляется по сети, потом когда-то асинхронно читается и возвращает управление в этот цикл. Всё это (в данном случае) в одном потоке, никаких скрытых тредпулов.
Вот и всё, наконец-то на С++ можно просто взять и написать телеграм бота, пользуйтесь ) https://github.com/bot-motherlib/TGBM
Комментарии (34)
sabudilovskiy
17.01.2025 14:00Раньше хабр был весь в статьях-нативках телеграм каналов, а теперь телеграм библиотек. Прогресс?
Sazonov
17.01.2025 14:00Зря вы так на vcpkg. Версионность там есть, хотя немного нетривиально реализуется. Свои библиотеки подключать - тоже без проблем. И у меня такое чувство что вы путаете репозиторий с проектами который управляется Майкрософтом, и саму систему vcpkg.
Kelbon Автор
17.01.2025 14:00Как ни крути, оно проигрывает CPM даже если там будет всё легко и будет хорошая документация, хотя бы потому что оно не развивается уже несколько лет
Playa
17.01.2025 14:00Пока ваше дерево зависимостей имеет глубину 1-2, пока используемые библиотеки ведут себя нормально, все работает. Дальше CPM начинает испытывать трудности и они сами предлагают использовать vcpkg в таком случае.
В какой-то момент поймал себя на мысли, что мне проще написать рецепт для vcpkg, чем в очередной раз разбираться с тем, как для какой-то библиотеки собрать зависимости и как ей потом подсунуть флаги компиляции - vcpkg решает это за меня, причем кроссплатформенно.Kelbon Автор
17.01.2025 14:00Какие трудности у cpm возникнут ?
Playa
17.01.2025 14:00Попробуйте, например, VTK добавить через CPM. Ну или CPython. А ещё лучше VTK с поддержкой python.
Я не говорю, что это невозможно, в конце концов принцип работы у всех одинаковый. Просто в случае с vcpkg это кто-то уже сделал и оно тестируется, а в случае с CPM это придётся делать самостоятельно.Kelbon Автор
17.01.2025 14:00Это вопрос хорошего cmake у библиотеки. Я вообще считаю, что лучше не использовать кривые библиотеки, пусть постараются и сделают хотя бы 1 нормально написанный файл в проекте (CMakeLists.txt), иначе их никто не будет использовать
Playa
17.01.2025 14:00VTK пилит Kitware, так что вряд ли у них плохой CMake. Он не плохой, он объёмный и там много фич с кучей зависимостей, которые в случае с CPM придется разруливать вам.
DjUmnik
17.01.2025 14:00Насчёт Conan не понял, чем он так плох? Вполне рабочая штука. Хотя да, они сломали всё при переходе на версию 2.0. Но в целом они спрятали зоопарк разных систем сборок библиотек за одним фасадом. Собственные пакеты создаются элементарно.
Kelbon Автор
17.01.2025 14:00И я и мои знакомые, которые пытались пользоваться conan зачастую не могут написать рецепт к простейшей библиотеке. А эти люди вообще-то С++ смогли выучить. Это говорит о том, что conan слишком неудобен для реальности
wl2776
17.01.2025 14:00А у меня, вот, получается. И с C++ я знаком, и рецепты на конане пишу.
Конан очень удобен для случаев, когда надо собрать чей-то чужой уже готовый проект. Добавление одного файла conanfile (.py или . txt) позволяет установить все зависимости без изменения исходников самого проекта. CPM так не может.
Arenoros
17.01.2025 14:00не сказал бы что прям элементарно, но уж всяко лучше чем устанавливать в систему непонятно что не понятно откуда. Так что я уж лучше разберусь со сложностями conan но буду иметь полный контроль над сборкой зависимостей.
Apoheliy
17.01.2025 14:00Ещё добавлю про систему сборки:
Вы (действительно!) уверены, что при наличии уже установленного OpenSSL версии 3 будет правильным (и безопасным!) скачивать в исходниках версию 1 с репозитория некого Джанбара из Франции, собирать её из исходников, и (подозреваю) установить её в систему как одну из версий криптобиблиотек?
Про остальные библиотеки тоже так себе решение: подтянуть ещё одну версию буста (причём не всю, только отдельные библиотеки) и др.
Возможно, это сомнительный путь. Не находите?
-
Ответ на "Почему версия 1": Потому что в файле deps.cmake указан тэг 1.1.1w-20231130. Хотя, возможно, для Джанбара это самая новая версия библиотеки.
Kelbon Автор
17.01.2025 14:00Почему версия 1? Даже через буст и шифры в коде явно отключается возможность установить соединение по версии 1 и 2
sabudilovskiy
17.01.2025 14:00С OpenSSL вообще непросто, у них есть версия SSL, версия библиотеки и версия TLS, 1.1.1w-20231130 поддерживает TLS 1.2/TLS 1.3.
Это не прям последняя версия, но с ней всё нормально
Homyakin
17.01.2025 14:00За старания, конечно, лайк.
если вы захотите написать телеграм бота, то вы (были) вынуждены делать это на python. Библиотеки на других языках непопулярны и зачастую не выполняют даже минимальных требований
Только данное утверждение выглядит крайне безосновательно, а по личному опыту даже не является правдой.
Kelbon Автор
17.01.2025 14:00много библиотек на блокирующих вызовах или с другими фундаментальными проблемами, даже на питоне кажется всего 2 библиотеки, которые стоят рассмотрения (telegram-bot и aiogram)
Homyakin
17.01.2025 14:00на блокирующих вызовах
Скорее всего мои боты пока не дошли до того, что это является проблемой (да и вряд ли дойдут).
Сам пишу ботов на Java с использованием TelegramBots и проблем у меня с библиотекой примерно никаких. Всё апи поддерживается, если чего-то мне не хватает, то это косяк апи телеграма, а не библиотеки.
В общем, интересно узнать, что за требования такие к библиотекам.
dyadyaSerezha
17.01.2025 14:00Абсолютно согласен. Перечислены некие внутренние технические требования, но не внешние к боту, и ощущение, что требования просто высосаны из пальца. И из текста непонятно, таких библиотек нет вообще или нет только для С++.
Kelbon Автор
17.01.2025 14:00Перечислены как раз минимальные требования. Блокирующие вызовы апи, в некоторых библиотеках даже без таймаутов, это буквально невозможность написать хоть что нибудь с помощью бота так, чтобы оно не зависло навсегда и не тормозило при наличии хотя бы 2 юзеров
Есть ещё боты с http1, которые заново создают соединение каждый раз при походе в апи, добавляя по 0.5-1 секунде к задержке ответа, это очень ощущается со стороны пользователя
Notevil
17.01.2025 14:00А вот вы про
> оно не зависло навсегда и не тормозило при наличии хотя бы 2 юзеров
А есть какое-то сравнение с питоновскими либами? Или тут в принципе бенчмаркать бессмысленно так-как очень быстро упремся в скорострельность серверов телеграмма?
Kelbon Автор
17.01.2025 14:00если бот блокируется пока обрабатывает одного пользователя, значит он не обрабатывает другого пользователя, тут не нужно бенчмарков, чтобы понять, что какой-то пользователь будет ждать минуты, чтобы до него очередь дошла
boldape
17.01.2025 14:00Я пишу с телефона и это очень больно, дальше идут параграфы не совсем согласованные между собой так как написаны они были в разном порядке, а это вступление вообще самым последним, чтобы хоть как-то смягчить удивление от моего коммента.
Скажите, а чем не устраивает классический вариант когда из главного потока синхронно в цикле полим и запускаем синхронную джобу на пуле потоков которая занимается обработкой?
Насчёт хттп2, чем вас курла не устроила?
На буст у многих аллергия по причине монструозности и отвратительной документации. Имхо делать его зависимостью в либе это вообще самое последнее средство когда по-другому вообще никак. Т.е. для меня это сразу красный флаг и четкое нет вашей либе, но я понимаю что художник вы и вам так красиво.
Вот например у нас в проекте тоже есть буст и если добавить вашу библиотеку то потенциально может появиться конфликт версий буста на ровном месте, потому что мы обновляем его только когда приспичит. И зачем нам этот головняк с разными версиями буста, я понимаю, что скорее всего никаких проблем не будет, но все же?
Если я правильно понял то у вас код пляшет от с++ структур по ним генерится сериализация в жисон, но есть и другой путь, вы можете генерить жисон, а потом из него генерить с++ структуры. Не уверен, что это не мое личное определение/понимание, но я называю этот подход обратным орм. Имхо сильно проще чем обычный орм когда источником правды служит конечный язык, а не скул/жисон. В идеале вам вообще не нужна билд зависимость от жисон библиотеки, вместо этого можно сгенерировать прям код сериализации только для ваших структур используя жисон библиотеку как дев зависимость в терминах раста, но честно я не знаю насколько это осуществимо на плюсах сегодня.
Все до этого существующие библиотеки телеграм ботов на С++ требовали установить зависимости вручную.
Имхо только так и надо. Вот например у нас используется йокто, а тамошние художники решили, что ходить в сеть во время сборки это вредно для здоровья. И все эти ваши фетч контенты с сипиэмами не работают, надо костыли делать. Опять же в экосистеме раста этот вопрос решен красиво, библиотека бьётся на более мелкие, т.е. например есть только та что генерит ц++ апи который про жисоны ни сном ни духом не знает, а просто отдает пэйлоад строкой , поверх уже сериализация в структуры и роутинг на команды, где то ещё будет подсос зависимостей из сипиэма в виде отдельной либы. А на границах интерфейсы. Зачем? Ну у нас и культя в проекте тоже есть и у нее тоже на любой вопрос свое решение и жисоны и сеть асинхронная имеются. В идеале я бы мог взять например ваш генератор апи и подставить свой транспорт потом распарсить жисон своей либой уже в свои структуры. Да это все сильно сложнее чем то что у вас, но зато намного проще комбится с существующими проектами. Ваша библиотека для написания бота отдельным приложением с ноля, а в существующий проект так просто как хочется не воткнется.
Корутины конечно модно и все такое, но ведь курла такая же асинхронная (как и культя), а если есть (а иначе нафига этот бот нужен) тяжёлая обработка то без пула потоков с джобами все равно не обойтись. Т.е. ваш демо/эхо бот точно также можно сделать с курлой в один поток, а что не демо так нужен пул все равно, так и зачем тогда эти корутины конкретно в этой либе? Я могу понять выбор корутин как достаточно универсальный интерфейс для транспорта, но вы транспорт гвоздями прибили и заменить его нельзя, тогда зачем корутины?
Я не критикую, а хочу понять вашу мотивацию/цели/проблемы связанные с выбором именно такого дизайна библиотеки. Т.е. мне лично код примеров вообще не интересен был как и сама либа, а вот как вы принимали архитектурные решение было бы интересно почитать.
Kelbon Автор
17.01.2025 14:00Скажите, а чем не устраивает классический вариант когда из главного потока синхронно в цикле полим и запускаем синхронную джобу на пуле потоков которая занимается обработкой?
тем, что это значительно менее эффективно и удобно. Плюс появляется многопоточность даже в самых простых приложениях, а это ведёт к багам
Плюс если у вас есть какой то тредпул встроенный в библиотеку и по сути глобальный, то это уже фреймворк, такие "умные" библиотеки потом при интеграции с другими ещё более умными порождают 10 тредпулов в одном приложении
Насчёт хттп2, чем вас курла не устроила?
у курла другие задачи, при этом там гораздо больше обработки ввиду того что легаси и гораздо меньше гибкости, а у нас своё решение, где мы можем творить что угодно под нашу конкретную задачу, получая максимальную производительность и гибкость
И та же асинхронность в курле прикручена как будто сбоку и библиотека кажется не рассчитана на такое использование
На буст у многих аллергия
страх буста во многом основан на мифах. в TGBM буст используется точечно, например boost asio, т.е. после сборки одного или нескольких .cpp где на asio зависимость, дальше сборка даже трогать буст не будет. Боязнь такой зависимости в основном связана с тем, что люди не хотят мучиться с её подключением. Но CPM решает эту проблему и подключая TGBM вы можете вообще не знать, что там есть буст. И скачивания тоже CPM избегает, если вам это нужно. И если ваш проект уже подключает буст, то CPM возьмёт его из кеша
вы можете генерить жисон, а потом из него генерить с++ структуры.
не понял тут. По документации генерируется .cpp, потом шаблоны в С++ коде по структурам делают парсинг/сериализацию в json. Какой-то невероятной завязки на json нет, через трейты можно даже добавить поддержку своего json, сейчас там ест поддержка для boost json и rapid json
В идеале вам вообще не нужна билд зависимость от жисон библиотеки
это разумеется невозможно, так как без сериализации и парсинга бот не заработает. А в случае парсинга, я кроме boost json больше не знаю ни одной библиотеки json поддерживающей потоковый парсинг, а это важная вещь позволяющая убрать лишние действия при обработке запросов
библиотека бьётся на более мелкие, т.е. например есть только та что генерит ц++
у нас библиотека итак разбита на множество частей. Отдельно
скрипты генерации апи
всё связанное с json
отдельно связанное с сетью и http1.1 / http2.0
отдельно корутины: kelcoro
отдельно часть http2.0 для кодирования хедеров по rfc: HPACK
В идеале я бы мог взять например ваш генератор апи и подставить свой транспорт потом распарсить жисон своей либой уже в свои структуры
никто вам не мешает это делать, можно отправить запрос не парся json и парсить самому. Генератор тоже отдельно существует
Я могу понять выбор корутин как достаточно универсальный интерфейс для транспорта, но вы транспорт гвоздями прибили и заменить его нельзя, тогда зачем корутины?
корутины здесь потому, что это единственный и лучший способ организации асинхронного кода. Насчёт транспорта я не понял, что прибили? Вы хотели по grpc ходить в телеграм? Телеграм позволяет обращаться только по http (и слава богу, ведь grpc та ещё хрень)
boldape
17.01.2025 14:00Плюс появляется многопоточность даже в самых простых приложениях, а это ведёт к багам
Это зависит от того как вы сделаете. Вот вы тут критикует курлу говоря, что там асинхронность с боку, но там как раз сделано так что вы сами управляете пулом потоков. Там очередь, а на чем ее крутить решает юзер код. Точно также можно сделать таски обработки запросов, а в апи выставляется функция запуска очереди. В простых случаях эта функция вызывается на одном потоке, хотите в главном как у вас в примере хотите в отдельном. В сложных случаях вызывается несколько раз из нескольких потоков - масштабирование.
у курла другие задачи, при этом там гораздо больше обработки ввиду того что легаси и гораздо меньше гибкости, а у нас своё решение, где мы можем творить что угодно под нашу конкретную задачу
Какие задачи решает курл я вроде бы как знаю, и меня удивило, что по вашему мнению он не покрывает хттп2 транспорт. Расскажите какие задачи решает ваша хттп2 реализация которые не решаются курлой? Какой такой гибкости вам не хватает?
И скачивания тоже CPM избегает, если вам это нужно. И если ваш проект уже подключает буст, то CPM возьмёт его из кеша
Да и обычный фетч контен можно сделать без скачивания только это все костыли плюс брать что то из кеша возможно при соблюдении правил - сипиэм должен быть последним и предыдущий подход должен юзать фаинд пэкедж. Ну для буста это скорее исключение если кто то не через фаинд его подключает, а вот много других либ далеко не всегда предоставляют симэйк скрипт и там уже может не получиться у сипиэма найти что то в кешах. В общем мне кажется, что вы рано считаете, что основная проблема с++ решена для вашей либы. Если вдруг у вас будет какое то количество сторонних использований и никто не будет жаловаться тогда да решена.
корутины здесь потому, что это единственный и лучший способ организации асинхронного кода.
Я не очень понимаю, что вы хотите этим сказать. Вы же не утверждаете, что до с++ 20 на этом языке невозможно было реализовать асинхронность? Понятие лучший тоже никак не раскрыто, а если вы на самом деле считаете, что корутины это единственный способ, то качественная оценка лучший не имеет смысла. Это как первый элемент в очереди из одного элемента он же и последний - худший.
Насчёт транспорта я не понял, что прибили? Вы хотели по grpc ходить в телеграм?
Я хочу заменить вашу хттп2 + азию на курлу или культю не меняя код апи.
в случае парсинга, я кроме boost json больше не знаю ни одной библиотеки json поддерживающей потоковый парсинг
Если вы про SAX парсер то например nlohmann::json умеет такое.
не понял тут
Там сложно объяснить простым комментом поэтому я не буду вдаваться в подробности. Есть ещё одна альтернатива вашей архитектуре, можно парсить хтмл от телеги и генерить какой нибудь стандартный рест апи файл, а уже потом используя стандартные генераторы реста получить готовую либу не только на с++, но и для других языков. Мы например так генерим с++ транспорт культевый для своих рестов, где то мне попадались генераторы и на другие реализации сети. Очевидно эта работа (по предоставлению стандартного реста) должна быть сделана самой телегой, но раз они не сделали то это было бы наиболее полезно.
у нас библиотека итак разбита на множество частей.
Есть разница между разбивкой библиотеки на части/фичи и отделение каждой части в независимую библиотеку. Разбивка на библиотеки сложнее, но как вы говорите гибче. Когда у вас разбивка идёт на фичи, то сборка/зависимости управляются единообразно в родной либе, а когда разбивка на либы, то необходимо предоставить интерфейсы к зависимостям на уровне сборки в каждой либо - больше работы/сложнее, но позволяет легче интегрировать только необходимые части в существующие проекты.
Kelbon Автор
17.01.2025 14:00Вы же не утверждаете, что до с++ 20 на этом языке невозможно было реализовать асинхронность?
future, then, калбеки, всё это не способны выражения асинхронного кода, а устаревшее легаси. Никто не выберет футуры и then, когда есть корутины. И корутины прекрасно работают поверх калбеков. В итоге, весь выбор который у вас есть для асинхронного кода это стекфул или стеклес корутины.
Я выбрал использовать стеклес корутины по множеству причин, одна из которых написанная мной библиотека kelcoro, остальное лучше узнавать в докладах, статьях и комитете стандартизации С++, который решил именно этот способ закрепить в стандарте языка
Если вы про SAX парсер то например nlohmann::json умеет такое.
Нет, я не просто про sax парсинг, а sax парсинг потоковый, когда за раз можно предоставить не весь json. nlohhman известен тем насколько он медленный, при этом он проигрывает в удобстве boost json из-за странных дизайн решений, таких как неявная конвертация json во что угодно. Мы серьёзно подходили к вопросу выбора библиотеки для json и есть целая папка бенчмарков различных способов. Ради интереса можете посмотреть на итоговое решение
можно парсить хтмл от телеги и генерить какой нибудь стандартный рест апи файл
и что потом из него сгенерировать? Скорее всего либо придётся ещё писать парсер этих довольно убогих форматов, либо получить убогий С++ код, на который без слёз не взглянешь потом
dyadyaSerezha
17.01.2025 14:00То есть, я правильно понимаю, что все существующие нормальные боты написаны без использования открытых библиотек или таких ботов нет вообще?
Kelbon Автор
17.01.2025 14:00на питоне есть библиотеки, которые выполняют требования из статьи, на С++ - раньше не было
dyadyaSerezha
17.01.2025 14:00Тогда зачем выбирать С++? Непонятно.
Kelbon Автор
17.01.2025 14:00У С++ есть много преимуществ относительно питона - удобнее писать большие и среднего размера проекты, не нужно учить питон и нанимать других программистов, производительность в конце концов. Я бы сказал так, а зачем выбирать питон? Если на С++ бот пишется даже легче?
Homyakin
17.01.2025 14:00чтобы оно не зависло навсегда и не тормозило при наличии хотя бы 2 юзеров
добавляя по 0.5-1 секунде к задержке ответа
Это откровенная неправда. Сам знаком с людьми, которые пишут довольно популярных ботов и на JS, и на .NET, и на JVM. Поэтому претензия к блокирующим вызовам выглядит скорее вкусовщиной.
buran1
17.01.2025 14:00Вкратце - нет, если вы захотите написать телеграм бота, то вы (были) вынуждены делать это на python. Библиотеки на других языках непопулярны и зачастую не выполняют даже минимальных требований
Вкратце - нет, неправда: кроме либ на питоне есть и на других яп и довольно развитые поделки, например для go : https://github.com/gotd/td
Там довольно крутая идея использована : чем просто писать либу к апи и потом заниматься всю жизнь её поддержкой,
лучше 1 раз написать парсер TL и сделать либу автогенерируемой (навроде того как имея описание http Rest API на ямле в формате openapi swagger можно генерировать либки)Kelbon Автор
17.01.2025 14:00Для конкретно telegram BOT api нет TL, оно для клиентов телеграма. А TGBM собственно автогенерирует по апи код, но пользователю библиотеки даётся не скрипт генерации, а уже готовый код
JBFW
Простой бот легко пишется без всяких библиотек и питонов, да вот хотя бы на perl )
Но на С конечно быстрее.