diff options
| author | 2025-01-13 20:58:36 -0600 | |
|---|---|---|
| committer | 2025-01-13 20:58:36 -0600 | |
| commit | ff428f36935cefd2b6d8ea6ba4a0572d75d6512d (patch) | |
| tree | cf8b71137247ba74c4a606146d45ec2791725877 /src/launcher | |
| parent | more stuff (diff) | |
library downloads complete
Diffstat (limited to 'src/launcher')
| -rw-r--r-- | src/launcher/download.rs | 4 | ||||
| -rw-r--r-- | src/launcher/rules.rs | 114 | ||||
| -rw-r--r-- | src/launcher/version.rs | 13 |
3 files changed, 126 insertions, 5 deletions
diff --git a/src/launcher/download.rs b/src/launcher/download.rs index ec89a15..813117c 100644 --- a/src/launcher/download.rs +++ b/src/launcher/download.rs @@ -206,6 +206,10 @@ impl VerifiedDownload { self } + pub fn get_path(&self) -> &Path { + &self.path + } + pub async fn make_dirs(&self) -> Result<(), io::Error> { fs::create_dir_all(self.path.parent().expect("download created with no containing directory (?)")).await } diff --git a/src/launcher/rules.rs b/src/launcher/rules.rs new file mode 100644 index 0000000..29da8a2 --- /dev/null +++ b/src/launcher/rules.rs @@ -0,0 +1,114 @@ +use std::error::Error; +use std::fmt::Display; +use crate::version::{Argument, CompatibilityRule, CompleteVersion, FeatureMatcher, Library, OSRestriction, RuleAction}; +use super::SystemInfo; + +#[derive(Debug)] +pub struct IncompatibleError { + what: &'static str, + reason: Option<String> +} + +impl Display for IncompatibleError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if let Some(reason) = self.reason.as_ref() { + write!(f, "{} incompatible: {}", self.what, reason) + } else { + write!(f, "{} incompatible", self.what) + } + } +} + +impl Error for IncompatibleError {} + +mod seal { + pub trait CompatCheckInner { + const WHAT: &'static str; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &super::CompatibilityRule>>; + fn get_incompatibility_reason(&self) -> Option<&str>; + } +} + +pub trait CompatCheck: seal::CompatCheckInner { + fn rules_apply<'a>(&'a self, system: &SystemInfo, feature_matcher: impl FeatureMatcher<'a>) -> Result<(), IncompatibleError> { + let Some(rules) = self.get_rules() else { return Ok(()) }; + let mut action = RuleAction::Disallow; + + fn match_os(os: &OSRestriction, system: &SystemInfo) -> bool { + os.os.is_none_or(|o| system.is_our_os(o)) + && os.version.as_ref().is_none_or(|v| v.is_match(system.os_version.as_str())) + && os.arch.as_ref().is_none_or(|a| a.is_match(system.arch.as_str())) + } + + for rule in rules { + if rule.os.as_ref().is_none_or(|o| match_os(o, system)) + && rule.features_match(feature_matcher) { + action = rule.action; + } + } + + if action == RuleAction::Disallow { + Err(IncompatibleError { + what: Self::WHAT, + reason: self.get_incompatibility_reason().map(|s| s.to_owned()) + }) + } else { + Ok(()) + } + } +} + +// trivial +impl seal::CompatCheckInner for CompatibilityRule { + const WHAT: &'static str = "rule"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + Some(Some(self)) + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + None + } +} + +impl seal::CompatCheckInner for CompleteVersion { + const WHAT: &'static str = "version"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + self.compatibility_rules.as_ref() + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + self.incompatibility_reason.as_ref().map(|s| s.as_str()) + } +} + +impl seal::CompatCheckInner for Library { + const WHAT: &'static str = "library"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + self.rules.as_ref() + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + None + } +} + +impl seal::CompatCheckInner for Argument { + const WHAT: &'static str = "argument"; + + fn get_rules(&self) -> Option<impl IntoIterator<Item = &CompatibilityRule>> { + self.rules.as_ref() + } + + fn get_incompatibility_reason(&self) -> Option<&str> { + None + } +} + +impl CompatCheck for CompatibilityRule {} +impl CompatCheck for CompleteVersion {} +impl CompatCheck for Library {} +impl CompatCheck for Argument {}
\ No newline at end of file diff --git a/src/launcher/version.rs b/src/launcher/version.rs index 411ac59..40bb953 100644 --- a/src/launcher/version.rs +++ b/src/launcher/version.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; use std::fmt::Display; use std::path::{Path, PathBuf}; -use log::{debug, info, warn}; +use log::{debug, info, trace, warn}; use sha1_smol::Digest; use tokio::{fs, io}; use crate::util; @@ -51,19 +51,22 @@ impl RemoteVersionList { // download it let ver_text = reqwest::get(ver.url.as_str()).await?.error_for_status()?.text().await?; - + debug!("Validating downloaded {}...", ver.id); // make sure it's valid util::verify_sha1(ver.sha1, ver_text.as_str()) .map_err::<Box<dyn Error>, _>(|e| format!("downloaded version {} has wrong hash! (expect {}, got {})", ver.id.as_str(), &ver.sha1, e).as_str().into())?; - + // make sure it's well-formed - let cver: CompleteVersion = serde_json::from_str(ver.url.as_str())?; + let cver: CompleteVersion = serde_json::from_str(ver_text.as_str())?; debug!("Saving version {}...", ver.id); // write it out - tokio::fs::write(path, ver_text).await?; + tokio::fs::write(path, ver_text).await.map_err(|e| { + warn!("Failed to save version {}: {}", ver.id, e); + e + })?; info!("Done downloading and verifying {}!", ver.id); |
