diff options
| author | 2025-01-22 02:08:31 -0600 | |
|---|---|---|
| committer | 2025-01-22 02:10:20 -0600 | |
| commit | e88c17a44c94f788e945c5728bc18beca7e0f8a6 (patch) | |
| tree | 586873a545cb6bc799129219d5e809106daa58c1 /src/launcher.rs | |
| parent | support jre specified in profile (diff) | |
get started on downloading JREs
also refactor ensure file logic
Diffstat (limited to 'src/launcher.rs')
| -rw-r--r-- | src/launcher.rs | 115 |
1 files changed, 12 insertions, 103 deletions
diff --git a/src/launcher.rs b/src/launcher.rs index f8be78b..19a9fa7 100644 --- a/src/launcher.rs +++ b/src/launcher.rs @@ -7,6 +7,7 @@ mod assets; mod extract; mod settings; mod runner; +mod jre; use std::borrow::Cow; use std::cmp::min; @@ -24,11 +25,8 @@ use const_format::formatcp; use futures::{StreamExt, TryStreamExt}; use log::{debug, info, trace, warn}; use reqwest::Client; -use sha1_smol::Sha1; use sysinfo::System; use tokio::{fs, io}; -use tokio::fs::File; -use tokio::io::AsyncWriteExt; use tokio_stream::wrappers::ReadDirStream; use download::{MultiDownloader, VerifiedDownload}; use rules::{CompatCheck, IncompatibleError}; @@ -36,13 +34,14 @@ use version::{VersionList, VersionResolveError, VersionResult}; use crate::version::{Logging, Library, OSRestriction, OperatingSystem, DownloadType, DownloadInfo, LibraryExtractRule, CompleteVersion, FeatureMatcher}; use assets::{AssetError, AssetRepository}; -use crate::util::{self, AsJavaPath, FileVerifyError, IntegrityError}; +use crate::util::{self, AsJavaPath}; pub use settings::*; pub use runner::run_the_game; +pub use crate::util::{EnsureFileError, FileVerifyError, IntegrityError}; use crate::assets::AssetIndex; -use crate::launcher::runner::ArgumentType; -use crate::launcher::strsub::SubFunc; +use runner::ArgumentType; +use strsub::SubFunc; use crate::version::manifest::VersionType; #[derive(Debug)] @@ -126,11 +125,8 @@ pub enum LaunchError { LibraryClasspathError(JoinPathsError), // ensure file errors - MissingURL, + EnsureFile(EnsureFileError), IO { what: &'static str, error: io::Error }, - Offline, - Download { url: String, error: reqwest::Error }, - Integrity(IntegrityError), // log errors UnknownLogType(String), @@ -158,11 +154,8 @@ impl Display for LaunchError { LaunchError::LibraryDownloadError => f.write_str("library download failed (see above logs for details)"), // TODO: booo this sucks LaunchError::LibraryExtractError(e) => write!(f, "library extract zip error: {e}"), LaunchError::LibraryClasspathError(e) => write!(f, "error building classpath: {e}"), - LaunchError::MissingURL => f.write_str("cannot download required file, URL is missing"), LaunchError::IO { what, error } => write!(f, "i/o error ({}): {}", what, error), - LaunchError::Offline => f.write_str("cannot download file in offline mode"), - LaunchError::Download { url, error } => write!(f, "failed to download file ({}): {}", url, error), - LaunchError::Integrity(e) => write!(f, "file verify error: {}", e), + LaunchError::EnsureFile(e) => e.fmt(f), LaunchError::UnknownLogType(t) => write!(f, "unknown log type: {}", t), LaunchError::InvalidLogId(Some(id)) => write!(f, "invalid log id: {}", id), LaunchError::InvalidLogId(None) => write!(f, "missing log id"), @@ -184,8 +177,7 @@ impl Error for LaunchError { LaunchError::LibraryExtractError(e) => Some(e), LaunchError::LibraryClasspathError(e) => Some(e), LaunchError::IO { error: e, .. } => Some(e), - LaunchError::Download { error: e, .. } => Some(e), - LaunchError::Integrity(e) => Some(e), + LaunchError::EnsureFile(e) => Some(e), LaunchError::Assets(e) => Some(e), LaunchError::ResolveJavaRuntime { error: e, .. } => Some(e), _ => None @@ -272,91 +264,6 @@ impl Launcher { lib.natives.as_ref().map_or(None, |n| n.get(&self.system_info.os)).map(|s| s.as_str()) } - async fn ensure_file(&self, path: &Path, dlinfo: &DownloadInfo) -> Result<(), LaunchError> { - // verify the file - match util::verify_file(path, dlinfo.size, dlinfo.sha1).await { - // integrity passed. return - Ok(_) => { - info!("File {} exists and integrity matches. Skipping.", path.display()); - return Ok(()); - }, - - // ruh roh - Err(e) => match e { - FileVerifyError::Open(_, ioe) if ioe.kind() != ErrorKind::NotFound => - return Err(LaunchError::IO{ what: "verify file (open)", error: ioe }), - FileVerifyError::Read(_, ioe) => return Err(LaunchError::IO{ what: "verify file (read)", error: ioe }), - FileVerifyError::Integrity(_, ie) => info!("file {} failed integrity check: {}", path.display(), ie), - _ => () - } - } - - if !self.online { - warn!("Cannot download file {}! We are offline. Rerun the launcher in online mode to launch this version.", path.display()); - return Err(LaunchError::Offline); - } - - // download it - let Some(url) = dlinfo.url.as_ref() else { - return Err(LaunchError::MissingURL); - }; - - let mut file = File::create(path).await.map_err(|e| LaunchError::IO { - what: "save downloaded file (open)", - error: e - })?; - - debug!("File {} must be downloaded ({}).", path.display(), url); - - let mut response = reqwest::get(url).await.map_err(|e| LaunchError::Download{ url: url.to_owned(), error: e })?; - let mut tally = 0usize; - let mut sha1 = Sha1::new(); - - while let Some(chunk) = response.chunk().await.map_err(|e| LaunchError::Download{ url: url.to_owned(), error: e })? { - let slice = chunk.as_ref(); - - file.write_all(slice).await.map_err(|e| LaunchError::IO { - what: "save downloaded file (write)", - error: e - })?; - - tally += slice.len(); - sha1.update(slice); - } - - drop(file); // manually close file - - let del_file_silent = || async { - debug!("Deleting downloaded file {} since its integrity doesn't match :(", path.display()); - let _ = fs::remove_file(path).await.map_err(|e| warn!("failed to delete invalid downloaded file: {}", e)); - () - }; - - if dlinfo.size.is_some_and(|s| s != tally) { - del_file_silent().await; - - return Err(LaunchError::Integrity(IntegrityError::SizeMismatch { - expect: dlinfo.size.unwrap(), - actual: tally - })); - } - - let digest = sha1.digest(); - - if dlinfo.sha1.is_some_and(|exp_dig| exp_dig != digest) { - del_file_silent().await; - - return Err(LaunchError::Integrity(IntegrityError::Sha1Mismatch { - expect: dlinfo.sha1.unwrap(), - actual: digest - })); - } - - info!("File {} downloaded successfully.", path.display()); - - Ok(()) - } - async fn log_config_ensure(&self, config: &Logging) -> Result<String, LaunchError> { info!("Ensuring log configuration exists and is valid."); @@ -381,7 +288,8 @@ impl Launcher { debug!("Logger config {} is at {}", id, path.display()); - self.ensure_file(&path, dlinfo).await?; + util::ensure_file(&path, dlinfo.url.as_ref().map(|s| s.as_str()), dlinfo.size, dlinfo.sha1, self.online).await + .map_err(|e| LaunchError::EnsureFile(e))?; struct PathSub<'a>(&'a Path); impl<'a> SubFunc<'a> for PathSub<'a> { @@ -535,7 +443,8 @@ impl Launcher { info!("Downloading client jar {}", client_path.display()); - self.ensure_file(client_path.as_path(), client).await?; + util::ensure_file(client_path.as_path(), client.url.as_ref().map(|s| s.as_str()), client.size, client.sha1, self.online).await + .map_err(|e| LaunchError::EnsureFile(e))?; client_jar_path = Some(client_path); } else { |
