aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--src/download.rs36
3 files changed, 36 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bce8b00..fb5d7c7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -486,6 +486,7 @@ dependencies = [
"toml",
"ureq",
"url",
+ "uuid",
"zip",
]
@@ -1214,6 +1215,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom 0.2.3",
+]
+
+[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 5bc82df..988af09 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,4 +24,5 @@ thiserror = "1.0.30"
toml = "0.5.8"
ureq = { version = "2.3.0", features = ["json"] }
url = { version = "2.2.2", features = ["serde"] }
+uuid = { version = "0.8.2", features = ["v4"] }
zip = "0.5.13"
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))
}
}