hrdf_parser/
hrdf.rs

1use std::{
2    error::Error,
3    fs::{self, File},
4    io::{BufReader, Cursor},
5    path::Path,
6    time::Instant,
7};
8
9use crate::{models::Version, storage::DataStorage};
10use serde::{Deserialize, Serialize};
11use sha2::{Digest, Sha256};
12use url::Url;
13use zip::ZipArchive;
14
15#[derive(Debug, Serialize, Deserialize)]
16pub struct Hrdf {
17    data_storage: DataStorage,
18}
19
20impl Hrdf {
21    /// Loads and parses the data.<br>
22    /// If an URL is provided, the HRDF archive (ZIP file) is downloaded automatically. If a path is provided, it must absolutely point to an HRDF archive (ZIP file).<br>
23    /// The ZIP archive is automatically decompressed into the /tmp folder.
24    pub async fn new(
25        version: Version,
26        url_or_path: &str,
27        force_rebuild_cache: bool,
28        cache_prefix: Option<String>,
29    ) -> Result<Self, Box<dyn Error>> {
30        let now = Instant::now();
31
32        let unique_filename = format!("{:x}", Sha256::digest(url_or_path.as_bytes()));
33        let cache_path = format!(
34            "{}/{unique_filename}.cache",
35            cache_prefix.unwrap_or(String::from("./"))
36        )
37        .replace("//", "/");
38
39        let hrdf = if Path::new(&cache_path).exists() && !force_rebuild_cache {
40            // Loading from cache.
41            log::info!("Loading HRDF data from cache ({cache_path})...");
42
43            // If loading from cache fails, None is returned.
44            Hrdf::load_from_cache(&cache_path).ok()
45        } else {
46            // No loading from cache.
47            None
48        };
49
50        let hrdf = if let Some(hrdf) = hrdf {
51            // The cache has been loaded without error.
52            hrdf
53        } else {
54            // The cache must be built.
55            // If cache loading has failed, the cache must be rebuilt.
56            let compressed_data_path = if Url::parse(url_or_path).is_ok() {
57                let compressed_data_path = format!("/tmp/{unique_filename}.zip");
58
59                if !Path::new(&compressed_data_path).exists() {
60                    // The data must be downloaded.
61                    log::info!("Downloading HRDF data to {compressed_data_path}...");
62                    let response = reqwest::get(url_or_path).await?;
63                    let mut file = std::fs::File::create(&compressed_data_path)?;
64                    let mut content = Cursor::new(response.bytes().await?);
65                    std::io::copy(&mut content, &mut file)?;
66                }
67
68                compressed_data_path
69            } else {
70                url_or_path.to_string()
71            };
72
73            let decompressed_data_path = format!("/tmp/{unique_filename}");
74
75            if !Path::new(&decompressed_data_path).exists() {
76                // The data must be decompressed.
77                log::info!("Unzipping HRDF archive into {decompressed_data_path}...");
78                let file = File::open(&compressed_data_path)?;
79                let mut archive = ZipArchive::new(BufReader::new(file))?;
80                archive.extract(&decompressed_data_path)?;
81            }
82
83            log::info!("Parsing HRDF data from {decompressed_data_path}...");
84
85            let hrdf = Self {
86                data_storage: DataStorage::new(version, &decompressed_data_path)?,
87            };
88
89            log::info!("Building cache...");
90            hrdf.build_cache(&cache_path)?;
91            hrdf
92        };
93
94        let elapsed = now.elapsed();
95
96        log::info!("HRDF data loaded in {:.2?}!", elapsed);
97
98        Ok(hrdf)
99    }
100
101    // Getters/Setters
102
103    pub fn data_storage(&self) -> &DataStorage {
104        &self.data_storage
105    }
106
107    // Functions
108
109    pub fn build_cache(&self, path: &str) -> Result<(), Box<dyn Error>> {
110        let data = bincode::serialize(&self)?;
111        fs::write(path, data)?;
112        Ok(())
113    }
114
115    pub fn load_from_cache(path: &str) -> Result<Self, Box<dyn Error>> {
116        let data = fs::read(path)?;
117        let hrdf: Self = bincode::deserialize(&data)?;
118        Ok(hrdf)
119    }
120}