net monitor uptime now uses serde

This commit is contained in:
Christoph J. Scherr 2023-07-12 19:15:42 +02:00
parent 8dc4a0aade
commit 37d77044b8
Signed by: PlexSheep
GPG Key ID: 25B4ACF7D88186CC
3 changed files with 37 additions and 59 deletions

View File

@ -35,4 +35,6 @@ openssl-sys = "0.9.90"
pyo3 = "0.18.1" pyo3 = "0.18.1"
regex = "1.9.1" regex = "1.9.1"
reqwest = { version = "0.11.18", features = ["blocking"] } reqwest = { version = "0.11.18", features = ["blocking"] }
serde = { version = "1.0.171", features = ["derive"] }
serde_json = "1.0.102"
signal-hook = "0.3.15" signal-hook = "0.3.15"

View File

@ -94,7 +94,7 @@ pub fn net(cli: &Cli, command: NetCommands) {
if repeat > 0 { if repeat > 0 {
uptime::continuous_uptime_monitor(success_ratio, urls, repeat * 1000, timeout); uptime::continuous_uptime_monitor(success_ratio, urls, repeat * 1000, timeout);
} else { } else {
let status = uptime::UptimeStatus::new(success_ratio, &urls, timeout); let status = uptime::UptimeStatus::new(success_ratio, urls, timeout);
println!("{}", status); println!("{}", status);
} }
} }

View File

