diff --git a/src/constants.rs b/src/constants.rs index 4a5dcb7..79b82de 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -175,6 +175,12 @@ pub const STATUS_XMRIG_THREADS: &str = "The amount of threads XMRig is curre pub const STATUS_SUBMENU_PROCESSES: &str = "View the status of process related data for [Gupax|P2Pool|XMRig]"; pub const STATUS_SUBMENU_P2POOL: &str = "View P2Pool specific data"; pub const STATUS_SUBMENU_MONERO: &str = "View general Monero blockchain data"; +pub const STATUS_SUBMENU_PAYOUT: &str = "The total amount of payouts received via P2Pool across all time"; +pub const STATUS_SUBMENU_XMR: &str = "The total of XMR mined via P2Pool across all time"; +pub const STATUS_SUBMENU_LATEST: &str = "Sort the logs latest to oldest"; +pub const STATUS_SUBMENU_OLDEST: &str = "Sort the logs oldest to latest"; +pub const STATUS_SUBMENU_BIGGEST: &str = "Sort the logs by biggest payouts first"; +pub const STATUS_SUBMENU_SMALLEST: &str = "Sort the logs by smallest payouts first"; // Gupax pub const GUPAX_UPDATE: &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically"; diff --git a/src/disk.rs b/src/disk.rs index 09f8d8c..ad001db 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -561,9 +561,12 @@ impl Pool { #[derive(Clone,Debug)] pub struct GupaxP2poolApi { pub log: String, // Log file only containing full payout lines + pub log_rev: String, // Same as above but reversed based off lines pub payout: HumanNumber, // Human-friendly display of payout count pub payout_u64: u64, // [u64] version of above pub payout_ord: PayoutOrd, // Ordered Vec of payouts, see [PayoutOrd] + pub payout_low: String, // A pre-allocated/computed [String] of the above Vec from low payout to high + pub payout_high: String, // Same as above but high -> low pub xmr: AtomicUnit, // XMR stored as atomic units pub path_log: PathBuf, // Path to [log] pub path_payout: PathBuf, // Path to [payout] @@ -576,9 +579,12 @@ impl GupaxP2poolApi { pub fn new() -> Self { Self { log: String::new(), + log_rev: String::new(), payout: HumanNumber::unknown(), payout_u64: 0, payout_ord: PayoutOrd::new(), + payout_low: String::new(), + payout_high: String::new(), xmr: AtomicUnit::new(), path_xmr: PathBuf::new(), path_payout: PathBuf::new(), @@ -624,6 +630,34 @@ impl GupaxP2poolApi { Ok(()) } + pub fn update_log_rev(&mut self) { + let mut log_rev = String::with_capacity(self.log.len()); + for line in self.log.lines().rev() { + log_rev.push_str(line); + log_rev.push_str("\n"); + } + self.log_rev = log_rev; + } + + pub fn append_head_log_rev(&mut self, line: &str) { + self.log_rev = format!("{}\n{}", line, self.log_rev); + } + + pub fn update_payout_low(&mut self) { + self.payout_ord.sort_payout_low_to_high(); + self.payout_low = self.payout_ord.to_string(); + } + + pub fn update_payout_high(&mut self) { + self.payout_ord.sort_payout_high_to_low(); + self.payout_high = self.payout_ord.to_string(); + } + + pub fn update_payout_strings(&mut self) { + self.update_payout_low(); + self.update_payout_high(); + } + pub fn read_all_files_and_update(&mut self) -> Result<(), TomlError> { let payout_u64 = match read_to_string(File::Payout, &self.path_payout)?.trim().parse::() { Ok(o) => o, @@ -636,6 +670,7 @@ impl GupaxP2poolApi { let payout = HumanNumber::from_u64(payout_u64); let log = read_to_string(File::Log, &self.path_log)?; self.payout_ord.update_from_payout_log(&log); + self.update_payout_strings(); *self = Self { log, payout, @@ -643,16 +678,19 @@ impl GupaxP2poolApi { xmr, ..std::mem::take(self) }; + self.update_log_rev(); Ok(()) } // Takes the log line and (date, atomic_unit, block) and updates [self] and the [PayoutOrd] pub fn add_payout(&mut self, log_payout_line: &str, date: String, atomic_unit: AtomicUnit, block: HumanNumber) { self.log.push_str(log_payout_line); + self.append_head_log_rev(log_payout_line); self.payout_u64 += 1; self.payout = HumanNumber::from_u64(self.payout_u64); self.xmr = self.xmr.add_self(atomic_unit); self.payout_ord.push(date, atomic_unit, block); + self.update_payout_strings(); } pub fn write_to_all_files(&self) -> Result<(), TomlError> { @@ -764,6 +802,34 @@ impl Display for Submenu { } } +//---------------------------------------------------------------------------------------------------- [PayoutView] enum for [Status/P2Pool] tab +// The enum buttons for selecting which "view" to sort the payout log in. +#[derive(Clone,Copy,Eq,PartialEq,Debug,Deserialize,Serialize)] +pub enum PayoutView { + Latest, // Shows the most recent logs first + Oldest, // Shows the oldest logs first + Biggest, // Shows highest to lowest payouts + Smallest, // Shows lowest to highest payouts +} + +impl PayoutView { + fn new() -> Self { + Self::Latest + } +} + +impl Default for PayoutView { + fn default() -> Self { + Self::new() + } +} + +impl Display for PayoutView { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self) + } +} + //---------------------------------------------------------------------------------------------------- [Hash] enum for [Status/P2Pool] #[derive(Clone,Copy,Eq,PartialEq,Debug,Deserialize,Serialize)] pub enum Hash { @@ -856,6 +922,7 @@ pub struct State { #[derive(Clone,PartialEq,Debug,Deserialize,Serialize)] pub struct Status { pub submenu: Submenu, + pub payout_view: PayoutView, pub monero_enabled: bool, pub manual_hash: bool, pub hashrate: f64, @@ -941,6 +1008,7 @@ impl Default for Status { fn default() -> Self { Self { submenu: Submenu::default(), + payout_view: PayoutView::default(), monero_enabled: false, manual_hash: false, hashrate: 0.0, diff --git a/src/main.rs b/src/main.rs index d1797c3..13d3fd5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1742,7 +1742,7 @@ XMRig console byte length: {}\n } Tab::Status => { debug!("App | Entering [Status] Tab"); - crate::disk::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, self.max_threads, self.width, self.height, ctx, ui); + crate::disk::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, self.max_threads, &self.gupax_p2pool_api, self.width, self.height, ctx, ui); } Tab::Gupax => { debug!("App | Entering [Gupax] Tab"); diff --git a/src/status.rs b/src/status.rs index 1395189..7861b80 100644 --- a/src/status.rs +++ b/src/status.rs @@ -25,6 +25,8 @@ use crate::{ Hash, Submenu, macros::*, + GupaxP2poolApi, + PayoutView, }; use std::sync::{Arc,Mutex}; use log::*; @@ -32,10 +34,12 @@ use egui::{ Label,RichText,TextStyle, TextStyle::Monospace, TextStyle::Name, + TextEdit, + SelectableLabel, }; impl crate::disk::Status { -pub fn show(&mut self, sys: &Arc>, p2pool_api: &Arc>, xmrig_api: &Arc>, p2pool_img: &Arc>, xmrig_img: &Arc>, p2pool_alive: bool, xmrig_alive: bool, max_threads: usize, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) { +pub fn show(&mut self, sys: &Arc>, p2pool_api: &Arc>, xmrig_api: &Arc>, p2pool_img: &Arc>, xmrig_img: &Arc>, p2pool_alive: bool, xmrig_alive: bool, max_threads: usize, gupax_p2pool_api: &Arc>, width: f32, height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) { //---------------------------------------------------------------------------------------------------- [Processes] if self.submenu == Submenu::Processes { let width = (width/3.0)-(SPACE*1.666); @@ -123,7 +127,50 @@ pub fn show(&mut self, sys: &Arc>, p2pool_api: &Arc ui.add_sized([width, log], TextEdit::multiline(&mut api.log.as_str())), + PayoutView::Oldest => ui.add_sized([width, log], TextEdit::multiline(&mut api.log_rev.as_str())), + PayoutView::Biggest => ui.add_sized([width, log], TextEdit::multiline(&mut api.payout_high.as_str())), + PayoutView::Smallest => ui.add_sized([width, log], TextEdit::multiline(&mut api.payout_low.as_str())), + }; + }); + }); + }); + drop(api); + //---------------------------------------------------------------------------------------------------- [Monero] } else if self.submenu == Submenu::Monero { } } diff --git a/src/xmr.rs b/src/xmr.rs index 6163748..3082fd7 100644 --- a/src/xmr.rs +++ b/src/xmr.rs @@ -225,10 +225,18 @@ impl PayoutOrd { self.0.sort_by(|a, b| b.1.0.cmp(&a.1.0)); } + // These sorting functions take around [0.0035~] seconds on a Ryzen 5950x + // given a Vec filled with 1_000_000 elements, not bad. pub fn sort_payout_low_to_high(&mut self) { self.0.sort_by(|a, b| a.1.0.cmp(&b.1.0)); } + // Returns a reversed [Iter] of the [PayoutOrd] + // This is obviously faster than actually reordering the Vec. + pub fn rev_iter(&self) -> std::iter::Rev> { + self.0.iter().rev() + } + // Recent <-> Oldest relies on the line order. // The raw log lines will be shown instead of this struct. } @@ -354,4 +362,26 @@ r#"2022-09-08 18:42:55.4636 | 0.001000000000 XMR | Block 2,654,321 println!("2: {:#?}", payout_ord); assert!(PayoutOrd::is_same(&payout_ord, &payout_ord_2) == false); } + + #[test] + fn view_reverse_payout_ord() { + use crate::xmr::PayoutOrd; + use crate::xmr::AtomicUnit; + use crate::human::HumanNumber; + let mut payout_ord = PayoutOrd::from_vec(vec![ + ("2022-09-08 18:42:55.4636".to_string(), AtomicUnit::from_u64(1000000000), HumanNumber::from_u64(2654321)), + ("2022-09-09 16:18:26.7582".to_string(), AtomicUnit::from_u64(2000000000), HumanNumber::from_u64(2654322)), + ("2022-09-10 11:15:21.1272".to_string(), AtomicUnit::from_u64(3000000000), HumanNumber::from_u64(2654323)), + ]); + println!("OG: {:#?}", payout_ord); + + for (_, atomic_unit, _) in payout_ord.rev_iter() { + if atomic_unit.to_u64() == 3000000000 { + break + } else { + println!("expected: 3000000000, found: {}", atomic_unit); + panic!("not reversed"); + } + } + } }