From ab9b98a819a1c9aeb9d315a84301239883237e41 Mon Sep 17 00:00:00 2001
From: hinto-janaiyo <hinto.janaiyo@protonmail.com>
Date: Thu, 13 Oct 2022 08:57:50 -0400
Subject: [PATCH] add toml.rs/constants.rs, ask_before_quit screen

---
 Cargo.lock       |  88 ++++++++++++++++++-
 Cargo.toml       |  34 +++++---
 build.sh         |  15 +++-
 src/README.md    |  49 +++++++++++
 src/constants.rs |  10 ++-
 src/main.rs      |  80 +++++++++++------
 src/toml.rs      | 223 +++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 453 insertions(+), 46 deletions(-)
 create mode 100644 src/README.md
 create mode 100644 src/toml.rs

diff --git a/Cargo.lock b/Cargo.lock
index 1d97e07..7a047f7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -133,6 +133,15 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
 
+[[package]]
+name = "block-buffer"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.11.0"
@@ -346,6 +355,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "cpufeatures"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "crc32fast"
 version = "1.3.2"
@@ -427,6 +445,16 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
 
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
 [[package]]
 name = "cty"
 version = "0.2.2"
@@ -440,7 +468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
 dependencies = [
  "byteorder",
- "digest",
+ "digest 0.9.0",
  "rand_core 0.5.1",
  "subtle",
  "zeroize",
@@ -490,6 +518,36 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "digest"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "dirs"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
 [[package]]
 name = "dispatch"
 version = "0.2.0"
@@ -950,15 +1008,21 @@ name = "gupax"
 version = "0.1.0"
 dependencies = [
  "chrono",
+ "dirs",
  "eframe",
  "egui",
  "egui_extras",
  "env_logger",
+ "hex-literal",
  "image",
  "log",
  "monero",
  "num_cpus",
  "regex",
+ "serde",
+ "serde_derive",
+ "sha2",
+ "toml",
 ]
 
 [[package]]
@@ -1699,6 +1763,17 @@ dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "redox_users"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
+dependencies = [
+ "getrandom 0.2.7",
+ "redox_syscall",
+ "thiserror",
+]
+
 [[package]]
 name = "regex"
 version = "1.6.0"
@@ -1820,6 +1895,17 @@ dependencies = [
  "pkg-config",
 ]
 
+[[package]]
+name = "sha2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.10.5",
+]
+
 [[package]]
 name = "shared_library"
 version = "0.1.9"
diff --git a/Cargo.toml b/Cargo.toml
index e80bacc..996ed95 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,27 +4,33 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-egui = "0.19.0"
-eframe = "0.19.0"
-egui_extras = { version = "0.19.0", features = ["image"] }
-image = { version = "0.24.4", features = ["png"] }
-num_cpus = "1.13.1"
-monero = "0.18.0"
-regex = "1.6.0"
-log = "0.4.17"
-env_logger = "0.9.1"
+dirs = "4.0.0"
 chrono = "0.4.22"
+eframe = "0.19.0"
+egui = "0.19.0"
+egui_extras = { version = "0.19.0", features = ["image"] }
+env_logger = "0.9.1"
+hex-literal = "0.3.4"
+image = { version = "0.24.4", features = ["png"] }
+log = "0.4.17"
+monero = "0.18.0"
+num_cpus = "1.13.1"
+regex = "1.6.0"
+serde = "1.0.145"
+serde_derive = "1.0.145"
+sha2 = "0.10.6"
+toml = "0.5.9"
 
 [profile.optimized]
-inherits = "release"
-strip = "debuginfo"
-debug = false
+codegen-units = 1
 debug-assertions = false
+debug = false
+incremental = true
+inherits = "release"
 lto = true
 overflow-checks = false
-incremental = true
-codegen-units = 1
 rpath = false
+strip = "debuginfo"
 
 [profile.optimized.package."*"]
 opt-level = 3
