diff --git a/.gitignore b/.gitignore index 922c946..695a23c 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ Cargo.lock /target /.idea +error.log diff --git a/Cargo.toml b/Cargo.toml index 5e6d566..ae14e97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,14 @@ [package] name = "snot" -version = "0.1.1" +version = "0.1.3" edition = "2021" authors = ["candifloss "] +description = "Simple NOTification" +license = "GPL-3.0-or-later" +repository = "https://git.candifloss.cc/candifloss/SNot" +homepage = "https://git.candifloss.cc/candifloss/SNot" +documentation = "https://git.candifloss.cc/candifloss/SNot" +readme = "README.md" [dependencies] zbus = "4.4.0" diff --git a/src/formats/rson.rs b/src/formats/rson.rs index fd4027d..9576477 100644 --- a/src/formats/rson.rs +++ b/src/formats/rson.rs @@ -1,10 +1,10 @@ // This module deals with converting the notification object into rson format, which can be used instead of json if preferred use crate::notification::Notification; -use rson_rs::ser::to_string as rson_string; use rson_rs::de::Error as RsonError; +use rson_rs::ser::to_string as rson_string; impl Notification { pub fn rson(&self) -> Result { - rson_string(self).map_err(|e| RsonError::Message(format!("RSON serialization error: {}", e))) + rson_string(self).map_err(|e| RsonError::Message(format!("RSON serialization error: {e}"))) } } diff --git a/src/formats/serde.rs b/src/formats/serde.rs index da73200..c2741c2 100644 --- a/src/formats/serde.rs +++ b/src/formats/serde.rs @@ -1,41 +1,87 @@ -use serde::{Serialize, Serializer}; -/* +use serde::ser::{Serialize, SerializeMap, Serializer}; +use serde_json::{Map, Value}; use std::collections::HashMap; -use std::hash::BuildHasher; -use zvariant::OwnedValue; */ +use zvariant::OwnedValue; +/// Serialize actions +/// # Errors +/// Will return an empty map if there are no actions pub fn serialize_actions(actions: &[String], serializer: S) -> Result where S: Serializer, { - let mut map = serde_json::Map::new(); + let mut map = Map::new(); - // Assuming actions are in pairs: [id, label, id, label, ...] - for chunk in actions.chunks(2) { - if let [id, label] = chunk { - map.insert(id.clone(), serde_json::Value::String(label.clone())); + // Actions are in pairs: [id, label, id, label, ...] + for pair in actions.chunks(2) { + if let [id, label] = pair { + map.insert(id.clone(), Value::String(label.clone())); } } map.serialize(serializer) } -/* -pub fn serialize_hints( - hints: &HashMap, +/// Serialize hints +/// # Errors +/// Will return an empty map if there are no hints +pub fn serialize_hints( + hints: &HashMap, serializer: S, ) -> Result where S: Serializer, - H: BuildHasher, { - let mut map = serde_json::Map::new(); - + // Start serializing the map + let mut map = serializer.serialize_map(Some(hints.len()))?; for (key, value) in hints { - // Customize OwnedValue serialization as needed - map.insert(key.clone(), serde_json::Value::String(value.to_string())); + // Serialize each entry as desired + map.serialize_entry(key, &HintValueSerializer(value))?; + } + map.end() +} + +// A custom struct to handle serialization of OwnedValue +struct HintValueSerializer<'a>(&'a OwnedValue); + +impl Serialize for HintValueSerializer<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let signature = self.0.value_signature().to_string(); // Get signature + + // Extract the raw value correctly + let raw_value = if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // BYTE: y + } else if let Ok(v) = self.0.downcast_ref::() { + Value::Bool(v) // BOOLEAN: b + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // INT16: n + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // UINT16: q + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // INT32: i + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // UINT32: u + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // INT64: x + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // UINT64: t + } else if let Ok(v) = self.0.downcast_ref::() { + Value::from(v) // DOUBLE: d + } else if let Ok(v) = self.0.downcast_ref::() { + Value::String(v.clone()) // STRING: s + } else if let Ok(v) = self.0.downcast_ref::<&str>() { + Value::String(v.to_string()) // str + } else { + Value::Null // Unsupported types: fallback to Null + }; // Not implemented: UNIX_FD: h, OBJECT_PATH: o, SIGNATURE: g + + // Serialize the final structure as a map + let mut map = serializer.serialize_map(Some(2))?; + map.serialize_entry("signature", &signature)?; + map.serialize_entry("value", &raw_value)?; + map.end() } - - map.serialize(serializer) } -*/ diff --git a/src/main.rs b/src/main.rs index bdf9847..b0f57d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,8 +13,8 @@ use futures_util::stream::TryStreamExt; use zbus::{message::Body, Connection, Result}; const SERVER_NAME: &str = "SNot"; // Server software name -const VENDOR: &str = "candifloss.cc"; // Server software vendor -const VERSION: &str = "0.1.2"; // Server software version +const VENDOR: &str = env!("CARGO_PKG_AUTHORS"); // Server software vendor +const VERSION: &str = env!("CARGO_PKG_VERSION"); // Server software version, from Cargo.toml const SPEC_VERSION: &str = "0.42"; // DBus specification version const NOTIF_INTERFACE: &str = "org.freedesktop.Notifications"; // DBus interface name @@ -109,7 +109,7 @@ async fn main() -> Result<()> { } "GetCapabilities" => { // Client requested server capabilities. Respond with the supported capabilities - let capabilities = vec!["actions", "body", "body-hyperlinks"]; // Add more LATER + let capabilities = vec![/*"actions",*/ "body", "body-hyperlinks"]; // Add more LATER connection.reply(&msg, &capabilities).await?; if verbose { println!("Request received: {member}\n\tCapabilities: {capabilities:?}"); @@ -134,8 +134,8 @@ async fn main() -> Result<()> { "r" => { // Print the rson version match notif.rson() { - Ok(rson_string) => println!("{}", rson_string), - Err(e) => eprintln!("Failed to convert to RSON: {}", e), + Ok(rson_string) => println!("{rson_string}"), + Err(e) => eprintln!("Failed to convert to RSON: {e}"), } } "p" => { diff --git a/src/notification.rs b/src/notification.rs index 538faa6..597201e 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -1,4 +1,4 @@ -use crate::formats::serde::serialize_actions; +use crate::formats::serde::{serialize_actions, serialize_hints}; use serde::Serialize; use std::collections::HashMap; use zbus::{message::Body, Result}; @@ -21,7 +21,7 @@ pub struct Notification { #[serde(serialize_with = "serialize_actions")] actions: Vec, // Useful extra data - notif type, urgency, notif sound, icon data, etc. - //#[serde(serialize_with = "serialize_hints")] + #[serde(serialize_with = "serialize_hints")] hints: HashMap, // Seconds till this notif expires. Optional expir_timeout: i32,