use crate::checksum::file::SumsFile;
use crate::error::Error::ParseError;
use crate::error::{ApiError, Result};
use crate::io::sums::ObjectSums;
use std::collections::HashSet;
use std::path::PathBuf;
use tokio::fs;
use tokio::io::{AsyncRead, AsyncReadExt};
#[derive(Debug, Default)]
pub struct FileBuilder {
file: Option<String>,
}
impl FileBuilder {
pub fn with_file(mut self, file: String) -> Self {
self.file = Some(file);
self
}
fn get_components(self) -> Result<String> {
self.file
.ok_or_else(|| ParseError("file is required for `FileBuilder`".to_string()))
}
pub fn build(self) -> Result<File> {
Ok(self.get_components()?.into())
}
}
impl From<String> for File {
fn from(file: String) -> Self {
Self::new(file)
}
}
#[derive(Debug, Clone)]
pub struct File {
file: String,
}
impl File {
pub fn new(file: String) -> Self {
Self { file }
}
pub async fn get_existing_sums(&self) -> Result<Option<SumsFile>> {
let path = SumsFile::format_sums_file(&self.file);
if !PathBuf::from(&path).exists() {
return Ok(None);
}
let mut file = fs::File::open(&path).await?;
let mut buf = vec![];
file.read_to_end(&mut buf).await?;
let sums = SumsFile::read_from_slice(&buf).await?;
Ok(Some(sums))
}
pub async fn sums_reader(&self) -> Result<impl AsyncRead + 'static> {
let path = SumsFile::format_target_file(&self.file);
Ok(fs::File::open(&path).await?)
}
pub async fn size(&self) -> Result<Option<u64>> {
Ok(fs::metadata(SumsFile::format_target_file(&self.file))
.await
.ok()
.map(|metadata| metadata.len()))
}
pub async fn write_sums(&self, sums_file: &SumsFile) -> Result<()> {
let path = SumsFile::format_sums_file(&self.file);
fs::write(&path, sums_file.to_json_string()?).await?;
Ok(())
}
}
#[async_trait::async_trait]
impl ObjectSums for File {
async fn sums_file(&mut self) -> Result<Option<SumsFile>> {
Ok(self.get_existing_sums().await?)
}
async fn reader(&mut self) -> Result<Box<dyn AsyncRead + Unpin + Send + 'static>> {
Ok(Box::new(self.sums_reader().await?))
}
async fn file_size(&mut self) -> Result<Option<u64>> {
self.size().await
}
async fn write_sums_file(&self, sums_file: &SumsFile) -> Result<()> {
self.write_sums(sums_file).await
}
fn location(&self) -> String {
self.file.to_string()
}
fn api_errors(&self) -> HashSet<ApiError> {
HashSet::new()
}
}