发行包上传抽 server_error_detail,统一 message/code/兜底顺序
- game_package_upload.rs 新增 pub(crate) server_error_detail,统一先取非空 message 再退非空 code 的顺序 - runtime.rs 五处 HTTP 错误分支改用该 helper,删除各自复制的过滤逻辑 - game_distribution_publish.rs 的 response_data 与 map_http_error 共用同一 helper - FORBIDDEN 分支改用 helper,补上此前缺失的空 message trim 过滤
This commit is contained in:
@@ -5,8 +5,9 @@
|
||||
//! 其它素材上传链路。
|
||||
|
||||
use crate::game_package_upload::{
|
||||
game_package_upload_staging_dir, stage_game_package_bytes, upload_staged_game_package,
|
||||
GamePackageUploadOutcome, GamePackageUploadRequest, StagedGamePackage,
|
||||
game_package_upload_staging_dir, server_error_detail, stage_game_package_bytes,
|
||||
upload_staged_game_package, GamePackageUploadOutcome, GamePackageUploadRequest,
|
||||
StagedGamePackage,
|
||||
};
|
||||
use crate::http_client::agc_main_site_client_builder;
|
||||
use crate::platform_session::{
|
||||
@@ -194,10 +195,9 @@ fn response_data(body: &str) -> Result<Value, String> {
|
||||
serde_json::from_str(body).map_err(|error| format!("服务端响应不是合法 JSON:{error}"))?;
|
||||
if value.get("ok").and_then(Value::as_bool) == Some(false) {
|
||||
let (code, message) = parse_error_payload(body);
|
||||
return Err(message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(|| "服务器未返回错误信息".to_string()));
|
||||
return Err(server_error_detail(code, message, || {
|
||||
"服务器未返回错误信息".to_string()
|
||||
}));
|
||||
}
|
||||
Ok(value.get("data").cloned().unwrap_or(value))
|
||||
}
|
||||
@@ -211,13 +211,10 @@ fn map_http_error(status: StatusCode, body: &str, fallback: &str) -> String {
|
||||
if status == StatusCode::FORBIDDEN {
|
||||
return format!(
|
||||
"permission-denied: {}",
|
||||
message.unwrap_or_else(|| "当前账号无权执行此操作".to_string())
|
||||
server_error_detail(code, message, || "当前账号无权执行此操作".to_string())
|
||||
);
|
||||
}
|
||||
let detail = message
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.or_else(|| code.filter(|value| !value.trim().is_empty()))
|
||||
.unwrap_or_else(|| format!("HTTP {}", status.as_u16()));
|
||||
let detail = server_error_detail(code, message, || format!("HTTP {}", status.as_u16()));
|
||||
format!("{fallback}:{detail}")
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,19 @@ fn parse_server_error(status: u16, body: &str) -> (Option<String>, Option<String
|
||||
(code, message)
|
||||
}
|
||||
|
||||
/// 服务端错误信封里「给用户看的那句」的统一取法:优先非空 `message`,退非空 `code`,
|
||||
/// 都没有才用调用点的 `fallback`。所有 HTTP 错误分支共用这一处顺序,避免各自漂移。
|
||||
pub(crate) fn server_error_detail(
|
||||
code: Option<String>,
|
||||
message: Option<String>,
|
||||
fallback: impl FnOnce() -> String,
|
||||
) -> String {
|
||||
message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(fallback)
|
||||
}
|
||||
|
||||
/// 从 409 响应里取权威已收字节;取不到就返回 `None`,由调用方按失败处理。
|
||||
fn parse_received_bytes(body: &str) -> Option<u64> {
|
||||
let parsed = serde_json::from_str::<Value>(body).ok()?;
|
||||
|
||||
@@ -155,10 +155,7 @@ async fn read_upload_state(
|
||||
})?;
|
||||
if status >= 400 {
|
||||
let (code, message) = parse_server_error(status, &body);
|
||||
let detail = message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(|| format!("HTTP {status}"));
|
||||
let detail = server_error_detail(code, message, || format!("HTTP {status}"));
|
||||
return Err(GamePackageUploadError::read_upload_state(detail));
|
||||
}
|
||||
let parsed: Value = serde_json::from_str(&body).map_err(|error| {
|
||||
@@ -213,30 +210,21 @@ async fn upload_chunk(
|
||||
})?;
|
||||
return Ok(received);
|
||||
}
|
||||
let detail = message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(|| format!("HTTP {status}"));
|
||||
let detail = server_error_detail(code, message, || format!("HTTP {status}"));
|
||||
return Err(ChunkUploadError::Fatal(
|
||||
GamePackageUploadError::upload_chunk(detail),
|
||||
));
|
||||
}
|
||||
if status >= 500 || status == 408 || status == 429 {
|
||||
let (code, message) = parse_server_error(status, &text);
|
||||
let detail = message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(|| format!("HTTP {status}"));
|
||||
let detail = server_error_detail(code, message, || format!("HTTP {status}"));
|
||||
return Err(ChunkUploadError::Retryable(
|
||||
GamePackageUploadError::upload_chunk(detail),
|
||||
));
|
||||
}
|
||||
if status >= 400 {
|
||||
let (code, message) = parse_server_error(status, &text);
|
||||
let detail = message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(|| format!("HTTP {status}"));
|
||||
let detail = server_error_detail(code, message, || format!("HTTP {status}"));
|
||||
return Err(ChunkUploadError::Fatal(
|
||||
GamePackageUploadError::upload_chunk(detail),
|
||||
));
|
||||
@@ -285,10 +273,7 @@ async fn complete_upload(
|
||||
})?;
|
||||
if status >= 400 {
|
||||
let (code, message) = parse_server_error(status, &text);
|
||||
let detail = message
|
||||
.filter(|detail| !detail.trim().is_empty())
|
||||
.or_else(|| code.filter(|detail| !detail.trim().is_empty()))
|
||||
.unwrap_or_else(|| format!("HTTP {status}"));
|
||||
let detail = server_error_detail(code, message, || format!("HTTP {status}"));
|
||||
return Err(GamePackageUploadError::complete_upload(detail));
|
||||
}
|
||||
let parsed: Value = serde_json::from_str(&text).map_err(|error| {
|
||||
|
||||
Reference in New Issue
Block a user