From dac7dee286189d1b02162323b2af59e23102efe2 Mon Sep 17 00:00:00 2001 From: Louis-Marie Baer Date: Tue, 12 Mar 2024 23:26:08 +0100 Subject: [PATCH] feat: console for log, input token field, better logic for running XvB process --- TODO_XMRvsBeast.md | 5 +- src/app/eframe_impl.rs | 9 +- src/app/panels/bottom.rs | 127 ++++++++++------ src/app/panels/middle/mod.rs | 5 +- src/app/panels/middle/status/mod.rs | 2 + src/app/panels/middle/status/processes.rs | 15 +- src/app/panels/middle/xvb.rs | 45 +++++- src/disk/state.rs | 14 +- src/helper/mod.rs | 55 ++++--- src/helper/xvb.rs | 175 +++++++++++++--------- src/utils/constants.rs | 2 + 11 files changed, 294 insertions(+), 160 deletions(-) diff --git a/TODO_XMRvsBeast.md b/TODO_XMRvsBeast.md index 7b4764df..fe5c5bc3 100644 --- a/TODO_XMRvsBeast.md +++ b/TODO_XMRvsBeast.md @@ -11,7 +11,7 @@ - [x] logo - [x] link to website - [ ] message overing explaining registration and needs to read the rules. - - [ ] token input + - [x] token input - [ ] hero checkbox - [ ] log section - [ ] status of h/s received by the raffle, authentication by token. @@ -19,13 +19,14 @@ - [ ] number of failures - [ ] round type in - [ ] win or loose + - [x] state of XvB process - [ ] new process for XvB - [x] status process XvB - [x] public information from [API](https://xmrvsbeast.com/p2pool/stats) - [x] stop, start, restart buttons - [x] button to autostart - [ ] distribute hashrate conforming to the algorithm. - - [ ] output log to console in XvB tab + - [x] output log to console in XvB tab - [ ] edit metadata of project - [ ] cargo package metadata - [ ] pgp signatures diff --git a/src/app/eframe_impl.rs b/src/app/eframe_impl.rs index 138ce604..d14aecef 100644 --- a/src/app/eframe_impl.rs +++ b/src/app/eframe_impl.rs @@ -93,6 +93,13 @@ impl eframe::App for App { xmrig_is_alive, xvb_is_alive, ); - self.middle_panel(ctx, frame, key, p2pool_is_alive, xmrig_is_alive); + self.middle_panel( + ctx, + frame, + key, + p2pool_is_alive, + xmrig_is_alive, + xvb_is_alive, + ); } } diff --git a/src/app/panels/bottom.rs b/src/app/panels/bottom.rs index a0784e1a..27d7eb39 100644 --- a/src/app/panels/bottom.rs +++ b/src/app/panels/bottom.rs @@ -342,7 +342,7 @@ impl crate::app::App { ui.add_sized(size, Button::new("⏹")) .on_disabled_hover_text("Stop P2Pool"); }); - // Check if address is okay before allowing to start. + // Check if address and path is okay before allowing to start. let mut text = String::new(); let mut ui_enabled = true; if !Regexes::addr_ok(&self.state.p2pool.address) { @@ -556,8 +556,10 @@ impl crate::app::App { ui.add_sized(size, Button::new("⏹")) .on_disabled_hover_text("Stop Xvb"); }); - let ui_enabled = - !self.state.p2pool.address.is_empty() && !self.state.xvb.token.is_empty(); + // verify that adddress and token syntaxes are correct + let ui_enabled = Regexes::addr_ok(&self.state.p2pool.address) + && self.state.xvb.token.len() == 9 + && self.state.xvb.token.parse::().is_ok(); ui.set_enabled(ui_enabled); let color = if ui_enabled { GREEN } else { RED }; if (ui_enabled && key.is_up() && !wants_input) @@ -575,57 +577,86 @@ impl crate::app::App { } fn status_p2pool(state: ProcessState, ui: &mut Ui, size: Vec2) { - match state { - Alive => ui - .add_sized(size, Label::new(RichText::new("P2Pool ⏺").color(GREEN))) - .on_hover_text(P2POOL_ALIVE), - Dead => ui - .add_sized(size, Label::new(RichText::new("P2Pool ⏺").color(GRAY))) - .on_hover_text(P2POOL_DEAD), - Failed => ui - .add_sized(size, Label::new(RichText::new("P2Pool ⏺").color(RED))) - .on_hover_text(P2POOL_FAILED), - Syncing => ui - .add_sized(size, Label::new(RichText::new("P2Pool ⏺").color(ORANGE))) - .on_hover_text(P2POOL_SYNCING), - Middle | Waiting | NotMining => ui - .add_sized(size, Label::new(RichText::new("P2Pool ⏺").color(YELLOW))) - .on_hover_text(P2POOL_MIDDLE), + let color; + let hover_text = match state { + Alive => { + color = GREEN; + P2POOL_ALIVE + } + Dead => { + color = GRAY; + P2POOL_DEAD + } + Failed => { + color = RED; + P2POOL_FAILED + } + Syncing => { + color = ORANGE; + P2POOL_SYNCING + } + Middle | Waiting | NotMining => { + color = YELLOW; + P2POOL_MIDDLE + } }; + status(ui, color, hover_text, size, "P2pool ⏺"); } fn status_xmrig(state: ProcessState, ui: &mut Ui, size: Vec2) { - match state { - Alive => ui - .add_sized(size, Label::new(RichText::new("XMRig ⏺").color(GREEN))) - .on_hover_text(XMRIG_ALIVE), - Dead => ui - .add_sized(size, Label::new(RichText::new("XMRig ⏺").color(GRAY))) - .on_hover_text(XMRIG_DEAD), - Failed => ui - .add_sized(size, Label::new(RichText::new("XMRig ⏺").color(RED))) - .on_hover_text(XMRIG_FAILED), - NotMining => ui - .add_sized(size, Label::new(RichText::new("XMRig ⏺").color(ORANGE))) - .on_hover_text(XMRIG_NOT_MINING), - Middle | Waiting | Syncing => ui - .add_sized(size, Label::new(RichText::new("XMRig ⏺").color(YELLOW))) - .on_hover_text(XMRIG_MIDDLE), + let color; + let hover_text = match state { + Alive => { + color = GREEN; + XMRIG_ALIVE + } + Dead => { + color = GRAY; + XMRIG_DEAD + } + Failed => { + color = RED; + XMRIG_FAILED + } + NotMining => { + color = ORANGE; + XMRIG_NOT_MINING + } + Middle | Waiting | Syncing => { + color = YELLOW; + XMRIG_MIDDLE + } }; + status(ui, color, hover_text, size, "XMRig ⏺"); } fn status_xvb(state: ProcessState, ui: &mut Ui, size: Vec2) { - match state { - Alive => ui - .add_sized(size, Label::new(RichText::new("XvB ⏺").color(GREEN))) - .on_hover_text(XVB_ALIVE), - Dead => ui - .add_sized(size, Label::new(RichText::new("XvB ⏺").color(GRAY))) - .on_hover_text(XVB_DEAD), - Failed => ui - .add_sized(size, Label::new(RichText::new("XvB ⏺").color(RED))) - .on_hover_text(XVB_FAILED), - Middle | Waiting | NotMining | Syncing => ui - .add_sized(size, Label::new(RichText::new("XvB ⏺").color(YELLOW))) - .on_hover_text(XVB_MIDDLE), + let color; + let hover_text = match state { + Alive => { + color = GREEN; + XVB_ALIVE + } + Dead => { + color = GRAY; + XVB_DEAD + } + Failed => { + color = RED; + XVB_FAILED + } + NotMining => { + color = ORANGE; + XVB_PUBLIC_ONLY + } + Middle | Waiting | Syncing => { + color = YELLOW; + XVB_MIDDLE + } }; + status(ui, color, hover_text, size, "XvB ⏺"); +} + +fn status(ui: &mut Ui, color: Color32, hover_text: &str, size: Vec2, text: &str) { + ui.add_sized(size, Label::new(RichText::new(text).color(color))) + .on_hover_text(hover_text); } diff --git a/src/app/panels/middle/mod.rs b/src/app/panels/middle/mod.rs index 017ec075..a8b2acba 100644 --- a/src/app/panels/middle/mod.rs +++ b/src/app/panels/middle/mod.rs @@ -19,6 +19,7 @@ impl crate::app::App { key: KeyPressed, p2pool_is_alive: bool, xmrig_is_alive: bool, + xvb_is_alive: bool, ) { // Middle panel, contents of the [Tab] debug!("App | Rendering CENTRAL_PANEL (tab contents)"); @@ -144,7 +145,7 @@ path_xmr: {:#?}\n } Tab::Status => { debug!("App | Entering [Status] Tab"); - crate::disk::state::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.xvb_api,&self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, self.max_threads, &self.gupax_p2pool_api, &self.benchmarks, self.size, ctx, ui); + crate::disk::state::Status::show(&mut self.state.status, &self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.xvb_api,&self.p2pool_img, &self.xmrig_img, p2pool_is_alive, xmrig_is_alive, xvb_is_alive, self.max_threads, &self.gupax_p2pool_api, &self.benchmarks, self.size, ctx, ui); } Tab::Gupax => { debug!("App | Entering [Gupax] Tab"); @@ -160,7 +161,7 @@ path_xmr: {:#?}\n } Tab::Xvb => { debug!("App | Entering [XvB] Tab"); - crate::disk::state::Xvb::show(self.size, ctx, ui, &self.xvb_api); + crate::disk::state::Xvb::show(&mut self.state.xvb, self.size, ctx, ui, &self.xvb_api); } } }); diff --git a/src/app/panels/middle/status/mod.rs b/src/app/panels/middle/status/mod.rs index 335a19eb..061ab070 100644 --- a/src/app/panels/middle/status/mod.rs +++ b/src/app/panels/middle/status/mod.rs @@ -46,6 +46,7 @@ impl Status { xmrig_img: &Arc>, p2pool_alive: bool, xmrig_alive: bool, + xvb_alive: bool, max_threads: usize, gupax_p2pool_api: &Arc>, benchmarks: &[Benchmark], @@ -65,6 +66,7 @@ impl Status { xmrig_alive, xmrig_api, xmrig_img, + xvb_alive, xvb_api, max_threads, ); diff --git a/src/app/panels/middle/status/processes.rs b/src/app/panels/middle/status/processes.rs index 53918c60..19331864 100644 --- a/src/app/panels/middle/status/processes.rs +++ b/src/app/panels/middle/status/processes.rs @@ -25,6 +25,7 @@ impl Status { xmrig_alive: bool, xmrig_api: &Arc>, xmrig_img: &Arc>, + xvb_alive: bool, xvb_api: &Arc>, max_threads: usize, ) { @@ -56,7 +57,7 @@ impl Status { max_threads, ); // [XvB] - xvb(ui, min_height, width, height, xvb_api); + xvb(ui, min_height, width, height, xvb_alive, xvb_api); }); } } @@ -351,11 +352,17 @@ fn xmrig( }); } -fn xvb(ui: &mut Ui, min_height: f32, width: f32, height: f32, xvb_api: &Arc>) { +fn xvb( + ui: &mut Ui, + min_height: f32, + width: f32, + height: f32, + xvb_alive: bool, + xvb_api: &Arc>, +) { // let api = lock!(xvb_api); - // if this field is empty, it means nothing was received from the API. - let enabled = !api.reward_yearly.is_empty(); + let enabled = xvb_alive; ScrollArea::vertical().show(ui, |ui| { ui.group(|ui| { ui.vertical(|ui| { diff --git a/src/app/panels/middle/xvb.rs b/src/app/panels/middle/xvb.rs index b82779ea..81265de3 100644 --- a/src/app/panels/middle/xvb.rs +++ b/src/app/panels/middle/xvb.rs @@ -1,10 +1,11 @@ use std::sync::{Arc, Mutex}; use egui::TextStyle::Name; -use egui::{Hyperlink, Image, TextEdit, Vec2}; +use egui::{Hyperlink, Image, Label, RichText, TextEdit, Vec2}; use log::debug; use crate::helper::xvb::PubXvbApi; +use crate::utils::constants::{GREEN, LIGHT_GRAY, RED, XVB_HELP, XVB_TOKEN_LEN}; use crate::utils::macros::lock; use crate::{ constants::{BYTES_XVB, SPACE}, @@ -13,11 +14,16 @@ use crate::{ impl crate::disk::state::Xvb { #[inline(always)] // called once - pub fn show(size: Vec2, _ctx: &egui::Context, ui: &mut egui::Ui, api: &Arc>) { + pub fn show( + &mut self, + size: Vec2, + _ctx: &egui::Context, + ui: &mut egui::Ui, + api: &Arc>, + ) { let website_height = size.y / 10.0; // let width = size.x - SPACE; // let height = size.y - SPACE; - let height = size.y; let width = size.x; let text_edit = size.y / 25.0; // logo and website link @@ -50,8 +56,37 @@ impl crate::disk::state::Xvb { ); }); }); - // address check - // input token }); + // input token + let len_token = format!("{}", self.token.len()); + let text_check; + let color; + if self.token.is_empty() { + text_check = format!("[{}/{}] ➖", len_token, XVB_TOKEN_LEN); + color = LIGHT_GRAY; + } else if self.token.parse::().is_ok() && self.token.len() < XVB_TOKEN_LEN { + text_check = format!("[{}/{}] ", len_token, XVB_TOKEN_LEN); + color = GREEN; + } else if self.token.parse::().is_ok() && self.token.len() == XVB_TOKEN_LEN { + text_check = "✔".to_string(); + color = GREEN; + } else { + text_check = format!("[{}/{}] ❌", len_token, XVB_TOKEN_LEN); + color = RED; + } + ui.group(|ui| { + let width = width - SPACE; + ui.spacing_mut().text_edit_width = (width) - (SPACE * 3.0); + ui.label("Your Token:"); + ui.horizontal(|ui| { + ui.add_sized( + [width / 8.0, text_edit], + TextEdit::singleline(&mut self.token), + ) + .on_hover_text_at_pointer(XVB_HELP); + ui.add(Label::new(RichText::new(text_check).color(color))) + }); + }); + // need to warn the user if no address is set in p2pool tab } } diff --git a/src/disk/state.rs b/src/disk/state.rs index 53ec1d39..968ca1e6 100644 --- a/src/disk/state.rs +++ b/src/disk/state.rs @@ -1,5 +1,6 @@ use anyhow::{bail, Result}; use hyper::StatusCode; +use hyper_tls::HttpsConnector; use super::*; use crate::{components::node::RemoteNode, disk::status::*}; @@ -329,8 +330,8 @@ impl Default for P2pool { impl Xvb { pub async fn is_token_exist(address: String, token: String) -> Result<()> { - let client: hyper::Client = - hyper::Client::builder().build(hyper::client::HttpConnector::new()); + let https = HttpsConnector::new(); + let client = hyper::Client::builder().build(https); if let Ok(request) = hyper::Request::builder() .method("GET") .uri(format!( @@ -339,16 +340,17 @@ impl Xvb { )) .body(hyper::Body::empty()) { - if let Ok(resp) = client.request(request).await { - match resp.status() { + match client.request(request).await { + Ok(resp) => match resp.status() { StatusCode::OK => Ok(()), StatusCode::UNPROCESSABLE_ENTITY => { bail!("the token is invalid for this xmr address.") } _ => bail!("The status of the response is not expected"), + }, + Err(err) => { + bail!("error from response: {}", err) } - } else { - bail!("error from response") } } else { bail!("request could not be build") diff --git a/src/helper/mod.rs b/src/helper/mod.rs index bc77633b..7d329fab 100644 --- a/src/helper/mod.rs +++ b/src/helper/mod.rs @@ -412,6 +412,7 @@ impl Helper { let lock = lock!(helper); let p2pool = Arc::clone(&lock.p2pool); let xmrig = Arc::clone(&lock.xmrig); + let xvb = Arc::clone(&lock.xvb); let pub_sys = Arc::clone(&lock.pub_sys); let gui_api_p2pool = Arc::clone(&lock.gui_api_p2pool); let gui_api_xmrig = Arc::clone(&lock.gui_api_xmrig); @@ -438,25 +439,27 @@ impl Helper { // 2. Lock... EVERYTHING! let mut lock = lock!(helper); - debug!("Helper | Locking (1/10) ... [helper]"); + debug!("Helper | Locking (1/11) ... [helper]"); let p2pool = lock!(p2pool); - debug!("Helper | Locking (2/10) ... [p2pool]"); + debug!("Helper | Locking (2/11) ... [p2pool]"); let xmrig = lock!(xmrig); - debug!("Helper | Locking (3/10) ... [xmrig]"); + debug!("Helper | Locking (3/11) ... [xmrig]"); + let xvb = lock!(xvb); + debug!("Helper | Locking (4/11) ... [xvb]"); let mut lock_pub_sys = lock!(pub_sys); - debug!("Helper | Locking (4/10) ... [pub_sys]"); + debug!("Helper | Locking (5/11) ... [pub_sys]"); let mut gui_api_p2pool = lock!(gui_api_p2pool); - debug!("Helper | Locking (5/10) ... [gui_api_p2pool]"); + debug!("Helper | Locking (6/11) ... [gui_api_p2pool]"); let mut gui_api_xmrig = lock!(gui_api_xmrig); - debug!("Helper | Locking (6/10) ... [gui_api_xmrig]"); + debug!("Helper | Locking (7/11) ... [gui_api_xmrig]"); let mut gui_api_xvb = lock!(gui_api_xvb); - debug!("Helper | Locking (7/10) ... [gui_api_xvb]"); + debug!("Helper | Locking (8/11) ... [gui_api_xvb]"); let mut pub_api_p2pool = lock!(pub_api_p2pool); - debug!("Helper | Locking (8/10) ... [pub_api_p2pool]"); + debug!("Helper | Locking (9/11) ... [pub_api_p2pool]"); let mut pub_api_xmrig = lock!(pub_api_xmrig); - debug!("Helper | Locking (9/10) ... [pub_api_xmrig]"); + debug!("Helper | Locking (10/11) ... [pub_api_xmrig]"); let mut pub_api_xvb = lock!(pub_api_xvb); - debug!("Helper | Locking (10/10) ... [pub_api_xvb]"); + debug!("Helper | Locking (11/11) ... [pub_api_xvb]"); // Calculate Gupax's uptime always. lock.uptime = HumanTime::into_human(lock.instant.elapsed()); // If [P2Pool] is alive... @@ -473,9 +476,13 @@ impl Helper { } else { debug!("Helper | XMRig is dead! Skipping..."); } - // XvB API is considered always available - debug!("Helper | XvB is alive! Running [combine_gui_pub_api()]"); - PubXvbApi::combine_gui_pub_api(&mut gui_api_xvb, &mut pub_api_xvb); + // If [XvB] is alive... + if xvb.is_alive() { + debug!("Helper | XvB is alive! Running [combine_gui_pub_api()]"); + PubXvbApi::combine_gui_pub_api(&mut gui_api_xvb, &mut pub_api_xvb); + } else { + debug!("Helper | XvB is dead! Skipping..."); + } // 2. Selectively refresh [sysinfo] for only what we need (better performance). sysinfo.refresh_cpu_specifics(sysinfo_cpu); @@ -495,25 +502,27 @@ impl Helper { // 3. Drop... (almost) EVERYTHING... IN REVERSE! drop(lock_pub_sys); - debug!("Helper | Unlocking (1/10) ... [pub_sys]"); + debug!("Helper | Unlocking (1/11) ... [pub_sys]"); + drop(xvb); + debug!("Helper | Unlocking (2/11) ... [xvb]"); drop(xmrig); - debug!("Helper | Unlocking (2/10) ... [xmrig]"); + debug!("Helper | Unlocking (3/11) ... [xmrig]"); drop(p2pool); - debug!("Helper | Unlocking (3/10) ... [p2pool]"); + debug!("Helper | Unlocking (4/11) ... [p2pool]"); drop(pub_api_xvb); - debug!("Helper | Unlocking (4/10) ... [pub_api_xvb]"); + debug!("Helper | Unlocking (5/11) ... [pub_api_xvb]"); drop(pub_api_xmrig); - debug!("Helper | Unlocking (5/10) ... [pub_api_xmrig]"); + debug!("Helper | Unlocking (6/11) ... [pub_api_xmrig]"); drop(pub_api_p2pool); - debug!("Helper | Unlocking (6/10) ... [pub_api_p2pool]"); + debug!("Helper | Unlocking (7/11) ... [pub_api_p2pool]"); drop(gui_api_xvb); - debug!("Helper | Unlocking (7/10) ... [gui_api_xvb]"); + debug!("Helper | Unlocking (8/11) ... [gui_api_xvb]"); drop(gui_api_xmrig); - debug!("Helper | Unlocking (8/10) ... [gui_api_xmrig]"); + debug!("Helper | Unlocking (9/11) ... [gui_api_xmrig]"); drop(gui_api_p2pool); - debug!("Helper | Unlocking (9/10) ... [gui_api_p2pool]"); + debug!("Helper | Unlocking (10/11) ... [gui_api_p2pool]"); drop(lock); - debug!("Helper | Unlocking (10/10) ... [helper]"); + debug!("Helper | Unlocking (11/11) ... [helper]"); // 4. Calculate if we should sleep or not. // If we should sleep, how long? diff --git a/src/helper/xvb.rs b/src/helper/xvb.rs index 5c8afcbe..5bd79371 100644 --- a/src/helper/xvb.rs +++ b/src/helper/xvb.rs @@ -26,8 +26,13 @@ impl Helper { // Just sets some signals for the watchdog thread to pick up on. pub fn stop_xvb(helper: &Arc>) { info!("XvB | Attempting to stop..."); - lock2!(helper, p2pool).signal = ProcessSignal::Stop; - lock2!(helper, p2pool).state = ProcessState::Middle; + lock2!(helper, xvb).signal = ProcessSignal::Stop; + lock2!(helper, xvb).state = ProcessState::Middle; + // Reset stats + let gui_api = Arc::clone(&lock!(helper).gui_api_xvb); + let pub_api = Arc::clone(&lock!(helper).pub_api_xvb); + *lock!(pub_api) = PubXvbApi::new(); + *lock!(gui_api) = PubXvbApi::new(); } pub fn restart_xvb( helper: &Arc>, @@ -35,8 +40,8 @@ impl Helper { state_p2pool: &crate::disk::state::P2pool, ) { info!("XvB | Attempting to restart..."); - lock2!(helper, p2pool).signal = ProcessSignal::Restart; - lock2!(helper, p2pool).state = ProcessState::Middle; + lock2!(helper, xvb).signal = ProcessSignal::Restart; + lock2!(helper, xvb).state = ProcessState::Middle; let helper = helper.clone(); let state_xvb = state_xvb.clone(); let state_p2pool = state_p2pool.clone(); @@ -66,29 +71,39 @@ impl Helper { let process = Arc::clone(&lock!(helper).xvb); let state_xvb = state_xvb.clone(); let state_p2pool = state_p2pool.clone(); - // two first verifications should be done before starting the process and giving the possibility to start it. - // verify if address is inserted - // if state_p2pool.address.is_empty() { - // warn!("Xvb | Start ... Failed because payout address is not inserted in P2pool tab"); - // lock2!(helper, xvb).state = ProcessState::Failed; - // return; - // } - // verify if token exist - // if state_xvb.token.is_empty() { - // warn!("Xvb | Start ... Failed because valid token is not inserted in XvB tab"); - // lock2!(helper, xvb).state = ProcessState::Failed; - // return; - // } + + // 2. Set process state + debug!("XvB | Setting process state..."); + { + let mut lock = lock!(process); + lock.state = ProcessState::Middle; + lock.signal = ProcessSignal::None; + lock.start = Instant::now(); + } // verify if token and address are existent on XvB server let rt = tokio::runtime::Runtime::new().unwrap(); - if !rt.block_on(async move { - Xvb::is_token_exist(state_p2pool.address, state_xvb.token) - .await - .is_ok() - }) { - warn!("Xvb | Start ... Failed because token and associated address are not existent on XvB server"); - lock2!(helper, xvb).state = ProcessState::Failed; - return; + let resp: anyhow::Result<()> = rt.block_on(async move { + Xvb::is_token_exist(state_p2pool.address, state_xvb.token).await?; + Ok(()) + }); + match resp { + Ok(_) => { + let mut lock = lock!(process); + lock.state = ProcessState::Alive; + } + Err(err) => { + // send to console: token non existent for address on XvB server + warn!("Xvb | Start ... Failed because token and associated address are not existent on XvB server: {}", err); + // output the error to console + if let Err(e) = writeln!( + lock!(gui_api).output, + "Failure to retrieve private stats from XvB server.\nError: {}", + err + ) { + error!("XvB Watchdog | GUI status write failed: {}", e); + } + lock2!(helper, xvb).state = ProcessState::NotMining; + } } thread::spawn(move || { @@ -104,49 +119,67 @@ impl Helper { ) { info!("XvB started"); - // 2. Set process state - debug!("XvB | Setting process state..."); - { - let mut lock = lock!(process); - lock.state = ProcessState::Middle; - lock.signal = ProcessSignal::None; - lock.start = Instant::now(); + if let Err(e) = writeln!( + lock!(gui_api).output, + "{}\nXvb started\n{}\n\n", + HORI_CONSOLE, + HORI_CONSOLE + ) { + error!("XvB Watchdog | GUI status write failed: {}", e); } - // Reset stats before loop - *lock!(pub_api) = PubXvbApi::new(); - *lock!(gui_api) = PubXvbApi::new(); - let start = lock!(process).start; info!("XvB | Entering watchdog mode... woof!"); loop { + debug!("XvB Watchdog | ----------- Start of loop -----------"); // Set timer let now = Instant::now(); // check signal + debug!("XvB | check signal"); if signal_interrupt(process.clone(), start, gui_api.clone()) { break; } - debug!("XvB Watchdog | ----------- Start of loop -----------"); - // Send an HTTP API request - debug!("XvB Watchdog | Attempting HTTP API request..."); - match PubXvbApi::request_xvb_public_api(client.clone(), XVB_URL_PUBLIC_API).await { - Ok(new_data) => { - debug!("XvB Watchdog | HTTP API request OK"); - let mut data = lock!(&pub_api); - *data = new_data; - } - Err(err) => { - warn!( - "XvB Watchdog | Could not send HTTP API request to: {}\n:{}", - XVB_URL_PUBLIC_API, err - ); + // Send an HTTP API request only if one minute is passed since the last. + // if since is 0, send request because it's the first time. + let since = lock!(gui_api).tick; + if since >= 60 || since == 0 { + // *lock!(pub_api) = PubXvbApi::new(); + // *lock!(gui_api) = PubXvbApi::new(); + debug!("XvB Watchdog | Attempting HTTP API request..."); + match PubXvbApi::request_xvb_public_api(client.clone(), XVB_URL_PUBLIC_API).await { + Ok(new_data) => { + debug!("XvB Watchdog | HTTP API request OK"); + *lock!(&pub_api) = new_data; + lock!(gui_api).tick += 0; + } + Err(err) => { + warn!( + "XvB Watchdog | Could not send HTTP API request to: {}\n:{}", + XVB_URL_PUBLIC_API, err + ); + // output the error to console + if let Err(e) = writeln!( + lock!(gui_api).output, + "Failure to retrieve public stats from {}", + XVB_URL_PUBLIC_API + ) { + error!("XvB Watchdog | GUI status write failed: {}", e); + } + lock!(process).state = ProcessState::Failed; + break; + } } } - // XvB Status do not need to be refreshed like others because combine_with_gui do not refresh if no data is changed. - let elapsed = now.elapsed().as_secs(); - if elapsed < 59 { - let sleep = 60 - elapsed; + + lock!(gui_api).tick += 1; + // Reset stats before loop + + // Sleep (only if 900ms hasn't passed) + let elapsed = now.elapsed().as_millis(); + // Since logic goes off if less than 1000, casting should be safe + if elapsed < 900 { + let sleep = (900 - elapsed) as u64; debug!("XvB Watchdog | END OF LOOP - Sleeping for [{}]s...", sleep); - std::thread::sleep(std::time::Duration::from_secs(sleep)) + std::thread::sleep(std::time::Duration::from_millis(sleep)) } else { debug!("XMRig Watchdog | END OF LOOP - Not sleeping!"); } @@ -161,6 +194,8 @@ pub struct PubXvbApi { pub output: String, #[serde(skip)] pub uptime: HumanTime, + #[serde(skip)] + pub tick: u8, pub time_remain: u32, // remaining time of round in minutes pub bonus_hr: f64, pub donate_hr: f64, // donated hr from all donors @@ -205,11 +240,22 @@ impl PubXvbApi { pub fn new() -> Self { Self::default() } + // The issue with just doing [gui_api = pub_api] is that values get overwritten. + // This doesn't matter for any of the values EXCEPT for the output, so we must + // manually append it instead of overwriting. + // This is used in the "helper" thread. pub(super) fn combine_gui_pub_api(gui_api: &mut Self, pub_api: &mut Self) { - // update only if there is data, if no new data, pub_api fields are on default value. - if !pub_api.reward_yearly.is_empty() { - *gui_api = std::mem::take(pub_api) + let mut output = std::mem::take(&mut gui_api.output); + let buf = std::mem::take(&mut pub_api.output); + if !buf.is_empty() { + output.push_str(&buf); } + let tick = std::mem::take(&mut gui_api.tick); + *gui_api = Self { + output, + tick, + ..pub_api.clone() + }; } #[inline] // Send an HTTP request to XvB's API, serialize it into [Self] and return it @@ -258,23 +304,14 @@ fn signal_interrupt( } debug!("XvB Watchdog | Stop SIGNAL done, breaking"); lock!(process).signal = ProcessSignal::None; + lock!(process).state = ProcessState::Dead; return true; // Check RESTART } else if lock!(process).signal == ProcessSignal::Restart { debug!("XvB Watchdog | Restart SIGNAL caught"); let uptime = HumanTime::into_human(start.elapsed()); info!("XvB Watchdog | Stopped ... Uptime was: [{}]", uptime); - // insert the signal into output of XvB - // This is written directly into the GUI API, because sometimes the 900ms event loop can't catch it. - if let Err(e) = writeln!( - lock!(gui_api).output, - "{}\nXvb stopped | Uptime: [{}] | \n{}\n\n\n\n", - HORI_CONSOLE, - uptime, - HORI_CONSOLE - ) { - error!("XvB Watchdog | GUI Uptime/Exit status write failed: {}", e); - } + // no output to console because service will be started with fresh output. debug!("XvB Watchdog | Restart SIGNAL done, breaking"); lock!(process).state = ProcessState::Waiting; return true; diff --git a/src/utils/constants.rs b/src/utils/constants.rs index c14996bd..bdca3047 100644 --- a/src/utils/constants.rs +++ b/src/utils/constants.rs @@ -107,6 +107,7 @@ pub const XVB_DEAD: &str = "XvB process is offline"; pub const XVB_FAILED: &str = "XvB process is misconfigured or the XvB node is offline"; pub const XVB_MIDDLE: &str = "XvB is in the middle of (re)starting/stopping"; pub const XVB_NOT_CONFIGURED: &str = "You need to insert an existent token before starting XvB"; +pub const XVB_PUBLIC_ONLY: &str = "XvB process is started only to get public stats"; // This is the typical space added when using // [ui.separator()] or [ui.group()] @@ -409,6 +410,7 @@ pub const XMRIG_PATH_EMPTY: &str = "XMRig PATH is empty! To fix: goto the [G pub const XVB_HELP: &str = "You need to register an account by clicking on the link above to get your token with the same p2pool XMR address you use for payment."; pub const XVB_URL: &str = "https://xmrvsbeast.com"; pub const XVB_URL_PUBLIC_API: &str = "https://xmrvsbeast.com/p2pool/stats"; +pub const XVB_TOKEN_LEN: usize = 9; // CLI argument messages pub const ARG_HELP: &str = r#"USAGE: ./gupax [--flag]