1use std::path::Path;
19use std::sync::{Arc, LazyLock, Mutex};
20use std::time::SystemTime;
21use std::fs;
22
23
24use crate::cfg_host_parser::HostConfig;
25use crate::cfg_resolv_parser::ResolveConfig;
26use crate::{error::*, internal_error, internal_error_map, write_error};
27
28use super::cfg_parsers::*;
29
30pub static CACHE: LazyLock<CachesController> = LazyLock::new(|| { CachesController::new() });
31
32pub trait CacheOperations
33{
34 fn is_reload_allowed(&self) -> bool;
35}
36
37#[derive(Clone, Debug)]
38struct CacheTime<'cache>
39{
40 path: &'cache Path,
41 last_modif: SystemTime,
42}
43
44impl<'cache> CacheTime<'cache>
45{
46 fn new(path: &'cache Path) -> CDnsResult<Self>
47 {
48 return Ok(Self { path: path, last_modif: Self::get_last_modified(path)? });
49 }
50
51 fn fake(path: &'cache Path) -> Self
52 {
53 return Self { path: path, last_modif: SystemTime::now() };
54 }
55
56 fn get_last_modified(path: &'cache Path) -> CDnsResult<SystemTime>
57 {
58 let metadata = fs::metadata(path).map_err(|e|
59 internal_error_map!(CDnsErrorType::InternalError, "fs::metadata::modified() not supported on this platform: '{}'", e)
60 )?;
61
62 let last_modif =
63 metadata.modified().map_err(|e|
64 internal_error_map!(CDnsErrorType::InternalError, "fs::metadata::modified() not supported on this platform: '{}'", e)
65 )?;
66
67 return Ok(last_modif);
68 }
69
70 fn check_modified(&mut self) -> CDnsResult<bool>
71 {
72 let last_modif =
74 match Self::get_last_modified(self.path)
75 {
76 Ok(t) => t,
77 Err(e) => internal_error!(CDnsErrorType::InternalError, "{}", e),
78 };
79
80 return Ok(self.last_modif != last_modif);
81 }
95}
96
97#[derive(Clone, Debug)]
98pub struct CacheInstance<T: Default + ConfigParser<T> + CacheOperations>
99{
100 last_modif: CacheTime<'static>,
101 cache: Arc<T>,
102}
103
104impl<T: Default + ConfigParser<T> + CacheOperations> Default for CacheInstance<T>
105{
106 fn default() -> Self
107 {
108 return
109 Self
110 {
111 last_modif: CacheTime::fake(T::get_file_path()),
112 cache: Arc::new(T::default()),
113 };
115 }
116}
117
118impl<T: Default + ConfigParser<T> + CacheOperations> CacheInstance<T>
119{
120 fn new() -> CDnsResult<Self>
121 {
122 return Ok(
123 Self
124 {
125 last_modif: CacheTime::new(T::get_file_path())?,
126 cache: Arc::new(T::parse_config()?),
127 }
129 );
130 }
131
132 fn read_config() -> CDnsResult<Arc<T>>
133 {
134 return Ok(Arc::new(T::parse_config()?));
135 }
136
137 fn check_modified(&mut self) -> CDnsResult<()>
138 {
139 if self.cache.is_reload_allowed() == false
141 {
142 return Ok(());
144 }
145
146 if self.last_modif.check_modified()? == true
147 {
148 self.cache = Self::read_config()?;
150 }
151
152 return Ok(());
153 }
154
155 fn clone_cache(&self) -> Arc<T>
156 {
157 return self.cache.clone();
158 }
159}
160
161pub struct CachesController
162{
163 resolv_cache: Mutex<CacheInstance<ResolveConfig>>,
164 host_cache: Mutex<CacheInstance<HostConfig>>
165}
166
167unsafe impl Sync for CachesController{}
168unsafe impl Send for CachesController{}
169
170impl CachesController
171{
172 fn new() -> Self
174 {
175 let resolve_cache_res = CacheInstance::<ResolveConfig>::new();
176
177 let host_cache_res = CacheInstance::<HostConfig>::new();
178
179 let resolve_cache =
180 match resolve_cache_res
181 {
182 Ok(r) => r,
183 Err(e) =>
184 {
185 write_error!(e);
186
187 CacheInstance::default()
188 }
189 };
190
191 let host_cache =
192 match host_cache_res
193 {
194 Ok(r) => r,
195 Err(e) =>
196 {
197 write_error!(e);
198
199 CacheInstance::default()
200 }
201 };
202
203
204 return
205 CachesController
206 {
207 resolv_cache: Mutex::new(resolve_cache),
208 host_cache: Mutex::new(host_cache),
209 };
210 }
211
212 pub
213 fn is_resolve_cached(&self) -> bool
214 {
215 return !self.resolv_cache.lock().unwrap().cache.is_default();
216 }
217
218 pub
219 fn is_host_cached(&self) -> bool
220 {
221 return !self.host_cache.lock().unwrap().cache.is_default();
222 }
223
224 fn try_cache_resolve(&self) -> CDnsResult<Arc<ResolveConfig>>
225 {
226 let mut mutx_resolv = self.resolv_cache.lock().unwrap();
227 mutx_resolv.check_modified()?;
228
229 return Ok(mutx_resolv.clone_cache());
230 }
231
232 pub
234 fn clone_resolve_list(&self) -> CDnsResult<Arc<ResolveConfig>>
235 {
236 match self.try_cache_resolve()
238 {
239 Ok(r) =>
240 return Ok(r),
241 Err(e) =>
242 {
243 write_error!(e);
244
245 return CacheInstance::<ResolveConfig>::read_config();
247 }
248 }
249 }
250
251 fn try_cache_host(&self) -> CDnsResult<Arc<HostConfig>>
252 {
253 let mut mutx_host = self.host_cache.lock().unwrap();
254 mutx_host.check_modified()?;
255
256 return Ok(mutx_host.clone_cache());
257 }
258
259 pub
261 fn clone_host_list(&self) -> CDnsResult<Arc<HostConfig>>
262 {
263 match self.try_cache_host()
264 {
265 Ok(r) =>
266 return Ok(r),
267 Err(e) =>
268 {
269 write_error!(e);
270
271 return CacheInstance::<HostConfig>::read_config();
273 }
274 }
275 }
276}
277
278
279
280#[cfg(test)]
281mod tests
282{
283 use crate::sync::caches::CACHE;
284
285 #[test]
286 fn test_init()
287 {
288 let res = CACHE.clone_resolve_list();
289 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
290
291 let res = res.unwrap();
292
293 println!("{:?}", res);
294
295 let res = CACHE.clone_host_list();
296 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
297
298 let res = res.unwrap();
299
300 println!("{:?}", res);
301 }
302}