diff --git a/lan-mouse-gtk/src/lib.rs b/lan-mouse-gtk/src/lib.rs index 9908e05f2..c1ac4a8fb 100644 --- a/lan-mouse-gtk/src/lib.rs +++ b/lan-mouse-gtk/src/lib.rs @@ -98,12 +98,34 @@ fn setup_menu(app: &adw::Application) { } fn build_ui(app: &Application) { + // If a window already exists (re-activation), just present it + if let Some(window) = app.windows().first() { + window.present(); + return; + } + log::debug!("connecting to lan-mouse-socket"); - let (mut frontend_rx, frontend_tx) = match lan_mouse_ipc::connect() { + let (mut frontend_rx, frontend_tx) = match lan_mouse_ipc::try_connect() { Ok(conn) => conn, Err(e) => { - log::error!("{e}"); - process::exit(1); + log::warn!("could not connect to daemon ({e}), spawning a new one"); + if let Err(spawn_err) = process::Command::new( + env::current_exe().expect("could not determine executable path"), + ) + .args(env::args().skip(1)) + .arg("daemon") + .spawn() + { + log::error!("failed to spawn daemon: {spawn_err}"); + process::exit(1); + } + match lan_mouse_ipc::connect() { + Ok(conn) => conn, + Err(e) => { + log::error!("{e}"); + process::exit(1); + } + } } }; log::debug!("connected to lan-mouse-socket"); diff --git a/lan-mouse-ipc/src/connect.rs b/lan-mouse-ipc/src/connect.rs index 1b751bea9..997b0096d 100644 --- a/lan-mouse-ipc/src/connect.rs +++ b/lan-mouse-ipc/src/connect.rs @@ -45,8 +45,40 @@ impl FrontendRequestWriter { } } +/// Try to connect to the service once without retrying. +pub fn try_connect() -> Result<(FrontendEventReader, FrontendRequestWriter), ConnectionError> { + #[cfg(unix)] + let rx = { + let socket_path = crate::default_socket_path()?; + UnixStream::connect(&socket_path)? + }; + #[cfg(windows)] + let rx = TcpStream::connect("127.0.0.1:5252")?; + make_connection(rx) +} + pub fn connect() -> Result<(FrontendEventReader, FrontendRequestWriter), ConnectionError> { let rx = wait_for_service()?; + make_connection(rx) +} + +#[cfg(unix)] +fn make_connection( + rx: UnixStream, +) -> Result<(FrontendEventReader, FrontendRequestWriter), ConnectionError> { + let tx = rx.try_clone()?; + let buf_reader = BufReader::new(rx); + let lines = buf_reader.lines(); + let line_writer = LineWriter::new(tx); + let reader = FrontendEventReader { lines }; + let writer = FrontendRequestWriter { line_writer }; + Ok((reader, writer)) +} + +#[cfg(windows)] +fn make_connection( + rx: TcpStream, +) -> Result<(FrontendEventReader, FrontendRequestWriter), ConnectionError> { let tx = rx.try_clone()?; let buf_reader = BufReader::new(rx); let lines = buf_reader.lines(); diff --git a/lan-mouse-ipc/src/lib.rs b/lan-mouse-ipc/src/lib.rs index a2c71126d..032f3c5ea 100644 --- a/lan-mouse-ipc/src/lib.rs +++ b/lan-mouse-ipc/src/lib.rs @@ -20,7 +20,7 @@ mod connect; mod connect_async; mod listen; -pub use connect::{FrontendEventReader, FrontendRequestWriter, connect}; +pub use connect::{FrontendEventReader, FrontendRequestWriter, connect, try_connect}; pub use connect_async::{AsyncFrontendEventReader, AsyncFrontendRequestWriter, connect_async}; pub use listen::AsyncFrontendListener; @@ -299,3 +299,18 @@ pub fn default_socket_path() -> Result { .join("Caches") .join(LAN_MOUSE_SOCKET_NAME)) } + +/// Check if a lan-mouse service is already running by probing the IPC socket. +#[cfg(unix)] +pub fn is_service_running() -> bool { + let Ok(socket_path) = default_socket_path() else { + return false; + }; + std::os::unix::net::UnixStream::connect(socket_path).is_ok() +} + +/// Check if a lan-mouse service is already running by probing the IPC socket. +#[cfg(windows)] +pub fn is_service_running() -> bool { + std::net::TcpStream::connect("127.0.0.1:5252").is_ok() +} diff --git a/src/main.rs b/src/main.rs index 0ca54c93d..e9f439b1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,18 +73,26 @@ fn run() -> Result<(), LanMouseError> { // run a frontend #[cfg(feature = "gtk")] { - let mut service = start_service()?; + // Only spawn a new daemon if one isn't already running + let mut service = if lan_mouse_ipc::is_service_running() { + log::info!("daemon already running, connecting to existing instance"); + None + } else { + Some(start_service()?) + }; let res = lan_mouse_gtk::run(); - #[cfg(unix)] - { - // on unix we give the service a chance to terminate gracefully - let pid = service.id() as libc::pid_t; - unsafe { - libc::kill(pid, libc::SIGINT); + if let Some(ref mut service) = service { + #[cfg(unix)] + { + // on unix we give the service a chance to terminate gracefully + let pid = service.id() as libc::pid_t; + unsafe { + libc::kill(pid, libc::SIGINT); + } + service.wait()?; } - service.wait()?; + service.kill()?; } - service.kill()?; res?; } #[cfg(not(feature = "gtk"))]