helper: p2pool - fix uptime, format with commas and spaces

This commit is contained in:
hinto-janaiyo 2022-12-06 15:17:37 -05:00
parent e1829f967c
commit 9b1a815089
No known key found for this signature in database
GPG key ID: B1C5A64B80691E45
2 changed files with 61 additions and 43 deletions

View file

@ -36,7 +36,8 @@ pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon@2x.png");
pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon.png"); pub const BYTES_ICON: &[u8] = include_bytes!("../images/icons/icon.png");
pub const BYTES_BANNER: &[u8] = include_bytes!("../images/banner.png"); pub const BYTES_BANNER: &[u8] = include_bytes!("../images/banner.png");
pub const HORIZONTAL: &str = "--------------------------------------------"; pub const HORIZONTAL: &str = "--------------------------------------------";
pub const HORI_DOUBLE: &str = "----------------------------------------------------------------------------------------"; // The text to separate my "process stopped, here's stats" text from the process output in the console.
pub const HORI_CONSOLE: &str = "---------------------------------------------------------------------------------------------------------------------------";
// P2Pool & XMRig default API stuff // P2Pool & XMRig default API stuff
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -73,6 +74,7 @@ pub const DARK_GRAY: egui::Color32 = egui::Color32::from_rgb(18, 18, 18);
// [Duration] constants // [Duration] constants
pub const SECOND: std::time::Duration = std::time::Duration::from_secs(1); pub const SECOND: std::time::Duration = std::time::Duration::from_secs(1);
pub const ZERO_SECONDS: std::time::Duration = std::time::Duration::from_secs(0);
pub const MILLI_900: std::time::Duration = std::time::Duration::from_millis(900); pub const MILLI_900: std::time::Duration = std::time::Duration::from_millis(900);
pub const TOKIO_SECOND: tokio::time::Duration = std::time::Duration::from_secs(1); pub const TOKIO_SECOND: tokio::time::Duration = std::time::Duration::from_secs(1);

View file

