main: implement [ErrorState] checks in main()

This commit is contained in:
hinto-janaiyo 2022-11-16 14:07:27 -05:00
parent a13e6d689b
commit 50fff5c311
No known key found for this signature in database
GPG key ID: B1C5A64B80691E45
4 changed files with 113 additions and 121 deletions

View file

@ -60,11 +60,11 @@ pub const HUGEPAGES_1GB: bool = true;
// Tooltips
// Gupax
pub const GUPAX_UPDATE: &'static str = "Check for update on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically";
pub const GUPAX_UPDATE: &'static str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically";
pub const GUPAX_AUTO_UPDATE: &'static str = "Automatically check for updates at startup";
pub const GUPAX_UPDATE_VIA_TOR: &'static str = "Update through the Tor network. Tor is embedded within Gupax; a Tor system proxy is not required";
pub const GUPAX_AUTO_NODE: &'static str = "Automatically ping the community Monero nodes and select the fastest at startup for P2Pool";
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_ASK_BEFORE_QUIT: &'static str = "Ask before quitting Gupax";
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; A red [X] will appear if there is no file found at the given path";
pub const GUPAX_PATH_XMRIG: &'static str = "The location of the XMRig binary: Both absolute and relative paths are accepted; A red [X] will appear if there is no file found at the given path";
@ -94,9 +94,9 @@ r#"Use advanced settings:
- Out/In peer setting
- Log level setting"#;
pub const P2POOL_NAME: &'static str = "Add a unique name to identify this node; Only [A-Za-z0-9-_] and spaces allowed; Max length = 30 characters";
pub const P2POOL_NODE_IP: &'static str = "Specify the Monero Node IP to connect to with P2Pool; Max length = 255 characters";
pub const P2POOL_RPC_PORT: &'static str = "Specify the RPC port of the Monero node; [0-65535]";
pub const P2POOL_ZMQ_PORT: &'static str = "Specify the ZMQ port of the Monero node; [0-65535]";
pub const P2POOL_NODE_IP: &'static 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: &'static str = "Specify the RPC port of the Monero node; [1-65535]";
pub const P2POOL_ZMQ_PORT: &'static str = "Specify the ZMQ port of the Monero node; [1-65535]";
pub const P2POOL_ADD: &'static str = "Add the current values to the list";
pub const P2POOL_DELETE: &'static str = "Delete the currently selected node";
pub const P2POOL_CLEAR: &'static str = "Clear all current values";

View file

