aboutsummaryrefslogtreecommitdiff
path: root/src/download.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/download.rs')
-rw-r--r--src/download.rs36
1 files changed, 25 insertions, 11 deletions
diff --git a/src/download.rs b/src/download.rs
index 75bea57..dfce2fc 100644
--- a/src/download.rs
+++ b/src/download.rs
@@ -1,10 +1,12 @@
use std::{
+ fs,
io::{Cursor, Read},
str::FromStr,
};
use tempdir::TempDir;
use url::Url;
+use uuid::Uuid;
use zip::ZipArchive;
use super::{
@@ -103,18 +105,30 @@ impl Downloader {
let data = Cursor::new(data);
let mut archive = ZipArchive::new(data)?;
- // Here we assume that the zipfile contains only one directory, so we just take the first
- // name we find and extract the leading directory name.
- let name = archive
- .file_names()
- .next()
- .and_then(|name| name.split('/').next())
- .ok_or(Error::EmptyArchive)?
- .to_string();
+ let dir = self
+ .temp_dir
+ .path()
+ .join(&Uuid::new_v4().to_hyphenated().to_string());
+ fs::create_dir(&dir)?;
- archive.extract(self.temp_dir.path())?;
+ archive.extract(&dir)?;
- let extracted_path = self.temp_dir.path().join(name);
- minemod::open_mod_or_pack(&extracted_path)
+ // Some archives contain the mod files directly, so try to open it:
+ if let Ok(pack) = minemod::open_mod_or_pack(&dir) {
+ return Ok(pack);
+ }
+
+ // If the archive does not contain the mod directly, we instead try the subdirectories that
+ // we've extracted.
+ for entry in fs::read_dir(&dir)? {
+ let entry = entry?;
+ let metadata = fs::metadata(&entry.path())?;
+ if metadata.is_dir() {
+ if let Ok(pack) = minemod::open_mod_or_pack(&entry.path()) {
+ return Ok(pack);
+ }
+ }
+ }
+ Err(Error::InvalidModDir(dir))
}
}