use std::{
fs::File,
io::Write,
path::{Path, PathBuf},
};
use tracing::error;
pub(crate) const DEFAULT_CACHE_FILE: &str = "rustypipe_cache.json";
pub trait CacheStorage: Sync + Send {
fn write(&self, data: &str);
fn read(&self) -> Option<String>;
}
pub struct FileStorage {
path: PathBuf,
}
impl FileStorage {
pub fn new<P: AsRef<Path>>(path: P) -> Self {
Self {
path: path.as_ref().to_path_buf(),
}
}
}
impl Default for FileStorage {
fn default() -> Self {
Self {
path: Path::new(DEFAULT_CACHE_FILE).into(),
}
}
}
impl CacheStorage for FileStorage {
fn write(&self, data: &str) {
fn _write(path: &Path, data: &str) -> Result<(), std::io::Error> {
let mut f = File::create(path)?;
#[cfg(target_family = "unix")]
{
use std::os::unix::fs::PermissionsExt;
let metadata = f.metadata()?;
let mut permissions = metadata.permissions();
permissions.set_mode(0o600);
std::fs::set_permissions(path, permissions)?;
}
f.write_all(data.as_bytes())
}
_write(&self.path, data).unwrap_or_else(|e| {
error!(
"Could not write cache to file `{}`. Error: {}",
self.path.to_string_lossy(),
e
);
});
}
fn read(&self) -> Option<String> {
if !self.path.exists() {
return None;
}
match std::fs::read_to_string(&self.path) {
Ok(data) => Some(data),
Err(e) => {
error!(
"Could not load cache from file `{}`. Error: {}",
self.path.to_string_lossy(),
e
);
None
}
}
}
}