diff --git a/src/client.rs b/src/client.rs index 299176e..d1af291 100644 --- a/src/client.rs +++ b/src/client.rs @@ -20,7 +20,7 @@ pub fn handle_client_only_action(action: ActionClientOnly) -> Result<()> { Ok(()) } -pub fn forward_command_to_server(mut stream: UnixStream, action: opts::ActionWithServer) -> Result<()> { +pub fn do_server_call(mut stream: UnixStream, action: opts::ActionWithServer) -> Result> { log::info!("Forwarding options to server"); stream .set_nonblocking(false) @@ -43,8 +43,6 @@ pub fn forward_command_to_server(mut stream: UnixStream, action: opts::ActionWit stream .read_to_string(&mut buf) .context("Error reading response from server")?; - if !buf.is_empty() { - println!("{}", buf); - } - Ok(()) + + Ok(if buf.is_empty() { None } else { Some(buf) }) } diff --git a/src/main.rs b/src/main.rs index b32b7cd..ca2712c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,16 +53,31 @@ fn main() { } opts::Action::WithServer(action) => { log::info!("Trying to find server process"); - if let Some(stream) = try_connect(&*IPC_SOCKET_PATH) { - log::info!("Connected to eww server."); - client::forward_command_to_server(stream, action).context("Error while forwarding command to server")?; - } else if action.needs_server_running() { - println!("No eww server running"); + match net::UnixStream::connect(&*IPC_SOCKET_PATH) { + Ok(stream) => { + log::info!("Connected to Eww server."); + let response = + client::do_server_call(stream, action).context("Error while forwarding command to server")?; + if let Some(response) = response { + println!("{}", response); + } + } + Err(_) => { + println!("Failed to connect to the eww daemon."); + println!("Make sure to start the eww daemon process by running `eww daemon` first."); + } + } + } + + opts::Action::Daemon => { + // make sure that there isn't already a Eww daemon running. + if check_server_running(&*IPC_SOCKET_PATH) { + eprintln!("Eww server already running."); std::process::exit(1); } else { - log::info!("No server running, initializing server..."); + log::info!("Initializing Eww server."); let _ = std::fs::remove_file(&*crate::IPC_SOCKET_PATH); - server::initialize_server(opts.should_detach, action)?; + server::initialize_server()?; } } } @@ -70,16 +85,14 @@ fn main() { if let Err(e) = result { eprintln!("{:?}", e); + std::process::exit(1); } } -fn try_connect(path: &std::path::PathBuf) -> Option { - if path.exists() { - for _ in 0..5 { - if let Ok(stream) = net::UnixStream::connect(&*IPC_SOCKET_PATH) { - return Some(stream); - } - } - } - return None; +/// Check if a eww server is currently running by trying to send a ping message to it. +fn check_server_running(socket_path: &std::path::PathBuf) -> bool { + let response = net::UnixStream::connect(socket_path) + .ok() + .and_then(|stream| client::do_server_call(stream, opts::ActionWithServer::Ping).ok()); + response.is_some() } diff --git a/src/opts.rs b/src/opts.rs index 3724d91..3abafd9 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -11,7 +11,6 @@ use crate::{ #[derive(Debug, Serialize, Deserialize, PartialEq)] pub struct Opt { pub action: Action, - pub should_detach: bool, } /// Helper struct that will be normalized into instance of [Opt] @@ -23,6 +22,10 @@ struct RawOpt { #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] pub enum Action { + /// Start the Eww daemon. + #[structopt(name = "daemon")] + Daemon, + #[structopt(flatten)] ClientOnly(ActionClientOnly), @@ -39,10 +42,6 @@ pub enum ActionClientOnly { #[derive(StructOpt, Debug, Serialize, Deserialize, PartialEq)] pub enum ActionWithServer { - /// Start the eww daemon. - #[structopt(name = "daemon")] - Daemon, - /// Ping the eww server, checking if it is reachable. #[structopt(name = "ping")] Ping, @@ -113,10 +112,7 @@ impl Opt { impl From for Opt { fn from(other: RawOpt) -> Self { let RawOpt { action } = other; - Opt { - should_detach: action == Action::WithServer(ActionWithServer::Daemon), - action, - } + Opt { action } } } @@ -130,7 +126,11 @@ fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimitiveValue)> { impl ActionWithServer { pub fn into_eww_command(self) -> (app::EwwCommand, Option>) { let command = match self { - ActionWithServer::Daemon | ActionWithServer::Ping => app::EwwCommand::NoOp, + ActionWithServer::Ping => { + let (send, recv) = tokio::sync::mpsc::unbounded_channel(); + let _ = send.send("pong".to_owned()); + return (app::EwwCommand::NoOp, Some(recv)); + } ActionWithServer::Update { mappings } => app::EwwCommand::UpdateVars(mappings.into_iter().collect()), ActionWithServer::OpenMany { windows } => app::EwwCommand::OpenMany(windows), ActionWithServer::OpenWindow { @@ -158,12 +158,4 @@ impl ActionWithServer { }; (command, None) } - - /// returns true if this command requires a server to already be running - pub fn needs_server_running(&self) -> bool { - match self { - ActionWithServer::OpenWindow { .. } | ActionWithServer::Daemon => false, - _ => true, - } - } } diff --git a/src/server.rs b/src/server.rs index e1a0d25..268e883 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,10 +12,8 @@ use tokio::{ sync::mpsc::*, }; -pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) -> Result<()> { - if should_detach { - do_detach()?; - } +pub fn initialize_server() -> Result<()> { + do_detach()?; simple_signal::set_handler(&[simple_signal::Signal::Int, simple_signal::Signal::Term], move |_| { println!("Shutting down eww daemon..."); @@ -24,6 +22,7 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) -> std::process::exit(1); } }); + let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel(); let config_file_path = crate::CONFIG_DIR.join("eww.xml"); let config_dir = config_file_path @@ -36,7 +35,6 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) -> let eww_config = config::EwwConfig::read_from_file(&config_file_path)?; gtk::init()?; - let (ui_send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel(); log::info!("Initializing script var handler"); let script_var_handler = script_var_handler::init(ui_send.clone()); @@ -58,13 +56,8 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) -> app.load_css(&eww_css)?; } - // run the command that eww was started with - log::info!("running command: {:?}", &action); - let (command, maybe_response_recv) = action.into_eww_command(); - app.handle_command(command); - // initialize all the handlers and tasks running asyncronously - init_async_part(config_file_path, scss_file_path, maybe_response_recv, ui_send); + init_async_part(config_file_path, scss_file_path, ui_send); glib::MainContext::default().spawn_local(async move { while let Some(event) = ui_recv.recv().await { @@ -78,28 +71,13 @@ pub fn initialize_server(should_detach: bool, action: opts::ActionWithServer) -> Ok(()) } -fn init_async_part( - config_file_path: PathBuf, - scss_file_path: PathBuf, - maybe_response_recv: Option>, - ui_send: UnboundedSender, -) { +fn init_async_part(config_file_path: PathBuf, scss_file_path: PathBuf, ui_send: UnboundedSender) { std::thread::spawn(move || { let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .expect("Failed to initialize tokio runtime"); rt.block_on(async { - // TODO This really does not belong here at all :< - // print out the response of this initial command, if there is any - tokio::spawn(async { - if let Some(mut response_recv) = maybe_response_recv { - if let Ok(Some(response)) = tokio::time::timeout(Duration::from_millis(100), response_recv.recv()).await { - println!("{}", response); - } - } - }); - let filewatch_join_handle = { let ui_send = ui_send.clone(); tokio::spawn(async move { run_filewatch(config_file_path, scss_file_path, ui_send).await })