diff --git a/Cargo.lock b/Cargo.lock index 078be3c..520b0b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,40 +3,155 @@ version = 4 [[package]] -name = "addr2line" -version = "0.24.2" +name = "async-channel" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ - "gimli", + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", ] [[package]] -name = "adler2" +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" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", + "async-io", + "blocking", + "futures-lite", ] [[package]] -name = "bytes" -version = "1.10.1" +name = "async-process" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +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", +] [[package]] name = "cfg-if" @@ -45,17 +160,94 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "gimli" -version = "0.31.1" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +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" [[package]] name = "hinoirisetr" version = "0.2.0" dependencies = [ "libloading", - "tokio", + "smol", ] [[package]] @@ -75,39 +267,16 @@ dependencies = [ ] [[package]] -name = "memchr" -version = "2.7.4" +name = "linux-raw-sys" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] -name = "miniz_oxide" -version = "0.8.8" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -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", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "pin-project-lite" @@ -116,28 +285,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] -name = "proc-macro2" -version = "1.0.95" +name = "piper" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ - "unicode-ident", + "atomic-waker", + "fastrand", + "futures-io", ] [[package]] -name = "quote" -version = "1.0.40" +name = "polling" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ - "proc-macro2", + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys", ] [[package]] -name = "rustc-demangle" -version = "0.1.24" +name = "rustix" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] [[package]] name = "signal-hook-registry" @@ -149,71 +333,52 @@ dependencies = [ ] [[package]] -name = "socket2" -version = "0.5.9" +name = "slab" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ - "libc", - "windows-sys", + "autocfg", ] [[package]] -name = "syn" -version = "2.0.100" +name = "smol" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", ] [[package]] -name = "tokio" -version = "1.44.2" +name = "tracing" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", + "tracing-core", ] [[package]] -name = "tokio-macros" -version = "2.5.0" +name = "tracing-core" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -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" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] diff --git a/Cargo.toml b/Cargo.toml index eed32fc..fa5c574 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2024" [dependencies] libloading = "0.8.6" -tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time","io-util","net","signal" ] } +smol = "2.0.2" [profile.release] strip = true diff --git a/src/main.rs b/src/main.rs index 4b9e8f1..5e8bde1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,31 @@ use std::env; use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::Ordering::SeqCst; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::{Duration, UNIX_EPOCH}; use hinoirisetr::notify::InitializedNotificationSystem; use hinoirisetr::time::Time; use hinoirisetr::{Config, apply_settings, compute_settings, debug, error, info, trace, warn}; -use tokio::io::{AsyncBufReadExt, BufReader}; -use tokio::net::UnixListener; -use tokio::signal::unix::{SignalKind, signal}; -use tokio::sync::{Notify, RwLock}; -use tokio::time::sleep; +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; const SOCKET_PATH: &str = "/tmp/hinoirisetr.sock"; static CONFIG: OnceLock>> = OnceLock::new(); -static LAST_MODIFIED: OnceLock>>> = OnceLock::new(); +static LAST_MODIFIED: OnceLock> = OnceLock::new(); enum NotifyState { Enabled(InitializedNotificationSystem), Disabled, } -async fn config_realoader(notify: Arc) { +async fn config_realoader(notify: Arc>) { debug!("config reloader started"); // Config polling every 5 seconds loop { @@ -31,12 +33,12 @@ async fn config_realoader(notify: Arc) { let config_path = get_config_path(); if config_path.exists() { let last_modified = LAST_MODIFIED.get().expect("last_modified not init"); - let last_modified_guard = last_modified.read().await; if let Ok(current_modified) = std::fs::metadata(&config_path) .and_then(|m| m.modified()) .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) { - if let Some(last) = *last_modified_guard { + let last: u64 = last_modified.load(Ordering::SeqCst); + if 0 != last { if current_modified > last { trace!("{current_modified}"); trace!("{last}"); @@ -50,11 +52,11 @@ async fn config_realoader(notify: Arc) { } } } - sleep(Duration::from_secs(5)).await; + Timer::after(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 = @@ -68,29 +70,30 @@ async fn socket_server(disabled: Arc, notify: Arc) { loop { let (stream, _) = listener.accept().await.unwrap(); - let mut lines = BufReader::new(stream).lines(); + let reader = BufReader::new(stream); + let mut lines = reader.lines(); trace!("socket server accepted connection"); - if let Ok(Some(line)) = lines.next_line().await { + if let Some(Ok(line)) = lines.next().await { match line.trim() { "disable" => { trace!("disable dispatched"); disabled.store(true, Ordering::SeqCst); - notify.notify_one(); + let _ = notify.send(()).await; debug!("dimming is disabled"); } "enable" => { trace!("enable dispatched"); disabled.store(false, Ordering::SeqCst); - notify.notify_one(); + let _ = notify.send(()).await; debug!("dimming is enabled"); } "toggle" => { trace!("toggle dispatched"); let now = !disabled.load(Ordering::SeqCst); disabled.store(now, Ordering::SeqCst); - notify.notify_one(); + let _ = notify.send(()).await; debug!("dimming is {}", if now { "enabled" } else { "disabled" }); } "status" => { @@ -128,7 +131,7 @@ async fn socket_server(disabled: Arc, notify: Arc) { match notification { NotifyState::Enabled(ref not) => { trace!("notify notification enabled"); - let timeout = config_handle().read().await.notification_timeout; + let timeout = config_guard().await.notification_timeout; match not.show_notification( "Sunsetting", &body, @@ -150,139 +153,152 @@ async fn socket_server(disabled: Arc, notify: Arc) { } } -#[tokio::main] -async fn main() { - 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 = 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 - .set(Arc::new(RwLock::new( - std::fs::metadata(&config_path) - .and_then(|m| m.modified()) - .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) - .ok(), - ))) - .unwrap(); - 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() - }; - - 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); - } +fn main() { + 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(_) => { - 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_realoader(notify).await; - }); - } - - // 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); - 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); + 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); - } - - tokio::select! { - _ = sleep(Duration::from_secs(300)) => {trace!("main loop tick");}, - _ = notify.notified() => {trace!("main loop woke up via notify");}, + hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Info); } } - } => {}, - _ = 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_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 + .set(Arc::new(AtomicU64::new( + std::fs::metadata(&config_path) + .and_then(|m| m.modified()) + .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) + .unwrap_or(0), + ))) + .unwrap(); + 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() + }; + + 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); + 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, + ); + } else { + let now = get_time(); + let (temp, gamma) = compute_settings(now, &*config_guard().await); + apply_settings(temp, gamma); + } + + 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}"), + // } + // } + }) } // 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; @@ -293,18 +309,18 @@ async fn reload_config(notify: Arc) { *config = cfg; trace!("new config: {:#?}", config); - let last_modified = LAST_MODIFIED.get().expect("last_modified not init"); - let mut last_modified = last_modified.write().await; - tokio::task::spawn_blocking(move || { - let new_modified = std::fs::metadata(&config_path) - .and_then(|m| m.modified()) - .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) - .ok(); - trace!("last_modified: {last_modified:?}"); - trace!("new_modified: {new_modified:?}"); - *last_modified = new_modified; - }); - notify.notify_one(); + // let mut last_modified = LAST_MODIFIED.get().expect("last_modified not init").clone(); + let new_modified = std::fs::metadata(&config_path) + .and_then(|m| m.modified()) + .map(|t| t.duration_since(UNIX_EPOCH).unwrap().as_secs()) + .unwrap_or(0); + trace!("new_modified: {new_modified:?}"); + LAST_MODIFIED + .get() + .expect("last_modified not init") + .store(new_modified, SeqCst); + // last_modified = new_modified.into(); + let _ = notify.send(()).await; } Err(err) => { error!("Failed to reload config: {err:?}"); @@ -348,7 +364,7 @@ fn get_config_path() -> PathBuf { } } -async fn config_guard() -> tokio::sync::RwLockReadGuard<'static, Config> { +async fn config_guard() -> RwLockReadGuard<'static, Config> { CONFIG.get().expect("config not init").read().await }