From 763f7346499de54c858b85593ba13609bc893e53 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sat, 8 Jul 2023 23:14:32 +0200 Subject: [PATCH] monitoring base basic check_uptime works --- Cargo.toml | 3 + README.md | 1 + src/bin/main/args.rs | 45 +++++++---- src/bin/main/mod.rs | 39 ++++++---- src/common/mod.rs | 1 + src/common/printing.rs | 0 src/networking/monitoring/mod.rs | 1 + src/networking/monitoring/uptime.rs | 113 ++++++++++++++++++++++++++++ src/template.rs | 2 + 9 files changed, 174 insertions(+), 31 deletions(-) create mode 100644 src/common/printing.rs create mode 100644 src/networking/monitoring/uptime.rs diff --git a/Cargo.toml b/Cargo.toml index 77901d6..dac060b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,12 @@ path = "src/bin/main/mod.rs" [dependencies] clap = { version = "4.3.11", features = ["derive"] } +clap-num = "1.0.2" clap-verbosity-flag = "2.0.1" env_logger = "0.10.0" gag = "1.0.0" log = { version = "0.4.19", features = ["max_level_trace", "release_max_level_trace"] } +num = "0.4.0" pyo3 = "0.18.1" regex = "1.9.1" +reqwest = { version = "0.11.18", features = ["blocking"] } diff --git a/README.md b/README.md index ceb9898..11beeac 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ So what? I don't care. Besides, there is not enough names to name everything uni ## Dependencies - See `cargo.toml` +- []openssl bindings for rust](https://docs.rs/openssl/latest/openssl/) - [Python](https://www.python.org/) - [`maturin`](https://maturin.rs) - `pip install maturin` diff --git a/src/bin/main/args.rs b/src/bin/main/args.rs index 707c5b3..75d8743 100644 --- a/src/bin/main/args.rs +++ b/src/bin/main/args.rs @@ -17,14 +17,18 @@ //// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// use clap::{Args, Parser, Subcommand}; +use clap_num::number_range; + use clap_verbosity_flag::Verbosity; //// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// +/// short about section displayed in help const ABOUT_ROOT: &'static str = r##" Personal multi tool A collection of tools made for personal use "##; +/// longer about section displayed in help, is combined with [the short help](ABOUT_ROOT) static LONG_ABOUT_ROOT: &'static str = r##" libpt is a personal general purpose library, offering this executable, a python module and a @@ -33,7 +37,7 @@ static LONG_ABOUT_ROOT: &'static str = r##" //// STATICS /////////////////////////////////////////////////////////////////////////////////////// /// ## Main struct for parsing CLI arguments -#[derive(Debug, Parser)] +#[derive(Debug, Clone, Parser)] #[command( author, version, @@ -57,14 +61,7 @@ pub struct Cli { } //////////////////////////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, Args)] -pub struct NetMonitorArgs { - #[clap(short)] - test: bool, -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, Args)] +#[derive(Debug, Clone, Args)] pub struct NetDiscoverArgs { #[clap(short)] test: bool, @@ -72,7 +69,7 @@ pub struct NetDiscoverArgs { //// ENUMS ///////////////////////////////////////////////////////////////////////////////////////// /// # Top level commands -#[derive(Debug, Subcommand)] +#[derive(Debug, Clone, Subcommand)] #[non_exhaustive] pub enum Commands { /// networking commands @@ -83,15 +80,29 @@ pub enum Commands { } //////////////////////////////////////////////////////////////////////////////////////////////////// -#[derive(Debug, Subcommand)] +#[derive(Debug, Clone, Subcommand)] #[non_exhaustive] pub enum NetCommands { - /// monitoring - Monitor(NetMonitorArgs), - /// - Discover(NetDiscoverArgs), + /// monitor your network + Monitor { + #[clap(short, long)] + repeat: bool, + + #[clap(short, long, default_value_t = 100, value_parser=max100)] + percentage_for_success: u8, + + #[arg(default_values_t = ["https://cloudflare.com".to_string()])] + additional_domains: Vec, + + }, + /// discover hosts in your network + Discover { + + } } +//////////////////////////////////////////////////////////////////////////////////////////////////// + //// STRUCTS /////////////////////////////////////////////////////////////////////////////////////// //// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// @@ -99,3 +110,7 @@ pub enum NetCommands { //// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// //// PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////// +/// custom value parser, only allow 0 to 100 +fn max100(s: &str) -> Result { + number_range(s, 0, 100) +} diff --git a/src/bin/main/mod.rs b/src/bin/main/mod.rs index 7bf26e6..6d3f84c 100644 --- a/src/bin/main/mod.rs +++ b/src/bin/main/mod.rs @@ -11,11 +11,12 @@ // enable clippy's extra lints, the pedantic version #![warn(clippy::pedantic)] -use std::process::exit; - //// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// +use libpt::networking::monitoring::uptime; use libpt::logger; +// we want the log macros in any case +#[allow(unused_imports)] use log::{debug, error, info, trace, warn}; use env_logger; @@ -26,8 +27,6 @@ mod args; use args::*; //// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// -/// Exit code: Bad command line argument -const EXIT_BAD_ARG: i32 = 1; //// STATICS /////////////////////////////////////////////////////////////////////////////////////// @@ -49,27 +48,35 @@ fn main() { let cli = Cli::parse(); // set up our logger to use the given verbosity - env_logger::Builder::new().filter_level(cli.verbose.log_level_filter()).init(); + env_logger::Builder::new() + .filter_level(cli.verbose.log_level_filter()) + .init(); trace!("started the main function"); - trace!("{:?}", cli); + trace!("{:?}", &cli); - match cli.command { - Commands::Net { command } => { - net(command) - } + match cli.clone().command { + Commands::Net { command } => net(&cli, command), } } //////////////////////////////////////////////////////////////////////////////////////////////////// /// ## Process `Net` subcommands -fn net(command: NetCommands) { +fn net(cli: &Cli, command: NetCommands) { match command { - NetCommands::Monitor(args) => { - dbg!(args); - } - NetCommands::Discover(args) => { - dbg!(args); + NetCommands::Monitor { + repeat, + percentage_for_success, + additional_domains, + } => { + let status: uptime::UptimeStatus = uptime::check_status( + additional_domains, + percentage_for_success, + ); + let _verbose = cli.verbose.log_level().is_some(); + println!("{}", uptime::display_uptime_status(status)); + } + NetCommands::Discover {} => {} } } diff --git a/src/common/mod.rs b/src/common/mod.rs index acc9031..c2af571 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -18,6 +18,7 @@ //// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// pub mod macros; +pub mod printing; //// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// diff --git a/src/common/printing.rs b/src/common/printing.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/networking/monitoring/mod.rs b/src/networking/monitoring/mod.rs index 5f1cda0..22d84ed 100644 --- a/src/networking/monitoring/mod.rs +++ b/src/networking/monitoring/mod.rs @@ -16,6 +16,7 @@ #![warn(clippy::pedantic)] //// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// +pub mod uptime; //// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// diff --git a/src/networking/monitoring/uptime.rs b/src/networking/monitoring/uptime.rs new file mode 100644 index 0000000..e1fd56d --- /dev/null +++ b/src/networking/monitoring/uptime.rs @@ -0,0 +1,113 @@ +//! # monitor your network uptime +//! +//! This method offers a way to monitor your networks/hosts uptime. This is achieved by making +//! https requests to a given list of + +//// ATTRIBUTES //////////////////////////////////////////////////////////////////////////////////// +// we want docs +#![warn(missing_docs)] +#![warn(rustdoc::missing_crate_level_docs)] +//////////////////////////////////////////////////////////////////////////////////////////////////// +// we want Debug everywhere. +#![warn(missing_debug_implementations)] +//////////////////////////////////////////////////////////////////////////////////////////////////// +// enable clippy's extra lints, the pedantic version +#![warn(clippy::pedantic)] + +use std::{fmt::Display, str::FromStr}; + +//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// +// we want the log macros in any case +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use reqwest; + +//// TYPES ///////////////////////////////////////////////////////////////////////////////////////// +pub type UptimeStatus = (bool, usize, usize); + +//// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// + +//// STATICS /////////////////////////////////////////////////////////////////////////////////////// + +//// MACROS //////////////////////////////////////////////////////////////////////////////////////// + +//// ENUMS ///////////////////////////////////////////////////////////////////////////////////////// + +//// STRUCTS /////////////////////////////////////////////////////////////////////////////////////// + +//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// + +//// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// +/// ## check uptime status +/// +/// This function checks the current network status. +/// +/// ### Parameters +/// additional_urls +/// +/// ### Returns +/// The function returns a tuple of the format +/// +/// `(status: [bool], reachable: [usize], checked: [usize])` +/// +/// #### `status` +/// Will be `true` if the check is considered a success. +pub fn check_status(urls_strs: Vec, percentage_for_success: u8) -> UptimeStatus { + if percentage_for_success > 100 { + panic!("percentage_for_success is over 100: {percentage_for_success}") + } + let status: bool; + let mut reachable: usize = 0; + let total: usize = urls_strs.len(); + + info!("checking with the following URLs: {:?}", urls_strs); + + let mut urls: Vec = Vec::new(); + for s in urls_strs { + let url = reqwest::Url::from_str(&s); + if url.is_ok() { + urls.push(url.unwrap()); + } else { + warn!("Invalid URL: '{}", s); + } + } + // make urls not mutable + let urls = urls; + + for url in urls { + let response = reqwest::blocking::get(url); + if response.is_ok() { + reachable += 1 + } + } + + // evaluate the status + if total != 0 { + info!("reachability ratio: {}", ((reachable as f32) / total as f32) * 100f32); + status = ((reachable as f32) / total as f32) * 100f32 >= percentage_for_success as f32; + } else { + // no reachable domains at all! + info!("no valid services given"); + status = true; + } + + return (status, reachable, total); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +/// ## display UptimeStatus +/// +/// returns a fancy string that shows the UptimeStatus, so you can print it to the user. +pub fn display_uptime_status(status: UptimeStatus) -> String { + format!( + r"{{ + success: {}, + reachable: {}, + checked: {} +}}", + status.0, status.1, status.2 + ) +} + +//// PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////// diff --git a/src/template.rs b/src/template.rs index e3c1dc2..dac9d32 100644 --- a/src/template.rs +++ b/src/template.rs @@ -19,6 +19,8 @@ //// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// +//// TYPES ///////////////////////////////////////////////////////////////////////////////////////// + //// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// //// STATICS ///////////////////////////////////////////////////////////////////////////////////////