summaryrefslogtreecommitdiffstats
path: root/src/launcher
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-01-13 20:58:36 -0600
committerLibravatar bigfoot547 <[email protected]>2025-01-13 20:58:36 -0600
commitff428f36935cefd2b6d8ea6ba4a0572d75d6512d (patch)
treecf8b71137247ba74c4a606146d45ec2791725877 /src/launcher
parentmore stuff (diff)
library downloads complete
Diffstat (limited to 'src/launcher')
-rw-r--r--src/launcher/download.rs4
-rw-r--r--src/launcher/rules.rs114
-rw-r--r--src/launcher/version.rs13
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);