diff --git a/src/ipc.rs b/src/ipc.rs index 99c31a3..a08b014 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,6 +1,11 @@ +use iced::futures::channel::mpsc; +use iced::futures::{SinkExt, Stream}; +use iced::{Subscription, stream}; use std::io::{Read, Write}; -use std::os::unix::net::{UnixListener, UnixStream}; +use std::os::unix::net::UnixStream; use std::path::PathBuf; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::UnixListener; const IPC_COMMAND_TOGGLE: &[u8] = b"toggle"; const IPC_COMMAND_OAUTH_PREFIX: &[u8] = b"oauth:"; @@ -50,39 +55,49 @@ pub fn is_daemon_running() -> bool { UnixStream::connect(&path).is_ok() } -pub fn start_listener(on_toggle: F) -> Result<(), Box> -where - F: Fn() + Send + 'static, -{ - let path = socket_path(); +fn listener() -> impl Stream { + stream::channel(100, |mut output: mpsc::Sender| async move { + let path = socket_path(); - if path.exists() { - std::fs::remove_file(&path)?; - } + if path.exists() { + let _ = std::fs::remove_file(&path); + } - let listener = UnixListener::bind(&path)?; + let listener = match UnixListener::bind(&path) { + Ok(l) => l, + Err(e) => { + eprintln!("Failed to bind IPC socket: {}", e); + std::future::pending::<()>().await; + return; + } + }; - std::thread::spawn(move || { - for stream in listener.incoming() { - if let Ok(mut stream) = stream { + loop { + if let Ok((mut stream, _)) = listener.accept().await { let mut buf = [0u8; 2048]; - if let Ok(n) = stream.read(&mut buf) { + if let Ok(n) = stream.read(&mut buf).await { let data = &buf[..n]; if data == IPC_COMMAND_TOGGLE { - on_toggle(); - let _ = stream.write_all(IPC_RESPONSE_OK); + let _ = output.send(crate::Message::ToggleWindow).await; + let _ = stream.write_all(IPC_RESPONSE_OK).await; } else if data.starts_with(IPC_COMMAND_OAUTH_PREFIX) { - let url = std::str::from_utf8(&data[IPC_COMMAND_OAUTH_PREFIX.len()..]) - .unwrap_or(""); - crate::deep_link::handle_oauth_redirect(url); - let _ = stream.write_all(IPC_RESPONSE_OK); + if let Ok(url) = + std::str::from_utf8(&data[IPC_COMMAND_OAUTH_PREFIX.len()..]) + { + let _ = output + .send(crate::Message::HandleOAuthRedirect(url.to_string())) + .await; + let _ = stream.write_all(IPC_RESPONSE_OK).await; + } } } } } - }); + }) +} - Ok(()) +pub fn subscription() -> Subscription { + Subscription::run(listener) } pub fn cleanup() { diff --git a/src/main.rs b/src/main.rs index 70ca8bd..e553212 100644 --- a/src/main.rs +++ b/src/main.rs @@ -148,12 +148,15 @@ fn subscription(state: &State) -> Subscription { None }); + let ipc_sub = ipc::subscription(); + let mut subs = vec![ message_sub, sidecar_sub, window_close_sub, animation_sub, escape_sub, + ipc_sub, ]; if state.window_id.is_some() { @@ -305,12 +308,6 @@ fn run_daemon() -> Result<(), Box> { setup_channels(); - ipc::start_listener(|| { - if let Some(mut sender) = globals::SENDER.lock().unwrap().clone() { - let _ = iced::futures::executor::block_on(sender.send(Message::ToggleWindow)); - } - })?; - let result = iced::daemon(boot, update, daemon_view) .subscription(subscription) .title("Flare") diff --git a/src/message.rs b/src/message.rs index d23d276..08fb16d 100644 --- a/src/message.rs +++ b/src/message.rs @@ -38,6 +38,7 @@ pub enum Message { Settings(crate::screens::settings::SettingsMessage), OpenUrl(String), + HandleOAuthRedirect(String), Tick(Instant), diff --git a/src/update.rs b/src/update.rs index f9565b2..d732799 100644 --- a/src/update.rs +++ b/src/update.rs @@ -227,6 +227,9 @@ pub fn update(state: &mut State, message: Message) -> Task { Message::OpenUrl(url) => { let _ = crate::utils::open_url(&url); } + Message::HandleOAuthRedirect(url) => { + crate::deep_link::handle_oauth_redirect(&url); + } Message::SidecarMessage(response) => { return handle_sidecar_response(state, response);