From 1a780226d32821448fb8c9024586aa481197a479 Mon Sep 17 00:00:00 2001 From: hinto-janaiyo <hinto.janaiyo@protonmail.com> Date: Tue, 27 Dec 2022 19:46:46 -0500 Subject: [PATCH] Status Submenu: add [PayoutOrd] parse & update from log --- README.md | 2 +- src/helper.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d73e58d..f281a62 100644 --- a/README.md +++ b/README.md @@ -482,7 +482,7 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x. -There are `26` unit tests throughout the codebase files, you should probably run: +There are `28` unit tests throughout the codebase files, you should probably run: ``` cargo test ``` diff --git a/src/helper.rs b/src/helper.rs index c1afca3..8bf25a0 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -1182,6 +1182,9 @@ impl Helper { struct P2poolRegex { payout: regex::Regex, float: regex::Regex, + date: regex::Regex, + block: regex::Regex, + int: regex::Regex, } impl P2poolRegex { @@ -1189,6 +1192,9 @@ impl P2poolRegex { Self { payout: regex::Regex::new("payout of [0-9].[0-9]+ XMR").unwrap(), float: regex::Regex::new("[0-9].[0-9]+").unwrap(), + date: regex::Regex::new("[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+").unwrap(), + block: regex::Regex::new("block [0-9]+").unwrap(), + int: regex::Regex::new("[0-9]+").unwrap(), } } } @@ -1210,6 +1216,10 @@ impl AtomicUnit { Self(sum) } + fn from_f64(f: f64) -> Self { + Self((f * 1_000_000_000_000.0) as u128) + } + fn to_f64(&self) -> f64 { self.0 as f64 / 1_000_000_000_000.0 } @@ -1249,6 +1259,56 @@ impl PayoutOrd { Self(vec![(String::from("????-??-?? ??:??:??.????"), AtomicUnit::new(), HumanNumber::unknown())]) } + // Takes in input of ONLY P2Pool payout logs and + // converts it into a usable [PayoutOrd] + // It expects log lines like this: + // "NOTICE 2022-04-11 00:20:17.2571 P2Pool You received a payout of 0.001371623621 XMR in block 2562511" + // For efficiency reasons, I'd like to know the byte size + // we should allocate for the vector so we aren't adding every loop. + // Given a log [str], the equation for how many bytes the final vec will be is: + // (BYTES_OF_DATE + BYTES OF XMR + BYTES OF BLOCK) * amount_of_lines + // The first three are more or less constants (monero block 10m is in 10,379 years...): [23, 14, 7] (sum: 44) + // Add 16 more bytes for wrapper type overhead and it's an even [60] bytes per line. + fn update_from_payout_log(&mut self, log: &str, regex: &P2poolRegex) { + let amount_of_lines = log.lines().count(); + let mut vec: Vec<(String, AtomicUnit, HumanNumber)> = Vec::with_capacity(60 * amount_of_lines); + for line in log.lines() { + // Date + let date = match regex.date.find(line) { + Some(date) => date.as_str().to_string(), + None => { error!("P2Pool | Date parse error: [{}]", line); "????-??-?? ??:??:??.????".to_string() }, + }; + // AtomicUnit + let atomic_unit = if let Some(word) = regex.payout.find(line) { + if let Some(word) = regex.float.find(word.as_str()) { + match word.as_str().parse::<f64>() { + Ok(au) => AtomicUnit::from_f64(au), + Err(e) => { error!("P2Pool | AtomicUnit parse error: [{}] on [{}]", e, line); AtomicUnit::new() }, + } + } else { + AtomicUnit::new() + } + } else { + AtomicUnit::new() + }; + // Block + let block = if let Some(word) = regex.block.find(line) { + if let Some(word) = regex.int.find(word.as_str()) { + match word.as_str().parse::<u64>() { + Ok(b) => HumanNumber::from_u64(b), + Err(e) => { error!("P2Pool | Block parse error: [{}] on [{}]", e, line); HumanNumber::unknown() }, + } + } else { + HumanNumber::unknown() + } + } else { + HumanNumber::unknown() + }; + vec.push((date, atomic_unit, block)); + } + *self = Self(vec); + } + // Takes the raw components (no wrapper types), convert them and pushes to existing [Self] fn push(&mut self, date: String, atomic_unit: u128, block: u64) { let atomic_unit = AtomicUnit(atomic_unit); @@ -1436,9 +1496,11 @@ impl PubP2poolApi { let mut sum: f64 = 0.0; let mut count: u128 = 0; for i in iter { - match regex.float.find(i.as_str()).unwrap().as_str().parse::<f64>() { - Ok(num) => { sum += num; count += 1; }, - Err(e) => error!("P2Pool | Total XMR sum calculation error: [{}]", e), + if let Some(word) = regex.float.find(i.as_str()) { + match word.as_str().parse::<f64>() { + Ok(num) => { sum += num; count += 1; }, + Err(e) => error!("P2Pool | Total XMR sum calculation error: [{}]", e), + } } } (count, sum) @@ -1885,7 +1947,28 @@ struct Result { #[cfg(test)] mod test { #[test] - fn sort_payout_ord() { + fn update_p2pool_payout_log() { + use crate::helper::PayoutOrd; + use crate::helper::P2poolRegex; + let log = +r#"NOTICE 2021-12-21 01:01:01.1111 P2Pool You received a payout of 0.001000000000 XMR in block 1 +NOTICE 2021-12-21 02:01:01.1111 P2Pool You received a payout of 0.002000000000 XMR in block 2 +NOTICE 2021-12-21 03:01:01.1111 P2Pool You received a payout of 0.003000000000 XMR in block 3 +"#; + let mut payout_ord = PayoutOrd::new(); + println!("BEFORE: {}", payout_ord); + PayoutOrd::update_from_payout_log(&mut payout_ord, log, &P2poolRegex::new()); + println!("AFTER: {}", payout_ord); + let should_be = +r#"2021-12-21 01:01:01.1111 | 0.001000000000 XMR | Block 1 +2021-12-21 02:01:01.1111 | 0.002000000000 XMR | Block 2 +2021-12-21 03:01:01.1111 | 0.003000000000 XMR | Block 3 +"#; + assert_eq!(payout_ord.to_string(), should_be) + } + + #[test] + fn sort_p2pool_payout_ord() { use crate::helper::PayoutOrd; use crate::helper::AtomicUnit; use crate::helper::HumanNumber;