platform-tripo 构造配置时拒绝零超时与空白凭据

- TripoSettings::new 改为返回 Result:request_timeout 必须大于零,api_key / base_url 不能是空白
- 新增 TripoSettings::validate 与 TripoError::Configuration,字段是公开的,因此 TripoProviderClient::new 在使用前再校验一次
- 拒绝零超时的理由是同一个值存在两种语义:tokio::time::timeout 立即超时,reqwest 却当成不超时
- api-server 构造入口把构造失败按既有 503 口径映射,并补全 TripoError 的匹配分支
- smoke 示例与 platform-tripo 测试跟进新的构造签名,新增零超时 / 空白凭据用例
This commit is contained in:
2026-09-23 16:16:27 +08:00
parent 825dde6602
commit ffee739774
6 changed files with 121 additions and 6 deletions
@@ -102,6 +102,16 @@ pub(crate) fn map_provider_error(error: TripoError) -> AppError {
"3D 生成任务的结果格式不符合预期,未落库。".to_string(),
)
}
// 配置问题正常在 `provider.rs` 就按 503 拦下;这里只是把枚举匹配补全,
// 真走到这一步说明有调用方绕过了构造入口,按服务不可用上报。
TripoError::Configuration { .. } => {
tracing::error!(error = %error, "tripo client misconfigured");
(
StatusCode::SERVICE_UNAVAILABLE,
"tripo-invalid-configuration",
"3D 生成服务配置不可用。".to_string(),
)
}
TripoError::Request { .. } | TripoError::Sdk { .. } | TripoError::Api { .. } => {
tracing::error!(error = %error, "tripo upstream error");
(
@@ -28,14 +28,17 @@ pub(crate) fn tripo_settings(config: &AppConfig) -> Result<TripoSettings, AppErr
.filter(|value| !value.is_empty())
.ok_or_else(|| not_configured("TRIPO_API_KEY 未配置,无法调用 Tripo 3D 生成服务。"))?;
Ok(TripoSettings::new(
// 上面的取值已经把空地址 / 空密钥挡掉、把超时钳到 >= 1ms,构造器在这里不会再失败;
// 仍然按 503 映射,保持「配置问题在扣费与入队之前失败」的既有口径。
TripoSettings::new(
api_key.to_string(),
base_url.to_string(),
Duration::from_millis(config.tripo_request_timeout_ms.max(1)),
// 重试次数直接决定产物下载的挂起时长,配置异常时封顶到 10 次。
config.tripo_retries.min(10),
TRIPO_USER_AGENT.to_string(),
))
)
.map_err(map_provider_client_error)
}
pub(crate) fn tripo_provider_client(config: &AppConfig) -> Result<TripoProviderClient, AppError> {