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 0000000..84d84ad Binary files /dev/null and b/images/ferris/happy.png differ 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(),