diff --git a/src/core_main.rs b/src/core_main.rs index 1c088f97b..3b241abe1 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -267,8 +267,6 @@ pub fn core_main() -> Option> { log::info!("start --uninstall-service"); crate::platform::uninstall_service(false); } else if args[0] == "--service" { - #[cfg(target_os = "macos")] - crate::platform::macos::hide_dock(); log::info!("start --service"); crate::start_os_service(); return None; diff --git a/src/platform/macos.rs b/src/platform/macos.rs index aff7f7593..ec2aac681 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -17,7 +17,7 @@ use core_graphics::{ display::{kCGNullWindowID, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo}, window::{kCGWindowName, kCGWindowOwnerPID}, }; -use hbb_common::{allow_err, anyhow::anyhow, bail, log, message_proto::Resolution}; +use hbb_common::{allow_err, anyhow::anyhow, bail, libc, log, message_proto::Resolution}; use include_dir::{include_dir, Dir}; use objc::{class, msg_send, sel, sel_impl}; use scrap::{libc::c_void, quartz::ffi::*}; @@ -479,38 +479,45 @@ pub fn lock_screen() { } pub fn start_os_service() { + crate::platform::macos::hide_dock(); let exe = std::env::current_exe().unwrap_or_default(); let tm0 = hbb_common::get_modified_time(&exe); - log::info!("{}", crate::username()); + log::info!("Username: {}", crate::username()); + log::info!("Startime: {:?}", get_server_start_time()); std::thread::spawn(move || loop { loop { std::thread::sleep(std::time::Duration::from_millis(300)); let now = hbb_common::get_modified_time(&exe); - if now != tm0 && now != std::time::UNIX_EPOCH { + let file_updated = now != tm0 && now != std::time::UNIX_EPOCH; + let Some(start_time) = get_server_start_time() else { + continue; + }; + let dt = start_time.1 - start_time.0; + if file_updated || dt >= 0 { // sleep a while to wait for resources file ready std::thread::sleep(std::time::Duration::from_millis(300)); - println!("{:?} updated, will restart", exe); - // this won't kill myself - std::process::Command::new("pkill") - .args(&["-f", &crate::get_app_name()]) - .status() - .ok(); - println!("The others killed"); - // launchctl load/unload/start agent not work in daemon, show not privileged. - // sudo launchctl asuser 501 open -n also not allowed. - std::process::Command::new("launchctl") - .args(&[ - "asuser", - &get_active_userid(), - "open", - "-a", - &exe.to_str().unwrap_or(""), - "--args", - "--server", - ]) - .status() - .ok(); + if file_updated { + log::info!("{:?} updated, will restart", exe); + } + if dt >= 0 { + // I tried add delegate (using tao and with its main loop0, but it works in normal mode, but not work as daemon + log::info!( + "Agent start later, {:?}, will restart to make delegate work", + start_time + ); + } + for pid in start_time.2 { + unsafe { + libc::kill(pid.as_u32() as _, libc::SIGTERM); + } + } + // https://emorydunn.github.io/LaunchAgent/Classes/LaunchAgent.html#/s:11LaunchAgentAAC16throttleIntervalSiSgvp, + // by default, ThrottleInterval = 10, we changed it to 1 + if dt >= 0 { + std::thread::sleep(std::time::Duration::from_secs(dt.clamp(3, 30) as _)); + } + log::info!("The others killed"); std::process::exit(0); } } @@ -614,25 +621,50 @@ pub fn hide_dock() { } } -fn check_main_window() -> bool { - if crate::check_process("", true) { - return true; +fn get_server_start_time() -> Option<(i64, i64, Vec)> { + use hbb_common::sysinfo::System; + let mut sys = System::new(); + sys.refresh_processes(); + let mut path = std::env::current_exe().unwrap_or_default(); + if let Ok(linked) = path.read_link() { + path = linked; } - let app = format!("/Applications/{}.app", crate::get_app_name()); - std::process::Command::new("open") - .args(["-n", &app]) - .status() - .ok(); - false + let path = path.to_string_lossy().to_lowercase(); + let Some(my_start_time) = sys + .process((std::process::id() as usize).into()) + .map(|p| p.start_time()) + else { + return None; + }; + let mut all = Vec::new(); + for (_, p) in sys.processes() { + let mut cur_path = p.exe().to_path_buf(); + if let Ok(linked) = cur_path.read_link() { + cur_path = linked; + } + if cur_path.to_string_lossy().to_lowercase() != path { + continue; + } + if p.pid().as_u32() == std::process::id() { + continue; + } + all.push(p); + } + for p in all.iter() { + let parg = if p.cmd().len() <= 1 { "" } else { &p.cmd()[1] }; + let pids = all.iter().map(|p| p.pid()).collect(); + if parg == "--server" { + return Some((my_start_time as _, p.start_time() as _, pids)); + } + } + None } pub fn handle_application_should_open_untitled_file() { hbb_common::log::debug!("icon clicked on finder"); let x = std::env::args().nth(1).unwrap_or_default(); if x == "--server" || x == "--cm" || x == "--tray" { - if crate::platform::macos::check_main_window() { - allow_err!(crate::ipc::send_url_scheme(crate::get_uri_prefix())); - } + std::thread::spawn(move || crate::handle_url_scheme("".to_lowercase())); } } diff --git a/src/platform/privileges_scripts/agent.plist b/src/platform/privileges_scripts/agent.plist index 5b52444da..5ff786a49 100644 --- a/src/platform/privileges_scripts/agent.plist +++ b/src/platform/privileges_scripts/agent.plist @@ -16,6 +16,8 @@ AfterInitialDemand + ThrottleInterval + 1 RunAtLoad ProgramArguments diff --git a/src/server.rs b/src/server.rs index 889747aec..ef89c5e3b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -550,12 +550,8 @@ async fn sync_and_watch_config_dir() { let mut cfg0 = (Config::get(), Config2::get()); let mut synced = false; - let tries = - if std::env::args().len() == 2 && std::env::args().nth(1) == Some("--server".to_owned()) { - 30 - } else { - 3 - }; + let is_server = std::env::args().nth(1) == Some("--server".to_owned()); + let tries = if is_server { 30 } else { 3 }; log::debug!("#tries of ipc service connection: {}", tries); use hbb_common::sleep; for i in 1..=tries { @@ -597,7 +593,14 @@ async fn sync_and_watch_config_dir() { match conn.send(&Data::SyncConfig(Some(cfg.clone().into()))).await { Err(e) => { log::error!("sync config to root failed: {}", e); - break; + match crate::ipc::connect(1000, "_service").await { + Ok(mut _conn) => { + conn = _conn; + log::info!("reconnected to ipc_service"); + break; + } + _ => {} + } } _ => { cfg0 = cfg;