feat: finish XvB Tab with private stats and better log output

fix: color code status
feat: reload automaticcly XvB process if p2pool is off/online
feat: add all 5 private stat in a pretty way outside of console
feat: begin to use readable to replace human.rs
feat: function to verify if share is in current window
feat: maj TODO

feat: Maj TODO
This commit is contained in:
Louis-Marie Baer 2024-03-15 21:40:27 +01:00
parent ecb1dd23e0
commit 9d163ae85e
12 changed files with 326 additions and 109 deletions

View file

@ -37,7 +37,6 @@ egui = "0.26.2"
egui_extras = { version = "0.26.2", features = ["image"] }
## 2023-12-28: https://github.com/hinto-janai/gupax/issues/68
eframe = { version = "0.26.2", default-features = false, features = ["glow"] }
## 2023-02-06: The below gets fixed by using the [wgpu] backend instead of [glow]
## It also fixes crashes on CPU-based graphics. Only used for Windows.
## Using [wgpu] actually crashes macOS (fixed in 0.20.x though).
@ -82,7 +81,7 @@ serde-this-or-that = "0.4.2"
tar = "0.4.40"
flate2 = "1.0"
sudo = "0.6.0"
readable = "0.16"
# macOS
[target.'cfg(target_os = "macos")'.dependencies]
# On apple-darwin targets there is an issue with the native and rustls
@ -97,6 +96,8 @@ openssl = { version = "0.10", features = ["vendored"] }
# We don't even use `xz` in `flate2` but this gets dynamically
# linked as well which causes problems, so statically link it.
lzma-sys = { version = "0.1.20", features = ["static"] }
[dev-dependencies]
egui = {version = "0.26.2", features=["callstack"]}
[target.'cfg(not(target_os = "macos"))'.dependencies]
tls-api-native-tls = "0.9.0"

View file

