mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 05:23:44 +08:00
feat: Add sidecar mode as an alternative to service mode
- Auto-fallback to sidecar mode if service mode fails
This commit is contained in:
parent
d370868222
commit
9d74b93ee0
@ -7,7 +7,7 @@ use crate::utils::{dirs, help};
|
||||
use anyhow::{bail, Result};
|
||||
use once_cell::sync::OnceCell;
|
||||
use serde_yaml::Mapping;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::{sync::Arc, time::Duration, path::PathBuf};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::time::sleep;
|
||||
@ -53,12 +53,37 @@ impl CoreManager {
|
||||
// 服务模式
|
||||
if service::check_service().await.is_ok() {
|
||||
log::info!(target: "app", "stop the core by service");
|
||||
service::stop_core_by_service().await?;
|
||||
match service::stop_core_by_service().await {
|
||||
Ok(_) => {
|
||||
log::info!(target: "app", "core stopped successfully by service");
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!(target: "app", "failed to stop core by service: {}", err);
|
||||
// 服务停止失败,尝试停止可能的sidecar进程
|
||||
self.stop_sidecar_process();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果没有使用服务,尝试停止sidecar进程
|
||||
self.stop_sidecar_process();
|
||||
}
|
||||
|
||||
*running = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 停止通过sidecar启动的进程
|
||||
fn stop_sidecar_process(&self) {
|
||||
if let Some(process) = handle::Handle::global().take_core_process() {
|
||||
log::info!(target: "app", "stopping core process in sidecar mode");
|
||||
if let Err(e) = process.kill() {
|
||||
log::warn!(target: "app", "failed to kill core process: {}", e);
|
||||
} else {
|
||||
log::info!(target: "app", "core process stopped successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 启动核心
|
||||
pub async fn start_core(&self) -> Result<()> {
|
||||
let mut running = self.running.lock().await;
|
||||
@ -69,11 +94,26 @@ impl CoreManager {
|
||||
|
||||
let config_path = Config::generate_file(ConfigType::Run)?;
|
||||
|
||||
// 服务模式
|
||||
// 先尝试服务模式
|
||||
if service::check_service().await.is_ok() {
|
||||
log::info!(target: "app", "try to run core in service mode");
|
||||
service::run_core_by_service(&config_path).await?;
|
||||
match service::run_core_by_service(&config_path).await {
|
||||
Ok(_) => {
|
||||
log::info!(target: "app", "core started successfully in service mode");
|
||||
},
|
||||
Err(err) => {
|
||||
// 服务启动失败,尝试sidecar模式
|
||||
log::warn!(target: "app", "failed to start core in service mode: {}", err);
|
||||
log::info!(target: "app", "trying to run core in sidecar mode");
|
||||
self.run_core_by_sidecar(&config_path).await?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 服务不可用,直接使用sidecar模式
|
||||
log::info!(target: "app", "service not available, running core in sidecar mode");
|
||||
self.run_core_by_sidecar(&config_path).await?;
|
||||
}
|
||||
|
||||
// 流量订阅
|
||||
#[cfg(target_os = "macos")]
|
||||
log_err!(Tray::global().subscribe_traffic().await);
|
||||
@ -83,11 +123,43 @@ impl CoreManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 通过sidecar启动内核
|
||||
async fn run_core_by_sidecar(&self, config_path: &PathBuf) -> Result<()> {
|
||||
let clash_core = { Config::verge().latest().clash_core.clone() };
|
||||
let clash_core = clash_core.unwrap_or("verge-mihomo".into());
|
||||
|
||||
log::info!(target: "app", "starting core {} in sidecar mode", clash_core);
|
||||
|
||||
let app_handle = handle::Handle::global().app_handle().ok_or(anyhow::anyhow!("failed to get app handle"))?;
|
||||
|
||||
// 获取配置目录
|
||||
let config_dir = dirs::app_home_dir()?;
|
||||
let config_path_str = dirs::path_to_str(config_path)?;
|
||||
|
||||
// 启动核心进程并转入后台运行
|
||||
let (_, child) = app_handle
|
||||
.shell()
|
||||
.sidecar(clash_core)?
|
||||
.args(["-d", dirs::path_to_str(&config_dir)?, "-f", config_path_str])
|
||||
.spawn()?;
|
||||
|
||||
// 保存进程ID以便后续管理
|
||||
handle::Handle::global().set_core_process(child);
|
||||
|
||||
// 等待短暂时间确保启动成功
|
||||
sleep(Duration::from_millis(300)).await;
|
||||
|
||||
log::info!(target: "app", "core started in sidecar mode");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 重启内核
|
||||
pub async fn restart_core(&self) -> Result<()> {
|
||||
// 重新启动app
|
||||
log::info!(target: "app", "restarting core");
|
||||
self.stop_core().await?;
|
||||
self.start_core().await?;
|
||||
log::info!(target: "app", "core restarted successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -139,9 +211,11 @@ impl CoreManager {
|
||||
}
|
||||
Err(err) => {
|
||||
println!("[切换内核] 内核切换失败: {}", err);
|
||||
Config::verge().discard();
|
||||
Config::runtime().discard();
|
||||
Err(err)
|
||||
// 即使使用服务失败,我们也尝试使用sidecar模式启动
|
||||
log::info!(target: "app", "trying sidecar mode after service failure");
|
||||
self.start_core().await?;
|
||||
Config::runtime().apply();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,8 +233,10 @@ impl CoreManager {
|
||||
}
|
||||
Err(err) => {
|
||||
println!("[切换内核] 内核切换失败: {}", err);
|
||||
Config::verge().discard();
|
||||
Err(err)
|
||||
// 即使使用服务失败,我们也尝试使用sidecar模式启动
|
||||
log::info!(target: "app", "trying sidecar mode after service failure with default config");
|
||||
self.start_core().await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
use tauri::{AppHandle, Emitter, Manager, WebviewWindow};
|
||||
use tauri_plugin_shell::process::CommandChild;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Handle {
|
||||
pub app_handle: Arc<RwLock<Option<AppHandle>>>,
|
||||
pub is_exiting: Arc<RwLock<bool>>,
|
||||
pub core_process: Arc<RwLock<Option<CommandChild>>>,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
@ -17,6 +19,7 @@ impl Handle {
|
||||
HANDLE.get_or_init(|| Handle {
|
||||
app_handle: Arc::new(RwLock::new(None)),
|
||||
is_exiting: Arc::new(RwLock::new(false)),
|
||||
core_process: Arc::new(RwLock::new(None)),
|
||||
})
|
||||
}
|
||||
|
||||
@ -68,6 +71,16 @@ impl Handle {
|
||||
*is_exiting = true;
|
||||
}
|
||||
|
||||
pub fn set_core_process(&self, process: CommandChild) {
|
||||
let mut core_process = self.core_process.write();
|
||||
*core_process = Some(process);
|
||||
}
|
||||
|
||||
pub fn take_core_process(&self) -> Option<CommandChild> {
|
||||
let mut core_process = self.core_process.write();
|
||||
core_process.take()
|
||||
}
|
||||
|
||||
pub fn is_exiting(&self) -> bool {
|
||||
*self.is_exiting.read()
|
||||
}
|
||||
|
@ -77,14 +77,12 @@ pub async fn resolve_setup(app: &mut App) {
|
||||
}
|
||||
}
|
||||
if !service_runing {
|
||||
log::error!(target: "app", "service not runing. exit");
|
||||
app.app_handle().exit(-2);
|
||||
log::warn!(target: "app", "service not running, will fallback to user mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!(target: "app", "{e:?}");
|
||||
app.app_handle().exit(-1);
|
||||
log::warn!(target: "app", "failed to install service: {e:?}, will fallback to user mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user