disk: add [ErrorState] handling for disk errors

This commit is contained in:
hinto-janaiyo 2022-11-19 21:20:28 -05:00
parent e8c41fceb3
commit 7a5fe24276
No known key found for this signature in database
GPG key ID: B1C5A64B80691E45
9 changed files with 209 additions and 217 deletions

101
Cargo.lock generated
View file

@ -1275,15 +1275,6 @@ dependencies = [
"bytemuck", "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]] [[package]]
name = "enum-ordinalize" name = "enum-ordinalize"
version = "3.1.12" version = "3.1.12"
@ -1920,7 +1911,6 @@ dependencies = [
"openssl", "openssl",
"rand 0.8.5", "rand 0.8.5",
"regex", "regex",
"reqwest",
"rfd", "rfd",
"rusqlite", "rusqlite",
"serde", "serde",
@ -1937,25 +1927,6 @@ dependencies = [
"zip", "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]] [[package]]
name = "half" name = "half"
version = "2.1.0" version = "2.1.0"
@ -2106,7 +2077,6 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2",
"http", "http",
"http-body", "http-body",
"httparse", "httparse",
@ -2223,12 +2193,6 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "ipnet"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -2438,12 +2402,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "mime"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@ -3339,43 +3297,6 @@ dependencies = [
"winapi", "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]] [[package]]
name = "retain_mut" name = "retain_mut"
version = "0.1.9" version = "0.1.9"
@ -3661,18 +3582,6 @@ dependencies = [
"serde", "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]] [[package]]
name = "serde_with" name = "serde_with"
version = "1.14.0" version = "1.14.0"
@ -4275,7 +4184,6 @@ dependencies = [
"futures-sink", "futures-sink",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]
@ -5439,15 +5347,6 @@ dependencies = [
"x11-dl", "x11-dl",
] ]
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winres" name = "winres"
version = "0.1.12" version = "0.1.12"

View file

@ -39,7 +39,7 @@ num_cpus = "1.13.1"
num-format = "0.4.0" num-format = "0.4.0"
rand = "0.8.5" rand = "0.8.5"
regex = "1.6.0" regex = "1.6.0"
reqwest = { version = "0.11.12", features = ["blocking", "json"] } #reqwest = { version = "0.11.12", features = ["blocking", "json"] }
rfd = "0.10.0" rfd = "0.10.0"
rusqlite = { version = "0.28.0", features = ["bundled"] } rusqlite = { version = "0.28.0", features = ["bundled"] }
serde = { version = "1.0.145", features = ["rc", "derive"] } serde = { version = "1.0.145", features = ["rc", "derive"] }

BIN
images/ferris/happy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -85,7 +85,7 @@ r#"Use advanced settings:
- P2Pool Main/Mini selection - P2Pool Main/Mini selection
- Out/In peer setting - Out/In peer setting
- Log level 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_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_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_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 // CLI argument messages
pub const ARG_HELP: &'static str = pub const ARG_HELP: &'static str =
r#"USAGE: ./gupax [--flags] r#"USAGE: ./gupax [--flag]
-h | --help Print this help message --help Print this help message
-v | --version Print version and build info --version Print version and build info
-l | --node-list Print the manual node list --state Print Gupax state
-s | --state Print Gupax state --nodes Print the manual node list
-n | --no-startup Disable all auto-startup settings for this instance --no-startup Disable all auto-startup settings for this instance
-r | --reset Reset all Gupax state and the manual node list --reset-state Reset all Gupax state (your settings)
-f | --ferris Print an extremely cute crab --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 To view more detailed console debug information, start Gupax with
the environment variable [RUST_LOG] set to a log level like so: the environment variable [RUST_LOG] set to a log level like so:

View file

@ -179,7 +179,7 @@ impl State {
} }
// Convert [String] to [State] // Convert [String] to [State]
pub fn from_string(string: String) -> Result<Self, TomlError> { pub fn from_string(string: &String) -> Result<Self, TomlError> {
match toml::de::from_str(&string) { match toml::de::from_str(&string) {
Ok(state) => { Ok(state) => {
info!("State | Parse ... OK"); info!("State | Parse ... OK");
@ -187,7 +187,7 @@ impl State {
Ok(state) Ok(state)
} }
Err(err) => { Err(err) => {
error!("State | String -> State ... FAIL ... {}", err); warn!("State | String -> State ... FAIL ... {}", err);
Err(TomlError::Deserialize(err)) Err(TomlError::Deserialize(err))
}, },
} }
@ -207,11 +207,20 @@ impl State {
// Create // Create
_ => { _ => {
Self::create_new()?; Self::create_new()?;
read_to_string(file, &path)? match read_to_string(file, &path) {
Ok(s) => s,
Err(e) => return Err(e),
}
}, },
}; };
// Deserialize // Deserialize, attempt merge if failed
Self::from_string(string) match Self::from_string(&string) {
Ok(s) => Ok(s),
Err(e) => {
warn!("State | Attempting merge...");
Self::merge(string)
},
}
} }
// Completely overwrite current [state.toml] // 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. // leaving behind old keys+values and updating [default] with old valid ones.
// Automatically overwrite current file. // Automatically overwrite current file.
pub fn merge(old: &Self) -> Result<Self, TomlError> { pub fn merge(old: String) -> Result<Self, TomlError> {
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)) },
};
let default = match toml::ser::to_string(&Self::new()) { let default = match toml::ser::to_string(&Self::new()) {
Ok(string) => { info!("Default TOML parse ... OK"); string }, Ok(string) => { info!("State | Default TOML parse ... OK"); string },
Err(err) => { error!("Couldn't parse default TOML into string"); return Err(TomlError::Serialize(err)) }, 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() { let mut new: Self = match Figment::new().merge(Toml::string(&old)).merge(Toml::string(&default)).extract() {
Ok(new) => { info!("TOML merge ... OK"); new }, Ok(new) => { info!("State | TOML merge ... OK"); new },
Err(err) => { error!("Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) }, Err(err) => { error!("State | Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) },
}; };
// Attempt save // Attempt save
Self::save(&mut new)?; Self::save(&mut new)?;
@ -298,7 +302,7 @@ impl Node {
} }
// Convert [String] to [Node] Vec // Convert [String] to [Node] Vec
pub fn from_string(string: String) -> Result<Vec<(String, Self)>, TomlError> { pub fn from_string_to_vec(string: &String) -> Result<Vec<(String, Self)>, TomlError> {
let nodes: toml::map::Map<String, toml::Value> = match toml::de::from_str(&string) { let nodes: toml::map::Map<String, toml::Value> = match toml::de::from_str(&string) {
Ok(map) => { Ok(map) => {
info!("Node | Parse ... OK"); info!("Node | Parse ... OK");
@ -312,7 +316,6 @@ impl Node {
let size = nodes.keys().len(); let size = nodes.keys().len();
let mut vec = Vec::with_capacity(size); let mut vec = Vec::with_capacity(size);
for (key, values) in nodes.iter() { for (key, values) in nodes.iter() {
// println!("{:#?}", values.get("ip")); std::process::exit(0);
let node = Node { let node = Node {
ip: values.get("ip").unwrap().as_str().unwrap().to_string(), ip: values.get("ip").unwrap().as_str().unwrap().to_string(),
rpc: values.get("rpc").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)? read_to_string(file, &path)?
}, },
}; };
// Deserialize // Deserialize, attempt merge if failed
Self::from_string(string) Self::from_string_to_vec(&string)
} }
// Completely overwrite current [node.toml] // Completely overwrite current [node.toml]
@ -380,26 +383,19 @@ impl Node {
let string = Self::to_string(vec); let string = Self::to_string(vec);
match fs::write(path, string) { match fs::write(path, string) {
Ok(_) => { info!("TOML save ... OK"); Ok(()) }, 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, // pub fn merge(old: &String) -> Result<Self, TomlError> {
// // leaving behind old keys+values and updating [default] with old valid ones. // info!("Node | Starting TOML merge...");
// // Automatically overwrite current file.
// pub fn merge(old: &Self) -> Result<Self, TomlError> {
// 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)) },
// };
// let default = match toml::ser::to_string(&Self::new()) { // let default = match toml::ser::to_string(&Self::new()) {
// Ok(string) => { info!("Default TOML parse ... OK"); string }, // Ok(string) => { info!("Node | Default TOML parse ... OK"); string },
// Err(err) => { error!("Couldn't parse default TOML into string"); return Err(TomlError::Serialize(err)) }, // 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() { // let mut new: Self = match Figment::new().merge(Toml::string(&old)).merge(Toml::string(&default)).extract() {
// Ok(new) => { info!("TOML merge ... OK"); new }, // Ok(new) => { info!("Node | TOML merge ... OK"); new },
// Err(err) => { error!("Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) }, // Err(err) => { error!("Node | Couldn't merge default + old TOML"); return Err(TomlError::Merge(err)) },
// }; // };
// // Attempt save // // Attempt save
// Self::save(&mut new)?; // Self::save(&mut new)?;
@ -408,15 +404,24 @@ impl Node {
} }
//---------------------------------------------------------------------------------------------------- Custom Error [TomlError] //---------------------------------------------------------------------------------------------------- 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 { 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::*; use TomlError::*;
match self { match self {
Io(err) => write!(f, "{}: {} | {}", ERROR, self, err), Io(err) => write!(f, "{}: IO | {}", ERROR, err),
Path(err) => write!(f, "{}: {} | {}", ERROR, self, err), Path(err) => write!(f, "{}: Path | {}", ERROR, err),
Serialize(err) => write!(f, "{}: {} | {}", ERROR, self, err), Serialize(err) => write!(f, "{}: Serialize | {}", ERROR, err),
Deserialize(err) => write!(f, "{}: {} | {}", ERROR, self, err), Deserialize(err) => write!(f, "{}: Deserialize | {}", ERROR, err),
Merge(err) => write!(f, "{}: {} | {}", ERROR, self, 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")] #[cfg(target_family = "unix")]
pub const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig"; 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) //---------------------------------------------------------------------------------------------------- [File] Enum (for matching which file)
#[derive(Clone,Copy,Eq,PartialEq,Debug,Deserialize,Serialize)] #[derive(Clone,Copy,Eq,PartialEq,Debug,Deserialize,Serialize)]
pub enum File { pub enum File {

View file

@ -17,6 +17,7 @@
// Some images of ferris in byte form for error messages, etc // 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_OOPS: &[u8] = include_bytes!("../images/ferris/oops.png");
pub const FERRIS_ERROR: &[u8] = include_bytes!("../images/ferris/error.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 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. // 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. // 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 // The ANSI codes were generated with [https://docs.rs/ansipix], but there is no reason to include the library and

View file

@ -86,7 +86,6 @@ pub struct App {
xmrig: bool, // Is xmrig online? xmrig: bool, // Is xmrig online?
// State from [--flags] // State from [--flags]
no_startup: bool, no_startup: bool,
reset: bool,
// Static stuff // Static stuff
now: Instant, // Internal timer now: Instant, // Internal timer
exe: String, // Path for [Gupax] binary exe: String, // Path for [Gupax] binary
@ -128,7 +127,6 @@ impl App {
p2pool: false, p2pool: false,
xmrig: false, xmrig: false,
no_startup: false, no_startup: false,
reset: false,
now: Instant::now(), now: Instant::now(),
exe: "".to_string(), exe: "".to_string(),
dir: "".to_string(), dir: "".to_string(),
@ -157,18 +155,42 @@ impl App {
Ok(dir) => dir, Ok(dir) => dir,
Err(err) => { panic_main(err.to_string()); exit(1); }, Err(err) => { panic_main(err.to_string()); exit(1); },
}; };
// Read disk state if no [--reset] arg // Read disk state
if app.reset == false { use TomlError::*;
app.og = match State::get() { app.state = match State::get() {
Ok(toml) => Arc::new(Mutex::new(toml)), Ok(toml) => toml,
Err(err) => { panic_main(err.to_string()); exit(1); }, Err(err) => {
}; error!("State ... {}", err);
} match err {
let mut og = app.og.lock().unwrap(); // Lock [og] Io(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
app.state = og.clone(); Path(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
// Get node list Serialize(e) => app.error_state.set(true, format!("State file: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
app.og_node_vec = Node::get().unwrap(); 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(); app.node_vec = app.og_node_vec.clone();
let mut og = app.og.lock().unwrap(); // Lock [og]
// Handle max threads // Handle max threads
og.xmrig.max_threads = num_cpus::get(); og.xmrig.max_threads = num_cpus::get();
let current = og.xmrig.current_threads; let current = og.xmrig.current_threads;
@ -222,7 +244,7 @@ impl Default for Tab {
//---------------------------------------------------------------------------------------------------- [ErrorState] struct //---------------------------------------------------------------------------------------------------- [ErrorState] struct
pub struct ErrorState { pub struct ErrorState {
error: bool, // Is there an error? 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? ferris: ErrorFerris, // Which ferris to display?
buttons: ErrorButtons, // Which buttons to display? buttons: ErrorButtons, // Which buttons to display?
} }
@ -231,17 +253,17 @@ impl ErrorState {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
error: false, error: false,
msg: "Unknown Error", msg: "Unknown Error".to_string(),
ferris: ErrorFerris::Oops, ferris: ErrorFerris::Oops,
buttons: ErrorButtons::Okay, buttons: ErrorButtons::Okay,
} }
} }
// Convenience function to set the [App] error state // 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<String>, ferris: ErrorFerris, buttons: ErrorButtons) {
*self = Self { *self = Self {
error, error,
msg, msg: msg.into(),
ferris, ferris,
buttons, buttons,
}; };
@ -253,12 +275,15 @@ impl ErrorState {
pub enum ErrorButtons { pub enum ErrorButtons {
YesNo, YesNo,
StayQuit, StayQuit,
ResetState,
ResetNode,
Okay, Okay,
Quit, Quit,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum ErrorFerris { pub enum ErrorFerris {
Happy,
Oops, Oops,
Error, Error,
Panic, Panic,
@ -267,6 +292,7 @@ pub enum ErrorFerris {
//---------------------------------------------------------------------------------------------------- [Images] struct //---------------------------------------------------------------------------------------------------- [Images] struct
struct Images { struct Images {
banner: RetainedImage, banner: RetainedImage,
happy: RetainedImage,
oops: RetainedImage, oops: RetainedImage,
error: RetainedImage, error: RetainedImage,
panic: RetainedImage, panic: RetainedImage,
@ -276,6 +302,7 @@ impl Images {
fn new() -> Self { fn new() -> Self {
Self { Self {
banner: RetainedImage::from_image_bytes("banner.png", BYTES_BANNER).unwrap(), 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(), oops: RetainedImage::from_image_bytes("oops.png", FERRIS_OOPS).unwrap(),
error: RetainedImage::from_image_bytes("error.png", FERRIS_ERROR).unwrap(), error: RetainedImage::from_image_bytes("error.png", FERRIS_ERROR).unwrap(),
panic: RetainedImage::from_image_bytes("panic.png", FERRIS_PANIC).unwrap(), panic: RetainedImage::from_image_bytes("panic.png", FERRIS_PANIC).unwrap(),
@ -388,6 +415,9 @@ fn init_auto(app: &App) {
if app.no_startup { if app.no_startup {
info!("[--no-startup] flag passed, skipping init_auto()..."); info!("[--no-startup] flag passed, skipping init_auto()...");
return return
} else if app.error_state.error {
info!("App error detected, skipping init_auto()...");
return
} else { } else {
info!("Starting init_auto()..."); info!("Starting init_auto()...");
} }
@ -442,17 +472,31 @@ fn init_auto(app: &App) {
} }
} }
fn reset() { fn reset_state() -> Result<(), TomlError> {
let mut code = 0;
info!("Resetting [state.toml]..."); info!("Resetting [state.toml]...");
match State::create_new() { match State::create_new() {
Ok(_) => info!("Resetting [state.toml] ... OK"), Ok(_) => { info!("Resetting [state.toml] ... OK"); Ok(()) },
Err(e) => { error!("Resetting [state.toml] ... FAIL ... {}", e); code = 1; }, Err(e) => { error!("Resetting [state.toml] ... FAIL ... {}", e); Err(e) },
} }
}
fn reset_nodes() -> Result<(), TomlError> {
info!("Resetting [node.toml]..."); info!("Resetting [node.toml]...");
match Node::create_new() { match Node::create_new() {
Ok(_) => info!("Resetting [node.toml] ... OK"), Ok(_) => { info!("Resetting [node.toml] ... OK"); Ok(()) },
Err(e) => { error!("Resetting [node.toml] ... FAIL ... {}", e); code = 1; }, 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 { match code {
0 => println!("\nGupax files were reset successfully."), 0 => println!("\nGupax files were reset successfully."),
@ -469,23 +513,25 @@ fn parse_args(mut app: App) -> App {
// [help/version], exit early // [help/version], exit early
for arg in &args { for arg in &args {
match arg.as_str() { match arg.as_str() {
"-h"|"--help" => { println!("{}", ARG_HELP); exit(0); }, "--help" => { println!("{}", ARG_HELP); exit(0); },
"-v"|"--version" => { "--version" => {
println!("Gupax {} [OS: {}, Commit: {}]\n\n{}", GUPAX_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT); println!("Gupax {} [OS: {}, Commit: {}]\n\n{}", GUPAX_VERSION, OS_NAME, &COMMIT[..40], ARG_COPYRIGHT);
exit(0); exit(0);
}, },
"-f"|"--ferris" => { println!("{}", FERRIS_ANSI); exit(0); }, "--ferris" => { println!("{}", FERRIS_ANSI); exit(0); },
_ => (), _ => (),
} }
} }
// Everything else // Everything else
for arg in args { for arg in args {
match arg.as_str() { match arg.as_str() {
"-l"|"--node-list" => { info!("Printing node list..."); print_disk_file(File::Node); } "--nodes" => { info!("Printing node list..."); print_disk_file(File::Node); }
"-s"|"--state" => { info!("Printing state..."); print_disk_file(File::State); } "--state" => { info!("Printing state..."); print_disk_file(File::State); }
"-r"|"--reset" => { reset(); } "--reset-state" => if let Ok(()) = reset_state() { exit(0) } else { exit(1) },
"-n"|"--no-startup" => { app.no_startup = true; } "--reset-nodes" => if let Ok(()) = reset_nodes() { exit(0) } else { exit(1) },
_ => { eprintln!("[Gupax error] Invalid option: [{}]\nFor help, use: [--help]", arg); exit(1); }, "--reset-all" => reset(),
"--no-startup" => app.no_startup = true,
_ => { eprintln!("[Gupax error] Invalid option: [{}]\nFor help, use: [--help]", arg); exit(1); },
} }
} }
app app
@ -604,14 +650,6 @@ fn main() {
} }
impl eframe::App for 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 { fn on_close_event(&mut self) -> bool {
if self.state.gupax.ask_before_quit { if self.state.gupax.ask_before_quit {
self.error_state.set(true, "", ErrorFerris::Oops, ErrorButtons::StayQuit); self.error_state.set(true, "", ErrorFerris::Oops, ErrorButtons::StayQuit);
@ -652,8 +690,10 @@ impl eframe::App for App {
// Display ferris // Display ferris
use ErrorFerris::*; use ErrorFerris::*;
use ErrorButtons::*;
let ferris = match self.error_state.ferris { let ferris = match self.error_state.ferris {
Oops => &self.img.oops, Happy => &self.img.happy,
Oops => &self.img.oops,
Error => &self.img.error, Error => &self.img.error,
Panic => &self.img.panic, 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("--- Are you sure you want to quit? ---"));
ui.add_sized([width, height], Label::new(text)) 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! ---")); match self.error_state.ferris {
ui.add_sized([width, height], Label::new(self.error_state.msg)) 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(); let height = ui.available_height();
// Capture [Esc] key // 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); } 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(); }, 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 return
@ -777,13 +867,21 @@ impl eframe::App for App {
self.node_vec = self.og_node_vec.clone(); self.node_vec = self.og_node_vec.clone();
} }
if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() {
let mut og = self.og.lock().unwrap(); match self.state.save() {
og.gupax = self.state.gupax.clone(); Ok(_) => {
og.p2pool = self.state.p2pool.clone(); let mut og = self.og.lock().unwrap();
og.xmrig = self.state.xmrig.clone(); og.gupax = self.state.gupax.clone();
self.og_node_vec = self.node_vec.clone(); og.p2pool = self.state.p2pool.clone();
self.state.save(); og.xmrig = self.state.xmrig.clone();
Node::save(&self.og_node_vec); },
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.add_space(ui.available_height()/2.0);
ui.hyperlink_to("Powered by egui", "https://github.com/emilk/egui"); 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("egui is licensed under MIT & Apache-2.0");
ui.label("Gupax, P2Pool, and XMRig are licensed under GPLv3"); ui.label("Gupax, P2Pool, and XMRig are licensed under GPLv3");
}); });

View file

@ -27,8 +27,6 @@ use log::*;
// header::{HeaderValue,LOCATION}, // header::{HeaderValue,LOCATION},
//}; //};
use reqwest::blocking::ClientBuilder;
//---------------------------------------------------------------------------------------------------- Node list //---------------------------------------------------------------------------------------------------- Node list
// Community Monerod nodes. All of these have ZMQ on 18083. // Community Monerod nodes. All of these have ZMQ on 18083.
// Adding/removing nodes will need changes to pretty // Adding/removing nodes will need changes to pretty

View file

@ -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); 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 the node already exists, show [Save] and mutate the already existing node
if exists { 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() { if ui.add_sized([width, text_edit], Button::new("Save")).on_hover_text(text).clicked() {
let node = Node { let node = Node {
ip: self.ip.clone(), ip: self.ip.clone(),