diff --git a/src-tauri/src/commands/failover.rs b/src-tauri/src/commands/failover.rs index 83558514c..4c1e71d56 100644 --- a/src-tauri/src/commands/failover.rs +++ b/src-tauri/src/commands/failover.rs @@ -56,21 +56,21 @@ pub async fn remove_from_failover_queue( .map_err(|e| e.to_string()) } -/// 获取指定应用的自动故障转移开关状态 +/// 获取指定应用的自动故障转移开关状态(从 proxy_config 表读取) #[tauri::command] pub async fn get_auto_failover_enabled( state: tauri::State<'_, AppState>, app_type: String, ) -> Result { - let key = format!("auto_failover_enabled_{app_type}"); state .db - .get_setting(&key) - .map(|v| v.map(|s| s == "true").unwrap_or(false)) // 默认关闭 + .get_proxy_config_for_app(&app_type) + .await + .map(|config| config.auto_failover_enabled) .map_err(|e| e.to_string()) } -/// 设置指定应用的自动故障转移开关状态 +/// 设置指定应用的自动故障转移开关状态(写入 proxy_config 表) /// /// 注意:关闭故障转移时不会清除队列,队列内容会保留供下次开启时使用 #[tauri::command] @@ -79,12 +79,24 @@ pub async fn set_auto_failover_enabled( app_type: String, enabled: bool, ) -> Result<(), String> { - let key = format!("auto_failover_enabled_{app_type}"); - let value = if enabled { "true" } else { "false" }; - log::info!( - "[Failover] Setting auto_failover_enabled: key='{key}', value='{value}', app_type='{app_type}'" + "[Failover] Setting auto_failover_enabled: app_type='{app_type}', enabled={enabled}" ); - state.db.set_setting(&key, value).map_err(|e| e.to_string()) + // 读取当前配置 + let mut config = state + .db + .get_proxy_config_for_app(&app_type) + .await + .map_err(|e| e.to_string())?; + + // 更新 auto_failover_enabled 字段 + config.auto_failover_enabled = enabled; + + // 写回数据库 + state + .db + .update_proxy_config_for_app(config) + .await + .map_err(|e| e.to_string()) } diff --git a/src-tauri/src/commands/proxy.rs b/src-tauri/src/commands/proxy.rs index 27ce31c00..37be402cf 100644 --- a/src-tauri/src/commands/proxy.rs +++ b/src-tauri/src/commands/proxy.rs @@ -62,6 +62,63 @@ pub async fn update_proxy_config( state.proxy_service.update_config(&config).await } +// ==================== Global & Per-App Config ==================== + +/// 获取全局代理配置 +/// +/// 返回统一的全局配置字段(代理开关、监听地址、端口、日志开关) +#[tauri::command] +pub async fn get_global_proxy_config( + state: tauri::State<'_, AppState>, +) -> Result { + let db = &state.db; + db.get_global_proxy_config() + .await + .map_err(|e| e.to_string()) +} + +/// 更新全局代理配置 +/// +/// 更新统一的全局配置字段,会同时更新三行(claude/codex/gemini) +#[tauri::command] +pub async fn update_global_proxy_config( + state: tauri::State<'_, AppState>, + config: GlobalProxyConfig, +) -> Result<(), String> { + let db = &state.db; + db.update_global_proxy_config(config) + .await + .map_err(|e| e.to_string()) +} + +/// 获取指定应用的代理配置 +/// +/// 返回应用级配置(enabled、auto_failover、超时、熔断器等) +#[tauri::command] +pub async fn get_proxy_config_for_app( + state: tauri::State<'_, AppState>, + app_type: String, +) -> Result { + let db = &state.db; + db.get_proxy_config_for_app(&app_type) + .await + .map_err(|e| e.to_string()) +} + +/// 更新指定应用的代理配置 +/// +/// 更新应用级配置(enabled、auto_failover、超时、熔断器等) +#[tauri::command] +pub async fn update_proxy_config_for_app( + state: tauri::State<'_, AppState>, + config: AppProxyConfig, +) -> Result<(), String> { + let db = &state.db; + db.update_proxy_config_for_app(config) + .await + .map_err(|e| e.to_string()) +} + /// 检查代理服务器是否正在运行 #[tauri::command] pub async fn is_proxy_running(state: tauri::State<'_, AppState>) -> Result { @@ -126,19 +183,12 @@ pub async fn reset_circuit_breaker( .reset_provider_circuit_breaker(&provider_id, &app_type) .await?; - // 3. 检查是否应该切回优先级更高的供应商 - let failover_key = format!("auto_failover_enabled_{app_type}"); - let auto_failover_enabled = match db.get_setting(&failover_key) { - Ok(Some(value)) => value == "true", - Ok(None) => { - log::debug!( - "[{app_type}] Failover setting '{failover_key}' not found, defaulting to disabled" - ); - false - } + // 3. 检查是否应该切回优先级更高的供应商(从 proxy_config 表读取) + let auto_failover_enabled = match db.get_proxy_config_for_app(&app_type).await { + Ok(config) => config.auto_failover_enabled, Err(e) => { log::error!( - "[{app_type}] Failed to read failover setting '{failover_key}': {e}, defaulting to disabled" + "[{app_type}] Failed to read proxy_config for auto_failover_enabled: {e}, defaulting to disabled" ); false } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 27110f225..556c326b6 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -596,7 +596,7 @@ pub fn run() { commands::upsert_mcp_server_in_config, commands::delete_mcp_server_in_config, commands::set_mcp_enabled, - // v3.7.0: Unified MCP management + // Unified MCP management commands::get_mcp_servers, commands::upsert_mcp_server, commands::delete_mcp_server, @@ -656,6 +656,11 @@ pub fn run() { commands::get_proxy_status, commands::get_proxy_config, commands::update_proxy_config, + // Global & Per-App Config + commands::get_global_proxy_config, + commands::update_global_proxy_config, + commands::get_proxy_config_for_app, + commands::update_proxy_config_for_app, commands::is_proxy_running, commands::is_live_takeover_active, commands::switch_proxy_provider, @@ -845,22 +850,20 @@ pub async fn cleanup_before_exit(app_handle: &tauri::AppHandle) { // 启动时恢复代理状态 // ============================================================ -/// 启动时根据 settings 表中的代理状态自动恢复代理服务 +/// 启动时根据 proxy_config 表中的代理状态自动恢复代理服务 /// -/// 检查 `proxy_takeover_claude`、`proxy_takeover_codex`、`proxy_takeover_gemini` 的值, -/// 如果有任一应用的状态为 `true`,则自动启动代理服务并接管对应应用的 Live 配置。 +/// 检查 `proxy_config.enabled` 字段,如果有任一应用的状态为 `true`, +/// 则自动启动代理服务并接管对应应用的 Live 配置。 async fn restore_proxy_state_on_startup(state: &store::AppState) { - // 收集需要恢复接管的应用列表 - let apps_to_restore: Vec<&str> = ["claude", "codex", "gemini"] - .iter() - .filter(|app_type| { - state - .db - .get_proxy_takeover_enabled(app_type) - .unwrap_or(false) - }) - .copied() - .collect(); + // 收集需要恢复接管的应用列表(从 proxy_config.enabled 读取) + let mut apps_to_restore = Vec::new(); + for app_type in ["claude", "codex", "gemini"] { + if let Ok(config) = state.db.get_proxy_config_for_app(app_type).await { + if config.enabled { + apps_to_restore.push(app_type); + } + } + } if apps_to_restore.is_empty() { log::debug!("启动时无需恢复代理状态"); @@ -882,7 +885,11 @@ async fn restore_proxy_state_on_startup(state: &store::AppState) { Err(e) => { log::error!("✗ 恢复 {app_type} 的代理接管状态失败: {e}"); // 失败时清除该应用的状态,避免下次启动再次尝试 - if let Err(clear_err) = state.db.set_proxy_takeover_enabled(app_type, false) { + if let Err(clear_err) = state + .proxy_service + .set_takeover_for_app(app_type, false) + .await + { log::error!("清除 {app_type} 代理状态失败: {clear_err}"); } }