From c8e5462d3378d6a5b239d17280219cbd54f65449 Mon Sep 17 00:00:00 2001 From: "hinto.janai" <hinto.janai@protonmail.com> Date: Wed, 19 Apr 2023 10:01:11 -0400 Subject: [PATCH] regex: `lazy_static` everything instead of function input --- src/constants.rs | 3 +- src/helper.rs | 96 ++++++++++++++++++++++++------------------------ src/main.rs | 13 +++---- src/p2pool.rs | 15 +++++--- src/regex.rs | 62 +++++++++++++++++++++---------- src/xmr.rs | 27 +++++++------- src/xmrig.rs | 19 ++++++---- 7 files changed, 133 insertions(+), 102 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 0e0d480..7c2330d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -91,10 +91,11 @@ pub const P2POOL_FAILED: &str = "P2Pool is offline and failed when exiting"; pub const P2POOL_MIDDLE: &str = "P2Pool is in the middle of (re)starting/stopping"; pub const P2POOL_SYNCING: &str = "P2Pool is still syncing. This indicator will turn GREEN when P2Pool is ready"; -pub const XMRIG_ALIVE: &str = "XMRig is online"; +pub const XMRIG_ALIVE: &str = "XMRig is online and mining"; pub const XMRIG_DEAD: &str = "XMRig is offline"; pub const XMRIG_FAILED: &str = "XMRig is offline and failed when exiting"; pub const XMRIG_MIDDLE: &str = "XMRig is in the middle of (re)starting/stopping"; +pub const XMRIG_NOT_MINING: &str = "XMRig is online, but not mining to any pool"; // This is the typical space added when using // [ui.separator()] or [ui.group()] diff --git a/src/helper.rs b/src/helper.rs index 934c680..0a5687b 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -47,7 +47,6 @@ use crate::{ SudoState, human::*, GupaxP2poolApi, - P2poolRegex, xmr::*, macros::*, RemoteNode, @@ -56,6 +55,10 @@ use sysinfo::SystemExt; use serde::{Serialize,Deserialize}; use sysinfo::{CpuExt,ProcessExt}; use log::*; +use crate::regex::{ + P2POOL_REGEX, + XMRIG_REGEX, +}; //---------------------------------------------------------------------------------------------------- Constants // The max amount of bytes of process output we are willing to @@ -182,7 +185,8 @@ impl Process { pub fn is_alive(&self) -> bool { self.state == ProcessState::Alive || self.state == ProcessState::Middle || - self.state == ProcessState::Syncing + self.state == ProcessState::Syncing || + self.state == ProcessState::NotMining } pub fn is_waiting(&self) -> bool { @@ -192,6 +196,10 @@ impl Process { pub fn is_syncing(&self) -> bool { self.state == ProcessState::Syncing } + + pub fn is_not_mining(&self) -> bool { + self.state == ProcessState::NotMining + } } //---------------------------------------------------------------------------------------------------- [Process*] Enum @@ -205,6 +213,9 @@ pub enum ProcessState { // Only for P2Pool, ORANGE. Syncing, + + // Only for XMRig, ORANGE. + NotMining, } impl Default for ProcessState { fn default() -> Self { Self::Dead } } @@ -267,14 +278,14 @@ impl Helper { } } - fn read_pty_p2pool(output_parse: Arc<Mutex<String>>, output_pub: Arc<Mutex<String>>, reader: Box<dyn std::io::Read + Send>, regex: P2poolRegex, gupax_p2pool_api: Arc<Mutex<GupaxP2poolApi>>) { + fn read_pty_p2pool(output_parse: Arc<Mutex<String>>, output_pub: Arc<Mutex<String>>, reader: Box<dyn std::io::Read + Send>, gupax_p2pool_api: Arc<Mutex<GupaxP2poolApi>>) { use std::io::BufRead; let mut stdout = std::io::BufReader::new(reader).lines(); while let Some(Ok(line)) = stdout.next() { // println!("{}", line); // For debugging. - if regex.payout.is_match(&line) { + if P2POOL_REGEX.payout.is_match(&line) { debug!("P2Pool PTY | Found payout, attempting write: {}", line); - let (date, atomic_unit, block) = PayoutOrd::parse_raw_payout_line(&line, ®ex); + let (date, atomic_unit, block) = PayoutOrd::parse_raw_payout_line(&line); let formatted_log_line = GupaxP2poolApi::format_payout(&date, &atomic_unit, &block); GupaxP2poolApi::add_payout(&mut lock!(gupax_p2pool_api), &formatted_log_line, date, atomic_unit, block); if let Err(e) = GupaxP2poolApi::write_to_all_files(&lock!(gupax_p2pool_api), &formatted_log_line) { error!("P2Pool PTY GupaxP2poolApi | Write error: {}", e); } @@ -496,16 +507,13 @@ impl Helper { let mut stdin = pair.master; drop(lock); - let regex = P2poolRegex::new(); - // 3. Spawn PTY read thread debug!("P2Pool | Spawning PTY read thread..."); let output_parse = Arc::clone(&lock!(process).output_parse); let output_pub = Arc::clone(&lock!(process).output_pub); let gupax_p2pool_api = Arc::clone(&gupax_p2pool_api); - let regex_clone = regex.clone(); thread::spawn(move || { - Self::read_pty_p2pool(output_parse, output_pub, reader, regex_clone, gupax_p2pool_api); + Self::read_pty_p2pool(output_parse, output_pub, reader, gupax_p2pool_api); }); let output_parse = Arc::clone(&lock!(process).output_parse); let output_pub = Arc::clone(&lock!(process).output_pub); @@ -657,7 +665,7 @@ impl Helper { // Always update from output debug!("P2Pool Watchdog | Starting [update_from_output()]"); - PubP2poolApi::update_from_output(&pub_api, &output_parse, &output_pub, start.elapsed(), ®ex, &process); + PubP2poolApi::update_from_output(&pub_api, &output_parse, &output_pub, start.elapsed(), &process); // Read [local] API debug!("P2Pool Watchdog | Attempting [local] API file read"); @@ -1369,12 +1377,12 @@ impl PubP2poolApi { // Essentially greps the output for [x.xxxxxxxxxxxx XMR] where x = a number. // It sums each match and counts along the way, handling an error by not adding and printing to console. - fn calc_payouts_and_xmr(output: &str, regex: &P2poolRegex) -> (u128 /* payout count */, f64 /* total xmr */) { - let iter = regex.payout.find_iter(output); + fn calc_payouts_and_xmr(output: &str) -> (u128 /* payout count */, f64 /* total xmr */) { + let iter = P2POOL_REGEX.payout.find_iter(output); let mut sum: f64 = 0.0; let mut count: u128 = 0; for i in iter { - if let Some(word) = regex.payout_float.find(i.as_str()) { + if let Some(word) = P2POOL_REGEX.payout_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), @@ -1390,7 +1398,6 @@ impl PubP2poolApi { output_parse: &Arc<Mutex<String>>, output_pub: &Arc<Mutex<String>>, elapsed: std::time::Duration, - regex: &P2poolRegex, process: &Arc<Mutex<Process>>, ) { // 1. Take the process's current output buffer and combine it with Pub (if not empty) @@ -1401,10 +1408,10 @@ impl PubP2poolApi { // 2. Parse the full STDOUT let mut output_parse = lock!(output_parse); - let (payouts_new, xmr_new) = Self::calc_payouts_and_xmr(&output_parse, regex); + let (payouts_new, xmr_new) = Self::calc_payouts_and_xmr(&output_parse); // Check for "SYNCHRONIZED" only if we aren't already. if lock!(process).state == ProcessState::Syncing { - if regex.synchronized.is_match(&output_parse) { + if P2POOL_REGEX.synchronized.is_match(&output_parse) { lock!(process).state = ProcessState::Alive; } } @@ -1917,37 +1924,32 @@ mod test { #[test] fn combine_gui_pub_p2pool_api() { - use crate::helper::PubP2poolApi; - let mut gui_api = PubP2poolApi::new(); - let mut pub_api = PubP2poolApi::new(); - pub_api.payouts = 1; - pub_api.payouts_hour = 2.0; - pub_api.payouts_day = 3.0; - pub_api.payouts_month = 4.0; - pub_api.xmr = 1.0; - pub_api.xmr_hour = 2.0; - pub_api.xmr_day = 3.0; - pub_api.xmr_month = 4.0; - println!("BEFORE - GUI_API: {:#?}\nPUB_API: {:#?}", gui_api, pub_api); - assert_ne!(gui_api, pub_api); - PubP2poolApi::combine_gui_pub_api(&mut gui_api, &mut pub_api); - println!("AFTER - GUI_API: {:#?}\nPUB_API: {:#?}", gui_api, pub_api); - assert_eq!(gui_api, pub_api); - pub_api.xmr = 2.0; - PubP2poolApi::combine_gui_pub_api(&mut gui_api, &mut pub_api); - assert_eq!(gui_api, pub_api); - assert_eq!(gui_api.xmr, 2.0); - assert_eq!(pub_api.xmr, 2.0); - } - - #[test] - fn build_p2pool_regex() { - crate::helper::P2poolRegex::new(); + use crate::helper::PubP2poolApi; + let mut gui_api = PubP2poolApi::new(); + let mut pub_api = PubP2poolApi::new(); + pub_api.payouts = 1; + pub_api.payouts_hour = 2.0; + pub_api.payouts_day = 3.0; + pub_api.payouts_month = 4.0; + pub_api.xmr = 1.0; + pub_api.xmr_hour = 2.0; + pub_api.xmr_day = 3.0; + pub_api.xmr_month = 4.0; + println!("BEFORE - GUI_API: {:#?}\nPUB_API: {:#?}", gui_api, pub_api); + assert_ne!(gui_api, pub_api); + PubP2poolApi::combine_gui_pub_api(&mut gui_api, &mut pub_api); + println!("AFTER - GUI_API: {:#?}\nPUB_API: {:#?}", gui_api, pub_api); + assert_eq!(gui_api, pub_api); + pub_api.xmr = 2.0; + PubP2poolApi::combine_gui_pub_api(&mut gui_api, &mut pub_api); + assert_eq!(gui_api, pub_api); + assert_eq!(gui_api.xmr, 2.0); + assert_eq!(pub_api.xmr, 2.0); } #[test] fn calc_payouts_and_xmr_from_output_p2pool() { - use crate::helper::{PubP2poolApi,P2poolRegex}; + use crate::helper::{PubP2poolApi}; use std::sync::{Arc,Mutex}; let public = Arc::new(Mutex::new(PubP2poolApi::new())); let output_parse = Arc::new(Mutex::new(String::from( @@ -1957,9 +1959,8 @@ mod test { ))); let output_pub = Arc::new(Mutex::new(String::new())); let elapsed = std::time::Duration::from_secs(60); - let regex = P2poolRegex::new(); let process = Arc::new(Mutex::new(Process::new(ProcessName::P2pool, "".to_string(), PathBuf::new()))); - PubP2poolApi::update_from_output(&public, &output_parse, &output_pub, elapsed, ®ex, &process); + PubP2poolApi::update_from_output(&public, &output_parse, &output_pub, elapsed, &process); let public = public.lock().unwrap(); println!("{:#?}", public); assert_eq!(public.payouts, 3); @@ -1974,7 +1975,7 @@ mod test { #[test] fn set_p2pool_synchronized() { - use crate::helper::{PubP2poolApi,P2poolRegex}; + use crate::helper::{PubP2poolApi}; use std::sync::{Arc,Mutex}; let public = Arc::new(Mutex::new(PubP2poolApi::new())); let output_parse = Arc::new(Mutex::new(String::from( @@ -1984,12 +1985,11 @@ mod test { ))); let output_pub = Arc::new(Mutex::new(String::new())); let elapsed = std::time::Duration::from_secs(60); - let regex = P2poolRegex::new(); let process = Arc::new(Mutex::new(Process::new(ProcessName::P2pool, "".to_string(), PathBuf::new()))); // It only gets checked if we're `Syncing`. process.lock().unwrap().state = ProcessState::Syncing; - PubP2poolApi::update_from_output(&public, &output_parse, &output_pub, elapsed, ®ex, &process); + PubP2poolApi::update_from_output(&public, &output_parse, &output_pub, elapsed, &process); println!("{:#?}", process); assert!(process.lock().unwrap().state == ProcessState::Alive); } diff --git a/src/main.rs b/src/main.rs index 481751b..9220362 100644 --- a/src/main.rs +++ b/src/main.rs @@ -158,7 +158,6 @@ pub struct App { version: &'static str, // Gupax version name_version: String, // [Gupax vX.X.X] img: Images, // Custom Struct holding pre-compiled bytes of [Images] - regex: Regexes, // Custom Struct holding pre-made [Regex]'s } impl App { @@ -264,7 +263,6 @@ impl App { version: GUPAX_VERSION, name_version: format!("Gupax {}", GUPAX_VERSION), img: Images::new(), - regex: Regexes::new(), }; //---------------------------------------------------------------------------------------------------- App init data that *could* panic info!("App Init | Getting EXE path..."); @@ -839,7 +837,7 @@ fn init_auto(app: &mut App) { // [Auto-P2Pool] if app.state.gupax.auto_p2pool { - if !Regexes::addr_ok(&app.regex, &app.state.p2pool.address) { + if !Regexes::addr_ok(&app.state.p2pool.address) { warn!("Gupax | P2Pool address is not valid! Skipping auto-p2pool..."); } else if !Gupax::path_is_file(&app.state.gupax.p2pool_path) { warn!("Gupax | P2Pool path is not a file! Skipping auto-p2pool..."); @@ -1527,14 +1525,15 @@ impl eframe::App for App { Alive => ui.add_sized([width, height], Label::new(RichText::new("P2Pool ⏺").color(GREEN))).on_hover_text(P2POOL_ALIVE), Dead => ui.add_sized([width, height], Label::new(RichText::new("P2Pool ⏺").color(GRAY))).on_hover_text(P2POOL_DEAD), Failed => ui.add_sized([width, height], Label::new(RichText::new("P2Pool ⏺").color(RED))).on_hover_text(P2POOL_FAILED), - Middle|Waiting => ui.add_sized([width, height], Label::new(RichText::new("P2Pool ⏺").color(YELLOW))).on_hover_text(P2POOL_MIDDLE), Syncing => ui.add_sized([width, height], Label::new(RichText::new("P2Pool ⏺").color(ORANGE))).on_hover_text(P2POOL_SYNCING), + Middle|Waiting|NotMining => ui.add_sized([width, height], Label::new(RichText::new("P2Pool ⏺").color(YELLOW))).on_hover_text(P2POOL_MIDDLE), }; ui.separator(); match xmrig_state { Alive => ui.add_sized([width, height], Label::new(RichText::new("XMRig ⏺").color(GREEN))).on_hover_text(XMRIG_ALIVE), Dead => ui.add_sized([width, height], Label::new(RichText::new("XMRig ⏺").color(GRAY))).on_hover_text(XMRIG_DEAD), Failed => ui.add_sized([width, height], Label::new(RichText::new("XMRig ⏺").color(RED))).on_hover_text(XMRIG_FAILED), + NotMining => ui.add_sized([width, height], Label::new(RichText::new("XMRig ⏺").color(ORANGE))).on_hover_text(XMRIG_NOT_MINING), Middle|Waiting|Syncing => ui.add_sized([width, height], Label::new(RichText::new("XMRig ⏺").color(YELLOW))).on_hover_text(XMRIG_MIDDLE), }; }); @@ -1647,7 +1646,7 @@ impl eframe::App for App { // Check if address is okay before allowing to start. let mut text = String::new(); let mut ui_enabled = true; - if !Regexes::addr_ok(&self.regex, &self.state.p2pool.address) { + if !Regexes::addr_ok(&self.state.p2pool.address) { ui_enabled = false; text = format!("Error: {}", P2POOL_ADDRESS); } else if !Gupax::path_is_file(&self.state.gupax.p2pool_path) { @@ -1874,11 +1873,11 @@ path_xmr: {:#?}\n } Tab::P2pool => { debug!("App | Entering [P2Pool] Tab"); - crate::disk::P2pool::show(&mut self.state.p2pool, &mut self.node_vec, &self.og, &self.ping, &self.regex, &self.p2pool, &self.p2pool_api, &mut self.p2pool_stdin, self.width, self.height, ctx, ui); + crate::disk::P2pool::show(&mut self.state.p2pool, &mut self.node_vec, &self.og, &self.ping, &self.p2pool, &self.p2pool_api, &mut self.p2pool_stdin, self.width, self.height, ctx, ui); } Tab::Xmrig => { debug!("App | Entering [XMRig] Tab"); - crate::disk::Xmrig::show(&mut self.state.xmrig, &mut self.pool_vec, &self.regex, &self.xmrig, &self.xmrig_api, &mut self.xmrig_stdin, self.width, self.height, ctx, ui); + crate::disk::Xmrig::show(&mut self.state.xmrig, &mut self.pool_vec, &self.xmrig, &self.xmrig_api, &mut self.xmrig_stdin, self.width, self.height, ctx, ui); } } }); diff --git a/src/p2pool.rs b/src/p2pool.rs index 1af9507..8586b17 100644 --- a/src/p2pool.rs +++ b/src/p2pool.rs @@ -31,10 +31,13 @@ use egui::{ use std::sync::{Arc,Mutex}; use regex::Regex; use log::*; +use crate::regex::{ + REGEXES, +}; impl crate::disk::P2pool { #[inline(always)] - pub fn show(&mut self, node_vec: &mut Vec<(String, Node)>, _og: &Arc<Mutex<State>>, ping: &Arc<Mutex<Ping>>, regex: &Regexes, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubP2poolApi>>, buffer: &mut String, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(&mut self, node_vec: &mut Vec<(String, Node)>, _og: &Arc<Mutex<State>>, ping: &Arc<Mutex<Ping>>, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubP2poolApi>>, buffer: &mut String, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) { let text_edit = height / 25.0; //---------------------------------------------------------------------------------------------------- [Simple] Console debug!("P2Pool Tab | Rendering [Console]"); @@ -93,7 +96,7 @@ impl crate::disk::P2pool { if self.address.is_empty() { text = format!("Monero Address [{}/95] ➖", len); color = Color32::LIGHT_GRAY; - } else if Regexes::addr_ok(regex, &self.address) { + } else if Regexes::addr_ok(&self.address) { text = format!("Monero Address [{}/95] ✔", len); color = Color32::from_rgb(100, 230, 100); } else { @@ -248,7 +251,7 @@ impl crate::disk::P2pool { text = format!("Name [ {}/30 ]➖", len); color = Color32::LIGHT_GRAY; incorrect_input = true; - } else if Regex::is_match(®ex.name, &self.name) { + } else if REGEXES.name.is_match(&self.name) { text = format!("Name [ {}/30 ]✔", len); color = Color32::from_rgb(100, 230, 100); } else { @@ -268,7 +271,7 @@ impl crate::disk::P2pool { text = format!(" IP [{}/255]➖", len); color = Color32::LIGHT_GRAY; incorrect_input = true; - } else if self.ip == "localhost" || Regex::is_match(®ex.ipv4, &self.ip) || Regex::is_match(®ex.domain, &self.ip) { + } else if self.ip == "localhost" || REGEXES.ipv4.is_match(&self.ip) || REGEXES.domain.is_match(&self.ip) { text = format!(" IP [{}/255]✔", len); color = Color32::from_rgb(100, 230, 100); } else { @@ -288,7 +291,7 @@ impl crate::disk::P2pool { text = format!(" RPC [ {}/5 ]➖", len); color = Color32::LIGHT_GRAY; incorrect_input = true; - } else if Regex::is_match(®ex.port, &self.rpc) { + } else if REGEXES.port.is_match(&self.rpc) { text = format!(" RPC [ {}/5 ]✔", len); color = Color32::from_rgb(100, 230, 100); } else { @@ -308,7 +311,7 @@ impl crate::disk::P2pool { text = format!(" ZMQ [ {}/5 ]➖", len); color = Color32::LIGHT_GRAY; incorrect_input = true; - } else if Regex::is_match(®ex.port, &self.zmq) { + } else if REGEXES.port.is_match(&self.zmq) { text = format!(" ZMQ [ {}/5 ]✔", len); color = Color32::from_rgb(100, 230, 100); } else { diff --git a/src/regex.rs b/src/regex.rs index cc9a21d..b5730ce 100644 --- a/src/regex.rs +++ b/src/regex.rs @@ -18,6 +18,14 @@ // Some regexes used throughout Gupax. use regex::Regex; +use lazy_static::lazy_static; + +//---------------------------------------------------------------------------------------------------- Lazy +lazy_static! { + pub static ref REGEXES: Regexes = Regexes::new(); + pub static ref P2POOL_REGEX: P2poolRegex = P2poolRegex::new(); + pub static ref XMRIG_REGEX: XmrigRegex = XmrigRegex::new(); +} //---------------------------------------------------------------------------------------------------- [Regexes] struct // General purpose Regexes, mostly used in the GUI. @@ -31,8 +39,8 @@ pub struct Regexes { } impl Regexes { - pub fn new() -> Self { - Regexes { + fn new() -> Self { + Self { name: Regex::new("^[A-Za-z0-9-_.]+( [A-Za-z0-9-_.]+)*$").unwrap(), address: Regex::new("^4[A-Za-z1-9]+$").unwrap(), // This still needs to check for (l, I, o, 0) ipv4: Regex::new(r#"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$"#).unwrap(), @@ -44,8 +52,8 @@ impl Regexes { // Check if a Monero address is correct. // This actually only checks for length & Base58, and doesn't do any checksum validation // (the last few bytes of a Monero address are a Keccak hash checksum) so some invalid addresses can trick this function. - pub fn addr_ok(&self, address: &str) -> bool { - address.len() == 95 && Regex::is_match(&self.address, address) && !address.contains('0') && !address.contains('O') && !address.contains('l') + pub fn addr_ok(address: &str) -> bool { + address.len() == 95 && REGEXES.address.is_match(address) && !address.contains('0') && !address.contains('O') && !address.contains('l') } } @@ -69,25 +77,41 @@ impl Regexes { // Both are nominally fast enough where it doesn't matter too much but meh, why not use regex. #[derive(Clone,Debug)] pub struct P2poolRegex { - pub date: regex::Regex, - pub payout: regex::Regex, - pub payout_float: regex::Regex, - pub block: regex::Regex, - pub block_int: regex::Regex, - pub block_comma: regex::Regex, - pub synchronized: regex::Regex, + pub date: Regex, + pub payout: Regex, + pub payout_float: Regex, + pub block: Regex, + pub block_int: Regex, + pub block_comma: Regex, + pub synchronized: Regex, } impl P2poolRegex { - pub fn new() -> Self { + fn new() -> Self { Self { - date: regex::Regex::new("[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+").unwrap(), - payout: regex::Regex::new("payout of [0-9].[0-9]+ XMR").unwrap(), // Assumes 12 digits after the dot. - payout_float: regex::Regex::new("[0-9].[0-9]{12}").unwrap(), // Assumes 12 digits after the dot. - block: regex::Regex::new("block [0-9]{7}").unwrap(), // Monero blocks will be 7 digits for... the next 10,379 years - block_int: regex::Regex::new("[0-9]{7}").unwrap(), - block_comma: regex::Regex::new("[0-9],[0-9]{3},[0-9]{3}").unwrap(), - synchronized: regex::Regex::new("SYNCHRONIZED").unwrap(), + date: Regex::new("[0-9]+-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+.[0-9]+").unwrap(), + payout: Regex::new("payout of [0-9].[0-9]+ XMR").unwrap(), // Assumes 12 digits after the dot. + payout_float: Regex::new("[0-9].[0-9]{12}").unwrap(), // Assumes 12 digits after the dot. + block: Regex::new("block [0-9]{7}").unwrap(), // Monero blocks will be 7 digits for... the next 10,379 years + block_int: Regex::new("[0-9]{7}").unwrap(), + block_comma: Regex::new("[0-9],[0-9]{3},[0-9]{3}").unwrap(), + synchronized: Regex::new("SYNCHRONIZED").unwrap(), + } + } +} + +//---------------------------------------------------------------------------------------------------- XMRig regex. +#[derive(Debug)] +pub struct XmrigRegex { + not_mining: Regex, + mining: Regex, +} + +impl XmrigRegex { + fn new() -> Self { + Self { + not_mining: Regex::new("no active pools, stop mining").unwrap(), + mining: Regex::new("new job").unwrap(), } } } diff --git a/src/xmr.rs b/src/xmr.rs index b1bf2cf..0b7ae86 100644 --- a/src/xmr.rs +++ b/src/xmr.rs @@ -24,7 +24,9 @@ use crate::{ human::*, - P2poolRegex, +}; +use crate::regex::{ + P2POOL_REGEX, }; use log::*; @@ -141,15 +143,15 @@ impl PayoutOrd { } // Expected input: "NOTICE 2022-01-27 01:30:23.1377 P2Pool You received a payout of 0.000000000001 XMR in block 2642816" - pub fn parse_raw_payout_line(line: &str, regex: &P2poolRegex) -> (String, AtomicUnit, HumanNumber) { + pub fn parse_raw_payout_line(line: &str) -> (String, AtomicUnit, HumanNumber) { // Date - let date = match regex.date.find(line) { + let date = match P2POOL_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.payout_float.find(word.as_str()) { + let atomic_unit = if let Some(word) = P2POOL_REGEX.payout.find(line) { + if let Some(word) = P2POOL_REGEX.payout_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() }, @@ -163,8 +165,8 @@ impl PayoutOrd { AtomicUnit::new() }; // Block - let block = if let Some(word) = regex.block.find(line) { - if let Some(word) = regex.block_int.find(word.as_str()) { + let block = if let Some(word) = P2POOL_REGEX.block.find(line) { + if let Some(word) = P2POOL_REGEX.block_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() }, @@ -181,14 +183,14 @@ impl PayoutOrd { } // Expected input: "2022-01-27 01:30:23.1377 | 0.000000000001 XMR | Block 2,642,816" - pub fn parse_formatted_payout_line(line: &str, regex: &P2poolRegex) -> (String, AtomicUnit, HumanNumber) { + pub fn parse_formatted_payout_line(line: &str) -> (String, AtomicUnit, HumanNumber) { // Date - let date = match regex.date.find(line) { + let date = match P2POOL_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_float.find(line) { + let atomic_unit = if let Some(word) = P2POOL_REGEX.payout_float.find(line) { match word.as_str().parse::<f64>() { Ok(au) => AtomicUnit::from_f64(au), Err(e) => { error!("P2Pool | AtomicUnit parse error: [{}] on [{}]", e, line); AtomicUnit::new() }, @@ -198,7 +200,7 @@ impl PayoutOrd { AtomicUnit::new() }; // Block - let block = match regex.block_comma.find(line) { + let block = match P2POOL_REGEX.block_comma.find(line) { Some(b) => HumanNumber::from_str(b.as_str()), None => { error!("P2Pool | Block parse error: [{}]", line); HumanNumber::unknown() }, }; @@ -215,12 +217,11 @@ impl PayoutOrd { // Spaces, pipes, commas and words (XMR, Block): [19] // Add 7 more bytes for wrapper type overhead and it's an even [70] bytes per line. pub fn update_from_payout_log(&mut self, log: &str) { - let regex = P2poolRegex::new(); let amount_of_lines = log.lines().count(); let mut vec: Vec<(String, AtomicUnit, HumanNumber)> = Vec::with_capacity(70 * amount_of_lines); for line in log.lines() { debug!("PayoutOrd | Parsing line: [{}]", line); - vec.push(Self::parse_formatted_payout_line(line, ®ex)); + vec.push(Self::parse_formatted_payout_line(line)); } *self = Self(vec); } diff --git a/src/xmrig.rs b/src/xmrig.rs index 056f9f6..730f7e2 100644 --- a/src/xmrig.rs +++ b/src/xmrig.rs @@ -32,10 +32,13 @@ use std::{ }; use regex::Regex; use log::*; +use crate::regex::{ + REGEXES, +}; impl crate::disk::Xmrig { #[inline(always)] - pub fn show(&mut self, pool_vec: &mut Vec<(String, Pool)>, regex: &Regexes, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubXmrigApi>>, buffer: &mut String, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) { + pub fn show(&mut self, pool_vec: &mut Vec<(String, Pool)>, process: &Arc<Mutex<Process>>, api: &Arc<Mutex<PubXmrigApi>>, buffer: &mut String, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) { let text_edit = height / 25.0; //---------------------------------------------------------------------------------------------------- [Simple] Console debug!("XMRig Tab | Rendering [Console]"); @@ -92,7 +95,7 @@ impl crate::disk::Xmrig { if self.address.is_empty() { text = format!("Monero Address [{}/95] ➖", len); color = LIGHT_GRAY; - } else if self.address.len() == 95 && Regex::is_match(®ex.address, &self.address) && ! self.address.contains('0') && ! self.address.contains('O') && ! self.address.contains('l') { + } else if Regexes::addr_ok(&self.address) { text = format!("Monero Address [{}/95] ✔", len); color = GREEN; } else { @@ -147,7 +150,7 @@ impl crate::disk::Xmrig { text = format!("Name [ {}/30 ]➖", len); color = LIGHT_GRAY; incorrect_input = true; - } else if Regex::is_match(®ex.name, &self.name) { + } else if REGEXES.name.is_match(&self.name) { text = format!("Name [ {}/30 ]✔", len); color = GREEN; } else { @@ -167,7 +170,7 @@ impl crate::disk::Xmrig { text = format!(" IP [{}/255]➖", len); color = LIGHT_GRAY; incorrect_input = true; - } else if self.ip == "localhost" || Regex::is_match(®ex.ipv4, &self.ip) || Regex::is_match(®ex.domain, &self.ip) { + } else if self.ip == "localhost" || REGEXES.ipv4.is_match(&self.ip) || REGEXES.domain.is_match(&self.ip) { text = format!(" IP [{}/255]✔", len); color = GREEN; } else { @@ -187,7 +190,7 @@ impl crate::disk::Xmrig { text = format!("Port [ {}/5 ]➖", len); color = LIGHT_GRAY; incorrect_input = true; - } else if Regex::is_match(®ex.port, &self.port) { + } else if REGEXES.port.is_match(&self.port) { text = format!("Port [ {}/5 ]✔", len); color = GREEN; } else { @@ -206,7 +209,7 @@ impl crate::disk::Xmrig { if self.rig.is_empty() { text = format!(" Rig [ {}/30 ]➖", len); color = LIGHT_GRAY; - } else if Regex::is_match(®ex.name, &self.rig) { + } else if REGEXES.name.is_match(&self.rig) { text = format!(" Rig [ {}/30 ]✔", len); color = GREEN; } else { @@ -361,7 +364,7 @@ impl crate::disk::Xmrig { text = format!("HTTP API IP [{}/255]➖", len); color = LIGHT_GRAY; incorrect_input = true; - } else if self.api_ip == "localhost" || Regex::is_match(®ex.ipv4, &self.api_ip) || Regex::is_match(®ex.domain, &self.api_ip) { + } else if self.api_ip == "localhost" || REGEXES.ipv4.is_match(&self.api_ip) || REGEXES.domain.is_match(&self.api_ip) { text = format!("HTTP API IP [{}/255]✔", len); color = GREEN; } else { @@ -381,7 +384,7 @@ impl crate::disk::Xmrig { text = format!("HTTP API Port [ {}/5 ]➖", len); color = LIGHT_GRAY; incorrect_input = true; - } else if Regex::is_match(®ex.port, &self.api_port) { + } else if REGEXES.port.is_match(&self.api_port) { text = format!("HTTP API Port [ {}/5 ]✔", len); color = GREEN; } else {