优化: 项目管理阻塞去重 + normalize_path/白名单抽公共
- collect_sample/detect_stack 三处包 spawn_blocking 防 async 阻塞 + bind_directory 补漏一处 - normalize_path 抽公共到 df-project/scan(删 project.rs 本地 + tool_registry inline 闭包) - tool_registry update_project 复用 crud is_allowed_column(删硬编码白名单,与 CRUD 同源) Sprint 20 审查 ③④⑤。todo 记 A/B 验证发现的 2 项非阻断(T-09 idea 补偿删级联 / T-10 normalize_path 同步)
This commit is contained in:
@@ -133,7 +133,10 @@ pub fn build_ai_tool_registry(db: &Arc<Database>) -> AiToolRegistry {
|
||||
let id = args["id"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 id"))?;
|
||||
let field = args["field"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 field"))?;
|
||||
let value = args["value"].as_str().ok_or_else(|| anyhow::anyhow!("缺少 value"))?;
|
||||
match field { "name" | "status" | "description" | "path" | "stack" => {}, _ => anyhow::bail!("不允许更新字段 '{}'", field) }
|
||||
// 复用 df-storage CRUD 白名单(按表隔离),与 update_field 校验同源
|
||||
if !df_storage::crud::is_allowed_column("projects", field) {
|
||||
anyhow::bail!("不允许更新字段 '{}'", field);
|
||||
}
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
repo.update_field(id, field, value).await?;
|
||||
Ok(serde_json::json!({ "id": id, "field": field, "updated": true }))
|
||||
@@ -176,26 +179,23 @@ pub fn build_ai_tool_registry(db: &Arc<Database>) -> AiToolRegistry {
|
||||
anyhow::bail!("目录不存在: {path}");
|
||||
}
|
||||
let repo = df_storage::crud::ProjectRepo::new(&db);
|
||||
// 防重复:canonicalize 规范化比较,防路径写法差异绕过
|
||||
let normalize = |s: &str| -> String {
|
||||
std::path::Path::new(s)
|
||||
.canonicalize()
|
||||
.map(|a| a.to_string_lossy().replace('\\', "/").to_lowercase())
|
||||
.unwrap_or_else(|_| s.trim_end_matches(['\\', '/']).replace('\\', "/").to_lowercase())
|
||||
};
|
||||
let target = normalize(path);
|
||||
// 防重复:canonicalize 规范化比较,防路径写法差异绕过(复用 df-project 公共 normalize_path)
|
||||
let target = df_project::scan::normalize_path(path);
|
||||
let projects = repo.list_active().await?;
|
||||
for proj in &projects {
|
||||
if proj.id != id {
|
||||
if let Some(pp) = &proj.path {
|
||||
if normalize(pp) == target {
|
||||
if df_project::scan::normalize_path(pp) == target {
|
||||
anyhow::bail!("目录已被项目「{}」绑定", proj.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 探测技术栈
|
||||
let stack = df_project::scan::detect_stack(dir)?;
|
||||
// 探测技术栈(spawn_blocking: detect_stack 内含多次同步 fs IO,避免阻塞 tokio runtime)
|
||||
let dir_buf = std::path::PathBuf::from(path);
|
||||
let stack = tokio::task::spawn_blocking(move || df_project::scan::detect_stack(&dir_buf))
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("技术栈探测任务失败: {e}"))??;
|
||||
let stack_json = serde_json::to_string(&stack)?;
|
||||
repo.update_field(id, "path", path).await?;
|
||||
repo.update_field(id, "stack", &stack_json).await?;
|
||||
|
||||
Reference in New Issue
Block a user