修复UI编辑器远端导入编译错误

将远端素材导入改为异步下载后加锁提交,消除 await 同步函数编译错误。

更新字体素材导入测试以使用当前筛选器与配置契约。
This commit is contained in:
2026-08-19 14:30:34 +08:00
parent b26d9f7e3a
commit d71c7d7015
2 changed files with 18 additions and 12 deletions
@@ -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<serde_json::Value>,
) -> Result<RemoteImportResult, String> {
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<u8> 在 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"))
@@ -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(['本地项目']);
});
});