update: dynamically return [Tor+TLS|TLS-only] HTTP client at runtime

This commit is contained in:
hinto-janaiyo 2022-10-25 17:15:07 -04:00
parent bf81b2c57c
commit 42373a37fe
No known key found for this signature in database
GPG key ID: D7483F6CA27D1B1D
2 changed files with 88 additions and 77 deletions

View file

@ -70,7 +70,7 @@ pub struct App {
// State // State
og: State, // og = Old state to compare against og: State, // og = Old state to compare against
state: State, // state = Working state (current settings) 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 diff: bool, // Instead of comparing [og == state] every frame, this bool indicates changes
// Process/update state: // Process/update state:
// Doesn't make sense to save this on disk // Doesn't make sense to save this on disk
@ -114,7 +114,7 @@ impl App {
node: Arc::new(Mutex::new(NodeStruct::default())), node: Arc::new(Mutex::new(NodeStruct::default())),
og: State::default(), og: State::default(),
state: 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, diff: false,
p2pool: false, p2pool: false,
xmrig: false, xmrig: false,
@ -147,7 +147,7 @@ impl App {
app.og.xmrig.max_threads = num_cpus::get(); 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; } 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.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 app
} }
} }
@ -372,8 +372,14 @@ impl eframe::App for App {
// *-------* // *-------*
// | DEBUG | // | DEBUG |
// *-------* // *-------*
self.update.start(); let p2pool = self.og.gupax.absolute_p2pool_path.clone();
thread::sleep; 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. // This sets the top level Ui dimensions.
// Used as a reference for other uis. // Used as a reference for other uis.
egui::CentralPanel::default().show(ctx, |ui| { self.width = ui.available_width(); self.height = ui.available_height(); }); egui::CentralPanel::default().show(ctx, |ui| { self.width = ui.available_width(); self.height = ui.available_height(); });

View file

@ -14,6 +14,15 @@
//// You should have received a copy of the GNU General Public License //// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// 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 //---------------------------------------------------------------------------------------------------- Imports
use serde_derive::{Serialize,Deserialize}; use serde_derive::{Serialize,Deserialize};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
@ -146,7 +155,7 @@ const FAKE_USER_AGENT: [&'static str; 50] = [
"curl/7.85.0", "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_TMP: &'static str = "Creating temporary directory";
const MSG_PKG: &'static str = "Creating package list"; const MSG_PKG: &'static str = "Creating package list";
const MSG_TOR: &'static str = "Creating Tor+HTTPS client"; const MSG_TOR: &'static str = "Creating Tor+HTTPS client";
@ -164,8 +173,8 @@ const MSG_ARCHIVE: &'static str = "Downloading packages";
// Progress bar structure: // Progress bar structure:
// 5% | Create tmp directory // 5% | Create tmp directory
// 5% | Create package list // 5% | Create package list
// 10% | Create Tor/HTTPS client // 15% | Create Tor/HTTPS client
// 20% | Download Metadata (x3) // 15% | Download Metadata (x3)
// 30% | Download Archive (x3) // 30% | Download Archive (x3)
// 15% | Extract (x3) // 15% | Extract (x3)
// 15% | Upgrade (x3) // 15% | Upgrade (x3)
@ -183,7 +192,7 @@ pub struct Update {
impl Update { impl Update {
// Takes in current paths from [State] // 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 { Self {
path_gupax: crate::get_exe().unwrap(), path_gupax: crate::get_exe().unwrap(),
path_p2pool: path_p2pool.display().to_string(), path_p2pool: path_p2pool.display().to_string(),
@ -207,32 +216,35 @@ impl Update {
.collect(); .collect();
let tmp = std::env::temp_dir(); let tmp = std::env::temp_dir();
let tmp = format!("{}{}{}{}", tmp.display(), "/gupax_", rand_string, "/"); let tmp = format!("{}{}{}{}", tmp.display(), "/gupax_", rand_string, "/");
info!("Update | TMP directory ... {}", tmp);
tmp tmp
} }
// The HTTPS client created when Tor is enabled: // Get a HTTPS client. Uses [Arti] if Tor is enabled.
// TLS implementation | tls-api -> native-tls // The base type looks something like [hyper::Client<...>].
// Tor implementatoin | arti // This is then wrapped with the custom [ClientEnum] type to implement
pub async fn get_tor_client() -> Result<ClientEnum, anyhow::Error> { // returning either a [Tor+TLS|TLS-only] client AT RUNTIME BASED ON USER SETTINGS
info!("Update | Creating Tor+HTTPS client..."); // tor == true? => return Tor client
let tor = TorClient::create_bootstrapped(TorClientConfig::default()).await?; // tor == false? => return normal TLS client
let tls = tls_api_native_tls::TlsConnector::builder()?.build()?; //
let http = ArtiHttpConnector::new(tor, tls); // Since functions that take generic INPUT are much easier to implement,
let client = ClientEnum::Tor(Client::builder().build(http)); // [get_response()] just takes a [hyper::Client<C>], which is passed to
info!("Update | Tor client ... OK"); // it via deconstructing this [ClientEnum] with a match, like so:
Ok(client) // ClientEnum::Tor(T) => get_reponse(... T ...)
} // ClientEnum::Https(H) => get_reponse(... H ...)
//
// The HTTPS client created when Tor is disabled: pub async fn get_client(tor: bool) -> Result<ClientEnum, anyhow::Error> {
// TLS implementation | hyper-tls if tor {
pub async fn get_client() -> Result<ClientEnum, anyhow::Error> { let tor = TorClient::create_bootstrapped(TorClientConfig::default()).await?;
info!("Update | Creating HTTPS client..."); let tls = tls_api_native_tls::TlsConnector::builder()?.build()?;
let mut https = hyper_tls::HttpsConnector::new(); let connector = ArtiHttpConnector::new(tor, tls);
https.https_only(true); let client = ClientEnum::Tor(Client::builder().build(connector));
let client = ClientEnum::Https(Client::builder().build(https)); return Ok(client)
info!("Update | HTTPS client ... OK"); } else {
Ok(client) let mut connector = hyper_tls::HttpsConnector::new();
connector.https_only(true);
let client = ClientEnum::Https(Client::builder().build(connector));
return Ok(client)
}
} }
// Download process: // Download process:
@ -248,57 +260,58 @@ impl Update {
// Set progress bar // Set progress bar
*self.msg.lock().unwrap() = MSG_START.to_string(); *self.msg.lock().unwrap() = MSG_START.to_string();
*self.prog.lock().unwrap() = 0; *self.prog.lock().unwrap() = 0;
info!("Update | Init | {}...", *self.msg.lock().unwrap());
// Get temporary directory // Get temporary directory
*self.msg.lock().unwrap() = MSG_TMP.to_string(); *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(); let tmp_dir = Self::get_tmp_dir();
*self.prog.lock().unwrap() = 5; *self.prog.lock().unwrap() += 5;
// Make Pkg vector // Make Pkg vector
*self.msg.lock().unwrap() = MSG_PKG.to_string(); *self.msg.lock().unwrap() = MSG_PKG.to_string();
info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap());
let vec = vec![ let vec = vec![
Pkg::new(Gupax, &tmp_dir, self.prog.clone(), self.msg.clone()), Pkg::new(Gupax, &tmp_dir, self.prog.clone(), self.msg.clone()),
Pkg::new(P2pool, &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()), Pkg::new(Xmrig, &tmp_dir, self.prog.clone(), self.msg.clone()),
]; ];
let mut handles: Vec<JoinHandle<()>> = vec![]; let mut handles: Vec<JoinHandle<()>> = vec![];
*self.prog.lock().unwrap() = 5; *self.prog.lock().unwrap() += 5;
// Create Tor/HTTPS client // Create Tor/HTTPS client
let mut client: ClientEnum; if self.tor { *self.msg.lock().unwrap() = MSG_TOR.to_string() } else { *self.msg.lock().unwrap() = MSG_HTTPS.to_string() }
if self.tor { info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap());
*self.msg.lock().unwrap() = MSG_TOR.to_string(); let client = Self::get_client(self.tor).await?;
client = Self::get_tor_client().await?; *self.prog.lock().unwrap() += 10;
} else {
*self.msg.lock().unwrap() = MSG_HTTPS.to_string();
client = Self::get_client().await?;
}
*self.prog.lock().unwrap() = 10;
// loop for metadata // Loop for metadata
info!("Update | Metadata | Starting metadata fetch...");
for pkg in vec.iter() { for pkg in vec.iter() {
info!("Update | Metadata | Starting ... {}", pkg.name); // Clone data before sending to async
let name = pkg.name.clone(); let name = pkg.name.clone();
let version = Arc::clone(&pkg.version); let version = Arc::clone(&pkg.version);
let request = hyper::Request::builder() let prog = Arc::clone(&pkg.prog);
.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 client = client.clone(); let client = client.clone();
let request = Pkg::get_request(pkg.link_metadata.to_string())?;
// Send to async
let handle: JoinHandle<()> = tokio::spawn(async move { 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); handles.push(handle);
} }
// Unwrap async
for handle in handles { for handle in handles {
handle.await?; handle.await?;
} }
info!("Update | Metadata ... OK\n"); info!("Update | Metadata ... OK");
Ok(()) Ok(())
//---------------------------------------------- //----------------------------------------------
// //
// // loop for download // // loop for download
// let mut handles: Vec<JoinHandle<()>> = vec![]; // let mut handles: Vec<JoinHandle<()>> = vec![];
// for pkg in vec.iter() { // for pkg in vec.iter() {
@ -358,10 +371,10 @@ impl Update {
} }
} }
// Wrapper type around Tor/HTTPS client #[derive(Debug,Clone)]
enum ClientEnum { enum ClientEnum {
Tor(Client<ArtiHttpConnector<tor_rtcompat::PreferredRuntime, tls_api_native_tls::TlsConnector>>), Tor(Client<ArtiHttpConnector<tor_rtcompat::PreferredRuntime, tls_api_native_tls::TlsConnector>>),
Https(Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>), Https(Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>),
} }
//---------------------------------------------------------------------------------------------------- Pkg struct/impl //---------------------------------------------------------------------------------------------------- Pkg struct/impl
@ -373,14 +386,14 @@ pub struct Pkg {
link_suffix: &'static str, link_suffix: &'static str,
link_extension: &'static str, link_extension: &'static str,
tmp_dir: String, tmp_dir: String,
update_prog: Arc<Mutex<u8>>, prog: Arc<Mutex<u8>>,
update_msg: Arc<Mutex<String>>, msg: Arc<Mutex<String>>,
bytes: Arc<Mutex<bytes::Bytes>>, bytes: Arc<Mutex<bytes::Bytes>>,
version: Arc<Mutex<String>>, version: Arc<Mutex<String>>,
} }
impl Pkg { impl Pkg {
pub fn new(name: Name, tmp_dir: &String, update_prog: Arc<Mutex<u8>>, update_msg: Arc<Mutex<String>>) -> Self { pub fn new(name: Name, tmp_dir: &String, prog: Arc<Mutex<u8>>, msg: Arc<Mutex<String>>) -> Self {
let link_metadata = match name { let link_metadata = match name {
Gupax => GUPAX_METADATA, Gupax => GUPAX_METADATA,
P2pool => P2POOL_METADATA, P2pool => P2POOL_METADATA,
@ -408,42 +421,34 @@ impl Pkg {
link_suffix, link_suffix,
link_extension, link_extension,
tmp_dir: tmp_dir.to_string(), tmp_dir: tmp_dir.to_string(),
update_prog, prog,
update_msg, msg,
bytes: Arc::new(Mutex::new(bytes::Bytes::new())), bytes: Arc::new(Mutex::new(bytes::Bytes::new())),
version: Arc::new(Mutex::new(String::new())), version: Arc::new(Mutex::new(String::new())),
} }
} }
// Generate GET request based off input URI + fake user agent // Generate GET request based off input URI + fake user agent
pub async fn get_request(self) -> Result<Request<Body>, anyhow::Error> { pub fn get_request(link: String) -> Result<Request<Body>, anyhow::Error> {
let user_agent = FAKE_USER_AGENT[thread_rng().gen_range(0..50)]; let user_agent = FAKE_USER_AGENT[thread_rng().gen_range(0..50)];
let request = Request::builder() let request = Request::builder()
.method("GET") .method("GET")
.uri(self.link_metadata) .uri(link)
.header(hyper::header::USER_AGENT, HeaderValue::from_static(user_agent)) .header(hyper::header::USER_AGENT, HeaderValue::from_static(user_agent))
.body(Body::empty())?; .body(Body::empty())?;
Ok(request) Ok(request)
} }
// Get response using [Tor client] + [request] // Get response using [Generic hyper::client<C>] & [Request]
// and change the [version] under an Arc<Mutex> // and change [version, prog] under an Arc<Mutex>
pub async fn get_tor_response(name: Name, version: Arc<Mutex<String>>, client: Client<ArtiHttpConnector<tor_rtcompat::PreferredRuntime, tls_api_native_tls::TlsConnector>>, request: Request<Body>) -> Result<(), Error> { pub async fn get_response<C>(name: Name, version: Arc<Mutex<String>>, prog: Arc<Mutex<u8>>, client: Client<C>, request: Request<Body>) -> Result<(), Error>
where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, {
let mut response = client.request(request).await?; let mut response = client.request(request).await?;
let body = hyper::body::to_bytes(response.body_mut()).await?; let body = hyper::body::to_bytes(response.body_mut()).await?;
let body: Version = serde_json::from_slice(&body)?; let body: Version = serde_json::from_slice(&body)?;
*version.lock().unwrap() = body.tag_name.clone(); *version.lock().unwrap() = body.tag_name.clone();
info!("Update | Metadata | {} {} ... OK", name, body.tag_name); *prog.lock().unwrap() += 5;
Ok(()) info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap());
}
// Same thing, but without Tor.
pub async fn get_response(name: Name, version: Arc<Mutex<String>>, client: Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>, request: Request<Body>) -> 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);
Ok(()) Ok(())
} }
} }