fast_assets/
manager.rs

1use crate::decompression_manager::DecompressionManager;
2use crate::downloader::Downloader;
3use crate::extension::Extension;
4use crate::index::Index;
5use std::io::{Read, Write};
6use std::path::PathBuf;
7
8#[derive(Default, Debug)]
9pub struct File {
10    pub from_archive: bool,
11    pub path: PathBuf,
12    pub data: Option<Vec<u8>>,
13    pub downloaded: bool,
14}
15
16impl File {
17    pub fn load(&mut self) -> std::io::Result<()> {
18        if self.path.exists() {
19            let mut buffer = Vec::<u8>::new();
20            let mut file = std::fs::File::options()
21                .read(true)
22                .open(self.path.clone())?;
23            file.read_to_end(&mut buffer)?;
24            file.flush()?;
25            self.data = Some(buffer);
26            return Ok(());
27        }
28        Err(std::io::Error::new(
29            std::io::ErrorKind::NotFound,
30            format!("File \"{:?}\" not found", self.path),
31        ))
32    }
33
34    pub fn save(&mut self) -> std::io::Result<()> {
35        if !self.downloaded {
36            let mut file = std::fs::File::options()
37                .write(true)
38                .truncate(true)
39                .create(true)
40                .open(self.path.clone())?;
41            match &self.data {
42                Some(data) => {
43                    file.write_all(data.as_slice())?;
44                    file.flush()?;
45                }
46                None => (),
47            }
48
49            Ok(())
50        } else {
51            println!("You cannot save a downloaded file using the asset manager.");
52            Ok(())
53        }
54    }
55}
56
57#[derive(Debug)]
58pub struct AssetsManager {
59    pub index: Index,
60    pub cache: DecompressionManager,
61    files: Vec<File>,
62    pub extension_list: Vec<Box<dyn Extension>>,
63    compression_formats: Vec<String>,
64    downloader: Downloader,
65}
66
67impl Default for AssetsManager {
68    fn default() -> Self {
69        return Self::new(Index::new("./", ""), DecompressionManager::default());
70    }
71}
72
73impl AssetsManager {
74    pub fn new(index: Index, cache: DecompressionManager) -> Self {
75        Self {
76            index,
77            cache,
78            files: Vec::new(),
79            extension_list: Vec::new(),
80            compression_formats: vec![String::from("zip")],
81            downloader: Downloader::default(),
82        }
83    }
84
85    pub fn move_file(&mut self, origin: &str, target: &str) -> std::io::Result<()> {
86        let origin = self.index.get_path(origin).unwrap();
87        std::fs::copy(origin.clone(), target.clone())?;
88        std::fs::remove_file(origin.clone())?;
89
90        self.index.remove_indexed_file(&origin);
91        let target_path = PathBuf::from(target);
92        if !target_path.exists() {
93            self.index.add_file(target_path);
94        }
95
96        Ok(())
97    }
98
99    pub fn remove_file(&mut self, origin: &str) -> std::io::Result<()> {
100        let origin = self.index.get_path(origin).unwrap();
101        std::fs::remove_file(origin.clone())?;
102        self.index.remove_indexed_file(&origin);
103
104        Ok(())
105    }
106
107    pub fn copy_file(&mut self, origin: &str, target: &str) -> std::io::Result<()> {
108        let origin = self.index.get_path(origin).unwrap();
109        std::fs::copy(origin.clone(), target.clone())?;
110
111        self.index.add_file(PathBuf::from(target));
112
113        Ok(())
114    }
115
116    pub fn create_file(&mut self, path: &str) -> std::io::Result<()> {
117        std::fs::File::options()
118            .create(true)
119            .write(true)
120            .open(path)?;
121        self.index.add_file(PathBuf::from(path));
122
123        Ok(())
124    }
125
126    pub fn remove_process_pass(&mut self, name: &str) {
127        for i in 0..self.extension_list.len() {
128            if self.extension_list[i].get_name() == name {
129                self.extension_list.remove(i);
130            }
131        }
132    }
133
134    pub fn add_compression_formats(&mut self, format: &str) {
135        self.compression_formats.push(String::from(format));
136    }
137
138    pub fn add_extension(&mut self, extension: Box<dyn Extension>) {
139        self.extension_list.push(extension);
140    }
141
142    pub fn load(&mut self, base_path: &str) -> std::io::Result<()> {
143        if (base_path.starts_with("http://") || base_path.starts_with("https://"))
144            && self.downloader.can_download(&base_path)
145        {
146            self.downloader.download_sync(
147                base_path.to_string(),
148                String::from("FastAssetAutoDownload_temp.tmp"),
149            );
150            let downloaded_content = std::fs::read("FastAssetAutoDownload_temp.tmp");
151            match downloaded_content {
152                Err(err) => {
153                    println!("Error while reading downloaded file: {}", err);
154                }
155                Ok(content) => {
156                    let file_path = PathBuf::from(base_path);
157                    let new_file = File {
158                        from_archive: false,
159                        path: file_path.clone(),
160                        data: Some(content),
161                        downloaded: true,
162                    };
163                    self.index.files.push(file_path);
164                    self.files.push(new_file);
165                    return Ok(());
166                }
167            }
168        }
169
170        let mut path;
171        if !(base_path.contains('\\') || base_path.contains('/')) {
172            path = self.index.get_path(base_path);
173        } else {
174            path = Some(String::from(base_path));
175        }
176
177        for i in 0..self.extension_list.len() {
178            let mut process_pass = self.extension_list.swap_remove(i);
179            if !process_pass.on_load(self, &mut path) {
180                return Ok(());
181            }
182            self.extension_list.insert(i, process_pass);
183        }
184
185        match path {
186            Some(path) => {
187                let path = PathBuf::from(path);
188
189                let mut in_archive: Option<String> = None;
190                let mut path_until_archive = Vec::<String>::new();
191                let mut path_in_archive = Vec::<String>::new();
192                for i in path.components() {
193                    let cmp = i.as_os_str().to_string_lossy();
194
195                    if in_archive.is_none() {
196                        path_until_archive.push(cmp.to_string());
197                    } else {
198                        path_in_archive.push(cmp.to_string());
199                    }
200
201                    for fmt in self.compression_formats.iter() {
202                        if cmp.ends_with(&format!(".{}", fmt)) {
203                            in_archive = Some(i.as_os_str().to_string_lossy().to_string());
204                        }
205                    }
206                }
207
208                match in_archive {
209                    Some(_) => {
210                        let mut file = File::default();
211
212                        let mut archive = String::new();
213                        path_until_archive.iter().for_each(|elem| {
214                            archive.push_str(&format!("{}/", elem));
215                        });
216                        archive.pop();
217                        file.from_archive = true;
218
219                        let mut path = String::new();
220                        path_in_archive.iter().for_each(|elem| {
221                            path.push_str(&format!("{}/", elem));
222                        });
223                        path.pop();
224                        file.path = PathBuf::from(path.clone());
225
226                        self.cache.load_archive(
227                            &archive,
228                            Some(vec![&path]),
229                            &mut self.extension_list,
230                        );
231
232                        file.from_archive = true;
233                        file.path = PathBuf::from(path);
234                        self.files.push(file);
235                    }
236                    None => {
237                        let mut file = File::default();
238                        file.path = path;
239                        file.load()?;
240                        self.files.push(file);
241                    }
242                }
243            }
244            None => {}
245        }
246
247        Ok(())
248    }
249
250    pub fn unload(&mut self, mut path: &str, mut cache_decompressed: bool) {
251        for i in 0..self.extension_list.len() {
252            let mut process_pass = self.extension_list.swap_remove(i);
253            if !process_pass.on_unload(self, &mut path, &mut cache_decompressed) {
254                return;
255            }
256            self.extension_list.insert(i, process_pass);
257        }
258
259        for file in self.files.iter_mut() {
260            let file_path = file.path.to_string_lossy();
261            if path == file_path {
262                file.data = None;
263                if file.from_archive {
264                    if cache_decompressed {
265                        self.cache.cache(&file_path);
266                    } else {
267                        self.cache.unload(&file_path);
268                    }
269                }
270            }
271        }
272    }
273
274    pub fn remove(&mut self, mut path: &str) {
275        for i in 0..self.extension_list.len() {
276            let mut process_pass = self.extension_list.swap_remove(i);
277            if !process_pass.on_remove(self, &mut path) {
278                return;
279            }
280            self.extension_list.insert(i, process_pass);
281        }
282
283        for i in 0..self.files.len() {
284            if i < self.files.len() {
285                let file_path = self.files[i].path.to_string_lossy();
286                if path == file_path {
287                    if self.files[i].from_archive {
288                        self.cache.remove(path);
289                    }
290                    self.files.remove(i);
291                }
292            }
293        }
294    }
295
296    pub fn find_file_index(&self, filename: &str) -> Option<usize> {
297        for i in 0..self.files.len() {
298            if self.files[i].path.file_name().unwrap().to_string_lossy() == filename {
299                return Some(i);
300            }
301        }
302        None
303    }
304
305    pub fn find_file_index_using_full_path(&self, path: &str) -> Option<usize> {
306        for i in 0..self.files.len() {
307            if self.files[i].path.to_string_lossy() == path {
308                return Some(i);
309            }
310        }
311        None
312    }
313
314    pub fn get(&mut self, path: &str) -> Option<Vec<u8>> {
315        let in_cache = self.cache.get_data(path);
316        return match in_cache {
317            Some(_) => in_cache,
318            None => {
319                let path = self
320                    .index
321                    .get_path(path)
322                    .expect(&format!("Cannot get path of: {}", path));
323                let index;
324                if path.contains('\\') || path.contains('/') {
325                    index = self.find_file_index_using_full_path(path.as_str());
326                } else {
327                    index = self.find_file_index(path.as_str());
328                }
329                if index.is_none() {
330                    return None;
331                }
332                self.files[index.unwrap()].data.clone()
333            }
334        };
335    }
336
337    pub fn get_ref(&mut self, path: &str) -> Option<&Option<Vec<u8>>> {
338        let path_buf = self.index.get_path(path).unwrap();
339        let is_full_path = path_buf.contains('\\') || path_buf.contains('/');
340        let in_cache = self.cache.get_data_ref(path);
341        match in_cache {
342            Some(_) => return in_cache,
343            None => {
344                for file in self.files.iter() {
345                    if is_full_path && file.path.to_string_lossy() == path_buf {
346                        return Some(&file.data);
347                    }
348                }
349            }
350        }
351        None
352    }
353
354    pub fn get_mut(&mut self, path: &str) -> Option<&mut Option<Vec<u8>>> {
355        let path_buf = self.index.get_path(path).unwrap();
356        let in_cache = self.cache.get_data_mut(path);
357        match in_cache {
358            Some(_) => return in_cache,
359            None => {
360                for file in self.files.iter_mut() {
361                    if file.path.to_string_lossy() == path_buf {
362                        return Some(&mut file.data);
363                    }
364                }
365            }
366        }
367        None
368    }
369
370    pub fn set_data(&mut self, path: &str, new_data: Vec<u8>) {
371        match self.get_mut(path) {
372            Some(data) => {
373                *data = Some(new_data);
374            }
375            None => (),
376        }
377    }
378
379    pub fn have_file(&self, filename: &str) -> bool {
380        for file in self.files.iter() {
381            if file.path.file_name().unwrap().to_string_lossy() == filename {
382                return true;
383            }
384        }
385
386        return self.index.have_file(filename);
387    }
388
389    pub fn save(&mut self, filename: &str) -> std::io::Result<()> {
390        for file in self.files.iter_mut() {
391            if file.path.file_name().unwrap().to_string_lossy() == filename {
392                return file.save();
393            }
394        }
395
396        Ok(())
397    }
398
399    pub fn get_files_matching_regex(&self, regex: &str) -> Vec<PathBuf> {
400        self.index.regex_search(regex)
401    }
402}