From 04db8a64543fdfa574355b5c966db6260f8a5c37 Mon Sep 17 00:00:00 2001 From: candifloss Date: Sun, 22 Sep 2024 01:32:17 +0530 Subject: [PATCH 1/4] begin rson.rs --- Cargo.toml | 2 +- src/formats/rson.rs | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 src/formats/rson.rs diff --git a/Cargo.toml b/Cargo.toml index 0b2c6a5..8622a5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,4 @@ zvariant = "4.2.0" tokio = { version = "1.40.0", features = ["full"] } futures-util = "0.3.30" serde_json = "1.0.128" -# rson_rs = "0.2.1" \ No newline at end of file +rson_rs = "0.2.1" \ No newline at end of file diff --git a/src/formats/rson.rs b/src/formats/rson.rs new file mode 100644 index 0000000..e69de29 From 3b92de541a5b6ec963439be0cf657493b0efecba Mon Sep 17 00:00:00 2001 From: candifloss Date: Sun, 22 Sep 2024 11:16:51 +0530 Subject: [PATCH 2/4] Added options j/p --- src/formats/rson.rs | 21 +++++++++++++++++++++ src/main.rs | 21 ++++++++++++++++++--- src/notification.rs | 7 +++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/formats/rson.rs b/src/formats/rson.rs index e69de29..cebe5d2 100644 --- a/src/formats/rson.rs +++ b/src/formats/rson.rs @@ -0,0 +1,21 @@ +// 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; +use rson_rs::value::Value; +use rson_rs::value::Value::Map; + +impl Notification { + pub fn actions_rson(&self) -> Value { + if self.actions().is_empty() { + Value::from_str("{actions: Null}") + } else { + // Wrap the map into a rson_rs::value::Value + self.actions() + .iter() + .map(|(id, label)| { + (id.clone(), Value::from_str(label)) // Create key-value pairs: id -> label + }) + .collect::>() // Collect into a rson_rs::value::Value::Map + } + } +} diff --git a/src/main.rs b/src/main.rs index f53fbcd..b25b0df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,12 @@ pub mod formats { pub mod json; pub mod plain; + //pub mod rson; } mod notification; use notification::{to_notif, Notification}; use std::collections::HashMap; +use std::env; use futures_util::stream::TryStreamExt; use zbus::{message::Body, Connection, Result}; @@ -29,6 +31,13 @@ fn server_properties() -> HashMap { #[tokio::main] async fn main() -> Result<()> { + let args: Vec = env::args().collect(); + let op_format: String = if args.is_empty() || args[1] == "j" { + "j".to_string() // Default value, json format + } else { + "p".to_string() // Plain format + }; + let connection = Connection::session().await?; connection .request_name(NOTIF_INTERFACE) // Requesting dbus for this service name. Any other services/procs using this name should be stopped/disabled before this @@ -36,6 +45,9 @@ async fn main() -> Result<()> { let mut stream = zbus::MessageStream::from(&connection); // Convert connection to a MessageStream, yields Message items + // Notification id, restarts with each session + let mut notification_id: u32 = 0; + // Iterate on the message stream while let Some(msg) = stream.try_next().await? { // Check the method calls in the received message's header @@ -81,7 +93,7 @@ async fn main() -> Result<()> { } "Notify" => { // New notification received. Now, respond to the client with a notification ID - let notification_id: u32 = 1; // This could be incremented or generated. DO IT LATER + notification_id += 1; // This could be incremented or generated. connection.reply(&msg, ¬ification_id).await?; // The client waits for this response in order to disconnect // Get the body of the message @@ -90,8 +102,11 @@ async fn main() -> Result<()> { // Convert the msg body to a Notification object let notif: Notification = to_notif(&msg_body)?; // Handle the notif - println!("New notification!\n{}\n", ¬if.plain()); // Print the plain version - println!("JSON!\n{}\n", ¬if.json()); // Print the plain version + if op_format == "j" { + println!("JSON!\n{}\n", ¬if.json()); // Print the json version + } else { + println!("New notification!\n{}\n", ¬if.plain()); // Print the plain version + } } "CloseNotification" => { // Client sent a close signal. Extract notification ID of the notif to be closed from the message body diff --git a/src/notification.rs b/src/notification.rs index 0153e7e..299e42d 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -65,6 +65,13 @@ impl Notification { } actions } + /* + pub fn actions(&self) -> Vec<(String, String)> { + self.actions + .chunks(2) + .map(|chunk| (chunk[0].clone(), chunk[1].clone())) + .collect() + } */ // Hints pub fn hints(&self) -> &HashMap { From 6fe5d22745d455c0c43c50ee0c39009eadef081d Mon Sep 17 00:00:00 2001 From: candifloss Date: Sun, 22 Sep 2024 15:48:27 +0530 Subject: [PATCH 3/4] Got rson working, added format and verbose options --- Cargo.toml | 3 ++- src/formats/rson.rs | 22 ++++++++--------- src/main.rs | 59 +++++++++++++++++++++++++++++++++------------ src/notification.rs | 4 +-- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8622a5e..cc90b6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snot" -version = "0.1.0" +version = "0.1.1" edition = "2021" authors = ["candifloss "] @@ -9,5 +9,6 @@ zbus = "4.4.0" zvariant = "4.2.0" tokio = { version = "1.40.0", features = ["full"] } futures-util = "0.3.30" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.128" rson_rs = "0.2.1" \ No newline at end of file diff --git a/src/formats/rson.rs b/src/formats/rson.rs index cebe5d2..d9420e0 100644 --- a/src/formats/rson.rs +++ b/src/formats/rson.rs @@ -1,21 +1,19 @@ // 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; -use rson_rs::value::Value; -use rson_rs::value::Value::Map; +use rson_rs::ser::to_string as rson_string; impl Notification { - pub fn actions_rson(&self) -> Value { + pub fn actions_rson(&self) -> String { if self.actions().is_empty() { - Value::from_str("{actions: Null}") + String::new() } else { - // Wrap the map into a rson_rs::value::Value - self.actions() - .iter() - .map(|(id, label)| { - (id.clone(), Value::from_str(label)) // Create key-value pairs: id -> label - }) - .collect::>() // Collect into a rson_rs::value::Value::Map + rson_string(&self.actions()).unwrap() } } + pub fn hints_rson(&self) -> String { + rson_string(&self.hints()).unwrap() + } + pub fn rson(&self) -> String { + rson_string(&self).unwrap() + } } diff --git a/src/main.rs b/src/main.rs index b25b0df..753bf17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ pub mod formats { pub mod json; pub mod plain; - //pub mod rson; + pub mod rson; } mod notification; use notification::{to_notif, Notification}; @@ -32,12 +32,18 @@ fn server_properties() -> HashMap { #[tokio::main] async fn main() -> Result<()> { let args: Vec = env::args().collect(); - let op_format: String = if args.is_empty() || args[1] == "j" { - "j".to_string() // Default value, json format + let op_format: &str = if args.is_empty() || args[1] == "j" { + "j" // Default value, json format + } else if args[1] == "p" { + "p" // Plain format + } else if args[1] == "r" { + "r" // rson format } else { - "p".to_string() // Plain format + "j" }; + let verbose: bool = (args.len() > 2) && (args[2] == "v"); + let connection = Connection::session().await?; connection .request_name(NOTIF_INTERFACE) // Requesting dbus for this service name. Any other services/procs using this name should be stopped/disabled before this @@ -64,9 +70,13 @@ async fn main() -> Result<()> { let properties = server_properties(); // Reply with the properties connection.reply(&msg, &properties).await?; - println!("GetAll request received for interface: {interface_name}"); + if verbose { + println!("GetAll request received for interface: {interface_name}"); + } } else { - println!("Unknown interface requested: {interface_name}"); + if verbose { + println!("Unknown interface requested: {interface_name}"); + } // Reply with an error connection .reply_error( @@ -81,15 +91,19 @@ async fn main() -> Result<()> { // Client requested server information. Respond with: (Server_name, author, software_version, dbus_spec_version) let response = (SERVER_NAME, VENDOR, VERSION, SPEC_VERSION); connection.reply(&msg, &response).await?; - println!("Request received: {member}\n\tName: {SERVER_NAME}, Vendor: {VENDOR}, Version: {VERSION}, DBus spec version: {SPEC_VERSION}"); - // Remove this LATER + if verbose { + println!("Request received: {member}\n\tName: {SERVER_NAME}, Vendor: {VENDOR}, Version: {VERSION}, DBus spec version: {SPEC_VERSION}"); + // Remove this LATER + } } "GetCapabilities" => { // Client requested server capabilities. Respond with the supported capabilities let capabilities = vec!["actions", "body", "body-hyperlinks"]; // Add more LATER connection.reply(&msg, &capabilities).await?; - println!("Request received: {member}\n\tCapabilities: {capabilities:?}"); - // Remove this LATER + if verbose { + println!("Request received: {member}\n\tCapabilities: {capabilities:?}"); + // Remove this LATER + } } "Notify" => { // New notification received. Now, respond to the client with a notification ID @@ -102,10 +116,19 @@ async fn main() -> Result<()> { // Convert the msg body to a Notification object let notif: Notification = to_notif(&msg_body)?; // Handle the notif - if op_format == "j" { - println!("JSON!\n{}\n", ¬if.json()); // Print the json version - } else { - println!("New notification!\n{}\n", ¬if.plain()); // Print the plain version + match op_format { + "j" => { + println!("{}", ¬if.json()); // Print the json version + } + "r" => { + println!("{}", ¬if.rson()); // Print the plain version + } + "p" => { + println!("{}\n", ¬if.plain()); // Print the plain version + } + _ => { + println!("Onkown output format."); + } } } "CloseNotification" => { @@ -114,13 +137,17 @@ async fn main() -> Result<()> { // Tracking notifications by their IDs, closing them, and other features may be implemented later // close_notification(notification_id); - println!("Closing notification with ID: {notification_id}"); + if verbose { + println!("Closing notification with ID: {notification_id}"); + } // Respond to the client, acknowledging the closure connection.reply(&msg, &()).await?; } _ => { - println!("Unhandled method: {member}"); // Other methods are either irrelevant or unhandled at this stage of development + if verbose { + println!("Unhandled method: {member}"); // Other methods are either irrelevant or unhandled at this stage of development + } } } } diff --git a/src/notification.rs b/src/notification.rs index 299e42d..95d6d5f 100644 --- a/src/notification.rs +++ b/src/notification.rs @@ -1,10 +1,10 @@ -// use serde::Serialize; +use serde::Serialize; use std::collections::HashMap; use zbus::{message::Body, Result}; use zvariant::OwnedValue; // A notificaion object -// #[derive(Serialize)] // To help with json +#[derive(Serialize)] // To help with json, rson pub struct Notification { // The application that sent the notification app_name: String, From 16cc7724757b5682a2cb11d36d7bc35ecf6d299c Mon Sep 17 00:00:00 2001 From: candifloss Date: Sun, 22 Sep 2024 15:57:03 +0530 Subject: [PATCH 4/4] edited README --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5c837ca..6899526 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,24 @@ Inspired by [`tiramisu`](https://github.com/Sweets/tiramisu) - Do one thing and do it well([DOTADIW](https://en.wikipedia.org/w/index.php?title=Unix_philosophy&useskin=vector#Do_One_Thing_and_Do_It_Well)) & [KISS](https://en.wikipedia.org/wiki/KISS_Principle) principle: no extra complicated features - (Not really a feature) Written in [`rust`](https://www.rust-lang.org/) using the [`zbus`](https://docs.rs/zbus/latest/zbus/) crate -## Upcoming feature - -- Better ways to work with other programs - -## Currently supported formats +## Supported formats - Plain text - Print the output text. (✓ Just print it) - [`json`](https://json.org) - This output can be parsed by other programs - -## Upcoming format(s) - - [`rson`](https://github.com/rson-rs/rson) - A more sensible alternative to json -## Why? +## Upcoming feature + +- Better handling of `json` and `rson` data +- Better ways to work with other programs + +## Usage + +```bash +snot [r|j|p] [v] +``` + +## Why this project? - Something simple to work with [`EWW`](https://github.com/elkowar/eww) widgets - I'm learning Rust \ No newline at end of file