mirror of
https://github.com/hinto-janai/gupax.git
synced 2024-12-23 03:19:21 +00:00
xmrig/status: implement API hyper/tokio call; add [Gupax] stats
This commit is contained in:
parent
81ec266e0a
commit
1e2b8f7803
8 changed files with 270 additions and 126 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -32,6 +32,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"static_vcruntime",
|
"static_vcruntime",
|
||||||
"sudo",
|
"sudo",
|
||||||
|
"sysinfo",
|
||||||
"tar",
|
"tar",
|
||||||
"tls-api",
|
"tls-api",
|
||||||
"tls-api-native-tls",
|
"tls-api-native-tls",
|
||||||
|
@ -2504,6 +2505,15 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -3820,6 +3830,20 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sysinfo"
|
||||||
|
version = "0.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d08ba83d6dde63d053e42d7230f0dc7f8d8efeb8d30d3681580d158156461ba"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"ntapi",
|
||||||
|
"once_cell",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "6.0.3"
|
version = "6.0.3"
|
||||||
|
|
|
@ -46,6 +46,7 @@ regex = { version = "1.6.0", default-features = false, features = ["perf"] }
|
||||||
rfd = "0.10.0"
|
rfd = "0.10.0"
|
||||||
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
sysinfo = { version = "0.27.0", default-features = false }
|
||||||
tls-api = "0.9.0"
|
tls-api = "0.9.0"
|
||||||
tls-api-native-tls = "0.9.0"
|
tls-api-native-tls = "0.9.0"
|
||||||
tokio = { version = "1.21.2", features = ["rt", "time", "macros", "process"] }
|
tokio = { version = "1.21.2", features = ["rt", "time", "macros", "process"] }
|
||||||
|
|
|
@ -69,6 +69,7 @@ pub const RED: egui::Color32 = egui::Color32::from_rgb(230, 50, 50);
|
||||||
pub const GREEN: egui::Color32 = egui::Color32::from_rgb(100, 230, 100);
|
pub const GREEN: egui::Color32 = egui::Color32::from_rgb(100, 230, 100);
|
||||||
pub const YELLOW: egui::Color32 = egui::Color32::from_rgb(230, 230, 100);
|
pub const YELLOW: egui::Color32 = egui::Color32::from_rgb(230, 230, 100);
|
||||||
pub const BRIGHT_YELLOW: egui::Color32 = egui::Color32::from_rgb(250, 250, 100);
|
pub const BRIGHT_YELLOW: egui::Color32 = egui::Color32::from_rgb(250, 250, 100);
|
||||||
|
pub const BONE: egui::Color32 = egui::Color32::from_rgb(190, 190, 190); // In between LIGHT_GRAY <-> GRAY
|
||||||
pub const WHITE: egui::Color32 = egui::Color32::WHITE;
|
pub const WHITE: egui::Color32 = egui::Color32::WHITE;
|
||||||
pub const GRAY: egui::Color32 = egui::Color32::GRAY;
|
pub const GRAY: egui::Color32 = egui::Color32::GRAY;
|
||||||
pub const LIGHT_GRAY: egui::Color32 = egui::Color32::LIGHT_GRAY;
|
pub const LIGHT_GRAY: egui::Color32 = egui::Color32::LIGHT_GRAY;
|
||||||
|
@ -110,6 +111,14 @@ pub const OS: &str = "🐧 Linux";
|
||||||
pub const OS_NAME: &str = "Linux";
|
pub const OS_NAME: &str = "Linux";
|
||||||
|
|
||||||
// Tooltips
|
// Tooltips
|
||||||
|
// Status
|
||||||
|
pub const STATUS_GUPAX_UPTIME: &str = "How long Gupax has been online";
|
||||||
|
pub const STATUS_GUPAX_CPU_USAGE: &str = "How much CPU Gupax is currently using. This accounts for all your threads (it is out of 100%)";
|
||||||
|
pub const STATUS_GUPAX_MEMORY_USAGE: &str = "How much memory Gupax is currently using in Megabytes";
|
||||||
|
pub const STATUS_GUPAX_SYSTEM_CPU_USAGE: &str = "How much CPU your entire system is currently using. This accounts for all your threads (it is out of 100%)";
|
||||||
|
pub const STATUS_GUPAX_SYSTEM_MEMORY: &str = "How much memory your entire system has (including swap) and is currently using in Gigabytes";
|
||||||
|
pub const STATUS_GUPAX_SYSTEM_CPU_MODEL: &str = "The detected model of your system's CPU and its current frequency";
|
||||||
|
|
||||||
// Gupax
|
// Gupax
|
||||||
pub const GUPAX_UPDATE: &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically";
|
pub const GUPAX_UPDATE: &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically";
|
||||||
pub const GUPAX_AUTO_UPDATE: &str = "Automatically check for updates at startup";
|
pub const GUPAX_AUTO_UPDATE: &str = "Automatically check for updates at startup";
|
||||||
|
|
|
@ -142,8 +142,8 @@ impl State {
|
||||||
simple: true,
|
simple: true,
|
||||||
auto_update: true,
|
auto_update: true,
|
||||||
auto_node: true,
|
auto_node: true,
|
||||||
auto_p2pool: true,
|
auto_p2pool: false,
|
||||||
auto_xmrig: true,
|
auto_xmrig: false,
|
||||||
ask_before_quit: true,
|
ask_before_quit: true,
|
||||||
save_before_quit: true,
|
save_before_quit: true,
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
|
|
@ -230,7 +230,7 @@ impl Gupax {
|
||||||
})});
|
})});
|
||||||
// Saved [Tab]
|
// Saved [Tab]
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let height = ui.available_height()/2.0;
|
let height = ui.available_height()/1.85;
|
||||||
let width = (width/5.0)-(SPACE*1.93);
|
let width = (width/5.0)-(SPACE*1.93);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.add_sized([width, height], SelectableLabel::new(self.tab == Tab::About, "About")).on_hover_text(GUPAX_TAB_ABOUT).clicked() { self.tab = Tab::About; }
|
if ui.add_sized([width, height], SelectableLabel::new(self.tab == Tab::About, "About")).on_hover_text(GUPAX_TAB_ABOUT).clicked() { self.tab = Tab::About; }
|
||||||
|
|
181
src/helper.rs
181
src/helper.rs
|
@ -46,6 +46,7 @@ use crate::{
|
||||||
constants::*,
|
constants::*,
|
||||||
SudoState,
|
SudoState,
|
||||||
};
|
};
|
||||||
|
use sysinfo::SystemExt;
|
||||||
use serde::{Serialize,Deserialize};
|
use serde::{Serialize,Deserialize};
|
||||||
use num_format::{Buffer,Locale};
|
use num_format::{Buffer,Locale};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
@ -67,7 +68,8 @@ const GUI_OUTPUT_LEEWAY: usize = MAX_GUI_OUTPUT_BYTES - 1000;
|
||||||
// A meta struct holding all the data that gets processed in this thread
|
// A meta struct holding all the data that gets processed in this thread
|
||||||
pub struct Helper {
|
pub struct Helper {
|
||||||
pub instant: Instant, // Gupax start as an [Instant]
|
pub instant: Instant, // Gupax start as an [Instant]
|
||||||
pub human_time: HumanTime, // Gupax uptime formatting for humans
|
pub uptime: HumanTime, // Gupax uptime formatting for humans
|
||||||
|
pub pub_sys: Arc<Mutex<Sys>>, // The public API for [sysinfo] that the [Status] tab reads from
|
||||||
pub p2pool: Arc<Mutex<Process>>, // P2Pool process state
|
pub p2pool: Arc<Mutex<Process>>, // P2Pool process state
|
||||||
pub xmrig: Arc<Mutex<Process>>, // XMRig process state
|
pub xmrig: Arc<Mutex<Process>>, // XMRig process state
|
||||||
pub gui_api_p2pool: Arc<Mutex<PubP2poolApi>>, // P2Pool API state (for GUI thread)
|
pub gui_api_p2pool: Arc<Mutex<PubP2poolApi>>, // P2Pool API state (for GUI thread)
|
||||||
|
@ -88,6 +90,30 @@ pub struct Helper {
|
||||||
// it's the helpers job to lock everything, and move the watchdog [Pub*Api]s
|
// it's the helpers job to lock everything, and move the watchdog [Pub*Api]s
|
||||||
// on a 1-second interval into the [GUI]'s [Pub*Api] struct, atomically.
|
// on a 1-second interval into the [GUI]'s [Pub*Api] struct, atomically.
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
#[derive(Debug,Clone)]
|
||||||
|
pub struct Sys {
|
||||||
|
pub gupax_uptime: String,
|
||||||
|
pub gupax_cpu_usage: String,
|
||||||
|
pub gupax_memory_used_mb: String,
|
||||||
|
pub system_cpu_model: String,
|
||||||
|
pub system_memory: String,
|
||||||
|
pub system_cpu_usage: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sys {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
gupax_uptime: "0 seconds".to_string(),
|
||||||
|
gupax_cpu_usage: "???%".to_string(),
|
||||||
|
gupax_memory_used_mb: "??? megabytes".to_string(),
|
||||||
|
system_cpu_usage: "???%".to_string(),
|
||||||
|
system_memory: "???GB / ???GB".to_string(),
|
||||||
|
system_cpu_model: "???".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [Process] Struct
|
//---------------------------------------------------------------------------------------------------- [Process] Struct
|
||||||
// This holds all the state of a (child) process.
|
// This holds all the state of a (child) process.
|
||||||
// The main GUI thread will use this to display console text, online state, etc.
|
// The main GUI thread will use this to display console text, online state, etc.
|
||||||
|
@ -191,10 +217,11 @@ use tokio::io::{BufReader,AsyncBufReadExt};
|
||||||
|
|
||||||
impl Helper {
|
impl Helper {
|
||||||
//---------------------------------------------------------------------------------------------------- General Functions
|
//---------------------------------------------------------------------------------------------------- General Functions
|
||||||
pub fn new(instant: std::time::Instant, p2pool: Arc<Mutex<Process>>, xmrig: Arc<Mutex<Process>>, gui_api_p2pool: Arc<Mutex<PubP2poolApi>>, gui_api_xmrig: Arc<Mutex<PubXmrigApi>>, img_p2pool: Arc<Mutex<ImgP2pool>>, img_xmrig: Arc<Mutex<ImgXmrig>>) -> Self {
|
pub fn new(instant: std::time::Instant, pub_sys: Arc<Mutex<Sys>>, p2pool: Arc<Mutex<Process>>, xmrig: Arc<Mutex<Process>>, gui_api_p2pool: Arc<Mutex<PubP2poolApi>>, gui_api_xmrig: Arc<Mutex<PubXmrigApi>>, img_p2pool: Arc<Mutex<ImgP2pool>>, img_xmrig: Arc<Mutex<ImgXmrig>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instant,
|
instant,
|
||||||
human_time: HumanTime::into_human(instant.elapsed()),
|
pub_sys,
|
||||||
|
uptime: HumanTime::into_human(instant.elapsed()),
|
||||||
priv_api_p2pool: Arc::new(Mutex::new(PrivP2poolApi::new())),
|
priv_api_p2pool: Arc::new(Mutex::new(PrivP2poolApi::new())),
|
||||||
priv_api_xmrig: Arc::new(Mutex::new(PrivXmrigApi::new())),
|
priv_api_xmrig: Arc::new(Mutex::new(PrivXmrigApi::new())),
|
||||||
pub_api_p2pool: Arc::new(Mutex::new(PubP2poolApi::new())),
|
pub_api_p2pool: Arc::new(Mutex::new(PubP2poolApi::new())),
|
||||||
|
@ -255,22 +282,6 @@ impl Helper {
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- P2Pool specific
|
//---------------------------------------------------------------------------------------------------- P2Pool specific
|
||||||
// Read P2Pool's API file.
|
|
||||||
fn read_p2pool_api(path: &std::path::PathBuf) -> Result<String, std::io::Error> {
|
|
||||||
match std::fs::read_to_string(path) {
|
|
||||||
Ok(s) => Ok(s),
|
|
||||||
Err(e) => { warn!("P2Pool API | [{}] read error: {}", path.display(), e); Err(e) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deserialize the above [String] into a [PrivP2poolApi]
|
|
||||||
fn str_to_priv_p2pool_api(string: &str) -> Result<PrivP2poolApi, serde_json::Error> {
|
|
||||||
match serde_json::from_str::<PrivP2poolApi>(string) {
|
|
||||||
Ok(a) => Ok(a),
|
|
||||||
Err(e) => { warn!("P2Pool API | Could not deserialize API data: {}", e); Err(e) },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just sets some signals for the watchdog thread to pick up on.
|
// Just sets some signals for the watchdog thread to pick up on.
|
||||||
pub fn stop_p2pool(helper: &Arc<Mutex<Self>>) {
|
pub fn stop_p2pool(helper: &Arc<Mutex<Self>>) {
|
||||||
info!("P2Pool | Attempting to stop...");
|
info!("P2Pool | Attempting to stop...");
|
||||||
|
@ -513,9 +524,9 @@ impl Helper {
|
||||||
PubP2poolApi::update_from_output(&pub_api, &output_full, &output_buf, start.elapsed(), ®ex);
|
PubP2poolApi::update_from_output(&pub_api, &output_full, &output_buf, start.elapsed(), ®ex);
|
||||||
|
|
||||||
// Read API file into string
|
// Read API file into string
|
||||||
if let Ok(string) = Self::read_p2pool_api(&path) {
|
if let Ok(string) = PrivP2poolApi::read_p2pool_api(&path) {
|
||||||
// Deserialize
|
// Deserialize
|
||||||
if let Ok(s) = Self::str_to_priv_p2pool_api(&string) {
|
if let Ok(s) = PrivP2poolApi::str_to_priv_p2pool_api(&string) {
|
||||||
// Update the structs.
|
// Update the structs.
|
||||||
PubP2poolApi::update_from_priv(&pub_api, &priv_api);
|
PubP2poolApi::update_from_priv(&pub_api, &priv_api);
|
||||||
}
|
}
|
||||||
|
@ -603,7 +614,7 @@ impl Helper {
|
||||||
pub fn start_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
|
pub fn start_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
|
||||||
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
||||||
|
|
||||||
let args = Self::build_xmrig_args_and_mutate_img(helper, state, path);
|
let (args, api_ip_port) = Self::build_xmrig_args_and_mutate_img(helper, state, path);
|
||||||
|
|
||||||
// Print arguments & user settings to console
|
// Print arguments & user settings to console
|
||||||
crate::disk::print_dash(&format!("XMRig | Launch arguments: {:#?}", args));
|
crate::disk::print_dash(&format!("XMRig | Launch arguments: {:#?}", args));
|
||||||
|
@ -616,15 +627,16 @@ impl Helper {
|
||||||
let priv_api = Arc::clone(&helper.lock().unwrap().priv_api_xmrig);
|
let priv_api = Arc::clone(&helper.lock().unwrap().priv_api_xmrig);
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
Self::spawn_xmrig_watchdog(process, gui_api, pub_api, priv_api, args, path, sudo);
|
Self::spawn_xmrig_watchdog(process, gui_api, pub_api, priv_api, args, path, sudo, api_ip_port);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes in some [State/Xmrig] and parses it to build the actual command arguments.
|
// Takes in some [State/Xmrig] and parses it to build the actual command arguments.
|
||||||
// Returns the [Vec] of actual arguments, and mutates the [ImgXmrig] for the main GUI thread
|
// Returns the [Vec] of actual arguments, and mutates the [ImgXmrig] for the main GUI thread
|
||||||
// It returns a value... and mutates a deeply nested passed argument... this is some pretty bad code...
|
// It returns a value... and mutates a deeply nested passed argument... this is some pretty bad code...
|
||||||
pub fn build_xmrig_args_and_mutate_img(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) -> Vec<String> {
|
pub fn build_xmrig_args_and_mutate_img(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) -> (Vec<String>, String) {
|
||||||
let mut args = Vec::with_capacity(500);
|
let mut args = Vec::with_capacity(500);
|
||||||
|
let mut api_ip_port = String::with_capacity(15);
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
// The actual binary we're executing is [sudo], technically
|
// The actual binary we're executing is [sudo], technically
|
||||||
// the XMRig path is just an argument to sudo, so add it.
|
// the XMRig path is just an argument to sudo, so add it.
|
||||||
|
@ -651,6 +663,7 @@ impl Helper {
|
||||||
threads: state.current_threads.to_string(),
|
threads: state.current_threads.to_string(),
|
||||||
url: "127.0.0.1:3333 (Local P2Pool)".to_string(),
|
url: "127.0.0.1:3333 (Local P2Pool)".to_string(),
|
||||||
};
|
};
|
||||||
|
api_ip_port = "127.0.0.1:18088".to_string();
|
||||||
|
|
||||||
// [Advanced]
|
// [Advanced]
|
||||||
} else {
|
} else {
|
||||||
|
@ -689,9 +702,10 @@ impl Helper {
|
||||||
url,
|
url,
|
||||||
threads: state.current_threads.to_string(),
|
threads: state.current_threads.to_string(),
|
||||||
};
|
};
|
||||||
|
api_ip_port = format!("{}:{}", api_ip, api_port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args
|
(args, api_ip_port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We actually spawn [sudo] on Unix, with XMRig being the argument.
|
// We actually spawn [sudo] on Unix, with XMRig being the argument.
|
||||||
|
@ -712,8 +726,10 @@ impl Helper {
|
||||||
cmd
|
cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// The P2Pool watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works.
|
// The XMRig watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works.
|
||||||
fn spawn_xmrig_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubXmrigApi>>, pub_api: Arc<Mutex<PubXmrigApi>>, priv_api: Arc<Mutex<PrivXmrigApi>>, args: Vec<String>, mut path: std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
|
// This isn't actually async, a tokio runtime is unfortunately needed because [Hyper] is an async library (HTTP API calls)
|
||||||
|
#[tokio::main]
|
||||||
|
async fn spawn_xmrig_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubXmrigApi>>, pub_api: Arc<Mutex<PubXmrigApi>>, priv_api: Arc<Mutex<PrivXmrigApi>>, args: Vec<String>, mut path: std::path::PathBuf, sudo: Arc<Mutex<SudoState>>, api_ip_port: String) {
|
||||||
// 1a. Create PTY
|
// 1a. Create PTY
|
||||||
let pty = portable_pty::native_pty_system();
|
let pty = portable_pty::native_pty_system();
|
||||||
let mut pair = pty.openpty(portable_pty::PtySize {
|
let mut pair = pty.openpty(portable_pty::PtySize {
|
||||||
|
@ -758,9 +774,7 @@ impl Helper {
|
||||||
let output_full = Arc::clone(&process.lock().unwrap().output_full);
|
let output_full = Arc::clone(&process.lock().unwrap().output_full);
|
||||||
let output_buf = Arc::clone(&process.lock().unwrap().output_buf);
|
let output_buf = Arc::clone(&process.lock().unwrap().output_buf);
|
||||||
|
|
||||||
// path.pop();
|
let client: hyper::Client<hyper::client::HttpConnector> = hyper::Client::builder().build(hyper::client::HttpConnector::new());
|
||||||
// path.push(P2POOL_API_PATH);
|
|
||||||
// let regex = P2poolRegex::new();
|
|
||||||
let start = process.lock().unwrap().start;
|
let start = process.lock().unwrap().start;
|
||||||
|
|
||||||
// 5. Loop as watchdog
|
// 5. Loop as watchdog
|
||||||
|
@ -838,15 +852,11 @@ impl Helper {
|
||||||
|
|
||||||
// Always update from output
|
// Always update from output
|
||||||
PubXmrigApi::update_from_output(&pub_api, &output_buf, start.elapsed());
|
PubXmrigApi::update_from_output(&pub_api, &output_buf, start.elapsed());
|
||||||
//
|
|
||||||
// // Read API file into string
|
// Send an HTTP API request
|
||||||
// if let Ok(string) = Self::read_xmrig_api(&path) {
|
if let Ok(priv_api) = PrivXmrigApi::request_xmrig_api(client.clone(), &api_ip_port).await {
|
||||||
// // Deserialize
|
PubXmrigApi::from_priv(&mut pub_api.lock().unwrap(), priv_api);
|
||||||
// if let Ok(s) = Self::str_to_priv_xmrig_api(&string) {
|
}
|
||||||
// // Update the structs.
|
|
||||||
// PubP2poolApi::update_from_priv(&pub_api, &priv_api);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check if logs need resetting
|
// Check if logs need resetting
|
||||||
Self::check_reset_output_full(&output_full, ProcessName::Xmrig);
|
Self::check_reset_output_full(&output_full, ProcessName::Xmrig);
|
||||||
|
@ -863,9 +873,44 @@ impl Helper {
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- The "helper"
|
//---------------------------------------------------------------------------------------------------- The "helper"
|
||||||
|
fn update_pub_sys_from_sysinfo(sysinfo: &sysinfo::System, pub_sys: &mut Sys, pid: &sysinfo::Pid, helper: &Helper, max_threads: usize) {
|
||||||
|
use sysinfo::{CpuExt,ProcessExt,NetworkExt,NetworksExt};
|
||||||
|
let gupax_uptime = helper.uptime.to_string();
|
||||||
|
let cpu = &sysinfo.cpus()[0];
|
||||||
|
let gupax_cpu_usage = format!("{:.2}%", sysinfo.process(*pid).unwrap().cpu_usage()/(max_threads as f32));
|
||||||
|
let gupax_memory_used_mb = HumanNumber::from_u64(sysinfo.process(*pid).unwrap().memory()/1_000_000);
|
||||||
|
let gupax_memory_used_mb = format!("{} megabytes", gupax_memory_used_mb);
|
||||||
|
let system_cpu_model = format!("{} ({}MHz)", cpu.brand(), cpu.frequency());
|
||||||
|
let system_memory = {
|
||||||
|
let used = (sysinfo.used_memory() as f64)/1_000_000_000.0;
|
||||||
|
let total = (sysinfo.total_memory() as f64)/1_000_000_000.0;
|
||||||
|
format!("{:.3} GB / {:.3} GB", used, total)
|
||||||
|
};
|
||||||
|
let system_cpu_usage = {
|
||||||
|
let mut total: f32 = 0.0;
|
||||||
|
for cpu in sysinfo.cpus() {
|
||||||
|
total += cpu.cpu_usage();
|
||||||
|
}
|
||||||
|
format!("{:.2}%", total/(max_threads as f32))
|
||||||
|
};
|
||||||
|
*pub_sys = Sys {
|
||||||
|
gupax_uptime,
|
||||||
|
gupax_cpu_usage,
|
||||||
|
gupax_memory_used_mb,
|
||||||
|
system_cpu_usage,
|
||||||
|
system_memory,
|
||||||
|
system_cpu_model,
|
||||||
|
..*pub_sys
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// The "helper" thread. Syncs data between threads here and the GUI.
|
// The "helper" thread. Syncs data between threads here and the GUI.
|
||||||
pub fn spawn_helper(helper: &Arc<Mutex<Self>>) {
|
pub fn spawn_helper(helper: &Arc<Mutex<Self>>, mut sysinfo: sysinfo::System, pid: sysinfo::Pid, max_threads: usize) {
|
||||||
let mut helper = Arc::clone(helper);
|
let mut helper = Arc::clone(helper);
|
||||||
|
let mut pub_sys = Arc::clone(&helper.lock().unwrap().pub_sys);
|
||||||
|
let sysinfo_cpu = sysinfo::CpuRefreshKind::everything();
|
||||||
|
let sysinfo_processes = sysinfo::ProcessRefreshKind::new().with_cpu();
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
info!("Helper | Hello from helper thread! Entering loop where I will spend the rest of my days...");
|
info!("Helper | Hello from helper thread! Entering loop where I will spend the rest of my days...");
|
||||||
// Begin loop
|
// Begin loop
|
||||||
|
@ -875,31 +920,37 @@ impl Helper {
|
||||||
|
|
||||||
// 2. Lock... EVERYTHING!
|
// 2. Lock... EVERYTHING!
|
||||||
let mut lock = helper.lock().unwrap();
|
let mut lock = helper.lock().unwrap();
|
||||||
|
// Calculate Gupax's uptime always.
|
||||||
|
lock.uptime = HumanTime::into_human(lock.instant.elapsed());
|
||||||
let mut gui_api_p2pool = lock.gui_api_p2pool.lock().unwrap();
|
let mut gui_api_p2pool = lock.gui_api_p2pool.lock().unwrap();
|
||||||
let mut gui_api_xmrig = lock.gui_api_xmrig.lock().unwrap();
|
let mut gui_api_xmrig = lock.gui_api_xmrig.lock().unwrap();
|
||||||
let mut pub_api_p2pool = lock.pub_api_p2pool.lock().unwrap();
|
let mut pub_api_p2pool = lock.pub_api_p2pool.lock().unwrap();
|
||||||
let mut pub_api_xmrig = lock.pub_api_xmrig.lock().unwrap();
|
let mut pub_api_xmrig = lock.pub_api_xmrig.lock().unwrap();
|
||||||
let p2pool = lock.p2pool.lock().unwrap();
|
let p2pool = lock.p2pool.lock().unwrap();
|
||||||
let xmrig = lock.xmrig.lock().unwrap();
|
let xmrig = lock.xmrig.lock().unwrap();
|
||||||
// Calculate Gupax's uptime always.
|
let mut lock_pub_sys = pub_sys.lock().unwrap();
|
||||||
let human_time = HumanTime::into_human(lock.instant.elapsed());
|
|
||||||
// If [P2Pool] is alive...
|
// If [P2Pool] is alive...
|
||||||
if p2pool.is_alive() { PubP2poolApi::combine_gui_pub_api(&mut gui_api_p2pool, &mut pub_api_p2pool); }
|
if p2pool.is_alive() { PubP2poolApi::combine_gui_pub_api(&mut gui_api_p2pool, &mut pub_api_p2pool); }
|
||||||
// If [XMRig] is alive...
|
// If [XMRig] is alive...
|
||||||
if xmrig.is_alive() { PubXmrigApi::combine_gui_pub_api(&mut gui_api_xmrig, &mut pub_api_xmrig); }
|
if xmrig.is_alive() { PubXmrigApi::combine_gui_pub_api(&mut gui_api_xmrig, &mut pub_api_xmrig); }
|
||||||
|
|
||||||
// 2. Drop... (almost) EVERYTHING... IN REVERSE!
|
// 2. Selectively refresh [sysinfo] for only what we need (better performance).
|
||||||
|
sysinfo.refresh_cpu_specifics(sysinfo_cpu);
|
||||||
|
sysinfo.refresh_processes_specifics(sysinfo_processes);
|
||||||
|
sysinfo.refresh_memory();
|
||||||
|
Self::update_pub_sys_from_sysinfo(&sysinfo, &mut lock_pub_sys, &pid, &lock, max_threads);
|
||||||
|
|
||||||
|
// 3. Drop... (almost) EVERYTHING... IN REVERSE!
|
||||||
|
drop(lock_pub_sys);
|
||||||
drop(xmrig);
|
drop(xmrig);
|
||||||
drop(p2pool);
|
drop(p2pool);
|
||||||
drop(pub_api_xmrig);
|
drop(pub_api_xmrig);
|
||||||
drop(pub_api_p2pool);
|
drop(pub_api_p2pool);
|
||||||
drop(gui_api_xmrig);
|
drop(gui_api_xmrig);
|
||||||
drop(gui_api_p2pool);
|
drop(gui_api_p2pool);
|
||||||
// Update the time... then drop :)
|
|
||||||
lock.human_time = human_time;
|
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
// 3. Calculate if we should sleep or not.
|
// 4. Calculate if we should sleep or not.
|
||||||
// If we should sleep, how long?
|
// If we should sleep, how long?
|
||||||
let elapsed = start.elapsed().as_millis();
|
let elapsed = start.elapsed().as_millis();
|
||||||
if elapsed < 1000 {
|
if elapsed < 1000 {
|
||||||
|
@ -908,7 +959,7 @@ impl Helper {
|
||||||
std::thread::sleep(std::time::Duration::from_millis((1000-elapsed) as u64));
|
std::thread::sleep(std::time::Duration::from_millis((1000-elapsed) as u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. End loop
|
// 5. End loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Something has gone terribly wrong if the helper exited this loop.
|
// 5. Something has gone terribly wrong if the helper exited this loop.
|
||||||
|
@ -1220,7 +1271,7 @@ impl PubP2poolApi {
|
||||||
let buf = std::mem::take(&mut pub_api.output);
|
let buf = std::mem::take(&mut pub_api.output);
|
||||||
*gui_api = Self {
|
*gui_api = Self {
|
||||||
output,
|
output,
|
||||||
..std::mem::take(&mut *pub_api)
|
..std::mem::take(pub_api)
|
||||||
};
|
};
|
||||||
if !buf.is_empty() { gui_api.output.push_str(&buf); }
|
if !buf.is_empty() { gui_api.output.push_str(&buf); }
|
||||||
}
|
}
|
||||||
|
@ -1327,6 +1378,22 @@ impl PrivP2poolApi {
|
||||||
connections: 0,
|
connections: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read P2Pool's API file to a [String].
|
||||||
|
fn read_p2pool_api(path: &std::path::PathBuf) -> Result<String, std::io::Error> {
|
||||||
|
match std::fs::read_to_string(path) {
|
||||||
|
Ok(s) => Ok(s),
|
||||||
|
Err(e) => { warn!("P2Pool API | [{}] read error: {}", path.display(), e); Err(e) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize the above [String] into a [PrivP2poolApi]
|
||||||
|
fn str_to_priv_p2pool_api(string: &str) -> Result<Self, serde_json::Error> {
|
||||||
|
match serde_json::from_str::<Self>(string) {
|
||||||
|
Ok(a) => Ok(a),
|
||||||
|
Err(e) => { warn!("P2Pool API | Could not deserialize API data: {}", e); Err(e) },
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- [ImgXmrig]
|
//---------------------------------------------------------------------------------------------------- [ImgXmrig]
|
||||||
|
@ -1385,7 +1452,7 @@ impl PubXmrigApi {
|
||||||
let buf = std::mem::take(&mut pub_api.output);
|
let buf = std::mem::take(&mut pub_api.output);
|
||||||
*gui_api = Self {
|
*gui_api = Self {
|
||||||
output,
|
output,
|
||||||
..std::mem::take(&mut *pub_api)
|
..std::mem::take(pub_api)
|
||||||
};
|
};
|
||||||
if !buf.is_empty() { gui_api.output.push_str(&buf); }
|
if !buf.is_empty() { gui_api.output.push_str(&buf); }
|
||||||
}
|
}
|
||||||
|
@ -1403,9 +1470,8 @@ impl PubXmrigApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats raw private data into ready-to-print human readable version.
|
// Formats raw private data into ready-to-print human readable version.
|
||||||
fn from_priv(private: PrivXmrigApi, output: String) -> Self {
|
fn from_priv(public: &mut Self, private: PrivXmrigApi) {
|
||||||
Self {
|
*public = Self {
|
||||||
output: output.clone(),
|
|
||||||
uptime: HumanTime::new(),
|
uptime: HumanTime::new(),
|
||||||
worker_id: private.worker_id,
|
worker_id: private.worker_id,
|
||||||
resources: HumanNumber::from_load(private.resources.load_average),
|
resources: HumanNumber::from_load(private.resources.load_average),
|
||||||
|
@ -1414,6 +1480,7 @@ impl PubXmrigApi {
|
||||||
diff: HumanNumber::from_u128(private.connection.diff),
|
diff: HumanNumber::from_u128(private.connection.diff),
|
||||||
accepted: HumanNumber::from_u128(private.connection.accepted),
|
accepted: HumanNumber::from_u128(private.connection.accepted),
|
||||||
rejected: HumanNumber::from_u128(private.connection.rejected),
|
rejected: HumanNumber::from_u128(private.connection.rejected),
|
||||||
|
..std::mem::take(public)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1440,6 +1507,16 @@ impl PrivXmrigApi {
|
||||||
hashrate: Hashrate::new(),
|
hashrate: Hashrate::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Send an HTTP request to XMRig's API, serialize it into [Self] and return it
|
||||||
|
async fn request_xmrig_api(client: hyper::Client<hyper::client::HttpConnector>, api_ip_port: &str) -> Result<Self, anyhow::Error> {
|
||||||
|
let request = hyper::Request::builder()
|
||||||
|
.method("GET")
|
||||||
|
.uri("http://".to_string() + api_ip_port + "/1/summary")
|
||||||
|
.body(hyper::Body::empty())?;
|
||||||
|
let mut response = tokio::time::timeout(std::time::Duration::from_millis(500), client.request(request)).await?;
|
||||||
|
let body = hyper::body::to_bytes(response?.body_mut()).await?;
|
||||||
|
Ok(serde_json::from_slice::<Self>(&body)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
|
|
38
src/main.rs
38
src/main.rs
|
@ -49,6 +49,15 @@ use std::{
|
||||||
time::Instant,
|
time::Instant,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
// Sysinfo (this controls which info we get)
|
||||||
|
use sysinfo::{
|
||||||
|
NetworkExt,
|
||||||
|
CpuExt,
|
||||||
|
ProcessExt,
|
||||||
|
System,
|
||||||
|
SystemExt,
|
||||||
|
PidExt,
|
||||||
|
};
|
||||||
// Modules
|
// Modules
|
||||||
mod ferris;
|
mod ferris;
|
||||||
mod constants;
|
mod constants;
|
||||||
|
@ -112,6 +121,7 @@ pub struct App {
|
||||||
// This holds everything related to the data processed by the "helper thread".
|
// This holds everything related to the data processed by the "helper thread".
|
||||||
// This includes the "helper" threads public P2Pool/XMRig's API.
|
// This includes the "helper" threads public P2Pool/XMRig's API.
|
||||||
helper: Arc<Mutex<Helper>>, // [Helper] state, mostly for Gupax uptime
|
helper: Arc<Mutex<Helper>>, // [Helper] state, mostly for Gupax uptime
|
||||||
|
pub_sys: Arc<Mutex<Sys>>, // [Sys] state, read by [Status], mutated by [Helper]
|
||||||
p2pool: Arc<Mutex<Process>>, // [P2Pool] process state
|
p2pool: Arc<Mutex<Process>>, // [P2Pool] process state
|
||||||
xmrig: Arc<Mutex<Process>>, // [XMRig] process state
|
xmrig: Arc<Mutex<Process>>, // [XMRig] process state
|
||||||
p2pool_api: Arc<Mutex<PubP2poolApi>>, // Public ready-to-print P2Pool API made by the "helper" thread
|
p2pool_api: Arc<Mutex<PubP2poolApi>>, // Public ready-to-print P2Pool API made by the "helper" thread
|
||||||
|
@ -126,6 +136,8 @@ pub struct App {
|
||||||
// State from [--flags]
|
// State from [--flags]
|
||||||
no_startup: bool,
|
no_startup: bool,
|
||||||
// Static stuff
|
// Static stuff
|
||||||
|
pid: sysinfo::Pid, // Gupax's PID
|
||||||
|
max_threads: usize, // Max amount of detected system threads
|
||||||
now: Instant, // Internal timer
|
now: Instant, // Internal timer
|
||||||
exe: String, // Path for [Gupax] binary
|
exe: String, // Path for [Gupax] binary
|
||||||
dir: String, // Directory [Gupax] binary is in
|
dir: String, // Directory [Gupax] binary is in
|
||||||
|
@ -160,6 +172,17 @@ impl App {
|
||||||
let xmrig_api = Arc::new(Mutex::new(PubXmrigApi::new()));
|
let xmrig_api = Arc::new(Mutex::new(PubXmrigApi::new()));
|
||||||
let p2pool_img = Arc::new(Mutex::new(ImgP2pool::new()));
|
let p2pool_img = Arc::new(Mutex::new(ImgP2pool::new()));
|
||||||
let xmrig_img = Arc::new(Mutex::new(ImgXmrig::new()));
|
let xmrig_img = Arc::new(Mutex::new(ImgXmrig::new()));
|
||||||
|
|
||||||
|
// We give this to the [Helper] thread.
|
||||||
|
let mut sysinfo = sysinfo::System::new_with_specifics(
|
||||||
|
sysinfo::RefreshKind::new()
|
||||||
|
.with_cpu(sysinfo::CpuRefreshKind::everything())
|
||||||
|
.with_processes(sysinfo::ProcessRefreshKind::new().with_cpu())
|
||||||
|
.with_memory());
|
||||||
|
sysinfo.refresh_all();
|
||||||
|
let pid = sysinfo::get_current_pid().unwrap();
|
||||||
|
let pub_sys = Arc::new(Mutex::new(Sys::new()));
|
||||||
|
|
||||||
let mut app = Self {
|
let mut app = Self {
|
||||||
tab: Tab::default(),
|
tab: Tab::default(),
|
||||||
ping: Arc::new(Mutex::new(Ping::new())),
|
ping: Arc::new(Mutex::new(Ping::new())),
|
||||||
|
@ -177,7 +200,7 @@ impl App {
|
||||||
restart: Arc::new(Mutex::new(Restart::No)),
|
restart: Arc::new(Mutex::new(Restart::No)),
|
||||||
diff: false,
|
diff: false,
|
||||||
error_state: ErrorState::new(),
|
error_state: ErrorState::new(),
|
||||||
helper: Arc::new(Mutex::new(Helper::new(now, p2pool.clone(), xmrig.clone(), p2pool_api.clone(), xmrig_api.clone(), p2pool_img.clone(), xmrig_img.clone()))),
|
helper: Arc::new(Mutex::new(Helper::new(now, pub_sys.clone(), p2pool.clone(), xmrig.clone(), p2pool_api.clone(), xmrig_api.clone(), p2pool_img.clone(), xmrig_img.clone()))),
|
||||||
p2pool,
|
p2pool,
|
||||||
xmrig,
|
xmrig,
|
||||||
p2pool_api,
|
p2pool_api,
|
||||||
|
@ -190,6 +213,9 @@ impl App {
|
||||||
resizing: false,
|
resizing: false,
|
||||||
alpha: 0,
|
alpha: 0,
|
||||||
no_startup: false,
|
no_startup: false,
|
||||||
|
pub_sys,
|
||||||
|
pid,
|
||||||
|
max_threads: num_cpus::get(),
|
||||||
now,
|
now,
|
||||||
admin: false,
|
admin: false,
|
||||||
exe: String::new(),
|
exe: String::new(),
|
||||||
|
@ -291,7 +317,7 @@ impl App {
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
let mut og = app.og.lock().unwrap(); // Lock [og]
|
let mut og = app.og.lock().unwrap(); // Lock [og]
|
||||||
// Handle max threads
|
// Handle max threads
|
||||||
og.xmrig.max_threads = num_cpus::get();
|
og.xmrig.max_threads = app.max_threads;
|
||||||
let current = og.xmrig.current_threads;
|
let current = og.xmrig.current_threads;
|
||||||
let max = og.xmrig.max_threads;
|
let max = og.xmrig.max_threads;
|
||||||
if current > max {
|
if current > max {
|
||||||
|
@ -340,7 +366,7 @@ impl App {
|
||||||
|
|
||||||
// Spawn the "Helper" thread.
|
// Spawn the "Helper" thread.
|
||||||
info!("Helper | Spawning helper thread...");
|
info!("Helper | Spawning helper thread...");
|
||||||
Helper::spawn_helper(&app.helper);
|
Helper::spawn_helper(&app.helper, sysinfo, app.pid, app.max_threads);
|
||||||
info!("Helper ... OK");
|
info!("Helper ... OK");
|
||||||
|
|
||||||
// Check for privilege. Should be Admin on [Windows] and NOT root on Unix.
|
// Check for privilege. Should be Admin on [Windows] and NOT root on Unix.
|
||||||
|
@ -617,7 +643,7 @@ fn init_auto(app: &mut App) {
|
||||||
Helper::start_p2pool(&app.helper, &app.state.p2pool, &app.state.gupax.absolute_p2pool_path);
|
Helper::start_p2pool(&app.helper, &app.state.p2pool, &app.state.gupax.absolute_p2pool_path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("Skipping auto-xmrig...");
|
info!("Skipping auto-p2pool...");
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Auto-XMRig]
|
// [Auto-XMRig]
|
||||||
|
@ -1044,7 +1070,6 @@ impl eframe::App for App {
|
||||||
TopBottomPanel::top("top").show(ctx, |ui| {
|
TopBottomPanel::top("top").show(ctx, |ui| {
|
||||||
let width = (self.width - (SPACE*10.0))/5.0;
|
let width = (self.width - (SPACE*10.0))/5.0;
|
||||||
let height = self.height/12.0;
|
let height = self.height/12.0;
|
||||||
ui.group(|ui| {
|
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let style = ui.style_mut();
|
let style = ui.style_mut();
|
||||||
|
@ -1064,7 +1089,6 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Bottom: app info + state/process buttons
|
// Bottom: app info + state/process buttons
|
||||||
TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
||||||
|
@ -1312,7 +1336,7 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Tab::Status => {
|
Tab::Status => {
|
||||||
Status::show(self, self.width, self.height, ctx, ui);
|
Status::show(&self.pub_sys, &self.p2pool_api, &self.xmrig_api, &self.p2pool_img, &self.xmrig_img, self.width, self.height, ctx, ui);
|
||||||
}
|
}
|
||||||
Tab::Gupax => {
|
Tab::Gupax => {
|
||||||
Gupax::show(&mut self.state.gupax, &self.og, &self.state_path, &self.update, &self.file_window, &mut self.error_state, &self.restart, self.width, self.height, frame, ctx, ui);
|
Gupax::show(&mut self.state.gupax, &self.og, &self.state_path, &self.update, &self.file_window, &mut self.error_state, &self.restart, self.width, self.height, frame, ctx, ui);
|
||||||
|
|
101
src/status.rs
101
src/status.rs
|
@ -15,56 +15,65 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crate::App;
|
use crate::{
|
||||||
use egui::{containers::*, *};
|
Helper,
|
||||||
|
PubP2poolApi,
|
||||||
|
PubXmrigApi,
|
||||||
|
ImgP2pool,
|
||||||
|
ImgXmrig,
|
||||||
|
constants::*,
|
||||||
|
Sys,
|
||||||
|
};
|
||||||
|
use std::sync::{Arc,Mutex};
|
||||||
|
use egui::{
|
||||||
|
containers::*,
|
||||||
|
Label,RichText,TextStyle
|
||||||
|
};
|
||||||
|
|
||||||
// Main data structure for the Status tab
|
// Main data structure for the Status tab
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Status {
|
pub struct Status {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Status {
|
impl Status {
|
||||||
pub fn show(_app: &mut App, _width: f32, _height: f32, _ctx: &egui::Context, ui: &mut egui::Ui) {
|
pub fn show(sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolApi>>, xmrig_api: &Arc<Mutex<PubXmrigApi>>, p2pool_img: &Arc<Mutex<ImgP2pool>>, xmrig_img: &Arc<Mutex<ImgXmrig>>, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) {
|
||||||
let color = if ui.visuals().dark_mode {
|
let width = (width/3.0)-(SPACE*1.666);
|
||||||
Color32::from_additive_luminance(196)
|
let min_height = height/1.14;
|
||||||
} else {
|
let height = height/20.0;
|
||||||
Color32::from_black_alpha(240)
|
ui.horizontal(|ui| {
|
||||||
};
|
// [Gupax]
|
||||||
|
ui.group(|ui| { ui.vertical(|ui| {
|
||||||
Frame::canvas(ui.style()).show(ui, |ui| {
|
ui.set_min_height(min_height);
|
||||||
ui.ctx().request_repaint();
|
ui.add_sized([width, height*2.0], Label::new(RichText::new("[Gupax]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into()))));
|
||||||
let time = ui.input().time;
|
// Uptime
|
||||||
|
ui.add_sized([width, height], Label::new(RichText::new("Uptime").underline().color(BONE))).on_hover_text(STATUS_GUPAX_UPTIME);
|
||||||
let desired_size = ui.available_width() * vec2(1.0, 0.3);
|
ui.add_sized([width, height], Label::new(format!("{}", sys.lock().unwrap().gupax_uptime)));
|
||||||
let (_id, rect) = ui.allocate_space(desired_size);
|
ui.add_sized([width, height], Label::new(RichText::new("Gupax CPU").underline().color(BONE))).on_hover_text(STATUS_GUPAX_CPU_USAGE);
|
||||||
|
ui.add_sized([width, height], Label::new(format!("{}", sys.lock().unwrap().gupax_cpu_usage)));
|
||||||
let to_screen =
|
ui.add_sized([width, height], Label::new(RichText::new("Gupax Memory").underline().color(BONE))).on_hover_text(STATUS_GUPAX_MEMORY_USAGE);
|
||||||
emath::RectTransform::from_to(Rect::from_x_y_ranges(0.0..=1.0, -1.0..=1.0), rect);
|
ui.add_sized([width, height], Label::new(format!("{}", sys.lock().unwrap().gupax_memory_used_mb)));
|
||||||
|
ui.add_sized([width, height], Label::new(RichText::new("System CPU").underline().color(BONE))).on_hover_text(STATUS_GUPAX_SYSTEM_CPU_USAGE);
|
||||||
let mut shapes = vec![];
|
ui.add_sized([width, height], Label::new(format!("{}", sys.lock().unwrap().system_cpu_usage)));
|
||||||
|
ui.add_sized([width, height], Label::new(RichText::new("System Memory").underline().color(BONE))).on_hover_text(STATUS_GUPAX_SYSTEM_MEMORY);
|
||||||
for &mode in &[2, 3, 5] {
|
ui.add_sized([width, height], Label::new(format!("{}", sys.lock().unwrap().system_memory)));
|
||||||
let mode = mode as f64;
|
ui.add_sized([width, height], Label::new(RichText::new("System CPU Model").underline().color(BONE))).on_hover_text(STATUS_GUPAX_SYSTEM_CPU_MODEL);
|
||||||
let n = 120;
|
ui.add_sized([width, height], Label::new(format!("{}", sys.lock().unwrap().system_cpu_model)));
|
||||||
let speed = 1.5;
|
})});
|
||||||
|
// [P2Pool]
|
||||||
let points: Vec<Pos2> = (0..=n)
|
ui.group(|ui| { ui.vertical(|ui| {
|
||||||
.map(|i| {
|
ui.set_min_height(min_height);
|
||||||
let t = i as f64 / (n as f64);
|
ui.add_sized([width, height*2.0], Label::new(RichText::new("[P2Pool]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into()))));
|
||||||
let amp = (time * speed * mode).sin() / mode;
|
// Uptime
|
||||||
let y = amp * (t * std::f64::consts::TAU / 2.0 * mode).sin();
|
ui.add_sized([width, height], Label::new(RichText::new("Uptime").underline()));
|
||||||
to_screen * pos2(t as f32, y as f32)
|
ui.add_sized([width, height], Label::new(format!("{}", p2pool_api.lock().unwrap().uptime)));
|
||||||
})
|
})});
|
||||||
.collect();
|
// [XMRig]
|
||||||
|
ui.group(|ui| { ui.vertical(|ui| {
|
||||||
let thickness = 10.0 / mode as f32;
|
ui.set_min_height(min_height);
|
||||||
shapes.push(epaint::Shape::line(points, Stroke::new(thickness, color)));
|
ui.add_sized([width, height*2.0], Label::new(RichText::new("[XMRig]").color(LIGHT_GRAY).text_style(TextStyle::Name("MonospaceLarge".into()))));
|
||||||
}
|
// Uptime
|
||||||
|
ui.add_sized([width, height], Label::new(RichText::new("Uptime").underline()));
|
||||||
ui.painter().extend(shapes);
|
ui.add_sized([width, height], Label::new(format!("{}", xmrig_api.lock().unwrap().uptime)));
|
||||||
|
})});
|
||||||
});
|
});
|
||||||
ui.label("WIP");
|
}
|
||||||
ui.label("Enjoy these cool lines.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue