this repo has no description
1use async_trait::async_trait; 2use aws_config::BehaviorVersion; 3use aws_config::meta::region::RegionProviderChain; 4use aws_sdk_s3::Client; 5use aws_sdk_s3::primitives::ByteStream; 6use thiserror::Error; 7 8#[derive(Error, Debug)] 9pub enum StorageError { 10 #[error("IO error: {0}")] 11 Io(#[from] std::io::Error), 12 #[error("S3 error: {0}")] 13 S3(String), 14 #[error("Other: {0}")] 15 Other(String), 16} 17 18#[async_trait] 19pub trait BlobStorage: Send + Sync { 20 async fn put(&self, key: &str, data: &[u8]) -> Result<(), StorageError>; 21 async fn get(&self, key: &str) -> Result<Vec<u8>, StorageError>; 22 async fn delete(&self, key: &str) -> Result<(), StorageError>; 23} 24 25pub struct S3BlobStorage { 26 client: Client, 27 bucket: String, 28} 29 30impl S3BlobStorage { 31 pub async fn new() -> Self { 32 // heheheh 33 let region_provider = RegionProviderChain::default_provider().or_else("us-east-1"); 34 let config = aws_config::defaults(BehaviorVersion::latest()) 35 .region(region_provider) 36 .load() 37 .await; 38 39 let bucket = std::env::var("S3_BUCKET").expect("S3_BUCKET must be set"); 40 41 let client = if let Ok(endpoint) = std::env::var("S3_ENDPOINT") { 42 let s3_config = aws_sdk_s3::config::Builder::from(&config) 43 .endpoint_url(endpoint) 44 .force_path_style(true) 45 .build(); 46 Client::from_conf(s3_config) 47 } else { 48 Client::new(&config) 49 }; 50 51 Self { client, bucket } 52 } 53} 54 55#[async_trait] 56impl BlobStorage for S3BlobStorage { 57 async fn put(&self, key: &str, data: &[u8]) -> Result<(), StorageError> { 58 self.client 59 .put_object() 60 .bucket(&self.bucket) 61 .key(key) 62 .body(ByteStream::from(data.to_vec())) 63 .send() 64 .await 65 .map_err(|e| StorageError::S3(e.to_string()))?; 66 Ok(()) 67 } 68 69 async fn get(&self, key: &str) -> Result<Vec<u8>, StorageError> { 70 let resp = self 71 .client 72 .get_object() 73 .bucket(&self.bucket) 74 .key(key) 75 .send() 76 .await 77 .map_err(|e| StorageError::S3(e.to_string()))?; 78 79 let data = resp 80 .body 81 .collect() 82 .await 83 .map_err(|e| StorageError::S3(e.to_string()))? 84 .into_bytes(); 85 86 Ok(data.to_vec()) 87 } 88 89 async fn delete(&self, key: &str) -> Result<(), StorageError> { 90 self.client 91 .delete_object() 92 .bucket(&self.bucket) 93 .key(key) 94 .send() 95 .await 96 .map_err(|e| StorageError::S3(e.to_string()))?; 97 Ok(()) 98 } 99}