use std::future::Future;
use std::path::Path;
use std::sync::Arc;
pub use aws_sdk_s3::primitives::ByteStream;
use chrono::DateTime;
use chrono::Utc;
use tokio::fs::File;
use tokio::fs::ReadDir;
use crate::Res;
pub mod auth;
mod local;
pub use local::LocalStorage;
#[cfg(test)]
pub mod mocks;
pub trait Storage {
fn copy(
&self,
from: impl AsRef<Path> + Send,
to: impl AsRef<Path> + Send,
) -> impl Future<Output = Res<u64>> + Send;
fn create_dir_all(&self, path: impl AsRef<Path> + Send) -> impl Future<Output = Res> + Send;
fn create_file(&self, path: impl AsRef<Path>) -> impl Future<Output = Res<File>>;
fn exists(&self, path: impl AsRef<Path>) -> impl Future<Output = bool>;
fn modified_timestamp(
&self,
path: impl AsRef<Path>,
) -> impl Future<Output = Res<DateTime<Utc>>>;
fn open_file(&self, path: impl AsRef<Path> + Send) -> impl Future<Output = Res<File>> + Send;
fn read_byte_stream(
&self,
path: impl AsRef<Path> + Send + Sync,
) -> impl Future<Output = Res<ByteStream>> + Send + Sync;
fn read_dir(
&self,
path: impl AsRef<Path> + Send + Sync,
) -> impl Future<Output = Res<ReadDir>> + Send + Sync;
fn remove_dir_all(&self, path: impl AsRef<Path> + Send) -> impl Future<Output = Res> + Send;
fn remove_file(
&self,
path: impl AsRef<Path> + Send,
) -> impl Future<Output = Result<(), std::io::Error>> + Send;
fn rename(
&self,
from: impl AsRef<Path> + Send,
to: impl AsRef<Path> + Send,
) -> impl Future<Output = Res> + Send;
fn write_byte_stream(
&self,
path: impl AsRef<Path> + Send + Sync,
body: ByteStream,
) -> impl Future<Output = Res> + Send + Sync;
}
impl<S: Storage + Send + Sync> Storage for Arc<S> {
async fn copy(&self, from: impl AsRef<Path> + Send, to: impl AsRef<Path> + Send) -> Res<u64> {
(**self).copy(from, to).await
}
async fn create_dir_all(&self, path: impl AsRef<Path> + Send) -> Res {
(**self).create_dir_all(path).await
}
async fn create_file(&self, path: impl AsRef<Path>) -> Res<File> {
(**self).create_file(path).await
}
async fn exists(&self, path: impl AsRef<Path>) -> bool {
(**self).exists(path).await
}
async fn modified_timestamp(&self, path: impl AsRef<Path>) -> Res<DateTime<Utc>> {
(**self).modified_timestamp(path).await
}
async fn open_file(&self, path: impl AsRef<Path> + Send) -> Res<File> {
(**self).open_file(path).await
}
async fn read_byte_stream(&self, path: impl AsRef<Path> + Send + Sync) -> Res<ByteStream> {
(**self).read_byte_stream(path).await
}
async fn read_dir(&self, path: impl AsRef<Path> + Send + Sync) -> Res<ReadDir> {
(**self).read_dir(path).await
}
async fn remove_dir_all(&self, path: impl AsRef<Path> + Send) -> Res {
(**self).remove_dir_all(path).await
}
async fn remove_file(&self, path: impl AsRef<Path> + Send) -> Result<(), std::io::Error> {
(**self).remove_file(path).await
}
async fn rename(&self, from: impl AsRef<Path> + Send, to: impl AsRef<Path> + Send) -> Res {
(**self).rename(from, to).await
}
async fn write_byte_stream(
&self,
path: impl AsRef<Path> + Send + Sync,
body: ByteStream,
) -> Res {
(**self).write_byte_stream(path, body).await
}
}
pub trait StorageExt: Storage {
fn read_bytes(
&self,
path: impl AsRef<Path> + Send + Sync,
) -> impl Future<Output = Res<Vec<u8>>> + Send + Sync;
}
impl<T: Storage + Sync> StorageExt for T {
async fn read_bytes(&self, path: impl AsRef<Path> + Send + Sync) -> Res<Vec<u8>> {
Ok(self.read_byte_stream(path).await?.collect().await?.to_vec())
}
}