@ -50,11 +50,24 @@ use log::*;
// create_new() | Write a default TOML Struct into the appropriate file (in OS data path)
// into_absolute_path() | Convert relative -> absolute path
pub fn get_file_path(file: File) -> Result<PathBuf, TomlError> {
pub fn get_os_data_path() -> Result<PathBuf, TomlError> {
// Get OS data folder
// Linux | $XDG_DATA_HOME or $HOME/.local/share | /home/alice/.local/state
// macOS | $HOME/Library/Application Support | /Users/Alice/Library/Application Support
// Windows | {FOLDERID_RoamingAppData} | C:\Users\Alice\AppData\Roaming
let mut path = match dirs::data_dir() {
Some(mut path) => {
info!("OS | Data path ... OK");
path
},
None => { error!("OS | Data path ... FAIL"); return Err(TomlError::Path(PATH_ERROR.to_string())) },
};
// Create directory
fs::create_dir_all(&path)?;
Ok(path)
}
pub fn get_file_path(file: File) -> Result<PathBuf, TomlError> {
let name = File::name(&file);
let mut path = match dirs::data_dir() {
@ -217,22 +230,22 @@ impl State {
// Save [State] onto disk file [gupax.toml]
pub fn save(&mut self) -> Result<(), TomlError> {
info!("Saving {:?} to disk...", self);
info!("State | Saving to disk...");
let path = get_file_path(File::State)?;
// Convert path to absolute
self.gupax.absolute_p2pool_path = into_absolute_path(self.gupax.p2pool_path.clone())?;
self.gupax.absolute_xmrig_path = into_absolute_path(self.gupax.xmrig_path.clone())?;
let string = match toml::ser::to_string(&self) {
Ok(string) => {
info!("TOML parse ... OK");
info!("State | Parse ... OK");
print_toml(&string);
string
},
Err(err) => { error!("Couldn't parse TOML into string"); return Err(TomlError::Serialize(err)) },
Err(err) => { error!("State | Couldn't parse TOML into string ... FAIL"); return Err(TomlError::Serialize(err)) },
};
match fs::write(path, string) {
Ok(_) => { info!("TOML save ... OK"); Ok(()) },
Err(err) => { error!("Couldn't overwrite TOML file"); return Err(TomlError::Io(err)) },
Ok(_) => { info!("State | Save ... OK"); Ok(()) },
Err(err) => { error!("State | Couldn't overwrite TOML file ... FAIL"); return Err(TomlError::Io(err)) },
}
}

View file

@ -64,8 +64,7 @@ use {ferris::*,constants::*,node::*,disk::*,status::*,gupax::*,p2pool::*,xmrig::
pub struct App {
// Misc state
tab: Tab, // What tab are we on?
quit: bool, // Was the quit button clicked?
quit_confirm: bool, // Was the quit confirmed?
// quit: bool, // Was the quit confirmed?
ping: Arc<Mutex<Ping>>, // Ping data found in [node.rs]
width: f32, // Top-level width
height: f32, // Top-level height
@ -95,9 +94,10 @@ pub struct App {
dir: String, // Directory [Gupax] binary is in
resolution: Vec2, // Frame resolution
os: &'static str, // OS
os_data_path: PathBuf, // OS data path (e.g: ~/.local/share/gupax)
version: &'static str, // Gupax version
name_version: String, // [Gupax vX.X.X]
image: Images, // Custom Struct holding pre-compiled bytes of [Images]
img: Images, // Custom Struct holding pre-compiled bytes of [Images]
regex: Regexes, // Custom Struct holding pre-made [Regex]'s
}
@ -114,8 +114,7 @@ impl App {
fn new() -> Self {
let app = Self {
tab: Tab::default(),
quit: false,
quit_confirm: false,
// quit: false,
ping: Arc::new(Mutex::new(Ping::new())),
width: 1280.0,
height: 720.0,
@ -135,9 +134,10 @@ impl App {
dir: "".to_string(),
resolution: Vec2::new(1280.0, 720.0),
os: OS,
os_data_path: PathBuf::new(),
version: GUPAX_VERSION,
name_version: format!("Gupax {}", GUPAX_VERSION),
image: Images::new(),
img: Images::new(),
regex: Regexes::new(),
};
// Apply arg state
@ -152,6 +152,11 @@ impl App {
Ok(dir) => dir,
Err(err) => { panic_main(err.to_string()); exit(1); },
};
// Get OS data path
app.os_data_path = match get_os_data_path() {
Ok(dir) => dir,
Err(err) => { panic_main(err.to_string()); exit(1); },
};
// Read disk state if no [--reset] arg
if app.reset == false {
app.og = match State::get() {
@ -200,8 +205,8 @@ impl Default for Tab {
//---------------------------------------------------------------------------------------------------- [ErrorState] struct
pub struct ErrorState {
error: bool, // Is there an error?
msg: String, // What message to display?
image: RetainedImage, // Which ferris to display?
msg: &'static str, // What message to display?
ferris: ErrorFerris, // Which ferris to display?
buttons: ErrorButtons, // Which buttons to display?
}
@ -209,27 +214,39 @@ impl ErrorState {
pub fn new() -> Self {
Self {
error: false,
msg: String::new(),
image: RetainedImage::from_image_bytes("banner.png", FERRIS_ERROR).unwrap(),
msg: "Unknown Error",
ferris: ErrorFerris::Oops,
buttons: ErrorButtons::Okay,
}
}
// Convenience function to set the [App] error state
pub fn set(mut self, new: Self) {
self = new;
pub fn set(&mut self, error: bool, msg: &'static str, ferris: ErrorFerris, buttons: ErrorButtons) {
*self = Self {
error,
msg,
ferris,
buttons,
};
}
}
//---------------------------------------------------------------------------------------------------- [ErrorButtons] enum
#[derive(Clone, Copy, Debug, PartialEq)]
enum ErrorButtons {
pub enum ErrorButtons {
YesNo,
YesQuit,
StayQuit,
Okay,
Quit,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ErrorFerris {
Oops,
Error,
Panic,
}
//---------------------------------------------------------------------------------------------------- [Images] struct
struct Images {
banner: RetainedImage,
@ -242,9 +259,9 @@ impl Images {
fn new() -> Self {
Self {
banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).unwrap(),
oops: RetainedImage::from_image_bytes("banner.png", FERRIS_OOPS).unwrap(),
error: RetainedImage::from_image_bytes("banner.png", FERRIS_ERROR).unwrap(),
panic: RetainedImage::from_image_bytes("banner.png", FERRIS_PANIC).unwrap(),
oops: RetainedImage::from_image_bytes("oops.png", FERRIS_OOPS).unwrap(),
error: RetainedImage::from_image_bytes("error.png", FERRIS_ERROR).unwrap(),
panic: RetainedImage::from_image_bytes("panic.png", FERRIS_PANIC).unwrap(),
}
}
}
@ -566,15 +583,23 @@ fn main() {
let mut app = App::new();
app.now = now;
init_auto(&app);
info!("Initialization DONE ... {} seconds", now.elapsed().as_secs_f32());
info!("Init ... DONE ... Took [{}] seconds", now.elapsed().as_secs_f32());
eframe::run_native(&app.name_version.clone(), options, Box::new(|cc| Box::new(App::cc(cc, app))),);
}
impl eframe::App for App {
// pub fn new() -> Self {
// Self {
// error: false,
// msg: String::new(),
// image: RetainedImage::from_image_bytes("banner.png", FERRIS_ERROR).unwrap(),
// buttons: ErrorButtons::Okay,
// }
// }
fn on_close_event(&mut self) -> bool {
self.quit = true;
if self.og.lock().unwrap().gupax.ask_before_quit {
self.quit_confirm
if self.state.gupax.ask_before_quit {
self.error_state.set(true, "", ErrorFerris::Oops, ErrorButtons::StayQuit);
false
} else {
true
}
@ -608,23 +633,49 @@ impl eframe::App for App {
let width = self.width;
let height = self.height/4.0;
ui.style_mut().override_text_style = Some(Name("MonospaceLarge".into()));
self.error_state.image.show_max_size(ui, Vec2::new(width, height));
ui.add_sized([width, height], Label::new("--- Gupax has encountered an error ---"));
ui.add_sized([width, height], Label::new(&self.error_state.msg));
// Display ferris
use ErrorFerris::*;
let ferris = match self.error_state.ferris {
Oops => &self.img.oops,
Error => &self.img.error,
Panic => &self.img.panic,
};
ferris.show_max_size(ui, Vec2::new(width, height));
// Error/Quit screen
match self.error_state.buttons {
StayQuit => {
let mut text = "--- Are you sure you want to quit? ---".to_string();
if *self.update.lock().unwrap().updating.lock().unwrap() { text = format!("{}\nUpdate is in progress...!", text); }
if self.p2pool { text = format!("{}\nP2Pool is online...!", text); }
if self.xmrig { text = format!("{}\nXMRig is online...!", text); }
ui.add_sized([width, height], Label::new(text))
},
_ => ui.add_sized([width, height], Label::new("--- Gupax has encountered an error! ---")),
};
ui.add_sized([width, height], Label::new(self.error_state.msg));
use ErrorButtons::*;
let height = ui.available_height();
// Capture [Esc] key
let esc = ctx.input_mut().consume_key(Modifiers::NONE, Key::Escape);
match self.error_state.buttons {
YesNo => {
if ui.add_sized([width, height/2.0], egui::Button::new("Yes")).clicked() { self.error_state = ErrorState::new(); }
if ui.add_sized([width, height/2.0], egui::Button::new("No")).clicked() { exit(1); }
// If [Esc] was pressed, assume [No]
if esc || ui.add_sized([width, height/2.0], egui::Button::new("No")).clicked() { exit(0); }
},
YesQuit => {
if ui.add_sized([width, height/2.0], egui::Button::new("Okay")).clicked() { self.error_state = ErrorState::new(); }
if ui.add_sized([width, height/2.0], egui::Button::new("Quit")).clicked() { exit(1); }
StayQuit => {
// If [Esc] was pressed, assume [Stay]
if esc || ui.add_sized([width, height/2.0], egui::Button::new("Stay")).clicked() {
self.error_state = ErrorState::new();
}
if ui.add_sized([width, height/2.0], egui::Button::new("Quit")).clicked() { exit(0); }
},
Okay => if ui.add_sized([width, height], egui::Button::new("Okay")).clicked() { self.error_state = ErrorState::new(); },
Quit => if ui.add_sized([width, height], egui::Button::new("Quit")).clicked() { exit(1); },
Okay => if esc || ui.add_sized([width, height], egui::Button::new("Okay")).clicked() { self.error_state = ErrorState::new(); },
Quit => if ui.add_sized([width, height], egui::Button::new("Quit")).clicked() { exit(0); },
}
})});
return
@ -647,80 +698,6 @@ impl eframe::App for App {
}
drop(og);
// Close confirmation.
if self.quit {
// If [ask_before_quit == true]
if self.og.lock().unwrap().gupax.ask_before_quit {
egui::TopBottomPanel::bottom("quit").show(ctx, |ui| {
let width = self.width;
let height = self.height/8.0;
ui.group(|ui| {
if ui.add_sized([width, height], egui::Button::new("Yes")).clicked() {
if self.og.lock().unwrap().gupax.save_before_quit {
if self.diff {
info!("Saving before quit...");
match self.state.save() {
Err(err) => { error!("{}", err); exit(1); },
_ => (),
};
} else {
info!("No changed detected, not saving...");
}
}
info!("Quit confirmation = yes ... goodbye!");
exit(0);
} else if ui.add_sized([width, height], egui::Button::new("No")).clicked() {
self.quit = false;
}
});
});
egui::CentralPanel::default().show(ctx, |ui| {
let width = self.width;
let height = ui.available_height();
let ten = height/10.0;
// Detect processes or update
ui.add_space(ten);
if *self.update.lock().unwrap().updating.lock().unwrap() || self.p2pool || self.xmrig {
ui.add_sized([width, height/4.0], Label::new("Are you sure you want to quit?"));
if *self.update.lock().unwrap().updating.lock().unwrap() { ui.add_sized([width, ten], Label::new("Update is in progress...!")); }
if self.p2pool { ui.add_sized([width, ten], Label::new("P2Pool is online...!")); }
if self.xmrig { ui.add_sized([width, ten], Label::new("XMRig is online...!")); }
// Else, just quit
} else {
if self.og.lock().unwrap().gupax.save_before_quit {
if self.diff {
info!("Saving before quit...");
match self.state.save() {
Err(err) => { error!("{}", err); exit(1); },
_ => (),
};
} else {
info!("No changed detected, not saving...");
}
}
info!("No processes or update in progress ... goodbye!");
exit(0);
}
});
// Else, quit (save if [save_before_quit == true]
} else {
if self.og.lock().unwrap().gupax.save_before_quit {
if self.diff {
info!("Saving before quit...");
match self.state.save() {
Err(err) => { error!("{}", err); exit(1); },
_ => (),
};
} else {
info!("No changed detected, not saving...");
}
}
info!("Quit confirmation = yes ... goodbye!");
exit(0);
}
return
}
// Top: Tabs
egui::TopBottomPanel::top("top").show(ctx, |ui| {
let width = (self.width - (SPACE*10.0))/5.0;
@ -728,10 +705,11 @@ impl eframe::App for App {
ui.group(|ui| {
ui.add_space(4.0);
ui.horizontal(|ui| {
ui.style_mut().override_text_style = Some(Name("Tab".into()));
ui.style_mut().visuals.widgets.inactive.fg_stroke.color = Color32::from_rgb(100, 100, 100);
ui.style_mut().visuals.selection.bg_fill = Color32::from_rgb(255, 120, 120);
ui.style_mut().visuals.selection.stroke = Stroke { width: 5.0, color: Color32::from_rgb(255, 255, 255) };
let style = ui.style_mut();
style.override_text_style = Some(Name("Tab".into()));
style.visuals.widgets.inactive.fg_stroke.color = Color32::from_rgb(100, 100, 100);
style.visuals.selection.bg_fill = Color32::from_rgb(255, 120, 120);
style.visuals.selection.stroke = Stroke { width: 5.0, color: Color32::from_rgb(255, 255, 255) };
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::About, "About")).clicked() { self.tab = Tab::About; }
ui.separator();
if ui.add_sized([width, height], egui::SelectableLabel::new(self.tab == Tab::Status, "Status")).clicked() { self.tab = Tab::Status; }
@ -868,7 +846,7 @@ impl eframe::App for App {
ui.add_space(10.0);
ui.vertical_centered(|ui| {
// Display [Gupax] banner at max, 1/4 the available length
self.image.banner.show_max_size(ui, Vec2::new(self.width, self.height/4.0));
self.img.banner.show_max_size(ui, Vec2::new(self.width, self.height/4.0));
ui.label("Gupax is a cross-platform GUI for mining");
ui.hyperlink_to("[Monero]", "https://www.github.com/monero-project/monero");
ui.label("on the decentralized");

View file

@ -298,6 +298,7 @@ impl P2pool {
zmq: self.zmq.clone(),
};
node_vec.push((self.name.clone(), node));
info!("Node | Added [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", node_vec_len+1, self.name, self.ip, self.rpc, self.zmq);
}
});
ui.horizontal(|ui| {
@ -314,7 +315,7 @@ impl P2pool {
_ => { self.selected_name = node_vec[n-1].0.clone(); self.selected_index = n as u16; },
};
node_vec.remove(n);
info!("Node | Removed index [{}. {}]", n+1, self.selected_name);
info!("Node | Deleted [index: {}, name: \"{}\", ip: \"{}\", rpc: {}, zmq: {}]", n+1, self.selected_name, self.selected_ip, self.selected_rpc, self.selected_zmq);
break
}
n += 1;