fix: change service installer and uninstaller

This commit is contained in:
GyDi 2022-04-27 15:46:44 +08:00 committed by GitHub
parent 77ef3847ce
commit f88989bd4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 49 deletions

View File

@ -143,20 +143,26 @@ async function resolveService() {
if (platform !== "win32") return; if (platform !== "win32") return;
const url =
"https://github.com/zzzgydi/clash-verge-service/releases/download/latest/clash-verge-service.exe";
const binName = "clash-verge-service.exe";
const resDir = path.join(cwd, "src-tauri/resources"); const resDir = path.join(cwd, "src-tauri/resources");
const targetPath = path.join(resDir, binName);
if (!FORCE && (await fs.pathExists(targetPath))) return; const repo =
"https://github.com/zzzgydi/clash-verge-service/releases/download/latest";
async function help(bin) {
const targetPath = path.join(resDir, bin);
if (!FORCE && (await fs.pathExists(targetPath))) return;
const url = `${repo}/${bin}`;
await downloadFile(url, targetPath);
}
await fs.mkdirp(resDir); await fs.mkdirp(resDir);
await downloadFile(url, targetPath); await help("clash-verge-service.exe");
await help("install-service.exe");
await help("uninstall-service.exe");
console.log(`[INFO]: resolve ${binName} finished`); console.log(`[INFO]: resolve Service finished`);
} }
/** /**

View File

@ -258,20 +258,20 @@ pub mod service {
#[tauri::command] #[tauri::command]
pub async fn check_service() -> Result<JsonResponse, String> { pub async fn check_service() -> Result<JsonResponse, String> {
wrap_err!(crate::core::Service::check_service().await) // no log
match crate::core::Service::check_service().await {
Ok(res) => Ok(res),
Err(err) => Err(err.to_string()),
}
} }
#[tauri::command] #[tauri::command]
pub async fn install_service() -> Result<(), String> { pub async fn install_service() -> Result<(), String> {
log_if_err!(crate::core::Service::install_service().await); wrap_err!(crate::core::Service::install_service().await)
let ret = wrap_err!(crate::core::Service::start_service().await);
log::info!("clash verge service started successfully");
ret
} }
#[tauri::command] #[tauri::command]
pub async fn uninstall_service() -> Result<(), String> { pub async fn uninstall_service() -> Result<(), String> {
log_if_err!(crate::core::Service::stop_service().await);
wrap_err!(crate::core::Service::uninstall_service().await) wrap_err!(crate::core::Service::uninstall_service().await)
} }
} }

View File

@ -191,8 +191,9 @@ pub mod win_service {
use super::*; use super::*;
use anyhow::Context; use anyhow::Context;
use deelevate::{PrivilegeLevel, Token}; use deelevate::{PrivilegeLevel, Token};
use runas::Command as RunasCommond; use runas::Command as RunasCommand;
use std::{env::current_exe, process::Command as StdCommond}; use std::os::windows::process::CommandExt;
use std::{env::current_exe, process::Command as StdCommand};
const SERVICE_NAME: &str = "clash_verge_service"; const SERVICE_NAME: &str = "clash_verge_service";
@ -217,61 +218,63 @@ pub mod win_service {
/// 该函数应该在协程或者线程中执行避免UAC弹窗阻塞主线程 /// 该函数应该在协程或者线程中执行避免UAC弹窗阻塞主线程
pub async fn install_service() -> Result<()> { pub async fn install_service() -> Result<()> {
let binary_path = dirs::service_path(); let binary_path = dirs::service_path();
let arg = format!("binpath={}", binary_path.as_os_str().to_string_lossy()); let install_path = binary_path.with_file_name("install-service.exe");
if !install_path.exists() {
bail!("installer exe not found");
}
let token = Token::with_current_process()?; let token = Token::with_current_process()?;
let level = token.privilege_level()?; let level = token.privilege_level()?;
let args = [
"create",
SERVICE_NAME,
arg.as_str(),
"type=own",
"start=AUTO",
"displayname=Clash Verge Service",
];
let status = match level { let status = match level {
PrivilegeLevel::NotPrivileged => RunasCommond::new("sc").args(&args).status()?, PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).status()?,
_ => StdCommond::new("sc").args(&args).status()?, _ => StdCommand::new(install_path)
.creation_flags(0x08000000)
.status()?,
}; };
if status.success() { if !status.success() {
return Ok(()); bail!(
"failed to install service with status {}",
status.code().unwrap()
);
} }
if status.code() == Some(1073i32) { Ok(())
bail!("clash verge service is installed");
}
bail!(
"failed to install service with status {}",
status.code().unwrap()
)
} }
/// Uninstall the Clash Verge Service /// Uninstall the Clash Verge Service
/// 该函数应该在协程或者线程中执行避免UAC弹窗阻塞主线程 /// 该函数应该在协程或者线程中执行避免UAC弹窗阻塞主线程
pub async fn uninstall_service() -> Result<()> { pub async fn uninstall_service() -> Result<()> {
let binary_path = dirs::service_path();
let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
if !uninstall_path.exists() {
bail!("uninstaller exe not found");
}
let token = Token::with_current_process()?; let token = Token::with_current_process()?;
let level = token.privilege_level()?; let level = token.privilege_level()?;
let args = ["delete", SERVICE_NAME];
let status = match level { let status = match level {
PrivilegeLevel::NotPrivileged => RunasCommond::new("sc").args(&args).status()?, PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).status()?,
_ => StdCommond::new("sc").args(&args).status()?, _ => StdCommand::new(uninstall_path)
.creation_flags(0x08000000)
.status()?,
}; };
match status.success() { if !status.success() {
true => Ok(()), bail!(
false => bail!(
"failed to uninstall service with status {}", "failed to uninstall service with status {}",
status.code().unwrap() status.code().unwrap()
), );
} }
Ok(())
} }
/// [deprecated]
/// start service /// start service
/// 该函数应该在协程或者线程中执行避免UAC弹窗阻塞主线程 /// 该函数应该在协程或者线程中执行避免UAC弹窗阻塞主线程
pub async fn start_service() -> Result<()> { pub async fn start_service() -> Result<()> {
@ -281,8 +284,8 @@ pub mod win_service {
let args = ["start", SERVICE_NAME]; let args = ["start", SERVICE_NAME];
let status = match level { let status = match level {
PrivilegeLevel::NotPrivileged => RunasCommond::new("sc").args(&args).status()?, PrivilegeLevel::NotPrivileged => RunasCommand::new("sc").args(&args).status()?,
_ => StdCommond::new("sc").args(&args).status()?, _ => StdCommand::new("sc").args(&args).status()?,
}; };
match status.success() { match status.success() {