From 3566b0ee7a01379cece547fb752e90f4e436638b Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 26 Apr 2022 11:19:45 +0800 Subject: [PATCH] new mac service and local config --- Cargo.lock | 70 ------ Cargo.toml | 1 - libs/hbb_common/src/config.rs | 241 ++++++++----------- libs/hbb_common/src/lib.rs | 6 + src/common.rs | 5 + src/ipc.rs | 55 +++-- src/lang.rs | 4 +- src/platform/macos.rs | 130 +++++++--- src/platform/privileges_scripts/install.scpt | 13 +- src/platform/privileges_scripts/load.scpt | 16 -- src/platform/privileges_scripts/unload.scpt | 6 - src/server.rs | 133 +++------- src/ui.rs | 36 +-- src/ui/ab.tis | 4 +- src/ui/index.tis | 7 +- 15 files changed, 308 insertions(+), 419 deletions(-) delete mode 100644 src/platform/privileges_scripts/load.scpt delete mode 100644 src/platform/privileges_scripts/unload.scpt diff --git a/Cargo.lock b/Cargo.lock index 6d26c022e..11def668f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1168,25 +1168,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fsevent" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -dependencies = [ - "bitflags", - "fsevent-sys", -] - -[[package]] -name = "fsevent-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" -dependencies = [ - "libc", -] - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -1805,26 +1786,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "inotify" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" -dependencies = [ - "bitflags", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - [[package]] name = "instant" version = "0.1.12" @@ -2205,18 +2166,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio 0.6.23", - "slab", -] - [[package]] name = "mio-named-pipes" version = "0.1.7" @@ -2368,24 +2317,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "notify" -version = "4.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" -dependencies = [ - "bitflags", - "filetime", - "fsevent", - "fsevent-sys", - "inotify", - "libc", - "mio 0.6.23", - "mio-extras", - "walkdir", - "winapi 0.3.9", -] - [[package]] name = "ntapi" version = "0.3.7" @@ -3349,7 +3280,6 @@ dependencies = [ "mac_address", "machine-uid", "magnum-opus", - "notify", "num_cpus", "objc", "parity-tokio-ipc", diff --git a/Cargo.toml b/Cargo.toml index 92479ef60..9213a4268 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,7 +72,6 @@ cocoa = "0.24" dispatch = "0.2" core-foundation = "0.9" core-graphics = "0.22" -notify = "4.0.17" include_dir = "0.7.2" [target.'cfg(target_os = "linux")'.dependencies] psimple = { package = "libpulse-simple-binding", version = "2.25" } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 8b1504d79..74982de5d 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -22,10 +22,7 @@ const SERIAL: i32 = 1; #[cfg(target_os = "macos")] // 128x128 on 160x160 canvas, then shrink to 128, mac looks better with padding pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAyVBMVEUAAAAAcf8Acf8Acf8Acv8Acf8Acf8Acf8Acf8AcP8Acf8Ab/8AcP8Acf////8AaP/z+f/o8v/k7v/5/v/T5f8AYP/u9v/X6f+hx/+Kuv95pP8Aef/B1/+TwP9xoP8BdP/g6P+Irv9ZmP8Bgf/E3f98q/9sn/+01f+Es/9nm/9Jif8hhv8off/M4P+syP+avP86iP/c7f+xy/9yqf9Om/9hk/9Rjv+60P99tv9fpf88lv8yjf8Tgf8deP+kvP8BiP8NeP8hkP80gP8oj2VLAAAADXRSTlMA7o7qLvnaxZ1FOxYPjH9HWgAABHJJREFUeNrtm+tW4jAQgBfwuu7MtIUWsOUiCCioIIgLiqvr+z/UHq/LJKVkmwTcc/r9E2nzlU4mSTP9lpGRkZGR8VX5cZjfL+yCEXYL+/nDH//U/Pd8DgyTy39Xbv7oIAcWyB0cqbW/sweW2NtRaj8H1sgpGOwUIAH7Bkd7YJW9dXFwAJY5WNP/cmCZQnJvzIN18on5LwfWySXlxEPYAIcad8D6PdiHDbCfIFCADVBIENiFDbCbIACKPPXrZ+cP8E6/0znvP4EymgIEravIRcTxu8HxNSJ60a8W0AYECKrlAN+YwAthCd9wm1Ug6wKzIn5SgRduXfwkqDasCjx0XFzi9PV6zwNcIuhcWBOg+ikySq8C9UD4dEKWBCoOcspvAuLHTo9sCDQiFPHotRM48j8G5gVur1FdAN2uaYEuiz7xFsgEJ2RUoMUakXuBTHHoGxQYOBhHjeUBAefEnMAowFhaLBOKuOemBBbxLRQrH2PBCgMvNCPQGMeevTb9zLrPxz2Mo+QbEaijzPUcOOHMQZkKGRAIPem39+bypREMPTkQW/oCfk866zAkiIFG4yIKRE/aAnfiSd0WrORY6pFdXQEqi9mvAQm0RIOSnoCcZ8vJoz3diCnjRk+g8VP4/fuQDJ2Lxr6WwG0gXs9aTpDzW0vgDBlVUpixR8gYk44AD8FrUKHr8JQJGgIDnoDqoALxmWPQSi9AVVzm8gKUuEPGr/QCvptwJkbSYT/TC4S8C96DGjTj86aHtAI0x2WaBIq0eSYYpRa4EsdWVVwWu9O0Aj6f6dyBMnwEraeOgSYu0wZlauzA47QCbT7DgAQSE+hZWoEBF/BBmWOewNMK3BsSqKUW4MGcWqCSVmDkbvkXGKQOwg6PAUO9oL3xXhA20yaiCjuwYygRVQlUOTWTCf2SuNJTxeFjgaHByGuAIvd8ItdPLTDhS7IuqEE1YSKVOgbayLhSFQhMzYh8hwfBs1r7c505YVIQYEdNoKwxK06MJiyrpUFHiF0NAfCQUVHoiRclIXJIR6C2fqG37pBHvcWpgwzvAtYwkR5UGV2e42UISdBJETl3mg8ouo54Rcnti1/vaT+iuUQBt500Cgo4U10BeHSkk57FB0JjWkKRMWgLUA0lLodtImAQdaMiiri3+gIAPZQoutHNsgKF1aaDMhMyIdBf8Th+Bh8MTjGWCpl5Wv43tDmnF+IUVMrcZgRoiAxhtrloYizNkZaAnF5leglbNhj0wYCAbCDvGb0mP4nib7O7ZlcYQ2m1gPtIZgVgGNNMeaVAaWR+57TrqgtUnm3sHQ+kYeE6fufUubG1ez50FXbPnWgBlgSABmN3TTcsRl2yWkHRrwbiunvk/W2+Mg1hPZplPDeXRbZzStFH15s1QIVd3UImP5z/bHpeeQLvRJ7XLFUffQIlCvqlXETQbgN9/rlYABGosv+Vi9m2Xs639YLGrZd0br+odetlvdsvbN56abfd4vbCzv9Q3v/ygoOV21A4OPpfXvH4Ai+5ZGRkZGRkbJA/t/I0QMzoMiEAAAAASUVORK5CYII= "; -#[cfg(windows)] // windows, 32x32, bigger very ugly after shrink -pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAolBMVEUAAAAAcf8Acf8Acf8AcP8Acf8Acf8Acf8AcP8Acf/////9/v/7/f+gyv9wr/8Ld/8GdP/A3P+nzv+Qwf9mqv8lhv8UfP+Kvv88k/8zjv/x+P/Y6f/U5//J4f/F3/+x1P+pz/+izP+Cuv9Zov9Qnv9FmP8gg//f7f+42P96tv9fpv8ui//1+f/q8//o8v/Q5f+ax/+Zxv+VxP+Fu/9rrf8rif+x1o3FAAAACXRSTlMAv/RPTPKHioRsIqhAAAABNklEQVQ4y4WT6XaCQAyFB7S2GUD2RaxSKGDV7sv7v1on4djEluL9Ncn5biaZk1FKzSwbRmVbM2V0DRNaGD9Maq6sacBS9jRwpUTw1Ww7SEOvkwQDaeVofQeJ1nrXjgD3pTaqCDCg/xs4OBrlwUGTHvxzoHAx69Y9+Hk5oGdAsCNXSoHfEN1JYEme4KcfvO9WAmtMBNx6jIaCgSPGLbAyvKRhAEcrAxAKTSZiACu+gNSbyWwZeKdQKj91yRXWIOWZTMgATun6EtjgczNQaKMEWD0+xJ6B4AnvECVqdKwYoJ50hIPyw25AANkzpsLB00cYOIUEoHU0uVaQVcMxBwlgVZJ3Orz+3ahH6gP2tBgfYzsZmdo1fGIzRx5Irn2WxKaHeJnKtb/4cS5/PbWACd0oo/n/39/4vwGFYSxtSYV4OAAAAABJRU5ErkJggg== -"; -#[cfg(target_os = "linux")] // 128x128 no padding +#[cfg(not(target_os = "macos"))] // 128x128 no padding pub const ICON: &str = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAA7VBMVEUAAAAAcf8Acf8Acf8Adf8Acf8Acf8AcP8Acv8AcP8Acf8Acf8Acf8Acv8Acf8Acf8Ab/8AcP8Acf8Acf8Acf/////7/f8Dc/8TfP/1+f/n8v9Hmf/u9v+Uw//Q5f9hp/8Yfv8Qev8Ld/+52P+z1f+s0f81j/8wjP8Hdf/3+/8mh/8fg//x9//h7//H4P9xsP9rrf9oq/8rif/r9P/D3v+92/+Duv9bpP/d7f/U5/9NnP8/lP8jhP/L4v/B3P+OwP9+t/95tf9Rn/8bgf/Z6v+Zx/90sv9lqf85kf+hy/9UoP+Wxf+kzP+dyP+Lvv/H4q8IAAAAFHRSTlMA+u6bB6x5XR4V0+S4i4k5N+a81W8MiAQAAAVcSURBVHjazdvpWtpAGIbhgEutdW3fL2GHsMsiq4KI+66t5384XahF/GbizJAy3j/1Ah5CJhNCxpm1vbryLRrBfxKJrq+sbjtSa5u7WIDdzTVH5PNSBAsSWfrsMJ+iWKDoJ2fW8hIWbGl55vW/YuE2XhUsb8CCr9OCJVix9G//gyWf/o6/KCyJfrbwAfAPYS0CayK/j4mbsGjrV8AXWLTrONuwasdZhVWrzgqsWnG+wap1Jwqrok4EVkUcmKhdVvBaOVnzYEY/oJpMD4mo6ONF/ZSIUsX2FZjQA7xRqUET+y/v2W/Sy59u62DCDMgdJmhqgIk7eqWQBBNWwPhmj147w8QTzTjKVsGEEBBLuzSrhIkivTF8DD/Aa6forQNMHBD/VyXkgHGfuBN5ALln1TADOnESyGCiT8L/1kILqD6Q0BEm9kkofhdSwNUJiV1jQvZ/SnthBNSaJJGZbgGJUnX+gEqCZPpsJ2T2Y/MGVBrE8eOAvCA/X8A4QXLnmEhTgIPqPAG5IQU4fhmkFOT7HAFenwIU8Jd/TUEODQIUtu1eOj/dUD9cknOTpgEDkup3YrOfVStDUomcWcBVisTiNxVw3TPpgCl4RgFFybZ/9iHmn8uS2yYBA8m7qUEu9oOEejH9gHxC+PazCHbcFM8K+gGHJNAs4z2xgnAkVHQDcnG1IzvnCSfvom7AM3EZ9voah4+KXoAvGFJHMSgqEfegF3BBTKoOVfkMMXFfJ8AT7MuXUDeOE9PWCUiKBpKOlmAP1gngH2LChw7vhJgr9YD8Hnt0BxrE27CtHnDJR4AHTX1+KFAP4Ef0LHTxN9HwlAMSbAjmoavKZ8ayakDXYAhwN3wzqgZk2UPvwRjshmeqATeCT09f3mWnEqoBGf4NxAB/moRqADuOtmDiid6KqQVcsQeOYOKW3uqqBRwL5nITj/yrlFpAVrDpTJT5llQLaLMHwshY7UDgvD+VujDC96WWWsBtSAE5FnChFnAeUkDMdAvw88EqTNT5SYXpTlgPaRQM1AIGorkolNnoUS1gJHigCX48SaoF3Asuspg4Mz0U8+FTgIkCG01V09kwBQP8xG5ofD5AXeirkPEJSUlwSVIfP5ykVQNaggvz+k7prTvVgDKF8BnUXP4kqgEe/257E8Ig7EE1gA8g2stBTz7FLxqrB3SIeYaeQ2IG6gE5l2+Cmt5MGOfP4KsGiH8DOYWOoujnDY2ALHF3810goZFOQDVBTFx9Uj7eI6bp6QTgnLjeGGq6KeJuoRUQixN3pDYWyz1Rva8XIL5UPFQZCsmG3gV7R+dieS+Jd3iHLglce7oBuCOhp3zwHLxPQpfQDvBOSKjZqUIml3ZJ6AD6AajFSZJwewWR8ZPsEY26SQDaJOMeZP23w6bTJ6kBjAJQILm9hzqm7otu4G+nhgGxIQUlPLKzL7GhbxqAboMCuN2XXd+lAL0ajAMwclV+FD6jAPEy5ghAlhfwX2FODX445gHKxyN++fs64PUHmDMAbbYN2DlKk2QaScwdgMs4SZxMv4OJJSoIIQBl2Qtk3gk4qiOUANRPJQHB+0A6j5AC4J27QQEZ4eZPAsYBXFk0N/YD7iUrxRBqALxOTzoMC3x8lCFlfkMjuz8iLfk6fzQCQgjg8q3ZEd8RzUVuKelBh96Nzcc3qelL1V+2zfRv1xc56Ino3tpdPT7cd//MspfTrD/7R6p4W4O2qLMObfnyIHvvYcrPtkZjDybW7d/eb32Bg/UlHnYXuXz5CMt8rC90sr7Uy/5iN+vL/ewveLS/5NNKwcbyR1r2a3/h8wdY+v3L2tZC5oUvW2uO1M7qyvp/Xv6/48z4CTxjJEfyjEaMAAAAAElFTkSuQmCC "; #[cfg(target_os = "macos")] @@ -36,6 +33,7 @@ type Size = (i32, i32, i32, i32); lazy_static::lazy_static! { static ref CONFIG: Arc> = Arc::new(RwLock::new(Config::load())); static ref CONFIG2: Arc> = Arc::new(RwLock::new(Config2::load())); + static ref LOCAL_CONFIG: Arc> = Arc::new(RwLock::new(LocalConfig::load())); pub static ref ONLINE: Arc>> = Default::default(); } #[cfg(any(target_os = "android", target_os = "ios"))] @@ -61,7 +59,7 @@ pub enum NetworkType { ProxySocks, } -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] pub struct Config { #[serde(default)] id: String, @@ -88,12 +86,8 @@ pub struct Socks5Server { } // more variable configs -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] pub struct Config2 { - #[serde(default)] - remote_id: String, // latest used one - #[serde(default)] - size: Size, #[serde(default)] rendezvous_server: String, #[serde(default)] @@ -193,14 +187,23 @@ impl Config2 { Config::load_::("2") } - fn reload(&mut self) { - let new_config = Config2::load(); - *self = new_config; + pub fn file() -> PathBuf { + Config::file_("2") } fn store(&self) { Config::store_(self, "2"); } + + pub fn get() -> Config2 { + return CONFIG2.read().unwrap().clone(); + } + + pub fn set(cfg: Config2) { + let mut lock = CONFIG2.write().unwrap(); + *lock = cfg; + lock.store(); + } } impl Config { @@ -222,11 +225,6 @@ impl Config { cfg } - fn reload(&mut self) { - let new_config = Config::load(); - *self = new_config; - } - fn store_(config: &T, suffix: &str) { let file = Self::file_(suffix); if let Err(err) = confy::store_path(file, config) { @@ -623,33 +621,6 @@ impl Config { salt } - pub fn get_size() -> Size { - CONFIG2.read().unwrap().size - } - - pub fn set_size(x: i32, y: i32, w: i32, h: i32) { - let mut config = CONFIG2.write().unwrap(); - let size = (x, y, w, h); - if size == config.size || size.2 < 300 || size.3 < 300 { - return; - } - config.size = size; - config.store(); - } - - pub fn set_remote_id(remote_id: &str) { - let mut config = CONFIG2.write().unwrap(); - if remote_id == config.remote_id { - return; - } - config.remote_id = remote_id.into(); - config.store(); - } - - pub fn get_remote_id() -> String { - CONFIG2.read().unwrap().remote_id.clone() - } - pub fn set_socks(socks: Option) { let mut config = CONFIG2.write().unwrap(); if config.socks == socks { @@ -670,91 +641,14 @@ impl Config { } } - pub fn sync_config_to_user>(target_username: String, to_dir: P) -> bool { - let config1_root_file_path = Config::file_(""); - let config1_filename = config1_root_file_path.file_name(); - - let config2_root_file_path = Config::file_("2"); - let config2_filename = config2_root_file_path.file_name(); - - let config1_to_file_path = to_dir - .as_ref() - .join(PathBuf::from(&config1_filename.unwrap())); - let config2_to_file_path = to_dir - .as_ref() - .join(PathBuf::from(&config2_filename.unwrap())); - - log::info!( - "config1_root_path:{}", - &config1_root_file_path.as_path().to_str().unwrap() - ); - log::info!( - "config2_root_path:{}", - &config2_root_file_path.as_path().to_str().unwrap() - ); - log::info!( - "config1_to_path:{}", - &config1_to_file_path.as_path().to_str().unwrap() - ); - log::info!( - "config2_to_path:{}", - &config2_to_file_path.as_path().to_str().unwrap() - ); - - match std::fs::copy(&config1_root_file_path, &config1_to_file_path) { - Err(e) => log::error!( - "copy config {} to user failed: {}", - config1_filename.unwrap().to_str().unwrap(), - e - ), - _ => {} - } - - match std::fs::copy(&config2_root_file_path, &config2_to_file_path) { - Err(e) => log::error!( - "copy config {} to user failed: {}", - config2_filename.unwrap().to_str().unwrap(), - e - ), - _ => {} - } - - let success = std::process::Command::new("chown") - .arg(&target_username.to_string()) - .arg(&config1_to_file_path.to_str().unwrap().to_string()) - .arg(&config2_to_file_path.to_str().unwrap().to_string()) - .spawn() - .is_ok(); - - if success { - CONFIG.write().unwrap().reload(); - CONFIG2.write().unwrap().reload(); - } - - return success; + pub fn get() -> Config { + return CONFIG.read().unwrap().clone(); } - pub fn sync_config_to_root>(from_file_path: P) -> bool { - if let Some(filename) = from_file_path.as_ref().file_name() { - let to = Config::path(filename); - return match std::fs::copy(from_file_path, &to) { - Ok(count) => { - if count > 0 { - return std::process::Command::new("chown") - .arg("root") - .arg(&to.to_str().unwrap().to_string()) - .spawn() - .is_ok(); - } - false - } - Err(e) => { - log::error!("sync_config_to_root failed: {}", e); - false - } - }; - } - false + pub fn set(cfg: Config) { + let mut lock = CONFIG.write().unwrap(); + *lock = cfg; + lock.store(); } } @@ -801,9 +695,7 @@ impl PeerConfig { && p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml") }) .map(|p| { - let t = fs::metadata(p) - .map(|m| m.modified().unwrap_or(SystemTime::UNIX_EPOCH)) - .unwrap_or(SystemTime::UNIX_EPOCH); + let t = crate::get_modified_time(&p); let id = p .file_stem() .map(|p| p.to_str().unwrap_or("")) @@ -826,27 +718,84 @@ impl PeerConfig { } #[derive(Debug, Default, Serialize, Deserialize, Clone)] -pub struct Fav { +pub struct LocalConfig { #[serde(default)] - pub peers: Vec, + remote_id: String, // latest used one + #[serde(default)] + size: Size, + #[serde(default)] + pub fav: Vec, + #[serde(default)] + options: HashMap, } -impl Fav { - pub fn load() -> Fav { - let _ = CONFIG.read().unwrap(); // for lock - match confy::load_path(&Config::file_("_fav")) { - Ok(fav) => fav, - Err(err) => { - log::error!("Failed to load fav: {}", err); - Default::default() - } +impl LocalConfig { + fn load() -> LocalConfig { + Config::load_::("_local") + } + + fn store(&self) { + Config::store_(self, "_local"); + } + + pub fn get_size() -> Size { + LOCAL_CONFIG.read().unwrap().size + } + + pub fn set_size(x: i32, y: i32, w: i32, h: i32) { + let mut config = LOCAL_CONFIG.write().unwrap(); + let size = (x, y, w, h); + if size == config.size || size.2 < 300 || size.3 < 300 { + return; + } + config.size = size; + config.store(); + } + + pub fn set_remote_id(remote_id: &str) { + let mut config = LOCAL_CONFIG.write().unwrap(); + if remote_id == config.remote_id { + return; + } + config.remote_id = remote_id.into(); + config.store(); + } + + pub fn get_remote_id() -> String { + LOCAL_CONFIG.read().unwrap().remote_id.clone() + } + + pub fn set_fav(fav: Vec) { + let mut lock = LOCAL_CONFIG.write().unwrap(); + if lock.fav == fav { + return; + } + lock.fav = fav; + lock.store(); + } + + pub fn get_fav() -> Vec { + LOCAL_CONFIG.read().unwrap().fav.clone() + } + + pub fn get_option(k: &str) -> String { + if let Some(v) = LOCAL_CONFIG.read().unwrap().options.get(k) { + v.clone() + } else { + "".to_owned() } } - pub fn store(peers: Vec) { - let f = Fav { peers }; - if let Err(err) = confy::store_path(Config::file_("_fav"), f) { - log::error!("Failed to store fav: {}", err); + pub fn set_option(k: String, v: String) { + let mut config = LOCAL_CONFIG.write().unwrap(); + let v2 = if v.is_empty() { None } else { Some(&v) }; + if v2 != config.options.get(&k) { + if v2.is_none() { + config.options.remove(&k); + } else { + config.options.insert(k, v); + } + config.store(); } } } diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 81871bf26..b8472ba52 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -187,6 +187,12 @@ pub fn get_version_number(v: &str) -> i64 { n } +pub fn get_modified_time(path: &std::path::Path) -> SystemTime { + std::fs::metadata(&path) + .map(|m| m.modified().unwrap_or(UNIX_EPOCH)) + .unwrap_or(UNIX_EPOCH) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/common.rs b/src/common.rs index 296b83d28..6d2d9c373 100644 --- a/src/common.rs +++ b/src/common.rs @@ -465,3 +465,8 @@ pub fn is_ip(id: &str) -> bool { .unwrap() .is_match(id) } + +#[inline] +pub fn get_app_name() -> &'static str { + hbb_common::config::APP_NAME +} diff --git a/src/ipc.rs b/src/ipc.rs index ae2db0bc6..600b35dc6 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -3,7 +3,7 @@ pub use clipboard::ClipbaordFile; use hbb_common::{ allow_err, bail, bytes, bytes_codec::BytesCodec, - config::{self, Config}, + config::{self, Config, Config2}, futures::StreamExt as _, futures_util::sink::SinkExt, log, timeout, tokio, @@ -96,15 +96,8 @@ pub enum Data { Socks(Option), FS(FS), Test, - SyncConfigToRootReq { - from: String, - }, - SyncConfigToRootResp(bool), - SyncConfigToUserReq { - username: String, - to: String, - }, - SyncConfigToUserResp(bool), + SyncConfig(Option<(Config, Config2)>), + #[cfg(not(any(target_os = "android", target_os = "ios")))] ClipbaordFile(ClipbaordFile), ClipboardFileEnabled(bool), } @@ -173,6 +166,30 @@ pub async fn new_listener(postfix: &str) -> ResultType { } } +pub struct CheckIfRestart(String, Vec, String); + +impl CheckIfRestart { + pub fn new() -> CheckIfRestart { + CheckIfRestart( + Config::get_option("stop-service"), + Config::get_rendezvous_servers(), + Config::get_option("audio-input"), + ) + } +} +impl Drop for CheckIfRestart { + fn drop(&mut self) { + if self.0 != Config::get_option("stop-service") + || self.1 != Config::get_rendezvous_servers() + { + RendezvousMediator::restart(); + } + if self.2 != Config::get_option("audio-input") { + crate::audio_service::restart(); + } + } +} + async fn handle(data: Data, stream: &mut Connection) { match data { Data::SystemInfo(_) => { @@ -280,21 +297,15 @@ async fn handle(data: Data, stream: &mut Connection) { let t = Config::get_nat_type(); allow_err!(stream.send(&Data::NatType(Some(t))).await); } - Data::SyncConfigToRootReq { from } => { - allow_err!( - stream - .send(&Data::SyncConfigToRootResp(Config::sync_config_to_root( - from - ))) - .await - ); + Data::SyncConfig(Some((config, config2))) => { + Config::set(config); + Config2::set(config2); + allow_err!(stream.send(&Data::SyncConfig(None)).await); } - Data::SyncConfigToUserReq { username, to } => { + Data::SyncConfig(None) => { allow_err!( stream - .send(&Data::SyncConfigToUserResp(Config::sync_config_to_user( - username, to - ))) + .send(&Data::SyncConfig(Some((Config::get(), Config2::get())))) .await ); } diff --git a/src/lang.rs b/src/lang.rs index f0ba973e1..3481de866 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -1,4 +1,4 @@ -use hbb_common::{config::Config, log}; +use hbb_common::{config::LocalConfig, log}; use std::ops::Deref; mod cn; @@ -19,7 +19,7 @@ pub fn translate(name: String) -> String { } pub fn translate_locale(name: String, locale: &str) -> String { - let mut lang = Config::get_option("lang"); + let mut lang = LocalConfig::get_option("lang"); if lang.is_empty() { lang = locale .split("-") diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 4ef995a02..07ffd782e 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -104,11 +104,12 @@ pub fn is_can_screen_recording(prompt: bool) -> bool { pub fn is_installed_daemon(prompt: bool) -> bool { let daemon = format!("{}_service.plist", crate::get_full_name()); let agent = format!("{}_server.plist", crate::get_full_name()); + let agent_plist_file = format!("/Library/LaunchAgents/{}", agent); if !prompt { if !std::path::Path::new(&format!("/Library/LaunchDaemons/{}", daemon)).exists() { return false; } - if !std::path::Path::new(&format!("/Library/LaunchAgents/{}", agent)).exists() { + if !std::path::Path::new(&agent_plist_file).exists() { return false; } return true; @@ -123,43 +124,92 @@ pub fn is_installed_daemon(prompt: bool) -> bool { let agent_plist = PRIVILEGES_SCRIPTS_DIR.get_file(&agent).unwrap(); let agent_plist_body = agent_plist.contents_utf8().unwrap(); - match std::process::Command::new("osascript") - .arg("-e") - .arg(install_script_body) - .arg(daemon_plist_body) - .arg(agent_plist_body) - .arg(&get_active_username()) - .spawn() - { - Ok(_) => { - std::process::exit(0); + std::thread::spawn(move || { + match std::process::Command::new("osascript") + .arg("-e") + .arg(install_script_body) + .arg(daemon_plist_body) + .arg(agent_plist_body) + .arg(&get_active_username()) + .output() + { + Err(e) => { + log::error!("run osascript failed: {}", e); + } + _ => { + if std::path::Path::new(&agent_plist_file).exists() { + std::process::Command::new("osascript") + .arg("-e") + .arg( + PRIVILEGES_SCRIPTS_DIR + .get_file("run.scpt") + .unwrap() + .contents_utf8() + .unwrap(), + ) + .arg(&format!( + "sleep 0.5; launchctl load -w {}; sleep 0.5; open /Applications/{}.app", + agent_plist_file, + crate::get_app_name() + )) + .spawn() + .ok(); + std::thread::sleep(std::time::Duration::from_millis(100)); // avoid exit crash + std::process::exit(0); + } + } } - Err(e) => { - log::error!("run osascript failed: {}", e); - false - } - } + }); + false } -pub fn launch(load: bool) { +pub fn uninstall() -> bool { // to-do: do together with win/linux about refactory start/stop service - if !is_installed() || !is_installed_daemon(false) { - return; - } - let mut script_filename = "load.scpt"; - if !load { - script_filename = "unload.scpt"; + if !is_installed_daemon(false) { + return false; } - let script_file = PRIVILEGES_SCRIPTS_DIR.get_file(script_filename).unwrap(); + let script_file = PRIVILEGES_SCRIPTS_DIR.get_file("uninstall.scpt").unwrap(); let script_body = script_file.contents_utf8().unwrap(); - std::process::Command::new("osascript") - .arg("-e") - .arg(script_body) - .arg(&get_active_username()) - .spawn() - .ok(); + std::thread::spawn(move || { + match std::process::Command::new("osascript") + .arg("-e") + .arg(script_body) + .arg(&get_active_username()) + .output() + { + Err(e) => { + log::error!("run osascript failed: {}", e); + } + _ => { + let agent = format!("{}_server.plist", crate::get_full_name()); + let agent_plist_file = format!("/Library/LaunchAgents/{}", agent); + if !std::path::Path::new(&agent_plist_file).exists() { + crate::ipc::set_option("stop-service", "Y"); + std::process::Command::new("osascript") + .arg("-e") + .arg( + PRIVILEGES_SCRIPTS_DIR + .get_file("run.scpt") + .unwrap() + .contents_utf8() + .unwrap(), + ) + .arg(&format!( + "sleep 0.5; launchctl remove {}_server; sleep 0.5; open /Applications/{}.app", + crate::get_full_name(), + crate::get_app_name() + )) + .spawn() + .ok(); + std::thread::sleep(std::time::Duration::from_millis(100)); // avoid exit crash + std::process::exit(0); + } + } + } + }); + true } pub fn get_cursor_pos() -> Option<(i32, i32)> { @@ -352,6 +402,24 @@ pub fn lock_screen() { pub fn start_os_service() { log::info!("{}", crate::username()); + + std::thread::spawn(move || loop { + let exe = std::env::current_exe().unwrap_or_default(); + let tm0 = hbb_common::get_modified_time(&exe); + + loop { + std::thread::sleep(std::time::Duration::from_millis(300)); + if hbb_common::get_modified_time(&exe) != tm0 { + log::info!("{:?} updated, will restart", exe); + std::process::Command::new("pkill") + .args(&["-f", exe.to_str().unwrap_or("")]) + .output() + .ok(); + std::process::exit(0); // self not killed by above pkill + } + } + }); + if let Err(err) = crate::ipc::start("_service") { log::error!("Failed to start ipc_service: {}", err); } @@ -425,7 +493,7 @@ pub fn is_installed() -> bool { if let Ok(p) = std::env::current_exe() { return p.to_str().unwrap_or_default().contains(&format!( "/Applications/{}.app", - hbb_common::config::APP_NAME + crate::get_app_name(), )); } false diff --git a/src/platform/privileges_scripts/install.scpt b/src/platform/privileges_scripts/install.scpt index 12bbdcd8c..c38320db5 100644 --- a/src/platform/privileges_scripts/install.scpt +++ b/src/platform/privileges_scripts/install.scpt @@ -1,19 +1,16 @@ on run {daemon_file, agent_file, user} - set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.RustDesk_service.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;" + set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.RustDesk_service.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;" - set sh2 to "echo " & quoted form of agent_file & " > /Library/LaunchAgents/com.carriez.RustDesk_server.plist && chown root:wheel /Library/LaunchAgents/com.carriez.RustDesk_server.plist;" + set sh2 to "echo " & quoted form of agent_file & " > /Library/LaunchAgents/com.carriez.RustDesk_server.plist && chown root:wheel /Library/LaunchAgents/com.carriez.RustDesk_server.plist;" set sh3 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk.toml /var/root/Library/Preferences/com.carriez.RustDesk/;" set sh4 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk2.toml /var/root/Library/Preferences/com.carriez.RustDesk/;" - set sh5 to "launchctl unload -w /Library/LaunchAgents/com.carriez.RustDesk_server.plist; launchctl load -w /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;" - - set sh6 to "pkill -f rustdesk; launchctl unload -w /Library/LaunchAgents/com.carriez.RustDesk_server.plist; launchctl load -w /Library/LaunchAgents/com.carriez.RustDesk_server.plist; open /Applications/RustDesk.app" + set sh5 to "launchctl load -w /Library/LaunchDaemons/com.carriez.RustDesk_service.plist;" - set sh to sh1 & sh2 & sh3 & sh4 & sh5 + set sh to sh1 & sh2 & sh3 & sh4 & sh5 - do shell script sh with prompt "RustDesk want to install daemon and agent" with administrator privileges - do shell script sh6 + do shell script sh with prompt "RustDesk want to install daemon and agent" with administrator privileges end run diff --git a/src/platform/privileges_scripts/load.scpt b/src/platform/privileges_scripts/load.scpt deleted file mode 100644 index a725af2bc..000000000 --- a/src/platform/privileges_scripts/load.scpt +++ /dev/null @@ -1,16 +0,0 @@ -on run {user} - - set sh1 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk.toml /var/root/Library/Preferences/com.carriez.RustDesk/;" - - set sh2 to "cp -rf /Users/" & user & "/Library/Preferences/com.carriez.RustDesk/RustDesk2.toml /var/root/Library/Preferences/com.carriez.RustDesk/;" - - set sh3 to "launchctl load -w /Library/LaunchDaemons/com.carriez.rustdesk_service.plist;" - - set sh4 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk_server.plist;" - - set sh to sh1 & sh2 & sh3 - - do shell script sh with prompt "RustDesk want to launch daemon" with administrator privileges - do shell script sh4 - -end run diff --git a/src/platform/privileges_scripts/unload.scpt b/src/platform/privileges_scripts/unload.scpt deleted file mode 100644 index f0c143f1c..000000000 --- a/src/platform/privileges_scripts/unload.scpt +++ /dev/null @@ -1,6 +0,0 @@ -set sh1 to "launchctl unload -w /Library/LaunchDaemons/com.carriez.rustdesk_service.plist;" -set sh2 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk_server.plist;" - -do shell script sh1 with prompt "RustDesk want to unload daemon" with administrator privileges -do shell script sh2 - diff --git a/src/server.rs b/src/server.rs index ac8530669..1e00b2c18 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,12 +1,10 @@ -#[cfg(target_os = "macos")] -use crate::ipc::ConnectionTmpl; use crate::ipc::Data; -use connection::{ConnInner, Connection}; +pub use connection::*; use hbb_common::{ allow_err, anyhow::{anyhow, Context}, bail, - config::{Config, CONNECT_TIMEOUT, RELAY_PORT}, + config::{Config, Config2, CONNECT_TIMEOUT, RELAY_PORT}, log, message_proto::*, protobuf::{Message as _, ProtobufEnum}, @@ -15,10 +13,6 @@ use hbb_common::{ sodiumoxide::crypto::{box_, secretbox, sign}, timeout, tokio, ResultType, Stream, }; -#[cfg(target_os = "macos")] -use notify::{watcher, RecursiveMode, Watcher}; -#[cfg(target_os = "macos")] -use parity_tokio_ipc::ConnectionClient; use service::{GenericService, Service, ServiceTmpl, Subscriber}; use std::{ collections::HashMap, @@ -339,101 +333,46 @@ async fn sync_and_watch_config_dir() { return; } - match crate::ipc::connect(1000, "_service").await { - Ok(mut conn) => { - match sync_config_to_user(&mut conn).await { - Err(e) => log::error!("sync config to user failed:{}", e), - _ => {} - } - - tokio::spawn(async move { - log::info!( - "watching config dir: {}", - Config::path("").to_str().unwrap().to_string() - ); - - let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); - watcher - .watch(Config::path("").as_path(), RecursiveMode::Recursive) - .unwrap(); + for i in 1..=6 { + sleep(i as f32 * 0.3).await; + match crate::ipc::connect(1000, "_service").await { + Ok(mut conn) => { + if conn.send(&Data::SyncConfig(None)).await.is_ok() { + if let Ok(Some(data)) = conn.next_timeout(1000).await { + match data { + Data::SyncConfig(Some((config, config2))) => { + let _chk = crate::ipc::CheckIfRestart::new(); + Config::set(config); + Config2::set(config2); + log::info!("sync config from root"); + } + _ => {} + }; + }; + } + let mut cfg0 = (Config::get(), Config2::get()); loop { - let ev = rx.recv(); - match ev { - Ok(event) => match event { - notify::DebouncedEvent::Write(path) => { - log::info!( - "config file changed, call ipc_service to sync: {}", - path.to_str().unwrap().to_string() - ); - - match sync_config_to_root(&mut conn, path).await { - Err(e) => log::error!("sync config to root failed: {}", e), - _ => {} - } + sleep(0.3).await; + let cfg = (Config::get(), Config2::get()); + if cfg != cfg0 { + cfg0 = cfg; + log::info!("config updated, sync to root"); + match conn.send(&Data::SyncConfig(Some(cfg0.clone()))).await { + Err(e) => { + log::error!("sync config to root failed: {}", e); } - x => { - log::debug!("another {:?}", x) + _ => { + conn.next_timeout(1000).await.ok(); } - }, - Err(e) => println!("watch error: {:?}", e), + } } } - }); - } - Err(_) => { - log::info!("connect ipc_service failed, skip config sync"); - return; + } + Err(_) => { + log::info!("#{} try: failed to connect to ipc_service", i); + } } } -} - -#[cfg(target_os = "macos")] -async fn sync_config_to_user(conn: &mut ConnectionTmpl) -> ResultType<()> { - allow_err!( - conn.send(&Data::SyncConfigToUserReq { - username: crate::username(), - to: Config::path("").to_str().unwrap().to_string(), - }) - .await - ); - - if let Some(data) = conn.next_timeout(2000).await? { - match data { - Data::SyncConfigToUserResp(success) => { - log::info!("copy and reload config dir success: {:?}", success); - } - _ => {} - }; - }; - - Ok(()) -} - -#[cfg(target_os = "macos")] -async fn sync_config_to_root( - conn: &mut ConnectionTmpl, - from: std::path::PathBuf, -) -> ResultType<()> { - allow_err!( - conn.send(&Data::SyncConfigToRootReq { - from: from.to_str().unwrap().to_string() - }) - .await - ); - - // todo: this code will block outer loop, resolve it later. - // if let Some(data) = conn.next_timeout(2000).await? { - // match data { - // Data::SyncConfigToRootResp(success) => { - // log::info!("copy config to root dir success: {:?}", success); - // } - // x => { - // log::info!("receive another {:?}", x) - // } - // }; - // }; - - Ok(()) + log::error!("skipped config sync"); } diff --git a/src/ui.rs b/src/ui.rs index 268b8bc59..75d3b5189 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -8,7 +8,7 @@ use crate::common::SOFTWARE_UPDATE_URL; use crate::ipc; use hbb_common::{ allow_err, - config::{self, Config, Fav, PeerConfig, APP_NAME, ICON}, + config::{self, Config, LocalConfig, PeerConfig, APP_NAME, ICON}, log, sleep, tokio::{self, time}, }; @@ -221,11 +221,11 @@ impl UI { } fn get_remote_id(&mut self) -> String { - Config::get_remote_id() + LocalConfig::get_remote_id() } fn set_remote_id(&mut self, id: String) { - Config::set_remote_id(&id); + LocalConfig::set_remote_id(&id); } fn goto_install(&mut self) { @@ -275,7 +275,11 @@ impl UI { } fn get_local_option(&self, key: String) -> String { - Config::get_option(&key) + LocalConfig::get_option(&key) + } + + fn set_local_option(&self, key: String, value: String) { + LocalConfig::set_option(key, value); } fn peer_has_password(&self, id: String) -> bool { @@ -353,6 +357,13 @@ impl UI { } fn set_option(&self, key: String, value: String) { + #[cfg(target_os = "macos")] + if &key == "stop-service" { + let is_stop = value == "Y"; + if is_stop && crate::platform::macos::uninstall() { + return; + } + } let mut options = self.2.lock().unwrap(); if value.is_empty() { options.remove(&key); @@ -360,11 +371,6 @@ impl UI { options.insert(key.clone(), value.clone()); } ipc::set_options(options.clone()).ok(); - - #[cfg(target_os = "macos")] - if &key == "stop-service" { - crate::platform::macos::launch(value != "Y"); - } } // TODO: ui prompt @@ -431,11 +437,11 @@ impl UI { fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) { crate::server::input_service::fix_key_down_timeout_at_exit(); - Config::set_size(x, y, w, h); + LocalConfig::set_size(x, y, w, h); } fn get_size(&mut self) -> Value { - let s = Config::get_size(); + let s = LocalConfig::get_size(); let mut v = Value::array(0); v.push(s.0); v.push(s.1); @@ -470,7 +476,7 @@ impl UI { } fn get_fav(&self) -> Value { - Value::from_iter(Fav::load().peers) + Value::from_iter(LocalConfig::get_fav()) } fn store_fav(&self, fav: Value) { @@ -482,10 +488,11 @@ impl UI { } } }); - Fav::store(tmp); + LocalConfig::set_fav(tmp); } fn get_recent_sessions(&mut self) -> Value { + // to-do: limit number of recent sessions, and remove old peer file let peers: Vec = PeerConfig::peers() .drain(..) .map(|p| Self::get_peer_value(p.0, p.2)) @@ -701,6 +708,7 @@ impl sciter::EventHandler for UI { fn get_options(); fn get_option(String); fn get_local_option(String); + fn set_local_option(String, String); fn get_peer_option(String, String); fn peer_has_password(String); fn forget_password(String); @@ -830,7 +838,7 @@ fn check_connect_status( reconnect: bool, ) -> (Arc>, Arc>>) { let status = Arc::new(Mutex::new((0, false))); - let options = Arc::new(Mutex::new(HashMap::new())); + let options = Arc::new(Mutex::new(Config::get_options())); let cloned = status.clone(); let cloned_options = options.clone(); std::thread::spawn(move || check_connect_status_(reconnect, cloned, cloned_options)); diff --git a/src/ui/ab.tis b/src/ui/ab.tis index eed861c12..2310e9ba4 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -66,7 +66,7 @@ class SessionStyle: Reactor.Component { event click $(span.inactive) { var option = getSessionsStyleOption(this.type); var sessionsStyle = getSessionsStyle(this.type); - handler.set_option(option, sessionsStyle == "tile" ? "list" : "tile"); + handler.set_local_option(option, sessionsStyle == "tile" ? "list" : "tile"); app.multipleSessions.update(); } } @@ -294,7 +294,7 @@ class MultipleSessions: Reactor.Component { if (el.id == "lan") { discover(); } - handler.set_option('show-sessions-type', el.id || ""); + handler.set_local_option('show-sessions-type', el.id || ""); this.stupidUpdate(); } diff --git a/src/ui/index.tis b/src/ui/index.tis index f1f3e74b9..32d1f609a 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -7,7 +7,7 @@ view.windowMinSize = (500, 300); var app; var tmp = handler.get_connect_status(); var connect_status = tmp[0]; -var service_stopped = false; +var service_stopped = handler.get_option("stop-service") == "Y"; var software_update_url = ""; var key_confirmed = tmp[1]; var system_error = ""; @@ -368,7 +368,7 @@ class App: Reactor.Component {is_win && handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? : ""} {is_can_screen_recording ? "": } {is_can_screen_recording && !handler.is_process_trusted(false) ? : ""} - {is_can_screen_recording && handler.is_process_trusted(false) && handler.is_installed() && !handler.is_installed_daemon(false) ? : ""} + {!service_stopped && is_can_screen_recording && handler.is_process_trusted(false) && handler.is_installed() && !handler.is_installed_daemon(false) ? : ""} {system_error ? : ""} {!system_error && handler.is_login_wayland() && !handler.current_is_wayland() ? : ""} {!system_error && handler.current_is_wayland() ? : ""} @@ -772,8 +772,7 @@ function checkConnectStatus() { var tmp = !!handler.get_option("stop-service"); if (tmp != service_stopped) { service_stopped = tmp; - app.connect_status.update(); - myIdMenu.update(); + app.update(); } tmp = handler.get_connect_status(); if (tmp[0] != connect_status) {