use std::path::{Path, PathBuf};
use bytes::Bytes;
use log::debug;
use crate::error::GalileoError;
use crate::layer::data_provider::PersistentCacheController;
#[derive(Debug, Clone)]
pub struct FileCacheController {
folder_path: PathBuf,
}
impl PersistentCacheController<str, Bytes> for FileCacheController {
fn get(&self, key: &str) -> Option<Bytes> {
let file_path = self.get_file_path(key);
if let Ok(bytes) = std::fs::read(file_path) {
Some(bytes.into())
} else {
None
}
}
fn insert(&self, key: &str, data: &Bytes) -> Result<(), GalileoError> {
let file_path = self.get_file_path(key);
match file_path.parent() {
Some(folder) => match ensure_folder_exists(folder) {
Ok(()) => {
debug!("Saving entry {key} to the cache file {file_path:?}");
std::fs::write(&file_path, data)?;
debug!("Entry {key} saved to cache file {file_path:?}");
Ok(())
}
Err(err) => {
debug!("Failed to add {key} entry to the cache failed {file_path:?} - failed to create folder: {err:?}");
Err(err.into())
}
},
None => {
debug!(
"Failed to add {key} entry to the cache failed {file_path:?} - no parent folder"
);
Err(GalileoError::IO)
}
}
}
}
impl FileCacheController {
pub fn new(path: impl AsRef<Path>) -> Result<Self, GalileoError> {
ensure_folder_exists(path.as_ref()).map_err(|err| {
GalileoError::FsIo(format!(
"failed to initialize file cache folder {:?}: {err}",
path.as_ref()
))
})?;
Ok(Self {
folder_path: path.as_ref().into(),
})
}
fn get_file_path(&self, url: &str) -> PathBuf {
let stripped = if let Some(v) = url.strip_prefix("http://") {
v
} else if let Some(v) = url.strip_prefix("https://") {
v
} else {
url
};
self.folder_path.join(Path::new(stripped))
}
}
fn ensure_folder_exists(folder_path: &Path) -> std::io::Result<()> {
std::fs::create_dir_all(folder_path)
}