#include "commands.h" #include "common.h" #include "curl/curl.h" #include "curl/easy.h" #include "td/telegram/td_api.h" #include "td/tl/TlObject.h" #include "util.h" #include #include #include #include #include #include #include #include #include void send_help_msg(context *ctx, td_api::message &msg); void cmd::handle_regular_message(context *ctx, td_api::message &msg) { if (msg.content_->get_id() == td_api::messageText::ID) { std::string text = static_cast(*msg.content_).text_->text_; if (std::strncmp(text.c_str(), "/shorten ", 9) == 0) { std::string_view param(text.begin() + 9, text.end()); size_t nextSpace = param.find(' '); if (nextSpace != std::string_view::npos) param.remove_suffix(param.size() - nextSpace); spdlog::info("Command /shorten received with parameter '{}'", param); std::string paramStr(param); if (!url::is_url_valid(paramStr)) { send_help_msg(ctx, msg); return; } bool result = shorten_link(std::string(param), ctx, [tg = ctx->tg, chat_id = msg.chat_id_, thread_id = msg.message_thread_id_](std::string url){ tg->send_query(td_api::make_object( chat_id, thread_id, nullptr /*reply_to*/, nullptr /*options*/, nullptr, // reply_markup static_cast>(td_api::make_object( std::move(td_api::make_object(url, std::move(std::vector>()))), nullptr /*link_preview_options*/, false /*clear_draft*/ )) ), {}); }); if (!result) { ctx->tg->send_query(td_api::make_object( msg.chat_id_, msg.message_thread_id_, nullptr /*reply_to*/, nullptr /*options*/, nullptr, // reply_markup static_cast>(td_api::make_object( std::move(td_api::make_object("произошла какая-то ошибка :(", std::move(std::vector>()))), nullptr /*link_preview_options*/, false /*clear_draft*/ )) ), {}); } } else if (std::strncmp(text.c_str(), "/shorten", 8) == 0) { send_help_msg(ctx, msg); } } } void cmd::handle_inline_query(context *ctx, td_api::updateNewInlineQuery &query) { std::vector> results; if (url::is_url_valid(query.query_)) { uint64_t pendingQueryId = new_pending_query_id(); spdlog::debug("inserting new inline query for url {}", query.query_); ctx->inlineQueries.insert(std::pair(pendingQueryId, {query.query_, std::chrono::steady_clock::now() + std::chrono::hours(5)})); auto messageButton = td_api::make_object( "shorten", static_cast>(td_api::make_object(std::to_string(pendingQueryId))) ); std::vector messageButtonRow; messageButtonRow.push_back(std::move(messageButton)); std::vector messageButtonRows; messageButtonRows.push_back(std::move(messageButtonRow)); results.push_back(static_cast>(td_api::make_object( "shorten", "", true, // hide_url "Shorten!", "...", "https://slavasil.ru/favicon.ico", 48, 48, static_cast>(td_api::make_object( std::move(messageButtonRows) )), static_cast>(td_api::make_object( td_api::make_object( "press the button to shorten", std::move(std::vector>()) ), td_api::make_object(true, "", false, false, false), false // clear_draft )) ))); } ctx->tg->send_query(td_api::make_object( query.id_, false, // is_personal nullptr, // button std::move(results), 0, // cache_time "" // next_offset ), {}); } void cmd::handle_callback_query(context *ctx, td_api::updateNewInlineCallbackQuery &query) { spdlog::info("callback query"); if (query.payload_->get_id() != td_api::callbackQueryPayloadData::ID) return; auto payload = td::move_tl_object_as(query.payload_); ctx->tg->send_query(td_api::make_object( query.id_, payload->data_, false, "", 0 ), [](TgObject obj){ if (obj->get_id() == td_api::error::ID) { spdlog::error("answerCallbackQuery error: {}", static_cast(obj.get())->message_); } }); uint64_t queryId = std::stoull(payload->data_); spdlog::debug("is query in cache? {}", ctx->inlineQueries.contains(queryId)); try { pending_inline_query &queryInfo = ctx->inlineQueries.at(queryId); shorten_link(queryInfo.text, ctx, [ctx, inlineMessageId = query.inline_message_id_](std::string url){ ctx->tg->send_query(td_api::make_object( inlineMessageId, nullptr, // reply_markup static_cast>(td_api::make_object( td_api::make_object( url, std::move(std::vector>()) ), td_api::make_object(true, "", false, false, false), //nullptr, false )) ), {}); }); ctx->inlineQueries.erase(queryId); } catch (std::out_of_range) { spdlog::warn("a user tried to use an expired pending query"); ctx->tg->send_query(td_api::make_object( query.inline_message_id_, nullptr, // reply_markup static_cast>(td_api::make_object( td_api::make_object( "<сообщение устарело>", std::move(std::vector>()) ), nullptr, false )) ), {}); } } void cmd::handle_chosen_inline_result(context *ctx, td_api::updateNewChosenInlineResult &result) { shorten_link(result.query_, ctx, [ctx, inlineMessageId = result.inline_message_id_](std::string url){ ctx->tg->send_query(td_api::make_object( inlineMessageId, nullptr, // reply_markup static_cast>(td_api::make_object( td_api::make_object( url, std::move(std::vector>()) ), td_api::make_object(true, "", false, false, false), //nullptr, false )) ), {}); }); } bool cmd::shorten_link(std::string link, context *ctx, std::function cb) { spdlog::debug("creating CURL request"); CURL *req = curl_easy_init(); if (!req) { return false; } char *escapedParam = curl_easy_escape(req, link.data(), link.size()); std::string url("https://slavasil.ru/create?url="); url += escapedParam; curl_free(escapedParam); curl_easy_setopt(req, CURLOPT_URL, url.c_str()); curl_easy_setopt(req, CURLOPT_WRITEFUNCTION, curl_receive_cb); curl_easy_setopt(req, CURLOPT_WRITEDATA, req); curl_easy_setopt(req, CURLOPT_PRIVATE, ctx); curl_easy_setopt(req, CURLOPT_FOLLOWLOCATION, 1); ctx->requests.emplace(req, [cb, req, ctx](active_request &r){ std::string shortenedUrl(r.receivedData.data(), r.receivedData.size()); spdlog::info("Received data from HTTP server: {}", shortenedUrl); cb(shortenedUrl); ctx->requests.erase(req); }); CURLMcode r = curl_multi_add_handle(ctx->curl, req); return r == CURLM_OK; } void send_help_msg(context *ctx, td_api::message &msg) { std::string textRaw("usage: /shorten "); std::vector> empty; auto text = static_cast>(td_api::make_object(td_api::make_object(textRaw, std::move(empty)), nullptr, false)); ctx->tg->send_query(td_api::make_object(msg.chat_id_, msg.message_thread_id_, nullptr, nullptr, nullptr, std::move(text)), {}); } uint64_t cmd::new_pending_query_id() { static std::mt19937 rng; static std::uniform_int_distribution dist(0, 0xFFFFFFFFFFFFFFFFULL); return dist(rng); }