From 38db383c9b0436fcc8334c8e54a0c617c7f38ed3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:37:34 +0000 Subject: [PATCH 1/7] Initial plan From eba47f8e5245cad5686e10b371bcab20278911db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:43:17 +0000 Subject: [PATCH 2/7] Convert from jsoncpp to nlohmann json library Co-authored-by: Royna2544 <69458352+Royna2544@users.noreply.github.com> --- CMakeLists.txt | 20 ++------- README.md | 6 +-- include/tgbot/TgTypeParser.h | 49 ++++++++++---------- include/tgbot/net/TgWebhookServer.h | 6 +-- src/Api.cpp | 70 ++++++++++++++--------------- src/TgTypeParser.cpp | 42 ++++++++--------- 6 files changed, 87 insertions(+), 106 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 150f9513..5d303243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,21 +58,8 @@ if (CURL_FOUND) target_compile_definitions(${PROJECT_NAME} PUBLIC -DHAVE_CURL) endif() -## jsoncpp -if (NOT TARGET JsonCpp::JsonCpp) - find_package(jsoncpp) - if (NOT TARGET JsonCpp::JsonCpp) - message(STATUS "Using alternative findjsoncpp") - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake") - find_package(JsonCppCustom) - if (NOT TARGET JsonCpp::JsonCpp) - message(FATAL_ERROR "Jsoncpp is not available") - endif() - endif() -endif() -install(FILES CMake/FindJsonCppCustom.cmake - DESTINATION lib/cmake/tgbot-cpp -) +## nlohmann_json +find_package(nlohmann_json 3.2.0 REQUIRED) ## boost set(Boost_USE_MULTITHREADED ON) @@ -91,7 +78,7 @@ set(LIB_LIST ZLIB::ZLIB OpenSSL::SSL Boost::system - JsonCpp::JsonCpp + nlohmann_json::nlohmann_json ) if (CURL_FOUND) @@ -105,7 +92,6 @@ endif() target_include_directories(${PROJECT_NAME} PUBLIC $ $) -target_include_directories(${PROJECT_NAME} PUBLIC ${jsoncpp_INCLUDE_DIRS} ${JSONCPP_PKG_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME} ${LIB_LIST}) include(GNUInstallDirs) install(TARGETS ${PROJECT_NAME} diff --git a/README.md b/README.md index a30bf3b0..3ec1f740 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Dependencies: - Boost - OpenSSL - ZLib -- JsonCpp +- nlohmann/json - Libcurl (optional unless you want to use curl-based http client `CurlHttpClient`). @@ -69,7 +69,7 @@ Dependencies: You can install dependencies on Debian-based distibutives with these commands: ```sh -sudo apt install g++ make binutils cmake libboost-system-dev libssl-dev zlib1g-dev libcurl4-openssl-dev libjsoncpp-dev +sudo apt install g++ make binutils cmake libboost-system-dev libssl-dev zlib1g-dev libcurl4-openssl-dev nlohmann-json3-dev ``` Optionally, install the dependencies for testing and documenting @@ -95,7 +95,7 @@ Alternatively, you can use Docker to build and run your bot. Set the base image You can install dependencies with these commands: ```sh -brew install gcc cmake boost openssl zlib curl jsoncpp +brew install gcc cmake boost openssl zlib curl nlohmann-json ``` You can compile and install the library like Linux instructions. diff --git a/include/tgbot/TgTypeParser.h b/include/tgbot/TgTypeParser.h index 2fb16237..594afcfc 100644 --- a/include/tgbot/TgTypeParser.h +++ b/include/tgbot/TgTypeParser.h @@ -1,7 +1,7 @@ #ifndef TGBOT_TGTYPEPARSER_H #define TGBOT_TGTYPEPARSER_H -#include +#include #include #include @@ -256,15 +256,15 @@ constexpr bool is_matrix_v = is_matrix::value; // Parse function for shared_ptr template -std::shared_ptr parse(const Json::Value &data) = delete; +std::shared_ptr parse(const nlohmann::json &data) = delete; #define DECLARE_PARSER_FROM_JSON(TYPE) \ template <> \ - TYPE::Ptr parse(const Json::Value &data) + TYPE::Ptr parse(const nlohmann::json &data) // Grab array of T from JSON array. template -std::vector> parseArray(const Json::Value &data) { +std::vector> parseArray(const nlohmann::json &data) { std::vector> result; for (const auto &item : data) { result.emplace_back(parse(item)); @@ -274,9 +274,9 @@ std::vector> parseArray(const Json::Value &data) { // Parse array from a key. template -std::vector> parseArray(const Json::Value &data, +std::vector> parseArray(const nlohmann::json &data, const std::string &key) { - if (!data.isMember(key)) { + if (!data.contains(key)) { return {}; } return parseArray(data[key]); @@ -284,7 +284,7 @@ std::vector> parseArray(const Json::Value &data, // Parse 2D array of T from JSON. template -Matrix> parseMatrix(const Json::Value &data) { +Matrix> parseMatrix(const nlohmann::json &data) { Matrix> result; for (const auto &item : data) { result.emplace_back(parseArray(item)); @@ -293,9 +293,9 @@ Matrix> parseMatrix(const Json::Value &data) { } template -Matrix> parseMatrix(const Json::Value &data, +Matrix> parseMatrix(const nlohmann::json &data, const std::string &key) { - if (!data.isMember(key)) { + if (!data.contains(key)) { return {}; } return parseMatrix(data[key]); @@ -303,25 +303,25 @@ Matrix> parseMatrix(const Json::Value &data, // Parse an array of primitive types. template -std::vector parsePrimitiveArray(const Json::Value &data, +std::vector parsePrimitiveArray(const nlohmann::json &data, const std::string &key) { - if (!data.isMember(key)) { + if (!data.contains(key)) { return {}; } std::vector result; for (const auto &item : data[key]) { - result.emplace_back(item.as()); + result.emplace_back(item.get()); } return result; } // Put function for objects to JSON template -Json::Value put(const T &value) = delete; +nlohmann::json put(const T &value) = delete; #define DECLARE_PARSER_TO_JSON(TYPE) \ template <> \ - Json::Value put(const TYPE::Ptr &object) + nlohmann::json put(const TYPE::Ptr &object) // Helper to put base class shared_ptr to derived T. template && std::is_base_of_v, bool> = true> -Json::Value put(const V &data) { +nlohmann::json put(const V &data) { return put(std::static_pointer_cast(data)); } // Put vector to JSON. template , bool> = true> -Json::Value put(const std::vector &vector) { - Json::Value dataArray(Json::arrayValue); +nlohmann::json put(const std::vector &vector) { + nlohmann::json dataArray = nlohmann::json::array(); for (const auto &item : vector) { if constexpr (detail::is_primitive_v) { - dataArray.append(item); + dataArray.push_back(item); } else if constexpr (std::is_same_v) { - dataArray.append(std::string(item)); + dataArray.push_back(std::string(item)); } else { // Recursively call put for non-primitives - dataArray.append(put(item)); + dataArray.push_back(put(item)); } } return dataArray; @@ -352,10 +352,10 @@ Json::Value put(const std::vector &vector) { // Put 2D array (Matrix) to JSON. template -Json::Value put(const Matrix &matrix) { - Json::Value dataMatrix(Json::arrayValue); +nlohmann::json put(const Matrix &matrix) { + nlohmann::json dataMatrix = nlohmann::json::array(); for (const auto &row : matrix) { - dataMatrix.append(put(row)); // Recursively call put for each row + dataMatrix.push_back(put(row)); // Recursively call put for each row } return dataMatrix; } @@ -363,8 +363,7 @@ Json::Value put(const Matrix &matrix) { // Serialize object to JSON string. template std::string putJSON(const T &object) { - Json::StreamWriterBuilder writer; - return Json::writeString(writer, put(object)); + return put(object).dump(); } #define IMPLEMENT_PARSERS(type) \ diff --git a/include/tgbot/net/TgWebhookServer.h b/include/tgbot/net/TgWebhookServer.h index 0cafd759..0a2e16e8 100644 --- a/include/tgbot/net/TgWebhookServer.h +++ b/include/tgbot/net/TgWebhookServer.h @@ -1,7 +1,7 @@ #ifndef TGBOT_TGHTTPSERVER_H #define TGBOT_TGHTTPSERVER_H -#include +#include #include #include @@ -38,9 +38,7 @@ class TgWebhookServer : public HttpServer { const std::string &data, const std::unordered_map &headers) { if (headers.at("_method") == "POST" && headers.at("_path") == _path) { - Json::Value update; - Json::Reader reader; - reader.parse(data, update, false); + nlohmann::json update = nlohmann::json::parse(data); _eventHandler->handleUpdate(parse(update)); } return HttpParser::generateResponse("", "text/plain", 200, "OK", false); diff --git a/src/Api.cpp b/src/Api.cpp index b9b45e14..240e815d 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -1,6 +1,4 @@ -#include -#include -#include +#include #include #include #include @@ -101,7 +99,7 @@ using TgBot::TgException; constexpr bool kSendRequestDebug = false; template -Json::Value sendRequest(const std::string_view _bot_url, +nlohmann::json sendRequest(const std::string_view _bot_url, TgBot::HttpClient *_httpClient, const std::string_view method, std::pair &&...args) { @@ -166,9 +164,10 @@ Json::Value sendRequest(const std::string_view _bot_url, TgException::ErrorCode::HtmlResponse); } - Json::Value result; - Json::Reader reader; - if (!reader.parse(serverResponse, result, false)) { + nlohmann::json result; + try { + result = nlohmann::json::parse(serverResponse); + } catch (const nlohmann::json::parse_error &e) { if constexpr (kSendRequestDebug) { std::cerr << "tgbot-cpp: Failed to parse response:" << serverResponse << std::endl; @@ -178,11 +177,11 @@ Json::Value sendRequest(const std::string_view _bot_url, TgException::ErrorCode::InvalidJson); } - if (result["ok"].asBool()) { + if (result["ok"].get()) { return result["result"]; } else { - std::string message = result["description"].asString(); - int errorCode = result["error_code"].as(); + std::string message = result["description"].get(); + int errorCode = result["error_code"].get(); throw TgException( message, static_cast(errorCode)); @@ -209,78 +208,77 @@ namespace TgBot { template <> std::string putJSON(const TgBot::Update::Types &object) { - Json::Value json; + nlohmann::json json = nlohmann::json::array(); if (object & Update::Types::business_connection) { - json.append("business_connection"); + json.push_back("business_connection"); } if (object & Update::Types::edited_business_message) { - json.append("edited_business_message"); + json.push_back("edited_business_message"); } if (object & Update::Types::edited_channel_post) { - json.append("edited_channel_post"); + json.push_back("edited_channel_post"); } if (object & Update::Types::edited_message) { - json.append("edited_message"); + json.push_back("edited_message"); } if (object & Update::Types::message) { - json.append("message"); + json.push_back("message"); } if (object & Update::Types::channel_post) { - json.append("channel_post"); + json.push_back("channel_post"); } if (object & Update::Types::business_message) { - json.append("business_message"); + json.push_back("business_message"); } if (object & Update::Types::deleted_business_messages) { - json.append("deleted_business_messages"); + json.push_back("deleted_business_messages"); } if (object & Update::Types::inline_query) { - json.append("inline_query"); + json.push_back("inline_query"); } if (object & Update::Types::poll) { - json.append("poll"); + json.push_back("poll"); } if (object & Update::Types::shipping_query) { - json.append("shipping_query"); + json.push_back("shipping_query"); } if (object & Update::Types::chosen_inline_result) { - json.append("chosen_inline_result"); + json.push_back("chosen_inline_result"); } if (object & Update::Types::callback_query) { - json.append("callback_query"); + json.push_back("callback_query"); } if (object & Update::Types::poll_answer) { - json.append("poll_answer"); + json.push_back("poll_answer"); } if (object & Update::Types::message_reaction) { - json.append("message_reaction"); + json.push_back("message_reaction"); } if (object & Update::Types::message_reaction_count) { - json.append("message_reaction_count"); + json.push_back("message_reaction_count"); } if (object & Update::Types::my_chat_member) { - json.append("my_chat_member"); + json.push_back("my_chat_member"); } if (object & Update::Types::chat_member) { - json.append("chat_member"); + json.push_back("chat_member"); } if (object & Update::Types::chat_join_request) { - json.append("chat_join_request"); + json.push_back("chat_join_request"); } if (object & Update::Types::chat_boost) { - json.append("chat_boost"); + json.push_back("chat_boost"); } if (object & Update::Types::removed_chat_boost) { - json.append("removed_chat_boost"); + json.push_back("removed_chat_boost"); } if (object & Update::Types::pre_checkout_query) { - json.append("pre_checkout_query"); + json.push_back("pre_checkout_query"); } if (object & Update::Types::purchased_paid_media) { - json.append("purchased_paid_media"); + json.push_back("purchased_paid_media"); } - Json::FastWriter writer; - return writer.write(json); + return json.dump(); } template <> diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index 3cfc11b2..efc7d508 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -12,8 +12,8 @@ namespace TgBot { // T should be instance of std::shared_ptr. template -std::shared_ptr parse(const Json::Value &data, const std::string &key) { - if (!data.isMember(key)) { +std::shared_ptr parse(const nlohmann::json &data, const std::string &key) { + if (!data.contains(key)) { return nullptr; } return parse(data[key]); @@ -27,17 +27,17 @@ TgException invalidType(const std::string_view name, } struct JsonWrapper { - JsonWrapper() : data_(Json::objectValue) {} + JsonWrapper() : data_(nlohmann::json::object()) {} template void put(const std::string_view key, T value) { - data_[key.data()] = std::move(value); + data_[std::string(key)] = std::move(value); } - void put(const std::string_view key, Json::Value value) { + void put(const std::string_view key, nlohmann::json value) { if (value.empty()) { return; } - data_[key.data()] = std::move(value); + data_[std::string(key)] = std::move(value); } template , bool> = true> @@ -45,47 +45,47 @@ struct JsonWrapper { if (!value) { return; // Skip empty optional } - data_[key.data()] = *value; + data_[std::string(key)] = *value; } - static void merge(Json::Value &thiz, const Json::Value &other) { - if (!thiz.isObject() || !other.isObject()) { + static void merge(nlohmann::json &thiz, const nlohmann::json &other) { + if (!thiz.is_object() || !other.is_object()) { return; } - for (const auto &key : other.getMemberNames()) { - if (thiz[key].isObject()) { - merge(thiz[key], other[key]); + for (auto it = other.begin(); it != other.end(); ++it) { + if (thiz[it.key()].is_object()) { + merge(thiz[it.key()], it.value()); } else { - thiz[key] = other[key]; + thiz[it.key()] = it.value(); } } } - void operator+=(const Json::Value &other) { merge(data_, other); } + void operator+=(const nlohmann::json &other) { merge(data_, other); } - JsonWrapper &operator=(Json::Value &&other) { + JsonWrapper &operator=(nlohmann::json &&other) { data_ = std::forward(other); return *this; } - operator Json::Value() const { return data_; } + operator nlohmann::json() const { return data_; } private: - Json::Value data_; + nlohmann::json data_; }; template || detail::is_optional_v, bool> = true> -void parse(const Json::Value &data, const std::string &key, T *value) { +void parse(const nlohmann::json &data, const std::string &key, T *value) { using Type = std::conditional_t, typename detail::is_optional::type, T>; using FixedType = std::conditional_t, double, Type>; using MoreFixedType = std::conditional_t, int64_t, FixedType>; - if (data[key].is()) { - *value = static_cast(data[key].as()); + if (data.contains(key) && !data[key].is_null()) { + *value = static_cast(data[key].get()); } } From 467f339a0de975d987e6f414ac4fc642acc77efe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:47:09 +0000 Subject: [PATCH 3/7] Fix remaining jsoncpp API calls to use nlohmann json Co-authored-by: Royna2544 <69458352+Royna2544@users.noreply.github.com> --- src/Api.cpp | 144 +++++++++++++++++++++---------------------- src/TgTypeParser.cpp | 8 +-- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/Api.cpp b/src/Api.cpp index 240e815d..6dc48d98 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -395,24 +395,24 @@ bool Api::setWebhook( std::pair{"ip_address", ipAddress}, std::pair{"drop_pending_updates", dropPendingUpdates}, std::pair{"secret_token", secretToken}) - .asBool(); + .get(); } bool Api::deleteWebhook(optional dropPendingUpdates) const { return sendRequest(_bot_api_baseurl, _httpClient, "deleteWebhook", std::pair{"drop_pending_updates", dropPendingUpdates}) - .asBool(); + .get(); } WebhookInfo::Ptr Api::getWebhookInfo() const { const auto &p = sendRequest(_bot_api_baseurl, _httpClient, "getWebhookInfo"); - if (!p.isMember("url")) { + if (!p.contains("url")) { return nullptr; } - if (!p["url"].asString().empty()) { + if (!p["url"].get().empty()) { return parse(p["url"]); } else { return nullptr; @@ -424,11 +424,11 @@ User::Ptr Api::getMe() const { } bool Api::logOut() const { - return sendRequest(_bot_api_baseurl, _httpClient, "logOut").asBool(); + return sendRequest(_bot_api_baseurl, _httpClient, "logOut").get(); } bool Api::close() const { - return sendRequest(_bot_api_baseurl, _httpClient, "close").asBool(); + return sendRequest(_bot_api_baseurl, _httpClient, "close").get(); } Message::Ptr Api::sendMessage( @@ -885,7 +885,7 @@ bool Api::setMessageReaction(ChatIdType chatId, std::pair{"message_id", messageId}, std::pair{"reaction", reaction}, std::pair{"is_big", isBig}) - .asBool(); + .get(); } bool Api::sendChatAction( @@ -897,7 +897,7 @@ bool Api::sendChatAction( std::pair{"chat_id", chatId}, std::pair{"action", action}, std::pair{"message_thread_id", messageThreadId}, std::pair{"business_connection_id", businessConnectionId}) - .asBool(); + .get(); } UserProfilePhotos::Ptr Api::getUserProfilePhotos( @@ -923,7 +923,7 @@ bool Api::banChatMember( std::pair{"user_id", userId}, std::pair{"until_date", untilDate}, std::pair{"revoke_messages", revokeMessages}) - .asBool(); + .get(); } bool Api::unbanChatMember(ChatIdType chatId, std::int64_t userId, @@ -932,7 +932,7 @@ bool Api::unbanChatMember(ChatIdType chatId, std::int64_t userId, std::pair{"chat_id", std::move(chatId)}, std::pair{"user_id", userId}, std::pair{"only_if_banned", onlyIfBanned}) - .asBool(); + .get(); } bool Api::restrictChatMember( @@ -946,7 +946,7 @@ bool Api::restrictChatMember( std::pair{"until_date", untilDate}, std::pair{"use_independent_chat_permissions", useIndependentChatPermissions}) - .asBool(); + .get(); } bool Api::promoteChatMember( @@ -976,7 +976,7 @@ bool Api::promoteChatMember( std::pair{"can_post_stories", canPostStories}, std::pair{"can_edit_stories", canEditStories}, std::pair{"can_delete_stories", canDeleteStories}) - .asBool(); + .get(); } bool Api::setChatAdministratorCustomTitle( @@ -987,7 +987,7 @@ bool Api::setChatAdministratorCustomTitle( std::pair{"chat_id", std::move(chatId)}, std::pair{"user_id", userId}, std::pair{"custom_title", customTitle}) - .asBool(); + .get(); } bool Api::banChatSenderChat(ChatIdType chatId, @@ -995,7 +995,7 @@ bool Api::banChatSenderChat(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "banChatSenderChat", std::pair{"chat_id", std::move(chatId)}, std::pair{"sender_chat_id", senderChatId}) - .asBool(); + .get(); } bool Api::unbanChatSenderChat(ChatIdType chatId, @@ -1003,7 +1003,7 @@ bool Api::unbanChatSenderChat(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "unbanChatSenderChat", std::pair{"chat_id", std::move(chatId)}, std::pair{"sender_chat_id", senderChatId}) - .asBool(); + .get(); } bool Api::setChatPermissions( @@ -1014,13 +1014,13 @@ bool Api::setChatPermissions( std::pair{"permissions", std::move(permissions)}, std::pair{"use_independent_chat_permissions", useIndependentChatPermissions}) - .asBool(); + .get(); } std::string Api::exportChatInviteLink(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "exportChatInviteLink", std::pair{"chat_id", std::move(chatId)}) - .asString(); + .get(); } ChatInviteLink::Ptr Api::createChatInviteLink( @@ -1062,34 +1062,34 @@ bool Api::approveChatJoinRequest(ChatIdType chatId, std::int64_t userId) const { return sendRequest(_bot_api_baseurl, _httpClient, "approveChatJoinRequest", std::pair{"chat_id", std::move(chatId)}, std::pair{"user_id", userId}) - .asBool(); + .get(); } bool Api::declineChatJoinRequest(ChatIdType chatId, std::int64_t userId) const { return sendRequest(_bot_api_baseurl, _httpClient, "declineChatJoinRequest", std::pair{"chat_id", std::move(chatId)}, std::pair{"user_id", userId}) - .asBool(); + .get(); } bool Api::setChatPhoto(ChatIdType chatId, InputFile::Ptr photo) const { return sendRequest(_bot_api_baseurl, _httpClient, "setChatPhoto", std::pair{"chat_id", std::move(chatId)}, std::pair{"photo", std::move(photo)}) - .asBool(); + .get(); } bool Api::deleteChatPhoto(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "deleteChatPhoto", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::setChatTitle(ChatIdType chatId, const std::string_view title) const { return sendRequest(_bot_api_baseurl, _httpClient, "setChatTitle", std::pair{"chat_id", std::move(chatId)}, std::pair{"title", title}) - .asBool(); + .get(); } bool Api::setChatDescription(ChatIdType chatId, @@ -1097,7 +1097,7 @@ bool Api::setChatDescription(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "setChatDescription", std::pair{"chat_id", std::move(chatId)}, std::pair{"description", description}) - .asBool(); + .get(); } bool Api::pinChatMessage(ChatIdType chatId, std::int32_t messageId, @@ -1106,7 +1106,7 @@ bool Api::pinChatMessage(ChatIdType chatId, std::int32_t messageId, std::pair{"chat_id", std::move(chatId)}, std::pair{"message_id", messageId}, std::pair{"disable_notification", disableNotification}) - .asBool(); + .get(); } bool Api::unpinChatMessage(ChatIdType chatId, @@ -1114,19 +1114,19 @@ bool Api::unpinChatMessage(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "unpinChatMessage", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_id", messageId}) - .asBool(); + .get(); } bool Api::unpinAllChatMessages(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "unpinAllChatMessages", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::leaveChat(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "leaveChat", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } Chat::Ptr Api::getChat(ChatIdType chatId) const { @@ -1144,7 +1144,7 @@ std::vector Api::getChatAdministrators( int32_t Api::getChatMemberCount(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "getChatMemberCount", std::pair{"chat_id", std::move(chatId)}) - .asInt(); + .get(); } ChatMember::Ptr Api::getChatMember(ChatIdType chatId, @@ -1159,13 +1159,13 @@ bool Api::setChatStickerSet(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "setChatStickerSet", std::pair{"chat_id", std::move(chatId)}, std::pair{"sticker_set_name", stickerSetName}) - .asBool(); + .get(); } bool Api::deleteChatStickerSet(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "deleteChatStickerSet", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } std::vector Api::getForumTopicIconStickers() const { @@ -1193,7 +1193,7 @@ bool Api::editForumTopic( std::pair{"message_thread_id", messageThreadId}, std::pair{"name", name}, std::pair{"icon_custom_emoji_id", std::move(iconCustomEmojiId)}) - .asBool(); + .get(); } bool Api::closeForumTopic(ChatIdType chatId, @@ -1201,7 +1201,7 @@ bool Api::closeForumTopic(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "closeForumTopic", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_thread_id", messageThreadId}) - .asBool(); + .get(); } bool Api::reopenForumTopic(ChatIdType chatId, @@ -1209,7 +1209,7 @@ bool Api::reopenForumTopic(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "reopenForumTopic", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_thread_id", messageThreadId}) - .asBool(); + .get(); } bool Api::deleteForumTopic(ChatIdType chatId, @@ -1217,7 +1217,7 @@ bool Api::deleteForumTopic(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "deleteForumTopic", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_thread_id", messageThreadId}) - .asBool(); + .get(); } bool Api::unpinAllForumTopicMessages(ChatIdType chatId, @@ -1226,45 +1226,45 @@ bool Api::unpinAllForumTopicMessages(ChatIdType chatId, "unpinAllForumTopicMessages", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_thread_id", messageThreadId}) - .asBool(); + .get(); } bool Api::editGeneralForumTopic(ChatIdType chatId, std::string name) const { return sendRequest(_bot_api_baseurl, _httpClient, "editGeneralForumTopic", std::pair{"chat_id", std::move(chatId)}, std::pair{"name", std::move(name)}) - .asBool(); + .get(); } bool Api::closeGeneralForumTopic(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "closeGeneralForumTopic", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::reopenGeneralForumTopic(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "reopenGeneralForumTopic", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::hideGeneralForumTopic(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "hideGeneralForumTopic", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::unhideGeneralForumTopic(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "unhideGeneralForumTopic", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::unpinAllGeneralForumTopicMessages(ChatIdType chatId) const { return sendRequest(_bot_api_baseurl, _httpClient, "unpinAllGeneralForumTopicMessages", std::pair{"chat_id", std::move(chatId)}) - .asBool(); + .get(); } bool Api::answerCallbackQuery(const std::string_view callbackQueryId, @@ -1277,7 +1277,7 @@ bool Api::answerCallbackQuery(const std::string_view callbackQueryId, std::pair{"callback_query_id", callbackQueryId}, std::pair{"text", text}, std::pair{"show_alert", showAlert}, std::pair{"url", url}, std::pair{"cache_time", cacheTime}) - .asBool(); + .get(); } UserChatBoosts::Ptr Api::getUserChatBoosts(ChatIdType chatId, @@ -1301,7 +1301,7 @@ bool Api::setMyCommands(const std::vector &commands, std::pair{"commands", commands}, std::pair{"scope", std::move(scope)}, std::pair{"language_code", languageCode}) - .asBool(); + .get(); } bool Api::deleteMyCommands(BotCommandScope::Ptr scope, @@ -1309,7 +1309,7 @@ bool Api::deleteMyCommands(BotCommandScope::Ptr scope, return sendRequest(_bot_api_baseurl, _httpClient, "deleteMyCommands", std::pair{"scope", std::move(scope)}, std::pair{"language_code", languageCode}) - .asBool(); + .get(); } std::vector Api::getMyCommands( @@ -1326,7 +1326,7 @@ bool Api::setMyName(const optional name, return sendRequest(_bot_api_baseurl, _httpClient, "setMyName", std::pair{"name", name}, std::pair{"language_code", languageCode}) - .asBool(); + .get(); } BotName::Ptr Api::getMyName(const optional languageCode) const { @@ -1340,7 +1340,7 @@ bool Api::setMyDescription(const optional description, return sendRequest(_bot_api_baseurl, _httpClient, "setMyDescription", std::pair{"description", description}, std::pair{"language_code", languageCode}) - .asBool(); + .get(); } BotDescription::Ptr Api::getMyDescription( @@ -1356,7 +1356,7 @@ bool Api::setMyShortDescription( return sendRequest(_bot_api_baseurl, _httpClient, "setMyShortDescription", std::pair{"short_description", shortDescription}, std::pair{"language_code", languageCode}) - .asBool(); + .get(); } BotShortDescription::Ptr Api::getMyShortDescription( @@ -1371,7 +1371,7 @@ bool Api::setChatMenuButton(optional chatId, return sendRequest(_bot_api_baseurl, _httpClient, "setChatMenuButton", std::pair{"chat_id", chatId}, std::pair{"menu_button", std::move(menuButton)}) - .asBool(); + .get(); } MenuButton::Ptr Api::getChatMenuButton(optional chatId) const { @@ -1386,7 +1386,7 @@ bool Api::setMyDefaultAdministratorRights(ChatAdministratorRights::Ptr rights, "setMyDefaultAdministratorRights", std::pair{"rights", std::move(rights)}, std::pair{"for_channels", forChannels}) - .asBool(); + .get(); } ChatAdministratorRights::Ptr Api::getMyDefaultAdministratorRights( @@ -1413,7 +1413,7 @@ Message::Ptr Api::editMessageText( std::pair{"reply_markup", std::move(replyMarkup)}, std::pair{"entities", entities}, std::pair{"link_preview", std::move(linkPreviewOptions)}); - if (p.isMember("message_id")) { + if (p.contains("message_id")) { return parse(p); } else { return nullptr; @@ -1434,7 +1434,7 @@ Message::Ptr Api::editMessageCaption( std::pair{"reply_markup", std::move(replyMarkup)}, std::pair{"parse_mode", parseMode}, std::pair{"caption_entities", captionEntities}); - if (p.isMember("message_id")) { + if (p.contains("message_id")) { return parse(p); } else { return nullptr; @@ -1451,7 +1451,7 @@ Message::Ptr Api::editMessageMedia( std::pair{"message_id", messageId}, std::pair{"inline_message_id", inlineMessageId}, std::pair{"reply_markup", std::move(replyMarkup)}); - if (p.isMember("message_id")) { + if (p.contains("message_id")) { return parse(p); } else { return nullptr; @@ -1468,7 +1468,7 @@ Message::Ptr Api::editMessageReplyMarkup( std::pair{"message_id", messageId}, std::pair{"inline_message_id", inlineMessageId}, std::pair{"reply_markup", std::move(replyMarkup)}); - if (p.isMember("message_id")) { + if (p.contains("message_id")) { return parse(p); } else { return nullptr; @@ -1488,7 +1488,7 @@ bool Api::deleteMessage(ChatIdType chatId, std::int32_t messageId) const { return sendRequest(_bot_api_baseurl, _httpClient, "deleteMessage", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_id", messageId}) - .asBool(); + .get(); } bool Api::deleteMessages(ChatIdType chatId, @@ -1496,7 +1496,7 @@ bool Api::deleteMessages(ChatIdType chatId, return sendRequest(_bot_api_baseurl, _httpClient, "deleteMessages", std::pair{"chat_id", std::move(chatId)}, std::pair{"message_ids", messageIds}) - .asBool(); + .get(); } Message::Ptr Api::sendSticker( @@ -1550,7 +1550,7 @@ bool Api::createNewStickerSet( std::pair{"stickers", stickers}, std::pair{"sticker_type", stickerType}, std::pair{"needs_repainting", needsRepainting}) - .asBool(); + .get(); } bool Api::addStickerToSet(std::int64_t userId, const std::string_view name, @@ -1558,7 +1558,7 @@ bool Api::addStickerToSet(std::int64_t userId, const std::string_view name, return sendRequest(_bot_api_baseurl, _httpClient, "addStickerToSet", std::pair{"user_id", userId}, std::pair{"name", name}, std::pair{"sticker", std::move(sticker)}) - .asBool(); + .get(); } bool Api::setStickerPositionInSet(const std::string_view sticker, @@ -1566,13 +1566,13 @@ bool Api::setStickerPositionInSet(const std::string_view sticker, return sendRequest(_bot_api_baseurl, _httpClient, "setStickerPositionInSet", std::pair{"sticker", sticker}, std::pair{"position", position}) - .asBool(); + .get(); } bool Api::deleteStickerFromSet(const std::string_view sticker) const { return sendRequest(_bot_api_baseurl, _httpClient, "deleteStickerFromSet", std::pair{"sticker", sticker}) - .asBool(); + .get(); } bool Api::replaceStickerInSet(std::int64_t userId, const std::string_view name, @@ -1582,7 +1582,7 @@ bool Api::replaceStickerInSet(std::int64_t userId, const std::string_view name, std::pair{"user_id", userId}, std::pair{"name", name}, std::pair{"old_sticker", oldSticker}, std::pair{"sticker", std::move(sticker)}) - .asBool(); + .get(); } bool Api::setStickerEmojiList(const std::string_view sticker, @@ -1590,7 +1590,7 @@ bool Api::setStickerEmojiList(const std::string_view sticker, return sendRequest(_bot_api_baseurl, _httpClient, "setStickerEmojiList", std::pair{"sticker", sticker}, std::pair{"emoji_list", emojiList}) - .asBool(); + .get(); } bool Api::setStickerKeywords(const std::string_view sticker, @@ -1598,7 +1598,7 @@ bool Api::setStickerKeywords(const std::string_view sticker, return sendRequest(_bot_api_baseurl, _httpClient, "setStickerKeywords", std::pair{"sticker", sticker}, std::pair{"keywords", keywords}) - .asBool(); + .get(); } bool Api::setStickerMaskPosition(const std::string_view sticker, @@ -1606,14 +1606,14 @@ bool Api::setStickerMaskPosition(const std::string_view sticker, return sendRequest(_bot_api_baseurl, _httpClient, "setStickerMaskPosition", std::pair{"sticker", sticker}, std::pair{"mask_position", std::move(maskPosition)}) - .asBool(); + .get(); } bool Api::setStickerSetTitle(const std::string_view name, const std::string_view title) const { return sendRequest(_bot_api_baseurl, _httpClient, "setStickerSetTitle", std::pair{"name", name}, std::pair{"title", title}) - .asBool(); + .get(); } bool Api::setStickerSetThumbnail(const std::string_view name, @@ -1624,7 +1624,7 @@ bool Api::setStickerSetThumbnail(const std::string_view name, std::pair{"name", name}, std::pair{"user_id", userId}, std::pair{"sticker_format", format}, std::pair{"thumbnail", std::move(thumbnail)}) - .asBool(); + .get(); } bool Api::setCustomEmojiStickerSetThumbnail( @@ -1634,13 +1634,13 @@ bool Api::setCustomEmojiStickerSetThumbnail( "setCustomEmojiStickerSetThumbnail", std::pair{"name", name}, std::pair{"custom_emoji_id", customEmojiId}) - .asBool(); + .get(); } bool Api::deleteStickerSet(const std::string_view name) const { return sendRequest(_bot_api_baseurl, _httpClient, "deleteStickerSet", std::pair{"name", name}) - .asBool(); + .get(); } bool Api::answerInlineQuery(const std::string_view inlineQueryId, @@ -1656,7 +1656,7 @@ bool Api::answerInlineQuery(const std::string_view inlineQueryId, std::pair{"is_personal", isPersonal}, std::pair{"next_offset", nextOffset}, std::pair{"button", std::move(button)}) - .asBool(); + .get(); } SentWebAppMessage::Ptr Api::answerWebAppQuery( @@ -1747,7 +1747,7 @@ std::string Api::createInvoiceLink( sendPhoneNumberToProvider}, std::pair{"send_email_to_provider", sendEmailToProvider}, std::pair{"is_flexible", isFlexible}) - .asString(); + .get(); } bool Api::answerShippingQuery( @@ -1759,7 +1759,7 @@ bool Api::answerShippingQuery( std::pair{"ok", ok}, std::pair{"shipping_options", shippingOptions}, std::pair{"error_message", errorMessage}) - .asBool(); + .get(); } bool Api::answerPreCheckoutQuery( @@ -1769,7 +1769,7 @@ bool Api::answerPreCheckoutQuery( std::pair{"pre_checkout_query_id", preCheckoutQueryId}, std::pair{"ok", ok}, std::pair{"error_message", errorMessage}) - .asBool(); + .get(); } bool Api::setPassportDataErrors( @@ -1778,7 +1778,7 @@ bool Api::setPassportDataErrors( return sendRequest(_bot_api_baseurl, _httpClient, "setPassportDataErrors", std::pair{"user_id", userId}, std::pair{"errors", errors}) - .asBool(); + .get(); } Message::Ptr Api::sendGame( diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index efc7d508..2a9f13b3 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -4936,13 +4936,13 @@ DECLARE_PARSER_TO_JSON(GameHighScore) { // GenericReply DECLARE_PARSER_FROM_JSON(GenericReply) { - if (data.isMember("force_reply")) { + if (data.contains("force_reply")) { return parse(data); - } else if (data.isMember("remove_keyboard")) { + } else if (data.contains("remove_keyboard")) { return parse(data); - } else if (data.isMember("keyboard")) { + } else if (data.contains("keyboard")) { return parse(data); - } else if (data.isMember("inline_keyboard")) { + } else if (data.contains("inline_keyboard")) { return parse(data); } return nullptr; From acae68a8b326fc0db056075dcfac93fcc20b1236 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:47:39 +0000 Subject: [PATCH 4/7] Update Dockerfiles to use nlohmann-json3-dev instead of libjsoncpp-dev Co-authored-by: Royna2544 <69458352+Royna2544@users.noreply.github.com> --- Dockerfile | 2 +- Dockerfile_test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 081cb2fd..13231a0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM debian:latest MAINTAINER Oleg Morozenkov RUN apt-get -qq update && \ - apt-get -qq install -y g++ make binutils cmake libssl-dev libboost-system-dev libcurl4-openssl-dev zlib1g-dev libjsoncpp-dev && \ + apt-get -qq install -y g++ make binutils cmake libssl-dev libboost-system-dev libcurl4-openssl-dev zlib1g-dev nlohmann-json3-dev && \ rm -rf /var/lib/apt/lists/* WORKDIR /usr/src/tgbot-cpp diff --git a/Dockerfile_test b/Dockerfile_test index 917a7737..d4668e1a 100644 --- a/Dockerfile_test +++ b/Dockerfile_test @@ -17,7 +17,7 @@ RUN apt-get -qq update && \ python2.7-dev \ wget \ zlib1g-dev \ - libjsoncpp-dev \ + nlohmann-json3-dev \ pkg-config && \ rm -rf /var/lib/apt/lists/* From 5a80febe22b6b88f94a61e793b0bddce9e0329d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:49:05 +0000 Subject: [PATCH 5/7] Fix JsonWrapper to use is_null() instead of empty() for proper null checking Co-authored-by: Royna2544 <69458352+Royna2544@users.noreply.github.com> --- src/TgTypeParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index 2a9f13b3..752ed89f 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -34,7 +34,7 @@ struct JsonWrapper { data_[std::string(key)] = std::move(value); } void put(const std::string_view key, nlohmann::json value) { - if (value.empty()) { + if (value.is_null()) { return; } data_[std::string(key)] = std::move(value); From 9331aff7ab0237b45961d7b14b4e609c9177fb34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:51:05 +0000 Subject: [PATCH 6/7] Fix getWebhookInfo to parse the entire response object instead of just the URL field Co-authored-by: Royna2544 <69458352+Royna2544@users.noreply.github.com> --- src/Api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api.cpp b/src/Api.cpp index 6dc48d98..9e077469 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -413,7 +413,7 @@ WebhookInfo::Ptr Api::getWebhookInfo() const { } if (!p["url"].get().empty()) { - return parse(p["url"]); + return parse(p); } else { return nullptr; } From 0b828dfe8384d5764f30e6e16588cfde26b8983c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 01:55:14 +0000 Subject: [PATCH 7/7] Convert from jsoncpp to nlohmann/json Co-authored-by: Royna2544 <69458352+Royna2544@users.noreply.github.com> --- CMake/FindJsonCppCustom.cmake | 27 ------------------------ Dockerfile | 1 - Dockerfile_test | 1 - _codeql_detected_source_root | 1 + samples/common_defs.cmake | 7 ++---- samples/echobot-submodule/CMakeLists.txt | 2 +- 6 files changed, 4 insertions(+), 35 deletions(-) delete mode 100644 CMake/FindJsonCppCustom.cmake create mode 120000 _codeql_detected_source_root diff --git a/CMake/FindJsonCppCustom.cmake b/CMake/FindJsonCppCustom.cmake deleted file mode 100644 index fc43e125..00000000 --- a/CMake/FindJsonCppCustom.cmake +++ /dev/null @@ -1,27 +0,0 @@ -# FindJsonCpp.cmake - -# Try to locate the jsoncpp package using pkg-config -find_package(PkgConfig QUIET) - -if (PKG_CONFIG_FOUND) - pkg_check_modules(JSONCPP_PKG jsoncpp) - - if (JSONCPP_PKG_FOUND) - # Create the jsoncpp imported target - if (NOT TARGET JsonCpp::JsonCpp) - add_library(JsonCpp::JsonCpp SHARED IMPORTED) - set_target_properties(JsonCpp::JsonCpp PROPERTIES - IMPORTED_LOCATION "${JSONCPP_PKG_LIBRARY_DIRS}/libjsoncpp.so" - INTERFACE_INCLUDE_DIRECTORIES "${JSONCPP_PKG_INCLUDE_DIRS}" - ) - - # Optionally, set any additional properties, such as dependencies or version - message(STATUS "Found JsonCpp: ${JSONCPP_PKG_LIBRARY_DIRS}/libjsoncpp.so") - endif() - - else() - message(FATAL_ERROR "Pkg-config found, but JsonCpp not found via pkg-config.") - endif() -else() - message(FATAL_ERROR "Pkg-config not found, cannot locate JsonCpp.") -endif() diff --git a/Dockerfile b/Dockerfile index 13231a0e..c79e66a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,6 @@ WORKDIR /usr/src/tgbot-cpp COPY include include COPY src src COPY CMakeLists.txt ./ -COPY CMake CMake RUN cmake . && \ make -j$(nproc) && \ diff --git a/Dockerfile_test b/Dockerfile_test index d4668e1a..20cd4956 100644 --- a/Dockerfile_test +++ b/Dockerfile_test @@ -26,7 +26,6 @@ COPY include include COPY src src COPY test test COPY CMakeLists.txt ./ -COPY CMake CMake RUN cmake -DENABLE_TESTS=ON . && \ make -j$(nproc) && \ diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 00000000..945c9b46 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/samples/common_defs.cmake b/samples/common_defs.cmake index ce5f8d22..bb2c30c9 100644 --- a/samples/common_defs.cmake +++ b/samples/common_defs.cmake @@ -7,14 +7,11 @@ set(Boost_USE_MULTITHREADED ON) find_package(Threads REQUIRED) find_package(OpenSSL REQUIRED) find_package(Boost COMPONENTS system REQUIRED) -find_package(jsoncpp QUIET) -if (NOT TARGET JsonCpp::JsonCPP) - include(/usr/local/lib/cmake/tgbot-cpp/FindJsonCppCustom.cmake) -endif() +find_package(nlohmann_json 3.2.0 REQUIRED) find_package(CURL) include_directories(/usr/local/include ${OPENSSL_INCLUDE_DIR} ${Boost_INCLUDE_DIR}) if (CURL_FOUND) include_directories(${CURL_INCLUDE_DIRS}) add_definitions(-DHAVE_CURL) endif() -set(LINK_LIB_LIST /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} JsonCpp::JsonCpp) \ No newline at end of file +set(LINK_LIB_LIST /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} nlohmann_json::nlohmann_json) \ No newline at end of file diff --git a/samples/echobot-submodule/CMakeLists.txt b/samples/echobot-submodule/CMakeLists.txt index 3b9444d2..1bb8811b 100644 --- a/samples/echobot-submodule/CMakeLists.txt +++ b/samples/echobot-submodule/CMakeLists.txt @@ -4,4 +4,4 @@ project(echobot-submodule) include(../common_defs.cmake) add_subdirectory(tgbot-cpp) add_executable(echobot-submodule src/main.cpp) -target_link_libraries(echobot-submodule TgBot ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} JsonCpp::JsonCpp) +target_link_libraries(echobot-submodule TgBot ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} nlohmann_json::nlohmann_json)