use std::error::Error;
use std::process::exit;
use aws_config::meta::region::RegionProviderChain;
use aws_config::Region;
use aws_sdk_s3::Client;
use aws_sdk_s3::types::{CorsConfiguration, CorsRule};
use aws_sdk_s3::primitives::{ByteStream, SdkBody};
use aws_sdk_s3::types::Bucket;
use url::Url;
use crate::squire;
pub async fn get_client(
region: &Region
) -> Client {
let config = aws_config::from_env()
.region(region.clone())
.load().await;
Client::new(&config)
}
pub async fn get_region(
config: &squire::settings::Config
) -> Region {
if config.region.is_empty() {
let region_provider = RegionProviderChain::default_provider()
.or_else("us-east-1");
region_provider.region().await.unwrap()
} else {
Region::new(config.region.to_string())
}
}
pub async fn get_buckets(
client: &Client
) -> Option<Vec<Bucket>> {
match client.list_buckets().send().await {
Ok(output) => output.buckets,
Err(error) => {
eprintln!("{:?}", error.source().unwrap());
exit(1)
}
}
}
pub async fn upload_object(
client: &Client,
bucket_name: &String,
data: &String,
file_name: &String,
) {
let byte_stream = ByteStream::new(SdkBody::from(data.to_owned()));
match client
.put_object()
.bucket(bucket_name.to_string())
.key(file_name.to_string()) .body(byte_stream)
.content_type("text/html")
.send()
.await {
Ok(_) => println!("{:?} has been uploaded as HTML to {:?}", &file_name, &bucket_name),
Err(err) => {
eprintln!("Unable to upload to S3: {:?}", err.source().unwrap());
exit(1)
}
}
}
pub async fn update_cors(
client: &Client,
bucket_name: &String,
website: &Url
) {
let origin = website.to_string().strip_suffix("/").unwrap().to_string();
let new_rule = match CorsRule::builder()
.allowed_origins(&origin)
.allowed_methods("GET")
.max_age_seconds(3000)
.build()
{
Ok(rule) => rule,
Err(err) => {
eprintln!("Unable to create CORS rule: {:?}", err.source().unwrap());
exit(1)
},
};
let existing_rules = match client
.get_bucket_cors()
.bucket(bucket_name)
.send()
.await
{
Ok(output) => output.cors_rules.unwrap_or_default(),
Err(_) => {
Vec::new()
}
};
let rule_exists = existing_rules.iter().any(|rule| {
rule.allowed_origins()
.contains(&origin)
&&
rule.allowed_methods()
.contains(&"GET".to_string())
&&
rule.max_age_seconds() == Some(3000)
});
if rule_exists {
println!("CORS rule already exists for {}", origin);
return;
}
let mut updated_rules = existing_rules;
updated_rules.push(new_rule);
let cors_config = match CorsConfiguration::builder()
.set_cors_rules(Some(updated_rules))
.build()
{
Ok(config) => config,
Err(err) => {
eprintln!("Unable to create CORS config: {:?}", err.source().unwrap());
exit(1)
},
};
match client
.put_bucket_cors()
.bucket(bucket_name)
.cors_configuration(cors_config)
.send()
.await
{
Ok(_) => println!("CORS configuration has been updated for: {:?}", origin),
Err(err) => {
eprintln!("Unable to update CORS configuration: {:?}", err.source().unwrap());
exit(1)
},
}
}