use crate::checksum::file::SumsFile;
use crate::error::{ApiError, Result};
use crate::io::Provider;
use crate::io::S3Client;
use crate::io::sums::aws::S3Builder;
use crate::io::sums::file::FileBuilder;
use dyn_clone::DynClone;
use futures_util::Stream;
use std::collections::HashSet;
use std::pin::Pin;
use std::sync::Arc;
use tokio::io::AsyncRead;
pub mod aws;
pub mod channel;
pub mod file;
pub type ReaderStream = Pin<Box<dyn Stream<Item = Result<Arc<[u8]>>> + Send>>;
#[async_trait::async_trait]
pub trait SharedReader {
async fn read_chunks(&mut self) -> Result<u64>;
fn as_stream(&mut self) -> ReaderStream;
}
#[async_trait::async_trait]
pub trait ObjectSums: DynClone {
async fn sums_file(&mut self) -> Result<Option<SumsFile>>;
async fn reader(&mut self) -> Result<Box<dyn AsyncRead + Unpin + Send>>;
async fn file_size(&mut self) -> Result<Option<u64>>;
async fn write_sums_file(&self, sums_file: &SumsFile) -> Result<()>;
fn location(&self) -> String;
fn api_errors(&self) -> HashSet<ApiError>;
}
dyn_clone::clone_trait_object!(ObjectSums);
#[derive(Debug, Default)]
pub struct ObjectSumsBuilder {
client: Option<S3Client>,
}
impl ObjectSumsBuilder {
pub async fn build(self, url: String) -> Result<Box<dyn ObjectSums + Send>> {
match Provider::try_from(url.as_str())? {
Provider::File { file } => {
Ok(Box::new(FileBuilder::default().with_file(file).build()?))
}
Provider::S3 { bucket, key } => {
let client = self.client.ok_or_else(|| {
crate::error::Error::ParseError(
"an S3 client is required for S3 providers".to_string(),
)
})?;
Ok(Box::new(
S3Builder::default()
.with_key(key)
.with_bucket(bucket)
.with_client(client)
.build()?,
))
}
}
}
pub fn set_client(mut self, client: Option<S3Client>) -> Self {
self.client = client;
self
}
}