mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-11-16 15:27:46 +00:00
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:
parent
ecb1dd23e0
commit
9d163ae85e
12 changed files with 326 additions and 109 deletions
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
);
|
||||
})
|
||||
});
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
Loading…
Reference in a new issue