archivist 0.4.5

Store files in a time or index based directory hierarchy, automatically deleting the oldest files if the size limit is reached
Documentation
use anyhow::Result;
use chrono::prelude::*;
use std::path::PathBuf;

pub trait FileTree {
    fn basepath_fileprefix(&mut self, file_suffix: &str) -> Result<(PathBuf, PathBuf)>;
}

pub struct DateTimeDirTree {
    basepath_fmt: String,
    filename_prefix_fmt: String,
    timestamp: Option<DateTime<FixedOffset>>,
}

impl DateTimeDirTree {
    pub fn new(basepath_fmt: &str, filename_prefix_fmt: &str) -> Self {
        Self {
            basepath_fmt: basepath_fmt.to_owned(),
            filename_prefix_fmt: filename_prefix_fmt.to_owned(),
            timestamp: None,
        }
    }

    pub fn set_timestamp<T: Into<DateTime<FixedOffset>>>(&mut self, ts: T) {
        self.timestamp = Some(ts.into());
    }
}

impl Default for DateTimeDirTree {
    fn default() -> Self {
        Self {
            basepath_fmt: "%Y/%m/%d/%H/".to_string(),
            filename_prefix_fmt: "%Y-%m-%d_%H-%M-%S-%3f_".to_string(),
            timestamp: None,
        }
    }
}

impl FileTree for DateTimeDirTree {
    fn basepath_fileprefix(&mut self, file_suffix: &str) -> Result<(PathBuf, PathBuf)> {
        let now = self.timestamp.unwrap_or_else(|| Utc::now().into());
        let basepath = now.format(&self.basepath_fmt).to_string();
        let filename = now.format(&self.filename_prefix_fmt).to_string() + file_suffix;
        Ok((basepath.into(), filename.into()))
    }
}

#[derive(Default)]
pub struct CountingTree {
    dir_counter: usize,
    file_counter: usize,
    max_in_dir: usize,
    pub id: String,
}

impl CountingTree {
    pub fn new(max_in_dir: usize) -> Self {
        CountingTree {
            max_in_dir,
            ..Default::default()
        }
    }
}

impl FileTree for CountingTree {
    fn basepath_fileprefix(&mut self, file_suffix: &str) -> Result<(PathBuf, PathBuf)> {
        let basepath: PathBuf = [self.id.as_ref(), self.dir_counter.to_string().as_str()]
            .iter()
            .collect();
        let filename = self.file_counter.to_string() + file_suffix;

        if self.file_counter + 1 > self.max_in_dir {
            self.file_counter = 0;
            self.dir_counter += 1;
        } else {
            self.file_counter += 1;
        }

        Ok((basepath, filename.into()))
    }
}