mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
Merge remote-tracking branch 'origin/pr/435' into aether-rust-pioneer
This commit is contained in:
@@ -209,6 +209,24 @@ pub(super) async fn maybe_build_local_admin_core_system_response(
|
||||
return Ok(Some(Json(json!({ "items": records })).into_response()));
|
||||
}
|
||||
|
||||
if decision.route_kind.as_deref() == Some("cleanup_usage_manual")
|
||||
&& request_method == http::Method::POST
|
||||
&& request_path == "/api/admin/system/cleanup/usage/manual"
|
||||
{
|
||||
return Ok(Some(
|
||||
build_manual_usage_cleanup_response(state, request_body).await?,
|
||||
));
|
||||
}
|
||||
|
||||
if decision.route_kind.as_deref() == Some("cleanup_usage_preview")
|
||||
&& request_method == http::Method::GET
|
||||
&& request_path == "/api/admin/system/cleanup/usage/preview"
|
||||
{
|
||||
return Ok(Some(
|
||||
build_manual_usage_cleanup_preview_response(state, request_context).await?,
|
||||
));
|
||||
}
|
||||
|
||||
if let Some((task_kind, action, object_type, object_id)) =
|
||||
admin_system_purge_task_for_route_kind(decision.route_kind.as_deref())
|
||||
{
|
||||
@@ -555,3 +573,171 @@ async fn build_admin_system_cleanup_payload(
|
||||
"cleaned": cleaned,
|
||||
}))
|
||||
}
|
||||
|
||||
async fn build_manual_usage_cleanup_response(
|
||||
state: &AdminAppState<'_>,
|
||||
request_body: Option<&Bytes>,
|
||||
) -> Result<Response<Body>, GatewayError> {
|
||||
let older_than_days = match parse_manual_usage_cleanup_request(request_body) {
|
||||
Ok(value) => value,
|
||||
Err(response) => return Ok(response),
|
||||
};
|
||||
|
||||
match crate::maintenance::run_manual_usage_cleanup_once(
|
||||
&state.app().data,
|
||||
older_than_days,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(summary) => {
|
||||
let total = summary
|
||||
.body_externalized
|
||||
.saturating_add(summary.legacy_body_refs_migrated)
|
||||
.saturating_add(summary.body_cleaned)
|
||||
.saturating_add(summary.header_cleaned)
|
||||
.saturating_add(summary.keys_cleaned)
|
||||
.saturating_add(summary.records_deleted);
|
||||
let message = match older_than_days {
|
||||
Some(days) => {
|
||||
format!("请求记录手动清理完成,清理 {days} 天前的记录,影响 {total} 项")
|
||||
}
|
||||
None => format!("请求记录手动清理完成(按当前策略),影响 {total} 项"),
|
||||
};
|
||||
let payload = json!({
|
||||
"message": message,
|
||||
"requested_older_than_days": older_than_days,
|
||||
"summary": {
|
||||
"body_externalized": summary.body_externalized,
|
||||
"legacy_body_refs_migrated": summary.legacy_body_refs_migrated,
|
||||
"body_cleaned": summary.body_cleaned,
|
||||
"header_cleaned": summary.header_cleaned,
|
||||
"keys_cleaned": summary.keys_cleaned,
|
||||
"records_deleted": summary.records_deleted,
|
||||
},
|
||||
"total_affected": total,
|
||||
});
|
||||
Ok(attach_admin_audit_response(
|
||||
Json(payload).into_response(),
|
||||
"admin_system_usage_cleanup_completed",
|
||||
"manual_usage_cleanup",
|
||||
"usage_cleanup",
|
||||
"global",
|
||||
))
|
||||
}
|
||||
Err(crate::maintenance::ManualUsageCleanupError::AlreadyRunning) => Ok((
|
||||
http::StatusCode::CONFLICT,
|
||||
Json(json!({
|
||||
"detail": "usage_cleanup_already_running",
|
||||
"message": "已有一次清理正在进行中,请稍后再试",
|
||||
})),
|
||||
)
|
||||
.into_response()),
|
||||
Err(crate::maintenance::ManualUsageCleanupError::DataLayer(err)) => {
|
||||
Err(GatewayError::Internal(err.to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_manual_usage_cleanup_preview_response(
|
||||
state: &AdminAppState<'_>,
|
||||
request_context: &AdminRequestContext<'_>,
|
||||
) -> Result<Response<Body>, GatewayError> {
|
||||
let older_than_days = match parse_older_than_days_query(request_context.query_string()) {
|
||||
Ok(value) => value,
|
||||
Err(response) => return Ok(response),
|
||||
};
|
||||
let preview =
|
||||
crate::maintenance::preview_manual_usage_cleanup(&state.app().data, older_than_days)
|
||||
.await
|
||||
.map_err(|err| GatewayError::Internal(err.to_string()))?;
|
||||
Ok(Json(json!({
|
||||
"requested_older_than_days": preview.requested_older_than_days,
|
||||
"effective_cutoffs": {
|
||||
"detail": preview.detail_cutoff,
|
||||
"compressed": preview.compressed_cutoff,
|
||||
"header": preview.header_cutoff,
|
||||
"log": preview.log_cutoff,
|
||||
},
|
||||
"counts": {
|
||||
"detail": preview.detail_count,
|
||||
"compressed": preview.compressed_count,
|
||||
"header": preview.header_count,
|
||||
"log": preview.log_count,
|
||||
},
|
||||
}))
|
||||
.into_response())
|
||||
}
|
||||
|
||||
fn parse_manual_usage_cleanup_request(
|
||||
request_body: Option<&Bytes>,
|
||||
) -> Result<Option<u32>, Response<Body>> {
|
||||
let Some(body) = request_body else {
|
||||
return Ok(None);
|
||||
};
|
||||
if body.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
let parsed: serde_json::Value = match serde_json::from_slice(body) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
return Err((
|
||||
http::StatusCode::BAD_REQUEST,
|
||||
Json(json!({ "detail": format!("请求体无效 JSON: {err}") })),
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
};
|
||||
let Some(object) = parsed.as_object() else {
|
||||
return Ok(None);
|
||||
};
|
||||
match object.get("older_than_days") {
|
||||
None | Some(serde_json::Value::Null) => Ok(None),
|
||||
Some(value) => value
|
||||
.as_u64()
|
||||
.and_then(|value| u32::try_from(value).ok())
|
||||
.filter(|days| *days >= 1)
|
||||
.map(Some)
|
||||
.ok_or_else(|| {
|
||||
(
|
||||
http::StatusCode::BAD_REQUEST,
|
||||
Json(json!({
|
||||
"detail": "older_than_days 必须为正整数",
|
||||
})),
|
||||
)
|
||||
.into_response()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_older_than_days_query(query_string: Option<&str>) -> Result<Option<u32>, Response<Body>> {
|
||||
let Some(query) = query_string.filter(|value| !value.is_empty()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
let value = query
|
||||
.split('&')
|
||||
.filter_map(|pair| pair.split_once('='))
|
||||
.find_map(|(key, value)| {
|
||||
if key == "older_than_days" && !value.is_empty() {
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let Some(raw) = value else {
|
||||
return Ok(None);
|
||||
};
|
||||
raw.parse::<u32>()
|
||||
.ok()
|
||||
.filter(|days| *days >= 1)
|
||||
.map(Some)
|
||||
.ok_or_else(|| {
|
||||
(
|
||||
http::StatusCode::BAD_REQUEST,
|
||||
Json(json!({
|
||||
"detail": "older_than_days 必须为正整数",
|
||||
})),
|
||||
)
|
||||
.into_response()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user