diff options
| author | 2025-01-15 19:45:33 -0600 | |
|---|---|---|
| committer | 2025-01-15 19:45:33 -0600 | |
| commit | cfc87ea505a330f727440b12c6b882de03df5baf (patch) | |
| tree | 46c68626f86a68875487b5f1313da882f93ae3e4 /src | |
| parent | get started on assets (diff) | |
wip: asset index
Diffstat (limited to 'src')
| -rw-r--r-- | src/launcher.rs | 1 | ||||
| -rw-r--r-- | src/launcher/assets.rs | 114 |
2 files changed, 115 insertions, 0 deletions
diff --git a/src/launcher.rs b/src/launcher.rs index 970386a..184bcae 100644 --- a/src/launcher.rs +++ b/src/launcher.rs @@ -4,6 +4,7 @@ mod profile; mod strsub; mod download; mod rules; +mod assets; use std::borrow::Cow; use std::collections::HashMap; diff --git a/src/launcher/assets.rs b/src/launcher/assets.rs new file mode 100644 index 0000000..020885f --- /dev/null +++ b/src/launcher/assets.rs @@ -0,0 +1,114 @@ +use std::error::Error;
+use std::fmt::{Display, Formatter, Write};
+use std::io::ErrorKind;
+use std::path::{Path, PathBuf};
+use std::path::Component::Normal;
+use log::{debug, info, warn};
+use tokio::{fs, io};
+use crate::assets::AssetIndex;
+use crate::util;
+use crate::util::FileVerifyError;
+use crate::version::DownloadInfo;
+
+const INDEX_PATH: &'static str = "indexes";
+const OBJECT_PATH: &'static str = "objects";
+
+pub struct AssetRepository {
+ online: bool,
+ home: PathBuf
+}
+
+#[derive(Debug)]
+pub enum AssetError {
+ InvalidId(Option<String>),
+ IO { what: &'static str, error: io::Error }
+}
+
+impl Display for AssetError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AssetError::InvalidId(None) => f.write_str("missing asset index id"),
+ AssetError::InvalidId(Some(id)) => write!(f, "invalid asset index id: {}", id),
+ AssetError::IO { what, error } => write!(f, "i/o error ({}): {}", what, error)
+ }
+ }
+}
+
+impl Error for AssetError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ AssetError::IO { error, .. } => Some(error),
+ _ => None
+ }
+ }
+}
+
+impl From<(&'static str, io::Error)> for AssetError {
+ fn from((what, error): (&'static str, io::Error)) -> Self {
+ AssetError::IO { what, error }
+ }
+}
+
+impl AssetRepository {
+ pub async fn new(online: bool, home: impl AsRef<Path>) -> Result<AssetRepository, io::Error> {
+ let home = home.as_ref().to_owned();
+
+ match fs::create_dir_all(&home).await {
+ Ok(_) => (),
+ Err(e) => match e.kind() {
+ ErrorKind::AlreadyExists => (),
+ _ => return Err(e)
+ }
+ };
+
+ Ok(AssetRepository {
+ online,
+ home
+ })
+ }
+
+ fn get_index_path(&self, id: &str) -> Result<PathBuf, AssetError> {
+ let indexes_path: &Path = (&self.home, INDEX_PATH).as_ref();
+ let Some(Normal(path)) = Path::new(id).components().last() else {
+ return Err(AssetError::InvalidId(id.into()));
+ };
+
+ let path = path.to_str().ok_or(AssetError::InvalidId(Some(path.to_string_lossy())))?;
+
+ // FIXME: change this once "add_extension" is stabilized
+ Ok((indexes_path, format!("{}.json", path)).into())
+ }
+
+ pub async fn load_index(&self, index: &DownloadInfo, id: Option<&str>) -> Result<AssetIndex, AssetError> {
+ let Some(id) = index.id.as_ref().map(|s| s.as_str()).or(id) else {
+ return Err(AssetError::InvalidId(None));
+ };
+
+ info!("Loading asset index {}", id);
+
+ let path = self.get_index_path(id)?;
+ debug!("Asset index {} is located at {}", id, path);
+
+ match util::verify_file(&path, index.size, index.sha1).await {
+ Ok(_) => todo!(), // load local index
+ Err(FileVerifyError::Open(_, e)) => match e.kind() {
+ ErrorKind::NotFound => (), // download
+ _ => return Err(("opening asset index", e).into())
+ },
+ Err(FileVerifyError::Integrity(_, e)) => {
+ info!("Asset index {} has mismatched integrity: {}, must download it.", id, e);
+ let _ = fs::remove_file(&path).await.map_err(|e| warn!("Error deleting modified index {}: {} (ignored)", id, e));
+ // download
+ },
+ Err(FileVerifyError::Read(_, e)) => return Err(("reading asset index", e).into())
+ }
+
+ if !self.online {
+ warn!("Must redownload asset index {}, but the launcher is in offline mode. Please try again in online mode.", id);
+ return todo!();
+ }
+
+ todo!()
+ }
+}
+
|
