mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-11-16 15:27:46 +00:00
Status Submenu: add [GupaxP2poolApi] to [disk.rs], add to [App]
This commit is contained in:
parent
3175824a2b
commit
2846441049
4 changed files with 276 additions and 12 deletions
|
@ -482,7 +482,7 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to
|
|||
|
||||
The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x.
|
||||
|
||||
There are `21` unit tests throughout the codebase files, you should probably run:
|
||||
There are `24` unit tests throughout the codebase files, you should probably run:
|
||||
```
|
||||
cargo test
|
||||
```
|
||||
|
|
236
src/disk.rs
236
src/disk.rs
|
@ -42,6 +42,7 @@ use serde::{Serialize,Deserialize};
|
|||
use figment::Figment;
|
||||
use figment::providers::{Format,Toml};
|
||||
use crate::{
|
||||
human::*,
|
||||
constants::*,
|
||||
gupax::Ratio,
|
||||
Tab,
|
||||
|
@ -59,6 +60,37 @@ const DIRECTORY: &str = "Gupax/";
|
|||
#[cfg(target_os = "linux")]
|
||||
const DIRECTORY: &str = "gupax/";
|
||||
|
||||
// File names
|
||||
pub const STATE_TOML: &str = "state.toml";
|
||||
pub const NODE_TOML: &str = "node.toml";
|
||||
pub const POOL_TOML: &str = "pool.toml";
|
||||
|
||||
// P2Pool API
|
||||
// Lives within the Gupax OS data directory.
|
||||
// ~/.local/share/gupax/p2pool/
|
||||
// ├─ payout // Raw log lines of payouts received
|
||||
// ├─ xmr // Raw log lines of XMR mined
|
||||
// ├─ block // Raw log lines of actual blocks found
|
||||
// ├─ total_payout // Single [u128] representing total payouts
|
||||
// ├─ total_xmr // Single [u128] representing total XMR mined in atomic units
|
||||
// ├─ total_block // Single [u128] representing total blocks foundpub const GUPAX_P2POOL_API_: &str = "state.toml";
|
||||
#[cfg(target_os = "windows")]
|
||||
pub const GUPAX_P2POOL_API_DIRECTORY: &str = r"p2pool\";
|
||||
#[cfg(target_family = "unix")]
|
||||
pub const GUPAX_P2POOL_API_DIRECTORY: &str = "p2pool/";
|
||||
pub const GUPAX_P2POOL_API_PAYOUT: &str = "payout";
|
||||
pub const GUPAX_P2POOL_API_BLOCK: &str = "block";
|
||||
pub const GUPAX_P2POOL_API_TOTAL_PAYOUT: &str = "total_payout";
|
||||
pub const GUPAX_P2POOL_API_TOTAL_XMR: &str = "total_xmr";
|
||||
pub const GUPAX_P2POOL_API_TOTAL_BLOCK: &str = "total_block";
|
||||
pub const GUPAX_P2POOL_API_FILE_ARRAY: [&str; 5] = [
|
||||
GUPAX_P2POOL_API_PAYOUT,
|
||||
GUPAX_P2POOL_API_BLOCK,
|
||||
GUPAX_P2POOL_API_TOTAL_PAYOUT,
|
||||
GUPAX_P2POOL_API_TOTAL_XMR,
|
||||
GUPAX_P2POOL_API_TOTAL_BLOCK,
|
||||
];
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub const DEFAULT_P2POOL_PATH: &str = r"P2Pool\p2pool.exe";
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -96,20 +128,37 @@ pub fn get_gupax_data_path() -> Result<PathBuf, TomlError> {
|
|||
path.push(DIRECTORY);
|
||||
info!("OS | Data path ... {}", path.display());
|
||||
create_gupax_dir(&path)?;
|
||||
let mut gupax_p2pool_dir = path.clone();
|
||||
gupax_p2pool_dir.push(GUPAX_P2POOL_API_DIRECTORY);
|
||||
create_gupax_p2pool_dir(&gupax_p2pool_dir)?;
|
||||
Ok(path)
|
||||
},
|
||||
None => { error!("OS | Data path ... FAIL"); Err(TomlError::Path(PATH_ERROR.to_string())) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gupax_p2pool_path(os_data_path: &PathBuf) -> PathBuf {
|
||||
let mut gupax_p2pool_dir = os_data_path.clone();
|
||||
gupax_p2pool_dir.push(GUPAX_P2POOL_API_DIRECTORY);
|
||||
gupax_p2pool_dir
|
||||
}
|
||||
|
||||
pub fn create_gupax_dir(path: &PathBuf) -> Result<(), TomlError> {
|
||||
// Create directory
|
||||
// Create Gupax directory
|
||||
match fs::create_dir_all(path) {
|
||||
Ok(_) => { info!("OS | Create data path ... OK"); Ok(()) },
|
||||
Err(e) => { error!("OS | Create data path ... FAIL ... {}", e); Err(TomlError::Io(e)) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_gupax_p2pool_dir(path: &PathBuf) -> Result<(), TomlError> {
|
||||
// Create Gupax directory
|
||||
match fs::create_dir_all(path) {
|
||||
Ok(_) => { info!("OS | Create Gupax-P2Pool API path ... OK"); Ok(()) },
|
||||
Err(e) => { error!("OS | Create Gupax-P2Pool API path ... FAIL ... {}", e); Err(TomlError::Io(e)) },
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a [File] path to a [String]
|
||||
pub fn read_to_string(file: File, path: &PathBuf) -> Result<String, TomlError> {
|
||||
match fs::read_to_string(path) {
|
||||
|
@ -511,6 +560,138 @@ impl Pool {
|
|||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Gupax-P2Pool API
|
||||
#[derive(Clone,Eq,PartialEq,Debug)]
|
||||
pub struct GupaxP2poolApi {
|
||||
pub payout: HumanNumber,
|
||||
pub xmr: HumanNumber,
|
||||
pub block: HumanNumber,
|
||||
pub int_payout: u128,
|
||||
pub int_xmr: u128,
|
||||
pub int_block: u128,
|
||||
pub log_payout: String,
|
||||
pub log_block: String,
|
||||
pub path_int_payout: PathBuf,
|
||||
pub path_int_xmr: PathBuf,
|
||||
pub path_int_block: PathBuf,
|
||||
pub path_log_payout: PathBuf,
|
||||
pub path_log_block: PathBuf,
|
||||
}
|
||||
|
||||
impl Default for GupaxP2poolApi { fn default() -> Self { Self::new() } }
|
||||
|
||||
impl GupaxP2poolApi {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
payout: HumanNumber::unknown(),
|
||||
xmr: HumanNumber::unknown(),
|
||||
block: HumanNumber::unknown(),
|
||||
int_payout: 0,
|
||||
int_xmr: 0,
|
||||
int_block: 0,
|
||||
log_payout: String::new(),
|
||||
log_block: String::new(),
|
||||
path_int_payout: PathBuf::new(),
|
||||
path_int_xmr: PathBuf::new(),
|
||||
path_int_block: PathBuf::new(),
|
||||
path_log_payout: PathBuf::new(),
|
||||
path_log_block: PathBuf::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fill_paths(&mut self, gupax_p2pool_dir: &PathBuf) {
|
||||
let mut path_int_payout = gupax_p2pool_dir.clone();
|
||||
let mut path_int_xmr = gupax_p2pool_dir.clone();
|
||||
let mut path_int_block = gupax_p2pool_dir.clone();
|
||||
let mut path_log_payout = gupax_p2pool_dir.clone();
|
||||
let mut path_log_block = gupax_p2pool_dir.clone();
|
||||
path_int_payout.push(GUPAX_P2POOL_API_TOTAL_PAYOUT);
|
||||
path_int_xmr.push(GUPAX_P2POOL_API_TOTAL_XMR);
|
||||
path_int_block.push(GUPAX_P2POOL_API_TOTAL_BLOCK);
|
||||
path_log_payout.push(GUPAX_P2POOL_API_PAYOUT);
|
||||
path_log_block.push(GUPAX_P2POOL_API_BLOCK);
|
||||
*self = Self {
|
||||
path_int_payout,
|
||||
path_int_xmr,
|
||||
path_int_block,
|
||||
path_log_payout,
|
||||
path_log_block,
|
||||
..std::mem::take(self)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn create_all_files(gupax_p2pool_dir: &PathBuf) -> Result<(), TomlError> {
|
||||
use std::io::Write;
|
||||
for file in GUPAX_P2POOL_API_FILE_ARRAY {
|
||||
let mut path = gupax_p2pool_dir.clone();
|
||||
path.push(file);
|
||||
if path.exists() {
|
||||
info!("GupaxP2poolApi | [{}] already exists, skipping...", path.display());
|
||||
continue
|
||||
}
|
||||
match std::fs::File::create(&path) {
|
||||
Ok(mut f) => {
|
||||
match file {
|
||||
GUPAX_P2POOL_API_TOTAL_PAYOUT|GUPAX_P2POOL_API_TOTAL_XMR|GUPAX_P2POOL_API_TOTAL_BLOCK => f.write_all(b"0")?,
|
||||
_ => (),
|
||||
}
|
||||
info!("GupaxP2poolApi | [{}] create ... OK", path.display());
|
||||
},
|
||||
Err(e) => { warn!("GupaxP2poolApi | [{}] create ... FAIL: {}", path.display(), e); return Err(TomlError::Io(e)) },
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_all_files_and_update(&mut self) -> Result<(), TomlError> {
|
||||
let int_payout = match read_to_string(File::IntPayout, &self.path_int_payout)?.as_str().parse::<u128>() {
|
||||
Ok(o) => o,
|
||||
Err(e) => { warn!("GupaxP2poolApi | [int_payout] parse error: {}", e); return Err(TomlError::Parse("int_payout")) }
|
||||
};
|
||||
let int_xmr = match read_to_string(File::IntXmr, &self.path_int_xmr)?.as_str().parse::<u128>() {
|
||||
Ok(o) => o,
|
||||
Err(e) => { warn!("GupaxP2poolApi | [int_xmr] parse error: {}", e); return Err(TomlError::Parse("int_xmr")) }
|
||||
};
|
||||
let int_block = match read_to_string(File::IntBlock, &self.path_int_block)?.as_str().parse::<u128>() {
|
||||
Ok(o) => o,
|
||||
Err(e) => { warn!("GupaxP2poolApi | [int_block] parse error: {}", e); return Err(TomlError::Parse("int_block")) }
|
||||
};
|
||||
let payout = HumanNumber::from_u128(int_payout);
|
||||
let xmr = HumanNumber::from_u128(int_xmr);
|
||||
let block = HumanNumber::from_u128(int_block);
|
||||
let log_payout = read_to_string(File::LogPayout, &self.path_log_payout)?;
|
||||
let log_block = read_to_string(File::LogBlock, &self.path_log_block)?;
|
||||
*self = Self {
|
||||
payout,
|
||||
xmr,
|
||||
block,
|
||||
int_payout,
|
||||
int_xmr,
|
||||
int_block,
|
||||
log_payout,
|
||||
log_block,
|
||||
..std::mem::take(self)
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_to_all_files(&self) -> Result<(), TomlError> {
|
||||
Self::save(&self.int_payout.to_string(), &self.path_int_payout)?;
|
||||
Self::save(&self.int_xmr.to_string(), &self.path_int_xmr)?;
|
||||
Self::save(&self.int_block.to_string(), &self.path_int_block)?;
|
||||
Self::save(&self.log_payout, &self.path_log_payout)?;
|
||||
Self::save(&self.log_block, &self.path_log_block)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save(string: &str, path: &PathBuf) -> Result<(), TomlError> {
|
||||
match fs::write(path, string) {
|
||||
Ok(_) => { info!("GupaxP2poolApi | Save [{}] ... OK", path.display()); Ok(()) },
|
||||
Err(e) => { error!("GupaxP2poolApi | Save [{}] ... FAIL: {}", path.display(), e); Err(TomlError::Io(e)) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Custom Error [TomlError]
|
||||
#[derive(Debug)]
|
||||
pub enum TomlError {
|
||||
|
@ -553,9 +734,17 @@ impl From<std::fmt::Error> for TomlError {
|
|||
//---------------------------------------------------------------------------------------------------- [File] Enum (for matching which file)
|
||||
#[derive(Clone,Copy,Eq,PartialEq,Debug,Deserialize,Serialize)]
|
||||
pub enum File {
|
||||
State, // state.toml -> Gupax state
|
||||
Node, // node.toml -> P2Pool manual node selector
|
||||
Pool, // pool.toml -> XMRig manual pool selector
|
||||
// State files
|
||||
State, // state.toml | Gupax state
|
||||
Node, // node.toml | P2Pool manual node selector
|
||||
Pool, // pool.toml | XMRig manual pool selector
|
||||
|
||||
// Gupax-P2Pool API
|
||||
LogPayout, // payout | Raw log lines of P2Pool payouts received
|
||||
LogBlock, // block | Raw log lines of actual blocks found via P2Pool
|
||||
IntPayout, // total_payout | Single [u128] representing total payouts
|
||||
IntXmr, // total_xmr | Single [u128] representing total XMR mined in atomic units
|
||||
IntBlock, // total_block | Single [u128] representing total blocks found
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- [Node] Struct
|
||||
|
@ -973,4 +1162,43 @@ mod test {
|
|||
assert!(!merged_state.contains("SETTING_THAT_DOESNT_EXIST_ANYMORE"));
|
||||
assert!(merged_state.contains("44hintoFpuo3ugKfcqJvh5BmrsTRpnTasJmetKC4VXCt6QDtbHVuixdTtsm6Ptp7Y8haXnJ6j8Gj2dra8CKy5ewz7Vi9CYW"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_and_serde_gupax_p2pool_api() {
|
||||
use crate::disk::GupaxP2poolApi;
|
||||
|
||||
// Get API dir, fill paths.
|
||||
let mut api = GupaxP2poolApi::new();
|
||||
let mut path = crate::disk::get_gupax_data_path().unwrap();
|
||||
path.push(crate::disk::GUPAX_P2POOL_API_DIRECTORY);
|
||||
GupaxP2poolApi::fill_paths(&mut api, &path);
|
||||
println!("{:#?}", api);
|
||||
|
||||
// Create and read all files, write some fake data.
|
||||
GupaxP2poolApi::create_all_files(&path).unwrap();
|
||||
GupaxP2poolApi::read_all_files_and_update(&mut api).unwrap();
|
||||
api.int_payout = 1;
|
||||
api.int_xmr = 2;
|
||||
api.int_block = 3;
|
||||
api.log_payout = "P2Pool You received a payout of 0.000000000001 XMR in block 2642816".to_string();
|
||||
api.log_block = "client 127.0.0.1:51111 user asdf found a mainchain block at height 2642816, submitting it".to_string();
|
||||
GupaxP2poolApi::write_to_all_files(&api).unwrap();
|
||||
println!("AFTER WRITE: {:#?}", api);
|
||||
|
||||
// Reset internal stats, read file data.
|
||||
api.int_payout = 0;
|
||||
api.int_xmr = 0;
|
||||
api.int_block = 0;
|
||||
api.log_payout.clear();
|
||||
api.log_block.clear();
|
||||
GupaxP2poolApi::read_all_files_and_update(&mut api).unwrap();
|
||||
println!("AFTER READ: {:#?}", api);
|
||||
|
||||
// Assert that the file read mutated the internal struct correctly.
|
||||
assert_eq!(api.int_payout, 1);
|
||||
assert_eq!(api.int_xmr, 2);
|
||||
assert_eq!(api.int_block, 3);
|
||||
assert_eq!(api.log_payout, "P2Pool You received a payout of 0.000000000001 XMR in block 2642816");
|
||||
assert_eq!(api.log_block, "client 127.0.0.1:51111 user asdf found a mainchain block at height 2642816, submitting it");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,8 +53,6 @@ use sysinfo::{CpuExt,ProcessExt};
|
|||
use log::*;
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Constants
|
||||
// The locale numbers are formatting in is English, which looks like: [1,000]
|
||||
const LOCALE: num_format::Locale = num_format::Locale::en;
|
||||
// The max amount of bytes of process output we are willing to
|
||||
// hold in memory before it's too much and we need to reset.
|
||||
const MAX_GUI_OUTPUT_BYTES: usize = 500_000;
|
||||
|
@ -1486,6 +1484,7 @@ impl PrivP2poolPoolApi {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||
struct PoolStatistics {
|
||||
hashRate: u128,
|
||||
|
|
47
src/main.rs
47
src/main.rs
|
@ -129,6 +129,12 @@ pub struct App {
|
|||
sudo: Arc<Mutex<SudoState>>, // This is just a dummy struct on [Windows].
|
||||
// State from [--flags]
|
||||
no_startup: bool,
|
||||
// Gupax-P2Pool API
|
||||
// Gupax's P2Pool API (e.g: ~/.local/share/gupax/p2pool/)
|
||||
// This is a file-based API that contains data for permanent stats.
|
||||
// The below struct holds everything needed for it, the paths, the
|
||||
// actual stats, and all the functions needed to mutate them.
|
||||
gupax_p2pool_api: GupaxP2poolApi,
|
||||
// Static stuff
|
||||
pid: sysinfo::Pid, // Gupax's PID
|
||||
max_threads: usize, // Max amount of detected system threads
|
||||
|
@ -138,7 +144,8 @@ pub struct App {
|
|||
resolution: Vec2, // Frame resolution
|
||||
os: &'static str, // OS
|
||||
admin: bool, // Are we admin? (for Windows)
|
||||
os_data_path: PathBuf, // OS data path (e.g: ~/.local/share/gupax)
|
||||
os_data_path: PathBuf, // OS data path (e.g: ~/.local/share/gupax/)
|
||||
gupax_p2pool_api_path: PathBuf, // Gupax-P2Pool API path (e.g: ~/.local/share/gupax/p2pool/)
|
||||
state_path: PathBuf, // State file path
|
||||
node_path: PathBuf, // Node file path
|
||||
pool_path: PathBuf, // Pool file path
|
||||
|
@ -219,6 +226,7 @@ impl App {
|
|||
resizing: false,
|
||||
alpha: 0,
|
||||
no_startup: false,
|
||||
gupax_p2pool_api: GupaxP2poolApi::new(),
|
||||
pub_sys,
|
||||
pid,
|
||||
max_threads: num_cpus::get(),
|
||||
|
@ -229,6 +237,7 @@ impl App {
|
|||
resolution: Vec2::new(APP_DEFAULT_HEIGHT, APP_DEFAULT_WIDTH),
|
||||
os: OS,
|
||||
os_data_path: PathBuf::new(),
|
||||
gupax_p2pool_api_path: PathBuf::new(),
|
||||
state_path: PathBuf::new(),
|
||||
node_path: PathBuf::new(),
|
||||
pool_path: PathBuf::new(),
|
||||
|
@ -259,11 +268,11 @@ impl App {
|
|||
debug!("App Init | Setting TOML path...");
|
||||
// Set [*.toml] path
|
||||
app.state_path = app.os_data_path.clone();
|
||||
app.state_path.push("state.toml");
|
||||
app.state_path.push(STATE_TOML);
|
||||
app.node_path = app.os_data_path.clone();
|
||||
app.node_path.push("node.toml");
|
||||
app.node_path.push(NODE_TOML);
|
||||
app.pool_path = app.os_data_path.clone();
|
||||
app.pool_path.push("pool.toml");
|
||||
app.pool_path.push(POOL_TOML);
|
||||
|
||||
// Apply arg state
|
||||
// It's not safe to [--reset] if any of the previous variables
|
||||
|
@ -334,6 +343,34 @@ impl App {
|
|||
debug!("Pool Vec:");
|
||||
debug!("{:#?}", app.pool_vec);
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// Read [GupaxP2poolApi] disk files
|
||||
app.gupax_p2pool_api_path = crate::disk::get_gupax_p2pool_path(&app.os_data_path);
|
||||
app.gupax_p2pool_api.fill_paths(&app.gupax_p2pool_api_path);
|
||||
GupaxP2poolApi::create_all_files(&app.gupax_p2pool_api_path);
|
||||
debug!("App Init | Reading Gupax-P2Pool API files...");
|
||||
match app.gupax_p2pool_api.read_all_files_and_update() {
|
||||
Ok(_) => {
|
||||
info!(
|
||||
"GupaxP2poolApi ... Payouts: {} | XMR (atomic-units): {} | Blocks: {}",
|
||||
app.gupax_p2pool_api.payout,
|
||||
app.gupax_p2pool_api.xmr,
|
||||
app.gupax_p2pool_api.block,
|
||||
);
|
||||
},
|
||||
Err(err) => {
|
||||
error!("GupaxP2poolApi ... {}", err);
|
||||
match err {
|
||||
Io(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
Path(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
Serialize(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
Deserialize(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
Format(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
Merge(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Error, ErrorButtons::ResetState),
|
||||
Parse(e) => app.error_state.set(format!("GupaxP2poolApi: {}", e), ErrorFerris::Panic, ErrorButtons::Quit),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
let mut og = app.og.lock().unwrap(); // Lock [og]
|
||||
|
@ -930,7 +967,7 @@ fn main() {
|
|||
Ok(_) => info!("Temporary folder cleanup ... OK"),
|
||||
Err(e) => warn!("Could not cleanup [gupax_tmp] folders: {}", e),
|
||||
}
|
||||
info!("Init ... DONE");
|
||||
info!("/*************************************/ Init ... OK /*************************************/");
|
||||
eframe::run_native(&app.name_version.clone(), options, Box::new(|cc| Box::new(App::cc(cc, app))),);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue