use aws_sdk_s3::{Client, primitives::ByteStream};
use std::error::Error as StdError;
use std::future::Future;
#[derive(Debug)]
pub struct StorageInput {
pub key: String,
pub content_type: String,
pub body: ByteStream,
}
#[derive(Debug)]
pub struct StorageResult {
pub etag: Option<String>,
}
pub trait StorageClient {
type Error: StdError + Send + Sync + 'static;
type Future<'a>: Future<Output = std::result::Result<StorageResult, Self::Error>> + Send
where
Self: 'a;
fn put_object<'a>(&'a self, input: StorageInput) -> Self::Future<'a>;
}
#[derive(Clone, Debug)]
pub struct S3Storage {
client: Client,
bucket: String,
}
impl S3Storage {
pub fn new(client: Client, bucket: impl Into<String>) -> Self {
Self {
client,
bucket: bucket.into(),
}
}
}
impl StorageClient for S3Storage {
type Error = aws_sdk_s3::Error;
type Future<'a> = std::pin::Pin<
Box<dyn Future<Output = std::result::Result<StorageResult, Self::Error>> + Send + 'a>,
>;
fn put_object<'a>(&'a self, input: StorageInput) -> Self::Future<'a> {
Box::pin(async move {
let result = self
.client
.put_object()
.bucket(&self.bucket)
.key(&input.key)
.content_type(&input.content_type)
.body(input.body)
.send()
.await?;
Ok(StorageResult {
etag: result.e_tag().map(|s| s.trim_matches('"').to_string()),
})
})
}
}