use std::marker::PhantomData;
use std::path::Path;
use std::sync::Arc;
use std::time::SystemTime;
use crate::a_sync::interface::{AsyncMutex, AsyncMutexGuard, MutexedCaches, UnifiedFs};
#[cfg(feature = "built_in_async")]
use crate::a_sync::{IoInterf};
use crate::cfg_host_parser::HostConfig;
use crate::cfg_resolv_parser::ResolveConfig;
use crate::{error::*, internal_error, internal_error_map, write_error};
use super::cfg_parsers::*;
pub trait CacheOperations
{
fn is_reload_allowed(&self) -> bool;
}
#[derive(Clone, Debug)]
struct CacheTime<'cache, FS: UnifiedFs>
{
path: &'cache Path,
last_modif: SystemTime,
_fs: PhantomData<FS>
}
impl<'cache, FS: UnifiedFs> CacheTime<'cache, FS>
{
async
fn new(path: &'cache Path) -> CDnsResult<CacheTime<'cache, FS>>
{
return Ok(
CacheTime
{
path: path,
last_modif: Self::get_last_modified(path).await?,
_fs: PhantomData
}
);
}
fn fake(path: &'cache Path) -> Self
{
return
Self
{
path: path,
last_modif: SystemTime::now(),
_fs: PhantomData
};
}
async
fn get_last_modified(path: &'cache Path) -> CDnsResult<SystemTime>
{
let metadata =
FS::metadata(path)
.await
.map_err(|e|
internal_error_map!(CDnsErrorType::InternalError,
"fs::metadata::modified() not supported on this platform: '{}'", e)
)?;
let last_modif =
metadata
.modified()
.map_err(|e|
internal_error_map!(CDnsErrorType::InternalError,
"fs::metadata::modified() not supported on this platform: '{}'", e)
)?;
return Ok(last_modif);
}
async
fn check_modified(&mut self) -> CDnsResult<bool>
{
let last_modif =
match Self::get_last_modified(self.path).await
{
Ok(t) => t,
Err(e) => internal_error!(CDnsErrorType::InternalError, "{}", e),
};
return Ok(self.last_modif != last_modif);
}
}
#[derive(Clone, Debug)]
pub struct CacheInstance<T: Default + ConfigParser<T> + CacheOperations, FS: UnifiedFs>
{
last_modif: CacheTime<'static, FS>,
cache: Arc<T>,
_fs: PhantomData<FS>
}
impl<T: Default + ConfigParser<T> + CacheOperations, FS: UnifiedFs> Default for CacheInstance<T, FS>
{
fn default() -> Self
{
return
Self
{
last_modif: CacheTime::fake(T::get_file_path()),
cache: Arc::new(T::default()),
_fs: PhantomData
};
}
}
impl<T: Default + ConfigParser<T> + CacheOperations, FS: UnifiedFs> CacheInstance<T, FS>
{
async
fn new() -> CDnsResult<Self>
{
return Ok(
Self
{
last_modif: CacheTime::new(T::get_file_path()).await?,
cache: Arc::new(T::parse_config::<FS>().await?),
_fs: PhantomData
}
);
}
async
fn read_config() -> CDnsResult<Arc<T>>
{
return Ok(Arc::new(T::parse_config::<FS>().await?));
}
async
fn check_modified(&mut self) -> CDnsResult<()>
{
if self.cache.is_reload_allowed() == false
{
return Ok(());
}
if self.last_modif.check_modified().await? == true
{
self.cache = Self::read_config().await?;
}
return Ok(());
}
fn clone_cache(&self) -> Arc<T>
{
return self.cache.clone();
}
}
#[cfg(feature = "built_in_async")]
#[derive(Debug)]
pub struct CachesController<MC: MutexedCaches = IoInterf>
{
resolv_cache: MC::ResolveCache,
host_cache: MC::HostCahae,
_p: PhantomData<MC>,
}
#[cfg(feature = "built_in_async")]
impl CachesController<IoInterf>
{
pub async
fn new() -> CDnsResult<Self>
{
return Ok(
CachesController
{
resolv_cache:
<IoInterf as MutexedCaches>::ResolveCache::a_new(CacheInstance::new().await?), host_cache:
<IoInterf as MutexedCaches>::HostCahae::a_new(CacheInstance::new().await?), _p:
PhantomData
}
);
}
}
#[cfg(not(feature = "built_in_async"))]
#[derive(Debug)]
pub struct CachesController<MC: MutexedCaches>
{
resolv_cache: MC::ResolveCache,
host_cache: MC::HostCahae,
_p: PhantomData<MC>,
}
unsafe impl<MC: MutexedCaches> Sync for CachesController<MC>{}
unsafe impl<MC: MutexedCaches> Send for CachesController<MC>{}
impl<MC: MutexedCaches> CachesController<MC>
{
pub async
fn new_custom() -> CDnsResult<Self>
{
return Ok(
CachesController
{
resolv_cache: MC::ResolveCache::a_new(CacheInstance::new().await?), host_cache: MC::HostCahae::a_new(CacheInstance::new().await?), _p: PhantomData
}
);
}
pub async
fn is_resolve_cached(&self) -> bool
{
return !self.resolv_cache.a_lock().await.guard().cache.is_default();
}
pub async
fn is_host_cached(&self) -> bool
{
return !self.host_cache.a_lock().await.guard().cache.is_default();
}
async
fn try_cache_resolve(&self) -> CDnsResult<Arc<ResolveConfig>>
{
let mut mutx_resolv = self.resolv_cache.a_lock().await;
mutx_resolv.guard_mut().check_modified().await?;
return Ok(mutx_resolv.guard().clone_cache());
}
pub async
fn clone_resolve_list(&self) -> CDnsResult<Arc<ResolveConfig>>
{
match self.try_cache_resolve().await
{
Ok(r) =>
return Ok(r),
Err(e) =>
{
write_error!(e);
return CacheInstance::<ResolveConfig, MC::MetadataFs>::read_config().await;
}
}
}
async
fn try_cache_host(&self) -> CDnsResult<Arc<HostConfig>>
{
let mut mutx_host = self.host_cache.a_lock().await;
mutx_host.guard_mut().check_modified().await?;
return Ok(mutx_host.guard().clone_cache());
}
pub async
fn clone_host_list(&self) -> CDnsResult<Arc<HostConfig>>
{
match self.try_cache_host().await
{
Ok(r) => return Ok(r),
Err(e) =>
{
write_error!(e);
return CacheInstance::<HostConfig, MC::MetadataFs>::read_config().await;
}
}
}
}
#[cfg(feature = "use_async_tokio_tls")]
#[cfg(test)]
mod tests
{
use std::sync::Arc;
use crate::a_sync::CachesController;
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_init()
{
let cache = Arc::new(CachesController::new().await.unwrap());
let res = cache.clone_resolve_list().await;
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
let res = res.unwrap();
println!("{:?}", res);
let res = cache.clone_host_list().await;
assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());
let res = res.unwrap();
println!("{:?}", res);
}
}