diff --git a/build.sh b/build.sh
index baf276e..f5a1341 100755
--- a/build.sh
+++ b/build.sh
@@ -4,4 +4,17 @@ set -e
 
 [[ $PWD = */gupax ]]
 
-RUSTFLAGS="-C target-cpu=native" cargo build --profile optimized && du -hs target/optimized/gupax
+if [[ $1 = *all* ]]; then
+	echo "=== building all ==="
+	echo "=== windows ==="
+	cargo build --profile optimized --target x86_64-pc-windows-gnu
+#	echo "=== macos ==="
+#	cargo build --profile optimized --target x86_64-apple-darwin
+	echo "=== linux ==="
+	cargo build --profile optimized
+	du -hs target/x86_64-pc-windows-gnu/optimized/gupax target/x86_64-apple-darwin/optimized/gupax target/optimized/gupax
+else
+	echo "=== building linux cpu optimized ==="
+	RUSTFLAGS="-C target-cpu=native" cargo build --profile optimized
+	du -hs target/optimized/gupax
+fi
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..c082873
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,49 @@
+# Gupax source files
+* [State](#State)
+* [Structure](#Structure)
+* [Bootstrap](#Bootstrap)
+
+## Structure
+| File/Folder    | Purpose |
+|----------------|---------|
+| `about.rs`     | Struct/impl for `About` tab
+| `constants.rs` | General constants needed in Gupax
+| `gupax.rs`     | Struct/impl for `Gupax` tab
+| `main.rs`      | Struct/enum/impl for `App/Tab/State`, init functions, main function
+| `p2pool.rs`    | Struct/impl for `P2Pool` tab
+| `status.rs`    | Struct/impl for `Status` tab
+| `toml.rs`      | Struct/impl for `gupax.toml`, the disk state
+| `xmrig.rs`     | Struct/impl for `XMRig` tab
+
+## Bootstrap
+This is how Gupax works internally when starting up, divided into 3 sections.
+
+1. **INIT**
+	- Initialize custom console logging with `log`, `env_logger` || *warn!*
+	- Initialize misc data (structs, text styles, thread count, images, etc) || *panic!*
+	- Check for admin privilege (for XMRig) || *warn!*
+	- Attempt to read `gupax.toml` || *warn!*, *initialize config with default options*
+	- If errors were found, pop-up window
+	
+2. **AUTO-UPDATE**
+	- If `auto_update` == `true`, pop-up auto-updating window || *info!*, *skip auto-update*
+	- Multi-threaded GitHub API check on Gupax -> P2Pool -> XMRig || *warn!*, *skip auto-update*
+	- Multi-threaded download if current version != new version || *warn!*, *skip auto-update*
+	- After download, atomically replace current binaries with new || *warn!*, *skip auto-update*
+	- Update version metadata || *warn!*, *skip auto-update*
+
+3. **MAIN**
+	- All data must be initialized at this point, either via `gupax.toml` or default options || *panic!*
+	- Start `App` frame || *panic!*
+	- Write state to `gupax.toml` on user clicking `Save` (after checking input for correctness) || *warn!*
+	- If `ask_before_quit` == `true`, check for running processes, unsaved state, and update connections before quitting
+	- Kill processes, kill connections, exit
+
+## State
+Internal state is saved in the "OS data folder" as `gupax.toml`, using the [TOML](https://github.com/toml-lang/toml) format. If the version can't be parsed (not in the `vX.X.X` or `vX.X` format), the auto-updater will be skipped. [If not found, a default `gupax.toml` file will be created with `Toml::default`.](https://github.com/hinto-janaiyo/gupax/blob/main/src/toml.rs)
+
+| OS       | Data Folder                              | Example                                                   |
+|----------|----------------------------------------- |-----------------------------------------------------------|
+| Windows  | `{FOLDERID_LocalAppData}`                | C:\Users\Alice\AppData\Roaming\Gupax\gupax.toml           |
+| macOS    | `$HOME`/Library/Application Support      | /Users/Alice/Library/Application Support/Gupax/gupax.toml |
+| Linux    | `$XDG_DATA_HOME` or `$HOME`/.local/share | /home/alice/.local/share/gupax/gupax.toml                 |
diff --git a/src/constants.rs b/src/constants.rs
index 3b13e42..77395cd 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -16,11 +16,17 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use std::net::{Ipv4Addr,SocketAddrV4};
+use sha2::{Sha256,Digest};
+use hex_literal::hex;
+use std::{io, fs};
+
+// These are the versions bundled with Gupax.
+pub const P2POOL_VERSION: &'static str = "v2.4";
+pub const XMRIG_VERSION: &'static str = "v6.18.0";
 
-// Compile-time constants
 pub const BYTES_ICON: &[u8] = include_bytes!("../images/png/icon.png");
 pub const BYTES_BANNER: &[u8] = include_bytes!("../images/png/banner.png");
-pub const P2POOL_BASE_ARGS: &'static str = "--host 127.0.0.1 --rpc-port 18081 --zmq-port 18083 --loglevel 3 --out-peers 10 --in-peers 10";
+pub const P2POOL_BASE_ARGS: &'static str = "";
 pub const XMRIG_BASE_ARGS: &'static str = "--http-host=127.0.0.1 --http-port=18088 --algo=rx/0 --coin=Monero --randomx-cache-qos";
 
 // OS specific
diff --git a/src/main.rs b/src/main.rs
index cf0601e..d5824e0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,7 +16,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
-use eframe::egui;
+use eframe::{egui,NativeOptions};
 use egui::{Vec2,Pos2};
 use std::process::exit;
 use std::thread;
@@ -36,12 +36,13 @@ use std::io::Write;
 use std::time::Instant;
 
 mod constants;
+mod toml;
 mod about;
 mod status;
 mod gupax;
 mod p2pool;
 mod xmrig;
-use {constants::*,about::*,status::*,gupax::*,p2pool::*,xmrig::*};
+use {constants::*,crate::toml::*,about::*,status::*,gupax::*,p2pool::*,xmrig::*};
 
 // The state of the outer [App].
 // See the [State] struct for the
@@ -60,6 +61,8 @@ pub struct App {
 	xmrig: bool,
 	state: State,
 	og: State,
+	allowed_to_close: bool,
+	show_confirmation_dialog: bool,
 }
 
 impl App {
@@ -79,12 +82,12 @@ impl App {
 		let resolution = cc.integration_info.window_info.size;
 		init_text_styles(&cc.egui_ctx, resolution[0] as f32);
 		let banner = match RetainedImage::from_image_bytes("banner.png", BYTES_BANNER) {
-			Ok(banner) => { info!("Banner loading OK"); banner },
+			Ok(banner) => { info!("Banner loading ... OK"); banner },
 			Err(err) => { error!("{}", err); panic!("{}", err); },
 		};
 		let mut state = State::new();
 		let mut og = State::new();
-		info!("{:?}", resolution);
+		info!("Frame resolution ... {:#?}", resolution);
 		Self {
 			version,
 			name_version,
@@ -99,6 +102,8 @@ impl App {
 			xmrig: false,
 			state,
 			og,
+			allowed_to_close: false,
+			show_confirmation_dialog: false,
 		}
 	}
 }
@@ -169,48 +174,58 @@ fn init_text_styles(ctx: &egui::Context, width: f32) {
 //	style.spacing.button_padding = Vec2::new(scale/2.0, scale/2.0);
 	ctx.set_style(style);
 	ctx.set_pixels_per_point(1.0);
+	ctx.request_repaint();
 }
 
-fn main() {
+fn init_logger() {
 	use env_logger::fmt::Color;
 	Builder::new().format(|buf, record| {
 		let level;
 		let mut style = buf.style();
 		match record.level() {
 			Level::Error => { style.set_color(Color::Red); level = "ERROR" },
-			Level::Warn => { style.set_color(Color::Yellow); level = "WARN " },
-			Level::Info => { style.set_color(Color::White); level = "INFO " },
+			Level::Warn => { style.set_color(Color::Yellow); level = "WARN" },
+			Level::Info => { style.set_color(Color::White); level = "INFO" },
 			Level::Debug => { style.set_color(Color::Blue); level = "DEBUG" },
 			Level::Trace => { style.set_color(Color::Magenta); level = "TRACE" },
 		};
 		writeln!(
 			buf,
-			"| {} | {} | {}:{} | {}",
+			"[{}] [{}] [{}:{}] {}",
 			style.set_bold(true).value(level),
 			buf.style().set_dimmed(true).value(chrono::Local::now().format("%F %T%.3f")),
 			buf.style().set_dimmed(true).value(record.file().unwrap_or("???")),
 			buf.style().set_dimmed(true).value(record.line().unwrap_or(0)),
 			record.args(),
 		)
-	}).filter_level(LevelFilter::Info).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().try_init();
-	info!("test");
-	warn!("test");
-	error!("test");
-	debug!("test");
+	}).filter_level(LevelFilter::Info).write_style(WriteStyle::Always).parse_default_env().format_timestamp_millis().init();
+	info!("init_logger() ... OK");
+}
 
+fn init_options() -> NativeOptions {
 	let mut options = eframe::NativeOptions::default();
 	options.min_window_size = Option::from(Vec2::new(1280.0, 720.0));
 	options.max_window_size = Option::from(Vec2::new(3180.0, 2160.0));
 	options.initial_window_size = Option::from(Vec2::new(1280.0, 720.0));
 	options.follow_system_theme = false;
 	options.default_theme = eframe::Theme::Dark;
-	let icon = image::load_from_memory(BYTES_ICON).expect("Failed to read ICON bytes").to_rgba8();
+	let icon = image::load_from_memory(BYTES_ICON).expect("Failed to read icon bytes").to_rgba8();
 	let (icon_width, icon_height) = icon.dimensions();
 	options.icon_data = Some(eframe::IconData {
 		rgba: icon.into_raw(),
 		width: icon_width,
 		height: icon_height,
 	});
+	info!("init_options() ... OK");
+	options
+}
+
+fn main() {
+	init_logger();
+	let options = init_options();
+	let toml = Toml::get();
+	info!("Printing gupax.toml...");
+	eprintln!("{:#?}", toml);
 	let now = Instant::now();
 	eframe::run_native(
 		"Gupax",
@@ -220,7 +235,29 @@ fn main() {
 }
 
 impl eframe::App for App {
-    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
+	fn on_close_event(&mut self) -> bool {
+		self.show_confirmation_dialog = true;
+		self.allowed_to_close
+	}
+	fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
+		if self.show_confirmation_dialog {
+			// Show confirmation dialog:
+			egui::CentralPanel::default().show(ctx, |ui| {
+				let width = ui.available_width();
+				let width = width - 10.0;
+				let height = ui.available_height();
+				init_text_styles(ctx, width);
+				ui.add_sized([width, height/2.0], Label::new("Are you sure you want to quit?"));
+				ui.group(|ui| {
+					if ui.add_sized([width, height/10.0], egui::Button::new("Yes")).clicked() {
+						exit(0);
+					} else if ui.add_sized([width, height/10.0], egui::Button::new("No")).clicked() {
+						self.show_confirmation_dialog = false;
+					}
+				});
+			});
+			return
+		}
 		// Top: Tabs
 		egui::CentralPanel::default().show(ctx, |ui| {
 			init_text_styles(ctx, ui.available_width());
@@ -355,16 +392,3 @@ impl eframe::App for App {
 		});
 	}
 }
-
-pub trait View {
-    fn ui(&mut self, ui: &mut egui::Ui);
-}
-
-/// Something to view
-pub trait Demo {
-    /// `&'static` so we can also use it as a key to store open/close state.
-    fn name(&self) -> &'static str;
-
-    /// Show windows, etc
-    fn show(&mut self, ctx: &egui::Context, open: &mut bool);
-}
diff --git a/src/toml.rs b/src/toml.rs
new file mode 100644
index 0000000..b2bd9a1
--- /dev/null
+++ b/src/toml.rs
@@ -0,0 +1,223 @@
+// Gupax - GUI Uniting P2Pool And XMRig
+//
+// Copyright (c) 2022 hinto-janaiyo
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+// This handles reading/parsing the state file: [gupax.toml]
+// The TOML format is used. This struct hierarchy directly
+// translates into the TOML parser:
+//   Toml/
+//   ├─ Gupax/
+//   │  ├─ ...
+//   ├─ P2pool/
+//   │  ├─ ...
+//   ├─ Xmrig/
+//   │  ├─ ...
+//   ├─ Version/
+//      ├─ ...
+
+use std::{fs,env};
+use std::fmt::Display;
+use std::path::{Path,PathBuf};
+use serde_derive::{Serialize,Deserialize};
+use log::*;
+
+//---------------------------------------------------------------------------------------------------- Impl
+// Since [State] is already used in [main.rs] to represent
+// working state, [Toml] is used to disk state.
+impl Toml {
+	pub fn default() -> Self {
+		use crate::constants::{P2POOL_VERSION,XMRIG_VERSION};
+		Self {
+			gupax: Gupax {
+				auto_update: true,
+				ask_before_quit: true,
+				p2pool_path: DEFAULT_P2POOL_PATH.to_string(),
+				xmrig_path: DEFAULT_XMRIG_PATH.to_string(),
+			},
+			p2pool: P2pool {
+				simple: true,
+				mini: true,
+				out_peers: 10,
+				in_peers: 10,
+				log_level: 3,
+				monerod: "localhost".to_string(),
+				rpc: 18081,
+				zmq: 18083,
+				address: "".to_string(),
+			},
+			xmrig: Xmrig {
+				simple: true,
+				tls: false,
+				nicehash: false,
+				keepalive: false,
+				threads: 1,
+				priority: 2,
+				pool: "localhost:3333".to_string(),
+				address: "".to_string(),
+			},
+			version: Version {
+				p2pool: P2POOL_VERSION.to_string(),
+				xmrig: XMRIG_VERSION.to_string(),
+			},
+		}
+	}
+
+	pub fn get() -> Result<Toml, TomlError> {
+		// Get OS data folder
+		// Linux   | $XDG_DATA_HOME or $HOME/.local/share | /home/alice/.local/state
+		// macOS   | $HOME/Library/Application Support    | /Users/Alice/Library/Application Support
+		// Windows | {FOLDERID_RoamingAppData}            | C:\Users\Alice\AppData\Roaming
+		let mut path = match dirs::data_dir() {
+			Some(mut path) => {
+				path.push(DIRECTORY);
+				info!("{}, OS data path ... OK", path.display());
+				path
+			},
+			None => { error!("Couldn't get OS PATH for data"); return Err(TomlError::Path(PATH_ERROR.to_string())) },
+		};
+
+		// Create directory
+		fs::create_dir_all(&path)?;
+
+		// Attempt to read file, create default if not found
+		path.push(FILENAME);
+		let file = match fs::read_to_string(&path) {
+			Ok(file) => file,
+			Err(err) => {
+				error!("TOML not found, attempting to create default");
+				let default = match toml::ser::to_string(&Toml::default()) {
+						Ok(o) => { info!("TOML serialization ... OK"); o },
+						Err(e) => { error!("Couldn't serialize default TOML file: {}", e); return Err(TomlError::Serialize(e)) },
+				};
+				fs::write(&path, default)?;
+				info!("TOML write ... OK");
+				fs::read_to_string(&path)?
+			},
+		};
+		info!("TOML read ... OK");
+
+		// Attempt to parse, return Result
+		match toml::from_str(&file) {
+			Ok(file) => { info!("TOML parse ... OK"); Ok(file) },
+			Err(err) => { error!("Couldn't parse TOML file"); Err(TomlError::Parse(err)) },
+		}
+	}
+}
+
+impl Display for TomlError {
+	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+		use TomlError::*;
+		match self {
+			Io(err) => write!(f, "{} | {}", ERROR, err),
+			Path(err) => write!(f, "{} | {}", ERROR, err),
+			Parse(err) => write!(f, "{} | {}", ERROR, err),
+			Serialize(err) => write!(f, "{} | {}", ERROR, err),
+		}
+	}
+}
+
+impl From<std::io::Error> for TomlError {
+	fn from(err: std::io::Error) -> Self {
+		TomlError::Io(err)
+	}
+}
+
+fn main() {
+	let state = match Toml::get() {
+		Ok(state) => { println!("OK"); state },
+		Err(err) => panic!(),
+	};
+}
+
+//---------------------------------------------------------------------------------------------------- Const
+const FILENAME: &'static str = "gupax.toml";
+const ERROR: &'static str = "TOML Error";
+const PATH_ERROR: &'static str = "PATH for state directory could not be not found";
+#[cfg(target_os = "windows")]
+const DIRECTORY: &'static str = "Gupax";
+#[cfg(target_os = "macos")]
+const DIRECTORY: &'static str = "Gupax";
+#[cfg(target_os = "linux")]
+const DIRECTORY: &'static str = "gupax";
+#[cfg(target_os = "windows")]
+const DEFAULT_P2POOL_PATH: &'static str = r"P2Pool\p2pool.exe";
+#[cfg(target_os = "macos")]
+const DEFAULT_P2POOL_PATH: &'static str = "P2Pool/p2pool";
+#[cfg(target_os = "linux")]
+const DEFAULT_P2POOL_PATH: &'static str = "p2pool/p2pool";
+#[cfg(target_os = "windows")]
+const DEFAULT_XMRIG_PATH: &'static str = r"XMRig\xmrig.exe";
+#[cfg(target_os = "macos")]
+const DEFAULT_XMRIG_PATH: &'static str = "XMRig/xmrig";
+#[cfg(target_os = "linux")]
+const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig";
+
+//---------------------------------------------------------------------------------------------------- Error Enum
+#[derive(Debug)]
+pub enum TomlError {
+	Io(std::io::Error),
+	Path(String),
+	Parse(toml::de::Error),
+	Serialize(toml::ser::Error),
+}
+
+//---------------------------------------------------------------------------------------------------- Structs
+#[derive(Debug,Deserialize,Serialize)]
+pub struct Toml {
+	gupax: Gupax,
+	p2pool: P2pool,
+	xmrig: Xmrig,
+	version: Version,
+}
+
+#[derive(Debug,Deserialize,Serialize)]
+struct Gupax {
+	auto_update: bool,
+	ask_before_quit: bool,
+	p2pool_path: String,
+	xmrig_path: String,
+}
+
+#[derive(Debug,Deserialize,Serialize)]
+struct P2pool {
+	simple: bool,
+	mini: bool,
+	out_peers: u8,
+	in_peers: u8,
+	log_level: u8,
+	monerod: String,
+	rpc: u16,
+	zmq: u16,
+	address: String,
+}
+
+#[derive(Debug,Deserialize,Serialize)]
+struct Xmrig {
+	simple: bool,
+	tls: bool,
+	nicehash: bool,
+	keepalive: bool,
+	threads: u16,
+	priority: u8,
+	pool: String,
+	address: String,
+}
+
+#[derive(Debug,Deserialize,Serialize)]
+struct Version {
+	p2pool: String,
+	xmrig: String,
+}