阶段3:迁移主站请求 Client 并补充边界验收
将生产 Rust 主站请求 Client 创建点切换到统一 factory。 覆盖账号态和开发者 Key 态的项目、素材、上传确认、生成、编辑、轮询及换签请求。 保留签名 URL 下载、OSS 上传、Provider、搜索、loopback 和更新下载的独立 Client 边界。 增加画板同步请求捕获测试,验证主站请求带标记且签名媒体下载不带标记。 更新 Issue 226 阶段实施方案与验收计划,明确阶段 3 完成、阶段 4 待开始。
This commit is contained in:
@@ -2484,7 +2484,7 @@ async fn recover_direct_taonier_spritesheet_read_only_at(
|
||||
task_id: art_spec.task_id.clone(),
|
||||
reference_resource_ids: Vec::new(),
|
||||
};
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.timeout(std::time::Duration::from_secs(60))
|
||||
.build()
|
||||
.map_err(|error| format!("创建陶泥儿只读资源恢复客户端失败:{error}"))?;
|
||||
|
||||
@@ -1810,7 +1810,9 @@ async fn bridge_remove_background(state: &DirectToolBridgeState, arguments: &Val
|
||||
.to_string();
|
||||
let (api_base_url, api_key, session) = resolve_canvas_sync_api_credentials(None, None)?;
|
||||
let access = ExternalEditorBindingAccess::new(&api_base_url, &api_key, session.as_ref())?;
|
||||
let client = reqwest::Client::new();
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.build()
|
||||
.map_err(|_| "创建抠图服务连接失败".to_string())?;
|
||||
let context =
|
||||
prepare_external_canvas_generation_context(&state.root, &client, &access).await?;
|
||||
let fingerprint = format!("{}\0{}", source_asset_id, asset_name);
|
||||
|
||||
@@ -2401,11 +2401,11 @@ pub(in crate::agent) async fn request_platform_art_asset_with_runtime_options_at
|
||||
.map_err(|error| format!("{EXTERNAL_GENERATION_RESULT_UNKNOWN_PREFIX} {error}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.timeout(Duration::from_secs(60))
|
||||
.build()
|
||||
.map_err(|error| format!("创建 External Editor HTTP 客户端失败:{error}"))?;
|
||||
let submit_client = reqwest::Client::builder()
|
||||
let submit_client = crate::http_client::agc_main_site_client_builder()
|
||||
.timeout(EXTERNAL_GENERATION_SUBMIT_TIMEOUT)
|
||||
.build()
|
||||
.map_err(|error| format!("创建 External Editor 生成提交客户端失败:{error}"))?;
|
||||
|
||||
@@ -374,7 +374,7 @@ async fn create_private_external_editor_api_credentials_from_platform_session(
|
||||
.to_string()
|
||||
})?;
|
||||
let api_base_url = normalize_external_editor_api_base_url(&session.api_base_url)?;
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.connect_timeout(Duration::from_secs(10))
|
||||
.timeout(Duration::from_secs(30))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
@@ -709,7 +709,9 @@ pub(crate) async fn sync_canvas_project_assets_at(
|
||||
init_local_game_project_at(root, "local-project-draft", "未命名游戏原型")?;
|
||||
let api_base_url = resolve_canvas_sync_api_base_url(api_base_url)?;
|
||||
let api_key = resolve_canvas_sync_api_key(api_key)?;
|
||||
let client = reqwest::Client::new();
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.build()
|
||||
.map_err(|error| format!("创建画板同步客户端失败:{error}"))?;
|
||||
let project_url = format!(
|
||||
"{}{}",
|
||||
api_base_url,
|
||||
@@ -1120,7 +1122,7 @@ where
|
||||
if max_bytes == 0 {
|
||||
return Err("画板资产剩余下载预算为 0,已拒绝同步".to_string());
|
||||
}
|
||||
let secure_client = reqwest::Client::builder()
|
||||
let secure_client = crate::http_client::agc_main_site_client_builder()
|
||||
.connect_timeout(Duration::from_secs(10))
|
||||
.timeout(Duration::from_secs(60))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
|
||||
@@ -3280,7 +3280,7 @@ async fn fetch_agent_editor_asset_records(
|
||||
resolve_canvas_sync_api_credentials(None, None)?;
|
||||
let access =
|
||||
ExternalEditorBindingAccess::new(&api_base_url, &bearer_token, frozen_session.as_ref())?;
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.connect_timeout(std::time::Duration::from_secs(10))
|
||||
.timeout(std::time::Duration::from_secs(60))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
@@ -3830,7 +3830,7 @@ pub(crate) async fn import_account_editor_assets_for_agent(
|
||||
}
|
||||
let access =
|
||||
ExternalEditorBindingAccess::new(&api_base_url, &bearer_token, frozen_session.as_ref())?;
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.connect_timeout(std::time::Duration::from_secs(10))
|
||||
.timeout(std::time::Duration::from_secs(60))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
|
||||
@@ -3726,11 +3726,11 @@ async fn reconcile_generation(
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.timeout(Duration::from_secs(60))
|
||||
.build()
|
||||
.map_err(|_| "无法创建图片生成 HTTP 客户端".to_string())?;
|
||||
let submit_client = reqwest::Client::builder()
|
||||
let submit_client = crate::http_client::agc_main_site_client_builder()
|
||||
.timeout(Duration::from_secs(35 * 60))
|
||||
.build()
|
||||
.map_err(|_| "无法创建图片生成提交客户端".to_string())?;
|
||||
|
||||
@@ -3098,7 +3098,7 @@ async fn prepare_remote_resource_edit(
|
||||
"result-unknown: 历史站内资源编辑 operation 不能由 External v1 自动重放".to_string(),
|
||||
);
|
||||
}
|
||||
let client = reqwest::Client::builder()
|
||||
let client = crate::http_client::agc_main_site_client_builder()
|
||||
.timeout(Duration::from_secs(35 * 60))
|
||||
.build()
|
||||
.map_err(|_| "无法创建资源编辑 HTTP 客户端".to_string())?;
|
||||
|
||||
@@ -2052,7 +2052,8 @@ fn import_canvas_export_zip_copies_files_and_registers_assets() {
|
||||
#[tokio::test]
|
||||
async fn sync_canvas_project_assets_downloads_external_resources() {
|
||||
let root = unique_project_path();
|
||||
let base_url = spawn_mock_external_canvas_api_server();
|
||||
let (request_sender, request_receiver) = mpsc::channel();
|
||||
let base_url = spawn_mock_external_canvas_api_server_with_capture(3, Some(request_sender));
|
||||
let _platform_session = crate::platform_session::install_test_platform_session(
|
||||
"canvas-sync-user",
|
||||
"test-editor-api-key",
|
||||
@@ -2097,6 +2098,26 @@ async fn sync_canvas_project_assets_downloads_external_resources() {
|
||||
assert!(agent_db.contains("\"recordType\":\"canvas.project_sync\""));
|
||||
assert!(!agent_db.contains("test-editor-api-key"));
|
||||
|
||||
let requests = request_receiver.try_iter().collect::<Vec<_>>();
|
||||
assert_eq!(requests.len(), 3, "画板同步应产生项目、换签和媒体请求");
|
||||
let main_site_requests = requests
|
||||
.iter()
|
||||
.filter(|request| !request.starts_with("GET /signed/"))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(main_site_requests.len(), 2);
|
||||
assert!(main_site_requests.iter().all(|request| {
|
||||
request
|
||||
.to_ascii_lowercase()
|
||||
.contains("x-genarrative-client: agc")
|
||||
}));
|
||||
let signed_download = requests
|
||||
.iter()
|
||||
.find(|request| request.starts_with("GET /signed/"))
|
||||
.expect("signed media download request");
|
||||
assert!(!signed_download
|
||||
.to_ascii_lowercase()
|
||||
.contains("x-genarrative-client:"));
|
||||
|
||||
fs::remove_dir_all(root).ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Issue #226:AGC 客户端主站请求统一标记实施方案
|
||||
|
||||
更新时间:2026-09-01<br>
|
||||
更新时间:2026-09-02<br>
|
||||
关联 Issue:
|
||||
|
||||
- `#226 添加客户端特殊标识`:本方案实际实施范围
|
||||
- `#225 添加客户端埋点统计`:主站接收、落库和后台统计,本文只冻结交接契约,不在本次实施
|
||||
|
||||
状态:阶段 2 已完成,待阶段 3 实施<br>
|
||||
本方案不包含代码修改
|
||||
状态:阶段 3 已完成,待阶段 4 实施<br>
|
||||
本方案包含 #226 客户端代码修改,不包含 #225 主站接收、落库和后台统计代码
|
||||
|
||||
## 1. 一句话交付结果
|
||||
|
||||
@@ -227,6 +227,16 @@ let client = agc_main_site_client_builder()
|
||||
- loopback 客户端工具桥 Client。
|
||||
- [main.rs](C:/projects/narrative/Genarrative/apps/ai-game-creator-shell/src-tauri/src/main.rs) 的更新下载请求。
|
||||
|
||||
### 6.5 阶段 3 实施记录
|
||||
|
||||
- 已将生产代码中明确用于主站 API 的 Client 创建点切换为 `crate::http_client::agc_main_site_client_builder()`,覆盖 `assets.rs`、`commands.rs`、`canvas_generation.rs`、`direct_runtime.rs`、`direct_tool_bridge.rs`、`asset_canvas/generation.rs` 和 `resource_editor.rs`。
|
||||
- 主站项目、素材库、素材目录、上传凭证、对象确认、资源登记、图片生成/编辑/抠图、视频/动画/音频生成以及 generation 查询请求复用带 `X-Genarrative-Client: agc` 的 Client。
|
||||
- `assets/read-url` 换签请求使用主站 factory;签名 URL 媒体下载仍使用独立的 `build_external_asset_download_client`,不会携带主站标记。
|
||||
- OSS multipart 上传、Provider、受控搜索、loopback 工具桥和更新下载没有切换到主站 factory。
|
||||
- 保留原有 timeout、connect timeout、redirect、`no_proxy`、Bearer/API Key、Idempotency-Key、请求体和响应处理;未修改 `ExternalEditorBindingAccess` 的路由映射语义。
|
||||
- 阶段 3 请求捕获验证:`sync_canvas_project_assets_downloads_external_resources`(1 test passed)确认账号态项目请求和 `assets/read-url` 带标记,签名媒体下载不带标记。
|
||||
- 阶段 3 验证命令:`cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml http_client -- --nocapture`(2 tests passed);`cargo test --locked --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml sync_canvas_project_assets_downloads_external_resources -- --nocapture`(1 test passed);`cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check`、`npm run check:encoding` 和 `git diff --check` 均通过。
|
||||
|
||||
## 7. 调用语义和现有路由边界
|
||||
|
||||
本次不改变 `ExternalEditorBindingAccess` 的职责:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Issue #226:AGC 客户端主站请求标记分阶段实施与验收计划
|
||||
|
||||
更新时间:2026-09-01<br>
|
||||
更新时间:2026-09-02<br>
|
||||
关联 Issue:
|
||||
|
||||
- `#226 添加客户端特殊标识`:本计划全部实施范围
|
||||
- `#225 添加客户端埋点统计`:只接收交接契约,不在本计划实现
|
||||
|
||||
当前状态:阶段 2 已完成;阶段 3 尚未开始。阶段 0 的证据与验收记录见
|
||||
当前状态:阶段 3 已完成;阶段 4 尚未开始。阶段 0 的证据与验收记录见
|
||||
[【阶段验收】Issue226阶段0现状基线与契约冻结-2026-09-01.md](C:/projects/narrative/Genarrative/local-docs/【阶段验收】Issue226阶段0现状基线与契约冻结-2026-09-01.md)。
|
||||
|
||||
## 1. 交付目标
|
||||
@@ -243,6 +243,15 @@ fn agc_main_site_client_builder() -> reqwest::ClientBuilder;
|
||||
- 没有把所有 Rust Client 粗暴替换成主站 Client。
|
||||
- 旧的第三方 Client 边界仍然清晰。
|
||||
|
||||
### 7.5 阶段 3 实施记录
|
||||
|
||||
- 已迁移 7 个生产 Rust 文件中的主站 Client 创建点:`assets.rs`、`commands.rs`、`agent/generation/canvas_generation.rs`、`agent/direct_runtime.rs`、`agent/direct_tool_bridge.rs`、`project/asset_canvas/generation.rs` 和 `project/resource_editor.rs`。
|
||||
- 迁移覆盖账号态实际 `/api/editor`、`/api/assets`、`/api/runtime` 路径,以及开发者 Key 态 `/api/external/v1` 路径;`assets/read-url` 的主站换签请求也通过 factory 创建。
|
||||
- 签名 URL 下载和 OSS multipart 上传仍由独立安全下载 Client 负责;Provider、搜索、loopback 和更新下载保持裸 Client。
|
||||
- 未修改 `ExternalEditorBindingAccess` 路由映射、凭据、请求体、operationId、Idempotency-Key 或本地账本语义。
|
||||
- 请求捕获测试已验证账号态画板同步的项目请求和换签请求带 `X-Genarrative-Client: agc`,签名媒体下载不带该 Header。
|
||||
- 阶段 3 验证:`http_client` 定向测试 2 个通过;`sync_canvas_project_assets_downloads_external_resources` 通过;Rust fmt、编码检查和 `git diff --check` 通过。
|
||||
|
||||
## 8. 阶段 4:第三方请求隔离与负向验证
|
||||
|
||||
### 8.1 工作内容
|
||||
|
||||
Reference in New Issue
Block a user