- Move User-Agent to reqwest client initialization
- Improve desktop path detection
- Run pipelines in parallel
This commit is contained in:
Michael Pfaff 2022-06-10 17:21:04 -04:00
parent 1c798dbcae
commit 4ad392d83a
Signed by: michael
GPG Key ID: CF402C4A012AA9D4
4 changed files with 57 additions and 26 deletions

1
Cargo.lock generated
View File

@ -842,6 +842,7 @@ name = "school-computer-toolkit"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dirs", "dirs",
"futures-util",
"miette", "miette",
"ramhorns", "ramhorns",
"reqwest", "reqwest",

View File

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
dirs = "4" dirs = "4"
futures-util = { version = "0.3.21", default-features = false, features = [ "alloc" ] }
miette = { version = "4.7", features = [ "fancy" ] } miette = { version = "4.7", features = [ "fancy" ] }
ramhorns = "0.14" ramhorns = "0.14"
reqwest = { version = "0.11.10", features = [ "json" ] } reqwest = { version = "0.11.10", features = [ "json" ] }

View File

@ -6,9 +6,6 @@ use tokio::io::AsyncWriteExt;
use crate::Context; use crate::Context;
const USER_AGENT_STR: &'static str =
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
/// A sequential pipeline of [`Step`]s. /// A sequential pipeline of [`Step`]s.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Pipeline<'a> { pub struct Pipeline<'a> {
@ -114,7 +111,6 @@ impl<'a> Step<'a> {
let mut resp = ctx let mut resp = ctx
.reqwest .reqwest
.get(url) .get(url)
.header("User-Agent", USER_AGENT_STR)
.send() .send()
.await .await
.into_diagnostic() .into_diagnostic()
@ -344,7 +340,6 @@ async fn fetch_latest_release<'a, 'b>(
.wrap_err("Invalid GitHub repo for download step.")?; .wrap_err("Invalid GitHub repo for download step.")?;
let mut resp = reqwest let mut resp = reqwest
.get(url) .get(url)
.header("User-Agent", USER_AGENT_STR)
.send() .send()
.await .await
.into_diagnostic() .into_diagnostic()

View File

@ -14,20 +14,26 @@ use install::{Pipeline, RemoteResource, ShortcutTarget, Step};
const SWTOOLS_PATH: &'static str = "C:\\SWTools"; const SWTOOLS_PATH: &'static str = "C:\\SWTools";
const USER_AGENT_STR: &'static str =
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
pub fn swtools_path() -> &'static Path { pub fn swtools_path() -> &'static Path {
Path::new(SWTOOLS_PATH) Path::new(SWTOOLS_PATH)
} }
pub fn desktop_path() -> PathBuf { pub fn desktop_path_fallible() -> Option<PathBuf> {
let mut dir = dirs::home_dir() dirs::desktop_dir()
.expect("Could not find your home directory.") .filter(|dir| dir.exists())
.join("Desktop"); .or_else(|| Some(Path::new("H:\\Profile\\Desktop").to_owned()))
if !dir.exists() { .filter(|dir| dir.exists())
dir = Path::new("H:\\Profile\\Desktop").to_owned(); .or_else(|| dirs::home_dir().map(|dir| dir.join("Desktop")))
}
dir
} }
pub fn desktop_path() -> PathBuf {
desktop_path_fallible().expect("Desktop directory should have been resolved by now.")
}
#[derive(Clone)]
pub struct Context { pub struct Context {
pub reqwest: reqwest::Client, pub reqwest: reqwest::Client,
} }
@ -44,7 +50,7 @@ async fn main() -> Result<()> {
bail!("Could not find or access {}", SWTOOLS_PATH); bail!("Could not find or access {}", SWTOOLS_PATH);
} }
if !desktop_path().exists() { if desktop_path_fallible().is_none() {
bail!("Could not find your desktop directory."); bail!("Could not find your desktop directory.");
} }
@ -59,20 +65,20 @@ async fn main() -> Result<()> {
let psiphon_dir = swtools_path().join("psiphon"); let psiphon_dir = swtools_path().join("psiphon");
let psiphon_bin = psiphon_dir.join("psiphon3.exe"); let psiphon_bin = psiphon_dir.join("psiphon3.exe");
let utilities = [ let pipelines = [
Pipeline::new( Pipeline::new(
"Install Notepad++", "Install Notepad++",
vec![ vec![
Step::DownloadFile { Step::DownloadFile {
file: nppp_zip.as_path().into(), file: nppp_zip.clone().into(),
res: RemoteResource::GitHubArtifact { res: RemoteResource::GitHubArtifact {
repo: "notepad-plus-plus/notepad-plus-plus", repo: "notepad-plus-plus/notepad-plus-plus",
pattern: "npp.{{tag_name_strip_prefix}}.portable.x64.zip", pattern: "npp.{{tag_name_strip_prefix}}.portable.x64.zip",
}, },
}, },
Step::ExtractFile { Step::ExtractFile {
file: nppp_zip.as_path().into(), file: nppp_zip.clone().into(),
dest: nppp_dir.as_path().into(), dest: nppp_dir.clone().into(),
}, },
Step::CreateShortcut { Step::CreateShortcut {
target: ShortcutTarget::Executable { target: ShortcutTarget::Executable {
@ -88,14 +94,14 @@ async fn main() -> Result<()> {
"Install Explorer++", "Install Explorer++",
vec![ vec![
Step::DownloadFile { Step::DownloadFile {
file: epp_zip.as_path().into(), file: epp_zip.clone().into(),
res: RemoteResource::Url( res: RemoteResource::Url(
"https://explorerplusplus.com/software/explorer++_1.3.5_x64.zip", "https://explorerplusplus.com/software/explorer++_1.3.5_x64.zip",
), ),
}, },
Step::ExtractFile { Step::ExtractFile {
file: epp_zip.as_path().into(), file: epp_zip.clone().into(),
dest: epp_dir.as_path().into(), dest: epp_dir.clone().into(),
}, },
Step::CreateShortcut { Step::CreateShortcut {
target: ShortcutTarget::Executable { target: ShortcutTarget::Executable {
@ -111,14 +117,14 @@ async fn main() -> Result<()> {
"Install Psiphon VPN", "Install Psiphon VPN",
vec![ vec![
Step::DownloadFile { Step::DownloadFile {
file: psiphon_bin.as_path().into(), file: psiphon_bin.clone().into(),
res: RemoteResource::Url( res: RemoteResource::Url(
"https://s3.amazonaws.com/f58p-mqce-k1yj/psiphon3.exe", "https://s3.amazonaws.com/f58p-mqce-k1yj/psiphon3.exe",
), ),
}, },
Step::CreateShortcut { Step::CreateShortcut {
target: ShortcutTarget::Executable { target: ShortcutTarget::Executable {
file: psiphon_bin.as_path().into(), file: psiphon_bin.clone().into(),
args: "", args: "",
}, },
file: desktop_path().join("Psiphon3.lnk").into(), file: desktop_path().join("Psiphon3.lnk").into(),
@ -166,14 +172,42 @@ async fn main() -> Result<()> {
let ctx = Context { let ctx = Context {
reqwest: reqwest::Client::builder() reqwest: reqwest::Client::builder()
.user_agent(USER_AGENT_STR)
.build() .build()
.into_diagnostic() .into_diagnostic()
.wrap_err("Could not initialize HTTP client.")?, .wrap_err("Could not initialize HTTP client.")?,
}; };
for utility in utilities { let results = futures_util::future::join_all(
utility.invoke(&ctx).await?; pipelines
.into_iter()
.map(|pipeline| tokio::spawn({
let ctx = ctx.clone();
async move {
pipeline.invoke(&ctx).await
}
})),
)
.await;
let results = results
.into_iter()
.map(|result| match result.into_diagnostic().wrap_err("Task error.") {
Ok(Ok(t)) => Ok(t),
Ok(Err(e)) => Err(e),
Err(e) => Err(e),
});
let mut had_error = false;
for result in results {
if let Err(e) = result {
had_error = true;
eprintln!("{e:?}");
}
} }
Ok(()) if had_error {
Err(miette!("One or more errors in pipelines."))
} else {
Ok(())
}
} }