Skip to content

Commit

Permalink
feat(dre): [DRE-237] Send desktop notifications when (not) voting wit…
Browse files Browse the repository at this point in the history
…h dre tool (#711)

Co-authored-by: sa-github-api <[email protected]>
  • Loading branch information
sasa-tomic and sa-github-api authored Aug 13, 2024
1 parent 2b16d1c commit 5d4f8f2
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 9 deletions.
37 changes: 28 additions & 9 deletions rs/cli/src/commands/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use log::info;
use spinners::{Spinner, Spinners};

use super::{ExecutableCommand, IcAdminRequirement};
use crate::desktop_notify::DesktopNotifier;

#[derive(Args, Debug)]
pub struct Vote {
Expand Down Expand Up @@ -49,7 +50,7 @@ impl ExecutableCommand for Vote {
let client: GovernanceCanisterWrapper = ctx.create_canister_client()?.into();

let mut voted_proposals = HashSet::new();
info!("Starting the voting loop...");
DesktopNotifier::send_info("DRE vote: starting", "Starting the voting loop...");

loop {
let proposals = client.get_pending_proposals().await?;
Expand All @@ -68,16 +69,34 @@ impl ExecutableCommand for Vote {

for proposal in proposals {
let datetime = Local::now();
info!(
"{} Voting on proposal {} (topic {:?}, proposer {}) -> {}",
datetime,
proposal.id.unwrap().id,
proposal.topic(),
proposal.proposer.unwrap_or_default().id,
proposal.proposal.clone().unwrap().title.unwrap()
DesktopNotifier::send_info(
"DRE vote: voting",
&format!(
"{} Voting on proposal {} (topic {:?}, proposer {}) -> {}",
datetime,
proposal.id.unwrap().id,
proposal.topic(),
proposal.proposer.unwrap_or_default().id,
proposal.proposal.clone().unwrap().title.unwrap()
),
);

let response = client.register_vote(ctx.ic_admin().neuron.neuron_id, proposal.id.unwrap().id).await?;
let response = match client.register_vote(ctx.ic_admin().neuron.neuron_id, proposal.id.unwrap().id).await {
Ok(response) => format!("Voted successfully: {}", response),
Err(e) => {
DesktopNotifier::send_critical(
"DRE vote: error",
&format!(
"Error voting on proposal {} (topic {:?}, proposer {}) -> {}",
proposal.id.unwrap().id,
proposal.topic(),
proposal.proposer.unwrap_or_default().id,
e
),
);
format!("Error voting: {}", e)
}
};
info!("{}", response);
voted_proposals.insert(proposal.id.unwrap().id);
}
Expand Down
151 changes: 151 additions & 0 deletions rs/cli/src/desktop_notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use log::{error, info, warn};
use std::process::Command;

pub struct DesktopNotifier;

impl DesktopNotifier {
/// Sends an informational notification.
///
/// # Arguments
///
/// * `title` - A title for the notification.
/// * `message` - The message body of the notification.
pub fn send_info(title: &str, message: &str) {
DesktopNotifier::notify(title, message, "info");
}

/// Sends a critical notification.
///
/// # Arguments
///
/// * `title` - A title for the notification.
/// * `message` - The message body of the notification.
pub fn send_critical(title: &str, message: &str) {
DesktopNotifier::notify(title, message, "critical");
}

#[cfg(target_os = "macos")]
fn notify(title: &str, message: &str, level: &str) {
if level == "critical" {
warn!("{}: {}", title, message);
} else {
info!("{}: {}", title, message);
}

let command_result = Command::new("osascript")
.arg("-e")
.arg(format!(
r#"display notification "{}" with title "{}" subtitle "{}""#,
message, title, level
))
.output();

match command_result {
Ok(output) => {
if !output.status.success() {
error!("Failed to send macOS notification: {}", String::from_utf8_lossy(&output.stderr));
}
}
Err(err) => {
error!("Notification command not found or failed: {}", err);
}
}
}

fn notify(title: &str, message: &str, level: &str) {
let urgency = if level == "critical" {
warn!("{}: {}", title, message);
"critical"
} else {
info!("{}: {}", title, message);
"normal"
};

let command_result = Command::new("notify-send")
.arg("-u")
.arg(urgency)
.arg("-a")
.arg("dre")
.arg(title)
.arg(message)
.output();

match command_result {
Ok(output) => {
if !output.status.success() {
error!("Failed to send Linux notification: {}", String::from_utf8_lossy(&output.stderr));
}
}
Err(err) => {
error!("Notification command not found or failed: {}", err);
}
}
}

#[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn notify() {
info!("Notification system is not supported on this operating system.");
}
}

#[cfg(test)]
mod tests {
use super::*;
use fs_err::{File, OpenOptions};
use log::{LevelFilter, Metadata, Record};
use std::io::Write;
use std::sync::Mutex;
use std::sync::Once;

static INIT: Once = Once::new();

fn initialize() {
INIT.call_once(|| {
// Initialize logger
let file = OpenOptions::new().create(true).write(true).truncate(true).open("test.log").unwrap();

log::set_boxed_logger(Box::new(SimpleLogger { file: Mutex::new(file) })).unwrap();
log::set_max_level(LevelFilter::Info);
});
}

struct SimpleLogger {
file: Mutex<File>,
}

impl log::Log for SimpleLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= log::max_level()
}

fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
let mut file = self.file.lock().unwrap();
writeln!(file, "{} - {}", record.level(), record.args()).unwrap();
}
}

fn flush(&self) {}
}

#[test]
fn test_send_info_notification() {
initialize();
DesktopNotifier::send_info("Test Info", "This is an info notification");
}

#[test]
fn test_send_critical_notification() {
initialize();
DesktopNotifier::send_critical("Test Critical", "This is a critical notification");
}

#[test]
fn test_unsupported_os() {
initialize();
if !cfg!(target_os = "macos") && !cfg!(target_os = "linux") {
DesktopNotifier::send_info("Unsupported OS Test", "Testing unsupported OS handling");
DesktopNotifier::send_critical("Unsupported OS Test", "Testing unsupported OS handling");
}
}
}
1 change: 1 addition & 0 deletions rs/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub mod auth;
pub mod commands;
pub mod ctx;
mod desktop_notify;
pub mod ic_admin;
mod operations;
mod qualification;
Expand Down
1 change: 1 addition & 0 deletions rs/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use log::{info, warn};
mod auth;
mod commands;
mod ctx;
mod desktop_notify;
mod ic_admin;
mod operations;
mod qualification;
Expand Down

0 comments on commit 5d4f8f2

Please sign in to comment.