diff --git a/backend/src/events.rs b/backend/src/events.rs index b60c2f5..a808d16 100644 --- a/backend/src/events.rs +++ b/backend/src/events.rs @@ -1,40 +1,58 @@ mod error; mod pushover; +use std::error::Error; 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::{events::error::DeliveryError, model::devices::Device}; -use chrono::Local; +use chrono::{Local, Utc}; use duration_string::DurationString; use log::{debug, info, warn}; // Private helper function to deliver messages -fn send_message(body: String) -> Result<(), DeliveryError> { - debug!("About to send notification ({body})."); +fn send_notification(notification: Notification) -> Result<(), Box> { + 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() { "pushover" => { - pushover::send_message(body)?; + pushover::send_message(notification.title, notification.body)?; } other => { warn!("Notification method set to '{other}'. Set logs to 'info' to see notifications."); - info!("Notification: {body}"); + info!("Notification: {}", notification.body); } }; Ok(()) } -pub fn trigger_new_device(device: Device) -> Result<(), DeliveryError> { - send_message(format!("New device found in your network: {device}"))?; +pub fn trigger_new_device(device: Device) -> Result<(), Box> { + 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(()) } pub fn trigger_existing_device( existing_device: Device, new_device: Device, -) -> Result<(), DeliveryError> { +) -> Result<(), Box> { // 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) .to_std() @@ -43,45 +61,77 @@ pub fn trigger_existing_device( if elapsed_since_last_seen >= Duration::from(get_settings().notifications.notify_when_not_seen_for) { - send_message(format!( - "Device MAC {} - IP {} - Vendor {} came back online after {}.", - new_device.mac_address, - new_device.ipv4_address, - new_device.vendor, - String::from(DurationString::from(Duration::from_secs( - elapsed_since_last_seen.as_secs() - ))) - ))?; + let notification = Notification::new( + Utc::now(), + NotificationType::DeviceOnlineAfterTime, + "A device came back online after a while".to_string(), + format!( + "Device:\n\nMAC address: {}\nIP address: {}\nVendor: {}\n\ncame back online after {}.", + 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 if (existing_device.ipv4_address != new_device.ipv4_address) && (existing_device.vendor != new_device.vendor) { - send_message(format!( - "Device with MAC {} changed IP address from {} to {} and vendor from {} to {}.", - existing_device.mac_address, - existing_device.ipv4_address, - new_device.ipv4_address, - existing_device.vendor, - new_device.vendor - ))?; + let notification = Notification::new( + Utc::now(), + NotificationType::DeviceChanged, + "Device changed vendor and IP address".to_string(), + format!( + "Device with MAC address {} has changed:\nIP address from {} to {}\nVendor from {} to {}.", + 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 { - send_message(format!( - "Device with MAC {} ({}) changed IP address from {} to {}.", - existing_device.mac_address, - new_device.vendor, - existing_device.ipv4_address, - new_device.ipv4_address - ))?; + let notification = Notification::new( + Utc::now(), + NotificationType::DeviceChanged, + "Device changed IP address".to_string(), + format!( + "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 { - send_message(format!( - "Device with MAC {} ({}) changed vendor from {} to {}.", - existing_device.mac_address, - existing_device.ipv4_address, - existing_device.vendor, - new_device.vendor - ))?; + let notification = Notification::new( + Utc::now(), + NotificationType::DeviceChanged, + "Device changed vendor".to_string(), + format!( + "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(()) diff --git a/backend/src/events/pushover.rs b/backend/src/events/pushover.rs index 91172e4..e330113 100644 --- a/backend/src/events/pushover.rs +++ b/backend/src/events/pushover.rs @@ -1,19 +1,22 @@ use log::{debug, error}; +use pushover::API; use pushover::requests::message::SendMessage; -use pushover::{API, Error}; +use crate::events::error::DeliveryError; 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})"); let api = API::new(); - let msg = SendMessage::new( + let mut msg = SendMessage::new( get_settings().notifications.pushover.token.as_str(), get_settings().notifications.pushover.user_key.as_str(), body, ); + msg.set_title(title); + match api.send(&msg) { Ok(_) => { debug!("Message sent successfully"); @@ -21,7 +24,7 @@ pub fn send_message(body: String) -> Result<(), Error> { } Err(error) => { error!("Error sending message via pushover: {error}"); - Err(error) + Err(DeliveryError::from(error)) } } } diff --git a/backend/src/model/notifications.rs b/backend/src/model/notifications.rs index 8cf0f2e..365b88f 100644 --- a/backend/src/model/notifications.rs +++ b/backend/src/model/notifications.rs @@ -53,6 +53,7 @@ impl PartialEq for Notification { pub enum NotificationType { NewDeviceFound, DeviceOnlineAfterTime, + DeviceChanged, Other, } @@ -61,6 +62,7 @@ impl fmt::Display for NotificationType { match self { Self::NewDeviceFound => write!(f, "NewDeviceFound"), Self::DeviceOnlineAfterTime => write!(f, "DeviceOnlineAfterTime"), + Self::DeviceChanged => write!(f, "DeviceChanged"), Self::Other => write!(f, "Other"), } }