Skip to content

Commit

Permalink
better error handling and runnable code
Browse files Browse the repository at this point in the history
  • Loading branch information
Omarabdul3ziz committed Sep 27, 2023
1 parent 47d3ac1 commit 5bb0268
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 56 deletions.
150 changes: 146 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 54 additions & 52 deletions src/s3/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod s3;

use anyhow::{anyhow, Context, Result};
use rusoto_core::{Region, RusotoError};
use rusoto_s3::{S3, S3Client, CreateBucketRequest, PutObjectRequest, GetObjectRequest, CreateBucketError};
use rusoto_s3::{
CreateBucketError, CreateBucketRequest, GetObjectRequest, PutObjectRequest, S3Client, S3,
};
use tokio::io::AsyncReadExt;

#[derive(Clone)]
struct BucketManager {
client: S3Client,
bucket: String,
Expand All @@ -14,82 +16,82 @@ struct Credentials {
secret_key: String,
}

impl BucketManager{
pub async fn new(endpoint: &str, region: &str, bucket: &str, cred: Credentials) -> Result<Self, String> {
impl BucketManager {
pub async fn new(
endpoint: &str,
region: &str,
bucket: &str,
cred: Credentials,
) -> Result<Self> {
let region = Region::Custom {
name: region.to_owned(),
endpoint: endpoint.to_owned(),
};

let dispatcher = match rusoto_core::request::HttpClient::new() {
Ok(http_client) => http_client,
Err(err) => return Err(format!("Error creating http client: {:?}", err))
};
let dispatcher =
rusoto_core::request::HttpClient::new().context("Error creating http client.")?;

let client = S3Client::new_with(
dispatcher,
rusoto_core::credential::StaticProvider::new_minimal(cred.access_key.to_string(), cred.secret_key.to_string()),
region,
let provider = rusoto_core::credential::StaticProvider::new_minimal(
cred.access_key.clone(),
cred.secret_key.clone(),
);

// create the bucket if not there
let create_bucket_request = CreateBucketRequest{
let client = S3Client::new_with(dispatcher, provider, region);

let create_bucket_request = CreateBucketRequest {
bucket: bucket.to_owned(),
..Default::default()
};

match client.create_bucket(create_bucket_request).await {
Ok(_) => Ok(Self {
client,
bucket: bucket.to_owned(),
}),
Err(err) => {
if let RusotoError::Service(CreateBucketError::BucketAlreadyOwnedByYou(_)) = err {
Ok(Self {
client,
bucket: bucket.to_owned(),
})
} else {
Err(format!("Error creating bucket: {:?}", err))
}
Ok(_) | Err(RusotoError::Service(CreateBucketError::BucketAlreadyOwnedByYou(_))) => {
Ok(Self {
client,
bucket: bucket.to_owned(),
})
}
Err(err) => Err(err).context("Error creating bucket"),
}
}

pub async fn set(&self, key: &str, data: &[u8]) -> Result<(), String> {
async fn set(&self, key: &str, data: &[u8]) -> Result<()> {
let put_object_request = PutObjectRequest {
bucket: self.bucket.to_owned(),
bucket: self.bucket.clone(),
key: key.to_owned(),
body: Some(data.to_vec().into()),
..Default::default()
};
match self.client.put_object(put_object_request).await {
Ok(_) => Ok(()),
Err(err) => Err(format!("Error uploading: {:?}", err)),
}
self.client
.put_object(put_object_request)
.await
.context("Error uploading")?;
Ok(())
}

pub async fn get(&self, key: &str) -> Result<Vec<u8>, String> {
async fn get(&self, key: &str) -> Result<Vec<u8>> {
let get_object_request = GetObjectRequest {
bucket: self.bucket.to_owned(),
bucket: self.bucket.clone(),
key: key.to_owned(),
..Default::default()
};

match self.client.get_object(get_object_request).await {
Ok(response) => {
if let Some(body) = response.body {
let mut buffer = Vec::new();
if let Err(io_err) = body.into_async_read().read_to_end(&mut buffer).await {
return Err(format!("Error reading data: {:?}", io_err))
} else {
return Ok(buffer);
}
} else {
return Err("No data found in S3 object.".to_string())
}
}
Err(err) => return Err(format!("Error retrieving data: {:?}", err)),
}
let res = self
.client
.get_object(get_object_request)
.await
.context("Error retrieving data")?;

// ensure body in not none
let body = res
.body
.ok_or_else(|| anyhow!("No data found in S3 object"))?;

let mut buffer = Vec::new();
body.into_async_read()
.read_to_end(&mut buffer)
.await
.context("Error reading data")?;

Ok(buffer)
}
}
}

0 comments on commit 5bb0268

Please sign in to comment.