1use std::path::Path;
27use std::sync::{Arc, LazyLock};
28use std::time::SystemTime;
29
30use tokio::fs;
31
32use tokio::sync::Mutex;
33
34
35use crate::cfg_host_parser::HostConfig;
36use crate::cfg_resolv_parser::ResolveConfig;
37use crate::{async_write_error, internal_error, internal_error_map, error::*};
38
39use super::cfg_parsers::*;
40
41pub static CACHE: LazyLock<CachesController> = LazyLock::new(|| { CachesController::new() });
42
43
44
45pub trait CacheOperations
46{
47 fn is_reload_allowed(&self) -> bool;
48}
49
50#[derive(Clone, Debug)]
51struct CacheTime<'cache>
52{
53 path: &'cache Path,
54 last_modif: SystemTime,
55}
56
57impl<'cache> CacheTime<'cache>
58{
59 async
60 fn new(path: &'cache Path) -> CDnsResult<CacheTime<'cache>>
61 {
62 return Ok(CacheTime { path: path, last_modif: Self::get_last_modified(path).await? });
63 }
64
65 fn fake(path: &'cache Path) -> Self
66 {
67 return Self { path: path, last_modif: SystemTime::now() };
68 }
69
70 async
71 fn get_last_modified(path: &'cache Path) -> CDnsResult<SystemTime>
72 {
73 let metadata = fs::metadata(path).await.map_err(|e|
74 internal_error_map!(CDnsErrorType::InternalError, "fs::metadata::modified() not supported on this platform: '{}'", e)
75 )?;
76
77 let last_modif =
78 metadata.modified().map_err(|e|
79 internal_error_map!(CDnsErrorType::InternalError, "fs::metadata::modified() not supported on this platform: '{}'", e)
80 )?;
81
82 return Ok(last_modif);
83 }
84
85 async
86 fn check_modified(&mut self) -> CDnsResult<bool>
87 {
88 let last_modif =
90 match Self::get_last_modified(self.path).await
91 {
92 Ok(t) => t,
93 Err(e) => internal_error!(CDnsErrorType::InternalError, "{}", e),
94 };
95
96 return Ok(self.last_modif != last_modif);
97 }
98}
99
100#[derive(Clone, Debug)]
101pub struct CacheInstance<T: Default + ConfigParser<T> + CacheOperations>{
103 last_modif: CacheTime<'static>,
104 cache: Arc<T>,
105 }
107
108impl<T: Default + ConfigParser<T> + CacheOperations> Default for CacheInstance<T>
109{
110 fn default() -> Self
111 {
112 return
113 Self
114 {
115 last_modif: CacheTime::fake(T::get_file_path()),
116 cache: Arc::new(T::default()),
117 };
119 }
120}
121
122impl<T: Default + ConfigParser<T> + CacheOperations> CacheInstance<T>
123{
124 async
125 fn new() -> CDnsResult<Self>
126 {
127 return Ok(
128 Self
129 {
130 last_modif: CacheTime::new(T::get_file_path()).await?,
131 cache: Arc::new(T::parse_config().await?),
132 }
134 );
135 }
136
137 async
138 fn read_config() -> CDnsResult<Arc<T>>
139 {
140 return Ok(Arc::new(T::parse_config().await?));
141 }
142
143 async
144 fn check_modified(&mut self) -> CDnsResult<()>
145 {
146 if self.cache.is_reload_allowed() == false
148 {
149 return Ok(());
151 }
152
153 if self.last_modif.check_modified().await? == true
154 {
155 self.cache = Self::read_config().await?;
157 }
158
159 return Ok(());
160 }
161
162 fn clone_cache(&self) -> Arc<T>
163 {
164 return self.cache.clone();
165 }
166}
167
168pub struct CachesController
169{
170 resolv_cache: Mutex<CacheInstance<ResolveConfig>>,
171 host_cache: Mutex<CacheInstance<HostConfig>>
172}
173
174unsafe impl Sync for CachesController{}
175unsafe impl Send for CachesController{}
176
177impl CachesController
178{
179 fn new() -> Self
181 {
182 return
212 CachesController
213 {
214 resolv_cache: Mutex::new(CacheInstance::default()),host_cache: Mutex::new(CacheInstance::default()),};
217 }
218
219 pub async
220 fn is_resolve_cached(&self) -> bool
221 {
222 return !self.resolv_cache.lock().await.cache.is_default();
223 }
224
225 pub async
226 fn is_host_cached(&self) -> bool
227 {
228 return !self.host_cache.lock().await.cache.is_default();
229 }
230
231 async
232 fn try_cache_resolve(&self) -> CDnsResult<Arc<ResolveConfig>>
233 {
234 let mut mutx_resolv = self.resolv_cache.lock().await;
235 mutx_resolv.check_modified().await?;
236
237 return Ok(mutx_resolv.clone_cache());
238 }
239
240 pub async
241 fn clone_resolve_list(&self) -> CDnsResult<Arc<ResolveConfig>>
242 {
243 match self.try_cache_resolve().await
245 {
246 Ok(r) => return Ok(r),
247 Err(e) =>
248 {
249 async_write_error!("{}", e);
250
251 return CacheInstance::<ResolveConfig>::read_config().await;
253 }
254 }
255 }
256
257 async
258 fn try_cache_host(&self) -> CDnsResult<Arc<HostConfig>>
259 {
260 let mut mutx_host = self.host_cache.lock().await;
261 mutx_host.check_modified().await?;
262
263 return Ok(mutx_host.clone_cache());
264 }
265
266 pub async
267 fn clone_host_list(&self) -> CDnsResult<Arc<HostConfig>>
268 {
269 match self.try_cache_host().await
270 {
271 Ok(r) => return Ok(r),
272 Err(e) =>
273 {
274 async_write_error!("{}", e);
275
276 return CacheInstance::<HostConfig>::read_config().await;
278 }
279 }
280 }
281}
282
283
284#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
285async fn test_init()
286{
287 let res = CACHE.clone_resolve_list().await;
288 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
289
290 let res = res.unwrap();
291
292 println!("{:?}", res);
293
294 let res = CACHE.clone_host_list().await;
295 assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
296
297 let res = res.unwrap();
298
299 println!("{:?}", res);
300}