diff --git a/members/pt/src/bin/ccc/mod.rs b/members/pt-bin/src/ccc/mod.rs similarity index 100% rename from members/pt/src/bin/ccc/mod.rs rename to members/pt-bin/src/ccc/mod.rs diff --git a/members/pt/src/bin/main/args.rs b/members/pt-bin/src/main/args.rs similarity index 100% rename from members/pt/src/bin/main/args.rs rename to members/pt-bin/src/main/args.rs diff --git a/members/pt/src/bin/main/mod.rs b/members/pt-bin/src/main/mod.rs similarity index 100% rename from members/pt/src/bin/main/mod.rs rename to members/pt-bin/src/main/mod.rs diff --git a/members/pt/src/common/mod.rs b/members/pt-core/src/lib.rs similarity index 100% rename from members/pt/src/common/mod.rs rename to members/pt-core/src/lib.rs diff --git a/members/pt/src/common/macros.rs b/members/pt-core/src/macros.rs similarity index 100% rename from members/pt/src/common/macros.rs rename to members/pt-core/src/macros.rs diff --git a/members/pt-core/src/main.rs b/members/pt-core/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/members/pt-core/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/members/pt/src/common/printing.rs b/members/pt-core/src/printing.rs similarity index 100% rename from members/pt/src/common/printing.rs rename to members/pt-core/src/printing.rs diff --git a/members/pt-math/Cargo.toml b/members/pt-math/Cargo.toml new file mode 100644 index 0000000..e16fef6 --- /dev/null +++ b/members/pt-math/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "pt-math" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/members/pt-math/src/lib.rs b/members/pt-math/src/lib.rs new file mode 100644 index 0000000..7d12d9a --- /dev/null +++ b/members/pt-math/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/members/pt-net/Cargo.toml b/members/pt-net/Cargo.toml index cbf11a2..5b97214 100644 --- a/members/pt-net/Cargo.toml +++ b/members/pt-net/Cargo.toml @@ -6,3 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +humantime = "2.1.0" +pt-core = { version = "0.1.0", path = "../pt-core" } +pt-log = { version = "0.1.0", path = "../pt-log" } +pt-math = { version = "0.1.0", path = "../pt-math" } +reqwest = { version = "0.11.20", features = ["blocking"] } +serde = { version = "1.0.188", features = ["serde_derive"] } +serde_json = "1.0.107" diff --git a/members/pt/src/networking/mod.rs b/members/pt-net/src/lib.rs similarity index 100% rename from members/pt/src/networking/mod.rs rename to members/pt-net/src/lib.rs diff --git a/members/pt-net/src/main.rs b/members/pt-net/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/members/pt-net/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/members/pt/src/networking/monitoring/mod.rs b/members/pt-net/src/monitoring/mod.rs similarity index 100% rename from members/pt/src/networking/monitoring/mod.rs rename to members/pt-net/src/monitoring/mod.rs diff --git a/members/pt/src/networking/monitoring/uptime.rs b/members/pt-net/src/monitoring/uptime.rs similarity index 83% rename from members/pt/src/networking/monitoring/uptime.rs rename to members/pt-net/src/monitoring/uptime.rs index f561530..6302b99 100644 --- a/members/pt/src/networking/monitoring/uptime.rs +++ b/members/pt-net/src/monitoring/uptime.rs @@ -19,19 +19,17 @@ use std::{fmt, time::Duration}; //// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// -use crate::logger::*; +use pt_log::*; use reqwest; use humantime::{format_duration, format_rfc3339}; use std::time::SystemTime; -use pyo3::prelude::*; - use serde::{Deserialize, Serialize}; use serde_json; -use crate::divider; +use pt_core::divider; //// TYPES ///////////////////////////////////////////////////////////////////////////////////////// @@ -50,27 +48,20 @@ pub const DEFAULT_CHECK_URLS: &'static [&'static str] = /// ## Describes an uptime status /// /// [`UptimeStatus`] describes the result of an uptime check. -#[pyclass] #[derive(Serialize, Deserialize)] pub struct UptimeStatus { /// true if the [`UptimeStatus`] is considered successful - #[pyo3(get, set)] pub success: bool, /// the percentage of reachable urls out of the total urls - #[pyo3(get, set)] pub success_ratio: u8, /// 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. - #[pyo3(get, set)] pub success_ratio_target: u8, /// the number of reachable [`urls`](UptimeStatus::urls) - #[pyo3(get, set)] pub reachable: usize, /// which urls to check in [`check()`](UptimeStatus::check) - #[pyo3(get, set)] pub urls: Vec, /// timeout length for requests (in ms) - #[pyo3(get, set)] pub timeout: u64, } @@ -146,38 +137,6 @@ impl UptimeStatus { trace!("calculated success as: {}", self.success) } } -//////////////////////////////////////////////////////////////////////////////////////////////////// -/// Implementation of the Python interface -#[pymethods] -impl UptimeStatus { - /// calls [`new()`](UptimeStatus::new) with python compatible arguments - #[new] - pub fn py_new(success_ratio_target: u8, urls: Vec, timeout: u64) -> Self { - Self::new(success_ratio_target, urls, timeout) - } - - /// Same as [`check()`](UptimeStatus::check) - #[pyo3(name = "check")] - pub fn py_check(&mut self) { - self.check(); - } - - /// Same as [`calc_success()`](UptimeStatus::calc_success) - #[pyo3(name = "calc_success")] - pub fn py_calc_success(&mut self) { - self.calc_success(); - } - - /// we want to display the [`UptimeStatus`] in python too, so we need `__str__` - pub fn __str__(&self) -> String { - format!("{}", self) - } - - /// we want to debug display the [`UptimeStatus`] in python too, so we need `__str__` - pub fn __repr__(&self) -> String { - format!("{:?}", self) - } -} //////////////////////////////////////////////////////////////////////////////////////////////////// impl fmt::Debug for UptimeStatus { @@ -261,30 +220,6 @@ pub fn continuous_uptime_monitor( } } -//////////////////////////////////////////////////////////////////////////////////////////////////// -/// Python interface for [`continuous_uptime_monitor`] -/// -/// Runs the function in a different thread and checks from time to time for things like Pythons -/// `KeyboardInterrupt` exception. -#[pyfunction] -#[pyo3(name = "continuous_uptime_monitor")] -pub fn py_continuous_uptime_monitor( - py: Python, - success_ratio_target: u8, - urls: Vec, - interval: u64, - timeout: u64, -) -> PyResult<()> { - // execute the function in a different thread - let _th = std::thread::spawn(move || { - continuous_uptime_monitor(success_ratio_target, urls, interval, timeout); - }); - loop { - Python::check_signals(py)?; - std::thread::sleep(std::time::Duration::from_millis(100)) - } -} - //// PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////// /// Displays the current status for the [continuous uptime monitor](continuous_uptime_monitor) fn display_uptime_status( diff --git a/members/pt/Cargo.toml b/members/pt/Cargo.toml index 9099e7d..e746e81 100644 --- a/members/pt/Cargo.toml +++ b/members/pt/Cargo.toml @@ -19,14 +19,15 @@ categories = ["command-line-utilities", "development-tools", "development-tools: [lib] name = "pt" crate-type = ["cdylib", "rlib"] +path = "src/lib.rs" [[bin]] name = "pt" -path = "src/bin/main/mod.rs" +path = "../members/pt-bin/src/main/mod.rs" [[bin]] name = "ccc" -path = "src/bin/ccc/mod.rs" +path = "../members/pt-bin/src/ccc/mod.rs" [dependencies] clap = { version = "4.3.11", features = ["derive"] } diff --git a/members/pt/src/logger/error.rs b/members/pt/src/logger/error.rs deleted file mode 100644 index d30d1c7..0000000 --- a/members/pt/src/logger/error.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! # very short description -//! -//! Short description -//! -//! Details -//! -//! ## Section 1 -//! -//! ## Section 2 - -//// 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)] - -//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// -use pyo3::{exceptions::PyException, PyErr}; -use tracing::subscriber::SetGlobalDefaultError; - -//// TYPES ///////////////////////////////////////////////////////////////////////////////////////// -/// a quick alias for a result with a [`LoggerError`] -pub type Result = std::result::Result; - -//// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// - -//// STATICS /////////////////////////////////////////////////////////////////////////////////////// - -//// MACROS //////////////////////////////////////////////////////////////////////////////////////// - -//// ENUMS ///////////////////////////////////////////////////////////////////////////////////////// -/// ## Errors for the [logger](crate::logger) -pub enum Error { - /// Bad IO operation - IO(std::io::Error), - /// Various errors raised when the messenger is used in a wrong way - Usage(String), - /// Could not assign logger as the global default - SetGlobalDefaultFail(SetGlobalDefaultError), -} - -//// STRUCTS /////////////////////////////////////////////////////////////////////////////////////// - -//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// -impl From for Error { - fn from(value: std::io::Error) -> Self { - Error::IO(value) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -impl From for Error { - fn from(value: SetGlobalDefaultError) -> Self { - Error::SetGlobalDefaultFail(value) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -impl Into for Error { - fn into(self) -> PyErr { - match self { - Error::IO(err) => PyException::new_err(format!("LoggerError: IO {err:?}")), - Error::Usage(err) => PyException::new_err(format!("LoggerError: Usage {err}")), - Error::SetGlobalDefaultFail(err) => { - PyException::new_err(format!("LoggerError: SetGlobalDefaultFail {err}")) - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -impl std::fmt::Debug for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Error::IO(e) => write!(f, ""), - Error::Usage(e) => write!(f, ""), - Error::SetGlobalDefaultFail(e) => write!(f, ""), - } - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Error::IO(e) => write!(f, "IO Error {e}"), - Error::Usage(e) => write!(f, "Usage Error {e}"), - Error::SetGlobalDefaultFail(e) => write!(f, "SetGlobalDefaultFail {e}"), - } - } -} - -//// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// - -//// PRIVATE FUNCTIONS ///////////////////////////////////////////////////////////////////////////// diff --git a/members/pt/src/logger/mod.rs b/members/pt/src/logger/mod.rs deleted file mode 100644 index 09ac4b9..0000000 --- a/members/pt/src/logger/mod.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! # A specialized Logger for [`pt`](crate) -//! -//! For the library version, only the basic [`log`] is used, so that it is possible for -//! the end user to use the [`log`] frontend they desire. -//! -//! I did however decide to create a [`Logger`] struct. This struct is mainly intended to be used -//! with the python module of [`pt`](crate), but is still just as usable in other contexts. -//! -//! ## Technologies used for logging: -//! - [`log`]: base logging crate -//! - [`env_logger`]: used for the executable - -//// ATTRIBUTES //////////////////////////////////////////////////////////////////////////////////// - -//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// -use std::{ - fmt, - path::PathBuf, - sync::atomic::{AtomicBool, Ordering}, -}; - -pub mod error; -use error::*; - -pub use tracing::{debug, error, info, trace, warn, Level}; -use tracing_appender; -use tracing_subscriber::{prelude::*, fmt::format::FmtSpan}; - -use pyo3::prelude::*; -//// CONSTANTS ///////////////////////////////////////////////////////////////////////////////////// -/// The log level used when none is specified -pub const DEFAULT_LOG_LEVEL: Level = Level::INFO; -/// The path where logs are stored when no path is given. -/// -/// Currently, this is `/dev/null`, meaning they will be written to the void = discarded. -pub const DEFAULT_LOG_DIR: &'static str = "/dev/null"; - -//// STATICS /////////////////////////////////////////////////////////////////////////////////////// -static INITIALIZED: AtomicBool = AtomicBool::new(false); - -//// STRUCTS /////////////////////////////////////////////////////////////////////////////////////// -/// ## Logger for [`pt`](crate) -/// -/// This struct exists mainly for the python module, so that we can use the same logger with both -/// python and rust. -/// -/// ### Setting a [`Level`](log::Level) -/// -/// To set a [`Level`](log::Level), you need to set the environment variable `LIBPT_LOGLEVEL` -/// to either of: -/// -/// - `Trace` -/// - `Debug` -/// - `Info` -/// - `Warn` -/// - `Error` -#[pyclass] -pub struct Logger {} - -//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// -/// ## Main implementation -impl Logger { - /// ## create a `Logger` - /// - /// Creates a new uninitialized [`Logger`] object. - pub fn new() -> Self { - let l = Logger {}; - l - } - /// ## initializes the logger - /// - /// Will enable the logger to be used. - /// - /// Assumes some defaults, use [`init_customized`](init_customized) for more control - pub fn init(log_dir: Option, max_level: Option) -> Result<()> { - Self::init_customized( - log_dir.is_some(), - log_dir.unwrap_or(PathBuf::from(DEFAULT_LOG_DIR)), - true, - false, - true, - false, - max_level.unwrap_or(DEFAULT_LOG_LEVEL), - false, - false, - false, - ) - } - - /// ## initializes the logger - /// - /// Will enable the logger to be used. - pub fn init_customized( - log_to_file: bool, - log_dir: PathBuf, - ansi: bool, - display_filename: bool, - display_level: bool, - display_target: bool, - max_level: Level, - display_thread_ids: bool, - display_thread_names: bool, - display_line_number: bool, - ) -> Result<()> { - // only init if no init has been performed yet - if INITIALIZED.load(Ordering::Relaxed) { - warn!("trying to reinitialize the logger, ignoring"); - return Err(Error::Usage(format!("logging is already initialized"))); - } else { - let filter = tracing_subscriber::filter::FilterFn::new(|metadata| { - // let mut filter = false; - // - // // if it's this lib, continue - // filter |= metadata.target().contains(env!("CARGO_PKG_NAME")); - // filter |= metadata.target().contains("pt"); - // - // // if it's another crate, only show above debug - // filter |= metadata.level() > &Level::DEBUG; - // - // filter - // FIXME: Make the filter customizable with sane defaults. Don't block the - // executing crate. - true - }); - - let basic_subscriber = tracing_subscriber::fmt::Subscriber::builder() - // subscriber configuration - .with_ansi(ansi) - .with_file(display_filename) - .with_level(display_level) - .with_target(display_target) - .with_max_level(max_level) - .with_thread_ids(display_thread_ids) - .with_line_number(display_line_number) - .with_thread_names(display_thread_names) - .with_span_events(FmtSpan::FULL) - //.pretty // too verbose and over multiple lines, a bit like python tracebacks - .finish() - // add layers - .with(filter); - - if log_to_file { - let file_appender = tracing_appender::rolling::daily(log_dir, "log"); - let (file_writer, _guard) = tracing_appender::non_blocking(file_appender); - let layered_subscriber = basic_subscriber - .with(tracing_subscriber::fmt::Layer::default().with_writer(file_writer)); - tracing::subscriber::set_global_default(layered_subscriber)?; - } else { - tracing::subscriber::set_global_default(basic_subscriber)?; - } - - INITIALIZED.store(true, Ordering::Relaxed); - Ok(()) - } - } - - /// ## logging at [`Level::Error`] - pub fn error(&self, printable: T) - where - T: fmt::Display, - { - error!("{}", printable) - } - /// ## logging at [`Level::Warn`] - pub fn warn(&self, printable: T) - where - T: fmt::Display, - { - warn!("{}", printable) - } - /// ## logging at [`Level::Info`] - pub fn info(&self, printable: T) - where - T: fmt::Display, - { - info!("{}", printable) - } - /// ## logging at [`Level::Debug`] - pub fn debug(&self, printable: T) - where - T: fmt::Display, - { - debug!("{}", printable) - } - /// ## logging at [`Level::Trace`] - pub fn trace(&self, printable: T) - where - T: fmt::Display, - { - trace!("{}", printable) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -/// ## Implementation of the python interface -#[pymethods] -impl Logger { - /// ## Python version of [`new()`](Logger::new) - #[new] - pub fn py_new() -> PyResult { - Ok(Logger::new()) - } - /// ## Python version of [`init()`](Logger::init) - #[pyo3(name = "init")] - #[staticmethod] - pub fn py_init(log_dir: Option, max_level: Option) -> Result<()> { - Self::init( - log_dir, - match max_level { - Some(s) => match s.to_uppercase().as_str() { - "TRACE" => Some(tracing::Level::TRACE), - "DEBUG" => Some(tracing::Level::DEBUG), - "INFO" => Some(tracing::Level::INFO), - "WARN" => Some(tracing::Level::WARN), - "ERROR" => Some(tracing::Level::ERROR), - _ => return Err(Error::Usage(format!("'{s}' is not a valid log level"))), - }, - None => None, - }, - ) - } - /// ## Python version of [`error()`](Logger::error) - #[pyo3(name = "error")] - pub fn py_error(&self, printable: String) { - self.error(printable) - } - /// ## Python version of [`warn()`](Logger::warn) - #[pyo3(name = "warn")] - pub fn py_warn(&self, printable: String) { - self.warn(printable) - } - /// ## Python version of [`info()`](Logger::info) - #[pyo3(name = "info")] - pub fn py_info(&self, printable: String) { - self.info(printable) - } - /// ## Python version of [`debug()`](Logger::debug) - #[pyo3(name = "debug")] - pub fn py_debug(&self, printable: String) { - self.debug(printable) - } - /// ## Python version of [`trace()`](Logger::trace) - #[pyo3(name = "trace")] - pub fn py_trace(&self, printable: String) { - self.trace(printable) - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -impl fmt::Debug for Logger { - /// ## Debug representation for [`Logger`] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Logger: {{initialized: {}}} ", - INITIALIZED.load(Ordering::Relaxed) - ) - } -} - -//// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// - -//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////