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 where T: Clone + Serialize + for<'de> Deserialize<'de> + std::fmt::Debug, { backup_dir: PathBuf, dirs: Vec<(PathBuf, PathBuf)>, default_metadata: T, managers: HashMap>, } impl MetaManager where T: Clone + Serialize + for<'de> Deserialize<'de> + std::fmt::Debug, { pub fn new>( 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) -> 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> { 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> { 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, ) -> Option> { self.managers .get(layer) .map(|manager| manager.restore_backup(start_time)) } pub fn managers(&self) -> &HashMap> { &self.managers } }