From 14a5538173cd6bdd41ea55c8b275859ab901b25e Mon Sep 17 00:00:00 2001 From: hinto-janaiyo Date: Sun, 16 Oct 2022 20:36:58 -0400 Subject: [PATCH] fix threads, gupax tab, inline about tab --- README.md | 23 ++++------ src/README.md | 9 ++-- src/constants.rs | 30 +++++++------ src/gupax.rs | 56 +++++++---------------- src/main.rs | 113 +++++++++++++++++++++++++---------------------- src/p2pool.rs | 23 ++++++++++ src/state.rs | 13 ++++-- 7 files changed, 139 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index b9894d8..6559daf 100644 --- a/README.md +++ b/README.md @@ -3,23 +3,18 @@ **Gupax** (*guh-picks*) is a cross-platform GUI for mining [**Monero**](https://github.com/monero-project/monero) on the decentralized [**P2Pool**](https://github.com/SChernykh/p2pool), using the dedicated [**XMRig**](https://github.com/xmrig/xmrig) miner for max hashrate. ## Demo -*
- Click me to load the demo! +https://user-images.githubusercontent.com/101352116/194763334-d8e936c9-a71e-474e-ac65-3a339b96a9d2.mp4 - https://user-images.githubusercontent.com/101352116/194763334-d8e936c9-a71e-474e-ac65-3a339b96a9d2.mp4 +
+Click me to load images! -
+![about.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/about.png) +![status.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/status.png) +![gupax.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/gupax.png) +![p2pool.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/p2pool.png) +![xmrig.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/xmrig.png) -*
- Click me to load images! - - ![about.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/about.png) - ![status.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/status.png) - ![gupax.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/gupax.png) - ![p2pool.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/p2pool.png) - ![xmrig.png](https://github.com/hinto-janaiyo/gupax/blob/main/images/tabs/xmrig.png) - -
+
## Implementation diff --git a/src/README.md b/src/README.md index a9d8e87..7ae5552 100644 --- a/src/README.md +++ b/src/README.md @@ -6,15 +6,14 @@ ## Structure | File/Folder | Purpose | |----------------|---------| -| `about.rs` | Struct/impl for `About` tab | `constants.rs` | General constants needed in Gupax -| `gupax.rs` | Struct/impl for `Gupax` tab +| `gupax.rs` | Impl for `Gupax` tab | `main.rs` | Struct/enum/impl for `App/Tab/State`, init functions, main function | `node.rs` | Struct/impl for Community Nodes -| `p2pool.rs` | Struct/impl for `P2Pool` tab -| `state.rs` | Struct/impl for `gupax.toml`, the disk state +| `p2pool.rs` | Impl for `P2Pool` tab +| `state.rs` | Struct/impl for `gupax.toml`, the disk state. This holds the structs representing tabs with mutable state (Gupax/P2Pool/XMRig) | `status.rs` | Struct/impl for `Status` tab -| `xmrig.rs` | Struct/impl for `XMRig` tab +| `xmrig.rs` | Impl for `XMRig` tab ## Bootstrap This is how Gupax works internally when starting up, divided into 3 sections. diff --git a/src/constants.rs b/src/constants.rs index 4cda9a6..0d696b1 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,9 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pub const GUPAX_VERSION: &'static str = "v0.1.0"; +pub const GUPAX_VERSION: &'static str = concat!("v", env!("CARGO_PKG_VERSION")); pub const P2POOL_VERSION: &'static str = "v2.4"; pub const XMRIG_VERSION: &'static str = "v6.18.0"; +pub const COMMIT: &'static str = include_str!("../.git/refs/heads/main"); pub const BYTES_ICON: &[u8] = include_bytes!("../images/png/icon.png"); pub const BYTES_BANNER: &[u8] = include_bytes!("../images/png/banner.png"); @@ -34,22 +35,26 @@ pub const HUGEPAGES_1GB: bool = false; #[cfg(target_os = "macos")] pub const OS: &'static str = " macOS"; #[cfg(target_os = "macos")] +pub const OS_NAME: &'static str = "macOS"; +#[cfg(target_os = "macos")] pub const HUGEPAGES_1GB: bool = false; #[cfg(target_os = "linux")] pub const OS: &'static str = "🐧 Linux"; #[cfg(target_os = "linux")] +pub const OS_NAME: &'static str = "Linux"; +#[cfg(target_os = "linux")] pub const HUGEPAGES_1GB: bool = true; // Tooltips // Gupax -pub const GUPAX_CHECK_FOR_UPDATES: &'static str = "Check for Gupax, P2Pool, and XMRig updates via GitHub's API"; -pub const GUPAX_UPGRADE: &'static str = "Upgrade anything that is out-of-date"; +pub const GUPAX_UPDATE: &'static str = "Update Gupax, P2Pool, and XMRig via GitHub's API"; pub const GUPAX_AUTO_UPDATE: &'static str = "Automatically check for updates at startup"; -pub const GUPAX_ASK_BEFORE_QUIT: &'static str = "Ask before quitting if processes are still alive"; -pub const GUPAX_PATH_CONFIG: &'static str = "The location of the Gupax configuration file"; -pub const GUPAX_PATH_P2POOL: &'static str = "The location of the P2Pool binary"; -pub const GUPAX_PATH_XMRIG: &'static str = "The location of the XMRig binary"; +pub const GUPAX_AUTO_NODE: &'static str = "Automatically ping the community Monero nodes and select the fastest at startup"; +pub const GUPAX_ASK_BEFORE_QUIT: &'static str = "Ask before quitting if processes are still alive, or if an update is in progress"; +pub const GUPAX_SAVE_BEFORE_QUIT: &'static str = "Automatically save any changed settings before quitting"; +pub const GUPAX_PATH_P2POOL: &'static str = "The location of the P2Pool binary, both absolute and relative paths are accepted"; +pub const GUPAX_PATH_XMRIG: &'static str = "The location of the XMRig binary, both absolute and relative paths are accepted"; // P2Pool pub const P2POOL_MAIN: &'static str = "The P2Pool main-chain. This P2Pool finds shares faster, but has a higher difficulty. Suitable for miners with more than 50kH/s"; pub const P2POOL_MINI: &'static str = "The P2Pool mini-chain. This P2Pool finds shares slower, but has a lower difficulty. Suitable for miners with less than 50kH/s"; @@ -77,9 +82,8 @@ r#"USAGE: gupax [--flags] -n | --no-startup Disable auto-update/node connections at startup -r | --reset Reset all Gupax configuration/state"#; pub const ARG_COPYRIGHT: &'static str = -r#"For more information: -https://github.com/hinto-janaiyo/gupax -https://github.com/SChernykh/p2pool -https://github.com/xmrig/xmrig - -Gupax, P2Pool, and XMRig are licensed under GPLv3."#; +r#"Gupax, P2Pool, and XMRig are licensed under GPLv3. +For more information, see here: + - https://github.com/hinto-janaiyo/gupax + - https://github.com/SChernykh/p2pool + - https://github.com/xmrig/xmrig"#; diff --git a/src/gupax.rs b/src/gupax.rs index 6b9f01a..581f0e5 100644 --- a/src/gupax.rs +++ b/src/gupax.rs @@ -19,32 +19,9 @@ use std::path::Path; use crate::App; use egui::WidgetType::Button; use crate::constants::*; - -// Main data structure for the Gupax tab -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Gupax { - auto_update: bool, - ask_before_quit: bool, - updating: bool, - upgrading: bool, - config: String, - p2pool: String, - xmrig: String, -} +use crate::state::Gupax; impl Gupax { - pub fn new() -> Self { - Self { - auto_update: false, - ask_before_quit: true, - updating: false, - upgrading: false, - config: String::from("/home/hinto/gupax/gupax.toml"), - p2pool: String::from("/home/hinto/gupax/p2pool"), - xmrig: String::from("/home/hinto/gupax/xmrig"), - } - } - pub fn show(state: &mut Gupax, ctx: &egui::Context, ui: &mut egui::Ui) { let height = ui.available_height(); let width = ui.available_width(); @@ -54,41 +31,40 @@ impl Gupax { ui.horizontal(|ui| { ui.group(|ui| { ui.vertical(|ui| { - ui.add_sized([half_width - 8.0, half_height], egui::Button::new("Check for updates")).on_hover_text(GUPAX_CHECK_FOR_UPDATES); + ui.add_sized([half_width - 8.0, half_height], egui::Button::new("Check for updates")).on_hover_text(GUPAX_UPDATE); ui.set_enabled(false); - ui.add_sized([half_width - 8.0, half_height], egui::Button::new("Upgrade")).on_hover_text(GUPAX_UPGRADE); + ui.add_sized([half_width - 8.0, half_height], egui::Button::new("Upgrade")).on_hover_text("asdf"); }); }); ui.group(|ui| { + let mut style = (*ctx.style()).clone(); + style.spacing.icon_width_inner = ui.available_height() / 6.0; + style.spacing.icon_width = ui.available_height() / 4.0; + style.spacing.icon_spacing = ui.available_width() / 20.0; + ctx.set_style(style); + let half_width = (half_width/2.0)-15.0; ui.vertical(|ui| { - let mut style = (*ctx.style()).clone(); - style.spacing.icon_width_inner = ui.available_height() / 6.0; - style.spacing.icon_width = ui.available_height() / 4.0; - style.spacing.icon_spacing = ui.available_width() / 20.0; - ctx.set_style(style); ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.auto_update, "Auto-update")).on_hover_text(GUPAX_AUTO_UPDATE); - ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.ask_before_quit, "Ask before quitting")).on_hover_text(GUPAX_ASK_BEFORE_QUIT); - }); + }); + ui.vertical(|ui| { + ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.auto_node, "Auto-node")).on_hover_text(GUPAX_AUTO_NODE); + ui.add_sized([half_width, half_height], egui::Checkbox::new(&mut state.save_before_quit, "Save before quitting")).on_hover_text(GUPAX_SAVE_BEFORE_QUIT); + }); }); }); ui.add_space(10.0); - ui.horizontal(|ui| { - ui.label("Gupax config path: "); - ui.spacing_mut().text_edit_width = ui.available_width() - 35.0; - ui.text_edit_singleline(&mut state.config).on_hover_text(GUPAX_PATH_CONFIG); - }); ui.horizontal(|ui| { ui.label("P2Pool binary path:"); ui.spacing_mut().text_edit_width = ui.available_width() - 35.0; - ui.text_edit_singleline(&mut state.p2pool).on_hover_text(GUPAX_PATH_P2POOL); + ui.text_edit_singleline(&mut state.p2pool_path).on_hover_text(GUPAX_PATH_P2POOL); }); ui.horizontal(|ui| { ui.label("XMRig binary path: "); ui.spacing_mut().text_edit_width = ui.available_width() - 35.0; - ui.text_edit_singleline(&mut state.xmrig).on_hover_text(GUPAX_PATH_XMRIG); + ui.text_edit_singleline(&mut state.xmrig_path).on_hover_text(GUPAX_PATH_XMRIG); }); } } diff --git a/src/main.rs b/src/main.rs index f84a2a7..7075ab4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ use egui::TextStyle::*; use egui::color::Color32; use egui::FontFamily::Proportional; use egui::{FontId,Label,RichText,Stroke,Vec2,Pos2}; +use egui::special_emojis::GITHUB; use egui_extras::RetainedImage; use eframe::{egui,NativeOptions}; @@ -97,7 +98,7 @@ impl App { } } - fn default() -> Self { + fn new() -> Self { let app = Self { tab: Tab::default(), quit: false, @@ -116,11 +117,30 @@ impl App { now: Instant::now(), resolution: Vec2::new(1280.0, 720.0), os: OS, - version: "v0.0.1".to_string(), - name_version: "Gupax v0.0.1".to_string(), + version: format!("{}", GUPAX_VERSION), + name_version: format!("Gupax {}", GUPAX_VERSION), banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).expect("oops"), }; - parse_args(app) + // Apply arg state + let mut app = parse_args(app); + // Read disk state if no [--reset] arg + if app.reset == false { + app.og = match State::get() { + Ok(toml) => toml, + Err(err) => { + error!("{}", err); + let error_msg = err.to_string(); + let options = Panic::options(); + eframe::run_native("Gupax", options, Box::new(|cc| Box::new(Panic::new(cc, error_msg))),); + exit(1); + }, + }; + } + // Make sure thread count is accurate/doesn't overflow + app.og.xmrig.max_threads = num_cpus::get(); + if app.og.xmrig.current_threads > app.og.xmrig.max_threads { app.og.xmrig.current_threads = app.og.xmrig.max_threads; } + app.state = app.og.clone(); + app } } @@ -238,7 +258,7 @@ fn parse_args(mut app: App) -> App { match arg.as_str() { "-h"|"--help" => { println!("{}", ARG_HELP); exit(0); }, "-v"|"--version" => { - println!("Gupax | {}\nP2Pool | {}\nXMRig | {}\n\n{}", GUPAX_VERSION, P2POOL_VERSION, XMRIG_VERSION, ARG_COPYRIGHT); + println!("Gupax | {}\nP2Pool | {}\nXMRig | {}\n\nOS: [{}], Commit: [{}]\n\n{}", GUPAX_VERSION, P2POOL_VERSION, XMRIG_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT); exit(0); }, _ => (), @@ -300,30 +320,22 @@ impl eframe::App for Panic { //---------------------------------------------------------------------------------------------------- Main [App] frame fn main() { init_logger(); - let app = App::default(); + let app = App::new(); let options = init_options(); - let toml = match State::get() { - Ok(toml) => toml, - Err(err) => { - error!("{}", err); - let error_msg = err.to_string(); - let options = Panic::options(); - eframe::run_native("Gupax", options, Box::new(|cc| Box::new(Panic::new(cc, error_msg))),); - exit(1); - }, - }; eframe::run_native("Gupax", options, Box::new(|cc| Box::new(App::cc(cc, app))),); } impl eframe::App for App { fn on_close_event(&mut self) -> bool { self.quit = true; - self.quit_confirm + if self.og.gupax.ask_before_quit { + self.quit_confirm + } else { + true + } } fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { -// init_text_styles(ctx, 1280.0); - // Close confirmation. if self.quit { egui::CentralPanel::default().show(ctx, |ui| { @@ -332,10 +344,11 @@ impl eframe::App for App { let width = width - 10.0; let height = ui.available_height(); // Detect processes or update - if self.p2pool || self.xmrig { + if self.p2pool || self.xmrig || self.updating { ui.add_sized([width, height/6.0], Label::new("Are you sure you want to quit?")); - if self.p2pool { ui.add_sized([width, height/6.0], Label::new("P2Pool is online...!")); } - if self.xmrig { ui.add_sized([width, height/6.0], Label::new("XMRig is online...!")); } + if self.updating { ui.add_sized([width, height/9.0], Label::new("Update is in progress...!")); } + if self.p2pool { ui.add_sized([width, height/9.0], Label::new("P2Pool is online...!")); } + if self.xmrig { ui.add_sized([width, height/9.0], Label::new("XMRig is online...!")); } // Else, just quit } else { if self.state.gupax.save_before_quit { @@ -383,27 +396,6 @@ impl eframe::App for App { }); } - // If ping-ING, display stats -// if *self.pinging.lock().unwrap() { -// egui::CentralPanel::default().show(ctx, |ui| { -// let width = ui.available_width(); -// let width = width - 10.0; -// let height = ui.available_height(); -// init_text_styles(ctx, width); -// ui.add_sized([width, height/2.0], Label::new(format!("In progress: {}", *self.pinging.lock().unwrap()))); -// ui.group(|ui| { -// if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() { -// info!("Quit confirmation = yes ... goodbye!"); -// exit(0); -// } else if ui.add_sized([width, height/10.0], egui::Button::new("No")).clicked() { -// info!("Quit confirmation = no ... returning!"); -// self.show_confirmation_dialog = false; -// } -// }); -// }); -// return -// } - // Top: Tabs egui::CentralPanel::default().show(ctx, |ui| { init_text_styles(ctx, ui.available_width()); @@ -439,19 +431,19 @@ impl eframe::App for App { ui.horizontal(|ui| { ui.group(|ui| { let width = width / 2.0; - ui.add_sized([width, height], Label::new(&self.name_version)); + ui.add_sized([width, height], Label::new(&*self.name_version)); ui.separator(); ui.add_sized([width, height], Label::new(self.os)); ui.separator(); ui.add_sized([width/1.5, height], Label::new("P2Pool")); - if self.p2pool == true { + if self.p2pool { ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(100, 230, 100)))); } else { ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(230, 50, 50)))); } ui.separator(); ui.add_sized([width/1.5, height], Label::new("XMRig")); - if self.xmrig == true { + if self.xmrig { ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(100, 230, 100)))); } else { ui.add_sized([width/4.0, height], Label::new(RichText::new("⏺").color(Color32::from_rgb(230, 50, 50)))); @@ -464,7 +456,7 @@ impl eframe::App for App { ui.set_enabled(false) } let width = width / 2.0; - if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { self.og = self.state.clone(); } + if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { self.og = self.state.clone(); self.state.save(); } if ui.add_sized([width, height], egui::Button::new("Reset")).on_hover_text("Reset changes").clicked() { self.state = self.og.clone(); } }); @@ -472,7 +464,7 @@ impl eframe::App for App { match self.tab { Tab::P2pool => { ui.group(|ui| { - if self.p2pool == true { + if self.p2pool { if ui.add_sized([width, height], egui::Button::new("⟲")).on_hover_text("Restart P2Pool").clicked() { self.p2pool = false; } if ui.add_sized([width, height], egui::Button::new("⏹")).on_hover_text("Stop P2Pool").clicked() { self.p2pool = false; } ui.add_enabled_ui(false, |ui| { @@ -489,7 +481,7 @@ impl eframe::App for App { } Tab::Xmrig => { ui.group(|ui| { - if self.xmrig == true { + if self.xmrig { if ui.add_sized([width, height], egui::Button::new("⟲")).on_hover_text("Restart XMRig").clicked() { self.xmrig = false; } if ui.add_sized([width, height], egui::Button::new("⏹")).on_hover_text("Stop XMRig").clicked() { self.xmrig = false; } ui.add_enabled_ui(false, |ui| { @@ -513,14 +505,31 @@ impl eframe::App for App { ui.style_mut().override_text_style = Some(egui::TextStyle::Body); match self.tab { Tab::About => { - About::show(self, ctx, ui); + ui.add_space(10.0); + ui.vertical_centered(|ui| { + let space = ui.available_height()/2.2; + self.banner.show(ui); + ui.label("Gupax (guh-picks) is a cross-platform GUI for mining"); + ui.hyperlink_to("[Monero]", "https://www.github.com/monero-project/monero"); + ui.label("on the decentralized"); + ui.hyperlink_to("[P2Pool]", "https://www.github.com/SChernykh/p2pool"); + ui.label("using the dedicated"); + ui.hyperlink_to("[XMRig]", "https://www.github.com/xmrig/xmrig"); + ui.label("miner for max hashrate"); + + ui.add_space(ui.available_height()/2.4); + + ui.hyperlink_to("Powered by egui", "https://github.com/emilk/egui"); + ui.hyperlink_to(format!("{} {}", GITHUB, "Gupax made by hinto-janaiyo"), "https://www.github.com/hinto-janaiyo/gupax"); + ui.label("egui is licensed under MIT & Apache-2.0"); + ui.label("Gupax, P2Pool, and XMRig are licensed under GPLv3"); + }); } Tab::Status => { Status::show(self, ctx, ui); } Tab::Gupax => { -// Gupax::show(self.state.gupax, ctx, ui); - exit(0); + Gupax::show(&mut self.state.gupax, ctx, ui); } Tab::P2pool => { P2pool::show(&mut self.state.p2pool, ctx, ui); diff --git a/src/p2pool.rs b/src/p2pool.rs index 5045249..31b13ad 100644 --- a/src/p2pool.rs +++ b/src/p2pool.rs @@ -35,6 +35,29 @@ use crate::node::{RINO,SETH,SELSTA}; impl P2pool { pub fn show(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) { + // TODO: + // ping code + // If ping-ING, display stats +// if *self.pinging.lock().unwrap() { +// egui::CentralPanel::default().show(ctx, |ui| { +// let width = ui.available_width(); +// let width = width - 10.0; +// let height = ui.available_height(); +// init_text_styles(ctx, width); +// ui.add_sized([width, height/2.0], Label::new(format!("In progress: {}", *self.pinging.lock().unwrap()))); +// ui.group(|ui| { +// if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() { +// info!("Quit confirmation = yes ... goodbye!"); +// exit(0); +// } else if ui.add_sized([width, height/10.0], egui::Button::new("No")).clicked() { +// info!("Quit confirmation = no ... returning!"); +// self.show_confirmation_dialog = false; +// } +// }); +// }); +// return +// } + let height = ui.available_height() / 10.0; let mut width = ui.available_width() - 50.0; ui.group(|ui| { diff --git a/src/state.rs b/src/state.rs index 4a8366e..4ebbd45 100644 --- a/src/state.rs +++ b/src/state.rs @@ -40,9 +40,13 @@ use log::*; impl State { pub fn default() -> Self { use crate::constants::{P2POOL_VERSION,XMRIG_VERSION}; + let max_threads = num_cpus::get(); + let current_threads; + if max_threads == 1 { current_threads = 1; } else { current_threads = max_threads / 2; } Self { gupax: Gupax { auto_update: true, + auto_node: true, ask_before_quit: true, save_before_quit: true, p2pool_path: DEFAULT_P2POOL_PATH.to_string(), @@ -66,8 +70,8 @@ impl State { nicehash: false, keepalive: false, hugepages_jit: true, - current_threads: 1, - max_threads: 1, + current_threads, + max_threads, priority: 2, pool: "localhost:3333".to_string(), address: "".to_string(), @@ -224,6 +228,7 @@ pub struct State { #[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)] pub struct Gupax { pub auto_update: bool, + pub auto_node: bool, pub ask_before_quit: bool, pub save_before_quit: bool, pub p2pool_path: String, @@ -253,8 +258,8 @@ pub struct Xmrig { pub nicehash: bool, pub keepalive: bool, pub hugepages_jit: bool, - pub max_threads: u16, - pub current_threads: u16, + pub max_threads: usize, + pub current_threads: usize, pub priority: u8, pub pool: String, pub address: String,