mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
feat: optimize service initialization logic to fallback to Sidecar mode on installation failure
This commit is contained in:
@@ -15,7 +15,10 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use chrono::Local;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
use std::fs::{create_dir_all, File};
|
||||||
|
use std::io::Write;
|
||||||
use std::{fmt, path::PathBuf, sync::Arc};
|
use std::{fmt, path::PathBuf, sync::Arc};
|
||||||
use tauri_plugin_shell::{process::CommandChild, ShellExt};
|
use tauri_plugin_shell::{process::CommandChild, ShellExt};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
@@ -441,7 +444,18 @@ impl CoreManager {
|
|||||||
.clone()
|
.clone()
|
||||||
.unwrap_or("verge-mihomo".to_string());
|
.unwrap_or("verge-mihomo".to_string());
|
||||||
let config_dir = dirs::app_home_dir()?;
|
let config_dir = dirs::app_home_dir()?;
|
||||||
let (_, child) = app_handle
|
|
||||||
|
let service_log_dir = dirs::app_home_dir()?.join("service");
|
||||||
|
create_dir_all(&service_log_dir)?;
|
||||||
|
|
||||||
|
let now = Local::now();
|
||||||
|
let timestamp = now.format("%Y%m%d_%H%M%S").to_string();
|
||||||
|
|
||||||
|
let log_path = service_log_dir.join(format!("sidecar_{}.log", timestamp));
|
||||||
|
|
||||||
|
let mut log_file = File::create(log_path)?;
|
||||||
|
|
||||||
|
let (mut rx, child) = app_handle
|
||||||
.shell()
|
.shell()
|
||||||
.sidecar(&clash_core)?
|
.sidecar(&clash_core)?
|
||||||
.args([
|
.args([
|
||||||
@@ -451,6 +465,26 @@ impl CoreManager {
|
|||||||
dirs::path_to_str(config_file)?,
|
dirs::path_to_str(config_file)?,
|
||||||
])
|
])
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Some(event) = rx.recv().await {
|
||||||
|
match event {
|
||||||
|
tauri_plugin_shell::process::CommandEvent::Stdout(line) => {
|
||||||
|
if let Err(e) = writeln!(log_file, "{}", String::from_utf8_lossy(&line)) {
|
||||||
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"[Sidecar] Failed to write stdout to file: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let pid = child.pid();
|
let pid = child.pid();
|
||||||
logging!(
|
logging!(
|
||||||
trace,
|
trace,
|
||||||
@@ -506,89 +540,205 @@ impl CoreManager {
|
|||||||
child_sidecar: Arc::new(Mutex::new(None)),
|
child_sidecar: Arc::new(Mutex::new(None)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 当服务安装失败时的回退逻辑
|
||||||
|
async fn attempt_service_init(&self) -> Result<()> {
|
||||||
|
if service::check_service_needs_reinstall().await {
|
||||||
|
logging!(info, Type::Core, true, "服务版本不匹配或状态异常,执行重装");
|
||||||
|
if let Err(e) = service::reinstall_service().await {
|
||||||
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"服务重装失败 during attempt_service_init: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
// 如果重装成功,还需要尝试启动服务
|
||||||
|
logging!(info, Type::Core, true, "服务重装成功,尝试启动服务");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = self.start_core_by_service().await {
|
||||||
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"通过服务启动核心失败 during attempt_service_init: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
// 确保 prefer_sidecar 在 start_core_by_service 失败时也被设置
|
||||||
|
let mut state = service::ServiceState::get();
|
||||||
|
if !state.prefer_sidecar {
|
||||||
|
state.prefer_sidecar = true;
|
||||||
|
state.last_error = Some(format!("通过服务启动核心失败: {}", e));
|
||||||
|
if let Err(save_err) = state.save() {
|
||||||
|
logging!(
|
||||||
|
error,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"保存ServiceState失败 (in attempt_service_init/start_core_by_service): {}",
|
||||||
|
save_err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn init(&self) -> Result<()> {
|
pub async fn init(&self) -> Result<()> {
|
||||||
logging!(trace, Type::Core, "Initializing core");
|
logging!(trace, Type::Core, "Initializing core");
|
||||||
|
|
||||||
if service::is_service_available().await.is_ok() {
|
let mut core_started_successfully = false;
|
||||||
logging!(info, Type::Core, true, "服务可用,直接使用服务模式");
|
|
||||||
|
|
||||||
// 检查版本是否需要重装
|
if service::is_service_available().await.is_ok() {
|
||||||
if service::check_service_needs_reinstall().await {
|
logging!(
|
||||||
logging!(info, Type::Core, true, "服务版本不匹配,执行重装");
|
info,
|
||||||
service::reinstall_service().await?;
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"服务当前可用或看似可用,尝试通过服务模式启动/重装"
|
||||||
|
);
|
||||||
|
match self.attempt_service_init().await {
|
||||||
|
Ok(_) => {
|
||||||
|
logging!(info, Type::Core, true, "服务模式成功启动核心");
|
||||||
|
core_started_successfully = true;
|
||||||
|
}
|
||||||
|
Err(_err) => {
|
||||||
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"服务模式启动或重装失败。将尝试Sidecar模式回退。"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"服务初始不可用 (is_service_available 调用失败)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.start_core_by_service().await?;
|
if !core_started_successfully {
|
||||||
} else {
|
logging!(
|
||||||
// 服务不可用,获取服务状态
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"核心未通过服务模式启动,执行Sidecar回退或首次安装逻辑"
|
||||||
|
);
|
||||||
|
|
||||||
let service_state = service::ServiceState::get();
|
let service_state = service::ServiceState::get();
|
||||||
let has_service_install_record = service_state.last_install_time > 0;
|
|
||||||
|
|
||||||
if service_state.prefer_sidecar {
|
if service_state.prefer_sidecar {
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Core,
|
Type::Core,
|
||||||
true,
|
true,
|
||||||
"用户偏好Sidecar模式,使用Sidecar模式启动"
|
"用户偏好Sidecar模式或先前服务启动失败,使用Sidecar模式启动"
|
||||||
);
|
);
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
}
|
// 如果 sidecar 启动成功,我们可以认为核心初始化流程到此结束
|
||||||
// 检查是否已经有服务安装记录,如果没有,则尝试安装
|
// 后续的 Tray::global().subscribe_traffic().await 仍然会执行
|
||||||
else if !has_service_install_record {
|
} else {
|
||||||
logging!(info, Type::Core, true, "首次运行,服务不可用,尝试安装");
|
let has_service_install_record = service_state.last_install_time > 0;
|
||||||
|
if !has_service_install_record {
|
||||||
|
logging!(
|
||||||
|
info,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"无服务安装记录 (首次运行或状态重置),尝试安装服务"
|
||||||
|
);
|
||||||
match service::install_service().await {
|
match service::install_service().await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
logging!(info, Type::Core, true, "服务安装成功");
|
logging!(info, Type::Core, true, "服务安装成功(首次尝试)");
|
||||||
|
|
||||||
let mut new_state = service::ServiceState::default();
|
let mut new_state = service::ServiceState::default();
|
||||||
new_state.record_install();
|
new_state.record_install();
|
||||||
new_state.prefer_sidecar = false;
|
new_state.prefer_sidecar = false;
|
||||||
new_state.save()?;
|
new_state.save()?;
|
||||||
|
|
||||||
if service::is_service_available().await.is_ok() {
|
if service::is_service_available().await.is_ok() {
|
||||||
self.start_core_by_service().await?;
|
logging!(info, Type::Core, true, "新安装的服务可用,尝试启动");
|
||||||
logging!(info, Type::Core, true, "服务启动成功");
|
if self.start_core_by_service().await.is_ok() {
|
||||||
|
logging!(info, Type::Core, true, "新安装的服务启动成功");
|
||||||
} else {
|
} else {
|
||||||
logging!(
|
logging!(
|
||||||
warn,
|
warn,
|
||||||
Type::Core,
|
Type::Core,
|
||||||
true,
|
true,
|
||||||
"服务安装成功但未能连接,回退到Sidecar模式"
|
"新安装的服务启动失败,回退到Sidecar模式"
|
||||||
);
|
);
|
||||||
|
let mut final_state = service::ServiceState::get();
|
||||||
|
final_state.prefer_sidecar = true;
|
||||||
|
final_state.last_error =
|
||||||
|
Some("Newly installed service failed to start".to_string());
|
||||||
|
final_state.save()?;
|
||||||
|
self.start_core_by_sidecar().await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"服务安装成功但未能连接/立即可用,回退到Sidecar模式"
|
||||||
|
);
|
||||||
|
let mut final_state = service::ServiceState::get();
|
||||||
|
final_state.prefer_sidecar = true;
|
||||||
|
final_state.last_error = Some(
|
||||||
|
"Newly installed service not immediately available/connectable"
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
final_state.save()?;
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// 安装失败,记录错误并使用sidecar模式
|
logging!(warn, Type::Core, true, "服务首次安装失败: {}", err);
|
||||||
logging!(warn, Type::Core, true, "服务安装失败: {}", err);
|
|
||||||
|
|
||||||
let new_state = service::ServiceState {
|
let new_state = service::ServiceState {
|
||||||
last_error: Some(err.to_string()),
|
last_error: Some(err.to_string()),
|
||||||
prefer_sidecar: true,
|
prefer_sidecar: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
new_state.save()?;
|
new_state.save()?;
|
||||||
|
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 有安装记录,服务未成功启动,且初始不偏好sidecar
|
||||||
|
// 这意味着服务之前可能可用,但 attempt_service_init 失败了(并应已设置 prefer_sidecar),
|
||||||
|
// 或者服务初始不可用,无偏好,有记录。应强制使用 sidecar。
|
||||||
logging!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::Core,
|
Type::Core,
|
||||||
true,
|
true,
|
||||||
"有服务安装记录但服务不可用,使用Sidecar模式"
|
"有服务安装记录但服务不可用/未启动,强制切换到Sidecar模式"
|
||||||
);
|
);
|
||||||
|
let mut final_state = service::ServiceState::get();
|
||||||
|
if !final_state.prefer_sidecar {
|
||||||
|
logging!(
|
||||||
|
warn,
|
||||||
|
Type::Core,
|
||||||
|
true,
|
||||||
|
"prefer_sidecar 为 false,因服务启动失败或不可用而强制设置为 true"
|
||||||
|
);
|
||||||
|
final_state.prefer_sidecar = true;
|
||||||
|
final_state.last_error =
|
||||||
|
Some(final_state.last_error.unwrap_or_else(|| {
|
||||||
|
"Service startup failed or unavailable before sidecar fallback"
|
||||||
|
.to_string()
|
||||||
|
}));
|
||||||
|
final_state.save()?;
|
||||||
|
}
|
||||||
self.start_core_by_sidecar().await?;
|
self.start_core_by_sidecar().await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logging!(trace, Type::Core, "Initied core");
|
logging!(trace, Type::Core, "Initied core logic completed");
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
logging_error!(Type::Core, true, Tray::global().subscribe_traffic().await);
|
logging_error!(Type::Core, true, Tray::global().subscribe_traffic().await);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use std::{
|
|||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
const REQUIRED_SERVICE_VERSION: &str = "1.0.8"; // 定义所需的服务版本号
|
const REQUIRED_SERVICE_VERSION: &str = "1.0.9"; // 定义所需的服务版本号
|
||||||
|
|
||||||
// 限制重装时间和次数的常量
|
// 限制重装时间和次数的常量
|
||||||
const REINSTALL_COOLDOWN_SECS: u64 = 300; // 5分钟冷却期
|
const REINSTALL_COOLDOWN_SECS: u64 = 300; // 5分钟冷却期
|
||||||
@@ -220,6 +220,7 @@ pub async fn reinstall_service() -> Result<()> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
let error = format!("failed to install service: {}", err);
|
let error = format!("failed to install service: {}", err);
|
||||||
service_state.last_error = Some(error.clone());
|
service_state.last_error = Some(error.clone());
|
||||||
|
service_state.prefer_sidecar = true;
|
||||||
service_state.save()?;
|
service_state.save()?;
|
||||||
bail!(error)
|
bail!(error)
|
||||||
}
|
}
|
||||||
@@ -347,6 +348,7 @@ pub async fn reinstall_service() -> Result<()> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
let error = format!("failed to install service: {}", err);
|
let error = format!("failed to install service: {}", err);
|
||||||
service_state.last_error = Some(error.clone());
|
service_state.last_error = Some(error.clone());
|
||||||
|
service_state.prefer_sidecar = true;
|
||||||
service_state.save()?;
|
service_state.save()?;
|
||||||
bail!(error)
|
bail!(error)
|
||||||
}
|
}
|
||||||
@@ -466,6 +468,7 @@ pub async fn reinstall_service() -> Result<()> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
let error = format!("failed to install service: {}", err);
|
let error = format!("failed to install service: {}", err);
|
||||||
service_state.last_error = Some(error.clone());
|
service_state.last_error = Some(error.clone());
|
||||||
|
service_state.prefer_sidecar = true;
|
||||||
service_state.save()?;
|
service_state.save()?;
|
||||||
bail!(error)
|
bail!(error)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user