diff --git a/Cargo.lock b/Cargo.lock index b8ca81f..678e0c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,155 +3,40 @@ version = 4 [[package]] -name = "async-channel" -version = "2.3.1" +name = "addr2line" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", + "gimli", ] [[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "tracing", - "windows-sys", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-net" +name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite", -] +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] -name = "async-process" -version = "2.3.0" +name = "backtrace" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", + "addr2line", "cfg-if", - "event-listener", - "futures-lite", - "rustix", - "tracing", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", ] [[package]] -name = "async-signal" -version = "0.2.10" +name = "bytes" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix", - "signal-hook-registry", - "slab", - "windows-sys", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cfg-if" @@ -160,94 +45,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "errno" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "event-listener" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hinoirisetr" version = "0.4.0" dependencies = [ "libloading", - "smol", + "tokio", ] [[package]] @@ -267,16 +75,39 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.4.15" +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "parking" -version = "2.2.1" +name = "miniz_oxide" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] [[package]] name = "pin-project-lite" @@ -285,43 +116,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] -name = "piper" -version = "0.2.4" +name = "proc-macro2" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", + "unicode-ident", ] [[package]] -name = "polling" -version = "3.7.4" +name = "quote" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys", + "proc-macro2", ] [[package]] -name = "rustix" -version = "0.38.44" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "signal-hook-registry" @@ -333,52 +149,71 @@ dependencies = [ ] [[package]] -name = "slab" -version = "0.4.9" +name = "socket2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ - "autocfg", + "libc", + "windows-sys", ] [[package]] -name = "smol" -version = "2.0.2" +name = "syn" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ - "async-channel", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-net", - "async-process", - "blocking", - "futures-lite", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "tracing" -version = "0.1.41" +name = "tokio" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", "pin-project-lite", - "tracing-core", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", ] [[package]] -name = "tracing-core" -version = "0.1.33" +name = "tokio-macros" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] diff --git a/Cargo.toml b/Cargo.toml index 6714853..2418e24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,14 +12,13 @@ edition = "2024" [dependencies] libloading = "0.8.6" -smol = "2.0.2" +tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time","io-util","net","signal" ] } [profile.release] strip = true lto = true codegen-units = 1 opt-level = "s" -panic = "abort" [profile.release.package."*"] opt-level = "z" diff --git a/src/main.rs b/src/main.rs index 66275cf..a3c8802 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,14 +8,14 @@ use std::time::{Duration, UNIX_EPOCH}; use hinoirisetr::notify::InitializedNotificationSystem; use hinoirisetr::time::Time; use hinoirisetr::{ - apply_settings, compute_settings, debug, error, info, trace, warn, Config, GammaBackend, TempBackend + Config, GammaBackend, TempBackend, apply_settings, compute_settings, debug, error, info, trace, + warn, }; -use smol::Timer; -use smol::channel::{Sender, unbounded}; -use smol::io::{AsyncBufReadExt, BufReader}; -use smol::lock::{RwLock, RwLockReadGuard}; -use smol::net::unix::UnixListener; -use smol::stream::StreamExt; +use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; +use tokio::net::UnixListener; +use tokio::signal::unix::{SignalKind, signal}; +use tokio::sync::{Notify, RwLock, RwLockReadGuard}; +use tokio::time::sleep; const SOCKET_PATH: &str = "/tmp/hinoirisetr.sock"; @@ -27,7 +27,7 @@ enum NotifyState { Disabled, } -async fn config_realoader(notify: Arc>) { +async fn config_reloader(notify: Arc) { debug!("config reloader started"); // Config polling every 5 seconds loop { @@ -53,11 +53,11 @@ async fn config_realoader(notify: Arc>) { } } } - Timer::after(Duration::from_secs(5)).await; + sleep(Duration::from_secs(5)).await; } } -async fn socket_server(disabled: Arc, notify: Arc>) { +async fn socket_server(disabled: Arc, notify: Arc) { let listener = UnixListener::bind(SOCKET_PATH).expect("Failed to bind socket"); trace!("socket server bound"); let notification: NotifyState = @@ -70,31 +70,31 @@ async fn socket_server(disabled: Arc, notify: Arc>) { }; loop { - let (stream, _) = listener.accept().await.unwrap(); - let reader = BufReader::new(stream); - let mut lines = reader.lines(); + let (mut stream, _) = listener.accept().await.unwrap(); + let (reader, mut writer) = stream.split(); + let mut lines = BufReader::new(reader).lines(); trace!("socket server accepted connection"); - if let Some(Ok(line)) = lines.next().await { + if let Ok(Some(line)) = lines.next_line().await { match line.trim() { "disable" => { trace!("disable dispatched"); disabled.store(true, Ordering::SeqCst); - let _ = notify.send(()).await; + notify.notify_one(); debug!("dimming is disabled"); } "enable" => { trace!("enable dispatched"); disabled.store(false, Ordering::SeqCst); - let _ = notify.send(()).await; + notify.notify_one(); debug!("dimming is enabled"); } "toggle" => { trace!("toggle dispatched"); let now = !disabled.load(Ordering::SeqCst); disabled.store(now, Ordering::SeqCst); - let _ = notify.send(()).await; + notify.notify_one(); debug!("dimming is {}", if now { "enabled" } else { "disabled" }); } "status" => { @@ -102,9 +102,8 @@ async fn socket_server(disabled: Arc, notify: Arc>) { // compute current temp/gamma let now = get_time(); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); - - info!( - "dimming is {} — temp: {}K, gamma: {}%", + let status = format!( + "dimming is {} - temp: {}K, gamma: {}%", if disabled.load(Ordering::SeqCst) { "disabled" } else { @@ -113,6 +112,14 @@ async fn socket_server(disabled: Arc, notify: Arc>) { cur_temp, cur_gamma ); + + if let Err(e) = writer.write(status.as_bytes()).await { + error!("Failed to write to socket: {e}"); + } else { + trace!("status written to socket"); + } + + info!("{}", status); } "reload" => { trace!("reload dispatched"); @@ -154,7 +161,8 @@ async fn socket_server(disabled: Arc, notify: Arc>) { } } -fn main() { +#[tokio::main] +async fn main() { let args: Vec = std::env::args().collect(); if args.len() > 1 && (args[1] == "--version" || args[1] == "-v") { @@ -162,169 +170,165 @@ fn main() { return; } - smol::block_on(async { - match env::var("RUST_LOG") { - Ok(val) => match val.parse::() { - Ok(level) => hinoirisetr::log::set_log_level(level), - Err(err) => error!("Failed to parse RUST_LOG: {err}"), - }, - Err(_) => { - if cfg!(debug_assertions) { - hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Debug); - } else { - hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Info); - } - } - } - - info!("starting the daemon"); - - if !is_binary_available("hyprctl") { - error!("hyprctl is not available, exiting."); - std::process::exit(1); - } - - let disabled = Arc::new(AtomicBool::new(false)); - let (notify_s, notify_r) = unbounded::<()>(); - let notify = Arc::new(notify_s); - - // load config - let config_path = get_config_path(); - let cfg: Config = if config_path.exists() { - debug!("Config file found, loading..."); - LAST_MODIFIED.store( - std::fs::metadata(&config_path) - .and_then(|m| m.modified()) - .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) - .unwrap_or(0), - SeqCst, - ); - match Config::load(&config_path) { - Ok(cfg) => cfg, - Err(err) => { - error!("Failed to load config: {err:?}"); - warn!("Using default config."); - Config::default() - } - } - } else { - warn!("Config file not found, using default config."); - warn!("Config path {}", get_config_path().display()); - Config::default() - }; - - // TODO: add a map to not check for binaries twice? - match cfg.gamma_backend { - GammaBackend::Hyprctl => check_binary("hyprctl"), - GammaBackend::Ddcutil => check_binary("ddcutil"), - GammaBackend::Xsct => check_binary("xsct"), - GammaBackend::Redshift => check_binary("redshift"), - GammaBackend::Gammastep => check_binary("gammastep"), - GammaBackend::None => {} - } - - match cfg.temp_backend { - TempBackend::Hyprctl => check_binary("hyprctl"), - TempBackend::Gammastep => check_binary("gammastep"), - TempBackend::Xsct => check_binary("xsct"), - TempBackend::Redshift => check_binary("redshift"), - TempBackend::None => {} - } - - CONFIG.set(Arc::new(RwLock::new(cfg))).unwrap(); - - if std::path::Path::new(SOCKET_PATH).exists() { - match std::os::unix::net::UnixStream::connect(SOCKET_PATH) { - Ok(_) => { - error!("Another instance is running."); - std::process::exit(1); - } - Err(_) => { - warn!("Stale socket found, removing."); - let _ = std::fs::remove_file(SOCKET_PATH); - } - } - } - - // Spawn control socket server - { - let disabled = Arc::clone(&disabled); - let notify = Arc::clone(¬ify); - smol::spawn(async move { - socket_server(disabled, notify).await; - }) - .detach(); - } - - // Spawn config reloader - { - let notify = Arc::clone(¬ify); - smol::spawn(async move { - config_realoader(notify).await; - }) - .detach(); - } - - // Spawn timer - { - let notify = Arc::clone(¬ify); - smol::spawn(async move { - loop { - Timer::after(Duration::from_secs(300)).await; - let _ = notify.send(()).await; - } - }) - .detach(); - } - - // Signal handling - // let mut sigint = signal(SignalKind::interrupt()).unwrap(); - // let mut sigterm = signal(SignalKind::terminate()).unwrap(); - - // set initial settings - { - let now = get_time(); - let (temp, gamma) = compute_settings(now, &*config_guard().await); - apply_settings(temp, gamma, &*config_guard().await); - trace!("initial settings applied: {temp}K, {gamma}%"); - } - - // Main loop with shutdown support - loop { - if disabled.load(Ordering::SeqCst) { - apply_settings( - config_guard().await.temp_day, - config_guard().await.gamma_day, - &*config_guard().await, - ); + match env::var("RUST_LOG") { + Ok(val) => match val.parse::() { + Ok(level) => hinoirisetr::log::set_log_level(level), + Err(err) => error!("Failed to parse RUST_LOG: {err}"), + }, + Err(_) => { + if cfg!(debug_assertions) { + hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Debug); } else { - let now = get_time(); - let (temp, gamma) = compute_settings(now, &*config_guard().await); - apply_settings(temp, gamma, &*config_guard().await); + hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Info); } - - let _ = notify_r.recv().await; } - // _ = sigint.recv() => { - // info!("Received SIGINT, shutting down..."); - // }, - // _ = sigterm.recv() => { - // info!("Received SIGTERM, shutting down..."); - // }, - // } + } - // Cleanup the socket file on shutdown - // if std::path::Path::new(SOCKET_PATH).exists() { - // match std::fs::remove_file(SOCKET_PATH) { - // Ok(_) => info!("Socket file {SOCKET_PATH} removed."), - // Err(e) => warn!("Failed to remove socket file {SOCKET_PATH}: {e}"), - // } - // } - }) + info!("starting the daemon"); + + if !is_binary_available("hyprctl") { + error!("hyprctl is not available, exiting."); + std::process::exit(1); + } + + let disabled = Arc::new(AtomicBool::new(false)); + let notify = Arc::new(Notify::new()); + + // load config + let config_path = get_config_path(); + let cfg: Config = if config_path.exists() { + debug!("Config file found, loading..."); + LAST_MODIFIED.store( + std::fs::metadata(&config_path) + .and_then(|m| m.modified()) + .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) + .unwrap_or(0), + SeqCst, + ); + match Config::load(&config_path) { + Ok(cfg) => cfg, + Err(err) => { + error!("Failed to load config: {err:?}"); + warn!("Using default config."); + Config::default() + } + } + } else { + warn!("Config file not found, using default config."); + warn!("Config path {}", get_config_path().display()); + Config::default() + }; + + // TODO: add a map to not check for binaries twice? + match cfg.gamma_backend { + GammaBackend::Hyprctl => check_binary("hyprctl"), + GammaBackend::Ddcutil => check_binary("ddcutil"), + GammaBackend::Xsct => check_binary("xsct"), + GammaBackend::Redshift => check_binary("redshift"), + GammaBackend::Gammastep => check_binary("gammastep"), + GammaBackend::None => {} + } + + match cfg.temp_backend { + TempBackend::Hyprctl => check_binary("hyprctl"), + TempBackend::Gammastep => check_binary("gammastep"), + TempBackend::Xsct => check_binary("xsct"), + TempBackend::Redshift => check_binary("redshift"), + TempBackend::None => {} + } + + CONFIG.set(Arc::new(RwLock::new(cfg))).unwrap(); + + if std::path::Path::new(SOCKET_PATH).exists() { + match std::os::unix::net::UnixStream::connect(SOCKET_PATH) { + Ok(_) => { + error!("Another instance is running."); + std::process::exit(1); + } + Err(_) => { + warn!("Stale socket found, removing."); + let _ = std::fs::remove_file(SOCKET_PATH); + } + } + } + + // Spawn control socket server + { + let disabled = Arc::clone(&disabled); + let notify = Arc::clone(¬ify); + tokio::spawn(async move { + socket_server(disabled, notify).await; + }); + } + + // Spawn config reloader + { + let notify = Arc::clone(¬ify); + tokio::spawn(async move { + config_reloader(notify).await; + }); + } + + // Spawn timer + { + let notify = Arc::clone(¬ify); + tokio::spawn(async move { + loop { + sleep(Duration::from_secs(300)).await; + notify.notify_one(); + } + }); + } + + // Signal handling + let mut sigint = signal(SignalKind::interrupt()).unwrap(); + let mut sigterm = signal(SignalKind::terminate()).unwrap(); + + // set initial settings + { + let now = get_time(); + let (temp, gamma) = compute_settings(now, &*config_guard().await); + apply_settings(temp, gamma, &*config_guard().await); + trace!("initial settings applied: {temp}K, {gamma}%"); + } + + // Main loop with shutdown support + tokio::select! { + _ = async { + loop { + if disabled.load(Ordering::SeqCst) { + apply_settings( + config_guard().await.temp_day, + config_guard().await.gamma_day, + &*config_guard().await, + ); + } else { + let now = get_time(); + let (temp, gamma) = compute_settings(now, &*config_guard().await); + apply_settings(temp, gamma, &*config_guard().await); + } + + notify.notified().await; + }} => {}, + _ = sigint.recv() => { + info!("Received SIGINT, shutting down..."); + }, + _ = sigterm.recv() => { + info!("Received SIGTERM, shutting down..."); + }, + } + + // Cleanup the socket file on shutdown + if std::path::Path::new(SOCKET_PATH).exists() { + match std::fs::remove_file(SOCKET_PATH) { + Ok(_) => info!("Socket file {SOCKET_PATH} removed."), + Err(e) => warn!("Failed to remove socket file {SOCKET_PATH}: {e}"), + } + } } // Function to handle config reloading -async fn reload_config(notify: Arc>) { +async fn reload_config(notify: Arc) { trace!("reload_config called"); let config_handle = config_handle(); let mut config = config_handle.write().await; @@ -341,7 +345,7 @@ async fn reload_config(notify: Arc>) { .unwrap_or(0); trace!("new_modified: {new_modified:?}"); LAST_MODIFIED.store(new_modified, SeqCst); - let _ = notify.send(()).await; + notify.notify_one(); } Err(err) => { error!("Failed to reload config: {err:?}");