From 5dde23210238e2c0428d37488395f1f7857c72a7 Mon Sep 17 00:00:00 2001 From: MistEO Date: Tue, 30 Aug 2022 23:57:19 +0800 Subject: [PATCH 01/11] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=95=B0=E6=8D=AE=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E5=B0=81=E8=A3=85=E4=BA=86=E4=B8=80=E4=B8=AA=20ReportDataTask?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/AutoRecruitTask.cpp | 131 ++++++++---------- src/MeoAssistant/AutoRecruitTask.h | 10 +- src/MeoAssistant/MeoAssistant.vcxproj | 2 + src/MeoAssistant/MeoAssistant.vcxproj.filters | 6 + src/MeoAssistant/ReportDataTask.cpp | 116 ++++++++++++++++ src/MeoAssistant/ReportDataTask.h | 46 ++++++ src/MeoAssistant/StageDropsTaskPlugin.cpp | 55 ++++---- src/MeoAssistant/StageDropsTaskPlugin.h | 6 +- 8 files changed, 265 insertions(+), 107 deletions(-) create mode 100644 src/MeoAssistant/ReportDataTask.cpp create mode 100644 src/MeoAssistant/ReportDataTask.h diff --git a/src/MeoAssistant/AutoRecruitTask.cpp b/src/MeoAssistant/AutoRecruitTask.cpp index 8b88a9418b..cb9af0fde9 100644 --- a/src/MeoAssistant/AutoRecruitTask.cpp +++ b/src/MeoAssistant/AutoRecruitTask.cpp @@ -7,6 +7,7 @@ #include "ProcessTask.h" #include "RecruitConfiger.h" #include "RecruitImageAnalyzer.h" +#include "ReportDataTask.h" #include "Resource.h" #include "AsstRanges.hpp" @@ -454,16 +455,24 @@ asst::AutoRecruitTask::calc_task_result_type asst::AutoRecruitTask::recruit_calc callback(AsstMsg::SubTaskExtraInfo, cb_info); } + bool to_report = false; if (!is_calc_only_task()) { // report if the slot is clean if (!m_dirty_slots.contains(index)) { - async_upload_result(info["details"]); + to_report = true; m_dirty_slots.emplace(index); // mark as dirty } else Log.info("will not report, dirty slots are", m_dirty_slots); } +#ifdef ASST_DEBUG + to_report = true; +#endif + if (to_report) { + upload_result(info["details"]); + } + if (need_exit()) return {}; // refresh @@ -664,16 +673,14 @@ bool asst::AutoRecruitTask::hire_all() return true; } -void asst::AutoRecruitTask::async_upload_result(const json::value& details) +void asst::AutoRecruitTask::upload_result(const json::value& details) { LogTraceFunction; if (m_upload_to_penguin) { - auto upload_future = std::async(std::launch::async, &AutoRecruitTask::upload_to_penguin, this, details); - m_upload_pending.emplace_back(std::move(upload_future)); + upload_to_penguin(details); } if (m_upload_to_yituliu) { - auto upload_future = std::async(std::launch::async, &AutoRecruitTask::upload_to_yituliu, this, details); - m_upload_pending.emplace_back(std::move(upload_future)); + upload_to_yituliu(details); } } @@ -681,12 +688,6 @@ void asst::AutoRecruitTask::upload_to_penguin(const json::value& details) { LogTraceFunction; - auto& opt = Resrc.cfg().get_options(); - - json::value cb_info = basic_info(); - cb_info["subtask"] = "ReportToPenguinStats"; - callback(AsstMsg::SubTaskStart, cb_info); - json::value body; body["server"] = m_server; body["stageId"] = "recruit"; @@ -701,85 +702,69 @@ void asst::AutoRecruitTask::upload_to_penguin(const json::value& details) body["source"] = "MeoAssistant"; body["version"] = Version; - std::string body_escape = utils::string_replace_all_batch(body.to_string(), { { "\"", "\\\"" } }); - -#ifdef _WIN32 - std::string body_escapes = utils::utf8_to_unicode_escape(body_escape); -#else - std::string body_escapes = body_escape; -#endif - std::string extra_param; if (!m_penguin_id.empty()) { extra_param = "-H \"authorization: PenguinID " + m_penguin_id + "\""; } - std::string cmd_line = utils::string_replace_all_batch(opt.penguin_report.cmd_format, - { { "[body]", body_escapes }, { "[extra]", extra_param } }); - Log.info("request_penguin |", cmd_line); - std::string response = utils::callcmd(cmd_line); - - Log.info("response:\n", response); - cb_info["details"]["response"] = response; - - static const std::regex http_ok_regex(R"(HTTP/.+ 200)"); - if (std::regex_search(response, http_ok_regex)) { - callback(AsstMsg::SubTaskCompleted, cb_info); - } - else { - cb_info["why"] = "上报失败"; - callback(AsstMsg::SubTaskError, cb_info); + if (!m_report_penguin_task_ptr) { + m_report_penguin_task_ptr = + std::make_shared(report_penguin_callback, static_cast(this), m_task_chain); } - static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); - std::smatch penguinid_sm; - if (std::regex_search(response, penguinid_sm, penguinid_regex)) { - json::value id_info = basic_info_with_what("PenguinId"); - m_penguin_id = penguinid_sm[1]; - id_info["details"]["id"] = m_penguin_id; - callback(AsstMsg::SubTaskExtraInfo, id_info); - } + m_report_penguin_task_ptr->set_report_type(ReportType::PenguinStats) + .set_body(body.to_string()) + .set_extra_param(extra_param) + .set_retry_times(5) + .run(); } void asst::AutoRecruitTask::upload_to_yituliu(const json::value& details) { LogTraceFunction; - auto& opt = Resrc.cfg().get_options(); - - json::value cb_info = basic_info(); - cb_info["subtask"] = "ReportToYituliu"; - callback(AsstMsg::SubTaskStart, cb_info); - json::value body = details; body["server"] = m_server; body["source"] = "MeoAssistant"; body["version"] = Version; body["uuid"] = m_yituliu_id; - std::string body_escape = utils::string_replace_all_batch(body.to_string(), { { "\"", "\\\"" } }); - -#ifdef _WIN32 - std::string body_escapes = utils::utf8_to_unicode_escape(body_escape); -#else - std::string body_escapes = body_escape; -#endif - - std::string cmd_line = utils::string_replace_all_batch(opt.yituliu_report.cmd_format, - { { "[body]", body_escapes }, { "[extra]", "" } }); - Log.trace("request_yituliu |", cmd_line); - - std::string response = utils::callcmd(cmd_line); - Log.trace("request_yituliu | response:\n", response); - - cb_info["details"]["response"] = response; - - static const std::regex http_ok_regex(R"(HTTP/.+ 200)"); - if (std::regex_search(response, http_ok_regex)) { - callback(AsstMsg::SubTaskCompleted, cb_info); - } - else { - cb_info["why"] = "上报失败"; - callback(AsstMsg::SubTaskError, cb_info); + if (!m_report_yituliu_task_ptr) { + m_report_yituliu_task_ptr = + std::make_shared(report_yituliu_callback, static_cast(this), m_task_chain); } + + m_report_yituliu_task_ptr->set_report_type(ReportType::YituliuBigData) + .set_body(body.to_string()) + .set_retry_times(1) + .run(); +} + +void asst::AutoRecruitTask::report_penguin_callback(AsstMsg msg, const json::value& detail, void* custom_arg) +{ + LogTraceFunction; + + auto p_this = static_cast(custom_arg); + if (!p_this) { + return; + } + + if (msg == AsstMsg::SubTaskExtraInfo && detail.get("what", std::string()) == "PenguinId") { + std::string id = detail.get("details", "id", std::string()); + p_this->m_penguin_id = id; + } + + p_this->callback(msg, detail); +} + +void asst::AutoRecruitTask::report_yituliu_callback(AsstMsg msg, const json::value& detail, void* custom_arg) +{ + LogTraceFunction; + + auto p_this = static_cast(custom_arg); + if (!p_this) { + return; + } + + p_this->callback(msg, detail); } diff --git a/src/MeoAssistant/AutoRecruitTask.h b/src/MeoAssistant/AutoRecruitTask.h index 6ecb3d05f9..1b906eab3b 100644 --- a/src/MeoAssistant/AutoRecruitTask.h +++ b/src/MeoAssistant/AutoRecruitTask.h @@ -3,13 +3,14 @@ #include "AsstTypes.h" -#include #include #include #include namespace asst { + class ReportDataTask; + class AutoRecruitTask final : public AbstractTask { public: @@ -46,9 +47,11 @@ namespace asst bool initialize_dirty_slot_info(const cv::Mat&); static std::vector start_recruit_analyze(const cv::Mat& image); - void async_upload_result(const json::value& details); + void upload_result(const json::value& details); void upload_to_penguin(const json::value& details); void upload_to_yituliu(const json::value& details); + static void report_penguin_callback(AsstMsg msg, const json::value& detail, void* custom_arg); + static void report_yituliu_callback(AsstMsg msg, const json::value& detail, void* custom_arg); using slot_index = size_t; @@ -88,7 +91,8 @@ namespace asst bool m_upload_to_yituliu = false; std::string m_penguin_id; std::string m_yituliu_id; - std::vector> m_upload_pending; + std::shared_ptr m_report_penguin_task_ptr = nullptr; + std::shared_ptr m_report_yituliu_task_ptr = nullptr; static slot_index slot_index_from_rect(const Rect& r) { diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 509e1812bb..00f8f9367b 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -40,6 +40,7 @@ + @@ -131,6 +132,7 @@ + diff --git a/src/MeoAssistant/MeoAssistant.vcxproj.filters b/src/MeoAssistant/MeoAssistant.vcxproj.filters index 81aef0266d..cf6e047830 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj.filters +++ b/src/MeoAssistant/MeoAssistant.vcxproj.filters @@ -384,6 +384,9 @@ 头文件\Task\Plugin + + 头文件\Task\Sub + @@ -656,6 +659,9 @@ 源文件\Task\Plugin + + 源文件\Task\Sub + diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp new file mode 100644 index 0000000000..e9c6202a5d --- /dev/null +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -0,0 +1,116 @@ +#include "ReportDataTask.h" + +#include "AsstUtils.hpp" +#include "Logger.hpp" +#include "Resource.h" + +#include + +#include +#include + +asst::ReportDataTask& asst::ReportDataTask::set_report_type(ReportType type) +{ + m_report_type = type; + return *this; +} + +asst::ReportDataTask& asst::ReportDataTask::set_body(std::string body) +{ + m_body = std::move(body); + return *this; +} + +asst::ReportDataTask& asst::ReportDataTask::set_extra_param(std::string extra_param) +{ + m_extra_param = std::move(extra_param); + return *this; +} + +bool asst::ReportDataTask::_run() +{ + LogTraceFunction; + + std::function report_func; + + switch (m_report_type) { + case ReportType::PenguinStats: + report_func = std::bind(&ReportDataTask::report_to_penguin, this); + break; + case ReportType::YituliuBigData: + report_func = std::bind(&ReportDataTask::report_to_yituliu, this); + break; + default: + return false; + } + + auto upload_future = std::async(std::launch::async, report_func); + m_upload_pending.emplace_back(std::move(upload_future)); + + return true; +} + +void asst::ReportDataTask::report_to_penguin() +{ + LogTraceFunction; + + const auto& [success, response] = + escape_and_request("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); + + static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); + std::smatch penguinid_sm; + if (std::regex_search(response, penguinid_sm, penguinid_regex)) { + json::value id_info = basic_info_with_what("PenguinId"); + std::string penguin_id = penguinid_sm[1]; + id_info["details"]["id"] = penguin_id; + callback(AsstMsg::SubTaskExtraInfo, id_info); + } +} + +void asst::ReportDataTask::report_to_yituliu() +{ + LogTraceFunction; + + escape_and_request("ReportToYituliu", Resrc.cfg().get_options().yituliu_report.cmd_format); +} + +asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const std::string& subtask, + const std::string& format) +{ + LogTraceFunction; + + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; + callback(AsstMsg::SubTaskStart, cb_info); + + std::string body_escape = utils::string_replace_all_batch(m_body, { { "\"", "\\\"" } }); + +#ifdef _WIN32 + std::string body_escapes = utils::utf8_to_unicode_escape(body_escape); +#else + std::string body_escapes = body_escape; +#endif + + std::string cmd_line = + utils::string_replace_all_batch(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); + + Log.info("request:\n", cmd_line); + std::string response = utils::callcmd(cmd_line); + Log.info("response:\n", response); + + cb_info["details"]["response"] = response; + + bool success = false; + static const std::regex http_ok_regex(R"(HTTP/.+ 200)"); + if (std::regex_search(response, http_ok_regex)) { + success = true; + callback(AsstMsg::SubTaskCompleted, cb_info); + } + else { + success = false; + cb_info["why"] = "上报失败"; + callback(AsstMsg::SubTaskError, cb_info); + } + + return { success, response }; +} diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h new file mode 100644 index 0000000000..c740212850 --- /dev/null +++ b/src/MeoAssistant/ReportDataTask.h @@ -0,0 +1,46 @@ +#pragma once + +#include "AbstractTask.h" + +#include + +namespace asst +{ + enum class ReportType + { + Invaild, + PenguinStats, + YituliuBigData, + }; + + class ReportDataTask : public AbstractTask + { + public: + using AbstractTask::AbstractTask; + virtual ~ReportDataTask() noexcept override = default; + + ReportDataTask& set_report_type(ReportType type); + + ReportDataTask& set_body(std::string body); + ReportDataTask& set_extra_param(std::string extra_param); + + protected: + struct Response + { + bool success = false; + std::string response; + }; + + protected: + virtual bool _run() override; + + void report_to_penguin(); + void report_to_yituliu(); + Response escape_and_request(const std::string& subtask, const std::string& format); + + ReportType m_report_type = ReportType::Invaild; + std::string m_body; + std::string m_extra_param; + std::vector> m_upload_pending; + }; +} diff --git a/src/MeoAssistant/StageDropsTaskPlugin.cpp b/src/MeoAssistant/StageDropsTaskPlugin.cpp index c38d4983cf..c41854de9c 100644 --- a/src/MeoAssistant/StageDropsTaskPlugin.cpp +++ b/src/MeoAssistant/StageDropsTaskPlugin.cpp @@ -8,6 +8,7 @@ #include "Controller.h" #include "Logger.hpp" #include "ProcessTask.h" +#include "ReportDataTask.h" #include "Resource.h" #include "RuntimeStatus.h" #include "StageDropsImageAnalyzer.h" @@ -90,8 +91,7 @@ bool asst::StageDropsTaskPlugin::_run() } if (m_enable_penguid && !m_is_annihilation) { - auto upload_future = std::async(std::launch::async, &StageDropsTaskPlugin::upload_to_penguin, this); - m_upload_pending.emplace_back(std::move(upload_future)); + upload_to_penguin(); } return true; @@ -205,11 +205,8 @@ void asst::StageDropsTaskPlugin::upload_to_penguin() { LogTraceFunction; - auto& opt = Resrc.cfg().get_options(); - json::value cb_info = basic_info(); cb_info["subtask"] = "ReportToPenguinStats"; - callback(AsstMsg::SubTaskStart, cb_info); // Doc: https://developer.penguin-stats_vec.io/public-api/api-v2-instruction/report-api std::string stage_id = m_cur_info_json.get("stage", "stageId", std::string()); @@ -251,38 +248,38 @@ void asst::StageDropsTaskPlugin::upload_to_penguin() body["source"] = "MeoAssistant"; body["version"] = Version; - std::string body_escape = utils::string_replace_all(body.to_string(), "\"", "\\\""); - std::string cmd_line = utils::string_replace_all(opt.penguin_report.cmd_format, "[body]", body_escape); - std::string extra_param; if (!m_penguin_id.empty()) { extra_param = "-H \"authorization: PenguinID " + m_penguin_id + "\""; } - cmd_line = utils::string_replace_all(cmd_line, "[extra]", extra_param); - Log.info("request_penguin |", cmd_line); - std::string response = utils::callcmd(cmd_line); - - Log.info("response:\n", response); - cb_info["details"]["response"] = response; - - static const std::regex http_ok_regex(R"(HTTP/.+ 200)"); - if (std::regex_search(response, http_ok_regex)) { - callback(AsstMsg::SubTaskCompleted, cb_info); - } - else { - cb_info["why"] = "上报失败"; - callback(AsstMsg::SubTaskError, cb_info); + if (!m_report_penguin_task_ptr) { + m_report_penguin_task_ptr = + std::make_shared(report_penguin_callback, static_cast(this), m_task_chain); } - static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); - std::smatch penguinid_sm; - if (std::regex_search(response, penguinid_sm, penguinid_regex)) { - json::value id_info = basic_info_with_what("PenguinId"); - m_penguin_id = penguinid_sm[1]; - id_info["details"]["id"] = m_penguin_id; - callback(AsstMsg::SubTaskExtraInfo, id_info); + m_report_penguin_task_ptr->set_report_type(ReportType::PenguinStats) + .set_body(body.to_string()) + .set_extra_param(extra_param) + .set_retry_times(5) + .run(); +} + +void asst::StageDropsTaskPlugin::report_penguin_callback(AsstMsg msg, const json::value& detail, void* custom_arg) +{ + LogTraceFunction; + + auto p_this = static_cast(custom_arg); + if (!p_this) { + return; } + + if (msg == AsstMsg::SubTaskExtraInfo && detail.get("what", std::string()) == "PenguinId") { + std::string id = detail.get("details", "id", std::string()); + p_this->m_penguin_id = id; + } + + p_this->callback(msg, detail); } bool asst::StageDropsTaskPlugin::check_stage_valid() diff --git a/src/MeoAssistant/StageDropsTaskPlugin.h b/src/MeoAssistant/StageDropsTaskPlugin.h index d4c3c137d1..85557221fc 100644 --- a/src/MeoAssistant/StageDropsTaskPlugin.h +++ b/src/MeoAssistant/StageDropsTaskPlugin.h @@ -1,7 +1,7 @@ #pragma once #include "AbstractTaskPlugin.h" -#include +#include #include #include @@ -11,6 +11,7 @@ namespace asst { class ProcessTask; + class ReportDataTask; class StageDropsTaskPlugin final : public AbstractTaskPlugin { @@ -36,6 +37,7 @@ namespace asst bool check_specify_quantity() const; void stop_task(); void upload_to_penguin(); + static void report_penguin_callback(AsstMsg msg, const json::value& detail, void* custom_arg); static constexpr int64_t RecognitionTimeOffset = 20; @@ -48,8 +50,8 @@ namespace asst mutable bool m_is_annihilation = false; bool m_start_button_delay_is_set = false; - std::vector> m_upload_pending; ProcessTask* m_cast_ptr = nullptr; + std::shared_ptr m_report_penguin_task_ptr = nullptr; bool m_enable_penguid = false; std::string m_penguin_id; std::string m_server = "CN"; From 211a0fb946dc9bd92c808d635ec96ccdef4c9d80 Mon Sep 17 00:00:00 2001 From: MistEO Date: Wed, 31 Aug 2022 00:51:02 +0800 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E4=BC=81?= =?UTF-8?q?=E9=B9=85=E7=9A=84=E9=87=8D=E4=BC=A0=E5=B9=82=E7=AD=89=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://galvingao.notion.site/API-c826a571040f4d239876ea4e78e58be3 --- resource/config.json | 2 +- src/MeoAssistant/ReportDataTask.cpp | 43 +++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/resource/config.json b/resource/config.json index 32b4957a7f..8eb97292d0 100644 --- a/resource/config.json +++ b/resource/config.json @@ -14,7 +14,7 @@ "adbExtraSwipeDuration_Doc": "额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能", "penguinReport": { "Doc": "企鹅物流汇报: https://penguin-stats.cn/", - "cmdFormat": "curl -H \"Content-Type: application/json\" -s -S -m 5 -i -d \"[body]\" \"https://penguin-stats.cn/PenguinStats/api/v2/report\" [extra]", + "cmdFormat": "curl -H \"Content-Type: application/json\" -s -S -m 5 -i -d \"[body]\" \"https://penguin-stats.io/PenguinStats/api/v2/report\" [extra]", "cmdFormat_Doc": "命令格式,想打印详细信息可以尝试添加 -v -i" }, "yituliuReport": { diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index e9c6202a5d..6a9f02a092 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -6,8 +6,11 @@ #include +#include #include +#include #include +#include asst::ReportDataTask& asst::ReportDataTask::set_report_type(ReportType type) { @@ -52,18 +55,40 @@ bool asst::ReportDataTask::_run() void asst::ReportDataTask::report_to_penguin() { + using namespace std::chrono; + LogTraceFunction; - const auto& [success, response] = - escape_and_request("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); + auto epoch = time_point_cast(steady_clock::now()).time_since_epoch(); + long long tick = duration_cast(epoch).count(); - static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); - std::smatch penguinid_sm; - if (std::regex_search(response, penguinid_sm, penguinid_regex)) { - json::value id_info = basic_info_with_what("PenguinId"); - std::string penguin_id = penguinid_sm[1]; - id_info["details"]["id"] = penguin_id; - callback(AsstMsg::SubTaskExtraInfo, id_info); + static std::default_random_engine rand_engine(std::random_device {}()); + static std::uniform_int_distribution rand_uni(0, UINT64_MAX); + + uint64_t rand = rand_uni(rand_engine); + + std::stringstream key_ss; + key_ss << "MAA" << std::hex << tick << rand; + std::string key = key_ss.str(); + Log.info("X-Penguin-Idempotency-Key:", key); + + m_extra_param += " -H \"X-Penguin-Idempotency-Key: " + std::move(key) + "\""; + + for (int i = 0; i != m_retry_times; ++i) { + const auto& [success, response] = + escape_and_request("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); + + if (success) { + static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); + std::smatch penguinid_sm; + if (std::regex_search(response, penguinid_sm, penguinid_regex)) { + json::value id_info = basic_info_with_what("PenguinId"); + std::string penguin_id = penguinid_sm[1]; + id_info["details"]["id"] = penguin_id; + callback(AsstMsg::SubTaskExtraInfo, id_info); + } + break; + } } } From a1c8aa133e983a0bd6bd10b663c3c044f12c27af Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Wed, 31 Aug 2022 17:31:37 +0800 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=20Response=20?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/AsstUtils.hpp | 8 ++ src/MeoAssistant/ReportDataTask.cpp | 29 +++---- src/MeoAssistant/ReportDataTask.h | 117 +++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 18 deletions(-) diff --git a/src/MeoAssistant/AsstUtils.hpp b/src/MeoAssistant/AsstUtils.hpp index 800b595336..7c15677d21 100644 --- a/src/MeoAssistant/AsstUtils.hpp +++ b/src/MeoAssistant/AsstUtils.hpp @@ -1,6 +1,7 @@ #pragma once #include "AsstConf.h" +#include "AsstRanges.hpp" #include #include @@ -26,6 +27,13 @@ namespace asst::utils struct integral_constant_at_template_instantiation : std::integral_constant {}; + template + requires ranges::range && ranges::range + dst_t view_cast(const src_t& src) + { + return dst_t(src.begin(), src.end()); + } + inline void _string_replace_all(std::string& str, const std::string_view& old_value, const std::string_view& new_value) { diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 6a9f02a092..cf02d99c7d 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -75,20 +75,25 @@ void asst::ReportDataTask::report_to_penguin() m_extra_param += " -H \"X-Penguin-Idempotency-Key: " + std::move(key) + "\""; for (int i = 0; i != m_retry_times; ++i) { - const auto& [success, response] = + const auto& response = escape_and_request("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); - if (success) { + if (response.success()) [[likely]] { static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); - std::smatch penguinid_sm; - if (std::regex_search(response, penguinid_sm, penguinid_regex)) { + if (response.headers().contains("X-Penguin-Set-Penguinid")) { json::value id_info = basic_info_with_what("PenguinId"); - std::string penguin_id = penguinid_sm[1]; + std::string penguin_id(response.headers().at("X-Penguin-Set-Penguinid")); id_info["details"]["id"] = penguin_id; callback(AsstMsg::SubTaskExtraInfo, id_info); } break; } + else if (!response.code_5xx()) [[unlikely]] { + json::value cb_info = basic_info(); + cb_info["why"] = std::string(response.status_code_info()); + cb_info["details"]["status_code"] = response.status_code(); + callback(AsstMsg::SubTaskError, cb_info); + } } } @@ -120,22 +125,18 @@ asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const st utils::string_replace_all_batch(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); Log.info("request:\n", cmd_line); - std::string response = utils::callcmd(cmd_line); + Response response = utils::callcmd(cmd_line); Log.info("response:\n", response); - cb_info["details"]["response"] = response; + cb_info["details"]["response"] = static_cast(response); - bool success = false; - static const std::regex http_ok_regex(R"(HTTP/.+ 200)"); - if (std::regex_search(response, http_ok_regex)) { - success = true; + if (response.status_code()) [[likely]] { callback(AsstMsg::SubTaskCompleted, cb_info); } - else { - success = false; + else { // 连状态码都没有,一般是网络错误 cb_info["why"] = "上报失败"; callback(AsstMsg::SubTaskError, cb_info); } - return { success, response }; + return response; } diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index c740212850..ed65e0cece 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -1,8 +1,11 @@ #pragma once #include "AbstractTask.h" +#include "AsstUtils.hpp" #include +#include +#include namespace asst { @@ -25,10 +28,116 @@ namespace asst ReportDataTask& set_extra_param(std::string extra_param); protected: - struct Response + class Response : public std::string { - bool success = false; - std::string response; + private: + std::string m_last_error; + size_t m_status_code = 0; + std::string_view m_protocol_version; + std::string_view m_status_code_info; + std::string_view m_data; + std::unordered_map m_headers; + bool _analyze_status_line(std::string_view status_line) + { + size_t __word_count = 0; + for (const std::string_view& word : + std::views::split(status_line, ' ') | std::views::transform([](auto str_range) { + return utils::view_cast(str_range); + })) { + ++__word_count; + if (__word_count == 1) { + static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; + if (!accepted_protocol_version.contains(utils::view_cast(word))) { + m_last_error = "unsupport protocol version"; + return false; + } + m_protocol_version = utils::view_cast(word); + } + else if (__word_count == 2) { + static const std::unordered_map numbers = { + { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, + { '5', 5 }, { '6', 6 }, { '7', 7 }, { '8', 8 }, { '9', 9 }, + }; + if (word.length() != 3) { + m_last_error = "status code length is not 3"; + return false; + } + m_status_code = 0; + for (char num : word) { + if (!numbers.contains(num)) { + m_last_error = "status code is not number"; + return false; + } + m_status_code = m_status_code * 10 + numbers.at(num); + } + } + else { + m_status_code_info = std::string_view(word.begin(), status_line.end()); + return true; + } + } + if (__word_count == 2) { + m_status_code_info = ""; + return true; + } + m_last_error = "status line too short"; + return false; + } + bool _analyze_headers_line(std::string_view status_line) + { + size_t colon_pos = status_line.find(':'); + if (colon_pos == status_line.npos) { + m_last_error = "connot decode header `" + std::string(status_line) + "`"; + return false; + } + m_headers[status_line.substr(0, colon_pos)] = + status_line.substr(colon_pos + 1 + status_line.substr(colon_pos + 1).find_first_not_of(' ')); + return true; + } + + public: + template + requires std::is_constructible_v + Response(Args&&... args) : std::string(std::forward(args)...) + { + bool __is_status_line = true; + for (const auto& line : std::views::split(*this, '\n')) { + std::string_view line_view; + if (utils::view_cast(line).ends_with('\r')) { + line_view = utils::view_cast(line | std::views::take(line.size() - 1)); + } + else { + line_view = utils::view_cast(line); + } + if (__is_status_line) { + if (!_analyze_status_line(line_view)) { + return; + } + __is_status_line = false; + } + else if (!line_view.empty()) { + if (!_analyze_headers_line(line_view)) { + return; + } + } + else { + m_data = std::string_view(line.begin(), this->end()); + return; + } + } + } + + size_t status_code() const { return m_status_code; } + std::string_view protocol_version() const { return m_protocol_version; } + std::string_view status_code_info() const { return m_status_code_info; } + std::string_view data() const { return m_data; } + const std::unordered_map headers() const { return m_headers; } + + bool success() const { return m_status_code == 200; } + bool code_2xx() const { return m_status_code >= 200 && m_status_code < 300; } + bool code_3xx() const { return m_status_code >= 300 && m_status_code < 400; } + bool code_4xx() const { return m_status_code >= 400 && m_status_code < 500; } + bool code_5xx() const { return m_status_code >= 500 && m_status_code < 600; } }; protected: @@ -43,4 +152,4 @@ namespace asst std::string m_extra_param; std::vector> m_upload_pending; }; -} +} // namespace asst From 9722a60eb9ee1b9dfed519e9dcf955c55bd99534 Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Wed, 31 Aug 2022 17:54:53 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20headers=20?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/ReportDataTask.cpp | 6 ++---- src/MeoAssistant/ReportDataTask.h | 18 +++++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index cf02d99c7d..5da701b7c7 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include asst::ReportDataTask& asst::ReportDataTask::set_report_type(ReportType type) @@ -79,10 +78,9 @@ void asst::ReportDataTask::report_to_penguin() escape_and_request("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); if (response.success()) [[likely]] { - static const std::regex penguinid_regex(R"(X-Penguin-Set-Penguinid: (\d+))"); - if (response.headers().contains("X-Penguin-Set-Penguinid")) { + if (response.contains_header("x-penguin-set-penguinid")) { json::value id_info = basic_info_with_what("PenguinId"); - std::string penguin_id(response.headers().at("X-Penguin-Set-Penguinid")); + std::string penguin_id(response.at_header("x-penguin-set-penguinid")); id_info["details"]["id"] = penguin_id; callback(AsstMsg::SubTaskExtraInfo, id_info); } diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index ed65e0cece..231e53525a 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -3,8 +3,8 @@ #include "AbstractTask.h" #include "AsstUtils.hpp" +#include #include -#include #include namespace asst @@ -36,7 +36,7 @@ namespace asst std::string_view m_protocol_version; std::string_view m_status_code_info; std::string_view m_data; - std::unordered_map m_headers; + std::unordered_map m_headers; bool _analyze_status_line(std::string_view status_line) { size_t __word_count = 0; @@ -46,12 +46,12 @@ namespace asst })) { ++__word_count; if (__word_count == 1) { - static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; - if (!accepted_protocol_version.contains(utils::view_cast(word))) { + static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; + if (!accepted_protocol_version.contains(utils::view_cast(word))) { m_last_error = "unsupport protocol version"; return false; } - m_protocol_version = utils::view_cast(word); + m_protocol_version = utils::view_cast(word); } else if (__word_count == 2) { static const std::unordered_map numbers = { @@ -90,7 +90,9 @@ namespace asst m_last_error = "connot decode header `" + std::string(status_line) + "`"; return false; } - m_headers[status_line.substr(0, colon_pos)] = + m_headers[utils::view_cast(status_line.substr(0, colon_pos) | views::transform([](char c) { + return static_cast(std::tolower(c)); + }))] = status_line.substr(colon_pos + 1 + status_line.substr(colon_pos + 1).find_first_not_of(' ')); return true; } @@ -131,7 +133,9 @@ namespace asst std::string_view protocol_version() const { return m_protocol_version; } std::string_view status_code_info() const { return m_status_code_info; } std::string_view data() const { return m_data; } - const std::unordered_map headers() const { return m_headers; } + std::string_view at_header(const std::string& key) const { return m_headers.at(key); } + bool contains_header(const std::string& key) const { return m_headers.contains(key); } + const std::unordered_map headers() const { return m_headers; } bool success() const { return m_status_code == 200; } bool code_2xx() const { return m_status_code >= 200 && m_status_code < 300; } From 897daeedaee77fc1071d566d3d66a0475988e33f Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Wed, 31 Aug 2022 19:53:18 +0800 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20[wip]=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=8A=E6=8A=A5=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/ReportDataTask.cpp | 70 ++++++++++++++++------------- src/MeoAssistant/ReportDataTask.h | 3 +- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 5da701b7c7..831646af57 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -73,25 +73,14 @@ void asst::ReportDataTask::report_to_penguin() m_extra_param += " -H \"X-Penguin-Idempotency-Key: " + std::move(key) + "\""; - for (int i = 0; i != m_retry_times; ++i) { - const auto& response = - escape_and_request("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); + ReportDataTask::Response response = + report_and_retry("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format, m_retry_times); - if (response.success()) [[likely]] { - if (response.contains_header("x-penguin-set-penguinid")) { - json::value id_info = basic_info_with_what("PenguinId"); - std::string penguin_id(response.at_header("x-penguin-set-penguinid")); - id_info["details"]["id"] = penguin_id; - callback(AsstMsg::SubTaskExtraInfo, id_info); - } - break; - } - else if (!response.code_5xx()) [[unlikely]] { - json::value cb_info = basic_info(); - cb_info["why"] = std::string(response.status_code_info()); - cb_info["details"]["status_code"] = response.status_code(); - callback(AsstMsg::SubTaskError, cb_info); - } + if (response.success() && response.contains_header("x-penguin-set-penguinid")) [[unlikely]] { + json::value id_info = basic_info_with_what("PenguinId"); + std::string penguin_id(response.at_header("x-penguin-set-penguinid")); + id_info["details"]["id"] = penguin_id; + callback(AsstMsg::SubTaskExtraInfo, id_info); } } @@ -99,11 +88,11 @@ void asst::ReportDataTask::report_to_yituliu() { LogTraceFunction; - escape_and_request("ReportToYituliu", Resrc.cfg().get_options().yituliu_report.cmd_format); + report_and_retry("ReportToYituliu", Resrc.cfg().get_options().yituliu_report.cmd_format); } -asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const std::string& subtask, - const std::string& format) +asst::ReportDataTask::Response asst::ReportDataTask::report_and_retry(const std::string& subtask, + const std::string& format, int report_retry_times) { LogTraceFunction; @@ -111,6 +100,33 @@ asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const st cb_info["subtask"] = subtask; callback(AsstMsg::SubTaskStart, cb_info); + ReportDataTask::Response response; + for (int i = 0; i != report_retry_times; ++i) { + response = escape_and_request(format); + + if (response.success()) { + callback(AsstMsg::SubTaskCompleted, cb_info); + return response; + } + else if (response.status_code() && !response.code_5xx()) { // 非 5xx 错误不必继续重试 + cb_info["why"] = "上报失败"; + cb_info["details"]["why"] = std::string(response.status_code_info()); + cb_info["details"]["status_code"] = response.status_code(); + cb_info["details"]["response"] = static_cast(response); + callback(AsstMsg::SubTaskError, cb_info); + return response; + } + } + + cb_info["why"] = "重试次数达到上限,上报失败"; + callback(AsstMsg::SubTaskError, cb_info); + return response; +} + +asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const std::string& format) +{ + LogTraceFunction; + std::string body_escape = utils::string_replace_all_batch(m_body, { { "\"", "\\\"" } }); #ifdef _WIN32 @@ -122,19 +138,9 @@ asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const st std::string cmd_line = utils::string_replace_all_batch(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); - Log.info("request:\n", cmd_line); Response response = utils::callcmd(cmd_line); + Log.info("request:\n", cmd_line); Log.info("response:\n", response); - cb_info["details"]["response"] = static_cast(response); - - if (response.status_code()) [[likely]] { - callback(AsstMsg::SubTaskCompleted, cb_info); - } - else { // 连状态码都没有,一般是网络错误 - cb_info["why"] = "上报失败"; - callback(AsstMsg::SubTaskError, cb_info); - } - return response; } diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index 231e53525a..ca663d0a1d 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -149,7 +149,8 @@ namespace asst void report_to_penguin(); void report_to_yituliu(); - Response escape_and_request(const std::string& subtask, const std::string& format); + Response escape_and_request(const std::string& format); + Response report_and_retry(const std::string& subtask, const std::string& format, int report_retry_times = 1); ReportType m_report_type = ReportType::Invaild; std::string m_body; From 1e53e390640bbbf014ac36efac95f819fa024ca1 Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Wed, 31 Aug 2022 20:32:06 +0800 Subject: [PATCH 06/11] =?UTF-8?q?feat,=20style:=20=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9B=E5=A2=9E=E5=8A=A0=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=87=8D=E8=AF=95=E7=9A=84=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/ReportDataTask.cpp | 43 +++++++++++++++++++------ src/MeoAssistant/ReportDataTask.h | 49 ++++++++++++++++------------- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 831646af57..e5ab53106d 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -96,30 +96,53 @@ asst::ReportDataTask::Response asst::ReportDataTask::report_and_retry(const std: { LogTraceFunction; - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; - callback(AsstMsg::SubTaskStart, cb_info); + { + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; + callback(AsstMsg::SubTaskStart, cb_info); + } ReportDataTask::Response response; for (int i = 0; i != report_retry_times; ++i) { response = escape_and_request(format); if (response.success()) { + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; callback(AsstMsg::SubTaskCompleted, cb_info); return response; } - else if (response.status_code() && !response.code_5xx()) { // 非 5xx 错误不必继续重试 + else if (response.status_code()) { + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; cb_info["why"] = "上报失败"; cb_info["details"]["why"] = std::string(response.status_code_info()); cb_info["details"]["status_code"] = response.status_code(); - cb_info["details"]["response"] = static_cast(response); - callback(AsstMsg::SubTaskError, cb_info); - return response; + cb_info["details"]["response_data"] = std::string(response.data()); + + if (!response.status_5xx()) { // 非 5xx 错误不必继续重试 + callback(AsstMsg::SubTaskError, cb_info); + return response; + } + else { + callback(AsstMsg::SubTaskExtraInfo, cb_info); + } + } + else { + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; + cb_info["why"] = "上报失败"; + cb_info["details"]["why"] = response.get_last_error(); + callback(AsstMsg::SubTaskExtraInfo, cb_info); } } - cb_info["why"] = "重试次数达到上限,上报失败"; - callback(AsstMsg::SubTaskError, cb_info); + { + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; + cb_info["why"] = "重试次数达到上限,上报失败"; + callback(AsstMsg::SubTaskError, cb_info); + } return response; } @@ -138,8 +161,8 @@ asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const st std::string cmd_line = utils::string_replace_all_batch(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); - Response response = utils::callcmd(cmd_line); Log.info("request:\n", cmd_line); + Response response = utils::callcmd(cmd_line); Log.info("response:\n", response); return response; diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index ca663d0a1d..f03cd4c93e 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -39,13 +39,13 @@ namespace asst std::unordered_map m_headers; bool _analyze_status_line(std::string_view status_line) { - size_t __word_count = 0; + size_t _word_count = 0; for (const std::string_view& word : - std::views::split(status_line, ' ') | std::views::transform([](auto str_range) { + views::split(status_line, ' ') | views::transform([](auto str_range) { return utils::view_cast(str_range); })) { - ++__word_count; - if (__word_count == 1) { + ++_word_count; + if (_word_count == 1) { static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; if (!accepted_protocol_version.contains(utils::view_cast(word))) { m_last_error = "unsupport protocol version"; @@ -53,7 +53,7 @@ namespace asst } m_protocol_version = utils::view_cast(word); } - else if (__word_count == 2) { + else if (_word_count == 2) { static const std::unordered_map numbers = { { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, { '5', 5 }, { '6', 6 }, { '7', 7 }, { '8', 8 }, { '9', 9 }, @@ -76,7 +76,7 @@ namespace asst return true; } } - if (__word_count == 2) { + if (_word_count == 2) { m_status_code_info = ""; return true; } @@ -85,15 +85,15 @@ namespace asst } bool _analyze_headers_line(std::string_view status_line) { - size_t colon_pos = status_line.find(':'); - if (colon_pos == status_line.npos) { + size_t _colon_pos = status_line.find(':'); + if (_colon_pos == status_line.npos) { m_last_error = "connot decode header `" + std::string(status_line) + "`"; return false; } - m_headers[utils::view_cast(status_line.substr(0, colon_pos) | views::transform([](char c) { - return static_cast(std::tolower(c)); - }))] = - status_line.substr(colon_pos + 1 + status_line.substr(colon_pos + 1).find_first_not_of(' ')); + m_headers[utils::view_cast( + status_line.substr(0, _colon_pos) | + views::transform([](char c) { return static_cast(std::tolower(c)); }))] = + status_line.substr(_colon_pos + 1 + status_line.substr(_colon_pos + 1).find_first_not_of(' ')); return true; } @@ -102,26 +102,30 @@ namespace asst requires std::is_constructible_v Response(Args&&... args) : std::string(std::forward(args)...) { - bool __is_status_line = true; - for (const auto& line : std::views::split(*this, '\n')) { + bool _is_status_line = true; + // 这里的 \r\n 处理很奇怪,因为 views::split 好像不支持 string,只能 char + for (const auto& line : views::split(*this, '\n')) { std::string_view line_view; if (utils::view_cast(line).ends_with('\r')) { - line_view = utils::view_cast(line | std::views::take(line.size() - 1)); + line_view = utils::view_cast(line | views::take(line.size() - 1)); } else { line_view = utils::view_cast(line); } - if (__is_status_line) { + // status + if (_is_status_line) { if (!_analyze_status_line(line_view)) { return; } - __is_status_line = false; + _is_status_line = false; } + // headers else if (!line_view.empty()) { if (!_analyze_headers_line(line_view)) { return; } } + // data else { m_data = std::string_view(line.begin(), this->end()); return; @@ -136,12 +140,13 @@ namespace asst std::string_view at_header(const std::string& key) const { return m_headers.at(key); } bool contains_header(const std::string& key) const { return m_headers.contains(key); } const std::unordered_map headers() const { return m_headers; } + const std::string& get_last_error() const noexcept { return m_last_error; } bool success() const { return m_status_code == 200; } - bool code_2xx() const { return m_status_code >= 200 && m_status_code < 300; } - bool code_3xx() const { return m_status_code >= 300 && m_status_code < 400; } - bool code_4xx() const { return m_status_code >= 400 && m_status_code < 500; } - bool code_5xx() const { return m_status_code >= 500 && m_status_code < 600; } + bool status_2xx() const { return m_status_code >= 200 && m_status_code < 300; } + bool status_3xx() const { return m_status_code >= 300 && m_status_code < 400; } + bool status_4xx() const { return m_status_code >= 400 && m_status_code < 500; } + bool status_5xx() const { return m_status_code >= 500 && m_status_code < 600; } }; protected: @@ -155,6 +160,6 @@ namespace asst ReportType m_report_type = ReportType::Invaild; std::string m_body; std::string m_extra_param; - std::vector> m_upload_pending; + static inline std::vector> m_upload_pending; }; } // namespace asst From a822f5f4a94fa986217e1cc2ed40c6dac2464ff0 Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Wed, 31 Aug 2022 20:48:14 +0800 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20=E5=8A=A0=E5=85=A5=20lambda=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=9D=A5=E8=87=AA=E5=AE=9A=E4=B9=89=E9=87=8D?= =?UTF-8?q?=E8=AF=95=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/ReportDataTask.cpp | 22 ++++++++++------------ src/MeoAssistant/ReportDataTask.h | 6 +++++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index e5ab53106d..4783722211 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -92,7 +92,8 @@ void asst::ReportDataTask::report_to_yituliu() } asst::ReportDataTask::Response asst::ReportDataTask::report_and_retry(const std::string& subtask, - const std::string& format, int report_retry_times) + const std::string& format, int report_retry_times, + std::function retry_condition) { LogTraceFunction; @@ -102,35 +103,32 @@ asst::ReportDataTask::Response asst::ReportDataTask::report_and_retry(const std: callback(AsstMsg::SubTaskStart, cb_info); } - ReportDataTask::Response response; + Response response; for (int i = 0; i != report_retry_times; ++i) { + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; + response = escape_and_request(format); if (response.success()) { - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; callback(AsstMsg::SubTaskCompleted, cb_info); return response; } else if (response.status_code()) { - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; cb_info["why"] = "上报失败"; cb_info["details"]["why"] = std::string(response.status_code_info()); cb_info["details"]["status_code"] = response.status_code(); cb_info["details"]["response_data"] = std::string(response.data()); - if (!response.status_5xx()) { // 非 5xx 错误不必继续重试 + if (retry_condition(response)) { + callback(AsstMsg::SubTaskExtraInfo, cb_info); + } + else { callback(AsstMsg::SubTaskError, cb_info); return response; } - else { - callback(AsstMsg::SubTaskExtraInfo, cb_info); - } } else { - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; cb_info["why"] = "上报失败"; cb_info["details"]["why"] = response.get_last_error(); callback(AsstMsg::SubTaskExtraInfo, cb_info); diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index f03cd4c93e..ba31866da7 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -155,7 +155,11 @@ namespace asst void report_to_penguin(); void report_to_yituliu(); Response escape_and_request(const std::string& format); - Response report_and_retry(const std::string& subtask, const std::string& format, int report_retry_times = 1); + Response report_and_retry( + const std::string& subtask, const std::string& format, int report_retry_times = 1, + std::function retry_condition = [](const Response& response) { + return response.status_5xx(); + }); ReportType m_report_type = ReportType::Invaild; std::string m_body; From 23fc21c15de7f16cc1b0d515d42b17284351064e Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Wed, 31 Aug 2022 21:02:20 +0800 Subject: [PATCH 08/11] feat: AsstHttp! --- src/MeoAssistant/AsstHttp.hpp | 131 ++++++++++++++++++ src/MeoAssistant/MeoAssistant.vcxproj | 1 + src/MeoAssistant/MeoAssistant.vcxproj.filters | 3 + src/MeoAssistant/ReportDataTask.cpp | 10 +- src/MeoAssistant/ReportDataTask.h | 123 +--------------- 5 files changed, 141 insertions(+), 127 deletions(-) create mode 100644 src/MeoAssistant/AsstHttp.hpp diff --git a/src/MeoAssistant/AsstHttp.hpp b/src/MeoAssistant/AsstHttp.hpp new file mode 100644 index 0000000000..96059c3e43 --- /dev/null +++ b/src/MeoAssistant/AsstHttp.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include "AsstUtils.hpp" + +#include +#include +#include +#include + +namespace asst +{ + class Response : public std::string + { + private: + std::string m_last_error; + size_t m_status_code = 0; + std::string_view m_protocol_version; + std::string_view m_status_code_info; + std::string_view m_data; + std::unordered_map m_headers; + bool _analyze_status_line(std::string_view status_line) + { + size_t _word_count = 0; + for (const std::string_view& word : views::split(status_line, ' ') | views::transform([](auto str_range) { + return utils::view_cast(str_range); + })) { + ++_word_count; + if (_word_count == 1) { + static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; + if (!accepted_protocol_version.contains(utils::view_cast(word))) { + m_last_error = "unsupport protocol version"; + return false; + } + m_protocol_version = utils::view_cast(word); + } + else if (_word_count == 2) { + static const std::unordered_map numbers = { + { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, + { '5', 5 }, { '6', 6 }, { '7', 7 }, { '8', 8 }, { '9', 9 }, + }; + if (word.length() != 3) { + m_last_error = "status code length is not 3"; + return false; + } + m_status_code = 0; + for (char num : word) { + if (!numbers.contains(num)) { + m_last_error = "status code is not number"; + return false; + } + m_status_code = m_status_code * 10 + numbers.at(num); + } + } + else { + m_status_code_info = std::string_view(word.begin(), status_line.end()); + return true; + } + } + if (_word_count == 2) { + m_status_code_info = ""; + return true; + } + m_last_error = "status line too short"; + return false; + } + bool _analyze_headers_line(std::string_view status_line) + { + size_t _colon_pos = status_line.find(':'); + if (_colon_pos == status_line.npos) { + m_last_error = "connot decode header `" + std::string(status_line) + "`"; + return false; + } + m_headers[utils::view_cast(status_line.substr(0, _colon_pos) | views::transform([](char c) { + return static_cast(std::tolower(c)); + }))] = + status_line.substr(_colon_pos + 1 + status_line.substr(_colon_pos + 1).find_first_not_of(' ')); + return true; + } + + public: + template + requires std::is_constructible_v + Response(Args&&... args) : std::string(std::forward(args)...) + { + bool _is_status_line = true; + // 这里的 \r\n 处理很奇怪,因为 views::split 好像不支持 string,只能 char + for (const auto& line : views::split(*this, '\n')) { + std::string_view line_view; + if (utils::view_cast(line).ends_with('\r')) { + line_view = utils::view_cast(line | views::take(line.size() - 1)); + } + else { + line_view = utils::view_cast(line); + } + // status + if (_is_status_line) { + if (!_analyze_status_line(line_view)) { + return; + } + _is_status_line = false; + } + // headers + else if (!line_view.empty()) { + if (!_analyze_headers_line(line_view)) { + return; + } + } + // data + else { + m_data = std::string_view(line.begin(), this->end()); + return; + } + } + } + + size_t status_code() const { return m_status_code; } + std::string_view protocol_version() const { return m_protocol_version; } + std::string_view status_code_info() const { return m_status_code_info; } + std::string_view data() const { return m_data; } + std::string_view at_header(const std::string& key) const { return m_headers.at(key); } + bool contains_header(const std::string& key) const { return m_headers.contains(key); } + const std::unordered_map headers() const { return m_headers; } + const std::string& get_last_error() const noexcept { return m_last_error; } + + bool success() const { return m_status_code == 200; } + bool status_2xx() const { return m_status_code >= 200 && m_status_code < 300; } + bool status_3xx() const { return m_status_code >= 300 && m_status_code < 400; } + bool status_4xx() const { return m_status_code >= 400 && m_status_code < 500; } + bool status_5xx() const { return m_status_code >= 500 && m_status_code < 600; } + }; +} // namespace asst diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 00f8f9367b..a1ef17228f 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -19,6 +19,7 @@ + diff --git a/src/MeoAssistant/MeoAssistant.vcxproj.filters b/src/MeoAssistant/MeoAssistant.vcxproj.filters index cf6e047830..b674f502a9 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj.filters +++ b/src/MeoAssistant/MeoAssistant.vcxproj.filters @@ -387,6 +387,9 @@ 头文件\Task\Sub + + 头文件\Utils + diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 4783722211..1aadfcb4f7 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -73,7 +73,7 @@ void asst::ReportDataTask::report_to_penguin() m_extra_param += " -H \"X-Penguin-Idempotency-Key: " + std::move(key) + "\""; - ReportDataTask::Response response = + Response response = report_and_retry("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format, m_retry_times); if (response.success() && response.contains_header("x-penguin-set-penguinid")) [[unlikely]] { @@ -91,9 +91,9 @@ void asst::ReportDataTask::report_to_yituliu() report_and_retry("ReportToYituliu", Resrc.cfg().get_options().yituliu_report.cmd_format); } -asst::ReportDataTask::Response asst::ReportDataTask::report_and_retry(const std::string& subtask, - const std::string& format, int report_retry_times, - std::function retry_condition) +asst::Response asst::ReportDataTask::report_and_retry(const std::string& subtask, const std::string& format, + int report_retry_times, + std::function retry_condition) { LogTraceFunction; @@ -144,7 +144,7 @@ asst::ReportDataTask::Response asst::ReportDataTask::report_and_retry(const std: return response; } -asst::ReportDataTask::Response asst::ReportDataTask::escape_and_request(const std::string& format) +asst::Response asst::ReportDataTask::escape_and_request(const std::string& format) { LogTraceFunction; diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index ba31866da7..330f45bea6 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -1,6 +1,7 @@ #pragma once #include "AbstractTask.h" +#include "AsstHttp.hpp" #include "AsstUtils.hpp" #include @@ -27,128 +28,6 @@ namespace asst ReportDataTask& set_body(std::string body); ReportDataTask& set_extra_param(std::string extra_param); - protected: - class Response : public std::string - { - private: - std::string m_last_error; - size_t m_status_code = 0; - std::string_view m_protocol_version; - std::string_view m_status_code_info; - std::string_view m_data; - std::unordered_map m_headers; - bool _analyze_status_line(std::string_view status_line) - { - size_t _word_count = 0; - for (const std::string_view& word : - views::split(status_line, ' ') | views::transform([](auto str_range) { - return utils::view_cast(str_range); - })) { - ++_word_count; - if (_word_count == 1) { - static const std::unordered_set accepted_protocol_version = { "HTTP/1.1" }; - if (!accepted_protocol_version.contains(utils::view_cast(word))) { - m_last_error = "unsupport protocol version"; - return false; - } - m_protocol_version = utils::view_cast(word); - } - else if (_word_count == 2) { - static const std::unordered_map numbers = { - { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, - { '5', 5 }, { '6', 6 }, { '7', 7 }, { '8', 8 }, { '9', 9 }, - }; - if (word.length() != 3) { - m_last_error = "status code length is not 3"; - return false; - } - m_status_code = 0; - for (char num : word) { - if (!numbers.contains(num)) { - m_last_error = "status code is not number"; - return false; - } - m_status_code = m_status_code * 10 + numbers.at(num); - } - } - else { - m_status_code_info = std::string_view(word.begin(), status_line.end()); - return true; - } - } - if (_word_count == 2) { - m_status_code_info = ""; - return true; - } - m_last_error = "status line too short"; - return false; - } - bool _analyze_headers_line(std::string_view status_line) - { - size_t _colon_pos = status_line.find(':'); - if (_colon_pos == status_line.npos) { - m_last_error = "connot decode header `" + std::string(status_line) + "`"; - return false; - } - m_headers[utils::view_cast( - status_line.substr(0, _colon_pos) | - views::transform([](char c) { return static_cast(std::tolower(c)); }))] = - status_line.substr(_colon_pos + 1 + status_line.substr(_colon_pos + 1).find_first_not_of(' ')); - return true; - } - - public: - template - requires std::is_constructible_v - Response(Args&&... args) : std::string(std::forward(args)...) - { - bool _is_status_line = true; - // 这里的 \r\n 处理很奇怪,因为 views::split 好像不支持 string,只能 char - for (const auto& line : views::split(*this, '\n')) { - std::string_view line_view; - if (utils::view_cast(line).ends_with('\r')) { - line_view = utils::view_cast(line | views::take(line.size() - 1)); - } - else { - line_view = utils::view_cast(line); - } - // status - if (_is_status_line) { - if (!_analyze_status_line(line_view)) { - return; - } - _is_status_line = false; - } - // headers - else if (!line_view.empty()) { - if (!_analyze_headers_line(line_view)) { - return; - } - } - // data - else { - m_data = std::string_view(line.begin(), this->end()); - return; - } - } - } - - size_t status_code() const { return m_status_code; } - std::string_view protocol_version() const { return m_protocol_version; } - std::string_view status_code_info() const { return m_status_code_info; } - std::string_view data() const { return m_data; } - std::string_view at_header(const std::string& key) const { return m_headers.at(key); } - bool contains_header(const std::string& key) const { return m_headers.contains(key); } - const std::unordered_map headers() const { return m_headers; } - const std::string& get_last_error() const noexcept { return m_last_error; } - - bool success() const { return m_status_code == 200; } - bool status_2xx() const { return m_status_code >= 200 && m_status_code < 300; } - bool status_3xx() const { return m_status_code >= 300 && m_status_code < 400; } - bool status_4xx() const { return m_status_code >= 400 && m_status_code < 500; } - bool status_5xx() const { return m_status_code >= 500 && m_status_code < 600; } - }; - protected: virtual bool _run() override; From fcb77ccedb76e5613fb0673133893699e9c86991 Mon Sep 17 00:00:00 2001 From: MistEO Date: Wed, 31 Aug 2022 22:20:16 +0800 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=E6=95=B4=E7=90=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=8A=E6=8A=A5=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/AsstHttp.hpp | 8 ++-- src/MeoAssistant/ReportDataTask.cpp | 68 ++++++++++------------------- src/MeoAssistant/ReportDataTask.h | 15 ++++--- 3 files changed, 36 insertions(+), 55 deletions(-) diff --git a/src/MeoAssistant/AsstHttp.hpp b/src/MeoAssistant/AsstHttp.hpp index 96059c3e43..f006eadb53 100644 --- a/src/MeoAssistant/AsstHttp.hpp +++ b/src/MeoAssistant/AsstHttp.hpp @@ -7,7 +7,7 @@ #include #include -namespace asst +namespace asst::http { class Response : public std::string { @@ -79,8 +79,8 @@ namespace asst public: template - requires std::is_constructible_v - Response(Args&&... args) : std::string(std::forward(args)...) + requires std::is_constructible_v Response(Args&&... args) + : std::string(std::forward(args)...) { bool _is_status_line = true; // 这里的 \r\n 处理很奇怪,因为 views::split 好像不支持 string,只能 char @@ -128,4 +128,4 @@ namespace asst bool status_4xx() const { return m_status_code >= 400 && m_status_code < 500; } bool status_5xx() const { return m_status_code >= 500 && m_status_code < 600; } }; -} // namespace asst +} // namespace asst::http diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 1aadfcb4f7..1d5b39027d 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -11,6 +11,8 @@ #include #include +std::vector> asst::ReportDataTask::m_upload_pending; + asst::ReportDataTask& asst::ReportDataTask::set_report_type(ReportType type) { m_report_type = type; @@ -73,8 +75,7 @@ void asst::ReportDataTask::report_to_penguin() m_extra_param += " -H \"X-Penguin-Idempotency-Key: " + std::move(key) + "\""; - Response response = - report_and_retry("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format, m_retry_times); + http::Response response = report("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); if (response.success() && response.contains_header("x-penguin-set-penguinid")) [[unlikely]] { json::value id_info = basic_info_with_what("PenguinId"); @@ -88,63 +89,42 @@ void asst::ReportDataTask::report_to_yituliu() { LogTraceFunction; - report_and_retry("ReportToYituliu", Resrc.cfg().get_options().yituliu_report.cmd_format); + report("ReportToYituliu", Resrc.cfg().get_options().yituliu_report.cmd_format); } -asst::Response asst::ReportDataTask::report_and_retry(const std::string& subtask, const std::string& format, - int report_retry_times, - std::function retry_condition) +asst::http::Response asst::ReportDataTask::report(const std::string& subtask, const std::string& format, + HttpResponsePred success_cond, HttpResponsePred retry_cond) { LogTraceFunction; - { - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; - callback(AsstMsg::SubTaskStart, cb_info); - } - - Response response; - for (int i = 0; i != report_retry_times; ++i) { - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; + json::value cb_info = basic_info(); + cb_info["subtask"] = subtask; + callback(AsstMsg::SubTaskStart, cb_info); + http::Response response; + for (int i = 0; i <= m_retry_times; ++i) { response = escape_and_request(format); - - if (response.success()) { + if (success_cond(response)) { callback(AsstMsg::SubTaskCompleted, cb_info); return response; } - else if (response.status_code()) { - cb_info["why"] = "上报失败"; - cb_info["details"]["why"] = std::string(response.status_code_info()); - cb_info["details"]["status_code"] = response.status_code(); - cb_info["details"]["response_data"] = std::string(response.data()); - - if (retry_condition(response)) { - callback(AsstMsg::SubTaskExtraInfo, cb_info); - } - else { - callback(AsstMsg::SubTaskError, cb_info); - return response; - } - } - else { - cb_info["why"] = "上报失败"; - cb_info["details"]["why"] = response.get_last_error(); - callback(AsstMsg::SubTaskExtraInfo, cb_info); + else if (!retry_cond(response)) { + break; } } - { - json::value cb_info = basic_info(); - cb_info["subtask"] = subtask; - cb_info["why"] = "重试次数达到上限,上报失败"; - callback(AsstMsg::SubTaskError, cb_info); - } + cb_info["why"] = "上报失败"; + cb_info["details"] = json::object { { "error", response.get_last_error() }, + { "status_code", response.status_code() }, + { "status_code_info", std::string(response.status_code_info()) }, + { "response", std::string(response.data()) } }; + + callback(AsstMsg::SubTaskError, cb_info); + return response; } -asst::Response asst::ReportDataTask::escape_and_request(const std::string& format) +asst::http::Response asst::ReportDataTask::escape_and_request(const std::string& format) { LogTraceFunction; @@ -160,7 +140,7 @@ asst::Response asst::ReportDataTask::escape_and_request(const std::string& forma utils::string_replace_all_batch(format, { { "[body]", body_escapes }, { "[extra]", m_extra_param } }); Log.info("request:\n", cmd_line); - Response response = utils::callcmd(cmd_line); + http::Response response = utils::callcmd(cmd_line); Log.info("response:\n", response); return response; diff --git a/src/MeoAssistant/ReportDataTask.h b/src/MeoAssistant/ReportDataTask.h index 330f45bea6..1e4867ca76 100644 --- a/src/MeoAssistant/ReportDataTask.h +++ b/src/MeoAssistant/ReportDataTask.h @@ -29,20 +29,21 @@ namespace asst ReportDataTask& set_extra_param(std::string extra_param); protected: + using HttpResponsePred = std::function; + virtual bool _run() override; void report_to_penguin(); void report_to_yituliu(); - Response escape_and_request(const std::string& format); - Response report_and_retry( - const std::string& subtask, const std::string& format, int report_retry_times = 1, - std::function retry_condition = [](const Response& response) { - return response.status_5xx(); - }); + http::Response escape_and_request(const std::string& format); + http::Response report( + const std::string& subtask, const std::string& format, + HttpResponsePred success_cond = [](const http::Response& response) -> bool { return response.success(); }, + HttpResponsePred retry_cond = [](const http::Response& response) -> bool { return response.status_5xx(); }); ReportType m_report_type = ReportType::Invaild; std::string m_body; std::string m_extra_param; - static inline std::vector> m_upload_pending; + static std::vector> m_upload_pending; }; } // namespace asst From c8cf91ef9c8866cb2c7920f71a9faef8f9913761 Mon Sep 17 00:00:00 2001 From: MistEO Date: Wed, 31 Aug 2022 22:34:31 +0800 Subject: [PATCH 10/11] =?UTF-8?q?perf:=20=E5=B1=8E=E4=B8=8A=E9=9B=95?= =?UTF-8?q?=E8=8A=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/AsstHttp.hpp | 32 ++++++++++++++--------------- src/MeoAssistant/ReportDataTask.cpp | 11 +++++----- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/MeoAssistant/AsstHttp.hpp b/src/MeoAssistant/AsstHttp.hpp index f006eadb53..978506d4aa 100644 --- a/src/MeoAssistant/AsstHttp.hpp +++ b/src/MeoAssistant/AsstHttp.hpp @@ -1,5 +1,6 @@ #pragma once +#include "AsstRanges.hpp" #include "AsstUtils.hpp" #include @@ -13,7 +14,7 @@ namespace asst::http { private: std::string m_last_error; - size_t m_status_code = 0; + unsigned m_status_code = 0; std::string_view m_protocol_version; std::string_view m_status_code_info; std::string_view m_data; @@ -34,22 +35,14 @@ namespace asst::http m_protocol_version = utils::view_cast(word); } else if (_word_count == 2) { - static const std::unordered_map numbers = { - { '0', 0 }, { '1', 1 }, { '2', 2 }, { '3', 3 }, { '4', 4 }, - { '5', 5 }, { '6', 6 }, { '7', 7 }, { '8', 8 }, { '9', 9 }, - }; if (word.length() != 3) { m_last_error = "status code length is not 3"; return false; } - m_status_code = 0; - for (char num : word) { - if (!numbers.contains(num)) { - m_last_error = "status code is not number"; - return false; - } - m_status_code = m_status_code * 10 + numbers.at(num); + if (!ranges::all_of(word, [](char c) -> bool { return std::isdigit(c); })) { + return false; } + m_status_code = std::atoi(word.data()); } else { m_status_code_info = std::string_view(word.begin(), status_line.end()); @@ -113,13 +106,20 @@ namespace asst::http } } - size_t status_code() const { return m_status_code; } + unsigned status_code() const { return m_status_code; } std::string_view protocol_version() const { return m_protocol_version; } std::string_view status_code_info() const { return m_status_code_info; } std::string_view data() const { return m_data; } - std::string_view at_header(const std::string& key) const { return m_headers.at(key); } - bool contains_header(const std::string& key) const { return m_headers.contains(key); } - const std::unordered_map headers() const { return m_headers; } + std::optional find_header(const std::string& key) const + { + if (auto iter = m_headers.find(key); iter != m_headers.cend()) { + return iter->second; + } + else { + return std::nullopt; + } + } + const auto& headers() const { return m_headers; } const std::string& get_last_error() const noexcept { return m_last_error; } bool success() const { return m_status_code == 200; } diff --git a/src/MeoAssistant/ReportDataTask.cpp b/src/MeoAssistant/ReportDataTask.cpp index 1d5b39027d..200a3d7197 100644 --- a/src/MeoAssistant/ReportDataTask.cpp +++ b/src/MeoAssistant/ReportDataTask.cpp @@ -77,11 +77,12 @@ void asst::ReportDataTask::report_to_penguin() http::Response response = report("ReportToPenguinStats", Resrc.cfg().get_options().penguin_report.cmd_format); - if (response.success() && response.contains_header("x-penguin-set-penguinid")) [[unlikely]] { - json::value id_info = basic_info_with_what("PenguinId"); - std::string penguin_id(response.at_header("x-penguin-set-penguinid")); - id_info["details"]["id"] = penguin_id; - callback(AsstMsg::SubTaskExtraInfo, id_info); + if (response.success()) [[unlikely]] { + if (auto penguinid_opt = response.find_header("x-penguin-set-penguinid")) { + json::value id_info = basic_info_with_what("PenguinId"); + id_info["details"]["id"] = std::string(penguinid_opt.value()); + callback(AsstMsg::SubTaskExtraInfo, id_info); + } } } From bd66e367467ec1f428477f1d2b9d937e144acea4 Mon Sep 17 00:00:00 2001 From: MistEO Date: Wed, 31 Aug 2022 22:50:00 +0800 Subject: [PATCH 11/11] =?UTF-8?q?chore:=20=E7=BB=99=E4=BC=81=E9=B9=85?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E8=B6=85=E6=97=B6=E5=8A=A0=E9=95=BF=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resource/config.json b/resource/config.json index 8eb97292d0..19eb1d5ac1 100644 --- a/resource/config.json +++ b/resource/config.json @@ -14,7 +14,7 @@ "adbExtraSwipeDuration_Doc": "额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能", "penguinReport": { "Doc": "企鹅物流汇报: https://penguin-stats.cn/", - "cmdFormat": "curl -H \"Content-Type: application/json\" -s -S -m 5 -i -d \"[body]\" \"https://penguin-stats.io/PenguinStats/api/v2/report\" [extra]", + "cmdFormat": "curl -H \"Content-Type: application/json\" -s -S -m 10 -i -d \"[body]\" \"https://penguin-stats.io/PenguinStats/api/v2/report\" [extra]", "cmdFormat_Doc": "命令格式,想打印详细信息可以尝试添加 -v -i" }, "yituliuReport": {