From 7a5fe2427679eaf9cc7b29a4ece354b17893b501 Mon Sep 17 00:00:00 2001 From: hinto-janaiyo Date: Sat, 19 Nov 2022 21:20:28 -0500 Subject: [PATCH] disk: add [ErrorState] handling for disk errors --- Cargo.lock | 101 -------------------- Cargo.toml | 2 +- images/ferris/happy.png | Bin 0 -> 52565 bytes src/constants.rs | 20 ++-- src/disk.rs | 95 +++++++++---------- src/ferris.rs | 2 +- src/main.rs | 202 +++++++++++++++++++++++++++++----------- src/node.rs | 2 - src/p2pool.rs | 2 +- 9 files changed, 209 insertions(+), 217 deletions(-) create mode 100644 images/ferris/happy.png diff --git a/Cargo.lock b/Cargo.lock index 6b6fbb0..3ef473c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1275,15 +1275,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - [[package]] name = "enum-ordinalize" version = "3.1.12" @@ -1920,7 +1911,6 @@ dependencies = [ "openssl", "rand 0.8.5", "regex", - "reqwest", "rfd", "rusqlite", "serde", @@ -1937,25 +1927,6 @@ dependencies = [ "zip", ] -[[package]] -name = "h2" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.1.0" @@ -2106,7 +2077,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", @@ -2223,12 +2193,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "ipnet" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" - [[package]] name = "itertools" version = "0.10.5" @@ -2438,12 +2402,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3339,43 +3297,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "reqwest" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - [[package]] name = "retain_mut" version = "0.1.9" @@ -3661,18 +3582,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_with" version = "1.14.0" @@ -4275,7 +4184,6 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -5439,15 +5347,6 @@ dependencies = [ "x11-dl", ] -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "winres" version = "0.1.12" diff --git a/Cargo.toml b/Cargo.toml index 3c4ec49..891132c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ num_cpus = "1.13.1" num-format = "0.4.0" rand = "0.8.5" regex = "1.6.0" -reqwest = { version = "0.11.12", features = ["blocking", "json"] } +#reqwest = { version = "0.11.12", features = ["blocking", "json"] } rfd = "0.10.0" rusqlite = { version = "0.28.0", features = ["bundled"] } serde = { version = "1.0.145", features = ["rc", "derive"] } diff --git a/images/ferris/happy.png b/images/ferris/happy.png new file mode 100644 index 0000000000000000000000000000000000000000..84d84adfc6a317c480520f6a54b2ca6d6ccfa30d GIT binary patch literal 52565 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 *WYPZ58~y#~uE`uEh%5TI&Gss3GOY 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 AX8-^I literal 0 HcmV?d00001 diff --git a/src/constants.rs b/src/constants.rs index 77ca9f5..c21250d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -85,7 +85,7 @@ r#"Use advanced settings: - P2Pool Main/Mini selection - 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_NAME: &'static str = "Add a unique name to identify this node; Only [A-Za-z0-9-_] and spaces allowed, if the name already exists, the current settings will be saved to the already existing entry; Max length = 30 characters"; 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]"; @@ -106,15 +106,17 @@ pub const XMRIG_PRIORITY: &'static str = "Set process priority (0 idle, 2 normal // CLI argument messages pub const ARG_HELP: &'static str = -r#"USAGE: ./gupax [--flags] +r#"USAGE: ./gupax [--flag] - -h | --help Print this help message - -v | --version Print version and build info - -l | --node-list Print the manual node list - -s | --state Print Gupax state - -n | --no-startup Disable all auto-startup settings for this instance - -r | --reset Reset all Gupax state and the manual node list - -f | --ferris Print an extremely cute crab + --help Print this help message + --version Print version and build info + --state Print Gupax state + --nodes Print the manual node list + --no-startup Disable all auto-startup settings for this instance + --reset-state Reset all Gupax state (your settings) + --reset-nodes Reset the manual node list in the [P2Pool] tab + --reset-all Reset both the state and the manual node list + --ferris Print an extremely cute crab To view more detailed console debug information, start Gupax with the environment variable [RUST_LOG] set to a log level like so: diff --git a/src/disk.rs b/src/disk.rs index 76a07fc..28ef127 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -179,7 +179,7 @@ impl State { } // Convert [String] to [State] - pub fn from_string(string: String) -> Result { + pub fn from_string(string: &String) -> Result { match toml::de::from_str(&string) { Ok(state) => { info!("State | Parse ... OK"); @@ -187,7 +187,7 @@ impl State { Ok(state) } Err(err) => { - error!("State | String -> State ... FAIL ... {}", err); + warn!("State | String -> State ... FAIL ... {}", err); Err(TomlError::Deserialize(err)) }, } @@ -207,11 +207,20 @@ impl State { // Create _ => { Self::create_new()?; - read_to_string(file, &path)? + match read_to_string(file, &path) { + Ok(s) => s, + Err(e) => return Err(e), + } }, }; - // Deserialize - Self::from_string(string) + // Deserialize, attempt merge if failed + match Self::from_string(&string) { + Ok(s) => Ok(s), + Err(e) => { + warn!("State | Attempting merge..."); + Self::merge(string) + }, + } } // Completely overwrite current [state.toml] @@ -250,22 +259,17 @@ impl State { } } - // Take [Self] as input, merge it with whatever the current [default] is, + // Take [String] as input, merge it with whatever the current [default] is, // leaving behind old keys+values and updating [default] with old valid ones. // Automatically overwrite current file. - pub fn merge(old: &Self) -> Result { - info!("Starting TOML merge..."); - let old = match toml::ser::to_string(&old) { - Ok(string) => { info!("Old TOML parse ... OK"); string }, - Err(err) => { error!("Couldn't parse old TOML into string"); return Err(TomlError::Serialize(err)) }, - }; + pub fn merge(old: String) -> Result { let default = match toml::ser::to_string(&Self::new()) { - Ok(string) => { info!("Default TOML parse ... OK"); string }, - Err(err) => { error!("Couldn't parse default TOML into string"); return Err(TomlError::Serialize(err)) }, + Ok(string) => { info!("State | Default TOML parse ... OK"); string }, + Err(err) => { error!("State | Couldn't parse default TOML into string"); return Err(TomlError::Serialize(err)) }, }; let mut new: Self = match Figment::new().merge(Toml::string(&old)).merge(Toml::string(&default)).extract() { - Ok(new) => { info!("TOML merge ... OK"); new }, - Err(err) => { error!("Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) }, + Ok(new) => { info!("State | TOML merge ... OK"); new }, + Err(err) => { error!("State | Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) }, }; // Attempt save Self::save(&mut new)?; @@ -298,7 +302,7 @@ impl Node { } // Convert [String] to [Node] Vec - pub fn from_string(string: String) -> Result, TomlError> { + pub fn from_string_to_vec(string: &String) -> Result, TomlError> { let nodes: toml::map::Map = match toml::de::from_str(&string) { Ok(map) => { info!("Node | Parse ... OK"); @@ -312,7 +316,6 @@ impl Node { let size = nodes.keys().len(); let mut vec = Vec::with_capacity(size); for (key, values) in nodes.iter() { -// println!("{:#?}", values.get("ip")); std::process::exit(0); let node = Node { ip: values.get("ip").unwrap().as_str().unwrap().to_string(), rpc: values.get("rpc").unwrap().as_str().unwrap().to_string(), @@ -357,8 +360,8 @@ impl Node { read_to_string(file, &path)? }, }; - // Deserialize - Self::from_string(string) + // Deserialize, attempt merge if failed + Self::from_string_to_vec(&string) } // Completely overwrite current [node.toml] @@ -380,26 +383,19 @@ impl Node { let string = Self::to_string(vec); match fs::write(path, string) { Ok(_) => { info!("TOML save ... OK"); Ok(()) }, - Err(err) => { error!("Couldn't overwrite TOML file"); return Err(TomlError::Io(err)) }, + Err(err) => { error!("Couldn't overwrite TOML file"); Err(TomlError::Io(err)) }, } } -// // Take [Self] as input, merge it with whatever the current [default] is, -// // leaving behind old keys+values and updating [default] with old valid ones. -// // Automatically overwrite current file. -// pub fn merge(old: &Self) -> Result { -// info!("Starting TOML merge..."); -// let old = match toml::ser::to_string(&old) { -// Ok(string) => { info!("Old TOML parse ... OK"); string }, -// Err(err) => { error!("Couldn't parse old TOML into string"); return Err(TomlError::Serialize(err)) }, -// }; +// pub fn merge(old: &String) -> Result { +// info!("Node | Starting TOML merge..."); // let default = match toml::ser::to_string(&Self::new()) { -// Ok(string) => { info!("Default TOML parse ... OK"); string }, -// Err(err) => { error!("Couldn't parse default TOML into string"); return Err(TomlError::Serialize(err)) }, +// Ok(string) => { info!("Node | Default TOML parse ... OK"); string }, +// Err(err) => { error!("Node | Couldn't parse default TOML into string"); return Err(TomlError::Serialize(err)) }, // }; // let mut new: Self = match Figment::new().merge(Toml::string(&old)).merge(Toml::string(&default)).extract() { -// Ok(new) => { info!("TOML merge ... OK"); new }, -// Err(err) => { error!("Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) }, +// Ok(new) => { info!("Node | TOML merge ... OK"); new }, +// Err(err) => { error!("Node | Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) }, // }; // // Attempt save // Self::save(&mut new)?; @@ -408,15 +404,24 @@ impl Node { } //---------------------------------------------------------------------------------------------------- Custom Error [TomlError] +#[derive(Debug)] +pub enum TomlError { + Io(std::io::Error), + Path(String), + Serialize(toml::ser::Error), + Deserialize(toml::de::Error), + Merge(figment::Error), +} + impl Display for TomlError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { use TomlError::*; match self { - Io(err) => write!(f, "{}: {} | {}", ERROR, self, err), - Path(err) => write!(f, "{}: {} | {}", ERROR, self, err), - Serialize(err) => write!(f, "{}: {} | {}", ERROR, self, err), - Deserialize(err) => write!(f, "{}: {} | {}", ERROR, self, err), - Merge(err) => write!(f, "{}: {} | {}", ERROR, self, err), + Io(err) => write!(f, "{}: IO | {}", ERROR, err), + Path(err) => write!(f, "{}: Path | {}", ERROR, err), + Serialize(err) => write!(f, "{}: Serialize | {}", ERROR, err), + Deserialize(err) => write!(f, "{}: Deserialize | {}", ERROR, err), + Merge(err) => write!(f, "{}: Merge | {}", ERROR, err), } } } @@ -447,16 +452,6 @@ pub const DEFAULT_XMRIG_PATH: &'static str = r"XMRig\xmrig.exe"; #[cfg(target_family = "unix")] pub const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig"; -//---------------------------------------------------------------------------------------------------- Error Enum -#[derive(Debug)] -pub enum TomlError { - Io(std::io::Error), - Path(String), - Serialize(toml::ser::Error), - Deserialize(toml::de::Error), - Merge(figment::Error), -} - //---------------------------------------------------------------------------------------------------- [File] Enum (for matching which file) #[derive(Clone,Copy,Eq,PartialEq,Debug,Deserialize,Serialize)] pub enum File { diff --git a/src/ferris.rs b/src/ferris.rs index 08eb09c..759e20b 100644 --- a/src/ferris.rs +++ b/src/ferris.rs @@ -17,6 +17,7 @@ // Some images of ferris in byte form for error messages, etc +pub const FERRIS_HAPPY: &[u8] = include_bytes!("../images/ferris/happy.png"); pub const FERRIS_OOPS: &[u8] = include_bytes!("../images/ferris/oops.png"); pub const FERRIS_ERROR: &[u8] = include_bytes!("../images/ferris/error.png"); pub const FERRIS_PANIC: &[u8] = include_bytes!("../images/ferris/panic.png"); // This isnt technically ferris but its ok since its spooky @@ -35,7 +36,6 @@ pub const FERRIS_PANIC: &[u8] = include_bytes!("../images/ferris/panic.png"); // - // This is the ANSI representation of Ferris in string form. // Calling [println!] on this straight up prints a 256-bit color Ferris to the terminal. // The ANSI codes were generated with [https://docs.rs/ansipix], but there is no reason to include the library and diff --git a/src/main.rs b/src/main.rs index 83e5e19..f779404 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,7 +86,6 @@ pub struct App { xmrig: bool, // Is xmrig online? // State from [--flags] no_startup: bool, - reset: bool, // Static stuff now: Instant, // Internal timer exe: String, // Path for [Gupax] binary @@ -128,7 +127,6 @@ impl App { p2pool: false, xmrig: false, no_startup: false, - reset: false, now: Instant::now(), exe: "".to_string(), dir: "".to_string(), @@ -157,18 +155,42 @@ impl App { 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() { - Ok(toml) => Arc::new(Mutex::new(toml)), - Err(err) => { panic_main(err.to_string()); exit(1); }, - }; - } - let mut og = app.og.lock().unwrap(); // Lock [og] - app.state = og.clone(); - // Get node list - app.og_node_vec = Node::get().unwrap(); + // Read disk state + use TomlError::*; + app.state = match State::get() { + Ok(toml) => toml, + Err(err) => { + error!("State ... {}", err); + match err { + Io(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Path(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Serialize(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Deserialize(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Merge(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Error, ErrorButtons::ResetState), + }; + State::new() + }, + }; + app.og = Arc::new(Mutex::new(app.state.clone())); + // Read node list + app.og_node_vec = match Node::get() { + Ok(toml) => toml, + Err(err) => { + error!("Node ... {}", err); + match err { + Io(e) => app.error_state.set(true, format!("Node list: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Path(e) => app.error_state.set(true, format!("Node list: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Serialize(e) => app.error_state.set(true, format!("Node list: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Deserialize(e) => app.error_state.set(true, format!("Node list: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + Merge(e) => app.error_state.set(true, format!("Node list: {}", e), ErrorFerris::Error, ErrorButtons::ResetState), + }; + Node::new_vec() + }, + }; app.node_vec = app.og_node_vec.clone(); + + + let mut og = app.og.lock().unwrap(); // Lock [og] // Handle max threads og.xmrig.max_threads = num_cpus::get(); let current = og.xmrig.current_threads; @@ -222,7 +244,7 @@ impl Default for Tab { //---------------------------------------------------------------------------------------------------- [ErrorState] struct pub struct ErrorState { error: bool, // Is there an error? - msg: &'static str, // What message to display? + msg: String, // What message to display? ferris: ErrorFerris, // Which ferris to display? buttons: ErrorButtons, // Which buttons to display? } @@ -231,17 +253,17 @@ impl ErrorState { pub fn new() -> Self { Self { error: false, - msg: "Unknown Error", + msg: "Unknown Error".to_string(), ferris: ErrorFerris::Oops, buttons: ErrorButtons::Okay, } } // Convenience function to set the [App] error state - pub fn set(&mut self, error: bool, msg: &'static str, ferris: ErrorFerris, buttons: ErrorButtons) { + pub fn set(&mut self, error: bool, msg: impl Into, ferris: ErrorFerris, buttons: ErrorButtons) { *self = Self { error, - msg, + msg: msg.into(), ferris, buttons, }; @@ -253,12 +275,15 @@ impl ErrorState { pub enum ErrorButtons { YesNo, StayQuit, + ResetState, + ResetNode, Okay, Quit, } #[derive(Clone, Copy, Debug, PartialEq)] pub enum ErrorFerris { + Happy, Oops, Error, Panic, @@ -267,6 +292,7 @@ pub enum ErrorFerris { //---------------------------------------------------------------------------------------------------- [Images] struct struct Images { banner: RetainedImage, + happy: RetainedImage, oops: RetainedImage, error: RetainedImage, panic: RetainedImage, @@ -276,6 +302,7 @@ impl Images { fn new() -> Self { Self { banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).unwrap(), + happy: RetainedImage::from_image_bytes("happy.png", FERRIS_HAPPY).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(), @@ -388,6 +415,9 @@ fn init_auto(app: &App) { if app.no_startup { info!("[--no-startup] flag passed, skipping init_auto()..."); return + } else if app.error_state.error { + info!("App error detected, skipping init_auto()..."); + return } else { info!("Starting init_auto()..."); } @@ -442,17 +472,31 @@ fn init_auto(app: &App) { } } -fn reset() { - let mut code = 0; +fn reset_state() -> Result<(), TomlError> { info!("Resetting [state.toml]..."); match State::create_new() { - Ok(_) => info!("Resetting [state.toml] ... OK"), - Err(e) => { error!("Resetting [state.toml] ... FAIL ... {}", e); code = 1; }, + Ok(_) => { info!("Resetting [state.toml] ... OK"); Ok(()) }, + Err(e) => { error!("Resetting [state.toml] ... FAIL ... {}", e); Err(e) }, } +} + +fn reset_nodes() -> Result<(), TomlError> { info!("Resetting [node.toml]..."); match Node::create_new() { - Ok(_) => info!("Resetting [node.toml] ... OK"), - Err(e) => { error!("Resetting [node.toml] ... FAIL ... {}", e); code = 1; }, + Ok(_) => { info!("Resetting [node.toml] ... OK"); Ok(()) }, + Err(e) => { error!("Resetting [node.toml] ... FAIL ... {}", e); Err(e) }, + } +} + +fn reset() { + let mut code = 0; + match reset_state() { + Ok(_) => (), + Err(_) => code = 1, + } + match reset_nodes() { + Ok(_) => (), + Err(_) => code = 1, } match code { 0 => println!("\nGupax files were reset successfully."), @@ -469,23 +513,25 @@ fn parse_args(mut app: App) -> App { // [help/version], exit early for arg in &args { match arg.as_str() { - "-h"|"--help" => { println!("{}", ARG_HELP); exit(0); }, - "-v"|"--version" => { + "--help" => { println!("{}", ARG_HELP); exit(0); }, + "--version" => { println!("Gupax {} [OS: {}, Commit: {}]\n\n{}", GUPAX_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT); exit(0); }, - "-f"|"--ferris" => { println!("{}", FERRIS_ANSI); exit(0); }, + "--ferris" => { println!("{}", FERRIS_ANSI); exit(0); }, _ => (), } } // Everything else for arg in args { match arg.as_str() { - "-l"|"--node-list" => { info!("Printing node list..."); print_disk_file(File::Node); } - "-s"|"--state" => { info!("Printing state..."); print_disk_file(File::State); } - "-r"|"--reset" => { reset(); } - "-n"|"--no-startup" => { app.no_startup = true; } - _ => { eprintln!("[Gupax error] Invalid option: [{}]\nFor help, use: [--help]", arg); exit(1); }, + "--nodes" => { info!("Printing node list..."); print_disk_file(File::Node); } + "--state" => { info!("Printing state..."); print_disk_file(File::State); } + "--reset-state" => if let Ok(()) = reset_state() { exit(0) } else { exit(1) }, + "--reset-nodes" => if let Ok(()) = reset_nodes() { exit(0) } else { exit(1) }, + "--reset-all" => reset(), + "--no-startup" => app.no_startup = true, + _ => { eprintln!("[Gupax error] Invalid option: [{}]\nFor help, use: [--help]", arg); exit(1); }, } } app @@ -604,14 +650,6 @@ fn main() { } 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 { if self.state.gupax.ask_before_quit { self.error_state.set(true, "", ErrorFerris::Oops, ErrorButtons::StayQuit); @@ -652,8 +690,10 @@ impl eframe::App for App { // Display ferris use ErrorFerris::*; + use ErrorButtons::*; let ferris = match self.error_state.ferris { - Oops => &self.img.oops, + Happy => &self.img.happy, + Oops => &self.img.oops, Error => &self.img.error, Panic => &self.img.panic, }; @@ -669,12 +709,23 @@ impl eframe::App for App { ui.add_sized([width, height], Label::new("--- Are you sure you want to quit? ---")); ui.add_sized([width, height], Label::new(text)) }, + ResetState => { + ui.add_sized([width, height], Label::new(format!("--- Gupax has encountered an error! ---\n{}", &self.error_state.msg))); + ui.add_sized([width, height], Label::new("Reset Gupax state? (Your settings)")) + }, + ResetNode => { + ui.add_sized([width, height], Label::new(format!("--- Gupax has encountered an error! ---\n{}", &self.error_state.msg))); + ui.add_sized([width, height], Label::new("Reset the manual node list?")) + }, _ => { - ui.add_sized([width, height], Label::new("--- Gupax has encountered an error! ---")); - ui.add_sized([width, height], Label::new(self.error_state.msg)) + match self.error_state.ferris { + Panic => ui.add_sized([width, height], Label::new("--- Gupax has encountered an un-recoverable error! ---")), + Happy => ui.add_sized([width, height], Label::new("--- Success! ---")), + _ => 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 @@ -693,8 +744,47 @@ impl eframe::App for App { } if ui.add_sized([width, height/2.0], egui::Button::new("Quit")).clicked() { exit(0); } }, + // This code handles the [state.toml/node.toml] resetting, [panic!]'ing if it errors once more + // Another error after this either means an IO error or permission error, which Gupax can't fix. + // [Yes/No] buttons + ResetState => { + if ui.add_sized([width, height/2.0], egui::Button::new("Yes")).clicked() { + match reset_state() { + Ok(_) => { + match State::get() { + Ok(s) => { + self.state = s; + self.og = Arc::new(Mutex::new(self.state.clone())); + self.error_state.set(true, "State read OK", ErrorFerris::Happy, ErrorButtons::Okay); + }, + Err(e) => self.error_state.set(true, format!("State read fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + } + }, + Err(e) => self.error_state.set(true, format!("State reset fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + }; + } + if esc || ui.add_sized([width, height/2.0], egui::Button::new("No")).clicked() { self.error_state = ErrorState::new() } + }, + ResetNode => { + if ui.add_sized([width, height/2.0], egui::Button::new("Yes")).clicked() { + match reset_nodes() { + Ok(_) => { + match Node::get() { + Ok(s) => { + self.node_vec = s; + self.og_node_vec = self.node_vec.clone(); + self.error_state.set(true, "Node read OK", ErrorFerris::Happy, ErrorButtons::Okay); + }, + Err(e) => self.error_state.set(true, format!("Node read fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + } + }, + Err(e) => self.error_state.set(true, format!("Node reset fail: {}", e), ErrorFerris::Panic, ErrorButtons::Quit), + }; + } + if esc || ui.add_sized([width, height/2.0], egui::Button::new("No")).clicked() { self.error_state = ErrorState::new() } + }, 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); }, + Quit => if ui.add_sized([width, height], egui::Button::new("Quit")).clicked() { exit(1); }, } })}); return @@ -777,13 +867,21 @@ impl eframe::App for App { self.node_vec = self.og_node_vec.clone(); } if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { - let mut og = self.og.lock().unwrap(); - og.gupax = self.state.gupax.clone(); - og.p2pool = self.state.p2pool.clone(); - og.xmrig = self.state.xmrig.clone(); - self.og_node_vec = self.node_vec.clone(); - self.state.save(); - Node::save(&self.og_node_vec); + match self.state.save() { + Ok(_) => { + let mut og = self.og.lock().unwrap(); + og.gupax = self.state.gupax.clone(); + og.p2pool = self.state.p2pool.clone(); + og.xmrig = self.state.xmrig.clone(); + }, + Err(e) => { + self.error_state.set(true, format!("State file: {}", e), ErrorFerris::Error, ErrorButtons::Okay); + }, + }; + match Node::save(&self.og_node_vec) { + Ok(_) => self.og_node_vec = self.node_vec.clone(), + Err(e) => self.error_state.set(true, format!("Node list: {}", e), ErrorFerris::Error, ErrorButtons::Okay), + }; } }); @@ -872,7 +970,7 @@ impl eframe::App for App { ui.add_space(ui.available_height()/2.0); 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.hyperlink_to(format!("{} {}", GITHUB, "Made by hinto-janaiyo"), "https://gupax.io"); ui.label("egui is licensed under MIT & Apache-2.0"); ui.label("Gupax, P2Pool, and XMRig are licensed under GPLv3"); }); diff --git a/src/node.rs b/src/node.rs index f714a1e..bf447e0 100644 --- a/src/node.rs +++ b/src/node.rs @@ -27,8 +27,6 @@ use log::*; // header::{HeaderValue,LOCATION}, //}; -use reqwest::blocking::ClientBuilder; - //---------------------------------------------------------------------------------------------------- Node list // Community Monerod nodes. All of these have ZMQ on 18083. // Adding/removing nodes will need changes to pretty diff --git a/src/p2pool.rs b/src/p2pool.rs index 363d1ab..3134156 100644 --- a/src/p2pool.rs +++ b/src/p2pool.rs @@ -332,7 +332,7 @@ impl P2pool { let text = format!("{}\n Currently selected node: {}. {}\n Current amount of nodes: {}/1000", text, self.selected_index, self.selected_name, node_vec_len); // If the node already exists, show [Save] and mutate the already existing node if exists { - ui.set_enabled(save_diff); + ui.set_enabled(!incorrect_input && save_diff); if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() { let node = Node { ip: self.ip.clone(),