use aws_config::{BehaviorVersion, Region}; use aws_sdk_s3::{config::Credentials, Client, Config}; use std::env; #[derive(Debug)] pub struct S3ClientConfig { pub access_key: String, secret_key: String, endpoint: String, pub bucket: String, region: String, } impl S3ClientConfig { pub fn from_env() -> Result> { Ok(S3ClientConfig { access_key: env::var("LINODE_ACCESS_KEY") .map_err(|_| "LINODE_ACCESS_KEY environment variable not set")?, secret_key: env::var("LINODE_SECRET_KEY") .map_err(|_| "LINODE_SECRET_KEY environment variable not set")?, endpoint: env::var("LINODE_ENDPOINT") .unwrap_or_else(|_| "us-ord-1.linodeobjects.com".to_string()), bucket: env::var("LINODE_BUCKET") .map_err(|_| "LINODE_BUCKET environment variable not set")?, region: env::var("LINODE_REGION").unwrap_or_else(|_| "us-ord".to_string()), }) } } pub async fn create_s3_client( config: &S3ClientConfig, ) -> Result> { let credentials = Credentials::new( &config.access_key, &config.secret_key, None, None, "linode-object-storage", ); let s3_config = Config::builder() .behavior_version(BehaviorVersion::latest()) .region(Region::new(config.region.clone())) .endpoint_url(format!("https://{}", config.endpoint)) .credentials_provider(credentials) .force_path_style(false) .build(); Ok(Client::from_conf(s3_config)) } pub async fn upload( client: &Client, bucket: &str, key: &str, content: &str, ) -> Result<(), Box> { println!("Uploading to Linode Object Storage..."); println!("Bucket: {}", bucket); let put_object_req = client .put_object() .bucket(bucket) .key(key) .body(content.as_bytes().to_vec().into()) .acl(aws_sdk_s3::types::ObjectCannedAcl::PublicRead) .content_type("application/rss+xml") .send() .await?; println!("Upload successful! ETag: {:?}", put_object_req.e_tag()); Ok(()) }