mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 17:15:38 +08:00
refactor: clash-verge-rev-service-ipc (#4841)
* feat: update service installation scripts and IPC integration - Updated `Cargo.toml` to use version 2.0.8 of `clash_verge_service_ipc` with "client" feature. - Renamed service installation and uninstallation scripts in `post-install.sh` and `pre-remove.sh`. - Removed `service_ipc` module and refactored IPC handling in `service.rs` to use the new `clash_verge_service_ipc` directly. - Adjusted service version checking and core management to align with the new IPC structure. - Simplified directory checks in `dirs.rs` and updated logging configurations in `init.rs`. - Updated Linux configuration file to reflect new script names. - Enhanced service installer hook to manage state more effectively. * refactor: simplify ClashConfig instantiation and remove unused service log file function * feat: update clash_verge_service_ipc to version 2.0.9 and enhance service initialization logging * chore: update clash_verge_service_ipc to version 2.0.10 and refactor async service manager initialization * fix: update clash_verge_service_ipc to version 2.0.11 and improve service manager initialization * fix: increase sleep duration for socket readiness check to improve stability * fix: update clash_verge_service_ipc to version 2.0.12 and kode-bridge to version 0.3.4; refactor service management and IPC path checks * fix: update clash_verge_service_ipc to version 2.0.13; refactor service connection and initialization logic
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
use crate::{
|
||||
config::Config,
|
||||
core::service_ipc::{IpcCommand, send_ipc_request},
|
||||
logging, logging_error,
|
||||
utils::{dirs, logging::Type},
|
||||
utils::{dirs, init::service_writer_config, logging::Type},
|
||||
};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use clash_verge_service_ipc::CoreConfig;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{env::current_exe, path::PathBuf, process::Command as StdCommand};
|
||||
use std::{
|
||||
env::current_exe,
|
||||
path::{Path, PathBuf},
|
||||
process::Command as StdCommand,
|
||||
time::Duration,
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
const REQUIRED_SERVICE_VERSION: &str = "1.1.2"; // 定义所需的服务版本号
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ServiceStatus {
|
||||
Ready,
|
||||
@@ -35,7 +38,7 @@ async fn uninstall_service() -> Result<()> {
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
|
||||
let uninstall_path = binary_path.with_file_name("clash-verge-service-uninstall.exe");
|
||||
|
||||
if !uninstall_path.exists() {
|
||||
bail!(format!("uninstaller not found: {uninstall_path:?}"));
|
||||
@@ -70,7 +73,7 @@ async fn install_service() -> Result<()> {
|
||||
use std::os::windows::process::CommandExt;
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let install_path = binary_path.with_file_name("install-service.exe");
|
||||
let install_path = binary_path.with_file_name("clash-verge-service-install.exe");
|
||||
|
||||
if !install_path.exists() {
|
||||
bail!(format!("installer not found: {install_path:?}"));
|
||||
@@ -119,7 +122,8 @@ async fn uninstall_service() -> Result<()> {
|
||||
logging!(info, Type::Service, "uninstall service");
|
||||
use users::get_effective_uid;
|
||||
|
||||
let uninstall_path = tauri::utils::platform::current_exe()?.with_file_name("uninstall-service");
|
||||
let uninstall_path =
|
||||
tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-uninstall");
|
||||
|
||||
if !uninstall_path.exists() {
|
||||
bail!(format!("uninstaller not found: {uninstall_path:?}"));
|
||||
@@ -159,7 +163,8 @@ async fn install_service() -> Result<()> {
|
||||
logging!(info, Type::Service, "install service");
|
||||
use users::get_effective_uid;
|
||||
|
||||
let install_path = tauri::utils::platform::current_exe()?.with_file_name("install-service");
|
||||
let install_path =
|
||||
tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-install");
|
||||
|
||||
if !install_path.exists() {
|
||||
bail!(format!("installer not found: {install_path:?}"));
|
||||
@@ -218,7 +223,7 @@ async fn uninstall_service() -> Result<()> {
|
||||
logging!(info, Type::Service, "uninstall service");
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let uninstall_path = binary_path.with_file_name("uninstall-service");
|
||||
let uninstall_path = binary_path.with_file_name("clash-verge-service-uninstall");
|
||||
|
||||
if !uninstall_path.exists() {
|
||||
bail!(format!("uninstaller not found: {uninstall_path:?}"));
|
||||
@@ -254,7 +259,7 @@ async fn install_service() -> Result<()> {
|
||||
logging!(info, Type::Service, "install service");
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
let install_path = binary_path.with_file_name("install-service");
|
||||
let install_path = binary_path.with_file_name("clash-verge-service-install");
|
||||
|
||||
if !install_path.exists() {
|
||||
bail!(format!("installer not found: {install_path:?}"));
|
||||
@@ -314,21 +319,17 @@ pub async fn force_reinstall_service() -> Result<()> {
|
||||
async fn check_service_version() -> Result<String> {
|
||||
let version_arc: Result<String> = {
|
||||
logging!(info, Type::Service, "开始检查服务版本 (IPC)");
|
||||
let payload = serde_json::json!({});
|
||||
let response = send_ipc_request(IpcCommand::GetVersion, payload).await?;
|
||||
|
||||
let data = response
|
||||
.data
|
||||
.ok_or_else(|| anyhow::anyhow!("服务版本响应中没有数据"))?;
|
||||
|
||||
if let Some(nested_data) = data.get("data")
|
||||
&& let Some(version) = nested_data.get("version").and_then(|v| v.as_str())
|
||||
{
|
||||
// logging!(info, Type::Service, true, "获取到服务版本: {}", version);
|
||||
Ok(version.to_string())
|
||||
} else {
|
||||
Ok("unknown".to_string())
|
||||
let response = clash_verge_service_ipc::get_version()
|
||||
.await
|
||||
.context("无法连接到Clash Verge Service")?;
|
||||
if response.code > 0 {
|
||||
let err_msg = response.message;
|
||||
logging!(error, Type::Service, "获取服务版本失败: {}", err_msg);
|
||||
return Err(anyhow::anyhow!(err_msg));
|
||||
}
|
||||
|
||||
let version = response.data.unwrap_or("unknown".to_string());
|
||||
Ok(version)
|
||||
};
|
||||
|
||||
match version_arc.as_ref() {
|
||||
@@ -340,7 +341,7 @@ async fn check_service_version() -> Result<String> {
|
||||
/// 检查服务是否需要重装
|
||||
pub async fn check_service_needs_reinstall() -> bool {
|
||||
match check_service_version().await {
|
||||
Ok(version) => version != REQUIRED_SERVICE_VERSION,
|
||||
Ok(version) => version != clash_verge_service_ipc::VERSION,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
@@ -356,35 +357,25 @@ pub(super) async fn start_with_existing_service(config_file: &PathBuf) -> Result
|
||||
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
|
||||
let bin_path = current_exe()?.with_file_name(format!("{clash_core}{bin_ext}"));
|
||||
|
||||
let payload = serde_json::json!({
|
||||
"core_type": clash_core,
|
||||
"bin_path": dirs::path_to_str(&bin_path)?,
|
||||
"config_dir": dirs::path_to_str(&dirs::app_home_dir()?)?,
|
||||
"config_file": dirs::path_to_str(config_file)?,
|
||||
// TODO 迁移 Service日志后删除
|
||||
"log_file": dirs::path_to_str(&dirs::service_log_file()?)?,
|
||||
});
|
||||
let payload = clash_verge_service_ipc::ClashConfig {
|
||||
core_config: CoreConfig {
|
||||
config_path: dirs::path_to_str(config_file)?.to_string(),
|
||||
core_path: dirs::path_to_str(&bin_path)?.to_string(),
|
||||
config_dir: dirs::path_to_str(&dirs::app_home_dir()?)?.to_string(),
|
||||
},
|
||||
log_config: service_writer_config().await?,
|
||||
};
|
||||
|
||||
let response = send_ipc_request(IpcCommand::StartClash, payload)
|
||||
let response = clash_verge_service_ipc::start_clash(&payload)
|
||||
.await
|
||||
.context("无法连接到Clash Verge Service")?;
|
||||
|
||||
if !response.success {
|
||||
let err_msg = response.error.unwrap_or_else(|| "启动核心失败".to_string());
|
||||
if response.code > 0 {
|
||||
let err_msg = response.message;
|
||||
logging!(error, Type::Service, "启动核心失败: {}", err_msg);
|
||||
bail!(err_msg);
|
||||
}
|
||||
|
||||
if let Some(data) = &response.data
|
||||
&& let Some(code) = data.get("code").and_then(|c| c.as_u64())
|
||||
&& code != 0
|
||||
{
|
||||
let msg = data
|
||||
.get("msg")
|
||||
.and_then(|m| m.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
bail!("启动核心失败: {}", msg);
|
||||
}
|
||||
|
||||
logging!(info, Type::Service, "服务成功启动核心");
|
||||
Ok(())
|
||||
}
|
||||
@@ -405,53 +396,51 @@ pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
|
||||
pub(super) async fn stop_core_by_service() -> Result<()> {
|
||||
logging!(info, Type::Service, "通过服务停止核心 (IPC)");
|
||||
|
||||
let payload = serde_json::json!({});
|
||||
let response = send_ipc_request(IpcCommand::StopClash, payload)
|
||||
let response = clash_verge_service_ipc::stop_clash()
|
||||
.await
|
||||
.context("无法连接到Clash Verge Service")?;
|
||||
|
||||
if !response.success {
|
||||
let err_msg = response.error.unwrap_or_else(|| "停止核心失败".to_string());
|
||||
if response.code > 0 {
|
||||
let err_msg = response.message;
|
||||
logging!(error, Type::Service, "停止核心失败: {}", err_msg);
|
||||
bail!(err_msg);
|
||||
}
|
||||
|
||||
if let Some(data) = &response.data
|
||||
&& let Some(code) = data.get("code")
|
||||
{
|
||||
let code_value = code.as_u64().unwrap_or(1);
|
||||
let msg = data
|
||||
.get("msg")
|
||||
.and_then(|m| m.as_str())
|
||||
.unwrap_or("未知错误");
|
||||
|
||||
if code_value != 0 {
|
||||
logging!(
|
||||
error,
|
||||
Type::Service,
|
||||
"停止核心返回错误: code={}, msg={}",
|
||||
code_value,
|
||||
msg
|
||||
);
|
||||
bail!("停止核心失败: {}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
logging!(info, Type::Service, "服务成功停止核心");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 检查服务是否正在运行
|
||||
pub async fn is_service_available() -> Result<()> {
|
||||
check_service_version().await?;
|
||||
clash_verge_service_ipc::connect().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_service_ipc_path_exists() -> bool {
|
||||
Path::new(clash_verge_service_ipc::IPC_PATH).exists()
|
||||
}
|
||||
|
||||
impl ServiceManager {
|
||||
pub fn default() -> Self {
|
||||
Self(ServiceStatus::Unavailable("Need Checks".into()))
|
||||
}
|
||||
|
||||
pub fn config() -> Option<clash_verge_service_ipc::IpcConfig> {
|
||||
Some(clash_verge_service_ipc::IpcConfig {
|
||||
default_timeout: Duration::from_millis(30),
|
||||
retry_delay: Duration::from_millis(250),
|
||||
max_retries: 6,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn init(&mut self) -> Result<()> {
|
||||
if let Err(e) = clash_verge_service_ipc::connect().await {
|
||||
self.0 = ServiceStatus::Unavailable("服务连接失败: {e}".to_string());
|
||||
return Err(e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn current(&self) -> ServiceStatus {
|
||||
self.0.clone()
|
||||
}
|
||||
@@ -487,31 +476,26 @@ impl ServiceManager {
|
||||
match status {
|
||||
ServiceStatus::Ready => {
|
||||
logging!(info, Type::Service, "服务就绪,直接启动");
|
||||
Ok(())
|
||||
}
|
||||
ServiceStatus::NeedsReinstall | ServiceStatus::ReinstallRequired => {
|
||||
logging!(info, Type::Service, "服务需要重装,执行重装流程");
|
||||
reinstall_service().await?;
|
||||
self.0 = ServiceStatus::Ready;
|
||||
Ok(())
|
||||
}
|
||||
ServiceStatus::ForceReinstallRequired => {
|
||||
logging!(info, Type::Service, "服务需要强制重装,执行强制重装流程");
|
||||
force_reinstall_service().await?;
|
||||
self.0 = ServiceStatus::Ready;
|
||||
Ok(())
|
||||
}
|
||||
ServiceStatus::InstallRequired => {
|
||||
logging!(info, Type::Service, "需要安装服务,执行安装流程");
|
||||
install_service().await?;
|
||||
self.0 = ServiceStatus::Ready;
|
||||
Ok(())
|
||||
}
|
||||
ServiceStatus::UninstallRequired => {
|
||||
logging!(info, Type::Service, "服务需要卸载,执行卸载流程");
|
||||
uninstall_service().await?;
|
||||
self.0 = ServiceStatus::Unavailable("Service Uninstalled".into());
|
||||
Ok(())
|
||||
}
|
||||
ServiceStatus::Unavailable(reason) => {
|
||||
logging!(
|
||||
@@ -521,9 +505,10 @@ impl ServiceManager {
|
||||
reason
|
||||
);
|
||||
self.0 = ServiceStatus::Unavailable(reason.clone());
|
||||
Err(anyhow::anyhow!("服务不可用: {}", reason))
|
||||
return Err(anyhow::anyhow!("服务不可用: {}", reason));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user