use std::path::PathBuf;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;
pub const DEFAULT_BACKUP_INTERVAL_SEC: u64 = 60;
#[derive(Debug, Clone)]
pub struct BackupDestination {
pub path: PathBuf,
}
pub struct BackupManager {
active: bool,
shutdown: Arc<AtomicBool>,
handle: Option<thread::JoinHandle<()>>,
n_files_copied: u32,
last_backup_ms: u64,
}
impl BackupManager {
pub fn new() -> Self {
BackupManager {
active: false,
shutdown: Arc::new(AtomicBool::new(false)),
handle: None,
n_files_copied: 0,
last_backup_ms: 0,
}
}
pub fn start(&mut self, _destination: BackupDestination) {
let shutdown = Arc::clone(&self.shutdown);
let handle = thread::Builder::new()
.name("noxu-backup-manager".to_string())
.spawn(move || {
while !shutdown.load(Ordering::Relaxed) {
thread::sleep(Duration::from_secs(
DEFAULT_BACKUP_INTERVAL_SEC,
));
}
})
.expect("failed to spawn noxu-backup-manager thread");
self.handle = Some(handle);
self.active = true;
}
pub fn is_running(&self) -> bool {
self.active
}
pub fn n_files_copied(&self) -> u32 {
self.n_files_copied
}
pub fn last_backup_ms(&self) -> u64 {
self.last_backup_ms
}
pub fn shutdown(&mut self) {
self.shutdown.store(true, Ordering::Relaxed);
if let Some(handle) = self.handle.take() {
let _ = handle.join();
}
self.active = false;
}
}
impl Default for BackupManager {
fn default() -> Self {
Self::new()
}
}
impl Drop for BackupManager {
fn drop(&mut self) {
if self.active {
self.shutdown();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_not_running() {
let mgr = BackupManager::new();
assert!(!mgr.is_running());
assert_eq!(mgr.n_files_copied(), 0);
}
#[test]
fn test_start_and_shutdown() {
let mut mgr = BackupManager::new();
mgr.start(BackupDestination { path: PathBuf::from("/tmp") });
assert!(mgr.is_running());
mgr.shutdown();
assert!(!mgr.is_running());
}
}