feat: get rid of chrono

This commit is contained in:
Vladimir Rubin 2025-04-27 00:06:21 +03:00
parent 709c9a81e0
commit 69f7c8c05f
Signed by: vavakado
GPG key ID: CAB744727F36B524
6 changed files with 190 additions and 221 deletions

149
Cargo.lock generated
View file

@ -17,21 +17,6 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 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]] [[package]]
name = "async-broadcast" name = "async-broadcast"
version = "0.7.2" version = "0.7.2"
@ -230,12 +215,6 @@ dependencies = [
"piper", "piper",
] ]
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.10.1" version = "1.10.1"
@ -263,20 +242,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 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]] [[package]]
name = "concurrent-queue" name = "concurrent-queue"
version = "2.5.0" version = "2.5.0"
@ -286,12 +251,6 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.21" version = "0.8.21"
@ -452,37 +411,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
name = "hinoirisetr" name = "hinoirisetr"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono",
"notify-rust", "notify-rust",
"serde", "serde",
"tokio", "tokio",
"toml", "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]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.9.0" version = "2.9.0"
@ -493,16 +427,6 @@ dependencies = [
"hashbrown", "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]] [[package]]
name = "libc" name = "libc"
version = "0.2.172" version = "0.2.172"
@ -607,15 +531,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 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]] [[package]]
name = "objc2" name = "objc2"
version = "0.6.1" version = "0.6.1"
@ -798,12 +713,6 @@ dependencies = [
"windows-sys 0.59.0", "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]] [[package]]
name = "serde" name = "serde"
version = "1.0.219" version = "1.0.219"
@ -1084,64 +993,6 @@ dependencies = [
"wit-bindgen-rt", "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]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View file

@ -4,7 +4,6 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
chrono = "0.4.40"
notify-rust = "4.11.7" notify-rust = "4.11.7"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.8" toml = "0.8"

View file

@ -5,10 +5,11 @@ use std::fs;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use chrono::{DateTime, Local, Timelike};
use serde::Deserialize; use serde::Deserialize;
use time::Time;
pub mod log; pub mod log;
pub mod time;
#[derive(Debug, Deserialize, Copy, Clone)] #[derive(Debug, Deserialize, Copy, Clone)]
#[serde(default)] #[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 /// Compute current temperature and gamma based on provided time
pub fn compute_settings(now: DateTime<Local>, config: &Config) -> (u16, u16) { pub fn compute_settings(now: Time, config: &Config) -> (u16, u16) {
trace!("compute_settings({now:?})"); trace!("compute_settings({now:?})");
let time_in_hours = now.hour() as f64 + now.minute() as f64 / 60.0; let time_in_hours = now.hour() as f64 + now.minute() as f64 / 60.0;
trace!("time_in_hours: {time_in_hours}"); trace!("time_in_hours: {time_in_hours}");

View file

@ -1,6 +1,7 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::str::FromStr;
use std::sync::atomic::{AtomicU8, Ordering}; use std::sync::atomic::{AtomicU8, Ordering};
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::SystemTime;
/// Levels of logging verbosity /// Levels of logging verbosity
#[derive(PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Copy)] #[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); 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 /// Set the global log level at runtime
pub fn set_log_level(level: LogLevel) { pub fn set_log_level(level: LogLevel) {
GLOBAL_LOG_LEVEL.store(level as u8, Ordering::Relaxed); 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<Self, Self::Err> {
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 { impl Display for LogLevel {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// ANSI color codes for terminal output // ANSI color codes for terminal output
@ -104,12 +71,17 @@ impl Display for LogLevel {
#[doc(hidden)] #[doc(hidden)]
pub fn log_internal(level: LogLevel, file: &str, line: u32, msg: &str) { pub fn log_internal(level: LogLevel, file: &str, line: u32, msg: &str) {
if (level as u8) <= (get_log_level() as u8) { if (level as u8) <= (get_log_level() as u8) {
let timestamp = format_timestamp( // Get current time in seconds since Unix epoch
SystemTime::now() let now = SystemTime::now();
.duration_since(UNIX_EPOCH)
.unwrap() let timestamp = match crate::time::Time::try_from(now) {
.as_secs(), Ok(time) => time.format_time(),
); Err(err) => {
eprintln!("Failed to get local time: {err:?}");
"????-??-?? ??:??:??".to_string()
}
};
if level == LogLevel::Trace { if level == LogLevel::Trace {
println!("{} |{timestamp}| {file}:{line} - {msg}", LogLevel::Trace); println!("{} |{timestamp}| {file}:{line} - {msg}", LogLevel::Trace);
} else { } else {

View file

@ -4,8 +4,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock};
use std::time::Duration; use std::time::Duration;
use chrono::Local; use hinoirisetr::time::Time;
use hinoirisetr::{apply_settings, compute_settings, debug, error, info, trace, warn, Config}; use hinoirisetr::{Config, apply_settings, compute_settings, debug, error, info, trace, warn};
use notify_rust::Notification; use notify_rust::Notification;
use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::net::UnixListener; use tokio::net::UnixListener;
@ -51,7 +51,7 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
"status" => { "status" => {
trace!("status dispatched"); trace!("status dispatched");
// compute current temp/gamma // compute current temp/gamma
let now = Local::now(); let now = get_time();
let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await);
info!( info!(
@ -67,7 +67,7 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
} }
"status_notify" => { "status_notify" => {
trace!("status_notify dispatched"); trace!("status_notify dispatched");
let now = Local::now(); let now = get_time();
let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await); let (cur_temp, cur_gamma) = compute_settings(now, &*config_guard().await);
let body = if disabled.load(Ordering::SeqCst) { let body = if disabled.load(Ordering::SeqCst) {
@ -99,13 +99,21 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
info!("starting the daemon"); match env::var("RUST_LOG") {
warn!("log level: {:?}", hinoirisetr::log::get_log_level()); Ok(val) => match val.parse::<hinoirisetr::log::LogLevel>() {
error!("log level: {:?}", hinoirisetr::log::get_log_level()); Ok(level) => hinoirisetr::log::set_log_level(level),
trace!("log level: {:?}", hinoirisetr::log::get_log_level()); Err(err) => error!("Failed to parse RUST_LOG: {err}"),
debug!("log level: {:?}", hinoirisetr::log::get_log_level()); },
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") { if !is_binary_available("hyprctl") {
error!("hyprctl is not available, exiting."); error!("hyprctl is not available, exiting.");
@ -161,7 +169,7 @@ async fn main() {
// set initial settings // set initial settings
{ {
let now = Local::now(); let now = get_time();
let (temp, gamma) = compute_settings(now, &*config_guard().await); let (temp, gamma) = compute_settings(now, &*config_guard().await);
apply_settings(temp, gamma); apply_settings(temp, gamma);
trace!("initial settings applied: {temp}K, {gamma}%"); trace!("initial settings applied: {temp}K, {gamma}%");
@ -174,7 +182,7 @@ async fn main() {
if disabled.load(Ordering::SeqCst) { if disabled.load(Ordering::SeqCst) {
apply_settings(config_guard().await.temp_day, config_guard().await.gamma_day); apply_settings(config_guard().await.temp_day, config_guard().await.gamma_day);
} else { } else {
let now = Local::now(); let now = get_time();
let (temp, gamma) = compute_settings(now,&*config_guard().await); let (temp, gamma) = compute_settings(now,&*config_guard().await);
apply_settings(temp, gamma); apply_settings(temp, gamma);
} }
@ -207,7 +215,11 @@ fn is_binary_available(binary_name: &str) -> bool {
if let Ok(paths) = env::var("PATH") { if let Ok(paths) = env::var("PATH") {
for path in env::split_paths(&paths) { for path in env::split_paths(&paths) {
let full_path = path.join(binary_name); 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; 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; // let lock = CONFIG.get().expect("config not initialized").read().await;
// lock.clone() // lock.clone()
// } // }
fn get_time() -> Time {
Time::now().expect("Failed to get local time")
}

130
src/time.rs Normal file
View file

@ -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<Self, TimeError> {
let now = SystemTime::now();
Time::try_from(now)
}
/// seconds: seconds since epoch
pub fn new(seconds: i64) -> Result<Self, TimeError> {
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<SystemTime> for Time {
type Error = TimeError; // Define an appropriate error type
fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
let seconds = time.duration_since(UNIX_EPOCH)?.as_secs() as i64;
Time::new(seconds)
}
}
impl From<Tm> 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<std::time::SystemTimeError> for TimeError {
fn from(err: std::time::SystemTimeError) -> Self {
TimeError::SystemTimeError(err)
}
}