From 69f7c8c05fce89251338b7e633c46e905f6a3ab1 Mon Sep 17 00:00:00 2001 From: Vladimir Rubin Date: Sun, 27 Apr 2025 00:06:21 +0300 Subject: [PATCH] feat: get rid of chrono --- Cargo.lock | 149 ---------------------------------------------------- Cargo.toml | 1 - src/lib.rs | 5 +- src/log.rs | 84 ++++++++++------------------- src/main.rs | 42 ++++++++++----- src/time.rs | 130 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 190 insertions(+), 221 deletions(-) create mode 100644 src/time.rs diff --git a/Cargo.lock b/Cargo.lock index b0a9e39..684a1b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,21 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "async-broadcast" version = "0.7.2" @@ -230,12 +215,6 @@ dependencies = [ "piper", ] -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - [[package]] name = "bytes" version = "1.10.1" @@ -263,20 +242,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chrono" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "concurrent-queue" version = "2.5.0" @@ -286,12 +251,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -452,37 +411,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" name = "hinoirisetr" version = "0.1.0" dependencies = [ - "chrono", "notify-rust", "serde", "tokio", "toml", ] -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "indexmap" version = "2.9.0" @@ -493,16 +427,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - [[package]] name = "libc" version = "0.2.172" @@ -607,15 +531,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "objc2" version = "0.6.1" @@ -798,12 +713,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - [[package]] name = "serde" version = "1.0.219" @@ -1084,64 +993,6 @@ dependencies = [ "wit-bindgen-rt", ] -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index d0a0041..bab445b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] -chrono = "0.4.40" notify-rust = "4.11.7" serde = { version = "1.0", features = ["derive"] } toml = "0.8" diff --git a/src/lib.rs b/src/lib.rs index 1b26164..5741c24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,10 +5,11 @@ use std::fs; use std::path::Path; use std::process::Command; -use chrono::{DateTime, Local, Timelike}; use serde::Deserialize; +use time::Time; pub mod log; +pub mod time; #[derive(Debug, Deserialize, Copy, Clone)] #[serde(default)] @@ -65,7 +66,7 @@ pub fn interpolate(start: u16, end: u16, factor: f64) -> u16 { } /// Compute current temperature and gamma based on provided time -pub fn compute_settings(now: DateTime, config: &Config) -> (u16, u16) { +pub fn compute_settings(now: Time, config: &Config) -> (u16, u16) { trace!("compute_settings({now:?})"); let time_in_hours = now.hour() as f64 + now.minute() as f64 / 60.0; trace!("time_in_hours: {time_in_hours}"); diff --git a/src/log.rs b/src/log.rs index 5e66675..2949003 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,6 +1,7 @@ use std::fmt::{Display, Formatter}; +use std::str::FromStr; use std::sync::atomic::{AtomicU8, Ordering}; -use std::time::{SystemTime, UNIX_EPOCH}; +use std::time::SystemTime; /// Levels of logging verbosity #[derive(PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Copy)] @@ -14,55 +15,6 @@ pub enum LogLevel { static GLOBAL_LOG_LEVEL: AtomicU8 = AtomicU8::new(LogLevel::Info as u8); -// Check if a year is a leap year -fn is_leap_year(year: u32) -> bool { - (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) -} - -// Convert seconds since epoch to YYYY-MM-DD HH:MM:SS (UTC) -fn format_timestamp(seconds: u64) -> String { - let mut days = (seconds / 86_400) as u32; // Total days since epoch - let seconds_in_day = (seconds % 86_400) as u32; - let hours = seconds_in_day / 3600; - let minutes = (seconds_in_day % 3600) / 60; - let seconds = seconds_in_day % 60; - - // Calculate year - let mut year = 1970; - while days > 0 { - let days_in_year = if is_leap_year(year) { 366 } else { 365 }; - if days >= days_in_year { - days -= days_in_year; - year += 1; - } else { - break; - } - } - - // Month lengths (non-leap and leap year variants) - let month_lengths = if is_leap_year(year) { - [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - } else { - [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - }; - - // Calculate month and day - let mut month = 1; - for &len in month_lengths.iter() { - if days < len { - break; - } - days -= len; - month += 1; - } - let day = days + 1; // Days are 1-based - - format!( - "{:04}-{:02}-{:02} {:02}:{:02}:{:02}", - year, month, day, hours, minutes, seconds - ) -} - /// Set the global log level at runtime pub fn set_log_level(level: LogLevel) { GLOBAL_LOG_LEVEL.store(level as u8, Ordering::Relaxed); @@ -80,6 +32,21 @@ pub fn get_log_level() -> LogLevel { } } +impl FromStr for LogLevel { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "error" => Ok(LogLevel::Error), + "warn" => Ok(LogLevel::Warn), + "info" => Ok(LogLevel::Info), + "debug" => Ok(LogLevel::Debug), + "trace" => Ok(LogLevel::Trace), + _ => Err(format!("Invalid log level: {s}")), + } + } +} + impl Display for LogLevel { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { // ANSI color codes for terminal output @@ -104,12 +71,17 @@ impl Display for LogLevel { #[doc(hidden)] pub fn log_internal(level: LogLevel, file: &str, line: u32, msg: &str) { if (level as u8) <= (get_log_level() as u8) { - let timestamp = format_timestamp( - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - ); + // Get current time in seconds since Unix epoch + let now = SystemTime::now(); + + let timestamp = match crate::time::Time::try_from(now) { + Ok(time) => time.format_time(), + Err(err) => { + eprintln!("Failed to get local time: {err:?}"); + "????-??-?? ??:??:??".to_string() + } + }; + if level == LogLevel::Trace { println!("{} |{timestamp}| {file}:{line} - {msg}", LogLevel::Trace); } else { diff --git a/src/main.rs b/src/main.rs index dd5a432..2e04d76 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,8 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::Duration; -use chrono::Local; -use hinoirisetr::{apply_settings, compute_settings, debug, error, info, trace, warn, Config}; +use hinoirisetr::time::Time; +use hinoirisetr::{Config, apply_settings, compute_settings, debug, error, info, trace, warn}; use notify_rust::Notification; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::net::UnixListener; @@ -51,7 +51,7 @@ async fn socket_server(disabled: Arc, notify: Arc) { "status" => { trace!("status dispatched"); // compute current temp/gamma - let now = Local::now(); + let now = get_time(); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); info!( @@ -67,7 +67,7 @@ async fn socket_server(disabled: Arc, notify: Arc) { } "status_notify" => { trace!("status_notify dispatched"); - let now = Local::now(); + let now = get_time(); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); let body = if disabled.load(Ordering::SeqCst) { @@ -99,13 +99,21 @@ async fn socket_server(disabled: Arc, notify: Arc) { #[tokio::main] async fn main() { - info!("starting the daemon"); - warn!("log level: {:?}", hinoirisetr::log::get_log_level()); - error!("log level: {:?}", hinoirisetr::log::get_log_level()); - trace!("log level: {:?}", hinoirisetr::log::get_log_level()); - debug!("log level: {:?}", hinoirisetr::log::get_log_level()); + 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::Trace); + } else { + hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Info); + } + } + } - hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Trace); + info!("starting the daemon"); if !is_binary_available("hyprctl") { error!("hyprctl is not available, exiting."); @@ -161,7 +169,7 @@ async fn main() { // set initial settings { - let now = Local::now(); + let now = get_time(); let (temp, gamma) = compute_settings(now, &*config_guard().await); apply_settings(temp, gamma); trace!("initial settings applied: {temp}K, {gamma}%"); @@ -174,7 +182,7 @@ async fn main() { if disabled.load(Ordering::SeqCst) { apply_settings(config_guard().await.temp_day, config_guard().await.gamma_day); } else { - let now = Local::now(); + let now = get_time(); let (temp, gamma) = compute_settings(now,&*config_guard().await); apply_settings(temp, gamma); } @@ -207,7 +215,11 @@ fn is_binary_available(binary_name: &str) -> bool { if let Ok(paths) = env::var("PATH") { for path in env::split_paths(&paths) { let full_path = path.join(binary_name); - if full_path.exists() && fs::metadata(&full_path).map(|m| m.is_file()).unwrap_or(false) { + if full_path.exists() + && fs::metadata(&full_path) + .map(|m| m.is_file()) + .unwrap_or(false) + { return true; } } @@ -246,3 +258,7 @@ async fn config_guard() -> tokio::sync::RwLockReadGuard<'static, Config> { // let lock = CONFIG.get().expect("config not initialized").read().await; // lock.clone() // } + +fn get_time() -> Time { + Time::now().expect("Failed to get local time") +} diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000..7d8fa90 --- /dev/null +++ b/src/time.rs @@ -0,0 +1,130 @@ +use std::ffi::c_int; +use std::fmt::{Display, Formatter}; +use std::time::{SystemTime, UNIX_EPOCH}; + +// Convert seconds since epoch to YYYY-MM-DD HH:MM:SS (UTC) +// Define the Tm struct from the C standard library +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct Tm { + tm_sec: c_int, // Seconds (0-60) + tm_min: c_int, // Minutes (0-59) + tm_hour: c_int, // Hours (0-23) + tm_mday: c_int, // Day of the month (1-31) + tm_mon: c_int, // Month (0-11) + tm_year: c_int, // Year since 1900 + tm_wday: c_int, // Day of the week (0-6, Sunday = 0) + tm_yday: c_int, // Day of the year (0-365) + tm_isdst: c_int, // Daylight saving time flag +} + +unsafe extern "C" { + fn localtime_r(timep: *const i64, result: *mut Tm) -> *mut Tm; +} + +#[derive(Debug)] +pub struct Time { + year: i32, + month: i32, + day: i32, + hour: i32, + minute: i32, + second: i32, +} + +impl Time { + pub fn now() -> Result { + let now = SystemTime::now(); + Time::try_from(now) + } + /// seconds: seconds since epoch + pub fn new(seconds: i64) -> Result { + let mut tm: Tm = unsafe { std::mem::zeroed() }; + // Call localtime_r with a pointer to our Tm struct + let result = unsafe { localtime_r(&seconds, &mut tm) }; + + // Check if the conversion was successful + if result.is_null() { + return Err(TimeError::InvalidTime); + } + + Ok(tm.into()) + } + + /// Getter for year + pub fn year(&self) -> i32 { + self.year + } + + /// Getter for month + pub fn month(&self) -> i32 { + self.month + } + + /// Getter for day + pub fn day(&self) -> i32 { + self.day + } + + /// Getter for hour + pub fn hour(&self) -> i32 { + self.hour + } + + /// Getter for minute + pub fn minute(&self) -> i32 { + self.minute + } + + /// Getter for second + pub fn second(&self) -> i32 { + self.second + } + + pub fn format_time(&self) -> String { + format!( + "{:04}-{:02}-{:02} {:02}:{:02}:{:02}", + self.year, self.month, self.day, self.hour, self.minute, self.second + ) + } +} + +impl Display for Time { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.format_time()) + } +} + +impl TryFrom for Time { + type Error = TimeError; // Define an appropriate error type + + fn try_from(time: SystemTime) -> Result { + let seconds = time.duration_since(UNIX_EPOCH)?.as_secs() as i64; + Time::new(seconds) + } +} + +impl From for Time { + fn from(tm: Tm) -> Self { + Self { + year: tm.tm_year + 1900, + month: tm.tm_mon + 1, + day: tm.tm_mday, + hour: tm.tm_hour, + minute: tm.tm_min, + second: tm.tm_sec, + } + } +} + +#[derive(Debug)] +pub enum TimeError { + SystemTimeError(std::time::SystemTimeError), + InvalidTime, +} + +impl From for TimeError { + fn from(err: std::time::SystemTimeError) -> Self { + TimeError::SystemTimeError(err) + } +}