mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-19 02:23:01 +08:00
rft: 增加企鹅物流 .cn 备用域名,迁移上报逻辑到 UI 层 (#13602)
* chore: 企鹅物流上报添加 .cn 域名 * rft: 将企鹅物流的上报交给 ui 处理 * chore: Auto update by pre-commit hooks [skip changelog] * chore: 上报移除 cpr version * docs: 添加对应文档 * chore: Auto update by pre-commit hooks [skip changelog] * chore: 获取新 id * chore: 提取链接 --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -41,23 +41,19 @@ bool asst::ReportDataTask::_run()
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
std::function<void(void)> report_func;
|
||||
|
||||
switch (m_report_type) {
|
||||
case ReportType::PenguinStats:
|
||||
report_func = std::bind(&ReportDataTask::report_to_penguin, this);
|
||||
report_to_penguin();
|
||||
break;
|
||||
case ReportType::YituliuBigDataAutoRecruit:
|
||||
case ReportType::YituliuBigDataStageDrops:
|
||||
report_func = std::bind(&ReportDataTask::report_to_yituliu, this, m_report_type);
|
||||
report_to_yituliu(m_report_type);
|
||||
break;
|
||||
case ReportType::Invalid:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto upload_future = std::async(std::launch::async, report_func);
|
||||
m_upload_pending.emplace_back(std::move(upload_future));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -70,98 +66,47 @@ void asst::ReportDataTask::callback(AsstMsg msg, const json::value& detail)
|
||||
|
||||
void asst::ReportDataTask::report_to_penguin()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
LogTraceFunction;
|
||||
|
||||
using namespace std::chrono;
|
||||
auto epoch = time_point_cast<nanoseconds>(steady_clock::now()).time_since_epoch();
|
||||
long long tick = duration_cast<nanoseconds>(epoch).count();
|
||||
|
||||
static std::default_random_engine rand_engine(std::random_device {}());
|
||||
static std::uniform_int_distribution<uint64_t> 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);
|
||||
|
||||
constexpr int DefaultBackoff = 3 * 1000; // 3s
|
||||
int backoff = DefaultBackoff;
|
||||
|
||||
auto penguin_success_cond = [](const cpr::Response& response) -> bool {
|
||||
return response.status_code == 200;
|
||||
};
|
||||
auto penguin_retry_cond = [&](const cpr::Response& response) -> bool {
|
||||
if (!response.status_code) {
|
||||
return true;
|
||||
}
|
||||
if (response.status_code >= 500 && response.status_code < 600) {
|
||||
backoff = static_cast<int>(backoff * 1.5);
|
||||
sleep(backoff);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
std::string idempotency_key = key_ss.str();
|
||||
|
||||
std::string url = Config.get_options().penguin_report.url;
|
||||
int timeout = Config.get_options().penguin_report.timeout;
|
||||
cpr::Header headers {};
|
||||
|
||||
for (const auto& [header_key, value] : Config.get_options().penguin_report.headers) {
|
||||
headers.emplace(header_key, value);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> headers;
|
||||
for (const auto& field : m_extra_headers) {
|
||||
headers.emplace(field);
|
||||
}
|
||||
headers.emplace("X-Penguin-Idempotency-Key", std::move(idempotency_key));
|
||||
|
||||
headers.emplace("X-Penguin-Idempotency-Key", std::move(key));
|
||||
ReportRequest req { .url = std::move(url),
|
||||
.extra_headers = std::move(headers),
|
||||
.body = m_body,
|
||||
.subtask_name = "ReportToPenguinStats" };
|
||||
|
||||
constexpr std::string_view PenguinSubtaskName = "ReportToPenguinStats";
|
||||
cpr::Response response =
|
||||
report(PenguinSubtaskName, url, headers, timeout, penguin_success_cond, penguin_retry_cond, false);
|
||||
|
||||
auto proc_response_id = [&]() {
|
||||
if (response.header.contains("x-penguin-set-penguinid")) [[unlikely]] {
|
||||
json::value id_info = basic_info_with_what("PenguinId");
|
||||
id_info["details"]["id"] = response.header["x-penguin-set-penguinid"];
|
||||
callback(AsstMsg::SubTaskExtraInfo, id_info);
|
||||
}
|
||||
};
|
||||
|
||||
if (response.status_code == 200) {
|
||||
proc_response_id();
|
||||
return;
|
||||
}
|
||||
|
||||
// 重新向企鹅物流统计的 CN 域名发送数据
|
||||
constexpr std::string_view Penguin_IO = "https://penguin-stats.io";
|
||||
// https://penguin-stats.alvorna.com: G找朋友开的代理,仅可以代理 API 请求。
|
||||
// 实际的网站访问请前往 https://penguin-stats.cn
|
||||
// constexpr std::string_view Penguin_CN = "https://penguin-stats.cn";
|
||||
constexpr std::string_view Penguin_CN_PROXY = "https://penguin-stats.alvorna.com";
|
||||
if (url.find(Penguin_IO) == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
Log.info("Re-report to penguin-stats.alvorna.com", Penguin_CN_PROXY);
|
||||
std::string new_url = utils::string_replace_all(url, Penguin_IO, Penguin_CN_PROXY);
|
||||
|
||||
backoff = DefaultBackoff;
|
||||
response = report(PenguinSubtaskName, new_url, headers, timeout, penguin_success_cond, penguin_retry_cond);
|
||||
|
||||
if (response.status_code == 200) {
|
||||
proc_response_id();
|
||||
return;
|
||||
json::value req_json = json::object { { "url", req.url },
|
||||
{ "headers", json::object {} },
|
||||
{ "body", req.body },
|
||||
{ "subtask", req.subtask_name } };
|
||||
for (auto& [k, v] : req.extra_headers) {
|
||||
req_json["headers"][k] = v;
|
||||
}
|
||||
callback(AsstMsg::ReportRequest, req_json);
|
||||
}
|
||||
|
||||
void asst::ReportDataTask::report_to_yituliu(ReportType reportType)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
constexpr std::string_view yituliu_subtask_name = "ReportToYituliu";
|
||||
std::string url;
|
||||
switch (reportType) {
|
||||
case ReportType::YituliuBigDataAutoRecruit:
|
||||
@@ -170,83 +115,27 @@ void asst::ReportDataTask::report_to_yituliu(ReportType reportType)
|
||||
case ReportType::YituliuBigDataStageDrops:
|
||||
url = Config.get_options().yituliu_report.drop_url;
|
||||
break;
|
||||
case ReportType::Invalid:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
const int timeout = Config.get_options().yituliu_report.timeout;
|
||||
cpr::Header headers = {};
|
||||
|
||||
for (const auto& [header_key, value] : Config.get_options().yituliu_report.headers) {
|
||||
headers.emplace(header_key, value);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> headers;
|
||||
for (const auto& field : m_extra_headers) {
|
||||
headers.emplace(field);
|
||||
}
|
||||
|
||||
report(yituliu_subtask_name, url, headers, timeout);
|
||||
}
|
||||
|
||||
cpr::Response asst::ReportDataTask::report(
|
||||
std::string_view subtask,
|
||||
const std::string& url,
|
||||
const cpr::Header& headers,
|
||||
const int timeout,
|
||||
HttpResponsePred success_cond,
|
||||
HttpResponsePred retry_cond,
|
||||
bool callback_on_failure)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
json::value cb_info = basic_info();
|
||||
cb_info["subtask"] = std::string(subtask);
|
||||
callback(AsstMsg::SubTaskStart, cb_info);
|
||||
|
||||
Log.info("Report url: ", url);
|
||||
for (const auto& [key, value] : headers) {
|
||||
Log.info("Report header: ", key, ":", value);
|
||||
}
|
||||
Log.info("Report body: ", m_body);
|
||||
|
||||
cpr::Response response;
|
||||
for (int i = 0; i <= m_retry_times; ++i) {
|
||||
response = cpr::Post(
|
||||
cpr::Url { url },
|
||||
cpr::Body { m_body },
|
||||
headers,
|
||||
cpr::Timeout { timeout },
|
||||
cpr::HttpVersion { cpr::HttpVersionCode::VERSION_2_0 });
|
||||
Log.info("Report response status code: ", response.status_code);
|
||||
for (const auto& [key, value] : response.header) {
|
||||
Log.info("Report response header: ", key, ":", value);
|
||||
}
|
||||
Log.info("Report response: ", response.text);
|
||||
if (success_cond(response)) {
|
||||
callback(AsstMsg::SubTaskCompleted, cb_info);
|
||||
return response;
|
||||
}
|
||||
else if (!retry_cond(response)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
Log.trace("retrying... | why:", response.error.message, "status_code:", response.status_code);
|
||||
}
|
||||
if (need_exit()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback_on_failure) {
|
||||
cb_info["why"] = "上报失败";
|
||||
cb_info["details"] = json::object {
|
||||
{ "error", response.error.message },
|
||||
{ "status_code", response.status_code },
|
||||
{ "status_code_info", response.reason },
|
||||
{ "response", response.text },
|
||||
};
|
||||
|
||||
callback(AsstMsg::SubTaskError, cb_info);
|
||||
}
|
||||
|
||||
return response;
|
||||
ReportRequest req { .url = std::move(url),
|
||||
.extra_headers = std::move(headers),
|
||||
.body = m_body,
|
||||
.subtask_name = "ReportToYituliu" };
|
||||
|
||||
json::value req_json = json::object { { "url", req.url },
|
||||
{ "headers", json::object {} },
|
||||
{ "body", req.body },
|
||||
{ "subtask", req.subtask_name } };
|
||||
for (auto& [k, v] : req.extra_headers) {
|
||||
req_json["headers"][k] = v;
|
||||
}
|
||||
callback(AsstMsg::ReportRequest, req_json);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user