mirror of
https://github.com/hinto-janai/gupax.git
synced 2024-11-17 09:47:36 +00:00
main: implement [ErrorState] checks in main()
This commit is contained in:
parent
a13e6d689b
commit
50fff5c311
4 changed files with 113 additions and 121 deletions
|
@ -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";
|
||||
|
|
25
src/disk.rs
25
src/disk.rs
|
@ -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)) },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
196
src/main.rs
196
src/main.rs
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue