|
@@ -1,5 +1,3 @@
|
|
-#![cfg(any(target_os = "windows", target_os = "linux"))]
|
|
|
|
-
|
|
|
|
use crate::config::Config;
|
|
use crate::config::Config;
|
|
use crate::utils::dirs;
|
|
use crate::utils::dirs;
|
|
use anyhow::{bail, Context, Result};
|
|
use anyhow::{bail, Context, Result};
|
|
@@ -31,14 +29,13 @@ pub struct JsonResponse {
|
|
|
|
|
|
/// Install the Clash Verge Service
|
|
/// Install the Clash Verge Service
|
|
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
|
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
|
-///
|
|
|
|
|
|
+///
|
|
#[cfg(target_os = "windows")]
|
|
#[cfg(target_os = "windows")]
|
|
pub async fn install_service() -> Result<()> {
|
|
pub async fn install_service() -> Result<()> {
|
|
use deelevate::{PrivilegeLevel, Token};
|
|
use deelevate::{PrivilegeLevel, Token};
|
|
use runas::Command as RunasCommand;
|
|
use runas::Command as RunasCommand;
|
|
use std::os::windows::process::CommandExt;
|
|
use std::os::windows::process::CommandExt;
|
|
|
|
|
|
-
|
|
|
|
let binary_path = dirs::service_path()?;
|
|
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("install-service.exe");
|
|
|
|
|
|
@@ -80,7 +77,11 @@ pub async fn install_service() -> Result<()> {
|
|
let elevator = crate::utils::unix_helper::linux_elevator();
|
|
let elevator = crate::utils::unix_helper::linux_elevator();
|
|
let status = match get_effective_uid() {
|
|
let status = match get_effective_uid() {
|
|
0 => StdCommand::new(installer_path).status()?,
|
|
0 => StdCommand::new(installer_path).status()?,
|
|
- _ => StdCommand::new(elevator).arg("sh").arg("-c").arg(installer_path).status()?,
|
|
|
|
|
|
+ _ => StdCommand::new(elevator)
|
|
|
|
+ .arg("sh")
|
|
|
|
+ .arg("-c")
|
|
|
|
+ .arg(installer_path)
|
|
|
|
+ .status()?,
|
|
};
|
|
};
|
|
|
|
|
|
if !status.success() {
|
|
if !status.success() {
|
|
@@ -93,6 +94,30 @@ pub async fn install_service() -> Result<()> {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#[cfg(target_os = "macos")]
|
|
|
|
+pub async fn install_service() -> Result<()> {
|
|
|
|
+ let binary_path = dirs::service_path()?;
|
|
|
|
+ let installer_path = binary_path.with_file_name("install-service");
|
|
|
|
+
|
|
|
|
+ if !installer_path.exists() {
|
|
|
|
+ bail!("installer not found");
|
|
|
|
+ }
|
|
|
|
+ let shell = installer_path.to_string_lossy();
|
|
|
|
+ let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
|
|
|
+
|
|
|
|
+ let status = StdCommand::new("osascript")
|
|
|
|
+ .args(vec!["-e", &command])
|
|
|
|
+ .status()?;
|
|
|
|
+
|
|
|
|
+ if !status.success() {
|
|
|
|
+ bail!(
|
|
|
|
+ "failed to install service with status {}",
|
|
|
|
+ status.code().unwrap()
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
/// Uninstall the Clash Verge Service
|
|
/// Uninstall the Clash Verge Service
|
|
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
|
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
|
#[cfg(target_os = "windows")]
|
|
#[cfg(target_os = "windows")]
|
|
@@ -101,7 +126,6 @@ pub async fn uninstall_service() -> Result<()> {
|
|
use runas::Command as RunasCommand;
|
|
use runas::Command as RunasCommand;
|
|
use std::os::windows::process::CommandExt;
|
|
use std::os::windows::process::CommandExt;
|
|
|
|
|
|
-
|
|
|
|
let binary_path = dirs::service_path()?;
|
|
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("uninstall-service.exe");
|
|
|
|
|
|
@@ -143,7 +167,11 @@ pub async fn uninstall_service() -> Result<()> {
|
|
let elevator = crate::utils::unix_helper::linux_elevator();
|
|
let elevator = crate::utils::unix_helper::linux_elevator();
|
|
let status = match get_effective_uid() {
|
|
let status = match get_effective_uid() {
|
|
0 => StdCommand::new(uninstaller_path).status()?,
|
|
0 => StdCommand::new(uninstaller_path).status()?,
|
|
- _ => StdCommand::new(elevator).arg("sh").arg("-c").arg(uninstaller_path).status()?,
|
|
|
|
|
|
+ _ => StdCommand::new(elevator)
|
|
|
|
+ .arg("sh")
|
|
|
|
+ .arg("-c")
|
|
|
|
+ .arg(uninstaller_path)
|
|
|
|
+ .status()?,
|
|
};
|
|
};
|
|
|
|
|
|
if !status.success() {
|
|
if !status.success() {
|
|
@@ -156,6 +184,32 @@ pub async fn uninstall_service() -> Result<()> {
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#[cfg(target_os = "macos")]
|
|
|
|
+pub async fn uninstall_service() -> Result<()> {
|
|
|
|
+ let binary_path = dirs::service_path()?;
|
|
|
|
+ let uninstaller_path = binary_path.with_file_name("uninstall-service");
|
|
|
|
+
|
|
|
|
+ if !uninstaller_path.exists() {
|
|
|
|
+ bail!("uninstaller not found");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let shell = uninstaller_path.to_string_lossy();
|
|
|
|
+ let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
|
|
|
+
|
|
|
|
+ let status = StdCommand::new("osascript")
|
|
|
|
+ .args(vec!["-e", &command])
|
|
|
|
+ .status()?;
|
|
|
|
+
|
|
|
|
+ if !status.success() {
|
|
|
|
+ bail!(
|
|
|
|
+ "failed to install service with status {}",
|
|
|
|
+ status.code().unwrap()
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+}
|
|
|
|
+
|
|
/// check the windows service status
|
|
/// check the windows service status
|
|
pub async fn check_service() -> Result<JsonResponse> {
|
|
pub async fn check_service() -> Result<JsonResponse> {
|
|
let url = format!("{SERVICE_URL}/get_clash");
|
|
let url = format!("{SERVICE_URL}/get_clash");
|
|
@@ -185,7 +239,7 @@ pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
|
|
let clash_core = { Config::verge().latest().clash_core.clone() };
|
|
let clash_core = { Config::verge().latest().clash_core.clone() };
|
|
let clash_core = clash_core.unwrap_or("clash".into());
|
|
let clash_core = clash_core.unwrap_or("clash".into());
|
|
|
|
|
|
- let bin_ext = if cfg!(windows) {".exe"} else {""};
|
|
|
|
|
|
+ let bin_ext = if cfg!(windows) { ".exe" } else { "" };
|
|
let clash_bin = format!("{clash_core}{bin_ext}");
|
|
let clash_bin = format!("{clash_core}{bin_ext}");
|
|
let bin_path = current_exe()?.with_file_name(clash_bin);
|
|
let bin_path = current_exe()?.with_file_name(clash_bin);
|
|
let bin_path = dirs::path_to_str(&bin_path)?;
|
|
let bin_path = dirs::path_to_str(&bin_path)?;
|