mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-03-24 16:33:48 +08:00
refactor(proxy): remove global auto-start flag
- Remove global proxy auto-start flag from config and UI. - Simplify per-app takeover start/stop and stop server when the last takeover is disabled. - Restore live takeover detection used for crash recovery. - Keep proxy_config.enabled column but always write 0 for compatibility. - Tests: not run (not requested).
This commit is contained in:
@@ -11,7 +11,7 @@ use crate::store::AppState;
|
||||
pub async fn start_proxy_server(
|
||||
state: tauri::State<'_, AppState>,
|
||||
) -> Result<ProxyServerInfo, String> {
|
||||
state.proxy_service.start(true).await
|
||||
state.proxy_service.start().await
|
||||
}
|
||||
|
||||
/// 启动代理服务器(带 Live 配置接管)
|
||||
|
||||
@@ -16,19 +16,18 @@ impl Database {
|
||||
let result = {
|
||||
let conn = lock_conn!(self.conn);
|
||||
conn.query_row(
|
||||
"SELECT enabled, listen_address, listen_port, max_retries,
|
||||
"SELECT listen_address, listen_port, max_retries,
|
||||
request_timeout, enable_logging, live_takeover_active
|
||||
FROM proxy_config WHERE id = 1",
|
||||
[],
|
||||
|row| {
|
||||
Ok(ProxyConfig {
|
||||
enabled: row.get::<_, i32>(0)? != 0,
|
||||
listen_address: row.get(1)?,
|
||||
listen_port: row.get::<_, i32>(2)? as u16,
|
||||
max_retries: row.get::<_, i32>(3)? as u8,
|
||||
request_timeout: row.get::<_, i32>(4)? as u64,
|
||||
enable_logging: row.get::<_, i32>(5)? != 0,
|
||||
live_takeover_active: row.get::<_, i32>(6).unwrap_or(0) != 0,
|
||||
listen_address: row.get(0)?,
|
||||
listen_port: row.get::<_, i32>(1)? as u16,
|
||||
max_retries: row.get::<_, i32>(2)? as u8,
|
||||
request_timeout: row.get::<_, i32>(3)? as u64,
|
||||
enable_logging: row.get::<_, i32>(4)? != 0,
|
||||
live_takeover_active: row.get::<_, i32>(5).unwrap_or(0) != 0,
|
||||
})
|
||||
},
|
||||
)
|
||||
@@ -57,7 +56,7 @@ impl Database {
|
||||
COALESCE((SELECT created_at FROM proxy_config WHERE id = 1), datetime('now')),
|
||||
datetime('now'))",
|
||||
rusqlite::params![
|
||||
if config.enabled { 1 } else { 0 },
|
||||
0, // 已移除自动启用逻辑,保留列但固定为 0
|
||||
config.listen_address,
|
||||
config.listen_port as i32,
|
||||
config.max_retries as i32,
|
||||
|
||||
@@ -524,12 +524,12 @@ pub fn run() {
|
||||
}
|
||||
}
|
||||
|
||||
// 异常退出恢复 + 自动启动代理服务器
|
||||
// 异常退出恢复
|
||||
let app_handle = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let state = app_handle.state::<AppState>();
|
||||
|
||||
// 检查是否有 Live 备份(表示上次有接管状态)
|
||||
// 检查是否有 Live 备份(表示上次异常退出时可能处于接管状态)
|
||||
let has_backups = match state.db.has_any_live_backup().await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
@@ -537,55 +537,15 @@ pub fn run() {
|
||||
false
|
||||
}
|
||||
};
|
||||
// 检查 Live 配置是否仍处于被接管状态(包含占位符)
|
||||
let live_taken_over = state.proxy_service.detect_takeover_in_live_configs();
|
||||
|
||||
// 获取代理配置
|
||||
let proxy_config = match state.db.get_proxy_config().await {
|
||||
Ok(config) => Some(config),
|
||||
Err(e) => {
|
||||
log::error!("启动时获取代理配置失败: {e}");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if has_backups {
|
||||
// 有备份说明上次退出时有接管状态
|
||||
// 检查 Live 配置是否仍处于被接管状态(包含占位符)
|
||||
let live_taken_over = state.proxy_service.detect_takeover_in_live_configs();
|
||||
|
||||
if live_taken_over {
|
||||
// Live 配置仍是接管状态,尝试重新启动代理服务以恢复接管
|
||||
log::info!("检测到上次接管状态,正在重新启动代理服务...");
|
||||
match state.proxy_service.start(false).await {
|
||||
Ok(info) => {
|
||||
log::info!("代理服务器已恢复启动: {}:{}", info.address, info.port);
|
||||
}
|
||||
Err(e) => {
|
||||
// 启动失败,恢复 Live 配置
|
||||
log::error!("恢复代理服务失败: {e},正在恢复 Live 配置...");
|
||||
if let Err(e) = state.proxy_service.recover_from_crash().await {
|
||||
log::error!("恢复 Live 配置失败: {e}");
|
||||
} else {
|
||||
log::info!("Live 配置已恢复");
|
||||
}
|
||||
}
|
||||
}
|
||||
if has_backups || live_taken_over {
|
||||
log::warn!("检测到上次异常退出(存在接管残留),正在恢复 Live 配置...");
|
||||
if let Err(e) = state.proxy_service.recover_from_crash().await {
|
||||
log::error!("恢复 Live 配置失败: {e}");
|
||||
} else {
|
||||
// Live 配置已经是正常状态,清理残留备份
|
||||
log::info!("Live 配置已是正常状态,清理残留备份...");
|
||||
if let Err(e) = state.db.delete_all_live_backups().await {
|
||||
log::warn!("清理残留 Live 备份失败: {e}");
|
||||
}
|
||||
}
|
||||
} else if let Some(config) = proxy_config {
|
||||
// 没有备份,检查是否需要自动启动代理服务器(总开关)
|
||||
if config.enabled {
|
||||
log::info!("代理服务配置为启用,正在启动...");
|
||||
match state.proxy_service.start(true).await {
|
||||
Ok(info) => {
|
||||
log::info!("代理服务器自动启动成功: {}:{}", info.address, info.port)
|
||||
}
|
||||
Err(e) => log::error!("代理服务器自动启动失败: {e}"),
|
||||
}
|
||||
log::info!("Live 配置已恢复");
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -855,20 +815,26 @@ pub async fn cleanup_before_exit(app_handle: &tauri::AppHandle) {
|
||||
if proxy_service.is_running().await {
|
||||
log::info!("检测到代理服务器正在运行,开始清理...");
|
||||
|
||||
// 检查是否处于 Live 接管模式
|
||||
if let Ok(is_takeover) = state.db.is_live_takeover_active().await {
|
||||
if is_takeover {
|
||||
// 接管模式:停止并恢复配置
|
||||
if let Err(e) = proxy_service.stop_with_restore().await {
|
||||
log::error!("退出时恢复 Live 配置失败: {e}");
|
||||
} else {
|
||||
log::info!("已恢复 Live 配置");
|
||||
}
|
||||
// 检查是否存在 Live 备份(有则视为接管)
|
||||
let has_backups = match state.db.has_any_live_backup().await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
log::error!("退出时检查 Live 备份失败: {e}");
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if has_backups {
|
||||
// 接管模式:停止并恢复配置
|
||||
if let Err(e) = proxy_service.stop_with_restore().await {
|
||||
log::error!("退出时恢复 Live 配置失败: {e}");
|
||||
} else {
|
||||
// 非接管模式:仅停止代理
|
||||
if let Err(e) = proxy_service.stop().await {
|
||||
log::error!("退出时停止代理失败: {e}");
|
||||
}
|
||||
log::info!("已恢复 Live 配置");
|
||||
}
|
||||
} else {
|
||||
// 非接管模式:仅停止代理
|
||||
if let Err(e) = proxy_service.stop().await {
|
||||
log::error!("退出时停止代理失败: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ use serde::{Deserialize, Serialize};
|
||||
/// 代理服务器配置
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ProxyConfig {
|
||||
/// 是否启用代理服务
|
||||
pub enabled: bool,
|
||||
/// 监听地址
|
||||
pub listen_address: String,
|
||||
/// 监听端口
|
||||
@@ -23,7 +21,6 @@ pub struct ProxyConfig {
|
||||
impl Default for ProxyConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
listen_address: "127.0.0.1".to_string(),
|
||||
listen_port: 15721, // 使用较少占用的高位端口
|
||||
max_retries: 3,
|
||||
|
||||
@@ -41,31 +41,16 @@ impl ProxyService {
|
||||
}
|
||||
|
||||
/// 启动代理服务器
|
||||
///
|
||||
/// - `persist_enabled = true`:将 `proxy_config.enabled` 持久化为启用(用于“总开关”)
|
||||
/// - `persist_enabled = false`:仅在当前进程启动代理服务(用于“按 App 接管”自动启动)
|
||||
pub async fn start(&self, persist_enabled: bool) -> Result<ProxyServerInfo, String> {
|
||||
pub async fn start(&self) -> Result<ProxyServerInfo, String> {
|
||||
// 1. 获取配置
|
||||
let mut config = self
|
||||
let config = self
|
||||
.db
|
||||
.get_proxy_config()
|
||||
.await
|
||||
.map_err(|e| format!("获取代理配置失败: {e}"))?;
|
||||
|
||||
// 2. 仅在需要时持久化 enabled(避免“按 App 接管”自动启动时误打开总开关)
|
||||
if persist_enabled {
|
||||
config.enabled = true;
|
||||
}
|
||||
|
||||
// 3. 若已在运行:确保持久化状态(如需要)并返回当前信息
|
||||
if let Some(server) = self.server.read().await.as_ref() {
|
||||
if persist_enabled {
|
||||
self.db
|
||||
.update_proxy_config(config)
|
||||
.await
|
||||
.map_err(|e| format!("保存代理配置失败: {e}"))?;
|
||||
}
|
||||
|
||||
let status = server.get_status().await;
|
||||
return Ok(ProxyServerInfo {
|
||||
address: status.address,
|
||||
@@ -86,14 +71,6 @@ impl ProxyService {
|
||||
// 5. 保存服务器实例
|
||||
*self.server.write().await = Some(server);
|
||||
|
||||
// 6. 持久化 enabled 状态(仅总开关)
|
||||
if persist_enabled {
|
||||
self.db
|
||||
.update_proxy_config(config)
|
||||
.await
|
||||
.map_err(|e| format!("保存代理配置失败: {e}"))?;
|
||||
}
|
||||
|
||||
log::info!("代理服务器已启动: {}:{}", info.address, info.port);
|
||||
Ok(info)
|
||||
}
|
||||
@@ -138,7 +115,7 @@ impl ProxyService {
|
||||
}
|
||||
|
||||
// 5. 启动代理服务器
|
||||
match self.start(true).await {
|
||||
match self.start().await {
|
||||
Ok(info) => Ok(info),
|
||||
Err(e) => {
|
||||
// 启动失败,恢复原始配置
|
||||
@@ -187,16 +164,16 @@ impl ProxyService {
|
||||
|
||||
/// 为指定应用开启/关闭 Live 接管
|
||||
///
|
||||
/// - 开启:自动启动代理服务(不影响总开关持久化),仅接管当前 app 的 Live 配置
|
||||
/// - 关闭:仅恢复当前 app 的 Live 配置;若总开关未开启且无其它接管,则自动停止代理服务
|
||||
/// - 开启:自动启动代理服务,仅接管当前 app 的 Live 配置
|
||||
/// - 关闭:仅恢复当前 app 的 Live 配置;若无其它接管,则自动停止代理服务
|
||||
pub async fn set_takeover_for_app(&self, app_type: &str, enabled: bool) -> Result<(), String> {
|
||||
let app = AppType::from_str(app_type).map_err(|e| format!("无效的应用类型: {e}"))?;
|
||||
let app_type_str = app.as_str();
|
||||
|
||||
if enabled {
|
||||
// 1) 代理服务未运行则自动启动(不持久化总开关)
|
||||
// 1) 代理服务未运行则自动启动
|
||||
if !self.is_running().await {
|
||||
self.start(false).await?;
|
||||
self.start().await?;
|
||||
}
|
||||
|
||||
// 2) 已接管则直接返回(幂等)
|
||||
@@ -252,7 +229,7 @@ impl ProxyService {
|
||||
.await
|
||||
.map_err(|e| format!("删除 {app_type_str} Live 备份失败: {e}"))?;
|
||||
|
||||
// 3) 若无其它接管,更新旧标志,并在总开关未开启时停止代理服务
|
||||
// 3) 若无其它接管,更新旧标志,并停止代理服务
|
||||
let has_any_backup = self
|
||||
.db
|
||||
.has_any_live_backup()
|
||||
@@ -261,13 +238,7 @@ impl ProxyService {
|
||||
if !has_any_backup {
|
||||
let _ = self.db.set_live_takeover_active(false).await;
|
||||
|
||||
let master_enabled = self
|
||||
.db
|
||||
.get_proxy_config()
|
||||
.await
|
||||
.map_err(|e| format!("获取代理配置失败: {e}"))?
|
||||
.enabled;
|
||||
if !master_enabled && self.is_running().await {
|
||||
if self.is_running().await {
|
||||
// 此时没有任何 app 处于接管状态,停止服务即可
|
||||
let _ = self.stop().await;
|
||||
}
|
||||
@@ -495,12 +466,6 @@ impl ProxyService {
|
||||
.await
|
||||
.map_err(|e| format!("停止代理服务器失败: {e}"))?;
|
||||
|
||||
// 将 enabled 设为 false,避免下次启动时自动开启
|
||||
if let Ok(mut config) = self.db.get_proxy_config().await {
|
||||
config.enabled = false;
|
||||
let _ = self.db.update_proxy_config(config).await;
|
||||
}
|
||||
|
||||
log::info!("代理服务器已停止");
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -513,15 +478,6 @@ impl ProxyService {
|
||||
// 1. 停止代理服务器(即使未运行也继续执行恢复逻辑)
|
||||
if let Err(e) = self.stop().await {
|
||||
log::warn!("停止代理服务器失败(将继续恢复 Live 配置): {e}");
|
||||
|
||||
// stop() 只有在 server 实例存在时才会把 enabled 设为 false;
|
||||
// 这里兜底确保“总开关关闭”能落盘关闭状态。
|
||||
if let Ok(mut config) = self.db.get_proxy_config().await {
|
||||
if config.enabled {
|
||||
config.enabled = false;
|
||||
let _ = self.db.update_proxy_config(config).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 恢复原始 Live 配置
|
||||
@@ -946,7 +902,7 @@ impl ProxyService {
|
||||
|
||||
/// 从异常退出中恢复(启动时调用)
|
||||
///
|
||||
/// 检测到 live_takeover_active=true 但代理未运行时调用此方法。
|
||||
/// 检测到 Live 备份残留时调用此方法。
|
||||
/// 会恢复 Live 配置、清除接管标志、删除备份。
|
||||
pub async fn recover_from_crash(&self) -> Result<(), String> {
|
||||
// 1. 恢复 Live 配置
|
||||
@@ -970,7 +926,7 @@ impl ProxyService {
|
||||
|
||||
/// 检测 Live 配置是否处于“被接管”的残留状态
|
||||
///
|
||||
/// 用于兜底处理:当数据库标志未写入成功(或旧版本遗留)但 Live 文件已经写成代理占位符时,
|
||||
/// 用于兜底处理:当数据库备份缺失但 Live 文件已经写成代理占位符时,
|
||||
/// 启动流程可以据此触发恢复逻辑。
|
||||
pub fn detect_takeover_in_live_configs(&self) -> bool {
|
||||
if let Ok(config) = self.read_claude_live() {
|
||||
@@ -1255,9 +1211,8 @@ impl ProxyService {
|
||||
.await
|
||||
.map_err(|e| format!("获取代理配置失败: {e}"))?;
|
||||
|
||||
// 保存到数据库(保持 enabled 和 live_takeover_active 状态不变)
|
||||
// 保存到数据库(保持 live_takeover_active 状态不变)
|
||||
let mut new_config = config.clone();
|
||||
new_config.enabled = previous.enabled;
|
||||
new_config.live_takeover_active = previous.live_takeover_active;
|
||||
|
||||
self.db
|
||||
|
||||
@@ -26,8 +26,11 @@ import { useTranslation } from "react-i18next";
|
||||
import type { TFunction } from "i18next";
|
||||
import type { ProxyConfig } from "@/types/proxy";
|
||||
|
||||
// 表单数据类型(不包含 enabled 字段,该字段由后端自动管理)
|
||||
type ProxyConfigForm = Omit<ProxyConfig, "enabled">;
|
||||
// 表单数据类型(仅包含可编辑字段)
|
||||
type ProxyConfigForm = Pick<
|
||||
ProxyConfig,
|
||||
"listen_address" | "listen_port" | "max_retries" | "request_timeout" | "enable_logging"
|
||||
>;
|
||||
|
||||
const createProxyConfigSchema = (t: TFunction) => {
|
||||
const requestTimeoutSchema = z
|
||||
@@ -120,19 +123,18 @@ export function ProxySettingsDialog({
|
||||
useEffect(() => {
|
||||
if (config) {
|
||||
form.reset({
|
||||
...config,
|
||||
listen_address: config.listen_address,
|
||||
listen_port: config.listen_port,
|
||||
max_retries: config.max_retries,
|
||||
request_timeout: config.request_timeout,
|
||||
enable_logging: config.enable_logging,
|
||||
});
|
||||
}
|
||||
}, [config, form]);
|
||||
|
||||
const onSubmit = async (data: ProxyConfigForm) => {
|
||||
try {
|
||||
// 添加 enabled 字段(从当前配置中获取,保持不变)
|
||||
const configToSave: ProxyConfig = {
|
||||
...data,
|
||||
enabled: config?.enabled ?? true,
|
||||
};
|
||||
await updateConfig(configToSave);
|
||||
await updateConfig(data);
|
||||
closePanel();
|
||||
} catch (error) {
|
||||
console.error("Save config failed:", error);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export interface ProxyConfig {
|
||||
enabled: boolean;
|
||||
listen_address: string;
|
||||
listen_port: number;
|
||||
max_retries: number;
|
||||
|
||||
Reference in New Issue
Block a user