feat: optimize service initialization logic to fallback to Sidecar mode on installation failure

This commit is contained in:
wonfen
2025-05-17 19:13:24 +08:00
parent e1d6c74e4f
commit 305a64c3e3
2 changed files with 211 additions and 58 deletions

View File

@@ -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(())
} }

View File

@@ -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)
} }