feat: get rid of libnotify
This commit is contained in:
parent
d27e81774f
commit
9e816928af
6 changed files with 256 additions and 1093 deletions
1078
Cargo.lock
generated
1078
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -4,9 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
notify-rust = "4.11.7"
|
libloading = "0.8.6"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
toml = "0.8"
|
|
||||||
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time","io-util","net","signal" ] }
|
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "time","io-util","net","signal" ] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
devShells.default = pkgs.mkShell rec {
|
devShells.default = pkgs.mkShell rec {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
rust
|
rust
|
||||||
|
pkgs.libnotify
|
||||||
];
|
];
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
@ -49,8 +50,12 @@
|
||||||
lockFile = ./Cargo.lock;
|
lockFile = ./Cargo.lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
postFixup = ''
|
||||||
|
patchelf $out/bin/hinoirisetr --add-rpath ${pkgs.libnotify}/lib
|
||||||
|
'';
|
||||||
|
|
||||||
nativeBuildInputs = [ ];
|
nativeBuildInputs = [ ];
|
||||||
buildInputs = [ ];
|
buildInputs = [ pkgs.libnotify ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
63
src/lib.rs
63
src/lib.rs
|
@ -1,18 +1,18 @@
|
||||||
//! hinoirisetr library
|
//! hinoirisetr library
|
||||||
//! Contains core logic for computing temperature and gamma and applying settings.
|
//! Contains core logic for computing temperature and gamma and applying settings.
|
||||||
|
|
||||||
use std::fs;
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use time::Time;
|
use time::Time;
|
||||||
|
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
pub mod notify;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[serde(default)]
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub temp_day: u16,
|
pub temp_day: u16,
|
||||||
pub temp_night: u16,
|
pub temp_night: u16,
|
||||||
|
@ -32,7 +32,7 @@ impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
temp_day: 6500,
|
temp_day: 6500,
|
||||||
temp_night: 2700,
|
temp_night: 2500,
|
||||||
gamma_day: 100,
|
gamma_day: 100,
|
||||||
gamma_night: 95,
|
gamma_night: 95,
|
||||||
sunset_start: 19,
|
sunset_start: 19,
|
||||||
|
@ -49,8 +49,57 @@ impl Config {
|
||||||
path: P,
|
path: P,
|
||||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
trace!("Config::load({path:?})");
|
trace!("Config::load({path:?})");
|
||||||
let content = fs::read_to_string(path)?;
|
let mut config = Self::default(); // Start with default values
|
||||||
let config = toml::from_str(&content)?;
|
|
||||||
|
let config_file = File::open(path)?;
|
||||||
|
let reader = BufReader::new(config_file);
|
||||||
|
let mut current_section = String::new();
|
||||||
|
|
||||||
|
for line in reader
|
||||||
|
.lines()
|
||||||
|
.map_while(Result::ok)
|
||||||
|
.map(|l| String::from(l.trim()))
|
||||||
|
.filter(|l| !l.is_empty())
|
||||||
|
.filter(|l| !l.starts_with('#'))
|
||||||
|
{
|
||||||
|
trace!("line: {line}");
|
||||||
|
if line.starts_with('[') && line.contains(']') {
|
||||||
|
current_section = line[1..line.find(']').unwrap()].to_string();
|
||||||
|
trace!("current_section: {current_section}");
|
||||||
|
} else if let Some((key, value)) = line.split_once('=') {
|
||||||
|
trace!("key: {key}, value: {value}");
|
||||||
|
let key_trimmed_string = key.trim().replace('"', "");
|
||||||
|
let key_trimmed = key_trimmed_string.as_str();
|
||||||
|
|
||||||
|
let value = value.trim().replace('"', "");
|
||||||
|
match current_section.as_str() {
|
||||||
|
"" => {
|
||||||
|
if key_trimmed == "notification_timeout" {
|
||||||
|
config.notification_timeout = value.parse()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"gamma" => match key_trimmed {
|
||||||
|
"day" => config.gamma_day = value.parse()?,
|
||||||
|
"night" => config.gamma_night = value.parse()?,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
"temp" => match key_trimmed {
|
||||||
|
"day" => config.temp_day = value.parse()?,
|
||||||
|
"night" => config.temp_night = value.parse()?,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
"time" => match key_trimmed {
|
||||||
|
"sunset_start" => config.sunset_start = value.parse()?,
|
||||||
|
"sunset_end" => config.sunset_end = value.parse()?,
|
||||||
|
"sunrise_start" => config.sunrise_start = value.parse()?,
|
||||||
|
"sunrise_end" => config.sunrise_end = value.parse()?,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
src/main.rs
53
src/main.rs
|
@ -4,9 +4,9 @@ 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 hinoirisetr::notify::Notification;
|
||||||
use hinoirisetr::time::Time;
|
use hinoirisetr::time::Time;
|
||||||
use hinoirisetr::{Config, apply_settings, compute_settings, debug, error, info, trace, warn};
|
use hinoirisetr::{Config, apply_settings, compute_settings, debug, error, info, trace, warn};
|
||||||
use notify_rust::Notification;
|
|
||||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||||
use tokio::net::UnixListener;
|
use tokio::net::UnixListener;
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
|
@ -17,9 +17,21 @@ const SOCKET_PATH: &str = "/tmp/hinoirisetr.sock";
|
||||||
|
|
||||||
static CONFIG: OnceLock<Arc<RwLock<Config>>> = OnceLock::new();
|
static CONFIG: OnceLock<Arc<RwLock<Config>>> = OnceLock::new();
|
||||||
|
|
||||||
|
enum NotifyState {
|
||||||
|
Enabled(Arc<Notification>),
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
|
async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
|
||||||
let listener = UnixListener::bind(SOCKET_PATH).expect("Failed to bind socket");
|
let listener = UnixListener::bind(SOCKET_PATH).expect("Failed to bind socket");
|
||||||
trace!("socket server bound");
|
trace!("socket server bound");
|
||||||
|
let notification: NotifyState = match unsafe { hinoirisetr::notify::Notification::new() } {
|
||||||
|
Some(not) => NotifyState::Enabled(Arc::new(not)),
|
||||||
|
None => {
|
||||||
|
info!("libnotify not found, disabling 'status_notify' command");
|
||||||
|
NotifyState::Disabled
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (stream, _) = listener.accept().await.unwrap();
|
let (stream, _) = listener.accept().await.unwrap();
|
||||||
|
@ -92,18 +104,31 @@ async fn socket_server(disabled: Arc<AtomicBool>, notify: Arc<Notify>) {
|
||||||
format!("temp: {cur_temp}K, gamma: {cur_gamma}%")
|
format!("temp: {cur_temp}K, gamma: {cur_gamma}%")
|
||||||
};
|
};
|
||||||
|
|
||||||
match Notification::new()
|
match notification {
|
||||||
.summary("Sunsetting")
|
NotifyState::Enabled(ref not) => {
|
||||||
.body(body.as_str())
|
trace!("notify notification enabled");
|
||||||
.timeout(notify_rust::Timeout::Milliseconds(
|
let timeout = config_handle().read().await.notification_timeout;
|
||||||
config_guard().await.notification_timeout,
|
unsafe {
|
||||||
))
|
not.init("hinoirisetr");
|
||||||
.show_async()
|
let local_notification =
|
||||||
.await
|
not.notify_notification_new("Sunsetting", body.as_str(), "");
|
||||||
{
|
not.notify_notification_set_timeout(
|
||||||
Ok(_) => {}
|
local_notification,
|
||||||
Err(err) => {
|
timeout as i32,
|
||||||
error!("Erorr occured while sending a notification: {err}")
|
|
||||||
|
);
|
||||||
|
not.notify_notification_show(
|
||||||
|
not.notify_notification_new(
|
||||||
|
"Sunsetting",
|
||||||
|
body.as_str(),
|
||||||
|
"notification-icon",
|
||||||
|
),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NotifyState::Disabled => {
|
||||||
|
trace!("notify notification disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +147,7 @@ async fn main() {
|
||||||
},
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Trace);
|
hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Debug);
|
||||||
} else {
|
} else {
|
||||||
hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Info);
|
hinoirisetr::log::set_log_level(hinoirisetr::log::LogLevel::Info);
|
||||||
}
|
}
|
||||||
|
|
144
src/notify.rs
Normal file
144
src/notify.rs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
#![allow(clippy::missing_safety_doc)]
|
||||||
|
|
||||||
|
use std::ffi::{CString, c_char, c_void};
|
||||||
|
|
||||||
|
use libloading::os::unix::Symbol as UnixSymbol;
|
||||||
|
use libloading::{Library, Symbol};
|
||||||
|
|
||||||
|
use crate::trace;
|
||||||
|
|
||||||
|
pub struct Notification {
|
||||||
|
_lib: Library, // << keep the library alive
|
||||||
|
notify_init: UnixSymbol<NotifyInit>,
|
||||||
|
notify_uninit: UnixSymbol<NotifyUninit>,
|
||||||
|
notify_notification_new: UnixSymbol<NotifyNotificationNew>,
|
||||||
|
notify_notification_show: UnixSymbol<NotifyNotificationShow>,
|
||||||
|
notify_notification_set_timeout: UnixSymbol<NotifyNotificationSetTimeout>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyInit = unsafe extern "C" fn(*const i8) -> bool;
|
||||||
|
type NotifyUninit = unsafe extern "C" fn();
|
||||||
|
|
||||||
|
type NotifyNotificationNew = unsafe extern "C" fn(
|
||||||
|
summary: *const c_char,
|
||||||
|
body: *const c_char,
|
||||||
|
icon: *const c_char,
|
||||||
|
) -> *mut std::os::raw::c_void;
|
||||||
|
|
||||||
|
type NotifyNotificationShow = unsafe extern "C" fn(
|
||||||
|
*mut c_void, // NotifyNotification*
|
||||||
|
*mut *mut c_void, // GError**
|
||||||
|
) -> i32;
|
||||||
|
|
||||||
|
type NotifyNotificationSetTimeout = unsafe extern "C" fn(
|
||||||
|
notification: *mut std::os::raw::c_void, // NotifyNotification*
|
||||||
|
timeout: i32, // gint
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Notification {
|
||||||
|
/// Try to load `libnotify.so.4` at runtime.
|
||||||
|
pub unsafe fn new() -> Option<Self> {
|
||||||
|
unsafe {
|
||||||
|
let (
|
||||||
|
lib,
|
||||||
|
notify_init,
|
||||||
|
notify_uninit,
|
||||||
|
notify_notification_new,
|
||||||
|
notify_notification_show,
|
||||||
|
notify_notification_set_timeout,
|
||||||
|
) = {
|
||||||
|
// 1) Load the library
|
||||||
|
let lib = Library::new("libnotify.so.4").ok()?;
|
||||||
|
|
||||||
|
// 2) Lookup each symbol into its own local
|
||||||
|
let init_sym: Symbol<NotifyInit> = lib.get(b"notify_init\0").ok()?;
|
||||||
|
let uninit_sym: Symbol<NotifyUninit> = lib.get(b"notify_uninit\0").ok()?;
|
||||||
|
let notify_notification_new_sym: Symbol<NotifyNotificationNew> =
|
||||||
|
lib.get(b"notify_notification_new\0").ok()?;
|
||||||
|
let notify_notification_show_sym: Symbol<NotifyNotificationShow> =
|
||||||
|
lib.get(b"notify_notification_show\0").ok()?;
|
||||||
|
let notify_notification_set_timeout_sym: Symbol<NotifyNotificationSetTimeout> =
|
||||||
|
lib.get(b"notify_notification_set_timeout\0").ok()?;
|
||||||
|
|
||||||
|
// 3) Transmute their lifetimes to 'static now that we own `lib` forever
|
||||||
|
let notify_init = init_sym.into_raw();
|
||||||
|
let notify_uninit = uninit_sym.into_raw();
|
||||||
|
let notify_notification_new = notify_notification_new_sym.into_raw();
|
||||||
|
let notify_notification_show = notify_notification_show_sym.into_raw();
|
||||||
|
let notify_notification_set_timeout =
|
||||||
|
notify_notification_set_timeout_sym.into_raw();
|
||||||
|
|
||||||
|
(
|
||||||
|
lib,
|
||||||
|
notify_init,
|
||||||
|
notify_uninit,
|
||||||
|
notify_notification_new,
|
||||||
|
notify_notification_show,
|
||||||
|
notify_notification_set_timeout,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3) Now that the borrows are done, move `lib` and the symbols into your struct
|
||||||
|
Some(Self {
|
||||||
|
_lib: lib,
|
||||||
|
notify_init,
|
||||||
|
notify_uninit,
|
||||||
|
notify_notification_new,
|
||||||
|
notify_notification_show,
|
||||||
|
notify_notification_set_timeout,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init(&self, app_name: &str) -> bool {
|
||||||
|
unsafe {
|
||||||
|
trace!("Notify::init({app_name:?})");
|
||||||
|
let cstr = CString::new(app_name).unwrap();
|
||||||
|
(self.notify_init)(cstr.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn uninit(&self) {
|
||||||
|
unsafe {
|
||||||
|
trace!("Notify::uninit()");
|
||||||
|
(self.notify_uninit)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn notify_notification_set_timeout(
|
||||||
|
&self,
|
||||||
|
notification: *mut std::os::raw::c_void,
|
||||||
|
timeout: i32,
|
||||||
|
) {
|
||||||
|
trace!("Notify::notify_notification_set_timeout({notification:?}, {timeout})");
|
||||||
|
unsafe {
|
||||||
|
(self.notify_notification_set_timeout)(notification, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn notify_notification_new(
|
||||||
|
&self,
|
||||||
|
summary: &str,
|
||||||
|
body: &str,
|
||||||
|
icon: &str,
|
||||||
|
) -> *mut std::os::raw::c_void {
|
||||||
|
unsafe {
|
||||||
|
trace!("Notify::notify_notification_new({summary:?}, {body:?}, {icon:?})");
|
||||||
|
let summary = CString::new(summary).unwrap();
|
||||||
|
let body = CString::new(body).unwrap();
|
||||||
|
let icon = CString::new(icon).unwrap();
|
||||||
|
(self.notify_notification_new)(summary.as_ptr(), body.as_ptr(), icon.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn notify_notification_show(
|
||||||
|
&self,
|
||||||
|
notification: *mut std::os::raw::c_void,
|
||||||
|
error: *mut *mut c_void,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
trace!("Notify::notify_notification_show({notification:?}, {error:?})");
|
||||||
|
(self.notify_notification_show)(notification, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue