summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ozone-cli/src/main.rs2
-rw-r--r--ozone/src/launcher.rs12
-rw-r--r--ozone/src/launcher/settings.rs2
-rw-r--r--ozone/src/launcher/version.rs86
4 files changed, 49 insertions, 53 deletions
diff --git a/ozone-cli/src/main.rs b/ozone-cli/src/main.rs
index d18e9b8..adfeb71 100644
--- a/ozone-cli/src/main.rs
+++ b/ozone-cli/src/main.rs
@@ -5,7 +5,7 @@ use std::process::ExitCode;
use log::{error, info, trace};
use clap::Parser;
use ozone::launcher::{Launcher, Settings};
-
+use ozone::launcher::version::VersionList;
use crate::cli::{Cli, ProfileCommand, RootCommand};
async fn main_inner(cli: Cli) -> Result<ExitCode, Box<dyn Error>> {
diff --git a/ozone/src/launcher.rs b/ozone/src/launcher.rs
index 0916fd8..6feeab5 100644
--- a/ozone/src/launcher.rs
+++ b/ozone/src/launcher.rs
@@ -260,11 +260,7 @@ impl Launcher {
let versions_home = home.join("versions");
debug!("Version list online?: {online}");
- let versions = if online {
- VersionList::online(versions_home.as_ref()).await.map_err(LaunchError::VersionInit)?
- } else {
- VersionList::offline(versions_home.as_ref()).await.map_err(LaunchError::VersionInit)?
- };
+ let versions = VersionList::new(&versions_home, online).await.map_err(LaunchError::VersionInit)?;
let assets_path = home.join("assets");
@@ -337,11 +333,7 @@ impl Launcher {
let feature_matcher = ProfileFeatureMatcher { profile };
let version_id = profile.get_version();
- let Some(version_id) = self.versions.get_profile_version_id(version_id) else {
- // idk how common this use case actually is
- warn!("Can't use latest release/snapshot profiles while offline!");
- return Err(LaunchError::UnknownVersion("<latest>".into()));
- };
+ let version_id = self.versions.get_profile_version_id(version_id);
info!("Preparing launch for \"{}\"...", version_id);
diff --git a/ozone/src/launcher/settings.rs b/ozone/src/launcher/settings.rs
index c9f2dd5..c480c33 100644
--- a/ozone/src/launcher/settings.rs
+++ b/ozone/src/launcher/settings.rs
@@ -31,7 +31,7 @@ pub struct SettingsData {
impl SettingsData {
fn check_consistent(&self) -> Result<(), String> {
- if let Some((name, profile)) = self.profiles.iter().find(|(name, profile)| !self.instances.contains_key(&profile.instance)) {
+ if let Some((name, profile)) = self.profiles.iter().find(|(_, profile)| !self.instances.contains_key(&profile.instance)) {
return Err(format!("profile {} refers to instance {}, which does not exist.", name, &profile.instance));
}
diff --git a/ozone/src/launcher/version.rs b/ozone/src/launcher/version.rs
index c7268db..a5369b9 100644
--- a/ozone/src/launcher/version.rs
+++ b/ozone/src/launcher/version.rs
@@ -1,10 +1,9 @@
use std::{collections::{BTreeMap, HashMap}, error::Error, io::ErrorKind};
use std::borrow::Cow;
use std::collections::HashSet;
-use std::fmt::Display;
+use std::fmt::{Display, Write};
use std::path::{Path, PathBuf};
use chrono::{DateTime, TimeDelta, Utc};
-use futures::TryFutureExt;
use log::{debug, info, warn};
use serde::{Deserialize, Serialize};
use sha1_smol::{Digest, Sha1};
@@ -20,7 +19,8 @@ pub enum VersionError {
IO { what: String, error: io::Error },
Request { what: String, error: reqwest::Error },
MalformedObject { what: String, error: serde_json::Error },
- VersionIntegrity { id: String, expect: Digest, got: Digest }
+ VersionIntegrity { id: String, expect: Digest, got: Digest },
+ Offline
}
impl Display for VersionError {
@@ -29,7 +29,8 @@ impl Display for VersionError {
VersionError::IO { what, error } => write!(f, "i/o error ({what}): {error}"),
VersionError::Request { what, error } => write!(f, "request error ({what}): {error}"),
VersionError::MalformedObject { what, error } => write!(f, "malformed {what}: {error}"),
- VersionError::VersionIntegrity { id, expect, got } => write!(f, "version {id} integrity mismatch (expect {expect}, got {got})")
+ VersionError::VersionIntegrity { id, expect, got } => write!(f, "version {id} integrity mismatch (expect {expect}, got {got})"),
+ VersionError::Offline => f.write_str("launcher is offline"),
}
}
}
@@ -47,7 +48,8 @@ impl Error for VersionError {
struct RemoteVersionList {
versions: HashMap<String, VersionManifestVersion>,
- latest: LatestVersions
+ latest: LatestVersions,
+ online: bool
}
#[derive(Serialize, Deserialize, Debug)]
@@ -63,7 +65,7 @@ const MANIFEST_CACHE_PATH: &str = ".manifest.json";
impl RemoteVersionList {
// errors from this function are fatal so if it's not a super duper bad error then log and ignore it
- async fn load_cached_manifest(home: impl AsRef<Path>) -> Result<Option<VersionManifest>, VersionError> {
+ async fn load_cached_manifest(home: impl AsRef<Path>, online: bool) -> Result<Option<VersionManifest>, VersionError> {
let home = home.as_ref();
let cache_info = match fs::read_to_string(home.join(MANIFEST_CACHE_INFO_PATH)).await {
Ok(s) => s,
@@ -81,7 +83,7 @@ impl RemoteVersionList {
};
let now = Utc::now();
- if now.signed_duration_since(cache_info.last_download) > MANIFEST_CACHE_MAX_AGE {
+ if online && now.signed_duration_since(cache_info.last_download) > MANIFEST_CACHE_MAX_AGE {
debug!("Cached version manifest is older than maximum age. Redownloading.");
return Ok(None);
}
@@ -113,15 +115,22 @@ impl RemoteVersionList {
}
};
+ debug!("Using cached version manifest.");
+
Ok(Some(manifest))
}
- async fn load_manifest(home: impl AsRef<Path>) -> Result<VersionManifest, VersionError> {
+ async fn load_manifest(home: impl AsRef<Path>, online: bool) -> Result<VersionManifest, VersionError> {
let home = home.as_ref();
- if let Some(manifest) = Self::load_cached_manifest(home).await? {
+ if let Some(manifest) = Self::load_cached_manifest(home, online).await? {
return Ok(manifest);
}
+ if !online {
+ warn!("Can't download version manifest while offline. Please rerun the launcher in online mode.");
+ return Err(VersionError::Offline);
+ }
+
debug!("Will download version manifest, since we couldn't load the cached version.");
let manifest_str = util::create_client().get(URL_VERSION_MANIFEST)
@@ -164,8 +173,8 @@ impl RemoteVersionList {
Ok(manifest)
}
- async fn new(home: impl AsRef<Path>) -> Result<RemoteVersionList, VersionError> {
- let manifest: VersionManifest = Self::load_manifest(&home).await?;
+ async fn new(home: impl AsRef<Path>, online: bool) -> Result<RemoteVersionList, VersionError> {
+ let manifest: VersionManifest = Self::load_manifest(&home, online).await?;
let mut versions = HashMap::new();
for v in manifest.versions {
@@ -175,11 +184,14 @@ impl RemoteVersionList {
debug!("Done loading remote versions!");
Ok(RemoteVersionList {
versions,
- latest: manifest.latest
+ latest: manifest.latest,
+ online
})
}
async fn download_version(&self, ver: &VersionManifestVersion, path: &Path) -> Result<CompleteVersion, VersionError> {
+ assert!(self.online, "download_version called in offline mode");
+
// ensure parent directory exists
info!("Downloading version {}.", ver.id);
tokio::fs::create_dir_all(path.parent().expect("version .json has no parent (impossible)")).await
@@ -329,7 +341,8 @@ impl LocalVersionList {
}
pub struct VersionList {
- remote: Option<RemoteVersionList>,
+ online: bool,
+ remote: RemoteVersionList,
local: LocalVersionList,
home: PathBuf
}
@@ -390,58 +403,44 @@ impl VersionList {
}
}
- pub async fn online(home: &Path) -> Result<VersionList, VersionError> {
+ pub async fn new(home: impl AsRef<Path>, online: bool) -> Result<VersionList, VersionError> {
+ let home = home.as_ref();
Self::create_dir_for(home).await.map_err(|e| VersionError::IO { what: format!("create version directory {}", home.display()), error: e })?;
- let remote = RemoteVersionList::new(home).await?;
+ let remote = RemoteVersionList::new(home, online).await?;
let local = LocalVersionList::load_versions(home, |s| remote.versions.contains_key(s)).await?;
Ok(VersionList {
- remote: Some(remote),
- local,
- home: home.to_path_buf()
- })
- }
-
- pub async fn offline(home: &Path) -> Result<VersionList, VersionError> {
- Self::create_dir_for(home).await.map_err(|e| VersionError::IO { what: format!("create version directory {}", home.display()), error: e })?;
-
- let local = LocalVersionList::load_versions(home, |_| false).await?;
-
- Ok(VersionList {
- remote: None,
+ online,
+ remote,
local,
home: home.to_path_buf()
})
}
pub fn is_online(&self) -> bool {
- self.remote.is_some()
+ self.online
}
pub fn get_version_lazy(&self, id: &str) -> VersionResult {
- self.remote.as_ref().and_then(|r| r.versions.get(id).map(VersionResult::from))
+ self.remote.versions.get(id).map(VersionResult::from)
.or_else(|| self.local.versions.get(id).map(VersionResult::from))
.unwrap_or(VersionResult::None)
}
- pub fn get_profile_version_id<'v>(&self, ver: &'v ProfileVersion) -> Option<Cow<'v, str>> {
+ pub fn get_profile_version_id<'v>(&self, ver: &'v ProfileVersion) -> Cow<'v, str> {
match ver {
- ProfileVersion::LatestRelease => self.remote.as_ref().map(|r| Cow::Owned(r.latest.release.clone())),
- ProfileVersion::LatestSnapshot => self.remote.as_ref().map(|r| Cow::Owned(r.latest.snapshot.clone())),
- ProfileVersion::Specific(ver) => Some(Cow::Borrowed(ver))
+ ProfileVersion::LatestRelease => self.remote.latest.release.clone().into(),
+ ProfileVersion::LatestSnapshot => self.remote.latest.snapshot.clone().into(),
+ ProfileVersion::Specific(ver) => Cow::Borrowed(ver)
}
}
pub fn get_remote_version(&self, id: &str) -> Option<&VersionManifestVersion> {
- let remote = self.remote.as_ref().expect("get_remote_version called in offline mode!");
-
- remote.versions.get(id)
+ self.remote.versions.get(id)
}
pub async fn load_remote_version(&self, ver: &VersionManifestVersion) -> Result<CompleteVersion, VersionError> {
- let remote = self.remote.as_ref().expect("load_remote_version called in offline mode!");
-
let id = ver.id.as_str();
let mut ver_path = self.home.join(id);
ver_path.push(format!("{id}.json"));
@@ -451,11 +450,16 @@ impl VersionList {
match LocalVersionList::load_version(ver_path.as_path(), Some(ver.sha1)).await {
Ok(v) => return Ok(v),
Err(e) => {
- info!("Redownloading {id}, since the local copy could not be loaded: {e}");
+ if self.online {
+ info!("Redownloading {id}, since the local copy could not be loaded: {e}");
+ } else {
+ warn!("Cannot download {id} (unable to load local copy: {e}). The launcher is offline.");
+ return Err(VersionError::Offline);
+ }
}
}
- remote.download_version(ver, ver_path.as_path()).await
+ self.remote.download_version(ver, ver_path.as_path()).await
}
pub async fn resolve_version<'v>(&self, ver: &'v CompleteVersion) -> Result<Cow<'v, CompleteVersion>, VersionResolveError> {