diff --git a/src/main.rs b/src/main.rs
index bbd7237..0c6acf8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -70,7 +70,7 @@ pub struct App {
// State
og: State, // og = Old state to compare against
state: State, // state = Working state (current settings)
- update: Update, // State for update data [update.rs]
+// update: Update, // State for update data [update.rs]
diff: bool, // Instead of comparing [og == state] every frame, this bool indicates changes
// Process/update state:
// Doesn't make sense to save this on disk
@@ -114,7 +114,7 @@ impl App {
node: Arc::new(Mutex::new(NodeStruct::default())),
og: State::default(),
state: State::default(),
- update: Update::new(&throwaway.gupax.absolute_p2pool_path, &throwaway.gupax.absolute_xmrig_path, true),
+// update: Update::new(&throwaway.gupax.absolute_p2pool_path, &throwaway.gupax.absolute_xmrig_path, true),
diff: false,
p2pool: false,
xmrig: false,
@@ -147,7 +147,7 @@ impl App {
app.og.xmrig.max_threads = num_cpus::get();
if app.og.xmrig.current_threads > app.og.xmrig.max_threads { app.og.xmrig.current_threads = app.og.xmrig.max_threads; }
app.state = app.og.clone();
- app.update = Update::new(&app.og.gupax.absolute_p2pool_path, &app.og.gupax.absolute_xmrig_path, app.og.gupax.update_via_tor);
+// app.update = Update::new(&app.og.gupax.absolute_p2pool_path, &app.og.gupax.absolute_xmrig_path, app.og.gupax.update_via_tor);
app
}
}
@@ -372,8 +372,14 @@ impl eframe::App for App {
// *-------*
// | DEBUG |
// *-------*
- self.update.start();
- thread::sleep;
+ let p2pool = self.og.gupax.absolute_p2pool_path.clone();
+ let xmrig = self.og.gupax.absolute_xmrig_path.clone();
+ let tor = self.og.gupax.update_via_tor.clone();
+ thread::spawn(move|| {
+ info!("Spawning update thread...");
+ let update = Update::start(&mut Update::new(p2pool, xmrig, tor));
+ });
+ thread::park();
// This sets the top level Ui dimensions.
// Used as a reference for other uis.
egui::CentralPanel::default().show(ctx, |ui| { self.width = ui.available_width(); self.height = ui.available_height(); });
diff --git a/src/update.rs b/src/update.rs
index 77a44bc..b0c28cd 100644
--- a/src/update.rs
+++ b/src/update.rs
@@ -14,6 +14,15 @@
//// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+// This file contains all (most) of the code for updating.
+// The main [Update] struct contains meta update information.
+// It is held by the top [App] struct. Each package also gets
+// a [Pkg] struct that only lasts as long as the download.
+//
+// An update is triggered by either:
+// a. user clicks update on [Gupax] tab
+// b. auto-update at startup
+
//---------------------------------------------------------------------------------------------------- Imports
use serde_derive::{Serialize,Deserialize};
use tokio::task::JoinHandle;
@@ -146,7 +155,7 @@ const FAKE_USER_AGENT: [&'static str; 50] = [
"curl/7.85.0",
];
-const MSG_START: &'static str = "Starting update...";
+const MSG_START: &'static str = "Starting update";
const MSG_TMP: &'static str = "Creating temporary directory";
const MSG_PKG: &'static str = "Creating package list";
const MSG_TOR: &'static str = "Creating Tor+HTTPS client";
@@ -164,8 +173,8 @@ const MSG_ARCHIVE: &'static str = "Downloading packages";
// Progress bar structure:
// 5% | Create tmp directory
// 5% | Create package list
-// 10% | Create Tor/HTTPS client
-// 20% | Download Metadata (x3)
+// 15% | Create Tor/HTTPS client
+// 15% | Download Metadata (x3)
// 30% | Download Archive (x3)
// 15% | Extract (x3)
// 15% | Upgrade (x3)
@@ -183,7 +192,7 @@ pub struct Update {
impl Update {
// Takes in current paths from [State]
- pub fn new(path_p2pool: &PathBuf, path_xmrig: &PathBuf, tor: bool) -> Self {
+ pub fn new(path_p2pool: PathBuf, path_xmrig: PathBuf, tor: bool) -> Self {
Self {
path_gupax: crate::get_exe().unwrap(),
path_p2pool: path_p2pool.display().to_string(),
@@ -207,32 +216,35 @@ impl Update {
.collect();
let tmp = std::env::temp_dir();
let tmp = format!("{}{}{}{}", tmp.display(), "/gupax_", rand_string, "/");
- info!("Update | TMP directory ... {}", tmp);
tmp
}
- // The HTTPS client created when Tor is enabled:
- // TLS implementation | tls-api -> native-tls
- // Tor implementatoin | arti
- pub async fn get_tor_client() -> Result {
- info!("Update | Creating Tor+HTTPS client...");
- let tor = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
- let tls = tls_api_native_tls::TlsConnector::builder()?.build()?;
- let http = ArtiHttpConnector::new(tor, tls);
- let client = ClientEnum::Tor(Client::builder().build(http));
- info!("Update | Tor client ... OK");
- Ok(client)
- }
-
- // The HTTPS client created when Tor is disabled:
- // TLS implementation | hyper-tls
- pub async fn get_client() -> Result {
- info!("Update | Creating HTTPS client...");
- let mut https = hyper_tls::HttpsConnector::new();
- https.https_only(true);
- let client = ClientEnum::Https(Client::builder().build(https));
- info!("Update | HTTPS client ... OK");
- Ok(client)
+ // Get a HTTPS client. Uses [Arti] if Tor is enabled.
+ // The base type looks something like [hyper::Client<...>].
+ // This is then wrapped with the custom [ClientEnum] type to implement
+ // returning either a [Tor+TLS|TLS-only] client AT RUNTIME BASED ON USER SETTINGS
+ // tor == true? => return Tor client
+ // tor == false? => return normal TLS client
+ //
+ // Since functions that take generic INPUT are much easier to implement,
+ // [get_response()] just takes a [hyper::Client], which is passed to
+ // it via deconstructing this [ClientEnum] with a match, like so:
+ // ClientEnum::Tor(T) => get_reponse(... T ...)
+ // ClientEnum::Https(H) => get_reponse(... H ...)
+ //
+ pub async fn get_client(tor: bool) -> Result {
+ if tor {
+ let tor = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
+ let tls = tls_api_native_tls::TlsConnector::builder()?.build()?;
+ let connector = ArtiHttpConnector::new(tor, tls);
+ let client = ClientEnum::Tor(Client::builder().build(connector));
+ return Ok(client)
+ } else {
+ let mut connector = hyper_tls::HttpsConnector::new();
+ connector.https_only(true);
+ let client = ClientEnum::Https(Client::builder().build(connector));
+ return Ok(client)
+ }
}
// Download process:
@@ -248,57 +260,58 @@ impl Update {
// Set progress bar
*self.msg.lock().unwrap() = MSG_START.to_string();
*self.prog.lock().unwrap() = 0;
+ info!("Update | Init | {}...", *self.msg.lock().unwrap());
// Get temporary directory
*self.msg.lock().unwrap() = MSG_TMP.to_string();
+ info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap());
let tmp_dir = Self::get_tmp_dir();
- *self.prog.lock().unwrap() = 5;
+ *self.prog.lock().unwrap() += 5;
// Make Pkg vector
*self.msg.lock().unwrap() = MSG_PKG.to_string();
+ info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap());
let vec = vec![
Pkg::new(Gupax, &tmp_dir, self.prog.clone(), self.msg.clone()),
Pkg::new(P2pool, &tmp_dir, self.prog.clone(), self.msg.clone()),
Pkg::new(Xmrig, &tmp_dir, self.prog.clone(), self.msg.clone()),
];
let mut handles: Vec> = vec![];
- *self.prog.lock().unwrap() = 5;
+ *self.prog.lock().unwrap() += 5;
// Create Tor/HTTPS client
- let mut client: ClientEnum;
- if self.tor {
- *self.msg.lock().unwrap() = MSG_TOR.to_string();
- client = Self::get_tor_client().await?;
- } else {
- *self.msg.lock().unwrap() = MSG_HTTPS.to_string();
- client = Self::get_client().await?;
- }
- *self.prog.lock().unwrap() = 10;
+ if self.tor { *self.msg.lock().unwrap() = MSG_TOR.to_string() } else { *self.msg.lock().unwrap() = MSG_HTTPS.to_string() }
+ info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap());
+ let client = Self::get_client(self.tor).await?;
+ *self.prog.lock().unwrap() += 10;
- // loop for metadata
+ // Loop for metadata
+ info!("Update | Metadata | Starting metadata fetch...");
for pkg in vec.iter() {
- info!("Update | Metadata | Starting ... {}", pkg.name);
+ // Clone data before sending to async
let name = pkg.name.clone();
let version = Arc::clone(&pkg.version);
- let request = hyper::Request::builder()
- .method("GET")
- .uri(pkg.link_metadata)
- .header(hyper::header::USER_AGENT, hyper::header::HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"))
- .body(Body::empty())?;
+ let prog = Arc::clone(&pkg.prog);
let client = client.clone();
+ let request = Pkg::get_request(pkg.link_metadata.to_string())?;
+ // Send to async
let handle: JoinHandle<()> = tokio::spawn(async move {
- Pkg::get_tor_response(name, version, client, request).await;
+ match client {
+ ClientEnum::Tor(t) => Pkg::get_response(name, version, prog, t, request).await,
+ ClientEnum::Https(h) => Pkg::get_response(name, version, prog, h, request).await,
+ };
});
handles.push(handle);
}
+ // Unwrap async
for handle in handles {
handle.await?;
}
- info!("Update | Metadata ... OK\n");
+ info!("Update | Metadata ... OK");
Ok(())
//----------------------------------------------
- //
+ //
// // loop for download
// let mut handles: Vec> = vec![];
// for pkg in vec.iter() {
@@ -358,10 +371,10 @@ impl Update {
}
}
-// Wrapper type around Tor/HTTPS client
+#[derive(Debug,Clone)]
enum ClientEnum {
- Tor(Client>),
- Https(Client>),
+ Tor(Client>),
+ Https(Client>),
}
//---------------------------------------------------------------------------------------------------- Pkg struct/impl
@@ -373,14 +386,14 @@ pub struct Pkg {
link_suffix: &'static str,
link_extension: &'static str,
tmp_dir: String,
- update_prog: Arc>,
- update_msg: Arc>,
+ prog: Arc>,
+ msg: Arc>,
bytes: Arc>,
version: Arc>,
}
impl Pkg {
- pub fn new(name: Name, tmp_dir: &String, update_prog: Arc>, update_msg: Arc>) -> Self {
+ pub fn new(name: Name, tmp_dir: &String, prog: Arc>, msg: Arc>) -> Self {
let link_metadata = match name {
Gupax => GUPAX_METADATA,
P2pool => P2POOL_METADATA,
@@ -408,42 +421,34 @@ impl Pkg {
link_suffix,
link_extension,
tmp_dir: tmp_dir.to_string(),
- update_prog,
- update_msg,
+ prog,
+ msg,
bytes: Arc::new(Mutex::new(bytes::Bytes::new())),
version: Arc::new(Mutex::new(String::new())),
}
}
// Generate GET request based off input URI + fake user agent
- pub async fn get_request(self) -> Result, anyhow::Error> {
+ pub fn get_request(link: String) -> Result, anyhow::Error> {
let user_agent = FAKE_USER_AGENT[thread_rng().gen_range(0..50)];
let request = Request::builder()
.method("GET")
- .uri(self.link_metadata)
+ .uri(link)
.header(hyper::header::USER_AGENT, HeaderValue::from_static(user_agent))
.body(Body::empty())?;
Ok(request)
}
- // Get response using [Tor client] + [request]
- // and change the [version] under an Arc
- pub async fn get_tor_response(name: Name, version: Arc>, client: Client>, request: Request) -> Result<(), Error> {
+ // Get response using [Generic hyper::client] & [Request]
+ // and change [version, prog] under an Arc
+ pub async fn get_response(name: Name, version: Arc>, prog: Arc>, client: Client, request: Request) -> Result<(), Error>
+ where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, {
let mut response = client.request(request).await?;
let body = hyper::body::to_bytes(response.body_mut()).await?;
let body: Version = serde_json::from_slice(&body)?;
*version.lock().unwrap() = body.tag_name.clone();
- info!("Update | Metadata | {} {} ... OK", name, body.tag_name);
- Ok(())
- }
-
- // Same thing, but without Tor.
- pub async fn get_response(name: Name, version: Arc>, client: Client>, request: Request) -> Result<(), Error> {
- let mut response = client.request(request).await?;
- let body = hyper::body::to_bytes(response.body_mut()).await?;
- let body: Version = serde_json::from_slice(&body)?;
- *version.lock().unwrap() = body.tag_name.clone();
- info!("Update | Metadata | {} {} ... OK", name, body.tag_name);
+ *prog.lock().unwrap() += 5;
+ info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap());
Ok(())
}
}