refactor(commands): update command layer to use database API
- Update config commands to query database for providers and settings - Modify provider commands to pass database handle to services - Update MCP commands to use database-backed operations - Refactor prompt and skill commands to leverage database storage - Simplify import/export commands with database integration
This commit is contained in:
@@ -141,11 +141,10 @@ pub async fn open_app_config_folder(handle: AppHandle) -> Result<bool, String> {
|
|||||||
pub async fn get_claude_common_config_snippet(
|
pub async fn get_claude_common_config_snippet(
|
||||||
state: tauri::State<'_, crate::store::AppState>,
|
state: tauri::State<'_, crate::store::AppState>,
|
||||||
) -> Result<Option<String>, String> {
|
) -> Result<Option<String>, String> {
|
||||||
let guard = state
|
state
|
||||||
.config
|
.db
|
||||||
.read()
|
.get_config_snippet("claude")
|
||||||
.map_err(|e| format!("读取配置锁失败: {e}"))?;
|
.map_err(|e| e.to_string())
|
||||||
Ok(guard.common_config_snippets.claude.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置 Claude 通用配置片段(已废弃,使用 set_common_config_snippet)
|
/// 设置 Claude 通用配置片段(已废弃,使用 set_common_config_snippet)
|
||||||
@@ -154,24 +153,22 @@ pub async fn set_claude_common_config_snippet(
|
|||||||
snippet: String,
|
snippet: String,
|
||||||
state: tauri::State<'_, crate::store::AppState>,
|
state: tauri::State<'_, crate::store::AppState>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let mut guard = state
|
|
||||||
.config
|
|
||||||
.write()
|
|
||||||
.map_err(|e| format!("写入配置锁失败: {e}"))?;
|
|
||||||
|
|
||||||
// 验证是否为有效的 JSON(如果不为空)
|
// 验证是否为有效的 JSON(如果不为空)
|
||||||
if !snippet.trim().is_empty() {
|
if !snippet.trim().is_empty() {
|
||||||
serde_json::from_str::<serde_json::Value>(&snippet)
|
serde_json::from_str::<serde_json::Value>(&snippet)
|
||||||
.map_err(|e| format!("无效的 JSON 格式: {e}"))?;
|
.map_err(|e| format!("无效的 JSON 格式: {e}"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
guard.common_config_snippets.claude = if snippet.trim().is_empty() {
|
let value = if snippet.trim().is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(snippet)
|
Some(snippet)
|
||||||
};
|
};
|
||||||
|
|
||||||
guard.save().map_err(|e| e.to_string())?;
|
state
|
||||||
|
.db
|
||||||
|
.set_config_snippet("claude", value)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,17 +178,10 @@ pub async fn get_common_config_snippet(
|
|||||||
app_type: String,
|
app_type: String,
|
||||||
state: tauri::State<'_, crate::store::AppState>,
|
state: tauri::State<'_, crate::store::AppState>,
|
||||||
) -> Result<Option<String>, String> {
|
) -> Result<Option<String>, String> {
|
||||||
use crate::app_config::AppType;
|
state
|
||||||
use std::str::FromStr;
|
.db
|
||||||
|
.get_config_snippet(&app_type)
|
||||||
let app = AppType::from_str(&app_type).map_err(|e| format!("无效的应用类型: {e}"))?;
|
.map_err(|e| e.to_string())
|
||||||
|
|
||||||
let guard = state
|
|
||||||
.config
|
|
||||||
.read()
|
|
||||||
.map_err(|e| format!("读取配置锁失败: {e}"))?;
|
|
||||||
|
|
||||||
Ok(guard.common_config_snippets.get(&app).cloned())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置通用配置片段(统一接口)
|
/// 设置通用配置片段(统一接口)
|
||||||
@@ -201,40 +191,31 @@ pub async fn set_common_config_snippet(
|
|||||||
snippet: String,
|
snippet: String,
|
||||||
state: tauri::State<'_, crate::store::AppState>,
|
state: tauri::State<'_, crate::store::AppState>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
use crate::app_config::AppType;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
let app = AppType::from_str(&app_type).map_err(|e| format!("无效的应用类型: {e}"))?;
|
|
||||||
|
|
||||||
let mut guard = state
|
|
||||||
.config
|
|
||||||
.write()
|
|
||||||
.map_err(|e| format!("写入配置锁失败: {e}"))?;
|
|
||||||
|
|
||||||
// 验证格式(根据应用类型)
|
// 验证格式(根据应用类型)
|
||||||
if !snippet.trim().is_empty() {
|
if !snippet.trim().is_empty() {
|
||||||
match app {
|
match app_type.as_str() {
|
||||||
AppType::Claude | AppType::Gemini => {
|
"claude" | "gemini" => {
|
||||||
// 验证 JSON 格式
|
// 验证 JSON 格式
|
||||||
serde_json::from_str::<serde_json::Value>(&snippet)
|
serde_json::from_str::<serde_json::Value>(&snippet)
|
||||||
.map_err(|e| format!("无效的 JSON 格式: {e}"))?;
|
.map_err(|e| format!("无效的 JSON 格式: {e}"))?;
|
||||||
}
|
}
|
||||||
AppType::Codex => {
|
"codex" => {
|
||||||
// TOML 格式暂不验证(或可使用 toml crate)
|
// TOML 格式暂不验证(或可使用 toml crate)
|
||||||
// 注意:TOML 验证较为复杂,暂时跳过
|
// 注意:TOML 验证较为复杂,暂时跳过
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guard.common_config_snippets.set(
|
let value = if snippet.trim().is_empty() {
|
||||||
&app,
|
None
|
||||||
if snippet.trim().is_empty() {
|
} else {
|
||||||
None
|
Some(snippet)
|
||||||
} else {
|
};
|
||||||
Some(snippet)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
guard.save().map_err(|e| e.to_string())?;
|
state
|
||||||
|
.db
|
||||||
|
.set_config_snippet(&app_type, value)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,11 +29,17 @@ pub async fn export_config_to_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 从文件导入配置
|
/// 从文件导入配置
|
||||||
|
/// TODO: 需要重构以使用数据库而不是 JSON 配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn import_config_from_file(
|
pub async fn import_config_from_file(
|
||||||
#[allow(non_snake_case)] filePath: String,
|
#[allow(non_snake_case)] _filePath: String,
|
||||||
state: State<'_, AppState>,
|
_state: State<'_, AppState>,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, String> {
|
||||||
|
// TODO: 实现基于数据库的导入逻辑
|
||||||
|
// 当前暂时禁用此功能
|
||||||
|
Err("配置导入功能正在重构中,暂时不可用".to_string())
|
||||||
|
|
||||||
|
/* 旧的实现,需要重构:
|
||||||
let (new_config, backup_id) = tauri::async_runtime::spawn_blocking(move || {
|
let (new_config, backup_id) = tauri::async_runtime::spawn_blocking(move || {
|
||||||
let path_buf = PathBuf::from(&filePath);
|
let path_buf = PathBuf::from(&filePath);
|
||||||
ConfigService::load_config_for_import(&path_buf)
|
ConfigService::load_config_for_import(&path_buf)
|
||||||
@@ -55,11 +61,18 @@ pub async fn import_config_from_file(
|
|||||||
"message": "Configuration imported successfully",
|
"message": "Configuration imported successfully",
|
||||||
"backupId": backup_id
|
"backupId": backup_id
|
||||||
}))
|
}))
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 同步当前供应商配置到对应的 live 文件
|
/// 同步当前供应商配置到对应的 live 文件
|
||||||
|
/// TODO: 需要重构以使用数据库而不是 JSON 配置
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn sync_current_providers_live(state: State<'_, AppState>) -> Result<Value, String> {
|
pub async fn sync_current_providers_live(_state: State<'_, AppState>) -> Result<Value, String> {
|
||||||
|
// TODO: 实现基于数据库的同步逻辑
|
||||||
|
// 当前暂时禁用此功能
|
||||||
|
Err("配置同步功能正在重构中,暂时不可用".to_string())
|
||||||
|
|
||||||
|
/* 旧的实现,需要重构:
|
||||||
{
|
{
|
||||||
let mut config_state = state
|
let mut config_state = state
|
||||||
.config
|
.config
|
||||||
@@ -73,6 +86,7 @@ pub async fn sync_current_providers_live(state: State<'_, AppState>) -> Result<V
|
|||||||
"success": true,
|
"success": true,
|
||||||
"message": "Live configuration synchronized"
|
"message": "Live configuration synchronized"
|
||||||
}))
|
}))
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 保存文件对话框
|
/// 保存文件对话框
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use indexmap::IndexMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@@ -82,12 +83,8 @@ pub async fn upsert_mcp_server_in_config(
|
|||||||
|
|
||||||
// 读取现有的服务器(如果存在)
|
// 读取现有的服务器(如果存在)
|
||||||
let existing_server = {
|
let existing_server = {
|
||||||
let cfg = state.config.read().map_err(|e| e.to_string())?;
|
let servers = state.db.get_all_mcp_servers().map_err(|e| e.to_string())?;
|
||||||
if let Some(servers) = &cfg.mcp.servers {
|
servers.get(&id).cloned()
|
||||||
servers.get(&id).cloned()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 构建新的统一服务器结构
|
// 构建新的统一服务器结构
|
||||||
@@ -165,7 +162,7 @@ use crate::app_config::McpServer;
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_mcp_servers(
|
pub async fn get_mcp_servers(
|
||||||
state: State<'_, AppState>,
|
state: State<'_, AppState>,
|
||||||
) -> Result<HashMap<String, McpServer>, String> {
|
) -> Result<IndexMap<String, McpServer>, String> {
|
||||||
McpService::get_all_servers(&state).map_err(|e| e.to_string())
|
McpService::get_all_servers(&state).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use indexmap::IndexMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
@@ -12,7 +12,7 @@ use crate::store::AppState;
|
|||||||
pub async fn get_prompts(
|
pub async fn get_prompts(
|
||||||
app: String,
|
app: String,
|
||||||
state: State<'_, AppState>,
|
state: State<'_, AppState>,
|
||||||
) -> Result<HashMap<String, Prompt>, String> {
|
) -> Result<IndexMap<String, Prompt>, String> {
|
||||||
let app_type = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
let app_type = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
||||||
PromptService::get_prompts(&state, app_type).map_err(|e| e.to_string())
|
PromptService::get_prompts(&state, app_type).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use indexmap::IndexMap;
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
use crate::app_config::AppType;
|
use crate::app_config::AppType;
|
||||||
@@ -13,7 +13,7 @@ use std::str::FromStr;
|
|||||||
pub fn get_providers(
|
pub fn get_providers(
|
||||||
state: State<'_, AppState>,
|
state: State<'_, AppState>,
|
||||||
app: String,
|
app: String,
|
||||||
) -> Result<HashMap<String, Provider>, String> {
|
) -> Result<IndexMap<String, Provider>, String> {
|
||||||
let app_type = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
let app_type = AppType::from_str(&app).map_err(|e| e.to_string())?;
|
||||||
ProviderService::list(state.inner(), app_type).map_err(|e| e.to_string())
|
ProviderService::list(state.inner(), app_type).map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ pub async fn get_skills(
|
|||||||
service: State<'_, SkillServiceState>,
|
service: State<'_, SkillServiceState>,
|
||||||
app_state: State<'_, AppState>,
|
app_state: State<'_, AppState>,
|
||||||
) -> Result<Vec<Skill>, String> {
|
) -> Result<Vec<Skill>, String> {
|
||||||
let repos = {
|
let repos = app_state.db.get_skill_repos().map_err(|e| e.to_string())?;
|
||||||
let config = app_state.config.read().map_err(|e| e.to_string())?;
|
|
||||||
config.skills.repos.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
service
|
service
|
||||||
.0
|
.0
|
||||||
@@ -32,10 +29,7 @@ pub async fn install_skill(
|
|||||||
app_state: State<'_, AppState>,
|
app_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
// 先在不持有写锁的情况下收集仓库与技能信息
|
// 先在不持有写锁的情况下收集仓库与技能信息
|
||||||
let repos = {
|
let repos = app_state.db.get_skill_repos().map_err(|e| e.to_string())?;
|
||||||
let config = app_state.config.read().map_err(|e| e.to_string())?;
|
|
||||||
config.skills.repos.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let skills = service
|
let skills = service
|
||||||
.0
|
.0
|
||||||
@@ -85,19 +79,16 @@ pub async fn install_skill(
|
|||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
app_state
|
||||||
let mut config = app_state.config.write().map_err(|e| e.to_string())?;
|
.db
|
||||||
|
.update_skill_state(
|
||||||
config.skills.skills.insert(
|
&directory,
|
||||||
directory.clone(),
|
&SkillState {
|
||||||
SkillState {
|
|
||||||
installed: true,
|
installed: true,
|
||||||
installed_at: Utc::now(),
|
installed_at: Utc::now(),
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
}
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
app_state.save().map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
@@ -113,13 +104,17 @@ pub fn uninstall_skill(
|
|||||||
.uninstall_skill(directory.clone())
|
.uninstall_skill(directory.clone())
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
{
|
// Remove from database by setting installed = false
|
||||||
let mut config = app_state.config.write().map_err(|e| e.to_string())?;
|
app_state
|
||||||
|
.db
|
||||||
config.skills.skills.remove(&directory);
|
.update_skill_state(
|
||||||
}
|
&directory,
|
||||||
|
&SkillState {
|
||||||
app_state.save().map_err(|e| e.to_string())?;
|
installed: false,
|
||||||
|
installed_at: Utc::now(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
@@ -129,28 +124,19 @@ pub fn get_skill_repos(
|
|||||||
_service: State<'_, SkillServiceState>,
|
_service: State<'_, SkillServiceState>,
|
||||||
app_state: State<'_, AppState>,
|
app_state: State<'_, AppState>,
|
||||||
) -> Result<Vec<SkillRepo>, String> {
|
) -> Result<Vec<SkillRepo>, String> {
|
||||||
let config = app_state.config.read().map_err(|e| e.to_string())?;
|
app_state.db.get_skill_repos().map_err(|e| e.to_string())
|
||||||
|
|
||||||
Ok(config.skills.repos.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn add_skill_repo(
|
pub fn add_skill_repo(
|
||||||
repo: SkillRepo,
|
repo: SkillRepo,
|
||||||
service: State<'_, SkillServiceState>,
|
_service: State<'_, SkillServiceState>,
|
||||||
app_state: State<'_, AppState>,
|
app_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
{
|
app_state
|
||||||
let mut config = app_state.config.write().map_err(|e| e.to_string())?;
|
.db
|
||||||
|
.save_skill_repo(&repo)
|
||||||
service
|
.map_err(|e| e.to_string())?;
|
||||||
.0
|
|
||||||
.add_repo(&mut config.skills, repo)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
app_state.save().map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,19 +144,12 @@ pub fn add_skill_repo(
|
|||||||
pub fn remove_skill_repo(
|
pub fn remove_skill_repo(
|
||||||
owner: String,
|
owner: String,
|
||||||
name: String,
|
name: String,
|
||||||
service: State<'_, SkillServiceState>,
|
_service: State<'_, SkillServiceState>,
|
||||||
app_state: State<'_, AppState>,
|
app_state: State<'_, AppState>,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
{
|
app_state
|
||||||
let mut config = app_state.config.write().map_err(|e| e.to_string())?;
|
.db
|
||||||
|
.delete_skill_repo(&owner, &name)
|
||||||
service
|
.map_err(|e| e.to_string())?;
|
||||||
.0
|
|
||||||
.remove_repo(&mut config.skills, owner, name)
|
|
||||||
.map_err(|e| e.to_string())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
app_state.save().map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user