Integrate unfinished server-rs refactor worklists
This commit is contained in:
133
server-rs/crates/api-server/src/platform_errors.rs
Normal file
133
server-rs/crates/api-server/src/platform_errors.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
use axum::http::{HeaderValue, StatusCode};
|
||||
use platform_auth::{AuthPlatformErrorKind, WechatProviderError};
|
||||
use platform_llm::{LlmError, LlmErrorKind};
|
||||
use platform_oss::{OssError, OssErrorKind};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::http_error::AppError;
|
||||
|
||||
// API 层统一消费 platform 的稳定错误分类,避免各 route 重复 match 具体 provider 分支。
|
||||
pub fn map_llm_error(error: LlmError) -> AppError {
|
||||
let message = llm_error_message(&error);
|
||||
let status = match error.kind() {
|
||||
LlmErrorKind::InvalidRequest => StatusCode::BAD_REQUEST,
|
||||
LlmErrorKind::InvalidConfig => StatusCode::SERVICE_UNAVAILABLE,
|
||||
LlmErrorKind::Upstream
|
||||
if matches!(
|
||||
error,
|
||||
LlmError::Upstream {
|
||||
status_code: 429,
|
||||
..
|
||||
}
|
||||
) =>
|
||||
{
|
||||
StatusCode::TOO_MANY_REQUESTS
|
||||
}
|
||||
LlmErrorKind::Timeout
|
||||
| LlmErrorKind::Connectivity
|
||||
| LlmErrorKind::Upstream
|
||||
| LlmErrorKind::StreamUnavailable
|
||||
| LlmErrorKind::EmptyResponse
|
||||
| LlmErrorKind::Transport
|
||||
| LlmErrorKind::Deserialize => StatusCode::BAD_GATEWAY,
|
||||
};
|
||||
|
||||
AppError::from_status(status).with_message(message)
|
||||
}
|
||||
|
||||
pub fn map_oss_error(error: OssError, provider: &'static str) -> AppError {
|
||||
let status = oss_error_status(error.kind());
|
||||
AppError::from_status(status).with_details(json!({
|
||||
"provider": provider,
|
||||
"message": error.to_string(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn map_phone_auth_platform_store_error(message: String) -> AppError {
|
||||
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(message)
|
||||
}
|
||||
|
||||
pub fn map_wechat_provider_error(error: WechatProviderError) -> AppError {
|
||||
let status = match error.kind() {
|
||||
AuthPlatformErrorKind::Disabled
|
||||
| AuthPlatformErrorKind::MissingCode
|
||||
| AuthPlatformErrorKind::InvalidCallback => StatusCode::BAD_REQUEST,
|
||||
AuthPlatformErrorKind::InvalidConfig => StatusCode::SERVICE_UNAVAILABLE,
|
||||
AuthPlatformErrorKind::RequestFailed
|
||||
| AuthPlatformErrorKind::DeserializeFailed
|
||||
| AuthPlatformErrorKind::MissingProfile
|
||||
| AuthPlatformErrorKind::Upstream => StatusCode::BAD_GATEWAY,
|
||||
AuthPlatformErrorKind::InvalidClaims
|
||||
| AuthPlatformErrorKind::SignFailed
|
||||
| AuthPlatformErrorKind::VerifyFailed
|
||||
| AuthPlatformErrorKind::CookieConfig
|
||||
| AuthPlatformErrorKind::HashFailed
|
||||
| AuthPlatformErrorKind::InvalidVerifyCode => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
|
||||
AppError::from_status(status).with_message(error.to_string())
|
||||
}
|
||||
|
||||
pub fn attach_retry_after(error: AppError, retry_after_seconds: u64) -> AppError {
|
||||
match HeaderValue::from_str(&retry_after_seconds.to_string()) {
|
||||
Ok(value) => error.with_header("retry-after", value),
|
||||
Err(_) => error,
|
||||
}
|
||||
}
|
||||
|
||||
fn oss_error_status(kind: OssErrorKind) -> StatusCode {
|
||||
match kind {
|
||||
OssErrorKind::InvalidConfig | OssErrorKind::InvalidRequest => StatusCode::BAD_REQUEST,
|
||||
OssErrorKind::ObjectNotFound => StatusCode::NOT_FOUND,
|
||||
OssErrorKind::Request | OssErrorKind::SerializePolicy | OssErrorKind::Sign => {
|
||||
StatusCode::BAD_GATEWAY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn llm_error_message(error: &LlmError) -> String {
|
||||
match error {
|
||||
LlmError::InvalidConfig(message)
|
||||
| LlmError::InvalidRequest(message)
|
||||
| LlmError::Transport(message)
|
||||
| LlmError::Deserialize(message) => message.clone(),
|
||||
LlmError::Timeout { .. }
|
||||
| LlmError::Connectivity { .. }
|
||||
| LlmError::Upstream { .. }
|
||||
| LlmError::StreamUnavailable
|
||||
| LlmError::EmptyResponse => error.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn map_oss_error_uses_stable_kind_for_not_found() {
|
||||
let error = map_oss_error(
|
||||
OssError::ObjectNotFound("missing object".to_string()),
|
||||
"oss",
|
||||
);
|
||||
|
||||
assert_eq!(error.status_code(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_llm_error_preserves_upstream_rate_limit() {
|
||||
let error = map_llm_error(LlmError::Upstream {
|
||||
status_code: 429,
|
||||
message: "too many requests".to_string(),
|
||||
});
|
||||
|
||||
assert_eq!(error.status_code(), StatusCode::TOO_MANY_REQUESTS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_wechat_provider_error_keeps_provider_boundary() {
|
||||
let error = map_wechat_provider_error(WechatProviderError::MissingCode);
|
||||
|
||||
assert_eq!(error.status_code(), StatusCode::BAD_REQUEST);
|
||||
assert_eq!(error.message(), "缺少微信授权 code");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user