update: implement download, 302 HTTP redirect, extraction

This commit is contained in:
hinto-janaiyo 2022-10-25 22:50:53 -04:00
parent 42373a37fe
commit 446cb9db85
No known key found for this signature in database
GPG key ID: D7483F6CA27D1B1D

View file

@ -157,7 +157,6 @@ const FAKE_USER_AGENT: [&'static str; 50] = [
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_TOR: &'static str = "Creating Tor+HTTPS client"; const MSG_TOR: &'static str = "Creating Tor+HTTPS client";
const MSG_HTTPS: &'static str = "Creating HTTPS client"; const MSG_HTTPS: &'static str = "Creating HTTPS client";
const MSG_METADATA: &'static str = "Fetching package metadata"; const MSG_METADATA: &'static str = "Fetching package metadata";
@ -171,8 +170,7 @@ const MSG_ARCHIVE: &'static str = "Downloading packages";
//---------------------------------------------------------------------------------------------------- Update struct/impl //---------------------------------------------------------------------------------------------------- Update struct/impl
// Contains values needed during update // Contains values needed during update
// Progress bar structure: // Progress bar structure:
// 5% | Create tmp directory // 10% | Create tmp directory and pkg list
// 5% | Create package list
// 15% | Create Tor/HTTPS client // 15% | Create Tor/HTTPS client
// 15% | Download Metadata (x3) // 15% | Download Metadata (x3)
// 30% | Download Archive (x3) // 30% | Download Archive (x3)
@ -266,24 +264,21 @@ impl Update {
*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()); 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() += 10;
// Make Pkg vector // 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![ 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;
// Create Tor/HTTPS client // Create Tor/HTTPS client
if self.tor { *self.msg.lock().unwrap() = MSG_TOR.to_string() } else { *self.msg.lock().unwrap() = MSG_HTTPS.to_string() } 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()); info!("Update | Init | {} ... {}%", *self.msg.lock().unwrap(), *self.prog.lock().unwrap());
let client = Self::get_client(self.tor).await?; let client = Self::get_client(self.tor).await?;
*self.prog.lock().unwrap() += 10; *self.prog.lock().unwrap() += 15;
// Loop for metadata // Loop for metadata
info!("Update | Metadata | Starting metadata fetch..."); info!("Update | Metadata | Starting metadata fetch...");
@ -297,77 +292,81 @@ impl Update {
// Send to async // Send to async
let handle: JoinHandle<()> = tokio::spawn(async move { let handle: JoinHandle<()> = tokio::spawn(async move {
match client { match client {
ClientEnum::Tor(t) => Pkg::get_response(name, version, prog, t, request).await, ClientEnum::Tor(t) => Pkg::get_metadata(name, version, prog, t, request).await,
ClientEnum::Https(h) => Pkg::get_response(name, version, prog, h, request).await, ClientEnum::Https(h) => Pkg::get_metadata(name, version, prog, h, request).await,
}; };
}); });
handles.push(handle); handles.push(handle);
} }
// TODO:
// connection fails sometimes
// Regex for [v...] or restart Client process.
// Unwrap async // Unwrap async
for handle in handles { for handle in handles {
handle.await?; handle.await?;
} }
info!("Update | Metadata ... OK"); info!("Update | Metadata ... OK");
Ok(())
//---------------------------------------------- // Loop for download
// let mut handles: Vec<JoinHandle<()>> = vec![];
// // loop for download info!("Update | Download | Starting download...");
// let mut handles: Vec<JoinHandle<()>> = vec![]; for pkg in vec.iter() {
// for pkg in vec.iter() { // Clone data before async
// let name = pkg.name.clone(); let name = pkg.name.clone();
// let bytes = Arc::clone(&pkg.bytes); let bytes = Arc::clone(&pkg.bytes);
// let version = pkg.version.lock().unwrap(); let prog = Arc::clone(&pkg.prog);
// let link; let client = client.clone();
// if pkg.name == Name::Xmrig { let version = pkg.version.lock().unwrap().to_string();
// link = pkg.link_prefix.clone() + &version + &pkg.link_suffix_1 + &version[1..] + &pkg.link_suffix_2; let link;
// } else { // Download link = PREFIX + Version (found at runtime) + SUFFIX + Version + EXT
// link = pkg.link_prefix.clone() + &version + &pkg.link_suffix_1 + &version + &pkg.link_suffix_2; // Example: https://github.com/hinto-janaiyo/gupax/releases/download/v0.0.1/gupax-v0.0.1-linux-standalone-x64
// } // XMRig doesn't have a [v], so slice it out
// println!("download: {:#?} | {}", pkg.name, link); if pkg.name == Name::Xmrig {
// let request = Client::get(&client.clone(), &link); link = pkg.link_prefix.to_string() + &version + &pkg.link_suffix + &version[1..] + &pkg.link_extension;
// let handle: JoinHandle<()> = tokio::spawn(async move { // TODO FIX ME
// get_bytes(request, bytes, name).await; // This is temp link for v0.0.1 of [Gupax]
// }); } else if pkg.name == Name::Gupax {
// handles.push(handle); link = "https://github.com/hinto-janaiyo/gupax/releases/download/v0.0.1/gupax-v0.0.1-linux-x64".to_string()
// } } else {
// for handle in handles { link = pkg.link_prefix.to_string() + &version + &pkg.link_suffix + &version + &pkg.link_extension;
// handle.await.unwrap(); }
// } info!("Update | Download | {} ... {}", pkg.name, link);
// println!("download ... OK\n"); let request = Pkg::get_request(link)?;
// let handle: JoinHandle<()> = tokio::spawn(async move {
// // extract match client {
// let TMP = num(); ClientEnum::Tor(t) => Pkg::get_bytes(name, bytes, prog, t, request).await,
// std::fs::create_dir(&TMP).unwrap(); ClientEnum::Https(h) => Pkg::get_bytes(name, bytes, prog, h, request).await,
// for pkg in vec.iter() { };
// let name = TMP.to_string() + &pkg.name.to_string(); });
// println!("extract: {:#?} | {}", pkg.name, name); handles.push(handle);
// if pkg.name == Name::Gupax { }
// std::fs::OpenOptions::new().mode(0o700).create(true).write(true).open(&name); for handle in handles {
// std::fs::write(name, pkg.bytes.lock().unwrap().as_ref()).unwrap(); handle.await?;
// } else { }
// std::fs::create_dir(&name).unwrap(); info!("Update | Download ... OK");
// tar::Archive::new(flate2::read::GzDecoder::new(pkg.bytes.lock().unwrap().as_ref())).unpack(name).unwrap();
// } // Write to disk, extract
// } let tmp = Self::get_tmp_dir();
// println!("extract ... OK"); // std::fs::OpenOptions::new().mode(0o700).create(true).write(true).open(&tmp);
// std::fs::create_dir(&tmp)?;
//async fn get_bytes(request: RequestBuilder, bytes: Arc<Mutex<bytes::Bytes>>, name: Name) { info!("Update | Extract | Starting extraction...");
// *bytes.lock().unwrap() = request.send().await.unwrap().bytes().await.unwrap(); for pkg in vec.iter() {
// println!("{} download ... OK", name); let tmp = tmp.to_string() + &pkg.name.to_string();
//} if pkg.name == Name::Gupax {
// std::fs::write(tmp, pkg.bytes.lock().unwrap().as_ref())?;
//async fn func(request: RequestBuilder, version: Arc<Mutex<String>>, name: Name) { } else {
// let response = request.send().await.unwrap().bytes().await.unwrap(); tar::Archive::new(flate2::read::GzDecoder::new(pkg.bytes.lock().unwrap().as_ref())).unpack(tmp)?;
// }
// let mut bytes = flate2::read::GzDecoder::new(response.as_ref()); *pkg.prog.lock().unwrap() += 5;
// let mut response = String::new(); info!("Update | Extract | {} ... {}%", pkg.name, pkg.prog.lock().unwrap());
// bytes.read_to_string(&mut response).unwrap(); }
// info!("Update | Extract ... OK");
// let response: Version = serde_json::from_str(&response).unwrap(); std::process::exit(0);
// *version.lock().unwrap() = response.tag_name.clone(); Ok(())
// println!("{} {} ... OK", name, response.tag_name);
//}
} }
} }
@ -388,7 +387,7 @@ pub struct Pkg {
tmp_dir: String, tmp_dir: String,
prog: Arc<Mutex<u8>>, prog: Arc<Mutex<u8>>,
msg: Arc<Mutex<String>>, msg: Arc<Mutex<String>>,
bytes: Arc<Mutex<bytes::Bytes>>, bytes: Arc<Mutex<hyper::body::Bytes>>,
version: Arc<Mutex<String>>, version: Arc<Mutex<String>>,
} }
@ -439,9 +438,9 @@ impl Pkg {
Ok(request) Ok(request)
} }
// Get response using [Generic hyper::client<C>] & [Request] // Get metadata using [Generic hyper::client<C>] & [Request]
// and change [version, prog] under an Arc<Mutex> // and change [version, prog] under an Arc<Mutex>
pub async fn get_response<C>(name: Name, version: Arc<Mutex<String>>, prog: Arc<Mutex<u8>>, client: Client<C>, request: Request<Body>) -> Result<(), Error> pub async fn get_metadata<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, { 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?;
@ -451,6 +450,23 @@ impl Pkg {
info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap()); info!("Update | Metadata | {} {} ... {}%", name, body.tag_name, *prog.lock().unwrap());
Ok(()) Ok(())
} }
// Takes a [Request], fills the appropriate [Pkg]
// [bytes] field with the [Archive/Standalone]
pub async fn get_bytes<C>(name: Name, bytes: Arc<Mutex<bytes::Bytes>>, prog: Arc<Mutex<u8>>, client: Client<C>, request: Request<Body>) -> Result<(), anyhow::Error>
where C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, {
// GitHub sends a 302 redirect, so we must follow
// the [Location] header... only if Reqwest had custom
// connectors so I didn't have to manually do this...
let response = client.request(request).await?;
let request = Self::get_request(response.headers().get(hyper::header::LOCATION).unwrap().to_str()?.to_string())?;
let response = client.request(request).await?;
let body = hyper::body::to_bytes(response.into_body()).await?;
*bytes.lock().unwrap() = body;
*prog.lock().unwrap() += 10;
info!("Update | Download | {} ... {}%", name, *prog.lock().unwrap());
Ok(())
}
} }
// This inherits the value of [tag_name] from GitHub's JSON API // This inherits the value of [tag_name] from GitHub's JSON API