titanit/src/storage.rs
2025-02-21 22:18:07 +02:00

88 lines
2.6 KiB
Rust

use anyhow::{bail, Result};
use std::{
fs::{create_dir_all, remove_file, rename, File},
path::{PathBuf, MAIN_SEPARATOR},
thread,
time::{Duration, SystemTime, UNIX_EPOCH},
};
const TMP_SUFFIX: &str = ".tmp";
pub struct Item {
pub file: File,
pub path: PathBuf,
// pub id: u64,
}
impl Item {
// Constructors
pub fn create(directory: &str) -> Result<Self> {
loop {
// generate file id from current unix time
let id = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
// build optimized fs path:
// add directory separator after every digit to keep up to 10 files per directory
let path = PathBuf::from(format!(
"{}{MAIN_SEPARATOR}{}{TMP_SUFFIX}",
directory.trim_end_matches(MAIN_SEPARATOR),
id.to_string().chars().fold(String::new(), |mut acc, c| {
if !acc.is_empty() {
acc.push(MAIN_SEPARATOR);
}
acc.push(c);
acc
})
));
// recursively create directories
// * parent directory is expected
create_dir_all(path.parent().unwrap())?;
// build `Self`
match File::create_new(&path) {
// make sure slot is not taken (by another thread)
Ok(file) => {
return Ok(Self {
file,
path,
// id
});
}
Err(_) => {
println!("[warning] Could not init location: {:?}", path.to_str());
// find free slot after some delay..
thread::sleep(Duration::from_secs(1));
continue;
}
}
}
}
// Actions
/// Take object processed, commit its changes
pub fn commit(self) -> Result<String> {
match self.path.to_str() {
Some(old) => match old.strip_suffix(TMP_SUFFIX) {
Some(new) => {
rename(old, new)?;
Ok(new.to_string())
}
None => bail!("Invalid TMP suffix"), // | panic
},
None => bail!("Invalid Item path"), // | panic
}
}
/// Cleanup object relationships
pub fn delete(self) -> Result<()> {
Ok(remove_file(self.path)?)
}
// Getters
/* @TODO implement short links handle without slash
pub fn alias(&self, relative: &str) -> String {} */
}