产物下载前校验任务确实处于完成态
- download_model 与 download_rendered_image 原先只看 output 是否存在,快照字段全公开、status 与 output 可以被人为构造得不一致 - 两个入口统一走 completed_output:先校验 task_id,再要求 status=Completed 且有输出,否则按输出结构错误失败
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use shared_contracts::model3d::common::Model3dTaskStatus;
|
||||
use tripo3d_sdk::TripoClient;
|
||||
|
||||
use super::{
|
||||
TripoDownloadedArtifact, TripoError, TripoSettings, TripoTaskHandle, TripoTaskSnapshot,
|
||||
TripoUrl, map_task, validate_task_id,
|
||||
TripoDownloadedArtifact, TripoError, TripoSettings, TripoTaskHandle, TripoTaskOutput,
|
||||
TripoTaskSnapshot, TripoUrl, map_task, validate_task_id,
|
||||
};
|
||||
|
||||
pub struct TripoProviderClient {
|
||||
@@ -47,18 +48,10 @@ impl TripoProviderClient {
|
||||
&self,
|
||||
task: &TripoTaskSnapshot,
|
||||
) -> Result<TripoDownloadedArtifact, TripoError> {
|
||||
let handle = &task.handle;
|
||||
validate_task_id(&handle.task_id)?;
|
||||
let output = task
|
||||
.output
|
||||
.as_ref()
|
||||
.ok_or_else(|| TripoError::OutputSchema {
|
||||
task_id: handle.task_id.clone(),
|
||||
message: "task has no completed model output".into(),
|
||||
})?;
|
||||
let output = completed_output(task)?;
|
||||
// TODO SDK upstream: expose a streaming artifact API; then replace this
|
||||
// provider-side reqwest client with the SDK stream and remove the duplicate downloader.
|
||||
self.download_artifact(&handle.task_id, output.model_url())
|
||||
self.download_artifact(&task.handle.task_id, output.model_url())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -70,16 +63,8 @@ impl TripoProviderClient {
|
||||
&self,
|
||||
task: &TripoTaskSnapshot,
|
||||
) -> Result<TripoDownloadedArtifact, TripoError> {
|
||||
let handle = &task.handle;
|
||||
validate_task_id(&handle.task_id)?;
|
||||
let output = task
|
||||
.output
|
||||
.as_ref()
|
||||
.ok_or_else(|| TripoError::OutputSchema {
|
||||
task_id: handle.task_id.clone(),
|
||||
message: "task has no completed model output".into(),
|
||||
})?;
|
||||
self.download_artifact(&handle.task_id, output.rendered_image_url())
|
||||
let output = completed_output(task)?;
|
||||
self.download_artifact(&task.handle.task_id, output.rendered_image_url())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -149,6 +134,27 @@ fn download_backoff(attempt: u32) -> Duration {
|
||||
Duration::from_millis(250u64.saturating_mul(2u64.saturating_pow(attempt.min(6))))
|
||||
}
|
||||
|
||||
/// 取完成态产物:下载入口只接受已完成且带输出的 task 快照。
|
||||
///
|
||||
/// `TripoTaskSnapshot` 字段全部公开,「完成态才有 output」只是 `map_task` 的约定,
|
||||
/// 不是类型保证;调用方可以构造出 status 与 output 不一致的快照,所以这里重新校验,
|
||||
/// 避免把失败 / 取消的任务当成成功产物下载。
|
||||
fn completed_output(task: &TripoTaskSnapshot) -> Result<&TripoTaskOutput, TripoError> {
|
||||
validate_task_id(&task.handle.task_id)?;
|
||||
if task.status != Model3dTaskStatus::Completed {
|
||||
return Err(TripoError::OutputSchema {
|
||||
task_id: task.handle.task_id.clone(),
|
||||
message: format!("task is not completed (status {:?})", task.status),
|
||||
});
|
||||
}
|
||||
task.output
|
||||
.as_ref()
|
||||
.ok_or_else(|| TripoError::OutputSchema {
|
||||
task_id: task.handle.task_id.clone(),
|
||||
message: "task has no completed output".into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn transport_error_kind(error: &reqwest::Error) -> &'static str {
|
||||
if error.is_timeout() {
|
||||
"timeout"
|
||||
|
||||
Reference in New Issue
Block a user