图生 3D 的引用类型判别改用枚举

- server-rs/crates/api-server/src/tripo3d/image_source.rs:ResolvedReference.kind 从 &'static str 改成 ResolvedReferenceKind 枚举,From<EditorReferenceRecord> 写值与匹配比较由同一处产出,字符串错字不再只在运行期暴露
- server-rs/crates/api-server/src/tripo3d/image_source.rs:对外文案仍由 as_str() 生成,用例同步改用枚举取值
This commit is contained in:
2026-09-24 18:03:05 +08:00
parent 06f091f0ff
commit cc472d0736
@@ -87,19 +87,38 @@ async fn resolve_source_object_key(
/// 定点查询返回的窄结果:只保留判定引用是否可用所需的记录类型与对象键。
struct ResolvedReference {
kind: &'static str,
kind: ResolvedReferenceKind,
object_key: Option<String>,
}
/// 记录类型判别:与 `Model3dGenerationSource` 的两个分支一一对应。
///
/// 用枚举而不是字符串字面量:`From<EditorReferenceRecord>` 写入的取值与
/// `resolve_source_object_key_with` 里比较的取值由同一处产出,错字不会再拖到运行期才发现。
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ResolvedReferenceKind {
Resource,
Asset,
}
impl ResolvedReferenceKind {
const fn as_str(self) -> &'static str {
match self {
Self::Resource => "resource",
Self::Asset => "asset",
}
}
}
impl From<EditorReferenceRecord> for ResolvedReference {
fn from(record: EditorReferenceRecord) -> Self {
match record {
EditorReferenceRecord::ProjectResource(resource) => Self {
kind: "resource",
kind: ResolvedReferenceKind::Resource,
object_key: resource.object_key,
},
EditorReferenceRecord::Asset(asset) => Self {
kind: "asset",
kind: ResolvedReferenceKind::Asset,
object_key: asset.object_key,
},
}
@@ -119,8 +138,12 @@ where
Fut: std::future::Future<Output = Result<ResolvedReference, AppError>>,
{
let (requested_kind, reference_id) = match source {
Model3dGenerationSource::Resource { resource_id } => ("resource", resource_id.as_str()),
Model3dGenerationSource::Asset { asset_id } => ("asset", asset_id.as_str()),
Model3dGenerationSource::Resource { resource_id } => {
(ResolvedReferenceKind::Resource, resource_id.as_str())
}
Model3dGenerationSource::Asset { asset_id } => {
(ResolvedReferenceKind::Asset, asset_id.as_str())
}
};
let resolved = resolve(reference_id.to_string()).await.map_err(|error| {
// 只有「未登记(404)/ 引用非法(400)」这一类才是“引用不可用”,收敛成同一句 400;
@@ -132,7 +155,10 @@ where
}
})?;
if resolved.kind != requested_kind {
return Err(image_source_kind_mismatch(requested_kind, resolved.kind));
return Err(image_source_kind_mismatch(
requested_kind.as_str(),
resolved.kind.as_str(),
));
}
resolved
.object_key
@@ -190,7 +216,7 @@ mod tests {
AppError::from_status(status).with_details(json!({ "reason": "probe" }))
}
fn resolved(kind: &'static str, object_key: Option<&str>) -> ResolvedReference {
fn resolved(kind: ResolvedReferenceKind, object_key: Option<&str>) -> ResolvedReference {
ResolvedReference {
kind,
object_key: object_key.map(str::to_string),
@@ -207,7 +233,7 @@ mod tests {
resource_id: "res-1".to_string(),
},
"res-1",
"resource",
ResolvedReferenceKind::Resource,
"objects/res-1.png",
),
(
@@ -215,7 +241,7 @@ mod tests {
asset_id: "asset-9".to_string(),
},
"asset-9",
"asset",
ResolvedReferenceKind::Asset,
"objects/asset-9.png",
),
] {
@@ -241,7 +267,10 @@ mod tests {
};
let error = resolve_source_object_key_with(&source, |_| async {
Ok(resolved("resource", Some("objects/asset-1.png")))
Ok(resolved(
ResolvedReferenceKind::Resource,
Some("objects/asset-1.png"),
))
})
.await
.expect_err("素材 ID 指向画布资源时必须报错");
@@ -264,10 +293,11 @@ mod tests {
resource_id: "res-1".to_string(),
};
let error =
resolve_source_object_key_with(&source, |_| async { Ok(resolved("resource", None)) })
.await
.expect_err("缺对象键时必须按服务端问题处理");
let error = resolve_source_object_key_with(&source, |_| async {
Ok(resolved(ResolvedReferenceKind::Resource, None))
})
.await
.expect_err("缺对象键时必须按服务端问题处理");
assert_eq!(error.status_code(), StatusCode::BAD_GATEWAY);
assert_eq!(