skyblock_repo/utils/
repo.rs

1#[cfg(feature = "python")]
2pub mod python {
3	use std::fs::{File, OpenOptions, create_dir_all, exists, remove_dir_all, remove_file, rename};
4	use std::io::{self, Write};
5	use std::path::Path;
6
7	use pyo3::exceptions::{PyIOError, PyRuntimeError};
8	use pyo3::*;
9
10	/// Downloads the github SkyblockRepo data and unzips
11	#[pyfunction(name = "download_repo")]
12	#[pyo3(signature=(delete_zip=true))]
13	pub fn download_zip(delete_zip: bool) -> PyResult<()> {
14		let url = "https://github.com/SkyblockRepo/Repo/archive/main.zip";
15
16		let mut response = ureq::get(url)
17			.call()
18			.map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
19
20		if !exists("SkyblockRepo")?
21			|| (!exists("SkyblockRepo-main.zip")? && !exists("SkyblockRepo")?)
22		{
23			if response.status() == 200 {
24				let mut file = OpenOptions::new()
25					.read(true)
26					.write(true)
27					.create_new(true)
28					.open("SkyblockRepo-main.zip")?;
29
30				let content = response
31					.body_mut()
32					.read_to_vec()
33					.map_err(|e| PyErr::new::<PyRuntimeError, _>(e.to_string()))?;
34				file.write_all(&content)?;
35
36				unzip_repo(file)?;
37			} else {
38				return Err(PyErr::new::<PyRuntimeError, _>(format!(
39					"Reqwest failed with status {}",
40					response.status()
41				)));
42			}
43		} else {
44			return Ok(());
45		}
46
47		if delete_zip {
48			remove_file(Path::new("SkyblockRepo-main.zip"))?;
49		}
50
51		Ok(())
52	}
53
54	fn unzip_repo(file: File) -> PyResult<()> {
55		let mut archive =
56			zip::ZipArchive::new(file).map_err(|e| PyErr::new::<PyIOError, _>(e.to_string()))?;
57
58		for i in 0..archive.len() {
59			let mut file = archive
60				.by_index(i)
61				.map_err(|e| PyErr::new::<PyIOError, _>(e.to_string()))?;
62			let outpath = match file.enclosed_name() {
63				| Some(path) => path,
64				| None => continue,
65			};
66
67			if file.is_dir() {
68				create_dir_all(&outpath)?;
69			} else {
70				if let Some(p) = outpath.parent() {
71					if !p.exists() {
72						create_dir_all(p)?;
73					}
74				}
75				let mut outfile = File::create(&outpath)?;
76				io::copy(&mut file, &mut outfile)?;
77			}
78
79			#[cfg(unix)]
80			{
81				use std::os::unix::fs::PermissionsExt;
82
83				if let Some(mode) = file.unix_mode() {
84					use std::fs::{Permissions, set_permissions};
85
86					set_permissions(&outpath, Permissions::from_mode(mode))?;
87				}
88			}
89		}
90
91		rename(Path::new("Repo-main"), Path::new("SkyblockRepo"))?;
92
93		Ok(())
94	}
95
96	#[pyfunction(name = "delete_repo")]
97	pub fn delete_repo_files() -> PyResult<()> {
98		let _ = remove_file("SkyblockRepo-main.zip").or_else(|err| {
99			// stifle file not found error because you can already remove the zip in the download function
100			if err.kind() == io::ErrorKind::NotFound {
101				Ok(())
102			} else {
103				Err(err)
104			}
105		})?;
106		remove_dir_all("SkyblockRepo")?;
107		Ok(())
108	}
109}
110
111#[cfg(not(feature = "python"))]
112pub mod rust {
113	use std::fs::{File, OpenOptions, create_dir_all, exists, remove_dir_all, remove_file, rename};
114	use std::io::{self, Write};
115	use std::path::Path;
116
117	#[cfg(feature = "log")]
118	use log::{error, trace};
119
120	/// Downloads the github SkyblockRepo data and unzips
121	///
122	/// You can additonally remove the downloaded zip and only keep the extracted directory by passing in `true`
123	pub fn download_zip(delete_zip: bool) -> Result<(), Box<dyn std::error::Error>> {
124		let url = "https://github.com/SkyblockRepo/Repo/archive/main.zip";
125
126		let mut response = ureq::get(url).call()?;
127
128		if !exists("SkyblockRepo")?
129			|| (!exists("SkyblockRepo-main.zip")? && !exists("SkyblockRepo")?)
130		{
131			if response.status() == 200 {
132				let mut file = OpenOptions::new()
133					.read(true)
134					.write(true)
135					.create_new(true)
136					.open("SkyblockRepo-main.zip")?;
137
138				let content = response.body_mut().read_to_vec()?;
139				file.write_all(&content)?;
140
141				unzip_repo(file)?;
142			} else {
143				return Err(format!("Reqwest failed with status {}", response.status()).into());
144			}
145		} else {
146			#[cfg(feature = "log")]
147			error!(
148				"SkyblockRepo-main.zip and/or SkyblockRepo/ directory are present, if you wish to refetch them, delete them."
149			);
150			return Ok(());
151		}
152
153		if delete_zip {
154			remove_file(Path::new("SkyblockRepo-main.zip"))?;
155		}
156
157		Ok(())
158	}
159
160	fn unzip_repo(file: File) -> Result<(), Box<dyn std::error::Error>> {
161		let mut archive = zip::ZipArchive::new(file)?;
162
163		for i in 0..archive.len() {
164			let mut file = archive.by_index(i)?;
165			let outpath = match file.enclosed_name() {
166				| Some(path) => path,
167				| None => continue,
168			};
169
170			if file.is_dir() {
171				#[cfg(feature = "log")]
172				trace!("File {} extracted to \"{}\"", i, outpath.display());
173				create_dir_all(&outpath)?;
174			} else {
175				#[cfg(feature = "log")]
176				trace!(
177					"File {} extracted to \"{}\" ({} bytes)",
178					i,
179					outpath.display(),
180					file.size()
181				);
182				if let Some(p) = outpath.parent() {
183					if !p.exists() {
184						create_dir_all(p)?;
185					}
186				}
187				let mut outfile = File::create(&outpath)?;
188				io::copy(&mut file, &mut outfile)?;
189			}
190
191			#[cfg(unix)]
192			{
193				use std::os::unix::fs::PermissionsExt;
194
195				if let Some(mode) = file.unix_mode() {
196					use std::fs::{Permissions, set_permissions};
197
198					set_permissions(&outpath, Permissions::from_mode(mode))?;
199				}
200			}
201		}
202
203		rename(Path::new("Repo-main"), Path::new("SkyblockRepo"))?;
204
205		Ok(())
206	}
207
208	pub fn delete_repo_files() -> Result<(), Box<dyn std::error::Error>> {
209		let _ = remove_file("SkyblockRepo-main.zip").or_else(|err| {
210			// stifle file not found error because you can already remove the zip in the download function
211			if err.kind() == io::ErrorKind::NotFound {
212				Ok(())
213			} else {
214				Err(err)
215			}
216		})?;
217		remove_dir_all("SkyblockRepo")?;
218		Ok(())
219	}
220}