garage_sdk/storage/
client.rs1use aws_sdk_s3::{Client, primitives::ByteStream};
2use std::error::Error as StdError;
3use std::future::Future;
4
5#[derive(Debug)]
7pub struct StorageInput {
8 pub key: String,
10 pub content_type: String,
12 pub body: ByteStream,
14}
15
16#[derive(Debug)]
18pub struct StorageResult {
19 pub etag: Option<String>,
21}
22
23pub trait StorageClient {
25 type Error: StdError + Send + Sync + 'static;
27 type Future<'a>: Future<Output = std::result::Result<StorageResult, Self::Error>> + Send
29 where
30 Self: 'a;
31
32 fn put_object<'a>(&'a self, input: StorageInput) -> Self::Future<'a>;
34}
35
36#[derive(Clone, Debug)]
38pub struct S3Storage {
39 client: Client,
40 bucket: String,
41}
42
43impl S3Storage {
44 pub fn new(client: Client, bucket: impl Into<String>) -> Self {
46 Self {
47 client,
48 bucket: bucket.into(),
49 }
50 }
51}
52
53impl StorageClient for S3Storage {
54 type Error = aws_sdk_s3::Error;
55 type Future<'a> = std::pin::Pin<
56 Box<dyn Future<Output = std::result::Result<StorageResult, Self::Error>> + Send + 'a>,
57 >;
58
59 fn put_object<'a>(&'a self, input: StorageInput) -> Self::Future<'a> {
60 Box::pin(async move {
61 let result = self
62 .client
63 .put_object()
64 .bucket(&self.bucket)
65 .key(&input.key)
66 .content_type(&input.content_type)
67 .body(input.body)
68 .send()
69 .await?;
70
71 Ok(StorageResult {
72 etag: result.e_tag().map(|s| s.trim_matches('"').to_string()),
73 })
74 })
75 }
76}