Improved notifications structure and now saving notifications to

database when triggered
This commit is contained in:
rzuasti
2026-02-23 13:23:36 -05:00
parent e38b875052
commit 03d2e6c9b1
3 changed files with 99 additions and 44 deletions
+90 -40
View File
@@ -1,40 +1,58 @@
mod error; mod error;
mod pushover; mod pushover;
use std::error::Error;
use std::time::Duration; use std::time::Duration;
use crate::db;
use crate::model::devices::Device;
use crate::model::notifications::Notification;
use crate::model::notifications::NotificationType;
use crate::settings::get_settings; use crate::settings::get_settings;
use crate::{events::error::DeliveryError, model::devices::Device}; use chrono::{Local, Utc};
use chrono::Local;
use duration_string::DurationString; use duration_string::DurationString;
use log::{debug, info, warn}; use log::{debug, info, warn};
// Private helper function to deliver messages // Private helper function to deliver messages
fn send_message(body: String) -> Result<(), DeliveryError> { fn send_notification(notification: Notification) -> Result<(), Box<dyn Error>> {
debug!("About to send notification ({body})."); debug!("About to record notification in database");
db::notifications::insert(notification.clone())?;
debug!("About to send notification ({notification}).");
match get_settings().notifications.method.as_str() { match get_settings().notifications.method.as_str() {
"pushover" => { "pushover" => {
pushover::send_message(body)?; pushover::send_message(notification.title, notification.body)?;
} }
other => { other => {
warn!("Notification method set to '{other}'. Set logs to 'info' to see notifications."); warn!("Notification method set to '{other}'. Set logs to 'info' to see notifications.");
info!("Notification: {body}"); info!("Notification: {}", notification.body);
} }
}; };
Ok(()) Ok(())
} }
pub fn trigger_new_device(device: Device) -> Result<(), DeliveryError> { pub fn trigger_new_device(device: Device) -> Result<(), Box<dyn Error>> {
send_message(format!("New device found in your network: {device}"))?; let notification = Notification::new(
Utc::now(),
NotificationType::NewDeviceFound,
"New device found in your network".to_string(),
format!(
"A new device was found in your network:\n\nMAC address: {}\nIP address: {}\nVendor: {}",
device.mac_address, device.ipv4_address, device.vendor
),
true,
);
send_notification(notification)?;
Ok(()) Ok(())
} }
pub fn trigger_existing_device( pub fn trigger_existing_device(
existing_device: Device, existing_device: Device,
new_device: Device, new_device: Device,
) -> Result<(), DeliveryError> { ) -> Result<(), Box<dyn Error>> {
// Notify if the device comes back online after not being seen for the configured period // Notify if the device comes back online after not being seen for the configured period
let elapsed_since_last_seen: Duration = (Local::now().to_utc() - existing_device.last_seen) let elapsed_since_last_seen: Duration = (Local::now().to_utc() - existing_device.last_seen)
.to_std() .to_std()
@@ -43,45 +61,77 @@ pub fn trigger_existing_device(
if elapsed_since_last_seen if elapsed_since_last_seen
>= Duration::from(get_settings().notifications.notify_when_not_seen_for) >= Duration::from(get_settings().notifications.notify_when_not_seen_for)
{ {
send_message(format!( let notification = Notification::new(
"Device MAC {} - IP {} - Vendor {} came back online after {}.", Utc::now(),
new_device.mac_address, NotificationType::DeviceOnlineAfterTime,
new_device.ipv4_address, "A device came back online after a while".to_string(),
new_device.vendor, format!(
String::from(DurationString::from(Duration::from_secs( "Device:\n\nMAC address: {}\nIP address: {}\nVendor: {}\n\ncame back online after {}.",
elapsed_since_last_seen.as_secs() new_device.mac_address,
))) new_device.ipv4_address,
))?; new_device.vendor,
String::from(DurationString::from(Duration::from_secs(
elapsed_since_last_seen.as_secs()
)))
),
true,
);
send_notification(notification)?;
} }
// Notify if the devices vendor and/or IP changed // Notify if the devices vendor and/or IP changed
if (existing_device.ipv4_address != new_device.ipv4_address) if (existing_device.ipv4_address != new_device.ipv4_address)
&& (existing_device.vendor != new_device.vendor) && (existing_device.vendor != new_device.vendor)
{ {
send_message(format!( let notification = Notification::new(
"Device with MAC {} changed IP address from {} to {} and vendor from {} to {}.", Utc::now(),
existing_device.mac_address, NotificationType::DeviceChanged,
existing_device.ipv4_address, "Device changed vendor and IP address".to_string(),
new_device.ipv4_address, format!(
existing_device.vendor, "Device with MAC address {} has changed:\nIP address from {} to {}\nVendor from {} to {}.",
new_device.vendor existing_device.mac_address,
))?; existing_device.ipv4_address,
new_device.ipv4_address,
existing_device.vendor,
new_device.vendor,
),
true,
);
send_notification(notification)?;
} else if existing_device.ipv4_address != new_device.ipv4_address { } else if existing_device.ipv4_address != new_device.ipv4_address {
send_message(format!( let notification = Notification::new(
"Device with MAC {} ({}) changed IP address from {} to {}.", Utc::now(),
existing_device.mac_address, NotificationType::DeviceChanged,
new_device.vendor, "Device changed IP address".to_string(),
existing_device.ipv4_address, format!(
new_device.ipv4_address "Device with MAC address {} ({}) has changed:\nIP address from {} to {}.",
))?; existing_device.mac_address,
existing_device.vendor,
existing_device.ipv4_address,
new_device.ipv4_address,
),
true,
);
send_notification(notification)?;
} else if existing_device.vendor != new_device.vendor { } else if existing_device.vendor != new_device.vendor {
send_message(format!( let notification = Notification::new(
"Device with MAC {} ({}) changed vendor from {} to {}.", Utc::now(),
existing_device.mac_address, NotificationType::DeviceChanged,
existing_device.ipv4_address, "Device changed vendor".to_string(),
existing_device.vendor, format!(
new_device.vendor "Device with MAC address {} ({}) has changed:\nVendor from {} to {}.",
))?; existing_device.mac_address,
existing_device.ipv4_address,
existing_device.vendor,
new_device.vendor,
),
true,
);
send_notification(notification)?;
}; };
Ok(()) Ok(())
+7 -4
View File
@@ -1,19 +1,22 @@
use log::{debug, error}; use log::{debug, error};
use pushover::API;
use pushover::requests::message::SendMessage; use pushover::requests::message::SendMessage;
use pushover::{API, Error};
use crate::events::error::DeliveryError;
use crate::settings::get_settings; use crate::settings::get_settings;
pub fn send_message(body: String) -> Result<(), Error> { pub fn send_message(title: String, body: String) -> Result<(), DeliveryError> {
debug!("About to send message via pushover ({body})"); debug!("About to send message via pushover ({body})");
let api = API::new(); let api = API::new();
let msg = SendMessage::new( let mut msg = SendMessage::new(
get_settings().notifications.pushover.token.as_str(), get_settings().notifications.pushover.token.as_str(),
get_settings().notifications.pushover.user_key.as_str(), get_settings().notifications.pushover.user_key.as_str(),
body, body,
); );
msg.set_title(title);
match api.send(&msg) { match api.send(&msg) {
Ok(_) => { Ok(_) => {
debug!("Message sent successfully"); debug!("Message sent successfully");
@@ -21,7 +24,7 @@ pub fn send_message(body: String) -> Result<(), Error> {
} }
Err(error) => { Err(error) => {
error!("Error sending message via pushover: {error}"); error!("Error sending message via pushover: {error}");
Err(error) Err(DeliveryError::from(error))
} }
} }
} }
+2
View File
@@ -53,6 +53,7 @@ impl PartialEq for Notification {
pub enum NotificationType { pub enum NotificationType {
NewDeviceFound, NewDeviceFound,
DeviceOnlineAfterTime, DeviceOnlineAfterTime,
DeviceChanged,
Other, Other,
} }
@@ -61,6 +62,7 @@ impl fmt::Display for NotificationType {
match self { match self {
Self::NewDeviceFound => write!(f, "NewDeviceFound"), Self::NewDeviceFound => write!(f, "NewDeviceFound"),
Self::DeviceOnlineAfterTime => write!(f, "DeviceOnlineAfterTime"), Self::DeviceOnlineAfterTime => write!(f, "DeviceOnlineAfterTime"),
Self::DeviceChanged => write!(f, "DeviceChanged"),
Self::Other => write!(f, "Other"), Self::Other => write!(f, "Other"),
} }
} }