diff --git a/.changes/fix-yield-single-instance-macos.md b/.changes/fix-yield-single-instance-macos.md new file mode 100644 index 000000000..d9985957a --- /dev/null +++ b/.changes/fix-yield-single-instance-macos.md @@ -0,0 +1,4 @@ +--- +"single-instance": patch +--- +Fix blocked thread on the single-instance plugin for MacOS: replace standard `UnixListener` with `tokio::net::UnixListener`, so the task can yield. diff --git a/Cargo.lock b/Cargo.lock index f4c95b5fa..86be4d023 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6793,6 +6793,7 @@ dependencies = [ "tauri", "tauri-plugin-deep-link", "thiserror 2.0.12", + "tokio", "tracing", "windows-sys 0.60.2", "zbus", diff --git a/plugins/single-instance/Cargo.toml b/plugins/single-instance/Cargo.toml index 3da9ba7c8..3af5667c8 100644 --- a/plugins/single-instance/Cargo.toml +++ b/plugins/single-instance/Cargo.toml @@ -24,6 +24,7 @@ tracing = { workspace = true } thiserror = { workspace = true } tauri-plugin-deep-link = { path = "../deep-link", version = "2.4.9", optional = true } semver = { version = "1", optional = true } +tokio = { version = "1", features = ["net"] } [target."cfg(target_os = \"windows\")".dependencies.windows-sys] version = "0.60" diff --git a/plugins/single-instance/src/platform_impl/macos.rs b/plugins/single-instance/src/platform_impl/macos.rs index a2df9092e..bd2c74a7e 100644 --- a/plugins/single-instance/src/platform_impl/macos.rs +++ b/plugins/single-instance/src/platform_impl/macos.rs @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MIT use std::{ - io::{BufWriter, Error, ErrorKind, Read, Write}, - os::unix::net::{UnixListener, UnixStream}, + io::{BufWriter, Error, ErrorKind, Write}, + os::unix::net::UnixStream, path::PathBuf, }; @@ -15,6 +15,7 @@ use tauri::{ plugin::{self, TauriPlugin}, AppHandle, Config, Manager, RunEvent, Runtime, }; +use tokio::io::AsyncReadExt; pub fn init(cb: Box>) -> TauriPlugin { plugin::Builder::new("single-instance") @@ -31,7 +32,7 @@ pub fn init(cb: Box>) -> TauriPlugin { ErrorKind::NotFound | ErrorKind::ConnectionRefused => { // This process claims itself as singleton as likely none exists socket_cleanup(&socket); - listen_for_other_instances(&socket, app.clone(), cb); + listen_for_other_instances(socket, app.clone(), cb); } _ => { tracing::debug!( @@ -92,42 +93,40 @@ fn notify_singleton(socket: &PathBuf) -> Result<(), Error> { } fn listen_for_other_instances( - socket: &PathBuf, + socket: PathBuf, app: AppHandle, mut cb: Box>, ) { - match UnixListener::bind(socket) { - Ok(listener) => { - tauri::async_runtime::spawn(async move { - for stream in listener.incoming() { - match stream { - Ok(mut stream) => { - let mut s = String::new(); - match stream.read_to_string(&mut s) { - Ok(_) => { - let (cwd, args) = s.split_once("\0\0").unwrap_or_default(); - let args: Vec = - args.split('\0').map(String::from).collect(); - cb(app.app_handle(), args, cwd.to_string()); - } - Err(e) => { - tracing::debug!("single_instance failed to be notified: {e}") - } + tauri::async_runtime::spawn(async move { + match tokio::net::UnixListener::bind(socket) { + Ok(listener) => loop { + match listener.accept().await { + Ok((mut stream, _addr)) => { + let mut s = String::new(); + match stream.read_to_string(&mut s).await { + Ok(_) => { + let (cwd, args) = s.split_once("\0\0").unwrap_or_default(); + let args: Vec = + args.split('\0').map(String::from).collect(); + cb(app.app_handle(), args, cwd.to_string()); + } + Err(e) => { + tracing::debug!("single_instance failed to be notified: {e}") } } - Err(err) => { - tracing::debug!("single_instance failed to be notified: {}", err); - continue; - } + } + Err(err) => { + tracing::debug!("single_instance failed to be notified: {}", err); + continue; } } - }); + }, + Err(err) => { + tracing::error!( + "single_instance failed to listen to other processes - launching normally: {}", + err + ); + } } - Err(err) => { - tracing::error!( - "single_instance failed to listen to other processes - launching normally: {}", - err - ); - } - } + }); }