From df93cb103c2f22090deb8e6db70c550a334d19e4 Mon Sep 17 00:00:00 2001 From: GyDi Date: Thu, 17 Nov 2022 20:19:40 +0800 Subject: [PATCH] refactor: for windows --- src-tauri/Cargo.lock | 36 ++--- src-tauri/src/cmds.rs | 20 +-- src-tauri/src/config/prfitem.rs | 8 +- src-tauri/src/core/core.rs | 78 +++++++---- src-tauri/src/core/core_service.rs | 217 ---------------------------- src-tauri/src/core/handle.rs | 10 +- src-tauri/src/core/mod.rs | 2 +- src-tauri/src/core/win_service.rs | 218 +++++++++++++++++++++++++++++ src-tauri/src/feat.rs | 7 +- src-tauri/src/main.rs | 12 +- src-tauri/src/utils/config.rs | 2 +- src-tauri/src/utils/dirs.rs | 18 +-- src-tauri/src/utils/help.rs | 9 +- src-tauri/src/utils/init.rs | 26 +--- src-tauri/src/utils/resolve.rs | 4 +- 15 files changed, 332 insertions(+), 335 deletions(-) delete mode 100644 src-tauri/src/core/core_service.rs create mode 100644 src-tauri/src/core/win_service.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c507246..f7aed53 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -985,9 +985,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.3", "crypto-common", @@ -3235,9 +3235,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" dependencies = [ "base64", "bytes", @@ -3670,7 +3670,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.5", + "digest 0.10.6", ] [[package]] @@ -3681,7 +3681,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.5", + "digest 0.10.6", ] [[package]] @@ -3705,7 +3705,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.5", + "digest 0.10.6", ] [[package]] @@ -3955,9 +3955,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c460173627564bde252ca5ebf346ba5b37c5cee1a445782bacc8e9b8d38b5e" +checksum = "a0382fcc02b87420a0d024ff6ec2dbfccdccafb46de8c03fb07dbf2f36810a42" dependencies = [ "bitflags", "cairo-rs", @@ -3995,7 +3995,7 @@ dependencies = [ "scopeguard", "serde", "unicode-segmentation", - "uuid 1.2.1", + "uuid 1.2.2", "windows 0.39.0", "windows-implement", "x11-dl", @@ -4060,7 +4060,7 @@ dependencies = [ "time 0.3.17", "tokio", "url", - "uuid 1.2.1", + "uuid 1.2.2", "webkit2gtk", "webview2-com", "windows 0.39.0", @@ -4105,7 +4105,7 @@ dependencies = [ "tauri-utils", "thiserror", "time 0.3.17", - "uuid 1.2.1", + "uuid 1.2.2", "walkdir", ] @@ -4138,7 +4138,7 @@ dependencies = [ "serde_json", "tauri-utils", "thiserror", - "uuid 1.2.1", + "uuid 1.2.2", "webview2-com", "windows 0.39.0", ] @@ -4156,7 +4156,7 @@ dependencies = [ "raw-window-handle", "tauri-runtime", "tauri-utils", - "uuid 1.2.1", + "uuid 1.2.2", "webkit2gtk", "webview2-com", "windows 0.39.0", @@ -4708,9 +4708,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "uuid" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83" +checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" dependencies = [ "getrandom 0.2.8", ] @@ -5358,9 +5358,9 @@ dependencies = [ [[package]] name = "wry" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923d297b203eae65b095af16c02978b7932be1968012b4da7138390edf34dea5" +checksum = "e0fd80bb2bd8e8eae26d59c5164e70233f29f7593cb886a958024a4fd8b5cd21" dependencies = [ "base64", "block", diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index d980176..8b09293 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -19,7 +19,7 @@ pub fn get_profiles() -> CmdResult { #[tauri::command] pub async fn enhance_profiles() -> CmdResult { - wrap_err!(CoreManager::global().activate_config().await) + wrap_err!(feat::handle_activate().await) } #[deprecated] @@ -209,8 +209,8 @@ pub async fn change_clash_core(clash_core: Option) -> CmdResult { /// restart the sidecar #[tauri::command] -pub fn restart_sidecar() -> CmdResult { - wrap_err!(CoreManager::global().run_core()) +pub async fn restart_sidecar() -> CmdResult { + wrap_err!(CoreManager::global().run_core().await) } /// get the system proxy @@ -254,22 +254,22 @@ pub fn open_web_url(url: String) -> CmdResult<()> { #[cfg(windows)] pub mod service { use super::*; - use crate::core::win_service::JsonResponse; + use crate::core::win_service; #[tauri::command] pub async fn start_service() -> CmdResult { - wrap_err!(crate::core::Service::start_service().await) + wrap_err!(win_service::start_service().await) } #[tauri::command] pub async fn stop_service() -> CmdResult { - wrap_err!(crate::core::Service::stop_service().await) + wrap_err!(win_service::stop_service().await) } #[tauri::command] - pub async fn check_service() -> CmdResult { + pub async fn check_service() -> CmdResult { // no log - match crate::core::Service::check_service().await { + match win_service::check_service().await { Ok(res) => Ok(res), Err(err) => Err(err.to_string()), } @@ -277,12 +277,12 @@ pub mod service { #[tauri::command] pub async fn install_service() -> CmdResult { - wrap_err!(crate::core::Service::install_service().await) + wrap_err!(win_service::install_service().await) } #[tauri::command] pub async fn uninstall_service() -> CmdResult { - wrap_err!(crate::core::Service::uninstall_service().await) + wrap_err!(win_service::uninstall_service().await) } } diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index a377fb9..cb81212 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -172,7 +172,7 @@ impl PrfItem { selected: None, extra: None, option: None, - updated: Some(help::get_now()), + updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(file_data.unwrap_or(tmpl::ITEM_LOCAL.into())), }) } @@ -301,7 +301,7 @@ impl PrfItem { selected: None, extra, option, - updated: Some(help::get_now()), + updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(data), }) } @@ -322,7 +322,7 @@ impl PrfItem { selected: None, extra: None, option: None, - updated: Some(help::get_now()), + updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(tmpl::ITEM_MERGE.into()), }) } @@ -343,7 +343,7 @@ impl PrfItem { selected: None, extra: None, option: None, - updated: Some(help::get_now()), + updated: Some(chrono::Local::now().timestamp() as usize), file_data: Some(tmpl::ITEM_SCRIPT.into()), }) } diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 30fe6cc..f9dee69 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -47,22 +47,13 @@ impl CoreManager { } } - // // 使用配置的核心 - // let verge_core = { Config::verge().clash_core.clone() }; - // if let Some(verge_core) = verge_core { - // if verge_core == "clash" || verge_core == "clash-meta" { - // let mut clash_core = self.clash_core.lock(); - // *clash_core = verge_core; - // } - // } - - // 启动clash - self.run_core()?; - - // 更新配置 tauri::async_runtime::spawn(async { - sleep(Duration::from_millis(100)).await; - crate::log_err!(Self::global().activate_config().await); + // 启动clash + if Self::global().run_core().await.is_ok() { + // 更新配置 + sleep(Duration::from_millis(100)).await; + crate::log_err!(Self::global().activate_config().await); + } }); Ok(()) @@ -89,9 +80,35 @@ impl CoreManager { } /// 启动核心 - pub fn run_core(&self) -> Result<()> { - // 先纠正重要的配置字段 - self.correct_config()?; + pub async fn run_core(&self) -> Result<()> { + #[cfg(target_os = "windows")] + { + use super::win_service; + + // 服务模式 + let enable = { + let enable = Config::verge().data().enable_service_mode.clone(); + enable.unwrap_or(false) + }; + + *self.use_service_mode.lock() = enable; + + if enable { + // 服务模式启动失败就直接运行sidecar + match { + win_service::check_service().await?; + win_service::run_core_by_service().await + } { + Ok(_) => return Ok(()), + Err(err) => { + // 修改这个值,免得stop出错 + *self.use_service_mode.lock() = false; + + log::error!(target: "app", "{err}"); + } + } + } + } let mut sidecar = self.sidecar.lock(); @@ -137,15 +154,15 @@ impl CoreManager { Logger::global().set_log(line); } CommandEvent::Stderr(err) => { - log::error!(target: "app" ,"[clash error]: {err}"); + log::error!(target: "app" ,"[clash]: {err}"); Logger::global().set_log(err); } CommandEvent::Error(err) => { - log::error!(target: "app" ,"[clash error]: {err}"); + log::error!(target: "app" ,"[clash]: {err}"); Logger::global().set_log(err); } CommandEvent::Terminated(_) => { - log::info!(target: "app" ,"clash core Terminated"); + log::info!(target: "app" ,"clash core terminated"); break; } _ => {} @@ -158,6 +175,14 @@ impl CoreManager { /// 停止核心运行 pub fn stop_core(&self) -> Result<()> { + #[cfg(target_os = "windows")] + if *self.use_service_mode.lock() { + tauri::async_runtime::block_on(async move { + log_err!(super::win_service::stop_core_by_service().await); + }); + return Ok(()); + } + let mut sidecar = self.sidecar.lock(); if let Some(child) = sidecar.take() { let _ = child.kill(); @@ -180,7 +205,7 @@ impl CoreManager { Config::verge().draft().clash_core = Some(clash_core); } - match self.run_core() { + match self.run_core().await { Ok(_) => { log_err!({ Config::verge().apply(); @@ -198,13 +223,6 @@ impl CoreManager { } } - /// 纠正一下配置 - /// 将mixed-port和external-controller都改为配置的内容 - pub fn correct_config(&self) -> Result<()> { - // todo!() - Ok(()) - } - /// 激活一个配置 pub async fn activate_config(&self) -> Result<()> { let clash_config = { Config::clash().latest().clone() }; @@ -224,8 +242,6 @@ impl CoreManager { // 检查配置是否正常 self.check_config()?; - // todo 是否需要检查核心是否运行 - // 发送请求 发送5次 for i in 0..5 { match clash_api::put_configs().await { diff --git a/src-tauri/src/core/core_service.rs b/src-tauri/src/core/core_service.rs deleted file mode 100644 index 7d52194..0000000 --- a/src-tauri/src/core/core_service.rs +++ /dev/null @@ -1,217 +0,0 @@ -#![cfg(target_os = "windows")] - -use crate::utils::{config, dirs}; -use anyhow::Context; -use deelevate::{PrivilegeLevel, Token}; -use runas::Command as RunasCommand; -use serde::{Deserialize, Serialize}; -use std::os::windows::process::CommandExt; -use std::{env::current_exe, process::Command as StdCommand}; - -const SERVICE_NAME: &str = "clash_verge_service"; - -const SERVICE_URL: &str = "http://127.0.0.1:33211"; - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct ResponseBody { - pub bin_path: String, - pub config_dir: String, - pub log_file: String, -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct JsonResponse { - pub code: u64, - pub msg: String, - pub data: Option, -} - -impl Service { - /// Install the Clash Verge Service - /// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程 - pub async fn install_service() -> Result<()> { - let binary_path = dirs::service_path(); - 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 level = token.privilege_level()?; - - let status = match level { - PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).status()?, - _ => StdCommand::new(install_path) - .creation_flags(0x08000000) - .status()?, - }; - - if !status.success() { - bail!( - "failed to install service with status {}", - status.code().unwrap() - ); - } - - Ok(()) - } - - /// Uninstall the Clash Verge Service - /// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程 - 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 level = token.privilege_level()?; - - let status = match level { - PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).status()?, - _ => StdCommand::new(uninstall_path) - .creation_flags(0x08000000) - .status()?, - }; - - if !status.success() { - bail!( - "failed to uninstall service with status {}", - status.code().unwrap() - ); - } - - Ok(()) - } - - /// [deprecated] - /// start service - /// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程 - pub async fn start_service() -> Result<()> { - let token = Token::with_current_process()?; - let level = token.privilege_level()?; - - let args = ["start", SERVICE_NAME]; - - let status = match level { - PrivilegeLevel::NotPrivileged => RunasCommand::new("sc").args(&args).status()?, - _ => StdCommand::new("sc").args(&args).status()?, - }; - - match status.success() { - true => Ok(()), - false => bail!( - "failed to start service with status {}", - status.code().unwrap() - ), - } - } - - /// stop service - pub async fn stop_service() -> Result<()> { - let url = format!("{SERVICE_URL}/stop_service"); - let res = reqwest::ClientBuilder::new() - .no_proxy() - .build()? - .post(url) - .send() - .await? - .json::() - .await - .context("failed to connect to the Clash Verge Service")?; - - if res.code != 0 { - bail!(res.msg); - } - - Ok(()) - } - - /// check the windows service status - pub async fn check_service() -> Result { - let url = format!("{SERVICE_URL}/get_clash"); - let response = reqwest::ClientBuilder::new() - .no_proxy() - .build()? - .get(url) - .send() - .await? - .json::() - .await - .context("failed to connect to the Clash Verge Service")?; - - Ok(response) - } - - /// start the clash by service - pub(super) async fn start_clash_by_service() -> Result<()> { - let status = Self::check_service().await?; - - if status.code == 0 { - Self::stop_clash_by_service().await?; - sleep(Duration::from_secs(1)).await; - } - - let clash_core = { - let global = Data::global(); - let verge = global.verge.lock(); - verge.clash_core.clone().unwrap_or("clash".into()) - }; - - let clash_bin = format!("{clash_core}.exe"); - let bin_path = current_exe().unwrap().with_file_name(clash_bin); - let bin_path = bin_path.as_os_str().to_str().unwrap(); - - let config_dir = dirs::app_home_dir(); - let config_dir = config_dir.as_os_str().to_str().unwrap(); - - let log_path = dirs::service_log_file(); - let log_path = log_path.as_os_str().to_str().unwrap(); - - let mut map = HashMap::new(); - map.insert("bin_path", bin_path); - map.insert("config_dir", config_dir); - map.insert("log_file", log_path); - - let url = format!("{SERVICE_URL}/start_clash"); - let res = reqwest::ClientBuilder::new() - .no_proxy() - .build()? - .post(url) - .json(&map) - .send() - .await? - .json::() - .await - .context("failed to connect to the Clash Verge Service")?; - - if res.code != 0 { - bail!(res.msg); - } - - Ok(()) - } - - /// stop the clash by service - pub(super) async fn stop_clash_by_service() -> Result<()> { - let url = format!("{SERVICE_URL}/stop_clash"); - let res = reqwest::ClientBuilder::new() - .no_proxy() - .build()? - .post(url) - .send() - .await? - .json::() - .await - .context("failed to connect to the Clash Verge Service")?; - - if res.code != 0 { - bail!(res.msg); - } - - Ok(()) - } -} diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index 7026e34..5b46cea 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -1,5 +1,5 @@ use super::tray::Tray; -use crate::log_if_err; +use crate::log_err; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; @@ -33,26 +33,26 @@ impl Handle { pub fn refresh_clash() { if let Some(window) = Self::global().get_window() { - log_if_err!(window.emit("verge://refresh-clash-config", "yes")); + log_err!(window.emit("verge://refresh-clash-config", "yes")); } } pub fn refresh_verge() { if let Some(window) = Self::global().get_window() { - log_if_err!(window.emit("verge://refresh-verge-config", "yes")); + log_err!(window.emit("verge://refresh-verge-config", "yes")); } } #[allow(unused)] pub fn refresh_profiles() { if let Some(window) = Self::global().get_window() { - log_if_err!(window.emit("verge://refresh-profiles-config", "yes")); + log_err!(window.emit("verge://refresh-profiles-config", "yes")); } } pub fn notice_message, M: Into>(status: S, msg: M) { if let Some(window) = Self::global().get_window() { - log_if_err!(window.emit("verge://notice-message", (status.into(), msg.into()))); + log_err!(window.emit("verge://notice-message", (status.into(), msg.into()))); } } diff --git a/src-tauri/src/core/mod.rs b/src-tauri/src/core/mod.rs index c0d1d6a..20e5600 100644 --- a/src-tauri/src/core/mod.rs +++ b/src-tauri/src/core/mod.rs @@ -13,7 +13,6 @@ pub mod clash_api; mod core; -pub mod core_service; pub mod handle; pub mod hotkey; pub mod logger; @@ -21,6 +20,7 @@ pub mod logger; pub mod sysopt; pub mod timer; pub mod tray; +pub mod win_service; pub use self::core::*; // pub use self::service::*; diff --git a/src-tauri/src/core/win_service.rs b/src-tauri/src/core/win_service.rs new file mode 100644 index 0000000..b0ddb8f --- /dev/null +++ b/src-tauri/src/core/win_service.rs @@ -0,0 +1,218 @@ +#![cfg(target_os = "windows")] + +use crate::config::Config; +use crate::utils::dirs; +use anyhow::{bail, Context, Result}; +use deelevate::{PrivilegeLevel, Token}; +use runas::Command as RunasCommand; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::os::windows::process::CommandExt; +use std::time::Duration; +use std::{env::current_exe, process::Command as StdCommand}; +use tokio::time::sleep; + +const SERVICE_NAME: &str = "clash_verge_service"; + +const SERVICE_URL: &str = "http://127.0.0.1:33211"; + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct ResponseBody { + pub core_type: Option, + pub bin_path: String, + pub config_dir: String, + pub log_file: String, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct JsonResponse { + pub code: u64, + pub msg: String, + pub data: Option, +} + +/// Install the Clash Verge Service +/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程 +pub async fn install_service() -> Result<()> { + let binary_path = dirs::service_path(); + 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 level = token.privilege_level()?; + + let status = match level { + PrivilegeLevel::NotPrivileged => RunasCommand::new(install_path).status()?, + _ => StdCommand::new(install_path) + .creation_flags(0x08000000) + .status()?, + }; + + if !status.success() { + bail!( + "failed to install service with status {}", + status.code().unwrap() + ); + } + + Ok(()) +} + +/// Uninstall the Clash Verge Service +/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程 +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 level = token.privilege_level()?; + + let status = match level { + PrivilegeLevel::NotPrivileged => RunasCommand::new(uninstall_path).status()?, + _ => StdCommand::new(uninstall_path) + .creation_flags(0x08000000) + .status()?, + }; + + if !status.success() { + bail!( + "failed to uninstall service with status {}", + status.code().unwrap() + ); + } + + Ok(()) +} + +/// start service +/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程 +#[deprecated] +pub async fn start_service() -> Result<()> { + let token = Token::with_current_process()?; + let level = token.privilege_level()?; + + let args = ["start", SERVICE_NAME]; + + let status = match level { + PrivilegeLevel::NotPrivileged => RunasCommand::new("sc").args(&args).status()?, + _ => StdCommand::new("sc").args(&args).status()?, + }; + + match status.success() { + true => Ok(()), + false => bail!( + "failed to start service with status {}", + status.code().unwrap() + ), + } +} + +/// stop service +pub async fn stop_service() -> Result<()> { + let url = format!("{SERVICE_URL}/stop_service"); + let res = reqwest::ClientBuilder::new() + .no_proxy() + .build()? + .post(url) + .send() + .await? + .json::() + .await + .context("failed to connect to the Clash Verge Service")?; + + if res.code != 0 { + bail!(res.msg); + } + + Ok(()) +} + +/// check the windows service status +pub async fn check_service() -> Result { + let url = format!("{SERVICE_URL}/get_clash"); + let response = reqwest::ClientBuilder::new() + .no_proxy() + .build()? + .get(url) + .send() + .await? + .json::() + .await + .context("failed to connect to the Clash Verge Service")?; + + Ok(response) +} + +/// start the clash by service +pub(super) async fn run_core_by_service() -> Result<()> { + let status = check_service().await?; + + if status.code == 0 { + stop_core_by_service().await?; + sleep(Duration::from_secs(1)).await; + } + + let clash_core = { Config::verge().latest().clash_core.clone() }; + let clash_core = clash_core.unwrap_or("clash".into()); + + let clash_bin = format!("{clash_core}.exe"); + let bin_path = current_exe()?.with_file_name(clash_bin); + let bin_path = dirs::path_to_str(&bin_path)?; + + let config_dir = dirs::app_home_dir(); + let config_dir = dirs::path_to_str(&config_dir)?; + + let log_path = dirs::service_log_file(); + let log_path = dirs::path_to_str(&log_path)?; + + let mut map = HashMap::new(); + map.insert("core_type", clash_core.as_str()); + map.insert("bin_path", bin_path); + map.insert("config_dir", config_dir); + map.insert("log_file", log_path); + + let url = format!("{SERVICE_URL}/start_clash"); + let res = reqwest::ClientBuilder::new() + .no_proxy() + .build()? + .post(url) + .json(&map) + .send() + .await? + .json::() + .await + .context("failed to connect to the Clash Verge Service")?; + + if res.code != 0 { + bail!(res.msg); + } + + Ok(()) +} + +/// stop the clash by service +pub(super) async fn stop_core_by_service() -> Result<()> { + let url = format!("{SERVICE_URL}/stop_clash"); + let res = reqwest::ClientBuilder::new() + .no_proxy() + .build()? + .post(url) + .send() + .await? + .json::() + .await + .context("failed to connect to the Clash Verge Service")?; + + if res.code != 0 { + bail!(res.msg); + } + + Ok(()) +} diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs index 2667ebe..4436664 100644 --- a/src-tauri/src/feat.rs +++ b/src-tauri/src/feat.rs @@ -7,9 +7,10 @@ use serde_yaml::{Mapping, Value}; // 重启clash pub fn restart_clash_core() { tauri::async_runtime::spawn(async { - CoreManager::global().run_core()?; - log_err!(handle_activate().await); - >::Ok(()) + match CoreManager::global().run_core().await { + Ok(_) => log_err!(handle_activate().await), + Err(err) => log::error!(target: "app", "{err}"), + } }); } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index b019d03..1c89859 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -11,7 +11,7 @@ mod feat; mod utils; use crate::utils::{init, resolve, server}; -use tauri::{api, Manager, SystemTray}; +use tauri::{api, SystemTray}; fn main() -> std::io::Result<()> { // 单例检测 @@ -20,13 +20,7 @@ fn main() -> std::io::Result<()> { return Ok(()); } - #[cfg(target_os = "windows")] - unsafe { - use crate::utils::dirs; - dirs::init_portable_flag(); - } - - crate::log_if_err!(init::init_config()); + crate::log_err!(init::init_config()); #[allow(unused_mut)] let mut builder = tauri::Builder::default() @@ -118,6 +112,8 @@ fn main() -> std::io::Result<()> { } #[cfg(target_os = "macos")] tauri::RunEvent::WindowEvent { label, event, .. } => { + use tauri::Manager; + if label == "main" { match event { tauri::WindowEvent::CloseRequested { api, .. } => { diff --git a/src-tauri/src/utils/config.rs b/src-tauri/src/utils/config.rs index efcdf6a..bcb99f6 100644 --- a/src-tauri/src/utils/config.rs +++ b/src-tauri/src/utils/config.rs @@ -34,7 +34,7 @@ pub fn read_merge_mapping(path: PathBuf) -> Mapping { match serde_yaml::from_str::(&yaml_str) { Ok(mut val) => { - crate::log_if_err!(val.apply_merge()); + crate::log_err!(val.apply_merge()); val.as_mapping().unwrap_or(&map).to_owned() } Err(_) => { diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs index 68cb423..8cb322d 100644 --- a/src-tauri/src/utils/dirs.rs +++ b/src-tauri/src/utils/dirs.rs @@ -1,3 +1,4 @@ +use anyhow::Result; use std::path::PathBuf; use tauri::{ api::path::{home_dir, resource_dir}, @@ -23,20 +24,21 @@ static mut PORTABLE_FLAG: bool = false; pub static mut APP_VERSION: &str = "v1.1.1"; /// initialize portable flag -#[allow(unused)] -pub unsafe fn init_portable_flag() { - #[cfg(target_os = "windows")] - { - use tauri::utils::platform::current_exe; +#[cfg(target_os = "windows")] +pub unsafe fn init_portable_flag() -> Result<()> { + use tauri::utils::platform::current_exe; - let exe = current_exe().unwrap(); - let dir = exe.parent().unwrap(); + let exe = current_exe()?; + + if let Some(dir) = exe.parent() { let dir = PathBuf::from(dir).join(".config/PORTABLE"); if dir.exists() { PORTABLE_FLAG = true; } } + + Ok(()) } /// get the verge app home dir @@ -123,7 +125,7 @@ pub fn service_log_file() -> PathBuf { let log_dir = app_logs_dir().join("service"); - let local_time = Local::now().format("%Y-%m-%d-%H%M%S").to_string(); + let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string(); let log_file = format!("{}.log", local_time); let log_file = log_dir.join(log_file); diff --git a/src-tauri/src/utils/help.rs b/src-tauri/src/utils/help.rs index 0c5bb7e..8ad5925 100644 --- a/src-tauri/src/utils/help.rs +++ b/src-tauri/src/utils/help.rs @@ -3,14 +3,6 @@ use nanoid::nanoid; use std::path::PathBuf; use std::process::Command; use std::str::FromStr; -use std::time::{SystemTime, UNIX_EPOCH}; - -pub fn get_now() -> usize { - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs() as _ -} const ALPHABET: [char; 62] = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', @@ -76,6 +68,7 @@ macro_rules! error { }; } +#[deprecated] #[macro_export] macro_rules! log_if_err { ($result: expr) => { diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index bb36352..7f6c74a 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -17,11 +17,11 @@ fn init_log() -> Result<()> { let _ = fs::create_dir_all(&log_dir); } - let local_time = Local::now().format("%Y-%m-%d-%H%M%S").to_string(); + let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string(); let log_file = format!("{}.log", local_time); let log_file = log_dir.join(log_file); - let time_format = "{d(%Y-%m-%d %H:%M:%S)} - {m}{n}"; + let time_format = "{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}"; let stdout = ConsoleAppender::builder() .encoder(Box::new(PatternEncoder::new(time_format))) .build(); @@ -47,6 +47,11 @@ fn init_log() -> Result<()> { /// Initialize all the files from resources pub fn init_config() -> Result<()> { + #[cfg(target_os = "windows")] + unsafe { + let _ = dirs::init_portable_flag(); + } + let _ = init_log(); let app_dir = dirs::app_home_dir(); @@ -94,21 +99,4 @@ pub fn init_resources(package_info: &PackageInfo) { let _ = fs::copy(src_path, target_path); } } - - // // copy the resource file - // let mmdb_path = app_dir.join("Country.mmdb"); - // let mmdb_tmpl = res_dir.join("Country.mmdb"); - // if !mmdb_path.exists() && mmdb_tmpl.exists() { - // let _ = fs::copy(mmdb_tmpl, mmdb_path); - // } - - // // copy the wintun.dll - // #[cfg(target_os = "windows")] - // { - // let wintun_path = app_dir.join("wintun.dll"); - // let wintun_tmpl = res_dir.join("wintun.dll"); - // if !wintun_path.exists() && wintun_tmpl.exists() { - // let _ = fs::copy(wintun_tmpl, wintun_path); - // } - // } } diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index e7810d7..37c258c 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -93,10 +93,10 @@ pub fn create_window(app_handle: &AppHandle) { } #[cfg(target_os = "macos")] - crate::log_if_err!(builder.decorations(true).inner_size(800.0, 642.0).build()); + crate::log_err!(builder.decorations(true).inner_size(800.0, 642.0).build()); #[cfg(target_os = "linux")] - crate::log_if_err!(builder + crate::log_err!(builder .decorations(false) .transparent(true) .inner_size(800.0, 636.0)