use crate::{error::Error, secret::S3Secret};
use aws_config::{BehaviorVersion, Region};
use aws_credential_types::{Credentials, provider::SharedCredentialsProvider};
use aws_sdk_s3::Client;
use futures::executor::block_on;
use std::{convert::TryFrom, sync::Arc};
#[derive(Clone)]
pub struct S3Endpoint {
connection: Arc<Client>,
bucket: String,
}
impl TryFrom<&S3Secret> for S3Endpoint {
type Error = Error;
fn try_from(secret: &S3Secret) -> Result<Self, Self::Error> {
let connection = Self::connect(secret)?;
let connection = Arc::new(connection);
Ok(Self {
connection,
bucket: secret.bucket().to_string(),
})
}
}
impl S3Endpoint {
pub fn connect(secret: &S3Secret) -> Result<Client, Error> {
let region = secret.region()?;
let keys = Credentials::from_keys(secret.access_key(), secret.secret_key(), None);
let config_loader = aws_config::defaults(BehaviorVersion::latest())
.credentials_provider(keys)
.region(region.unwrap_or(Region::new("us-east-1")));
let config_loader = if let Some(hostname) = secret.hostname() {
config_loader.endpoint_url(hostname)
} else {
config_loader
};
let config = block_on(config_loader.load());
if let Some(role_name) = &secret.role_name() {
let provider = block_on(
aws_config::sts::AssumeRoleProvider::builder(role_name.clone())
.session_name(
secret
.session_name
.clone()
.unwrap_or("rs_transfer_session".into()),
)
.configure(&config)
.build(),
);
let sts_config = config
.to_builder()
.credentials_provider(SharedCredentialsProvider::new(provider))
.build();
let client = aws_sdk_sts::Client::new(&sts_config);
let req = client.get_caller_identity();
let resp = block_on(req.send());
match resp {
Ok(payload) => {
log::info!("Successfully assumed role for session.");
log::debug!(
"UserID : {}",
payload.user_id().unwrap_or_default()
);
log::debug!(
"Account: {}",
payload.account().unwrap_or_default()
);
log::debug!(
"Arn : {}",
payload.arn().unwrap_or_default()
);
}
Err(e) => log::error!("{e:?}"),
}
Ok(Client::new(&sts_config))
} else {
Ok(Client::new(&config))
}
}
pub fn connection(&self) -> Arc<Client> {
self.connection.clone()
}
pub fn bucket(&self) -> &str {
&self.bucket
}
}