feat: supports auto launch on macos and windows

This commit is contained in:
GyDi 2022-01-15 21:55:05 +08:00
parent 3c3d77fbea
commit cc0e930d34
No known key found for this signature in database
GPG Key ID: 1C95E0D3467B3084
4 changed files with 62 additions and 117 deletions

View File

@ -1,6 +1,6 @@
use crate::utils::{config, dirs, startup, sysopt::SysProxyConfig}; use crate::utils::{config, dirs, sysopt::SysProxyConfig};
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use tauri::api::path::resource_dir; use tauri::api::path::resource_dir;
/// ### `verge.yaml` schema /// ### `verge.yaml` schema
@ -14,7 +14,7 @@ pub struct VergeConfig {
pub theme_blur: Option<bool>, pub theme_blur: Option<bool>,
/// can the app auto startup /// can the app auto startup
pub enable_self_startup: Option<bool>, pub enable_auto_launch: Option<bool>,
/// set system proxy /// set system proxy
pub enable_system_proxy: Option<bool>, pub enable_system_proxy: Option<bool>,
@ -49,7 +49,7 @@ pub struct Verge {
pub cur_sysproxy: Option<SysProxyConfig>, pub cur_sysproxy: Option<SysProxyConfig>,
pub exe_path: Option<PathBuf>, pub auto_launch: Option<AutoLaunch>,
} }
impl Default for Verge { impl Default for Verge {
@ -64,7 +64,7 @@ impl Verge {
config: VergeConfig::new(), config: VergeConfig::new(),
old_sysproxy: None, old_sysproxy: None,
cur_sysproxy: None, cur_sysproxy: None,
exe_path: None, auto_launch: None,
} }
} }
@ -101,53 +101,61 @@ impl Verge {
} }
} }
/// set the exe_path /// init the auto launch
pub fn set_exe_path(&mut self, package_info: &tauri::PackageInfo) { pub fn init_launch(&mut self, package_info: &tauri::PackageInfo) {
let exe = if cfg!(target_os = "windows") { let app_name = "clash-verge";
"clash-verge.exe" let app_path = get_app_path(app_name);
} else { let app_path = resource_dir(package_info).unwrap().join(app_path);
"clash-verge" let app_path = app_path.as_os_str().to_str().unwrap();
};
let path = resource_dir(package_info).unwrap().join(exe); let auto = AutoLaunchBuilder::new()
self.exe_path = Some(path); .set_app_name(app_name)
.set_app_path(app_path)
.build();
self.auto_launch = Some(auto);
} }
/// sync the startup when run the app /// sync the startup when run the app
pub fn sync_startup(&self) -> Result<(), String> { pub fn sync_launch(&self) -> Result<(), String> {
let enable = self.config.enable_self_startup.clone().unwrap_or(false); let enable = self.config.enable_auto_launch.clone().unwrap_or(false);
if !enable { if !enable {
return Ok(()); return Ok(());
} }
if self.exe_path.is_none() {
return Err("should init the exe_path first".into()); if self.auto_launch.is_none() {
return Err("should init the auto launch first".into());
}
let auto_launch = self.auto_launch.clone().unwrap();
let is_enabled = auto_launch.is_enabled().unwrap_or(false);
if !is_enabled {
if let Err(_) = auto_launch.enable() {
return Err("failed to enable auto-launch".into());
}
} }
let exe_path = self.exe_path.clone().unwrap();
match startup::get_startup(&exe_path) {
Ok(sys_enable) => {
if sys_enable || (!sys_enable && startup::set_startup(true, &exe_path).is_ok()) {
Ok(()) Ok(())
} else {
Err("failed to sync startup".into())
}
}
Err(_) => Err("failed to get system startup info".into()),
}
} }
/// update the startup /// update the startup
fn update_startup(&mut self, enable: bool) -> Result<(), String> { fn update_launch(&mut self, enable: bool) -> Result<(), String> {
let conf_enable = self.config.enable_self_startup.clone().unwrap_or(false); let conf_enable = self.config.enable_auto_launch.clone().unwrap_or(false);
if enable == conf_enable { if enable == conf_enable {
return Ok(()); return Ok(());
} }
if self.exe_path.is_none() {
return Err("should init the exe_path first".into()); let auto_launch = self.auto_launch.clone().unwrap();
}
let exe_path = self.exe_path.clone().unwrap(); let result = if enable {
match startup::set_startup(enable, &exe_path) { auto_launch.enable()
} else {
auto_launch.disable()
};
match result {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(_) => Err("failed to set system startup info".into()), Err(_) => Err("failed to set system startup info".into()),
} }
@ -166,10 +174,10 @@ impl Verge {
} }
// should update system startup // should update system startup
if patch.enable_self_startup.is_some() { if patch.enable_auto_launch.is_some() {
let enable = patch.enable_self_startup.unwrap(); let enable = patch.enable_auto_launch.unwrap();
self.update_startup(enable)?; self.update_launch(enable)?;
self.config.enable_self_startup = Some(enable); self.config.enable_auto_launch = Some(enable);
} }
// should update system proxy // should update system proxy
@ -187,7 +195,7 @@ impl Verge {
} }
// todo // todo
// should update system proxt too // should update system proxy too
if patch.system_proxy_bypass.is_some() { if patch.system_proxy_bypass.is_some() {
self.config.system_proxy_bypass = patch.system_proxy_bypass; self.config.system_proxy_bypass = patch.system_proxy_bypass;
} }
@ -195,3 +203,14 @@ impl Verge {
self.config.save_file() self.config.save_file()
} }
} }
// Get the target app_path
fn get_app_path(app_name: &str) -> String {
#[cfg(target_os = "linux")]
let ext = "";
#[cfg(target_os = "macos")]
let ext = ".app";
#[cfg(target_os = "windows")]
let ext = ".exe";
String::from(app_name) + ext
}

