summaryrefslogtreecommitdiffstats
path: root/src/launcher.rs
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-01-22 02:08:31 -0600
committerLibravatar bigfoot547 <[email protected]>2025-01-22 02:10:20 -0600
commite88c17a44c94f788e945c5728bc18beca7e0f8a6 (patch)
tree586873a545cb6bc799129219d5e809106daa58c1 /src/launcher.rs
parentsupport 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.rs115
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 {