135 lines
3.8 KiB
Rust
135 lines
3.8 KiB
Rust
use super::{Manager, ManagerConfig};
|
|
use chrono::Utc;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::collections::HashMap;
|
|
use std::io;
|
|
use std::path::PathBuf;
|
|
|
|
/// Manages a collection of backup layers, allowing them to be utilized as a single object.
|
|
pub struct MetaManager<T>
|
|
where
|
|
T: Clone + Serialize + for<'de> Deserialize<'de> + std::fmt::Debug,
|
|
{
|
|
backup_dir: PathBuf,
|
|
dirs: Vec<(PathBuf, PathBuf)>,
|
|
default_metadata: T,
|
|
managers: HashMap<String, Manager<T>>,
|
|
}
|
|
|
|
impl<T> MetaManager<T>
|
|
where
|
|
T: Clone + Serialize + for<'de> Deserialize<'de> + std::fmt::Debug,
|
|
{
|
|
pub fn new<P: Into<PathBuf>>(
|
|
backup_dir: P,
|
|
dirs: Vec<(PathBuf, PathBuf)>,
|
|
default_metadata: T,
|
|
) -> Self {
|
|
MetaManager {
|
|
backup_dir: backup_dir.into(),
|
|
dirs,
|
|
default_metadata,
|
|
managers: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
/// Add a new manager to track, initializing it first.
|
|
pub fn add(&mut self, config: &ManagerConfig) -> io::Result<()> {
|
|
// Backup dir itself should exist, but we control its contents, so we can create
|
|
// separate directories for each layer
|
|
let path = self.backup_dir.join(&config.name);
|
|
|
|
// If the directory already exists, that's okay
|
|
match std::fs::create_dir(&path) {
|
|
Ok(()) => (),
|
|
Err(e) => match e.kind() {
|
|
io::ErrorKind::AlreadyExists => (),
|
|
_ => return Err(e),
|
|
},
|
|
};
|
|
|
|
let mut manager = Manager::new(
|
|
path,
|
|
self.dirs.clone(),
|
|
self.default_metadata.clone(),
|
|
config.chain_len,
|
|
config.chains,
|
|
chrono::Duration::minutes(config.frequency.into()),
|
|
);
|
|
manager.load()?;
|
|
self.managers.insert(config.name.clone(), manager);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Convenient wrapper for `add`.
|
|
pub fn add_all(&mut self, configs: &Vec<ManagerConfig>) -> io::Result<()> {
|
|
for config in configs {
|
|
self.add(config)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Return the name of the next scheduled layer, if one or more managers are present.
|
|
pub fn next_scheduled_layer(&self) -> Option<&str> {
|
|
self.managers
|
|
.iter()
|
|
.min_by_key(|(_, m)| m.next_scheduled_time())
|
|
.map(|(k, _)| k.as_str())
|
|
}
|
|
|
|
/// Return the earliest scheduled time for the underlying managers.
|
|
pub fn next_scheduled_time(&self) -> Option<chrono::DateTime<Utc>> {
|
|
self.managers
|
|
.values()
|
|
.map(|m| m.next_scheduled_time())
|
|
.min()
|
|
}
|
|
|
|
/// Perform a backup cycle for the earliest scheduled manager.
|
|
pub fn perform_backup_cycle(&mut self) -> io::Result<()> {
|
|
if let Some(manager) = self
|
|
.managers
|
|
.values_mut()
|
|
.min_by_key(|m| m.next_scheduled_time())
|
|
{
|
|
manager.create_backup()?;
|
|
manager.remove_old_backups()
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
/// Create a manual backup for a specific layer
|
|
pub fn create_backup(&mut self, layer: &str) -> Option<io::Result<()>> {
|
|
if let Some(manager) = self.managers.get_mut(layer) {
|
|
let mut res = manager.create_backup();
|
|
|
|
if res.is_ok() {
|
|
res = manager.remove_old_backups();
|
|
}
|
|
|
|
Some(res)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Restore a backup for a specific layer
|
|
pub fn restore_backup(
|
|
&self,
|
|
layer: &str,
|
|
start_time: chrono::DateTime<Utc>,
|
|
) -> Option<io::Result<()>> {
|
|
self.managers
|
|
.get(layer)
|
|
.map(|manager| manager.restore_backup(start_time))
|
|
}
|
|
|
|
pub fn managers(&self) -> &HashMap<String, Manager<T>> {
|
|
&self.managers
|
|
}
|
|
}
|