use std::{
fs::{create_dir_all, File, OpenOptions},
io::{ErrorKind, Read, Write},
path::PathBuf,
time::{SystemTime, UNIX_EPOCH},
};
use gethostname::gethostname;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{
config::Config,
error::{Error, Result},
packages::Package,
pathinfo::PathInfo,
};
pub type BackupId = String;
#[derive(Debug, Serialize, Deserialize)]
pub struct Backup {
id: String,
timestamp: u64,
packages: Vec<Package>,
files: Vec<PathInfo>,
}
impl Backup {
pub fn create(config: &Config, packages: Vec<Package>) -> Result<Self> {
let mut files: Vec<PathInfo> = Vec::new();
for dir in &config.directories {
files.push(PathInfo::from_path(config, dir)?);
}
Ok(Self {
// UUID not really needed, maybe a shorter hash
id: Uuid::new_v4().to_string(),
timestamp: Self::get_timestamp(),
packages,
files,
})
}
pub fn save(&self, config: &Config) -> Result<()> {
let rel_location = format!(
"bu_{}_{}",
gethostname()
.into_string()
.map_err(|_| Error::InvalidOsString)?,
Self::get_timestamp()
);
let bl = BackupLocation {
id: self.id.to_string(),
rel_location,
};
Self::append_to_root_index(config, bl.clone())?;
let backup_root = format!("{}/{}", config.root, bl.rel_location);
create_dir_all(&backup_root).unwrap();
let path = format!("{}/index.json", backup_root);
let mut f = File::create(path).unwrap();
f.write_all(&serde_json::to_vec(self).unwrap()).unwrap();
Ok(())
}
pub fn get(config: &Config, _id: Option<BackupId>) -> Result<()> {
let backup_index_root = format!("{}/index.json", config.root);
let mut file = File::open(backup_index_root)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
let list: Vec<BackupLocation> = serde_json::from_str(&content)?;
println!("{list:#?}");
todo!();
Ok(())
}
fn append_to_root_index(config: &Config, new_backup: BackupLocation) -> Result<()> {
let backup_index_root = format!("{}/index.json", config.root);
let path = PathBuf::from(&backup_index_root);
if path.exists() {
let mut f = File::open(&path)?;
let mut content = String::new();
f.read_to_string(&mut content)?;
let mut loc: Vec<BackupLocation> = serde_json::from_str(&content)?;
let mut f = File::create(path)?;
loc.push(new_backup);
f.write_all(&serde_json::to_vec(&loc)?)?;
} else {
let mut f = File::create(backup_index_root)?;
f.write_all(&serde_json::to_vec(&vec![new_backup])?)?;
};
Ok(())
}
fn get_timestamp() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct BackupLocation {
id: BackupId,
rel_location: String,
}