keys/p2pool/xmrig: change key shortcuts, check for [ACCEPTABLE_*]

Keyboard shortcuts [Left] & [Right] were clobbering the
[TextEdit] left/right movement, so they are now [Z/X].
The shortcuts also look to make sure a TextEdit isn't
in focus so that [S/R/Z/X] can actually be typed.

P2Pool/XMRig now make sure the path ends with an [ACCEPTABLE_*]
value (e.g: P2pool, P2POOL) before enabling the [Start] UI.
This commit is contained in:
hinto-janaiyo 2022-12-16 09:47:16 -05:00
parent aad1a26e1e
commit 29445e1bd1
No known key found for this signature in database
GPG key ID: B1C5A64B80691E45
6 changed files with 135 additions and 60 deletions

View file

@ -14,6 +14,7 @@ Gupax is a (Windows|macOS|Linux) GUI for mining [**Monero**](https://github.com/
* [Advanced](#Advanced)
- [Verifying](#Verifying)
- [Command Line](#Command-Line)
- [Key Shortcuts](#Key-Shortcuts)
- [Resolution](#Resolution)
- [Tor/Arti](#TorArti)
- [Logs](#Logs)
@ -186,6 +187,27 @@ By default, Gupax has `auto-update` & `auto-ping` enabled. This can only be turn
---
### Key Shortcuts
The letter keys (Z/X/S/R) will only work if nothing is in focus, i.e, you _are not_ editing a text box.
An ALT+F4 will also trigger the exit confirm screen (if enabled).
```
*---------------------------------------*
| Key shortcuts |
|---------------------------------------|
| F11 | Fullscreen |
| Escape | Quit screen |
| Up | Start/Restart |
| Down | Stop |
| Z | Switch to Left Tab |
| X | Switch to Right Tab |
| S | Save |
| R | Reset |
*---------------------------------------*
```
---
### Resolution
The default resolution of Gupax is `1280x960` which is a `4:3` aspect ratio.

View file

@ -2,7 +2,6 @@
* [Structure](#Structure)
* [Thread Model](#Thread-Model)
* [Bootstrap](#Bootstrap)
* [Disk](#Disk)
* [Scale](#Scale)
* [Naming Scheme](#naming-scheme)
* [Sudo](#Sudo)

View file

@ -42,17 +42,18 @@ pub const HORI_CONSOLE: &str = "------------------------------------------------
// Keyboard shortcuts
pub const KEYBOARD_SHORTCUTS: &str =
r#"*--------------------------------------*
| Key shortcuts |
|--------------------------------------|
| F11 | Fullscreen |
| Escape | Quit screen |
| Left/Right | Switch Tabs |
| Up | Start/Restart |
| Down | Stop |
| S | Save |
| R | Reset |
*--------------------------------------*"#;
r#"*---------------------------------------*
| Key shortcuts |
|---------------------------------------|
| F11 | Fullscreen |
| Escape | Quit screen |
| Up | Start/Restart |
| Down | Stop |
| Z | Switch to Left Tab |
| X | Switch to Right Tab |
| S | Save |
| R | Reset |
*---------------------------------------*"#;
// P2Pool & XMRig default API stuff
#[cfg(target_os = "windows")]
pub const P2POOL_API_PATH: &str = r"local\stats"; // The default relative FS path of P2Pool's local API
@ -219,7 +220,10 @@ pub const P2POOL_NAME: &str = "Add a unique name to identify this node; Only [A-
pub const P2POOL_NODE_IP: &str = "Specify the Monero Node IP to connect to with P2Pool; It must be a valid IPv4 address or a valid domain name; Max length = 255 characters";
pub const P2POOL_RPC_PORT: &str = "Specify the RPC port of the Monero node; [1-65535]";
pub const P2POOL_ZMQ_PORT: &str = "Specify the ZMQ port of the Monero node; [1-65535]";
pub const P2POOL_PATH_NOT_EXE: &str = "P2Pool binary not found at the given path in the Gupax tab!";
pub const P2POOL_PATH_NOT_FILE: &str = "P2Pool binary not found at the given PATH in the Gupax tab!";
pub const P2POOL_PATH_NOT_VALID: &str = "P2Pool binary at the given PATH in the Gupax tab doesn't look like P2Pool!";
pub const P2POOL_PATH_OK: &str = "P2Pool was found at the given PATH";
pub const P2POOL_PATH_EMPTY: &str = "P2Pool PATH is empty";
// Node/Pool list
pub const LIST_ADD: &str = "Add the current values to the list";
@ -259,7 +263,10 @@ pub const XMRIG_API_PORT: &str = "Specify which port to bind to for XMRig's HTTP
pub const XMRIG_TLS: &str = "Enable SSL/TLS connections (needs pool support)";
pub const XMRIG_KEEPALIVE: &str = "Send keepalive packets to prevent timeout (needs pool support)";
pub const XMRIG_THREADS: &str = "Number of CPU threads to use for mining";
pub const XMRIG_PATH_NOT_EXE: &str = "XMRig binary not found at the given path in the Gupax tab!";
pub const XMRIG_PATH_NOT_FILE: &str = "XMRig binary not found at the given PATH in the Gupax tab!";
pub const XMRIG_PATH_NOT_VALID: &str = "XMRig binary at the given PATH in the Gupax tab doesn't look like XMRig!";
pub const XMRIG_PATH_OK: &str = "XMRig was found at the given PATH";
pub const XMRIG_PATH_EMPTY: &str = "XMRig PATH is empty";
// CLI argument messages
pub const ARG_HELP: &str =

View file

@ -143,18 +143,15 @@ impl Gupax {
let text_edit = (ui.available_width()/10.0)-SPACE;
ui.horizontal(|ui| {
if self.p2pool_path.is_empty() {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ").color(LIGHT_GRAY)));
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ").color(LIGHT_GRAY))).on_hover_text(P2POOL_PATH_EMPTY);
} else {
match crate::disk::into_absolute_path(self.p2pool_path.clone()) {
Ok(path) => {
if path.is_file() {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ✔").color(GREEN)))
} else {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ❌").color(RED)))
}
},
_ => ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ❌").color(RED))),
};
if !Self::path_is_file(&self.p2pool_path) {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ❌").color(RED))).on_hover_text(P2POOL_PATH_NOT_FILE);
} else if !crate::update::check_p2pool_path(&self.p2pool_path) {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ❌").color(RED))).on_hover_text(P2POOL_PATH_NOT_VALID);
} else {
ui.add_sized([text_edit, height], Label::new(RichText::new("P2Pool Binary Path ✔").color(GREEN))).on_hover_text(P2POOL_PATH_OK);
}
}
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
ui.set_enabled(!file_window.lock().unwrap().thread);
@ -165,12 +162,15 @@ impl Gupax {
});
ui.horizontal(|ui| {
if self.xmrig_path.is_empty() {
ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ").color(LIGHT_GRAY)));
ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ").color(LIGHT_GRAY))).on_hover_text(XMRIG_PATH_EMPTY);
} else {
match Self::path_is_exe(&self.xmrig_path) {
true => ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ✔").color(GREEN))),
false => ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ❌").color(RED))),
};
if !Self::path_is_file(&self.xmrig_path) {
ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ❌").color(RED))).on_hover_text(XMRIG_PATH_NOT_FILE);
} else if !crate::update::check_xmrig_path(&self.xmrig_path) {
ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ❌").color(RED))).on_hover_text(XMRIG_PATH_NOT_VALID);
} else {
ui.add_sized([text_edit, height], Label::new(RichText::new(" XMRig Binary Path ✔").color(GREEN))).on_hover_text(XMRIG_PATH_OK);
}
}
ui.spacing_mut().text_edit_width = ui.available_width() - SPACE;
ui.set_enabled(!file_window.lock().unwrap().thread);
@ -250,8 +250,8 @@ impl Gupax {
})});
}
// Checks if a path is a valid path to an executable.
pub fn path_is_exe(path: &str) -> bool {
// Checks if a path is a valid path to a file.
pub fn path_is_file(path: &str) -> bool {
let path = path.to_string();
match crate::disk::into_absolute_path(path) {
Ok(path) => path.is_file(),

View file

@ -578,11 +578,11 @@ impl Regexes {
#[derive(Debug,Clone,Eq,PartialEq)]
enum KeyPressed {
F11,
Left,
Right,
Up,
Down,
Esc,
Z,
X,
S,
R,
None,
@ -592,11 +592,11 @@ impl KeyPressed {
fn is_f11(&self) -> bool {
*self == Self::F11
}
fn is_left(&self) -> bool {
*self == Self::Left
fn is_z(&self) -> bool {
*self == Self::Z
}
fn is_right(&self) -> bool {
*self == Self::Right
fn is_x(&self) -> bool {
*self == Self::X
}
fn is_up(&self) -> bool {
*self == Self::Up
@ -714,8 +714,10 @@ fn init_auto(app: &mut App) {
if app.state.gupax.auto_p2pool {
if !Regexes::addr_ok(&app.regex, &app.state.p2pool.address) {
warn!("Gupax | P2Pool address is not valid! Skipping auto-p2pool...");
} else if !Gupax::path_is_exe(&app.state.gupax.p2pool_path) {
warn!("Gupax | P2Pool path is not an executable! Skipping auto-p2pool...");
} else if !Gupax::path_is_file(&app.state.gupax.p2pool_path) {
warn!("Gupax | P2Pool path is not a file! Skipping auto-p2pool...");
} else if !crate::update::check_p2pool_path(&app.state.gupax.p2pool_path) {
warn!("Gupax | P2Pool path is not valid! Skipping auto-p2pool...");
} else {
Helper::start_p2pool(&app.helper, &app.state.p2pool, &app.state.gupax.absolute_p2pool_path);
}
@ -725,8 +727,10 @@ fn init_auto(app: &mut App) {
// [Auto-XMRig]
if app.state.gupax.auto_xmrig {
if !Gupax::path_is_exe(&app.state.gupax.xmrig_path) {
if !Gupax::path_is_file(&app.state.gupax.xmrig_path) {
warn!("Gupax | XMRig path is not an executable! Skipping auto-xmrig...");
} else if !crate::update::check_xmrig_path(&app.state.gupax.xmrig_path) {
warn!("Gupax | XMRig path is not valid! Skipping auto-xmrig...");
} else if cfg!(windows) {
Helper::start_xmrig(&app.helper, &app.state.xmrig, &app.state.gupax.absolute_xmrig_path, Arc::clone(&app.sudo));
} else {
@ -917,10 +921,10 @@ impl eframe::App for App {
let key: KeyPressed = {
if input.consume_key(Modifiers::NONE, Key::F11) {
KeyPressed::F11
} else if input.consume_key(Modifiers::NONE, Key::ArrowLeft) {
KeyPressed::Left
} else if input.consume_key(Modifiers::NONE, Key::ArrowRight) {
KeyPressed::Right
} else if input.consume_key(Modifiers::NONE, Key::Z) {
KeyPressed::Z
} else if input.consume_key(Modifiers::NONE, Key::X) {
KeyPressed::X
} else if input.consume_key(Modifiers::NONE, Key::ArrowUp) {
KeyPressed::Up
} else if input.consume_key(Modifiers::NONE, Key::ArrowDown) {
@ -936,12 +940,16 @@ impl eframe::App for App {
}
};
drop(input);
// Check if egui wants keyboard input.
// This prevents keyboard shortcuts from clobbering TextEdits.
// (Typing S in text would always [Save] instead)
let wants_input = ctx.wants_keyboard_input();
if key.is_f11() {
let info = frame.info();
frame.set_fullscreen(!info.window_info.fullscreen);
// Change Tabs LEFT
} else if key.is_left() {
} else if key.is_z() && !wants_input {
match self.tab {
Tab::About => self.tab = Tab::Xmrig,
Tab::Status => self.tab = Tab::About,
@ -950,7 +958,7 @@ impl eframe::App for App {
Tab::Xmrig => self.tab = Tab::P2pool,
};
// Change Tabs RIGHT
} else if key.is_right() {
} else if key.is_x() && !wants_input {
match self.tab {
Tab::About => self.tab = Tab::Status,
Tab::Status => self.tab = Tab::Gupax,
@ -1294,7 +1302,7 @@ impl eframe::App for App {
ui.group(|ui| {
ui.set_enabled(self.diff);
let width = width / 2.0;
if key.is_r() || ui.add_sized([width, height], Button::new("Reset")).on_hover_text("Reset changes").clicked() {
if key.is_r() && !wants_input || ui.add_sized([width, height], Button::new("Reset")).on_hover_text("Reset changes").clicked() {
let og = self.og.lock().unwrap().clone();
self.state.gupax = og.gupax;
self.state.p2pool = og.p2pool;
@ -1302,7 +1310,7 @@ impl eframe::App for App {
self.node_vec = self.og_node_vec.clone();
self.pool_vec = self.og_pool_vec.clone();
}
if key.is_s() || ui.add_sized([width, height], Button::new("Save")).on_hover_text("Save changes").clicked() {
if key.is_s() && !wants_input || ui.add_sized([width, height], Button::new("Save")).on_hover_text("Save changes").clicked() {
match State::save(&mut self.state, &self.state_path) {
Ok(_) => {
let mut og = self.og.lock().unwrap();
@ -1359,10 +1367,10 @@ impl eframe::App for App {
ui.add_sized([width, height], Button::new("")).on_disabled_hover_text("Start P2Pool");
});
} else if p2pool_is_alive {
if key.is_up() || ui.add_sized([width, height], Button::new("")).on_hover_text("Restart P2Pool").clicked() {
if key.is_up() && !wants_input || ui.add_sized([width, height], Button::new("")).on_hover_text("Restart P2Pool").clicked() {
Helper::restart_p2pool(&self.helper, &self.state.p2pool, &self.state.gupax.absolute_p2pool_path);
}
if key.is_down() || ui.add_sized([width, height], Button::new("")).on_hover_text("Stop P2Pool").clicked() {
if key.is_down() && !wants_input || ui.add_sized([width, height], Button::new("")).on_hover_text("Stop P2Pool").clicked() {
Helper::stop_p2pool(&self.helper);
}
ui.add_enabled_ui(false, |ui| {
@ -1379,12 +1387,15 @@ impl eframe::App for App {
if !Regexes::addr_ok(&self.regex, &self.state.p2pool.address) {
ui_enabled = false;
text = P2POOL_ADDRESS.to_string();
} else if !Gupax::path_is_exe(&self.state.gupax.p2pool_path) {
} else if !Gupax::path_is_file(&self.state.gupax.p2pool_path) {
ui_enabled = false;
text = P2POOL_PATH_NOT_EXE.to_string();
text = P2POOL_PATH_NOT_FILE.to_string();
} else if !crate::update::check_p2pool_path(&self.state.gupax.p2pool_path) {
ui_enabled = false;
text = P2POOL_PATH_NOT_VALID.to_string();
}
ui.set_enabled(ui_enabled);
if (ui_enabled && key.is_up()) || ui.add_sized([width, height], Button::new("")).on_hover_text("Start P2Pool").on_disabled_hover_text(text).clicked() {
if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new("")).on_hover_text("Start P2Pool").on_disabled_hover_text(text).clicked() {
Helper::start_p2pool(&self.helper, &self.state.p2pool, &self.state.gupax.absolute_p2pool_path);
}
}
@ -1410,7 +1421,7 @@ impl eframe::App for App {
ui.add_sized([width, height], Button::new("")).on_disabled_hover_text("Start XMRig");
});
} else if xmrig_is_alive {
if key.is_up() || ui.add_sized([width, height], Button::new("")).on_hover_text("Restart XMRig").clicked() {
if key.is_up() && !wants_input || ui.add_sized([width, height], Button::new("")).on_hover_text("Restart XMRig").clicked() {
if cfg!(windows) {
Helper::restart_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path, Arc::clone(&self.sudo));
} else {
@ -1418,7 +1429,7 @@ impl eframe::App for App {
self.error_state.ask_sudo(&self.sudo);
}
}
if key.is_down() || ui.add_sized([width, height], Button::new("")).on_hover_text("Stop XMRig").clicked() {
if key.is_down() && !wants_input || ui.add_sized([width, height], Button::new("")).on_hover_text("Stop XMRig").clicked() {
if cfg!(target_os = "macos") {
self.sudo.lock().unwrap().signal = ProcessSignal::Stop;
self.error_state.ask_sudo(&self.sudo);
@ -1436,17 +1447,20 @@ impl eframe::App for App {
});
let mut text = String::new();
let mut ui_enabled = true;
if !Gupax::path_is_exe(&self.state.gupax.xmrig_path) {
if !Gupax::path_is_file(&self.state.gupax.xmrig_path) {
ui_enabled = false;
text = XMRIG_PATH_NOT_EXE.to_string();
text = XMRIG_PATH_NOT_FILE.to_string();
} else if !crate::update::check_xmrig_path(&self.state.gupax.xmrig_path) {
ui_enabled = false;
text = XMRIG_PATH_NOT_VALID.to_string();
}
ui.set_enabled(ui_enabled);
#[cfg(target_os = "windows")]
if (ui_enabled && key.is_up()) || ui.add_sized([width, height], Button::new("")).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new("")).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
Helper::start_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path, Arc::clone(&self.sudo));
}
#[cfg(target_family = "unix")]
if (ui_enabled && key.is_up()) || ui.add_sized([width, height], Button::new("")).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new("")).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
self.sudo.lock().unwrap().signal = ProcessSignal::Start;
self.error_state.ask_sudo(&self.sudo);
}

View file

@ -168,6 +168,39 @@ const UPGRADE: &str = "----------------- Upgrade ------------------";
//const MSG_EXTRACT: &'static str = "Extracting packages";
//const MSG_UPGRADE: &'static str = "Upgrading packages";
//---------------------------------------------------------------------------------------------------- General functions
pub fn check_p2pool_path(path: &str) -> bool {
let path = match crate::disk::into_absolute_path(path.to_string()) {
Ok(p) => p,
Err(e) => return false,
};
let path = match path.file_name() {
Some(p) => p,
None => { error!("Couldn't get P2Pool file name"); return false; },
};
if path == ACCEPTABLE_P2POOL[0] || path == ACCEPTABLE_P2POOL[1] || path == ACCEPTABLE_P2POOL[2] || path == ACCEPTABLE_P2POOL[3] {
true
} else {
false
}
}
pub fn check_xmrig_path(path: &str) -> bool {
let path = match crate::disk::into_absolute_path(path.to_string()) {
Ok(p) => p,
Err(e) => return false,
};
let path = match path.file_name() {
Some(p) => p,
None => { error!("Couldn't get XMRig file name"); return false; },
};
if path == ACCEPTABLE_XMRIG[0] || path == ACCEPTABLE_XMRIG[1] || path == ACCEPTABLE_XMRIG[2] || path == ACCEPTABLE_XMRIG[3] {
true
} else {
false
}
}
//---------------------------------------------------------------------------------------------------- Update struct/impl
// Contains values needed during update
// Progress bar structure: