From d71c7d70158ad5b627013fe015440471e7d528c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 19 Aug 2026 14:30:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DUI=E7=BC=96=E8=BE=91=E5=99=A8?= =?UTF-8?q?=E8=BF=9C=E7=AB=AF=E5=AF=BC=E5=85=A5=E7=BC=96=E8=AF=91=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将远端素材导入改为异步下载后加锁提交,消除 await 同步函数编译错误。 更新字体素材导入测试以使用当前筛选器与配置契约。 --- .../src-tauri/src/commands.rs | 16 ++++++++++------ .../tests/assetImporter.test.ts | 14 ++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/commands.rs b/apps/ai-game-creator-shell/src-tauri/src/commands.rs index ebee36b45..63a580216 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/commands.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/commands.rs @@ -2202,25 +2202,22 @@ mod ui_editor_font_tests { } } -pub(crate) fn import_ui_editor_remote_assets( +pub(crate) async fn import_ui_editor_remote_assets( project_path: String, assets: Vec, ) -> Result { let root = Path::new(project_path.trim()); enforce_project_permission_policy(root, "canvas.asset_import")?; - let _lock = acquire_project_write_lock(root, "canvas.asset_import")?; if assets.len() > UI_EDITOR_IMAGE_MAX_COUNT { return Err(format!("一次最多选择 {UI_EDITOR_IMAGE_MAX_COUNT} 张图片")); } - // 远程素材导入保持与本地图片/字体相同的增量语义,不对已成功项目文件做整批回滚。 + // IPC 只传稳定引用/签名 URL,由 Rust 流式下载并限制响应体;下载期间不占有项目写锁。 let mut total_size = 0u64; - let mut imported = Vec::with_capacity(assets.len()); + let mut downloads = Vec::with_capacity(assets.len()); for asset in assets { let asset_id = json_string_field(&asset, "assetId") .or_else(|| json_string_field(&asset, "objectKey")) .ok_or_else(|| "平台素材缺少稳定 assetId/objectKey,拒绝导入".to_string())?; - // 参考资源同步流程:IPC 只传稳定引用/签名 URL,由 Rust 流式下载并限制响应体, - // 避免把不受控的 Vec 在 IPC 反序列化阶段一次性放入内存。 let download_url = json_string_field(&asset, "downloadUrl") .ok_or_else(|| format!("平台素材 {asset_id} 缺少 downloadUrl"))?; let remaining = UI_EDITOR_IMAGE_MAX_TOTAL_SIZE.saturating_sub(total_size); @@ -2243,6 +2240,13 @@ pub(crate) fn import_ui_editor_remote_assets( } else { return Err("平台素材不是受支持的 PNG/JPEG/WEBP 图片".to_string()); }; + downloads.push((asset, asset_id, media_type.to_string(), bytes)); + } + + let _lock = acquire_project_write_lock(root, "canvas.asset_import")?; + // 远程素材导入保持与本地图片/字体相同的增量语义,不对已成功项目文件做整批回滚。 + let mut imported = Vec::with_capacity(downloads.len()); + for (asset, asset_id, media_type, bytes) in downloads { let extension = infer_file_extension( json_string_field(&asset, "objectKey") .or_else(|| json_string_field(&asset, "imageSrc")) diff --git a/apps/ai-game-creator-shell/tests/assetImporter.test.ts b/apps/ai-game-creator-shell/tests/assetImporter.test.ts index fbe973a26..fb59bd4a5 100644 --- a/apps/ai-game-creator-shell/tests/assetImporter.test.ts +++ b/apps/ai-game-creator-shell/tests/assetImporter.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest'; +import { FONT_IMPORTER_SETTINGS } from '../src/components/AssetImporter/settings'; import { buildProjectFiles, buildRootFiles, @@ -25,15 +26,16 @@ describe('AssetImporter font mode', () => { }, ]; - const files = buildProjectFiles(assets, 'font').filter( - (entry) => !entry.isDirectory, - ); + const files = buildProjectFiles( + assets, + FONT_IMPORTER_SETTINGS.local.typeFilter, + ).filter((entry) => !entry.isDirectory); expect(files.map((entry) => entry.asset?.id)).toEqual([ 'font-1', 'font-by-extension', ]); - expect(buildRootFiles('font').map((entry) => entry.name)).toEqual([ - '本地项目字体', - ]); + expect( + buildRootFiles(FONT_IMPORTER_SETTINGS).map((entry) => entry.name), + ).toEqual(['本地项目']); }); });