You've already forked AstralRinth
forked from didirus/AstralRinth
Add tests and example for modpack support
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
//! Provides utilties for downloading and parsing modpacks
|
||||
|
||||
use std::{convert::TryFrom, io, path::Path};
|
||||
use daedalus::download_file;
|
||||
use fs_extra::dir::CopyOptions;
|
||||
use std::{borrow::Borrow, convert::TryFrom, env, io, path::Path};
|
||||
use tokio::fs;
|
||||
use uuid::Uuid;
|
||||
use zip::ZipArchive;
|
||||
|
||||
use self::manifest::Manifest;
|
||||
|
||||
mod manifest;
|
||||
pub mod manifest;
|
||||
|
||||
pub const MANIFEST_PATH: &'static str = "index.json";
|
||||
pub const OVERRIDES_PATH: &'static str = "overrides/";
|
||||
@@ -19,6 +22,12 @@ pub enum ModpackError {
|
||||
#[error("I/O error while reading modpack: {0}")]
|
||||
FSExtraError(#[from] fs_extra::error::Error),
|
||||
|
||||
#[error("Error extracting archive: {0}")]
|
||||
ZipError(#[from] zip::result::ZipError),
|
||||
|
||||
#[error("Invalid modpack format: {0}")]
|
||||
FormatError(String),
|
||||
|
||||
#[error("Invalid output directory: {0}")]
|
||||
InvalidDirectory(String),
|
||||
|
||||
@@ -35,13 +44,44 @@ pub enum ModpackError {
|
||||
JoinError(#[from] tokio::task::JoinError),
|
||||
}
|
||||
|
||||
/// Realise a modpack from a given URL
|
||||
pub async fn fetch_modpack(
|
||||
url: &str,
|
||||
sha1: Option<&str>,
|
||||
dest: &Path,
|
||||
side: manifest::ModpackSide,
|
||||
) -> Result<(), ModpackError> {
|
||||
let bytes = download_file(url, sha1).await?;
|
||||
let mut archive = ZipArchive::new(io::Cursor::new(&bytes as &[u8]))?;
|
||||
realise_modpack_zip(&mut archive, dest, side).await
|
||||
}
|
||||
|
||||
/// Realise a given modpack from a zip archive
|
||||
pub async fn realise_modpack_zip(
|
||||
archive: &mut ZipArchive<impl io::Read + io::Seek>,
|
||||
dest: &Path,
|
||||
side: manifest::ModpackSide,
|
||||
) -> Result<(), ModpackError> {
|
||||
let tmp = env::temp_dir().join(format!("theseus-{}/", Uuid::new_v4()));
|
||||
archive.extract(&tmp)?;
|
||||
realise_modpack(&tmp, dest, side).await
|
||||
}
|
||||
|
||||
/// Realise a given modpack into an instance
|
||||
pub async fn realise_modpack(dir: &Path, dest: &Path, side: &manifest::ModpackSide) -> Result<(), ModpackError> {
|
||||
pub async fn realise_modpack(
|
||||
dir: &Path,
|
||||
dest: &Path,
|
||||
side: manifest::ModpackSide,
|
||||
) -> Result<(), ModpackError> {
|
||||
if dest.is_file() {
|
||||
return Err(ModpackError::InvalidDirectory(String::from("Output is not a directory")));
|
||||
return Err(ModpackError::InvalidDirectory(String::from(
|
||||
"Output is not a directory",
|
||||
)));
|
||||
}
|
||||
if dest.exists() && std::fs::read_dir(dest).map_or(false, |it| it.count() != 0) {
|
||||
return Err(ModpackError::InvalidDirectory(String::from("Output directory is non-empty")));
|
||||
return Err(ModpackError::InvalidDirectory(String::from(
|
||||
"Output directory is non-empty",
|
||||
)));
|
||||
}
|
||||
if !dest.exists() {
|
||||
fs::create_dir_all(dest).await?;
|
||||
@@ -57,9 +97,12 @@ pub async fn realise_modpack(dir: &Path, dest: &Path, side: &manifest::ModpackSi
|
||||
// NOTE: I'm using standard files here, since Serde does not support async readers
|
||||
let manifest_path = Some(dir.join(MANIFEST_PATH))
|
||||
.filter(|it| it.exists() && it.is_file())
|
||||
.ok_or(ModpackError::ManifestError(String::from("Manifest missing or is not a file")))?;
|
||||
.ok_or(ModpackError::ManifestError(String::from(
|
||||
"Manifest missing or is not a file",
|
||||
)))?;
|
||||
let manifest_file = std::fs::File::open(manifest_path)?;
|
||||
let manifest_json: serde_json::Value = serde_json::from_reader(io::BufReader::new(manifest_file))?;
|
||||
let manifest_json: serde_json::Value =
|
||||
serde_json::from_reader(io::BufReader::new(manifest_file))?;
|
||||
let manifest = Manifest::try_from(manifest_json)?;
|
||||
|
||||
// Realise manifest
|
||||
|
||||
Reference in New Issue
Block a user