mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 08:45:41 +08:00
wip: windows service mode
This commit is contained in:
@@ -57,61 +57,6 @@ impl Service {
|
||||
self.start()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn install(&mut self) -> Result<()> {
|
||||
use std::{env::current_exe, ffi::OsString};
|
||||
use windows_service::{
|
||||
service::{ServiceAccess, ServiceErrorControl, ServiceInfo, ServiceStartType, ServiceType},
|
||||
service_manager::{ServiceManager, ServiceManagerAccess},
|
||||
};
|
||||
|
||||
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
|
||||
let service_binary_path = current_exe().unwrap().with_file_name("clash.exe");
|
||||
|
||||
let service_info = ServiceInfo {
|
||||
name: OsString::from("clash_verge_core"),
|
||||
display_name: OsString::from("Clash Verge Core"),
|
||||
service_type: ServiceType::OWN_PROCESS,
|
||||
start_type: ServiceStartType::OnDemand,
|
||||
error_control: ServiceErrorControl::Normal,
|
||||
executable_path: service_binary_path,
|
||||
launch_arguments: vec![],
|
||||
dependencies: vec![],
|
||||
account_name: None, // run as System
|
||||
account_password: None,
|
||||
};
|
||||
|
||||
let service = service_manager.create_service(&service_info, ServiceAccess::CHANGE_CONFIG)?;
|
||||
service.set_description("Clash Core Service installed by Clash Verge")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn check_status(&mut self) -> Result<String> {
|
||||
use windows_service::{
|
||||
service::{ServiceAccess, ServiceState},
|
||||
service_manager::{ServiceManager, ServiceManagerAccess},
|
||||
};
|
||||
|
||||
let manager_access = ServiceManagerAccess::CONNECT;
|
||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||
|
||||
let service_access = ServiceAccess::QUERY_STATUS; // | ServiceAccess::STOP | ServiceAccess::DELETE;
|
||||
let service = service_manager.open_service("clash_verge_core", service_access)?;
|
||||
|
||||
let service_status = service.query_status()?;
|
||||
|
||||
Ok(format!("{:?}", service_status.current_state))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn start_service(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// update clash config
|
||||
/// using PUT methods
|
||||
pub fn set_config(&self, info: ClashInfo, config: Mapping, notice: Notice) -> Result<()> {
|
||||
@@ -176,3 +121,91 @@ impl Drop for Service {
|
||||
log_if_err!(self.stop());
|
||||
}
|
||||
}
|
||||
|
||||
/// ### Service Mode
|
||||
///
|
||||
#[cfg(windows)]
|
||||
mod win_service {
|
||||
use super::*;
|
||||
use deelevate::{PrivilegeLevel, Token};
|
||||
use runas::Command as RunasCommond;
|
||||
use std::process::Command as StdCommond;
|
||||
|
||||
const SERVICE_NAME: &str = "clash_verge_service";
|
||||
|
||||
impl Service {
|
||||
/// install the Clash Verge Service (windows only)
|
||||
pub fn install_service(&mut self) -> Result<()> {
|
||||
let binary_path = dirs::service_path();
|
||||
let arg = format!("binpath={}", binary_path.as_os_str().to_string_lossy());
|
||||
|
||||
let token = Token::with_current_process()?;
|
||||
let level = token.privilege_level()?;
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let args = [
|
||||
"create",
|
||||
SERVICE_NAME,
|
||||
arg.as_str(),
|
||||
"type=own",
|
||||
"start=AUTO",
|
||||
"displayname=Clash Verge Service",
|
||||
];
|
||||
|
||||
let status = match level {
|
||||
PrivilegeLevel::NotPrivileged => RunasCommond::new("sc").args(&args).status(),
|
||||
_ => StdCommond::new("sc").args(&args).status(),
|
||||
};
|
||||
|
||||
match status {
|
||||
Ok(status) => {
|
||||
if status.success() {
|
||||
log::info!("install clash verge service successfully");
|
||||
} else if status.code() == Some(1073i32) {
|
||||
log::info!("clash verge service is installed");
|
||||
} else {
|
||||
log::error!(
|
||||
"failed to install service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => log::error!("failed to install service for {err}"),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// uninstall
|
||||
pub fn uninstall_service(&mut self) -> Result<()> {
|
||||
let token = Token::with_current_process()?;
|
||||
let level = token.privilege_level()?;
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let args = ["delete", SERVICE_NAME];
|
||||
|
||||
let status = match level {
|
||||
PrivilegeLevel::NotPrivileged => RunasCommond::new("sc").args(&args).status(),
|
||||
_ => StdCommond::new("sc").args(&args).status(),
|
||||
};
|
||||
|
||||
match status {
|
||||
Ok(status) => {
|
||||
if status.success() {
|
||||
log::info!("uninstall clash verge service successfully");
|
||||
} else {
|
||||
log::error!(
|
||||
"failed to uninstall service with status {}",
|
||||
status.code().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(err) => log::error!("failed to uninstall service for {err}"),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ static VERGE_CONFIG: &str = "verge.yaml";
|
||||
static PROFILE_YAML: &str = "profiles.yaml";
|
||||
static PROFILE_TEMP: &str = "clash-verge-runtime.yaml";
|
||||
|
||||
#[cfg(windows)]
|
||||
static mut RESOURCE_DIR: Option<PathBuf> = None;
|
||||
|
||||
/// portable flag
|
||||
#[allow(unused)]
|
||||
static mut PORTABLE_FLAG: bool = false;
|
||||
@@ -58,9 +61,16 @@ pub fn app_home_dir() -> PathBuf {
|
||||
|
||||
/// get the resources dir
|
||||
pub fn app_resources_dir(package_info: &PackageInfo) -> PathBuf {
|
||||
resource_dir(package_info, &Env::default())
|
||||
let res_dir = resource_dir(package_info, &Env::default())
|
||||
.unwrap()
|
||||
.join("resources")
|
||||
.join("resources");
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
RESOURCE_DIR = Some(res_dir.clone());
|
||||
}
|
||||
|
||||
res_dir
|
||||
}
|
||||
|
||||
/// profiles dir
|
||||
@@ -92,3 +102,14 @@ pub fn profiles_temp_path() -> PathBuf {
|
||||
#[cfg(feature = "debug-yml")]
|
||||
return app_home_dir().join(PROFILE_TEMP);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
static SERVICE_PATH: &str = "clash-verge-service.exe";
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn service_path() -> PathBuf {
|
||||
unsafe {
|
||||
let res_dir = RESOURCE_DIR.clone().unwrap();
|
||||
res_dir.join(SERVICE_PATH)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user