use crate::chunker::{Chunker, SlicerSettings};
use crate::manifest::archive::{Archive, Extent};
use crate::manifest::target::{BackupObject, BackupTarget, RestoreObject, RestoreTarget};
use crate::repository::{Backend, Repository};
use anyhow::Result;
use async_trait::async_trait;
use std::collections::HashMap;
use std::io::{Empty, Read, Write};
#[async_trait]
pub trait BackupDriver<T: Read + Send + 'static>: BackupTarget<T> {
async fn raw_store_object<
B: Backend,
C: SlicerSettings<Empty> + SlicerSettings<T> + 'static,
>(
&self,
repo: &mut Repository<B>,
chunker: Chunker<C>,
archive: &Archive,
path: String,
objects: HashMap<String, BackupObject<T>>,
) -> Result<()> {
for (namespace, backup_object) in objects {
let mut archive = archive.namespace_append(&namespace);
let mut ranges = backup_object.ranges();
let range_count = ranges.len();
if range_count == 0 {
archive.put_empty(&path);
} else if range_count == 1 {
let object = ranges.remove(0).object;
archive.put_object(&chunker, repo, &path, object).await?;
} else {
let mut readers: Vec<(Extent, T)> = Vec::new();
for object in ranges {
let extent = Extent {
start: object.start,
end: object.end,
};
let object = object.object;
readers.push((extent, object));
}
archive
.put_sparse_object(&chunker, repo, &path, readers)
.await?;
}
}
Ok(())
}
async fn store_object<B: Backend, C: SlicerSettings<Empty> + SlicerSettings<T> + 'static>(
&self,
repo: &mut Repository<B>,
chunker: Chunker<C>,
archive: &Archive,
path: String,
) -> Result<()> {
let objects = self.backup_object(&path);
self.raw_store_object(repo, chunker, archive, path, objects)
.await
}
}
#[async_trait(?Send)]
pub trait RestoreDriver<T: Write + Send + 'static>: RestoreTarget<T> {
async fn raw_retrieve_object<B: Backend>(
&self,
repo: &mut Repository<B>,
archive: &Archive,
path: &str,
objects: HashMap<String, RestoreObject<T>>,
) -> Result<()> {
for (namespace, restore_object) in objects {
let archive = archive.namespace_append(&namespace);
let mut ranges = restore_object.ranges();
let range_count = ranges.len();
if range_count == 1 {
let object = ranges.remove(0).object;
archive.get_object(repo, &path, object).await?;
} else {
let mut writers: Vec<(Extent, T)> = Vec::new();
for object in ranges {
let extent = Extent {
start: object.start,
end: object.end,
};
let object = object.object;
writers.push((extent, object));
}
archive.get_sparse_object(repo, &path, writers).await?;
}
}
Ok(())
}
async fn retrieve_object<B: Backend>(
&self,
repo: &mut Repository<B>,
archive: &Archive,
path: &str,
) -> Result<()> {
let objects = self.restore_object(path);
self.raw_retrieve_object(repo, archive, path, objects).await
}
}