Merge pull request #369 from Heasn/master
New launch daemon/agents and config sync service on macOS
This commit is contained in:
		
						commit
						07aa0898c5
					
				
							
								
								
									
										90
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										90
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1150,6 +1150,25 @@ 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" | ||||
| @ -1733,6 +1752,45 @@ dependencies = [ | ||||
|  "tiff", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "include_dir" | ||||
| version = "0.7.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "482a2e29200b7eed25d7fdbd14423326760b7f6658d21a4cf12d55a50713c69f" | ||||
| dependencies = [ | ||||
|  "include_dir_macros", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "include_dir_macros" | ||||
| version = "0.7.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5e074c19deab2501407c91ba1860fa3d6820bfde307db6d8cb851b55a10be89b" | ||||
| dependencies = [ | ||||
|  "proc-macro2", | ||||
|  "quote", | ||||
| ] | ||||
| 
 | ||||
| [[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" | ||||
| @ -2095,6 +2153,18 @@ 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" | ||||
| @ -2308,6 +2378,24 @@ dependencies = [ | ||||
|  "version_check", | ||||
| ] | ||||
| 
 | ||||
| [[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.6" | ||||
| @ -3230,6 +3318,7 @@ dependencies = [ | ||||
|  "flexi_logger", | ||||
|  "hbb_common", | ||||
|  "hound", | ||||
|  "include_dir", | ||||
|  "lazy_static", | ||||
|  "libc", | ||||
|  "libpulse-binding", | ||||
| @ -3237,6 +3326,7 @@ dependencies = [ | ||||
|  "mac_address", | ||||
|  "machine-uid", | ||||
|  "magnum-opus", | ||||
|  "notify", | ||||
|  "objc", | ||||
|  "parity-tokio-ipc", | ||||
|  "psutil", | ||||
|  | ||||
| @ -69,7 +69,8 @@ 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] | ||||
| libpulse-simple-binding = "2.24" | ||||
| libpulse-binding = "2.25" | ||||
|  | ||||
| @ -190,6 +190,11 @@ impl Config2 { | ||||
|         Config::load_::<Config2>("2") | ||||
|     } | ||||
| 
 | ||||
|     fn reload(&mut self) { | ||||
|         let new_config = Config2::load(); | ||||
|         *self = new_config; | ||||
|     } | ||||
| 
 | ||||
|     fn store(&self) { | ||||
|         Config::store_(self, "2"); | ||||
|     } | ||||
| @ -214,6 +219,11 @@ impl Config { | ||||
|         cfg | ||||
|     } | ||||
| 
 | ||||
|     fn reload(&mut self) { | ||||
|         let new_config = Config::load(); | ||||
|         *self = new_config; | ||||
|     } | ||||
| 
 | ||||
|     fn store_<T: serde::Serialize>(config: &T, suffix: &str) { | ||||
|         let file = Self::file_(suffix); | ||||
|         if let Err(err) = confy::store_path(file, config) { | ||||
| @ -272,7 +282,7 @@ impl Config { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn path<P: AsRef<Path>>(p: P) -> PathBuf { | ||||
|     pub fn path<P: AsRef<Path>>(p: P) -> PathBuf { | ||||
|         #[cfg(any(target_os = "android", target_os = "ios"))] | ||||
|         { | ||||
|             let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); | ||||
| @ -659,6 +669,93 @@ impl Config { | ||||
|             Some(_) => NetworkType::ProxySocks, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn sync_config_to_user<P: AsRef<Path>>(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 sync_config_to_root<P: AsRef<Path>>(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 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const PEERS: &str = "peers"; | ||||
|  | ||||
							
								
								
									
										27
									
								
								src/ipc.rs
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								src/ipc.rs
									
									
									
									
									
								
							| @ -92,6 +92,15 @@ pub enum Data { | ||||
|     Socks(Option<config::Socks5Server>), | ||||
|     FS(FS), | ||||
|     Test, | ||||
|     SyncConfigToRootReq { | ||||
|         from: String, | ||||
|     }, | ||||
|     SyncConfigToRootResp(bool), | ||||
|     SyncConfigToUserReq { | ||||
|         username: String, | ||||
|         to: String, | ||||
|     }, | ||||
|     SyncConfigToUserResp(bool), | ||||
| } | ||||
| 
 | ||||
| #[tokio::main(flavor = "current_thread")] | ||||
| @ -252,6 +261,24 @@ 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::SyncConfigToUserReq { username, to } => { | ||||
|             allow_err!( | ||||
|                 stream | ||||
|                     .send(&Data::SyncConfigToUserResp(Config::sync_config_to_user( | ||||
|                         username, to | ||||
|                     ))) | ||||
|                     .await | ||||
|             ); | ||||
|         } | ||||
|         _ => {} | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -102,6 +102,13 @@ fn main() { | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         #[cfg(target_os = "macos")] | ||||
|         if args[0] == "--daemon" { | ||||
|             log::info!("start --daemon"); | ||||
|             crate::platform::start_daemon(); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     ui::start(&mut args[..]); | ||||
| } | ||||
|  | ||||
| @ -17,9 +17,12 @@ use core_graphics::{ | ||||
|     window::{kCGWindowName, kCGWindowOwnerPID}, | ||||
| }; | ||||
| use hbb_common::{allow_err, bail, log}; | ||||
| use include_dir::{include_dir, Dir}; | ||||
| use objc::{class, msg_send, sel, sel_impl}; | ||||
| use scrap::{libc::c_void, quartz::ffi::*}; | ||||
| 
 | ||||
| static PRIVILEGES_SCRIPTS_DIR: Dir = | ||||
|     include_dir!("$CARGO_MANIFEST_DIR/src/platform/privileges_scripts"); | ||||
| static mut LATEST_SEED: i32 = 0; | ||||
| 
 | ||||
| extern "C" { | ||||
| @ -98,6 +101,79 @@ pub fn is_can_screen_recording(prompt: bool) -> bool { | ||||
|     can_record_screen | ||||
| } | ||||
| 
 | ||||
| pub fn is_installed_daemon(prompt: bool) -> bool { | ||||
|     if !prompt { | ||||
|         if !std::path::Path::new("/Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist") | ||||
|             .exists() | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist") | ||||
|             .exists() | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if !std::path::Path::new("/Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist") | ||||
|             .exists() | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     let install_script = PRIVILEGES_SCRIPTS_DIR.get_file("install.scpt").unwrap(); | ||||
|     let install_script_body = install_script.contents_utf8().unwrap(); | ||||
| 
 | ||||
|     let daemon_plist = PRIVILEGES_SCRIPTS_DIR | ||||
|         .get_file("com.carriez.rustdesk.daemon.plist") | ||||
|         .unwrap(); | ||||
|     let daemon_plist_body = daemon_plist.contents_utf8().unwrap(); | ||||
| 
 | ||||
|     let root_agent_plist = PRIVILEGES_SCRIPTS_DIR | ||||
|         .get_file("com.carriez.rustdesk.agent.root.plist") | ||||
|         .unwrap(); | ||||
|     let root_agent_plist_body = root_agent_plist.contents_utf8().unwrap(); | ||||
| 
 | ||||
|     let user_agent_plist = PRIVILEGES_SCRIPTS_DIR | ||||
|         .get_file("com.carriez.rustdesk.agent.user.plist") | ||||
|         .unwrap(); | ||||
|     let user_agent_plist_body = user_agent_plist.contents_utf8().unwrap(); | ||||
| 
 | ||||
|     match std::process::Command::new("osascript") | ||||
|         .arg("-e") | ||||
|         .arg(install_script_body) | ||||
|         .arg(daemon_plist_body) | ||||
|         .arg(root_agent_plist_body) | ||||
|         .arg(user_agent_plist_body) | ||||
|         .spawn() | ||||
|     { | ||||
|         Ok(mut proc) => proc.wait().is_ok(), | ||||
|         Err(e) => { | ||||
|             log::error!("run osascript failed: {}", e); | ||||
|             false | ||||
|         }, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn launch_or_stop_daemon(launch: bool) { | ||||
|     let mut script_filename = "launch_service.scpt"; | ||||
|     if !launch { | ||||
|         script_filename = "stop_service.scpt"; | ||||
|     } | ||||
| 
 | ||||
|     let script_file = PRIVILEGES_SCRIPTS_DIR.get_file(script_filename).unwrap(); | ||||
|     let script_body = script_file.contents_utf8().unwrap(); | ||||
| 
 | ||||
|     std::process::Command::new("osascript") | ||||
|         .arg("-e") | ||||
|         .arg(script_body) | ||||
|         .spawn() | ||||
|         .ok(); | ||||
| } | ||||
| 
 | ||||
| pub fn get_cursor_pos() -> Option<(i32, i32)> { | ||||
|     unsafe { | ||||
|         let e = CGEventCreate(0 as _); | ||||
| @ -333,3 +409,11 @@ pub fn block_input(_v: bool) { | ||||
| pub fn is_installed() -> bool { | ||||
|     true | ||||
| } | ||||
| 
 | ||||
| pub fn start_daemon() { | ||||
|     log::info!("{}", crate::username()); | ||||
|     if let Err(err) = crate::ipc::start("_daemon") { | ||||
|         log::error!("Failed to start ipc_daemon: {}", err); | ||||
|         std::process::exit(-1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,28 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| <plist version="1.0"> | ||||
|     <dict> | ||||
|         <key>Label</key> | ||||
|         <string>com.carriez.rustdesk.agent.root</string> | ||||
|         <key>LimitLoadToSessionType</key> | ||||
|         <array> | ||||
|             <string>LoginWindow</string> | ||||
|         </array> | ||||
|         <key>KeepAlive</key> | ||||
|         <dict> | ||||
|             <key>SuccessfulExit</key> | ||||
|             <false /> | ||||
|             <key>AfterInitialDemand</key> | ||||
|             <false /> | ||||
|         </dict> | ||||
|         <key>RunAtLoad</key> | ||||
|         <true /> | ||||
|         <key>ProgramArguments</key> | ||||
|         <array> | ||||
|             <string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string> | ||||
|             <string>--server</string> | ||||
|         </array> | ||||
|         <key>WorkingDirectory</key> | ||||
|         <string>/Applications/RustDesk.app/Contents/MacOS/</string> | ||||
|     </dict> | ||||
| </plist> | ||||
| @ -0,0 +1,28 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| <plist version="1.0"> | ||||
|     <dict> | ||||
|         <key>Label</key> | ||||
|         <string>com.carriez.rustdesk.agent.user</string> | ||||
|         <key>LimitLoadToSessionType</key> | ||||
|         <array> | ||||
|             <string>Aqua</string> | ||||
|         </array> | ||||
|         <key>KeepAlive</key> | ||||
|         <dict> | ||||
|             <key>SuccessfulExit</key> | ||||
|             <false /> | ||||
|             <key>AfterInitialDemand</key> | ||||
|             <false /> | ||||
|         </dict> | ||||
|         <key>RunAtLoad</key> | ||||
|         <true /> | ||||
|         <key>ProgramArguments</key> | ||||
|         <array> | ||||
|             <string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string> | ||||
|             <string>--server</string> | ||||
|         </array> | ||||
|         <key>WorkingDirectory</key> | ||||
|         <string>/Applications/RustDesk.app/Contents/MacOS/</string> | ||||
|     </dict> | ||||
| </plist> | ||||
| @ -0,0 +1,19 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| <plist version="1.0"> | ||||
|     <dict> | ||||
|         <key>Label</key> | ||||
|         <string>com.carriez.rustdesk.daemon</string> | ||||
|         <key>KeepAlive</key> | ||||
|         <true/> | ||||
|         <key>ProgramArguments</key> | ||||
|         <array> | ||||
|         	<string>/Applications/RustDesk.app/Contents/MacOS/rustdesk</string> | ||||
|         	<string>--daemon</string> | ||||
|         </array> | ||||
|         <key>RunAtLoad</key> | ||||
|         <true/> | ||||
|         <key>WorkingDirectory</key> | ||||
|         <string>/Applications/RustDesk.app/Contents/MacOS/</string> | ||||
|     </dict> | ||||
| </plist> | ||||
							
								
								
									
										19
									
								
								src/platform/privileges_scripts/install.scpt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/platform/privileges_scripts/install.scpt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| on run {daemon_file, root_agent_file, user_agent_file} | ||||
| 
 | ||||
| 	set sh1 to "echo " & quoted form of daemon_file & " > /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist && chown root:wheel /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist;" | ||||
| 
 | ||||
| 	set sh2 to "echo " & quoted form of root_agent_file & " > /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" | ||||
| 
 | ||||
| 	set sh3 to "echo " & quoted form of user_agent_file & " > /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist && chown root:wheel /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" | ||||
| 
 | ||||
|     set sh4 to "launchctl load -w /Library/LaunchDaemons/com.carriez.rustdesk.daemon.plist;" | ||||
| 
 | ||||
|     set sh5 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" | ||||
| 
 | ||||
|     set sh6 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" | ||||
| 
 | ||||
| 	set sh to sh1 & sh2 & sh3 & sh4 & sh5 &sh6 | ||||
| 
 | ||||
| 	log (sh) | ||||
| 	do shell script sh with prompt "RustDesk 需要安装服务" with administrator privileges | ||||
| end run | ||||
							
								
								
									
										7
									
								
								src/platform/privileges_scripts/launch_service.scpt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/platform/privileges_scripts/launch_service.scpt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| set sh1 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" | ||||
| 
 | ||||
| set sh2 to "launchctl load -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" | ||||
| 
 | ||||
| set sh to sh1 & sh2 | ||||
| 
 | ||||
| do shell script sh with prompt "RustDesk 需要停止服务" with administrator privileges | ||||
							
								
								
									
										7
									
								
								src/platform/privileges_scripts/stop_service.scpt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/platform/privileges_scripts/stop_service.scpt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| set sh1 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk.agent.root.plist;" | ||||
| 
 | ||||
| set sh2 to "launchctl unload -w /Library/LaunchAgents/com.carriez.rustdesk.agent.user.plist;" | ||||
| 
 | ||||
| set sh to sh1 & sh2 | ||||
| 
 | ||||
| do shell script sh with prompt "RustDesk 需要停止服务" with administrator privileges | ||||
							
								
								
									
										119
									
								
								src/server.rs
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								src/server.rs
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| use crate::ipc::Data; | ||||
| use crate::ipc::{ConnectionTmpl, Data}; | ||||
| use connection::{ConnInner, Connection}; | ||||
| use hbb_common::{ | ||||
|     allow_err, | ||||
| @ -9,12 +9,16 @@ use hbb_common::{ | ||||
|     message_proto::*, | ||||
|     protobuf::{Message as _, ProtobufEnum}, | ||||
|     rendezvous_proto::*, | ||||
|     sleep, | ||||
|     sleep, socket_client, | ||||
|     sodiumoxide::crypto::{box_, secretbox, sign}, | ||||
|     timeout, tokio, ResultType, Stream, | ||||
|     socket_client, | ||||
| }; | ||||
| #[cfg(target_os = "macos")] | ||||
| use notify::{watcher, RecursiveMode, Watcher}; | ||||
| use parity_tokio_ipc::ConnectionClient; | ||||
| use service::{GenericService, Service, ServiceTmpl, Subscriber}; | ||||
| use std::path::PathBuf; | ||||
| use std::time::Duration; | ||||
| use std::{ | ||||
|     collections::HashMap, | ||||
|     net::SocketAddr, | ||||
| @ -268,6 +272,10 @@ pub async fn start_server(is_server: bool, _tray: bool) { | ||||
|         log::info!("DISPLAY={:?}", std::env::var("DISPLAY")); | ||||
|         log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY")); | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(target_os = "macos")] | ||||
|     sync_and_watch_config_dir().await; | ||||
| 
 | ||||
|     if is_server { | ||||
|         std::thread::spawn(move || { | ||||
|             if let Err(err) = crate::ipc::start("") { | ||||
| @ -317,3 +325,108 @@ pub async fn start_server(is_server: bool, _tray: bool) { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(target_os = "macos")] | ||||
| async fn sync_and_watch_config_dir() { | ||||
|     if crate::username() == "root" { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     match crate::ipc::connect(1000, "_daemon").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(); | ||||
| 
 | ||||
|                 loop { | ||||
|                     let ev = rx.recv(); | ||||
|                     match ev { | ||||
|                         Ok(event) => match event { | ||||
|                             notify::DebouncedEvent::Write(path) => { | ||||
|                                 log::info!( | ||||
|                                     "config file changed, call ipc_daemon 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), | ||||
|                                     _ => {} | ||||
|                                 } | ||||
|                             } | ||||
|                             x => { | ||||
|                                 log::debug!("another {:?}", x) | ||||
|                             } | ||||
|                         }, | ||||
|                         Err(e) => println!("watch error: {:?}", e), | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|         Err(_) => { | ||||
|             log::info!("connect ipc_daemon failed, skip config sync"); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(target_os = "macos")] | ||||
| async fn sync_config_to_user(conn: &mut ConnectionTmpl<ConnectionClient>) -> 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<ConnectionClient>, | ||||
|     from: 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(()) | ||||
| } | ||||
|  | ||||
							
								
								
									
										15
									
								
								src/ui.rs
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/ui.rs
									
									
									
									
									
								
							| @ -360,9 +360,14 @@ impl UI { | ||||
|         if value.is_empty() { | ||||
|             options.remove(&key); | ||||
|         } else { | ||||
|             options.insert(key, value); | ||||
|             options.insert(key.clone(), value.clone()); | ||||
|         } | ||||
|         ipc::set_options(options.clone()).ok(); | ||||
| 
 | ||||
|         #[cfg(target_os = "macos")] | ||||
|         if &key == "stop-service" { | ||||
|             crate::platform::macos::launch_or_stop_daemon(value != "Y"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn install_path(&mut self) -> String { | ||||
| @ -525,6 +530,13 @@ impl UI { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     fn is_installed_daemon(&mut self, _prompt: bool) -> bool { | ||||
|         #[cfg(target_os = "macos")] | ||||
|         return crate::platform::macos::is_installed_daemon(_prompt); | ||||
|         #[cfg(not(target_os = "macos"))] | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     fn get_error(&mut self) -> String { | ||||
|         #[cfg(target_os = "linux")] | ||||
|         { | ||||
| @ -668,6 +680,7 @@ impl sciter::EventHandler for UI { | ||||
|         fn goto_install(); | ||||
|         fn is_process_trusted(bool); | ||||
|         fn is_can_screen_recording(bool); | ||||
|         fn is_installed_daemon(bool); | ||||
|         fn get_error(); | ||||
|         fn is_login_wayland(); | ||||
|         fn fix_login_wayland(); | ||||
|  | ||||
| @ -307,6 +307,7 @@ class App: Reactor.Component | ||||
|                     {handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? <UpgradeMe /> : ""} | ||||
|                     {is_can_screen_recording ? "": <CanScreenRecording />} | ||||
|                     {is_can_screen_recording && !handler.is_process_trusted(false) ? <TrustMe /> : ""} | ||||
|                     {is_can_screen_recording && handler.is_process_trusted(false) && !handler.is_installed_daemon(false) ? <InstallDaemon /> : ""} | ||||
|                     {system_error ? <SystemError /> : ""} | ||||
|                     {!system_error && handler.is_login_wayland() && !handler.current_is_wayland() ? <FixWayland /> : ""} | ||||
|                     {!system_error && handler.current_is_wayland() ? <ModifyDefaultLogin /> : ""} | ||||
| @ -491,6 +492,21 @@ class CanScreenRecording: Reactor.Component { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| class InstallDaemon: Reactor.Component { | ||||
|     function render() { | ||||
|         return <div .trust-me> | ||||
|             <div>{translate('Configuration Permissions')}</div> | ||||
|             <div>{translate('install_daemon')}</div> | ||||
|             <div #install-daemon .link>{translate('Configure')}</div> | ||||
|         </div>; | ||||
|     } | ||||
| 
 | ||||
|     event click $(#install-daemon) { | ||||
|         handler.is_installed_daemon(true); | ||||
|         watch_trust(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| class FixWayland: Reactor.Component { | ||||
|     function render() { | ||||
|         return <div .trust-me> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user