@ -13,11 +13,11 @@
- [x] link and message hovering explaining registration and needs to read the rules.
- [x] token input
- [x] hero checkbox
- [ ] log section
- [ ] round type in
- [ ] win or loose
- [x] log section
- [x] state of XvB process
- [x] private stats
- [x] round type in
- [x] win or loose
- [ ] new process for XvB
- [x] status process XvB
- [x] public information from [API](https://xmrvsbeast.com/p2pool/stats)

View file

@ -644,11 +644,11 @@ fn status_xvb(state: ProcessState, ui: &mut Ui, size: Vec2) {
color = RED;
XVB_FAILED
}
NotMining => {
NotMining | Syncing => {
color = ORANGE;
XVB_PUBLIC_ONLY
}
Middle | Waiting | Syncing => {
Middle | Waiting => {
color = YELLOW;
XVB_MIDDLE
}

View file

@ -1,9 +1,8 @@
use std::sync::{Arc, Mutex};
use crate::{
app::Benchmark, disk::state::Status, helper::xmrig::PubXmrigApi, utils::human::HumanNumber,
};
use crate::{app::Benchmark, disk::state::Status, helper::xmrig::PubXmrigApi};
use egui::{Hyperlink, ProgressBar, Spinner, Vec2};
use readable::num::{Float, Percent, Unsigned};
use crate::utils::macros::lock;
@ -67,7 +66,7 @@ impl Status {
.on_hover_text(STATUS_SUBMENU_YOUR_HIGH);
ui.add_sized(
[width, text],
Label::new(format!("{} H/s", HumanNumber::from_f32(cpu.high))),
Label::new(format!("{} H/s", Float::from_0(cpu.high.into()))),
);
ui.add_sized(
[width, text],
@ -76,7 +75,7 @@ impl Status {
.on_hover_text(STATUS_SUBMENU_YOUR_AVERAGE);
ui.add_sized(
[width, text],
Label::new(format!("{} H/s", HumanNumber::from_f32(cpu.average))),
Label::new(format!("{} H/s", Float::from_0(cpu.average.into()))),
);
ui.add_sized(
[width, text],
@ -85,7 +84,7 @@ impl Status {
.on_hover_text(STATUS_SUBMENU_YOUR_LOW);
ui.add_sized(
[width, text],
Label::new(format!("{} H/s", HumanNumber::from_f32(cpu.low))),
Label::new(format!("{} H/s", Float::from_0(cpu.low.into()))),
);
})
})
@ -96,7 +95,7 @@ impl Status {
if xmrig_alive {
let api = lock!(xmrig_api);
let percent = (api.hashrate_raw / cpu.high) * 100.0;
let human = HumanNumber::to_percent(percent);
let human = Percent::from(percent);
if percent > 100.0 {
ui.add_sized(
[width, double],
@ -188,31 +187,34 @@ impl Status {
ui.add_sized([cpu, text], Label::new(benchmark.cpu.as_str()));
ui.separator();
ui.add_sized([bar, text], ProgressBar::new(benchmark.percent / 100.0))
.on_hover_text(HumanNumber::to_percent(benchmark.percent).as_str());
.on_hover_text(Percent::from(benchmark.percent).as_str());
ui.separator();
ui.add_sized(
[high, text],
Label::new(HumanNumber::to_hashrate(benchmark.high).as_str()),
Label::new(format!("{} H/s", Float::from_0(benchmark.high.into()))),
);
ui.separator();
ui.add_sized(
[average, text],
Label::new(HumanNumber::to_hashrate(benchmark.average).as_str()),
Label::new(format!(
"{} H/s",
Float::from_0(benchmark.average.into())
)),
);
ui.separator();
ui.add_sized(
[low, text],
Label::new(HumanNumber::to_hashrate(benchmark.low).as_str()),
Label::new(format!("{} H/s", Float::from_0(benchmark.low.into()))),
);
ui.separator();
ui.add_sized(
[rank, text],
Label::new(HumanNumber::from_u16(benchmark.rank).as_str()),
Label::new(Float::from(benchmark.low).as_str()),
);
ui.separator();
ui.add_sized(
[bench, text],
Label::new(HumanNumber::from_u16(benchmark.benchmarks).as_str()),
Label::new(Unsigned::from(benchmark.benchmarks).as_str()),
);
})
});

View file

@ -1,6 +1,7 @@
use std::sync::{Arc, Mutex};
use egui::{Label, RichText, SelectableLabel, Slider, TextEdit, Vec2};
use readable::num::Unsigned;
use crate::{
disk::{
@ -9,7 +10,7 @@ use crate::{
status::{Hash, PayoutView},
},
helper::p2pool::PubP2poolApi,
utils::{constants::*, human::HumanNumber, macros::lock},
utils::{constants::*, macros::lock},
};
impl Status {
@ -267,7 +268,7 @@ impl Status {
);
ui.add_sized(
[width, text],
Label::new(format!("{} H/s", HumanNumber::from_u64(hashrate))),
Label::new(format!("{} H/s", Unsigned::from(hashrate))),
);
ui.add_sized(
[width, text],

View file

@ -1,4 +1,5 @@
use egui::{ScrollArea, Ui, Vec2};
use readable::up::UptimeFull;
use std::sync::{Arc, Mutex};
use crate::disk::state::Status;
@ -164,7 +165,17 @@ fn p2pool(
Label::new(RichText::new("Shares Found").underline().color(BONE)),
)
.on_hover_text(STATUS_P2POOL_SHARES);
ui.add_sized([width, height], Label::new(format!("{}", api.shares_found)));
ui.add_sized(
[width, height],
Label::new(format!(
"{}",
if let Some(s) = api.shares_found {
s.to_string()
} else {
UNKNOWN_DATA.to_string()
}
)),
);
ui.add_sized(
[width, height],
Label::new(RichText::new("Payouts").underline().color(BONE)),
@ -293,7 +304,10 @@ fn xmrig(
Label::new(RichText::new("Uptime").underline().color(BONE)),
)
.on_hover_text(STATUS_XMRIG_UPTIME);
ui.add_sized([width, height], Label::new(format!("{}", api.uptime)));
ui.add_sized(
[width, height],
Label::new(UptimeFull::from(api.uptime).as_str()),
);
ui.add_sized(
[width, height],
Label::new(

View file

@ -7,7 +7,8 @@ use log::debug;
use crate::helper::xvb::PubXvbApi;
use crate::utils::constants::{
GREEN, LIGHT_GRAY, ORANGE, RED, XVB_DONATED_1H_FIELD, XVB_DONATED_24H_FIELD, XVB_FAILURE_FIELD,
XVB_HELP, XVB_HERO_SELECT, XVB_TOKEN_FIELD, XVB_TOKEN_LEN, XVB_URL_RULES,
XVB_HELP, XVB_HERO_SELECT, XVB_ROUND_TYPE_FIELD, XVB_TOKEN_FIELD, XVB_TOKEN_LEN, XVB_URL_RULES,
XVB_WINNER_FIELD,
};
use crate::utils::macros::lock;
use crate::utils::regex::Regexes;
@ -125,11 +126,15 @@ impl crate::disk::state::Xvb {
// ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
// widget takes a third less space for two separator.
let width_stat =
(ui.available_width() / 3.0) - (12.0 + ui.style().spacing.item_spacing.x) / 3.0;
let width_stat = (ui.available_width() / 5.0)
- ((24.0 + ui.style().spacing.item_spacing.x + SPACE) / 5.0);
// 0.0 means minimum
let height_stat = 0.0;
let size_stat = vec2(width_stat, height_stat);
let round = match &priv_stats.round_participate {
Some(r) => r.to_string(),
None => "None".to_string(),
};
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.group(|ui| {
let size_stat = vec2(
@ -159,12 +164,36 @@ impl crate::disk::state::Xvb {
})
.response
});
ui.separator();
ui.add_enabled_ui(priv_stats.round_participate.is_some(), |ui| {
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_ROUND_TYPE_FIELD);
ui.label(round);
})
.response
})
.on_disabled_hover_text("You do not yet have a share in the PPLNS Window.");
});
ui.separator();
ui.add_sized(size_stat, |ui: &mut Ui| {
ui.vertical_centered(|ui| {
ui.label(XVB_WINNER_FIELD);
ui.label(
priv_stats
.win_current
.then(|| "You are Winning the round !")
.unwrap_or("You are not the winner"),
);
})
.response
});
})
.response
});
});
// Rules link help
ui.add_space(ui.available_height() / 4.0);
ui.add_space(ui.available_height() / 2.0);
ui.vertical_centered(|ui| {
ui.hyperlink_to("Rules", XVB_URL_RULES)
.on_hover_text("Click here to read the rules and understand how the raffle works.");

View file

@ -742,7 +742,10 @@ mod test {
assert_eq!(p.hashrate_15m.to_string(), "10,000");
assert_eq!(p.hashrate_1h.to_string(), "20,000");
assert_eq!(p.hashrate_24h.to_string(), "30,000");
assert_eq!(p.shares_found.to_string(), "1,000");
assert_eq!(
p.shares_found.expect("the value is set").to_string(),
"1,000"
);
assert_eq!(p.average_effort.to_string(), "100.00%");
assert_eq!(p.current_effort.to_string(), "200.00%");
assert_eq!(p.connections.to_string(), "1,234");

View file

@ -167,7 +167,7 @@ impl Helper {
// Takes in a 95-char Monero address, returns the first and last
// 6 characters separated with dots like so: [4abcde...abcdef]
fn head_tail_of_monero_address(address: &str) -> String {
pub fn head_tail_of_monero_address(address: &str) -> String {
if address.len() < 95 {
return "???".to_string();
}
@ -718,7 +718,7 @@ pub struct PubP2poolApi {
pub hashrate_15m: HumanNumber,
pub hashrate_1h: HumanNumber,
pub hashrate_24h: HumanNumber,
pub shares_found: HumanNumber,
pub shares_found: Option<u64>,
pub average_effort: HumanNumber,
pub current_effort: HumanNumber,
pub connections: HumanNumber,
@ -775,7 +775,7 @@ impl PubP2poolApi {
hashrate_15m: HumanNumber::unknown(),
hashrate_1h: HumanNumber::unknown(),
hashrate_24h: HumanNumber::unknown(),
shares_found: HumanNumber::unknown(),
shares_found: None,
average_effort: HumanNumber::unknown(),
current_effort: HumanNumber::unknown(),
connections: HumanNumber::unknown(),
@ -944,7 +944,7 @@ impl PubP2poolApi {
hashrate_15m: HumanNumber::from_u64(local.hashrate_15m),
hashrate_1h: HumanNumber::from_u64(local.hashrate_1h),
hashrate_24h: HumanNumber::from_u64(local.hashrate_24h),
shares_found: HumanNumber::from_u64(local.shares_found),
shares_found: Some(local.shares_found),
average_effort: HumanNumber::to_percent(local.average_effort),
current_effort: HumanNumber::to_percent(local.current_effort),
connections: HumanNumber::from_u32(local.connections),
@ -1114,6 +1114,45 @@ impl PubP2poolApi {
_ => "[************************************************************]",
}
}
// function to know if a share is in current window.
// If new share found, an instant of when it was found.
pub(super) fn is_share_present_in_ppplns_window(
&self,
old_shares: &mut u64,
last_time_found: Option<Instant>,
mini: bool,
) -> (bool, Option<Instant>) {
if let Some(v) = self.shares_found {
if v > *old_shares {
// found new share
*old_shares = v;
return (true, Some(Instant::now()));
} else {
// no new share found this last minute, check if last share is still valid
if let Some(n) = last_time_found {
// a share was found before, is it still valid ?
let time_window = if mini {
TIME_PPLNS_WINDOW_MINI
} else {
TIME_PPLNS_WINDOW_MAIN
};
if n.elapsed() > time_window {
// if time is expired, no share is present in current PW
(false, None)
} else {
// if time is not expired, at least one is present in current PW
(true, None)
}
} else {
// no share found before and no new share found, so there is no share in current PW
(false, None)
}
}
} else {
// data from p2pool is not ready yet, so no share in pplns window.
return (false, None);
}
}
}
//---------------------------------------------------------------------------------------------------- Private P2Pool "Local" Api

View file

@ -1,8 +1,11 @@
use crate::helper::{ProcessName, ProcessSignal, ProcessState};
use crate::regex::XMRIG_REGEX;
use crate::utils::human::HumanNumber;
use crate::utils::sudo::SudoState;
use crate::{constants::*, human::*, macros::*};
use crate::{constants::*, macros::*};
use log::*;
use readable::num::Unsigned;
use readable::up::Uptime;
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::{
@ -405,7 +408,7 @@ impl Helper {
"Failed"
}
};
let uptime = HumanTime::into_human(start.elapsed());
let uptime = Uptime::from(start.elapsed());
info!(
"XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]",
uptime, exit_status
@ -469,7 +472,7 @@ impl Helper {
"Unknown Error"
}
};
let uptime = HumanTime::into_human(start.elapsed());
let uptime = Uptime::from(start.elapsed());
info!(
"XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]",
uptime, exit_status
@ -598,13 +601,13 @@ impl ImgXmrig {
#[derive(Debug, Clone)]
pub struct PubXmrigApi {
pub output: String,
pub uptime: HumanTime,
pub uptime: Duration,
pub worker_id: String,
pub resources: HumanNumber,
pub hashrate: HumanNumber,
pub diff: HumanNumber,
pub accepted: HumanNumber,
pub rejected: HumanNumber,
pub resources: String,
pub hashrate: String,
pub diff: String,
pub accepted: String,
pub rejected: String,
pub hashrate_raw: f32,
}
@ -619,13 +622,13 @@ impl PubXmrigApi {
pub fn new() -> Self {
Self {
output: String::new(),
uptime: HumanTime::new(),
worker_id: "???".to_string(),
resources: HumanNumber::unknown(),
hashrate: HumanNumber::unknown(),
diff: HumanNumber::unknown(),
accepted: HumanNumber::unknown(),
rejected: HumanNumber::unknown(),
uptime: Duration::from_secs(0),
worker_id: UNKNOWN_DATA.to_string(),
resources: UNKNOWN_DATA.to_string(),
hashrate: UNKNOWN_DATA.to_string(),
diff: UNKNOWN_DATA.to_string(),
accepted: UNKNOWN_DATA.to_string(),
rejected: UNKNOWN_DATA.to_string(),
hashrate_raw: 0.0,
}
}
@ -661,7 +664,7 @@ impl PubXmrigApi {
public.output.push_str(&std::mem::take(&mut *output_pub));
}
// Update uptime
public.uptime = HumanTime::into_human(elapsed);
public.uptime = elapsed;
}
// 2. Check for "new job"/"no active...".
@ -687,11 +690,11 @@ impl PubXmrigApi {
*public = Self {
worker_id: private.worker_id,
resources: HumanNumber::from_load(private.resources.load_average),
hashrate: HumanNumber::from_hashrate(private.hashrate.total),
diff: HumanNumber::from_u128(private.connection.diff),
accepted: HumanNumber::from_u128(private.connection.accepted),
rejected: HumanNumber::from_u128(private.connection.rejected),
resources: HumanNumber::from_load(private.resources.load_average).to_string(),
hashrate: HumanNumber::from_hashrate(private.hashrate.total).to_string(),
diff: Unsigned::from(private.connection.diff as usize).to_string(),
accepted: Unsigned::from(private.connection.accepted as usize).to_string(),
rejected: Unsigned::from(private.connection.rejected as usize).to_string(),
hashrate_raw,
..std::mem::take(&mut *public)
}

View file

@ -5,6 +5,7 @@ use hyper::client::HttpConnector;
use hyper::StatusCode;
use hyper_tls::HttpsConnector;
use log::{debug, error, info, warn};
use readable::up::Uptime;
use serde::Deserialize;
use std::fmt::Write;
use std::{
@ -13,16 +14,16 @@ use std::{
time::Instant,
};
use crate::utils::constants::XVB_URL;
use crate::utils::constants::{XVB_PUBLIC_ONLY, XVB_URL};
use crate::{
helper::{ProcessSignal, ProcessState},
utils::{
constants::{HORI_CONSOLE, XVB_URL_PUBLIC_API},
human::HumanTime,
macros::{lock, lock2, sleep},
},
};
use super::p2pool::PubP2poolApi;
use super::{Helper, Process};
impl Helper {
@ -31,11 +32,6 @@ impl Helper {
info!("XvB | Attempting to stop...");
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<Mutex<Self>>,
@ -72,9 +68,15 @@ impl Helper {
let gui_api = Arc::clone(&lock!(helper).gui_api_xvb);
let pub_api = Arc::clone(&lock!(helper).pub_api_xvb);
let process = Arc::clone(&lock!(helper).xvb);
// needed to see if it is alive. For XvB process to function completely, p2pool node must be alive to check the shares in the pplns window.
let process_p2pool = Arc::clone(&lock!(helper).p2pool);
let gui_api_p2pool = Arc::clone(&lock!(helper).gui_api_p2pool);
let state_xvb_check = state_xvb.clone();
let state_p2pool_check = state_p2pool.clone();
// Reset before printing to output.
// Need to reset because values of stats would stay otherwise which could bring confusion even if panel is with a disabled theme.
*lock!(pub_api) = PubXvbApi::new();
*lock!(gui_api) = PubXvbApi::new();
// 2. Set process state
debug!("XvB | Setting process state...");
{
@ -96,16 +98,40 @@ impl Helper {
}
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);
warn!("Xvb | Start ... Partially failed because token and associated address are not existent on XvB server: {}\n", 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
"Failure to retrieve private stats from XvB server.\nError: {}\n{}\n",
err,
XVB_PUBLIC_ONLY
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
lock2!(helper, xvb).state = ProcessState::NotMining;
lock!(process).state = ProcessState::NotMining;
}
}
if !lock!(process_p2pool).is_alive() {
// send to console: p2pool process is not running
warn!("Xvb | Start ... Partially failed because P2pool instance is not running.");
// output the error to console
if let Err(e) = writeln!(
lock!(gui_api).output,
"\nFailure to completely start XvB process because p2pool instance is not running.\n",
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
lock!(process).state = ProcessState::Syncing;
}
if lock!(process).state != ProcessState::Alive {
if let Err(e) = writeln!(lock!(gui_api).output, "\n{}\n", XVB_PUBLIC_ONLY,) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
} else {
info!("XvB started");
if let Err(e) = writeln!(lock!(gui_api).output, "\nXvB started\n") {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
}
let state_xvb_thread = state_xvb.clone();
@ -118,6 +144,8 @@ impl Helper {
process,
&state_xvb_thread,
&state_p2pool_thread,
gui_api_p2pool,
process_p2pool,
);
});
}
@ -129,21 +157,57 @@ impl Helper {
process: Arc<Mutex<Process>>,
state_xvb: &crate::disk::state::Xvb,
state_p2pool: &crate::disk::state::P2pool,
gui_api_p2pool: Arc<Mutex<PubP2poolApi>>,
process_p2pool: Arc<Mutex<Process>>,
) {
info!("XvB started");
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);
}
// see how many shares are found at p2pool node only if XvB is started successfully. If it wasn't, maybe P2pool is node not running.
let mut old_shares = if lock!(process).state == ProcessState::Alive {
// a loop until the value is some to let p2pool work and get first value.
loop {
if let Some(s) = lock!(gui_api_p2pool).shares_found {
break s;
}
std::thread::sleep(std::time::Duration::from_secs(1));
}
} else {
// if Syncing state, this value is not needed
0
};
// let mut old_shares = 0;
let mut time_last_share: Option<Instant> = None;
let start = lock!(process).start;
info!("XvB | Entering watchdog mode... woof!");
loop {
debug!("XvB Watchdog | ----------- Start of loop -----------");
// verify if p2pool node is running with correct token.
if lock!(process).state != ProcessState::NotMining {
if lock!(process_p2pool).is_alive() {
// verify if state is to changed
if lock!(process).state == ProcessState::Syncing {
info!("XvB | started this time with p2pool");
lock!(process).state = ProcessState::Alive;
if let Err(e) = writeln!(
lock!(gui_api).output,
"\nXvB is now started because p2pool node came online.\n",
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
}
} else {
// verify if the state is changing because p2pool is not alive anymore.
if lock!(process).state != ProcessState::Syncing {
info!("XvB | stop partially because p2pool is not alive anymore.");
lock!(process).state = ProcessState::Alive;
if let Err(e) = writeln!(
lock!(gui_api).output,
"\nXvB is now partially stopped because p2pool node came offline.\n",
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
lock!(process).state = ProcessState::Syncing
}
}
}
// Set timer
let now = Instant::now();
// check signal
@ -151,6 +215,7 @@ impl Helper {
if signal_interrupt(process.clone(), start, gui_api.clone()) {
break;
}
// verify if
// 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;
@ -179,44 +244,86 @@ impl Helper {
}
}
debug!("XvB Watchdog | Attempting HTTP private API request...");
match XvbPrivStats::request_api(&state_p2pool.address, &state_xvb.token).await {
Ok(b) => {
debug!("XvB Watchdog | HTTP API request OK");
let new_data = match serde_json::from_slice::<XvbPrivStats>(&b) {
Ok(data) => data,
Err(e) => {
warn!("XvB Watchdog | Data provided from private API is not deserializ-able.Error: {}", e);
// output the error to console
if let Err(e) = writeln!(
// only if private API is accessible, NotMining here means that the token and address is not registered on the XvB website.
if lock!(process).state == ProcessState::Alive {
// reload private stats
match XvbPrivStats::request_api(&state_p2pool.address, &state_xvb.token).await {
Ok(b) => {
debug!("XvB Watchdog | HTTP API request OK");
let new_data = match serde_json::from_slice::<XvbPrivStats>(&b) {
Ok(data) => data,
Err(e) => {
warn!("XvB Watchdog | Data provided from private API is not deserializ-able.Error: {}", e);
// output the error to console
if let Err(e) = writeln!(
lock!(gui_api).output,
"XvB Watchdog | Data provided from private API is not deserializ-able.Error: {}", e
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
break;
}
};
lock!(&pub_api).stats_priv = new_data;
}
Err(err) => {
warn!(
break;
}
};
lock!(&pub_api).stats_priv = new_data;
}
Err(err) => {
warn!(
"XvB Watchdog | Could not send HTTP private API request to: {}\n:{}",
XVB_URL, err
);
// output the error to console
if let Err(e) = writeln!(
lock!(gui_api).output,
"Failure to retrieve private stats from {}",
XVB_URL
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
// output the error to console
if let Err(e) = writeln!(
lock!(gui_api).output,
"Failure to retrieve private stats from {}",
XVB_URL
) {
error!("XvB Watchdog | GUI status write failed: {}", e);
}
lock!(process).state = ProcessState::Failed;
break;
}
lock!(process).state = ProcessState::Failed;
break;
}
// check if share is in pplns window
// p2pool local api show only found shares and not current shares. So we need to keep track of the time
// the height of p2pool would be nicer but the p2pool api doesn't show it.
let (share, new_time) = lock!(gui_api_p2pool)
.is_share_present_in_ppplns_window(
&mut old_shares,
time_last_share,
state_p2pool.mini,
);
if let Some(n) = new_time {
time_last_share = Some(n);
}
// // verify in which round type we are
let round = if share {
let stats_priv = &lock!(pub_api).stats_priv;
match (
stats_priv.donor_1hr_avg / 1000.0,
stats_priv.donor_24hr_avg / 1000.0,
) {
x if x.0 > 1000.0 && x.1 > 1000.0 => Some(XvbRound::DonorMega),
x if x.0 > 100.0 && x.1 > 100.0 => Some(XvbRound::DonorWhale),
x if x.0 > 10.0 && x.1 > 10.0 => Some(XvbRound::DonorVip),
x if x.0 > 1.0 && x.1 > 1.0 => Some(XvbRound::Donor),
(_, _) => Some(XvbRound::Vip),
}
} else {
None
};
// refresh the round we participate
lock!(&pub_api).stats_priv.round_participate = round;
// verify if we are the winner of the current round
if &lock!(pub_api).stats_pub.winner
== Helper::head_tail_of_monero_address(&state_p2pool.address).as_str()
{
lock!(pub_api).stats_priv.win_current = true
}
}
lock!(gui_api).tick += 0;
lock!(gui_api).tick = 0;
}
lock!(gui_api).tick += 1;
@ -240,7 +347,7 @@ use serde_this_or_that::as_u64;
#[derive(Debug, Clone, Default)]
pub struct PubXvbApi {
pub output: String,
pub uptime: HumanTime,
pub uptime: u64,
pub tick: u8,
pub stats_pub: XvbPubStats,
pub stats_priv: XvbPrivStats,
@ -323,6 +430,10 @@ pub struct XvbPrivStats {
pub fails: u8,
pub donor_1hr_avg: f32,
pub donor_24hr_avg: f32,
#[serde(skip)]
pub win_current: bool,
#[serde(skip)]
pub round_participate: Option<XvbRound>,
}
#[derive(Debug, Clone, Default, Display, Deserialize)]
@ -379,15 +490,18 @@ fn signal_interrupt(
if lock!(process).signal == ProcessSignal::Stop {
debug!("P2Pool Watchdog | Stop SIGNAL caught");
// Wait to get the exit status
let uptime = HumanTime::into_human(start.elapsed());
info!("Xvb Watchdog | Stopped ... Uptime was: [{}]", uptime);
let uptime = start.elapsed();
info!(
"Xvb Watchdog | Stopped ... Uptime was: [{}]",
Uptime::from(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,
Uptime::from(uptime),
HORI_CONSOLE
) {
error!("XvB Watchdog | GUI Uptime/Exit status write failed: {}", e);
@ -399,7 +513,7 @@ fn signal_interrupt(
// Check RESTART
} else if lock!(process).signal == ProcessSignal::Restart {
debug!("XvB Watchdog | Restart SIGNAL caught");
let uptime = HumanTime::into_human(start.elapsed());
let uptime = Uptime::from(start.elapsed());
info!("XvB Watchdog | Stopped ... Uptime was: [{}]", uptime);
// no output to console because service will be started with fresh output.
debug!("XvB Watchdog | Restart SIGNAL done, breaking");

View file

@ -107,7 +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";
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()]
@ -420,6 +420,8 @@ pub const XVB_TOKEN_FIELD: &str = "Token";
pub const XVB_FAILURE_FIELD: &str = "Failures";
pub const XVB_DONATED_1H_FIELD: &str = "Donated last hour";
pub const XVB_DONATED_24H_FIELD: &str = "Donated last 24 hours";
pub const XVB_ROUND_TYPE_FIELD: &str = "Round";
pub const XVB_WINNER_FIELD: &str = "Win";
// CLI argument messages
pub const ARG_HELP: &str = r#"USAGE: ./gupax [--flag]
@ -443,6 +445,15 @@ pub const ARG_COPYRIGHT: &str = r#"Gupax is licensed under GPLv3.
For more information, see link below:
<https://github.com/hinto-janai/gupax>"#;
// Unknown Data, replace HumanNumlber::unknown()
pub const UNKNOWN_DATA: &str = "???";
// Time PPLNS WINDOW in seconds
// it is an estimation based on number of block in a pplns window and block time (10s). The difficulty of the network should adapt to get close to this value.
pub const TIME_PPLNS_WINDOW_MINI: Duration = Duration::from_secs(2160 * 10);
pub const TIME_PPLNS_WINDOW_MAIN: Duration = Duration::from_secs(363 * 10);
use std::time::Duration;
//---------------------------------------------------------------------------------------------------- Visuals
use egui::epaint::{Rounding, Shadow, Stroke};