@ -71,8 +71,6 @@ pub struct Process {
pub name: ProcessName, // P2Pool or XMRig? pub name: ProcessName, // P2Pool or XMRig?
pub state: ProcessState, // The state of the process (alive, dead, etc) pub state: ProcessState, // The state of the process (alive, dead, etc)
pub signal: ProcessSignal, // Did the user click [Start/Stop/Restart]? pub signal: ProcessSignal, // Did the user click [Start/Stop/Restart]?
pub start: Instant, // Start time of process
pub uptime: HumanTime, // Human readable process uptime
// STDIN Problem: // STDIN Problem:
// - User can input many many commands in 1 second // - User can input many many commands in 1 second
// - The process loop only processes every 1 second // - The process loop only processes every 1 second
@ -96,18 +94,19 @@ pub struct Process {
// The "watchdog" threads mutate this, the "helper" thread synchronizes the [Pub*Api] structs // The "watchdog" threads mutate this, the "helper" thread synchronizes the [Pub*Api] structs
// so that the data in here is cloned there roughly once a second. GUI thread never touches this. // so that the data in here is cloned there roughly once a second. GUI thread never touches this.
output: Arc<Mutex<String>>, output: Arc<Mutex<String>>,
// Start time of process.
start: std::time::Instant,
} }
//---------------------------------------------------------------------------------------------------- [Process] Impl //---------------------------------------------------------------------------------------------------- [Process] Impl
impl Process { impl Process {
pub fn new(name: ProcessName, args: String, path: PathBuf) -> Self { pub fn new(name: ProcessName, args: String, path: PathBuf) -> Self {
let now = Instant::now();
Self { Self {
name, name,
state: ProcessState::Dead, state: ProcessState::Dead,
signal: ProcessSignal::None, signal: ProcessSignal::None,
start: now, start: Instant::now(),
uptime: HumanTime::into_human(now.elapsed()),
stdin: Option::None, stdin: Option::None,
child: Option::None, child: Option::None,
// P2Pool log level 1 produces a bit less than 100,000 lines a day. // P2Pool log level 1 produces a bit less than 100,000 lines a day.
@ -331,6 +330,7 @@ impl Helper {
path.push(P2POOL_API_PATH); path.push(P2POOL_API_PATH);
let regex = P2poolRegex::new(); let regex = P2poolRegex::new();
let output = Arc::clone(&process.lock().unwrap().output); let output = Arc::clone(&process.lock().unwrap().output);
let start = process.lock().unwrap().start;
// 4. Loop as watchdog // 4. Loop as watchdog
loop { loop {
@ -341,43 +341,46 @@ impl Helper {
if process.lock().unwrap().signal == ProcessSignal::Stop { if process.lock().unwrap().signal == ProcessSignal::Stop {
child_pty.lock().unwrap().kill(); // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool) child_pty.lock().unwrap().kill(); // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
// Wait to get the exit status // Wait to get the exit status
let mut lock = process.lock().unwrap();
let exit_status = match child_pty.lock().unwrap().wait() { let exit_status = match child_pty.lock().unwrap().wait() {
Ok(e) => if e.success() { lock.state = ProcessState::Dead; "Successful" } else { lock.state = ProcessState::Failed; "Failed" }, Ok(e) => {
_ => { lock.state = ProcessState::Failed; "Unknown Error" }, if e.success() {
process.lock().unwrap().state = ProcessState::Dead; "Successful"
} else {
process.lock().unwrap().state = ProcessState::Failed; "Failed"
}
},
_ => { process.lock().unwrap().state = ProcessState::Failed; "Unknown Error" },
}; };
let uptime = lock.uptime.clone(); let uptime = HumanTime::into_human(start.elapsed());
info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status); info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
// This is written directly into the public API, because sometimes the 900ms event loop can't catch it. // This is written directly into the public API, because sometimes the 900ms event loop can't catch it.
writeln!(pub_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n", HORI_DOUBLE, uptime, exit_status, HORI_DOUBLE); writeln!(pub_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
lock.signal = ProcessSignal::None; process.lock().unwrap().signal = ProcessSignal::None;
break break
} else if process.lock().unwrap().signal == ProcessSignal::Restart { } else if process.lock().unwrap().signal == ProcessSignal::Restart {
child_pty.lock().unwrap().kill(); // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool) child_pty.lock().unwrap().kill(); // This actually sends a SIGHUP to p2pool (closes the PTY, hangs up on p2pool)
// Wait to get the exit status // Wait to get the exit status
let mut lock = process.lock().unwrap();
let exit_status = match child_pty.lock().unwrap().wait() { let exit_status = match child_pty.lock().unwrap().wait() {
Ok(e) => if e.success() { "Successful" } else { "Failed" }, Ok(e) => if e.success() { "Successful" } else { "Failed" },
_ => "Unknown Error", _ => "Unknown Error",
}; };
let uptime = lock.uptime.clone(); let uptime = HumanTime::into_human(start.elapsed());
info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status); info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
// This is written directly into the public API, because sometimes the 900ms event loop can't catch it. // This is written directly into the public API, because sometimes the 900ms event loop can't catch it.
writeln!(pub_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n", HORI_DOUBLE, uptime, exit_status, HORI_DOUBLE); writeln!(pub_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
lock.state = ProcessState::Waiting; process.lock().unwrap().state = ProcessState::Waiting;
break break
// Check if the process is secretly died without us knowing :) // Check if the process is secretly died without us knowing :)
} else if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() { } else if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
let mut lock = process.lock().unwrap();
let exit_status = match code.success() { let exit_status = match code.success() {
true => { lock.state = ProcessState::Dead; "Successful" }, true => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
false => { lock.state = ProcessState::Failed; "Failed" }, false => { process.lock().unwrap().state = ProcessState::Failed; "Failed" },
}; };
let uptime = lock.uptime.clone(); let uptime = HumanTime::into_human(start.elapsed());
info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status); info!("P2Pool | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
// This is written directly into the public API, because sometimes the 900ms event loop can't catch it. // This is written directly into the public API, because sometimes the 900ms event loop can't catch it.
writeln!(pub_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n", HORI_DOUBLE, uptime, exit_status, HORI_DOUBLE); writeln!(pub_api.lock().unwrap().output, "{}\nP2Pool stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
lock.signal = ProcessSignal::None; process.lock().unwrap().signal = ProcessSignal::None;
break break
} }
@ -392,7 +395,7 @@ impl Helper {
drop(lock); drop(lock);
// Always update from output // Always update from output
PubP2poolApi::update_from_output(&pub_api, &output, process.lock().unwrap().start.elapsed().as_secs_f64(), &regex); PubP2poolApi::update_from_output(&pub_api, &output, start.elapsed(), &regex);
// Read API file into string // Read API file into string
if let Ok(string) = Self::read_p2pool_api(&path) { if let Ok(string) = Self::read_p2pool_api(&path) {
@ -506,19 +509,25 @@ use std::time::Duration;
pub struct HumanTime(Duration); pub struct HumanTime(Duration);
impl HumanTime { impl HumanTime {
pub fn new() -> HumanTime {
HumanTime(ZERO_SECONDS)
}
pub fn into_human(d: Duration) -> HumanTime { pub fn into_human(d: Duration) -> HumanTime {
HumanTime(d) HumanTime(d)
} }
fn plural(f: &mut std::fmt::Formatter, started: &mut bool, name: &str, value: u64) -> std::fmt::Result { fn plural(f: &mut std::fmt::Formatter, started: &mut bool, name: &str, value: u64) -> std::fmt::Result {
if value > 0 { if value > 0 {
if *started { f.write_str(" ")?; } if *started {
f.write_str(", ")?;
} }
write!(f, "{} {}", value, name)?; write!(f, "{} {}", value, name)?;
if value > 1 { if value > 1 {
f.write_str("s")?; f.write_str("s")?;
} }
*started = true; *started = true;
}
Ok(()) Ok(())
} }
} }
@ -527,7 +536,7 @@ impl std::fmt::Display for HumanTime {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let secs = self.0.as_secs(); let secs = self.0.as_secs();
if secs == 0 { if secs == 0 {
f.write_str("0s")?; f.write_str("0 seconds")?;
return Ok(()); return Ok(());
} }
@ -701,6 +710,8 @@ pub struct PubP2poolApi {
pub mini: bool, pub mini: bool,
// Output // Output
pub output: String, pub output: String,
// Uptime
pub uptime: HumanTime,
// These are manually parsed from the STDOUT. // These are manually parsed from the STDOUT.
pub payouts: u128, pub payouts: u128,
pub payouts_hour: f64, pub payouts_hour: f64,
@ -725,6 +736,7 @@ impl PubP2poolApi {
Self { Self {
mini: true, mini: true,
output: String::with_capacity(56_000_000), output: String::with_capacity(56_000_000),
uptime: HumanTime::new(),
payouts: 0, payouts: 0,
payouts_hour: 0.0, payouts_hour: 0.0,
payouts_day: 0.0, payouts_day: 0.0,
@ -744,26 +756,30 @@ impl PubP2poolApi {
} }
// Mutate [PubP2poolApi] with data the process output. // Mutate [PubP2poolApi] with data the process output.
fn update_from_output(public: &Arc<Mutex<Self>>, output: &Arc<Mutex<String>>, elapsed: f64, regex: &P2poolRegex) { fn update_from_output(public: &Arc<Mutex<Self>>, output: &Arc<Mutex<String>>, elapsed: std::time::Duration, regex: &P2poolRegex) {
// 1. Clone output
let output = output.lock().unwrap().clone(); let output = output.lock().unwrap().clone();
// 1. Parse STDOUT
// 2. Parse STDOUT
let (payouts, xmr) = Self::calc_payouts_and_xmr(&output, &regex); let (payouts, xmr) = Self::calc_payouts_and_xmr(&output, &regex);
// 2. Calculate hour/day/month given elapsed time // 3. Calculate hour/day/month given elapsed time
let elapsed_as_secs_f64 = elapsed.as_secs_f64();
// Payouts // Payouts
let per_sec = (payouts as f64) / elapsed; let per_sec = (payouts as f64) / elapsed_as_secs_f64;
let payouts_hour = (per_sec * 60.0) * 60.0; let payouts_hour = (per_sec * 60.0) * 60.0;
let payouts_day = payouts_hour * 24.0; let payouts_day = payouts_hour * 24.0;
let payouts_month = payouts_day * 30.0; let payouts_month = payouts_day * 30.0;
// Total XMR // Total XMR
let per_sec = xmr / elapsed; let per_sec = xmr / elapsed_as_secs_f64;
let xmr_hour = (per_sec * 60.0) * 60.0; let xmr_hour = (per_sec * 60.0) * 60.0;
let xmr_day = payouts_hour * 24.0; let xmr_day = payouts_hour * 24.0;
let xmr_month = payouts_day * 30.0; let xmr_month = payouts_day * 30.0;
// 3. Mutate the struct with the new info // 4. Mutate the struct with the new info
let mut public = public.lock().unwrap(); let mut public = public.lock().unwrap();
*public = Self { *public = Self {
uptime: HumanTime::into_human(elapsed),
output, output,
payouts, payouts,
xmr, xmr,
@ -779,7 +795,7 @@ impl PubP2poolApi {
// Mutate [PubP2poolApi] with data from a [PrivP2poolApi] and the process output. // Mutate [PubP2poolApi] with data from a [PrivP2poolApi] and the process output.
fn update_from_priv(public: &Arc<Mutex<Self>>, private: &Arc<Mutex<PrivP2poolApi>>) { fn update_from_priv(public: &Arc<Mutex<Self>>, private: &Arc<Mutex<PrivP2poolApi>>) {
// 3. Final priv -> pub conversion // priv -> pub conversion
let private = private.lock().unwrap(); let private = private.lock().unwrap();
let mut public = public.lock().unwrap(); let mut public = public.lock().unwrap();
*public = Self { *public = Self {