1use anyhow::Result;
2use std::{
3 env::var,
4 fs::{create_dir_all, File},
5 io,
6 path::PathBuf,
7};
8
9pub fn download_file(url: &url::Url, path: &PathBuf) -> Result<()> {
11 let url = url.clone();
12 debug!("Downloading {} to {:?}", url, path);
13 if path.is_dir() {
15 return Err(anyhow!("Path is a directory"));
16 }
17 let parent = path.parent().unwrap();
19 create_dir_all(parent)?;
20 let mut resp = reqwest::blocking::get(url)?;
22 let mut out = File::create(path)?;
23 io::copy(&mut resp, &mut out)?;
24 Ok(())
25}
26
27pub fn get_cache_dir() -> PathBuf {
32 #[cfg(target_os = "windows")]
33 {
34 let path = var("MINEFLAKE_CACHE").unwrap_or_else(|_| {
35 var("TEMP").unwrap_or_else(|_| {
36 var("LOCALAPPDATA").unwrap_or_else(|_| {
37 var("TEMP").unwrap_or_else(|_| "C:\\Windows\\Temp".to_string())
38 })
39 })
40 });
41 let mut path = PathBuf::from(path);
42 path.push("mineflake");
43 path
44 }
45 #[cfg(not(target_os = "windows"))]
46 {
47 let path = var("MINEFLAKE_CACHE")
48 .unwrap_or_else(|_| var("HOME").unwrap_or_else(|_| "/tmp".to_string()));
49 let mut path = PathBuf::from(path);
50 path.push(".cache");
51 path.push("mineflake");
52 path
53 }
54}
55
56pub fn split_hash(hash: &str) -> PathBuf {
58 let mut path = PathBuf::new();
59 let mut chars = hash.chars();
60 for _ in 0..4 {
61 path.push(chars.by_ref().take(2).collect::<String>());
62 }
63 path.push(chars.collect::<String>());
64 path
65}
66
67pub fn download_file_to_cache(url: &url::Url, extension: &str) -> Result<String> {
74 let hash = sha256::digest(url.to_string().as_bytes());
75 let hash_path = split_hash(&hash);
76 let mut path = get_cache_dir();
77 path.push(hash_path);
78 path.set_extension(extension);
79 if !path.exists() {
80 download_file(url, &path)?;
81 } else {
82 debug!("File already exists in cache");
83 }
84 Ok(hash)
85}
86
87pub fn download_file_to_cache_full_path(url: &url::Url, extension: &str) -> Result<PathBuf> {
90 let hash = download_file_to_cache(url, extension)?;
91 let hash_path = split_hash(&hash);
92 let mut path = get_cache_dir();
93 path.push(hash_path);
94 path.set_extension(extension);
95 Ok(path)
96}
97
98pub fn unzip_file_from_cache(hash: &str) -> Result<PathBuf> {
100 let cache = get_cache_dir();
101 let hash_path = split_hash(hash);
102 let mut zip_path = cache.clone();
103 zip_path.push(&hash_path);
104 zip_path.set_extension("zip");
105 let mut dir_path = cache;
106 dir_path.push(&hash_path);
107 if dir_path.exists() {
108 return Ok(dir_path);
109 }
110 if !zip_path.exists() {
111 return Err(anyhow!("File doesn't exist in cache"));
112 }
113 if !dir_path.exists() {
114 zip::read::ZipArchive::new(File::open(zip_path)?)?.extract(&dir_path)?;
115 } else {
116 debug!("File already unzipped in cache");
117 }
118 Ok(dir_path)
119}
120
121pub fn download_and_unzip_file(url: &url::Url) -> Result<PathBuf> {
123 let hash = download_file_to_cache(url, "zip")?;
124 unzip_file_from_cache(&hash)
125}
126
127#[cfg(test)]
128mod tests {
129 #[test]
130 pub fn test_split_hash() {
131 assert_eq!(
132 super::split_hash("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"),
133 std::path::PathBuf::from(
134 "01/23/45/67/89abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
135 )
136 );
137 }
138}