mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 21:30:17 +08:00
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.
This commit is contained in:
@@ -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<Self, ProxyError> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,25 +35,16 @@ impl ProviderRouter {
|
||||
pub async fn select_providers(&self, app_type: &str) -> Result<Vec<Provider>, 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());
|
||||
|
||||
|
||||
@@ -43,7 +43,22 @@ impl ProxyService {
|
||||
|
||||
/// 启动代理服务器
|
||||
pub async fn start(&self) -> Result<ProxyServerInfo, String> {
|
||||
// 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<ProxyTakeoverStatus, String> {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user