notification daemon
git clone https://git.lucas.co/cce-notifier.git
Optimize config loading in cce-notifier using static cache
Makefile | 2 ++
cce-notifier.service | 14 +++++++++
src/main.rs | 81 ++++++++++++++++++++++++++++++++++++++++------------
3 files changed, 79 insertions(+), 18 deletions(-)
diff --git a/Makefile b/Makefile
index 9a1ab80..125908d 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,8 @@ build:
install: build
mkdir -p ~/.local/bin
install -m 755 ../target/release/cce-notifier ~/.local/bin/cce-notifier
+ mkdir -p ~/.config/systemd/user
+ install -m 644 cce-notifier.service ~/.config/systemd/user/cce-notifier.service
run:
cargo run
diff --git a/cce-notifier.service b/cce-notifier.service
new file mode 100644
index 0000000..f8a90e1
--- /dev/null
+++ b/cce-notifier.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=CCE Notification Daemon
+After=graphical-session.target
+PartOf=graphical-session.target
+
+[Service]
+Type=simple
+ExecStart=%h/.local/bin/cce-notifier
+Restart=on-failure
+RestartSec=3
+Environment=RUST_LOG=info
+
+[Install]
+WantedBy=graphical-session.target
diff --git a/src/main.rs b/src/main.rs
index 078ff20..561e48d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -449,41 +449,86 @@ impl NotificationApp {
}
}
+struct CachedConfig {
+ last_modified: Option<std::time::SystemTime>,
+ parsed: Option<serde_json::Value>,
+}
+
+static CONFIG_CACHE: std::sync::RwLock<CachedConfig> = std::sync::RwLock::new(CachedConfig {
+ last_modified: None,
+ parsed: None,
+});
+
+fn load_config() -> serde_json::Value {
+ let path = "/home/lsgalante/.config/cce/config.kdl";
+ let current_modified = std::fs::metadata(path).ok().and_then(|m| m.modified().ok());
+
+ if let Ok(cache) = CONFIG_CACHE.read() {
+ if cache.last_modified.is_some() && cache.last_modified == current_modified {
+ if let Some(ref val) = cache.parsed {
+ return val.clone();
+ }
+ }
+ }
+
+ let content = std::fs::read_to_string(path).unwrap_or_default();
+ let val = cce_ui::config::parse_kdl_to_json(&content);
+ if let Ok(mut cache) = CONFIG_CACHE.write() {
+ cache.last_modified = current_modified;
+ cache.parsed = Some(val.clone());
+ }
+ val
+}
+
fn play_bell_if_configured() {
- let config_path = "/home/lsgalante/.config/cce/config.json";
- let content = std::fs::read_to_string(config_path).unwrap_or_default();
- let val: serde_json::Value = serde_json::from_str(&content).unwrap_or_default();
- let bell_enabled = val.pointer("/notifications/bell").and_then(|v| v.as_bool()).unwrap_or(false);
+ let val = load_config();
+ let sound_type = val.pointer("/notifications/bell").and_then(|v| v.as_str()).unwrap_or("none");
- if bell_enabled {
- log::info!("Playing notification bell sound...");
- if let Err(e) = std::process::Command::new("pw-play")
- .arg("/usr/share/sounds/freedesktop/stereo/bell.oga")
+ let sound_event = match sound_type {
+ "bell" => Some("bell"),
+ "dialog" => Some("dialog-information"),
+ "message" => Some("message"),
+ _ => None,
+ };
+
+ if let Some(event) = sound_event {
+ log::info!("Playing notification sound ({})...", sound_type);
+ if std::process::Command::new("canberra-gtk-play")
+ .arg("-i")
+ .arg(event)
.spawn()
+ .is_err()
{
- log::error!("Failed to spawn pw-play: {}", e);
+ let sound_file = match sound_type {
+ "bell" => "/usr/share/sounds/freedesktop/stereo/bell.oga",
+ "dialog" => "/usr/share/sounds/freedesktop/stereo/dialog-information.oga",
+ "message" => "/usr/share/sounds/freedesktop/stereo/message.oga",
+ _ => "",
+ };
+ if !sound_file.is_empty() {
+ if let Err(e) = std::process::Command::new("pw-play")
+ .arg(sound_file)
+ .spawn()
+ {
+ log::error!("Failed to spawn pw-play: {}", e);
+ }
+ }
}
}
}
fn read_duration_if_configured() -> u64 {
- let config_path = "/home/lsgalante/.config/cce/config.json";
- let content = std::fs::read_to_string(config_path).unwrap_or_default();
- let val: serde_json::Value = serde_json::from_str(&content).unwrap_or_default();
+ let val = load_config();
val.pointer("/notifications/duration").and_then(|v| v.as_u64()).unwrap_or(5)
}
fn read_opacity_if_configured() -> f32 {
- let config_path = "/home/lsgalante/.config/cce/config.json";
- let content = std::fs::read_to_string(config_path).unwrap_or_default();
- let val: serde_json::Value = serde_json::from_str(&content).unwrap_or_default();
+ let val = load_config();
val.pointer("/notifications/opacity").and_then(|v| v.as_f64()).map(|n| n as f32).unwrap_or(0.9)
}
fn read_bg_color_if_configured() -> [f32; 4] {
- let config_path = "/home/lsgalante/.config/cce/config.json";
- let content = std::fs::read_to_string(config_path).unwrap_or_default();
- let val: serde_json::Value = serde_json::from_str(&content).unwrap_or_default();
+ let val = load_config();
if let Some(hex_str) = val.pointer("/notifications/bg_color").and_then(|v| v.as_str()) {
let hex = hex_str.trim_matches(|c| c == '"' || c == '\'' || c == ' ').trim_start_matches('#');