diff --git a/swhkd/src/daemon.rs b/swhkd/src/daemon.rs index 70553d8..4eb0d23 100644 --- a/swhkd/src/daemon.rs +++ b/swhkd/src/daemon.rs @@ -13,8 +13,9 @@ use std::{ env, error::Error, fs::{self, File, OpenOptions, Permissions}, - io::Read, - os::unix::{fs::PermissionsExt, net::UnixListener}, + hash::{DefaultHasher, Hash, Hasher}, + io::{Read, Write}, + os::unix::{fs::PermissionsExt, net::UnixStream}, path::{Path, PathBuf}, process::{exit, id, Command, Stdio}, sync::{Arc, Mutex}, @@ -92,7 +93,8 @@ async fn main() -> Result<(), Box> { log::debug!("Wating for server to start..."); // The first and the most important request for the env - let env = refresh_env(invoking_uid)?.unwrap_or(environ::Env::construct(None)); + let (env, mut env_hash) = refresh_env(invoking_uid, 0)?; + let env = env.unwrap_or(environ::Env::construct(None)); log::trace!("Environment Aquired"); let log_file_name = if let Some(val) = args.log { val @@ -130,6 +132,7 @@ async fn main() -> Result<(), Box> { // along with it, an additional 120ms is added to it, just to be safe. let delta = (args.cooldown.unwrap_or(250) as f64 * 0.1) as u64; let server_cooldown = args.refresh.unwrap_or(default_cooldown - delta); + let server_cooldown = 30; // Set up a channel to communicate with the server // The channel can have upto 100 commands in the queue @@ -149,19 +152,22 @@ async fn main() -> Result<(), Box> { loop { { let mut pairs = pairs_clone.lock().unwrap(); - match refresh_env(invoking_uid) { - Ok(Some(env)) => { + match refresh_env(invoking_uid, env_hash) { + Ok((Some(env), hash)) => { pairs.clone_from(&env.pairs); + env_hash = hash; + } + Ok((None, hash)) => { + env_hash = hash; } - Ok(None) => {} Err(e) => { log::error!("Error: {}", e); _ = Command::new("notify-send").arg(format!("ERROR {}", e)).spawn(); - log::warn!("Skipping refresh..."); + exit(1); } } } - sleep(Duration::from_millis(server_cooldown)).await; + sleep(Duration::from_secs(server_cooldown)).await; } }); @@ -632,29 +638,48 @@ fn get_file_paths(runtime_dir: &str) -> (String, String) { } /// Refreshes the environment variables from the server -fn refresh_env(invoking_uid: u32) -> Result, Box> { +fn refresh_env( + invoking_uid: u32, + prev_hash: u64, +) -> Result<(Option, u64), Box> { // A simple placeholder for the env that is to be refreshed let env = environ::Env::construct(None); let (_pid_path, sock_path) = get_file_paths(env.xdg_runtime_dir(invoking_uid).to_str().unwrap()); - if Path::new(&sock_path).exists() { - fs::remove_file(&sock_path)?; + let mut result: String = String::new(); + if let Ok(mut stream) = UnixStream::connect(&sock_path) { + let n = stream.write(&[1])?; + if n != 1 { + log::error!("Failed to write to socket."); + exit(1); + } + stream.read_to_string(&mut result)?; } + let env_hash = calculate_hash(result.clone()); - let mut result: String = String::new(); - let listener = UnixListener::bind(&sock_path)?; - fs::set_permissions(sock_path, fs::Permissions::from_mode(0o666))?; - for mut socket in listener.incoming().flatten() { - let mut buf = String::new(); - socket.read_to_string(&mut buf)?; - // If the server doesn't return any variables, return None - if buf.is_empty() { - return Ok(None); + if env_hash == prev_hash { + log::info!("No change in env detected."); + return Ok((None, env_hash)); + } + + if let Ok(mut stream) = UnixStream::connect(&sock_path) { + let n = stream.write(&[2])?; + if n != 1 { + log::error!("Failed to write to socket."); + exit(1); } - log::info!("Env refreshed from server."); - result.push_str(&buf); + log::info!("wrote get"); + stream.read_to_string(&mut result)?; + log::info!("read get"); } - Ok(Some(environ::Env::construct(Some(&result)))) + + Ok((Some(environ::Env::construct(Some(&result))), env_hash)) +} + +pub fn calculate_hash(t: String) -> u64 { + let mut hasher = DefaultHasher::new(); + t.hash(&mut hasher); + hasher.finish() } diff --git a/swhks/src/main.rs b/swhks/src/main.rs index ca4916e..dc75c1b 100644 --- a/swhks/src/main.rs +++ b/swhks/src/main.rs @@ -1,6 +1,8 @@ use std::error::Error; use std::fs::Permissions; use std::hash::{DefaultHasher, Hash, Hasher}; +use std::io::Read; +use std::os::unix::net::UnixListener; use std::{ fs::{self}, io::Write, @@ -57,21 +59,53 @@ fn main() -> std::io::Result<()> { log::info!("Started SWHKS placeholder server"); // Daemonize the process - let _ = nix::unistd::daemon(true, false); + //let _ = nix::unistd::daemon(true, false); setup_swhks(invoking_uid, PathBuf::from(runtime_dir)); - loop { - if let Ok(mut stream) = UnixStream::connect(&sock_file_path) { - // Only if the environment has changed, send it to swhkd, else do nothing. - if prev_hash != calculate_hash(get_env().unwrap()) { - log::debug!("Env changed, sending to swhkd"); - let new_env = get_env().unwrap(); - let _ = stream.write_all(new_env.as_bytes()); - log::debug!("Sent env to swhkd"); - prev_hash = calculate_hash(new_env); + + if Path::new(&sock_file_path).exists() { + fs::remove_file(&sock_file_path)?; + } + + let listener = UnixListener::bind(sock_file_path)?; + let mut buff = [0; 1]; + println!("Listening for incoming connections..."); + + for stream in listener.incoming() { + match stream { + Ok(mut stream) => { + println!("Connection established!"); + stream.read_exact(&mut buff)?; + println!("Received: {:?}", buff); + if buff == [1] { + log::debug!("Received VERIFY message from swhkd"); + let _ = stream.write_all(prev_hash.to_string().as_bytes()); + log::debug!("Sent hash to swhkd"); + stream.flush()?; + continue; + } + if buff == [2] { + log::debug!("Received GET message from swhkd"); + let env = get_env().unwrap(); + if prev_hash == calculate_hash(env.clone()) { + log::debug!("No changes in environment variables"); + } else { + log::debug!("Changes in environment variables"); + } + prev_hash = calculate_hash(env.clone()); + let _ = stream.write_all(env.as_bytes()); + stream.flush()?; + continue; + } } - }; + Err(e) => { + log::error!("Error: {}", e); + break; + } + } } + + Ok(()) } /// Calculates a simple hash of the string