From 4edeadae7d136597fa87384a506c1338a2806245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Mon, 21 Sep 2026 14:02:58 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E8=AE=B0Tripo=203D=E7=9A=84=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=BB=93=E6=9E=9Coperation=5Fkind=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95=20-=20SpacetimeDB=20storage=20=E7=9A=84=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=99=A8=E7=94=9F=E6=88=90=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=20model3d=5Ftext=5Fto=5Fmodel=20=E4=B8=8E=20?= =?UTF-8?q?model3d=5Fimage=5Fto=5Fmodel=20-=20=E7=99=BD=E5=90=8D=E5=8D=95?= =?UTF-8?q?=E6=98=AF=E5=8E=9F=E5=AD=90=E8=90=BD=E5=BA=93=E7=9A=84=20operat?= =?UTF-8?q?ion=5Fkind=20=E9=97=A8=E7=A6=81=EF=BC=8C=E6=9C=AA=E7=99=BB?= =?UTF-8?q?=E8=AE=B0=E4=BC=9A=E8=AE=A9=E6=95=B4=E7=AC=94=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E4=BA=8B=E5=8A=A1=E8=A2=AB=E6=8B=92=20-=20api-server=20?= =?UTF-8?q?=E4=BE=A7=E6=8C=89=E6=BA=90=E7=A0=81=E9=92=89=E4=BD=8F=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=20job=20kind=20=E5=B7=B2=E5=9C=A8=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95=E5=86=85=EF=BC=8C=E9=81=BF=E5=85=8D=E5=8F=AA=E5=9C=A8?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=9C=9F=E6=89=8D=E5=8F=91=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crates/api-server/src/tripo3d/job.rs | 20 +++++++++++++++++++ .../src/editor_project_storage.rs | 5 ++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/server-rs/crates/api-server/src/tripo3d/job.rs b/server-rs/crates/api-server/src/tripo3d/job.rs index 962d399ee..39e48b6f4 100644 --- a/server-rs/crates/api-server/src/tripo3d/job.rs +++ b/server-rs/crates/api-server/src/tripo3d/job.rs @@ -180,4 +180,24 @@ mod tests { assert!(parse_model3d_job_request(MODEL3D_TEXT_TO_MODEL_JOB_KIND, &payload).is_err()); assert!(parse_model3d_job_request("unknown_job_kind", &payload).is_err()); } + + /// 原子落库在 SpacetimeDB 侧按 operation_kind 白名单拒绝未知生成结果; + /// 白名单是另一个 crate 里的字符串字面量,所以在这里按源码钉住,避免只在运行期才炸。 + #[test] + fn model3d_job_kinds_are_registered_in_editor_generation_whitelist() { + let whitelist = include_str!("../../../spacetime-module/src/editor_project_storage.rs"); + let declared = whitelist + .split_once("const EDITOR_GENERATION_OPERATION_KINDS") + .and_then(|(_, rest)| rest.split_once("];")) + .map(|(list, _)| list) + .expect("应能在 SpacetimeDB storage 源码里定位 operation_kind 白名单"); + + for kind in Model3dJobKind::ALL { + assert!( + declared.contains(&format!("\"{}\"", kind.as_str())), + "{} 必须在编辑器生成 operation_kind 白名单内", + kind.as_str() + ); + } + } } diff --git a/server-rs/crates/spacetime-module/src/editor_project_storage.rs b/server-rs/crates/spacetime-module/src/editor_project_storage.rs index 1f506eed4..96a736bf9 100644 --- a/server-rs/crates/spacetime-module/src/editor_project_storage.rs +++ b/server-rs/crates/spacetime-module/src/editor_project_storage.rs @@ -26,7 +26,7 @@ const EDITOR_IMAGE_ASSET_KIND_CLEANUP_CANVAS_MAX_BATCH_SIZE: u32 = 5; const EDITOR_LEGACY_IMAGE_ASSET_KIND: &str = "image"; // 透明图集最多产出 256 个切片,另有 provider 原图和透明整图两个正式 item。 const EDITOR_GENERATION_RESULT_MAX_ITEMS: usize = 258; -const EDITOR_GENERATION_OPERATION_KINDS: [&str; 10] = [ +const EDITOR_GENERATION_OPERATION_KINDS: [&str; 12] = [ "editor_image_generation", "editor_icon_spec_generation", "editor_image_edit", @@ -37,6 +37,9 @@ const EDITOR_GENERATION_OPERATION_KINDS: [&str; 10] = [ "editor_video_generation", "editor_sound_effect_generation", "editor_background_music_generation", + // Tripo 3D 的产物没有图片画布入口,但共用同一原子落库事务;不在这里登记就会被整笔拒绝。 + "model3d_text_to_model", + "model3d_image_to_model", ]; const EDITOR_CHARACTER_ANIMATION_ASSET_KIND: &str = "character-animation"; const EDITOR_CHARACTER_ANIMATION_OBJECT_KIND: &str = "editor_character_animation";