View File

@ -4,5 +4,4 @@ pub mod fetch;
pub mod init; pub mod init;
pub mod resolve; pub mod resolve;
pub mod server; pub mod server;
pub mod startup;
pub mod sysopt; pub mod sysopt;

View File

@ -9,6 +9,7 @@ pub fn resolve_setup(app: &App) {
let window = app.get_window("main").unwrap(); let window = app.get_window("main").unwrap();
window.set_shadow(true); window.set_shadow(true);
// enable system blur
use tauri_plugin_vibrancy::Vibrancy; use tauri_plugin_vibrancy::Vibrancy;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
window.apply_blur(); window.apply_blur();
@ -42,9 +43,9 @@ pub fn resolve_setup(app: &App) {
log::error!("{}", err); log::error!("{}", err);
} }
verge.set_exe_path(app.package_info());
verge.init_sysproxy(clash.info.port.clone()); verge.init_sysproxy(clash.info.port.clone());
if let Err(err) = verge.sync_startup() { verge.init_launch(app.package_info());
if let Err(err) = verge.sync_launch() {
log::error!("{}", err); log::error!("{}", err);
} }
} }

View File

@ -1,74 +0,0 @@
use std::io;
use std::path::PathBuf;
static APP_KEY: &str = "ClashVerge";
/// get the startup value
/// whether as same as the exe_path
#[cfg(target_os = "windows")]
pub fn get_startup(exe_path: &PathBuf) -> io::Result<bool> {
use winreg::enums::*;
use winreg::RegKey;
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let cur_var = hkcu.open_subkey_with_flags(
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
KEY_READ,
)?;
match cur_var.get_value::<String, _>(APP_KEY) {
Ok(path) => {
let exe_path = exe_path.clone();
let exe_path = exe_path.as_os_str().to_str().unwrap();
Ok(path == exe_path)
}
Err(_) => Ok(false),
}
}
/// set the startup on windows
/// delete the reg key if disabled
#[cfg(target_os = "windows")]
pub fn set_startup(enable: bool, exe_path: &PathBuf) -> io::Result<()> {
use winreg::enums::*;
use winreg::RegKey;
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let cur_var = hkcu.open_subkey_with_flags(
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
KEY_SET_VALUE,
)?;
match enable {
true => {
let exe_path = exe_path.clone();
let exe_path = exe_path.as_os_str().to_str().unwrap();
cur_var.set_value::<&str, _>(APP_KEY, &exe_path)
}
false => cur_var.delete_value(APP_KEY),
}
}
/// todo
#[cfg(target_os = "macos")]
pub fn get_startup(exe_path: &PathBuf) -> io::Result<bool> {
Ok(true)
}
/// todo
#[cfg(target_os = "macos")]
pub fn set_startup(enable: bool, exe_path: &PathBuf) -> io::Result<()> {
Ok(())
}
#[cfg(target_os = "windows")]
#[test]
fn test() {
let path = PathBuf::from(r"D:\Software\Clash Verge\clash-verge.exe");
assert!(set_startup(true, &path).is_ok());
assert_eq!(get_startup(&path).unwrap(), true);
assert!(set_startup(false, &path).is_ok());
assert_eq!(get_startup(&path).unwrap(), false);
}