@ -16,20 +16,23 @@
// enable clippy's extra lints, the pedantic version // enable clippy's extra lints, the pedantic version
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
use std::{fmt, str::FromStr, time::Duration}; use std::{fmt, time::Duration};
//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// //// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
// we want the log macros in any case // we want the log macros in any case
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use reqwest::{self, Url}; use reqwest;
use humantime::{format_duration, format_rfc3339}; use humantime::{format_duration, format_rfc3339};
use std::time::SystemTime; use std::time::SystemTime;
use pyo3::prelude::*; use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json;
use crate::divider; use crate::divider;
//// TYPES ///////////////////////////////////////////////////////////////////////////////////////// //// TYPES /////////////////////////////////////////////////////////////////////////////////////////
@ -50,44 +53,43 @@ pub const DEFAULT_CHECK_URLS: &'static [&'static str] =
/// ///
/// [`UptimeStatus`] describes the result of an uptime check. /// [`UptimeStatus`] describes the result of an uptime check.
#[pyclass] #[pyclass]
#[derive(Serialize, Deserialize)]
pub struct UptimeStatus { pub struct UptimeStatus {
/// true if the [`UptimeStatus`] is considered successful /// true if the [`UptimeStatus`] is considered successful
#[pyo3(get, set)]
pub success: bool, pub success: bool,
/// the percentage of reachable urls out of the total urls /// the percentage of reachable urls out of the total urls
#[pyo3(get, set)]
pub success_ratio: u8, pub success_ratio: u8,
/// the percentage of reachable urls out of the total urls that need to be reachable in order /// the percentage of reachable urls out of the total urls that need to be reachable in order
/// for this [`UptimeStatus`] to be considered a success. /// for this [`UptimeStatus`] to be considered a success.
#[pyo3(get, set)]
pub success_ratio_target: u8, pub success_ratio_target: u8,
/// the number of reachable [`urls`](UptimeStatus::urls) /// the number of reachable [`urls`](UptimeStatus::urls)
#[pyo3(get, set)]
pub reachable: usize, pub reachable: usize,
/// which urls to check in [`check()`](UptimeStatus::check) /// which urls to check in [`check()`](UptimeStatus::check)
pub urls: Vec<Url>, #[pyo3(get, set)]
pub urls: Vec<String>,
/// timeout length for requests (in ms) /// timeout length for requests (in ms)
pub timeout: u64 #[pyo3(get, set)]
pub timeout: u64,
} }
//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// //// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
/// Main implementation /// Main implementation
impl UptimeStatus { impl UptimeStatus {
/// ## create a new `UptimeStatus` and perform it's check /// ## create a new `UptimeStatus` and perform it's check
pub fn new(success_ratio_target: u8, url_strs: &Vec<String>, timeout: u64) -> Self { pub fn new(success_ratio_target: u8, urls: Vec<String>, timeout: u64) -> Self {
assert!(success_ratio_target <= 100); assert!(success_ratio_target <= 100);
let mut status = UptimeStatus { let mut status = UptimeStatus {
success: false, success: false,
success_ratio: 0, success_ratio: 0,
success_ratio_target, success_ratio_target,
reachable: 0, reachable: 0,
urls: Vec::new(), urls,
timeout timeout,
}; };
for s in url_strs {
let url = reqwest::Url::from_str(&s);
if url.is_ok() {
status.urls.push(url.unwrap());
} else {
warn!("Invalid URL: '{}", s);
}
}
status.urls.dedup(); status.urls.dedup();
status.check(); status.check();
@ -152,8 +154,8 @@ impl UptimeStatus {
impl UptimeStatus { impl UptimeStatus {
/// calls [`new()`](UptimeStatus::new) with python compatible arguments /// calls [`new()`](UptimeStatus::new) with python compatible arguments
#[new] #[new]
pub fn py_new(success_ratio_target: u8, url_strs: Vec<String>, timeout: u64) -> Self { pub fn py_new(success_ratio_target: u8, urls: Vec<String>, timeout: u64) -> Self {
Self::new(success_ratio_target, &url_strs, timeout) Self::new(success_ratio_target, urls, timeout)
} }
/// Same as [`check()`](UptimeStatus::check) /// Same as [`check()`](UptimeStatus::check)
@ -168,23 +170,6 @@ impl UptimeStatus {
self.calc_success(); self.calc_success();
} }
/// ## get urls for python
///
/// Since [`UptimeStatus::urls`] has no python equivalent, return the urls as a `list[str]` in
/// Python.
///
/// Practically, this is also handy for rust implementations that want to access the URLs as
/// [Strings](String).
pub fn urls(&self) -> Vec<String> {
let mut url_strs: Vec<String> = Vec::new();
for url in self.urls.clone() {
url_strs.push(url.to_string());
}
return url_strs;
}
/// we want to display the [`UptimeStatus`] in python too, so we need `__str__` /// we want to display the [`UptimeStatus`] in python too, so we need `__str__`
pub fn __str__(&self) -> String { pub fn __str__(&self) -> String {
format!("{}", self) format!("{}", self)
@ -199,36 +184,22 @@ impl UptimeStatus {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl fmt::Debug for UptimeStatus { impl fmt::Debug for UptimeStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut url_strs: Vec<&str> = Vec::new(); let mut urls: Vec<&str> = Vec::new();
for url in &self.urls { for url in &self.urls {
url_strs.push(url.as_str()); urls.push(url.as_str());
} }
write!( write!(f, "{}", serde_json::to_string(self).unwrap())
f,
concat!(
"{{ success: {}, success_ratio: {}%, success_ratio_target: {}%,",
" reachable: {}, urls: {:?}}}"
),
self.success, self.success_ratio, self.success_ratio_target, self.reachable, url_strs
)
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl fmt::Display for UptimeStatus { impl fmt::Display for UptimeStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut url_strs: Vec<&str> = Vec::new(); let mut urls: Vec<&str> = Vec::new();
for url in &self.urls { for url in &self.urls {
url_strs.push(url.as_str()); urls.push(url.as_str());
} }
write!( write!(f, "{}", serde_json::to_string_pretty(self).unwrap())
f,
concat!(
"{{\n\tsuccess: {},\n\tsuccess_ratio: {}%,\n\tsuccess_ratio_target: {}%,\n",
"\treachable: {},\n\turls: {:?}\n}}"
),
self.success, self.success_ratio, self.success_ratio_target, self.reachable, url_strs
)
} }
} }
@ -240,7 +211,12 @@ impl fmt::Display for UptimeStatus {
/// On change of status, an update will be logged at [INFO Level](log::Level::Info), containing /// On change of status, an update will be logged at [INFO Level](log::Level::Info), containing
/// information on your current status, including timestamps of the last up/down time and durations /// information on your current status, including timestamps of the last up/down time and durations
/// since. /// since.
pub fn continuous_uptime_monitor(success_ratio_target: u8, urls: Vec<String>, interval: u64, timeout: u64) { pub fn continuous_uptime_monitor(
success_ratio_target: u8,
urls: Vec<String>,
interval: u64,
timeout: u64,
) {
if urls.len() == 0 { if urls.len() == 0 {
error!("No URLs provided. There is nothing to monitor."); error!("No URLs provided. There is nothing to monitor.");
return; return;
@ -249,7 +225,7 @@ pub fn continuous_uptime_monitor(success_ratio_target: u8, urls: Vec<String>, in
let interval = std::time::Duration::from_millis(interval); let interval = std::time::Duration::from_millis(interval);
let mut last_downtime: Option<SystemTime> = None; let mut last_downtime: Option<SystemTime> = None;
let mut last_uptime: Option<SystemTime> = None; let mut last_uptime: Option<SystemTime> = None;
let mut status = UptimeStatus::new(success_ratio_target, &urls, timeout); let mut status = UptimeStatus::new(success_ratio_target, urls, timeout);
let mut last_was_up: bool = false; let mut last_was_up: bool = false;
let mut last_ratio: u8 = status.success_ratio; let mut last_ratio: u8 = status.success_ratio;
loop { loop {
@ -295,7 +271,7 @@ pub fn py_continuous_uptime_monitor(
success_ratio_target: u8, success_ratio_target: u8,
urls: Vec<String>, urls: Vec<String>,
interval: u64, interval: u64,
timeout: u64 timeout: u64,
) -> PyResult<()> { ) -> PyResult<()> {
// execute the function in a different thread // execute the function in a different thread
let _th = std::thread::spawn(move || { let _th = std::thread::spawn(move || {