fix threads, gupax tab, inline about tab

This commit is contained in:
hinto-janaiyo 2022-10-16 20:36:58 -04:00
parent 773bc65593
commit 14a5538173
No known key found for this signature in database
GPG key ID: D7483F6CA27D1B1D
7 changed files with 139 additions and 128 deletions

View file

@ -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
* <details>
<summary>Click me to load the demo!</summary>
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
<details>
<summary>Click me to load images!</summary>
</details>
![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)
* <details>
<summary>Click me to load images!</summary>
![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)
</details>
</details>
## Implementation

View file

@ -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.

View file

@ -15,9 +15,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
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"#;

View file

@ -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);
});
}
}

View file

@ -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);

View file

@ -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| {

View file

@ -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,