From c09e0378b9b63a19098b4a8b3b20cf48d8fa5d70 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Wed, 24 Dec 2025 23:43:52 +0800 Subject: [PATCH] refactor(proxy): update service layer for per-app config structure Adapt proxy service, handler context, and provider router to use the new per-app configuration model. Read enabled/timeout settings from proxy_config table instead of settings table. --- src-tauri/src/proxy/handler_context.rs | 31 +++-- src-tauri/src/proxy/provider_router.rs | 35 +++--- src-tauri/src/services/proxy.rs | 150 ++++++++++++++++--------- 3 files changed, 132 insertions(+), 84 deletions(-) diff --git a/src-tauri/src/proxy/handler_context.rs b/src-tauri/src/proxy/handler_context.rs index 3105b7eb0..86bce211d 100644 --- a/src-tauri/src/proxy/handler_context.rs +++ b/src-tauri/src/proxy/handler_context.rs @@ -5,7 +5,7 @@ use crate::app_config::AppType; use crate::provider::Provider; use crate::proxy::{ - forwarder::RequestForwarder, server::ProxyState, types::ProxyConfig, ProxyError, + forwarder::RequestForwarder, server::ProxyState, types::AppProxyConfig, ProxyError, }; use std::time::Instant; @@ -22,15 +22,15 @@ pub struct StreamingTimeoutConfig { /// /// 贯穿整个请求生命周期,包含: /// - 计时信息 -/// - 代理配置 +/// - 应用级代理配置(per-app) /// - 选中的 Provider 列表(用于故障转移) /// - 请求模型名称 /// - 日志标签 pub struct RequestContext { /// 请求开始时间 pub start_time: Instant, - /// 代理配置快照 - pub config: ProxyConfig, + /// 应用级代理配置(per-app,包含重试次数和超时配置) + pub app_config: AppProxyConfig, /// 选中的 Provider(故障转移链的第一个) pub provider: Provider, /// 完整的 Provider 列表(用于故障转移) @@ -71,7 +71,14 @@ impl RequestContext { app_type_str: &'static str, ) -> Result { let start_time = Instant::now(); - let config = state.config.read().await.clone(); + + // 从数据库读取应用级代理配置(per-app) + let app_config = state + .db + .get_proxy_config_for_app(app_type_str) + .await + .map_err(|e| ProxyError::DatabaseError(e.to_string()))?; + let current_provider_id = crate::settings::get_current_provider(&app_type).unwrap_or_default(); @@ -105,7 +112,7 @@ impl RequestContext { Ok(Self { start_time, - config, + app_config, provider, providers, current_provider_id, @@ -144,15 +151,15 @@ impl RequestContext { pub fn create_forwarder(&self, state: &ProxyState) -> RequestForwarder { RequestForwarder::new( state.provider_router.clone(), - self.config.non_streaming_timeout, - self.config.max_retries, + self.app_config.non_streaming_timeout as u64, + self.app_config.max_retries as u8, state.status.clone(), state.current_providers.clone(), state.failover_manager.clone(), state.app_handle.clone(), self.current_provider_id.clone(), - self.config.streaming_first_byte_timeout, - self.config.streaming_idle_timeout, + self.app_config.streaming_first_byte_timeout as u64, + self.app_config.streaming_idle_timeout as u64, ) } @@ -173,8 +180,8 @@ impl RequestContext { #[inline] pub fn streaming_timeout_config(&self) -> StreamingTimeoutConfig { StreamingTimeoutConfig { - first_byte_timeout: self.config.streaming_first_byte_timeout, - idle_timeout: self.config.streaming_idle_timeout, + first_byte_timeout: self.app_config.streaming_first_byte_timeout as u64, + idle_timeout: self.app_config.streaming_idle_timeout as u64, } } } diff --git a/src-tauri/src/proxy/provider_router.rs b/src-tauri/src/proxy/provider_router.rs index dbd1ee008..248873f66 100644 --- a/src-tauri/src/proxy/provider_router.rs +++ b/src-tauri/src/proxy/provider_router.rs @@ -35,25 +35,16 @@ impl ProviderRouter { pub async fn select_providers(&self, app_type: &str) -> Result, AppError> { let mut result = Vec::new(); - // 检查该应用的自动故障转移开关是否开启 - let failover_key = format!("auto_failover_enabled_{app_type}"); - let auto_failover_enabled = match self.db.get_setting(&failover_key) { - Ok(Some(value)) => { - let enabled = value == "true"; - log::info!( - "[{app_type}] Failover setting '{failover_key}' = '{value}', enabled: {enabled}" - ); + // 检查该应用的自动故障转移开关是否开启(从 proxy_config 表读取) + let auto_failover_enabled = match self.db.get_proxy_config_for_app(app_type).await { + Ok(config) => { + let enabled = config.auto_failover_enabled; + log::info!("[{app_type}] Failover enabled from proxy_config: {enabled}"); enabled } - Ok(None) => { - log::warn!( - "[{app_type}] Failover setting '{failover_key}' not found in database, defaulting to disabled" - ); - false - } 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 } @@ -315,8 +306,11 @@ mod tests { db.add_to_failover_queue("claude", "b").unwrap(); db.add_to_failover_queue("claude", "a").unwrap(); - db.set_setting("auto_failover_enabled_claude", "true") - .unwrap(); + + // 启用自动故障转移(使用新的 proxy_config API) + let mut config = db.get_proxy_config_for_app("claude").await.unwrap(); + config.auto_failover_enabled = true; + db.update_proxy_config_for_app(config).await.unwrap(); let router = ProviderRouter::new(db.clone()); let providers = router.select_providers("claude").await.unwrap(); @@ -349,8 +343,11 @@ mod tests { db.add_to_failover_queue("claude", "a").unwrap(); db.add_to_failover_queue("claude", "b").unwrap(); - db.set_setting("auto_failover_enabled_claude", "true") - .unwrap(); + + // 启用自动故障转移(使用新的 proxy_config API) + let mut config = db.get_proxy_config_for_app("claude").await.unwrap(); + config.auto_failover_enabled = true; + db.update_proxy_config_for_app(config).await.unwrap(); let router = ProviderRouter::new(db.clone()); diff --git a/src-tauri/src/services/proxy.rs b/src-tauri/src/services/proxy.rs index 03570eb05..29b5b3157 100644 --- a/src-tauri/src/services/proxy.rs +++ b/src-tauri/src/services/proxy.rs @@ -43,7 +43,22 @@ impl ProxyService { /// 启动代理服务器 pub async fn start(&self) -> Result { - // 1. 获取配置 + // 1. 启动时自动设置 proxy_enabled = true + let mut global_config = self + .db + .get_global_proxy_config() + .await + .map_err(|e| format!("获取全局代理配置失败: {e}"))?; + + if !global_config.proxy_enabled { + global_config.proxy_enabled = true; + self.db + .update_global_proxy_config(global_config.clone()) + .await + .map_err(|e| format!("更新代理总开关失败: {e}"))?; + } + + // 2. 获取配置 let config = self .db .get_proxy_config() @@ -115,14 +130,7 @@ impl ProxyService { return Err(e); } - // 5. 设置 settings 表中所有应用的接管状态(用于重启后自动恢复) - for app in ["claude", "codex", "gemini"] { - if let Err(e) = self.db.set_proxy_takeover_enabled(app, true) { - log::warn!("设置 {app} 接管状态失败: {e}"); - } - } - - // 6. 启动代理服务器 + // 5. 启动代理服务器 match self.start().await { Ok(info) => Ok(info), Err(e) => { @@ -132,8 +140,6 @@ impl ProxyService { Ok(()) => { let _ = self.db.set_live_takeover_active(false).await; let _ = self.db.delete_all_live_backups().await; - // 清除 settings 状态 - let _ = self.db.clear_all_proxy_takeover(); } Err(restore_err) => { log::error!("恢复原始配置失败,将保留备份以便下次启动恢复: {restore_err}"); @@ -146,29 +152,30 @@ impl ProxyService { /// 获取各应用的接管状态(是否改写该应用的 Live 配置指向本地代理) pub async fn get_takeover_status(&self) -> Result { - let claude = self + // 从 proxy_config.enabled 读取(优先),兼容旧的 live_backup 备份检测 + let claude_enabled = self .db - .get_live_backup("claude") + .get_proxy_config_for_app("claude") .await - .map_err(|e| format!("获取 Claude 接管状态失败: {e}"))? - .is_some(); - let codex = self + .map(|c| c.enabled) + .unwrap_or(false); + let codex_enabled = self .db - .get_live_backup("codex") + .get_proxy_config_for_app("codex") .await - .map_err(|e| format!("获取 Codex 接管状态失败: {e}"))? - .is_some(); - let gemini = self + .map(|c| c.enabled) + .unwrap_or(false); + let gemini_enabled = self .db - .get_live_backup("gemini") + .get_proxy_config_for_app("gemini") .await - .map_err(|e| format!("获取 Gemini 接管状态失败: {e}"))? - .is_some(); + .map(|c| c.enabled) + .unwrap_or(false); Ok(ProxyTakeoverStatus { - claude, - codex, - gemini, + claude: claude_enabled, + codex: codex_enabled, + gemini: gemini_enabled, }) } @@ -187,13 +194,13 @@ impl ProxyService { } // 2) 已接管则直接返回(幂等) - if self + let current_config = self .db - .get_live_backup(app_type_str) + .get_proxy_config_for_app(app_type_str) .await - .map_err(|e| format!("检查 {app_type_str} Live 备份失败: {e}"))? - .is_some() - { + .map_err(|e| format!("获取 {app_type_str} 配置失败: {e}"))?; + + if current_config.enabled { return Ok(()); } @@ -223,25 +230,32 @@ impl ProxyService { return Err(e); } - // 6) 设置 settings 表中的接管状态 + // 6) 设置 proxy_config.enabled = true + let mut updated_config = self + .db + .get_proxy_config_for_app(app_type_str) + .await + .map_err(|e| format!("获取 {app_type_str} 配置失败: {e}"))?; + updated_config.enabled = true; self.db - .set_proxy_takeover_enabled(app_type_str, true) - .map_err(|e| format!("设置 {app_type_str} 接管状态失败: {e}"))?; + .update_proxy_config_for_app(updated_config) + .await + .map_err(|e| format!("设置 {app_type_str} enabled 状态失败: {e}"))?; // 7) 兼容旧逻辑:写入 any-of 标志(失败不影响功能) let _ = self.db.set_live_takeover_active(true).await; return Ok(()); } - // 关闭接管:无备份则视为未接管(幂等) - let has_backup = self + // 关闭接管:检查 enabled 状态 + let current_config = self .db - .get_live_backup(app_type_str) + .get_proxy_config_for_app(app_type_str) .await - .map_err(|e| format!("检查 {app_type_str} Live 备份失败: {e}"))? - .is_some(); - if !has_backup { - return Ok(()); + .map_err(|e| format!("获取 {app_type_str} 配置失败: {e}"))?; + + if !current_config.enabled { + return Ok(()); // 未接管,幂等返回 } // 1) 恢复 Live 配置 @@ -253,10 +267,17 @@ impl ProxyService { .await .map_err(|e| format!("删除 {app_type_str} Live 备份失败: {e}"))?; - // 3) 清除 settings 表中该应用的接管状态 + // 3) 设置 proxy_config.enabled = false + let mut updated_config = self + .db + .get_proxy_config_for_app(app_type_str) + .await + .map_err(|e| format!("获取 {app_type_str} 配置失败: {e}"))?; + updated_config.enabled = false; self.db - .set_proxy_takeover_enabled(app_type_str, false) - .map_err(|e| format!("清除 {app_type_str} 接管状态失败: {e}"))?; + .update_proxy_config_for_app(updated_config) + .await + .map_err(|e| format!("清除 {app_type_str} enabled 状态失败: {e}"))?; // 4) 清除该应用的健康状态(关闭代理时重置队列状态) self.db @@ -265,12 +286,14 @@ impl ProxyService { .map_err(|e| format!("清除 {app_type_str} 健康状态失败: {e}"))?; // 5) 若无其它接管,更新旧标志,并停止代理服务 - let has_any_backup = self + // 检查是否还有其它 app 的 enabled = true + let any_enabled = self .db - .has_any_live_backup() + .is_live_takeover_active() .await - .map_err(|e| format!("检查 Live 备份失败: {e}"))?; - if !has_any_backup { + .map_err(|e| format!("检查接管状态失败: {e}"))?; + + if !any_enabled { let _ = self.db.set_live_takeover_active(false).await; if self.is_running().await { @@ -502,6 +525,20 @@ impl ProxyService { .await .map_err(|e| format!("停止代理服务器失败: {e}"))?; + // 停止时设置 proxy_enabled = false + let mut global_config = self + .db + .get_global_proxy_config() + .await + .map_err(|e| format!("获取全局代理配置失败: {e}"))?; + + if global_config.proxy_enabled { + global_config.proxy_enabled = false; + if let Err(e) = self.db.update_global_proxy_config(global_config).await { + log::warn!("更新代理总开关失败: {e}"); + } + } + log::info!("代理服务器已停止"); Ok(()) } else { @@ -527,10 +564,17 @@ impl ProxyService { .await .map_err(|e| format!("清除接管状态失败: {e}"))?; - // 4. 清除 settings 表中的代理状态(用户手动关闭,不需要下次自动恢复) - self.db - .clear_all_proxy_takeover() - .map_err(|e| format!("清除代理状态失败: {e}"))?; + // 4. 清除所有应用的 enabled 状态(用户手动关闭,不需要下次自动恢复) + for app_type in ["claude", "codex", "gemini"] { + if let Ok(mut config) = self.db.get_proxy_config_for_app(app_type).await { + if config.enabled { + config.enabled = false; + if let Err(e) = self.db.update_proxy_config_for_app(config).await { + log::warn!("清除 {app_type} enabled 状态失败: {e}"); + } + } + } + } // 5. 删除备份 self.db @@ -562,7 +606,7 @@ impl ProxyService { self.restore_live_configs().await?; // 3. 更新 proxy_config 表中的 live_takeover_active 标志(兼容旧版) - // 注意:仅更新 proxy_config 表,不清除 settings 表中的 proxy_takeover_* 状态 + // 注意:保留 proxy_config.enabled 状态,下次启动时自动恢复 if let Ok(mut config) = self.db.get_proxy_config().await { config.live_takeover_active = false; let _ = self.db.update_proxy_config(config).await;