use std::future::Future; use std::pin::Pin; use std::sync::Arc; use anyhow::Error; use super::crypt_config::CryptConfig; use super::data_blob::DataBlob; use super::datastore::DataStore; /// The ReadChunk trait allows reading backup data chunks (local or remote) pub trait ReadChunk { /// Returns the encoded chunk data fn read_raw_chunk(&self, digest: &[u8; 32]) -> Result; /// Returns the decoded chunk data fn read_chunk(&self, digest: &[u8; 32]) -> Result, Error>; } #[derive(Clone)] pub struct LocalChunkReader { store: Arc, crypt_config: Option>, } impl LocalChunkReader { pub fn new(store: Arc, crypt_config: Option>) -> Self { Self { store, crypt_config, } } } impl ReadChunk for LocalChunkReader { fn read_raw_chunk(&self, digest: &[u8; 32]) -> Result { self.store.load_chunk(digest) } fn read_chunk(&self, digest: &[u8; 32]) -> Result, Error> { let chunk = ReadChunk::read_raw_chunk(self, digest)?; let raw_data = chunk.decode(self.crypt_config.as_ref().map(Arc::as_ref))?; // fixme: verify digest? Ok(raw_data) } } pub trait AsyncReadChunk: Send { /// Returns the encoded chunk data fn read_raw_chunk<'a>( &'a self, digest: &'a [u8; 32], ) -> Pin> + Send + 'a>>; /// Returns the decoded chunk data fn read_chunk<'a>( &'a self, digest: &'a [u8; 32], ) -> Pin, Error>> + Send + 'a>>; } impl AsyncReadChunk for LocalChunkReader { fn read_raw_chunk<'a>( &'a self, digest: &'a [u8; 32], ) -> Pin> + Send + 'a>> { Box::pin(async move{ let (path, _) = self.store.chunk_path(digest); let raw_data = tokio::fs::read(&path).await?; let chunk = DataBlob::load_from_reader(&mut &raw_data[..])?; Ok(chunk) }) } fn read_chunk<'a>( &'a self, digest: &'a [u8; 32], ) -> Pin, Error>> + Send + 'a>> { Box::pin(async move { let chunk = AsyncReadChunk::read_raw_chunk(self, digest).await?; let raw_data = chunk.decode(self.crypt_config.as_ref().map(Arc::as_ref))?; // fixme: verify digest? Ok(raw_data) }) } }