From 2de7903d99e74f289250b535a0be79d0af3e6082 Mon Sep 17 00:00:00 2001
From: hinto-janaiyo <hinto.janaiyo@protonmail.com>
Date: Thu, 1 Dec 2022 23:13:53 -0500
Subject: [PATCH] helper: map xmrig/p2pool JSON API key/values to structs for
 serde

---
 Cargo.lock    |  46 +++++++++-------
 Cargo.toml    |   2 +-
 src/helper.rs | 146 ++++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 153 insertions(+), 41 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index a0e5c22..052c060 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -254,9 +254,9 @@ dependencies = [
 
 [[package]]
 name = "async-trait"
-version = "0.1.58"
+version = "0.1.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
+checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2728,9 +2728,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
 dependencies = [
  "cfg-if",
  "libc",
@@ -3359,18 +3359,18 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 
 [[package]]
 name = "serde"
-version = "1.0.147"
+version = "1.0.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.147"
+version = "1.0.148"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3442,9 +3442,9 @@ dependencies = [
 
 [[package]]
 name = "sha-1"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
+checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -3515,6 +3515,15 @@ dependencies = [
  "dirs",
 ]
 
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "signature"
 version = "1.6.4"
@@ -3675,9 +3684,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
 
 [[package]]
 name = "syn"
-version = "1.0.103"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3930,6 +3939,7 @@ dependencies = [
  "mio",
  "num_cpus",
  "pin-project-lite",
+ "signal-hook-registry",
  "socket2",
  "tokio-macros",
  "winapi",
@@ -3937,9 +3947,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-macros"
-version = "1.8.0"
+version = "1.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
+checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5209,9 +5219,9 @@ dependencies = [
 
 [[package]]
 name = "zeroize_derive"
-version = "1.3.2"
+version = "1.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
+checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5260,9 +5270,9 @@ dependencies = [
 
 [[package]]
 name = "zstd-sys"
-version = "2.0.3+zstd.1.5.2"
+version = "2.0.4+zstd.1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44ccf97612ac95f3ccb89b2d7346b345e52f1c3019be4984f0455fb4ba991f8a"
+checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0"
 dependencies = [
  "cc",
  "libc",
diff --git a/Cargo.toml b/Cargo.toml
index 3161fe5..8adf894 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,7 +45,7 @@ serde = { version = "1.0.145", features = ["rc", "derive"] }
 serde_json = "1.0"
 tls-api = "0.9.0"
 tls-api-native-tls = "0.9.0"
-tokio = { version = "1.21.2", features = ["rt", "time", "macros"] }
+tokio = { version = "1.21.2", features = ["rt", "time", "macros", "process"] }
 toml = { version = "0.5.9", features = ["preserve_order"] }
 tor-rtcompat = "0.7.0"
 walkdir = "2.3.2"
diff --git a/src/helper.rs b/src/helper.rs
index ac55c3b..9fd2385 100644
--- a/src/helper.rs
+++ b/src/helper.rs
@@ -48,14 +48,14 @@ use log::*;
 //---------------------------------------------------------------------------------------------------- [Helper] Struct
 // A meta struct holding all the data that gets processed in this thread
 pub struct Helper {
-	instant: Instant,      // Gupax start as an [Instant]
-	human_time: HumanTime, // Gupax uptime formatting for humans
-	p2pool: Process,       // P2Pool process state
-	xmrig: Process,        // XMRig process state
-	pub_api_p2pool: P2poolApi, // P2Pool API state
-	pub_api_xmrig: XmrigApi,   // XMRig API state
-//	priv_api_p2pool:
-//	priv_api_xmrig:
+	pub instant: Instant,      // Gupax start as an [Instant]
+	pub human_time: HumanTime, // Gupax uptime formatting for humans
+	pub p2pool: Process,       // P2Pool process state
+	pub xmrig: Process,        // XMRig process state
+	pub pub_api_p2pool: PubP2poolApi, // P2Pool API state (for GUI thread)
+	pub pub_api_xmrig: PubXmrigApi,   // XMRig API state (for GUI thread)
+	priv_api_p2pool: PrivP2poolApi, // For "watchdog" thread
+	priv_api_xmrig: PrivXmrigApi,   // For "watchdog" thread
 }
 
 // Impl found at the very bottom of this file.
@@ -195,31 +195,131 @@ impl std::fmt::Display for HumanTime {
 	}
 }
 
-//---------------------------------------------------------------------------------------------------- [P2poolApi]
-pub struct P2poolApi {
+//---------------------------------------------------------------------------------------------------- Public P2Pool API
+// GUI thread interfaces with this.
+pub struct PubP2poolApi {
 
 }
 
-impl P2poolApi {
+impl PubP2poolApi {
 	pub fn new() -> Self {
 		Self {
 		}
 	}
 }
 
-//---------------------------------------------------------------------------------------------------- [XmrigApi]
-pub struct XmrigApi {
+//---------------------------------------------------------------------------------------------------- Private P2Pool API
+// This is the data the "watchdog" threads mutate.
+// It matches directly to P2Pool's [local/stats] JSON API file (excluding a few stats).
+// P2Pool seems to initialize all stats at 0 (or 0.0), so no [Option] wrapper seems needed.
+#[derive(Debug, Serialize, Deserialize)]
+struct PrivP2poolApi {
+	hashrate_15m: u128,
+	hashrate_1h: u128,
+	hashrate_24h: u128,
+	shares_found: u128,
+	average_effort: f64,
+	current_effort: f64,
+	connections: u16, // No one will have more than 65535 connections... right?
+}
+
+impl PrivP2poolApi {
+	fn new() -> Self {
+		Self {
+			hashrate_15m: 0,
+			hashrate_1h: 0,
+			hashrate_24h: 0,
+			shares_found: 0,
+			average_effort: 0.0,
+			current_effort: 0.0,
+			connections: 0,
+		}
+	}
+}
+
+//---------------------------------------------------------------------------------------------------- Public XMRig API
+pub struct PubXmrigApi {
 
 }
 
-impl XmrigApi {
+impl PubXmrigApi {
 	pub fn new() -> Self {
 		Self {
 		}
 	}
 }
 
+//---------------------------------------------------------------------------------------------------- Private XMRig API
+// This matches to some JSON stats in the HTTP call [summary],
+// e.g: [wget -qO- localhost:18085/1/summary].
+// XMRig doesn't initialize stats at 0 (or 0.0) and instead opts for [null]
+// which means some elements need to be wrapped in an [Option] or else serde will [panic!].
+#[derive(Debug, Serialize, Deserialize)]
+struct PrivXmrigApi {
+	worker_id: String,
+	resources: Resources,
+	connection: Connection,
+	hashrate: Hashrate,
+}
+
+impl PrivXmrigApi {
+	fn new() -> Self {
+		Self {
+			worker_id: String::new(),
+			resources: Resources::new(),
+			connection: Connection::new(),
+			hashrate: Hashrate::new(),
+		}
+	}
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+struct Resources {
+	load_average: [Option<f32>; 3],
+}
+impl Resources {
+	fn new() -> Self {
+		Self {
+			load_average: [Some(0.0), Some(0.0), Some(0.0)],
+		}
+	}
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+struct Connection {
+	pool: String,
+	ping: u32,
+	diff: u128,
+	accepted: u128,
+	rejected: u128,
+}
+impl Connection {
+	fn new() -> Self {
+		Self {
+			pool: String::new(),
+			ping: 0,
+			diff: 0,
+			accepted: 0,
+			rejected: 0,
+		}
+	}
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+struct Hashrate {
+	total: [Option<f32>; 3],
+}
+impl Hashrate {
+	fn new() -> Self {
+		Self {
+			total: [Some(0.0), Some(0.0), Some(0.0)],
+		}
+	}
+}
+
 //---------------------------------------------------------------------------------------------------- [Helper]
+use tokio::io::{BufReader,AsyncBufReadExt};
+
 impl Helper {
 	pub fn new(instant: std::time::Instant) -> Self {
 		Self {
@@ -227,8 +327,10 @@ impl Helper {
 			human_time: HumanTime::into_human(instant.elapsed()),
 			p2pool: Process::new(ProcessName::P2pool, String::new(), PathBuf::new()),
 			xmrig: Process::new(ProcessName::Xmrig, String::new(), PathBuf::new()),
-			p2pool_api: P2poolApi::new(),
-			xmrig_api: XmrigApi::new(),
+			pub_api_p2pool: PubP2poolApi::new(),
+			pub_api_xmrig: PubXmrigApi::new(),
+			priv_api_p2pool: PrivP2poolApi::new(),
+			priv_api_xmrig: PrivXmrigApi::new(),
 		}
 	}
 
@@ -264,13 +366,13 @@ impl Helper {
 	// [helper] = Actual Arc
 	// [h]      = Temporary lock that gets dropped
 	// [jobs]   = Vector of async jobs ready to go
-	#[tokio::main]
-	pub async fn helper(helper: Arc<Mutex<Self>>) {
+//	#[tokio::main]
+	pub fn helper(helper: Arc<Mutex<Self>>) {
 		// Begin loop
 		loop {
 
 		// 1. Create "jobs" vector holding async tasks
-		let jobs: Vec<tokio::task::JoinHandle<Result<(), anyhow::Error>>> = vec![];
+//		let jobs: Vec<tokio::task::JoinHandle<Result<(), anyhow::Error>>> = vec![];
 
 		// 2. Loop init timestamp
 		let start = Instant::now();
@@ -303,9 +405,9 @@ impl Helper {
 		drop(h);
 
 		// 6. Execute all async tasks
-		for job in jobs {
-			job.await;
-		}
+//		for job in jobs {
+//			job.await;
+//		}
 
 		// 7. Set Gupax/P2Pool/XMRig uptime
 		let mut h = helper.lock().unwrap();