Trabalhando com S3 e armazenamentos em nuvem em Rust: biblioteca aws-sdk-s3
Armazenamentos de objetos em nuvem, como Amazon S3, tornaram-se padrão para armazenamento e entrega de arquivos, backups e conteúdo de mídia. Rust, como linguagem de programação de sistemas, oferece ferramentas poderosas e seguras para integração com esses serviços. A biblioteca principal é aws-sdk-s3 — o SDK oficial da Amazon para Rust.
Neste artigo, vamos abordar como configurar o projeto, realizar operações básicas (upload, download, exclusão) e trabalhar com armazenamentos compatíveis com S3 (por exemplo, MinIO ou Yandex Object Storage).
Instalação e configuração
Adicione ao Cargo.toml:
[dependencies]aws-sdk-s3 = "1.0"aws-config = "1.0"tokio = { version = "1", features = ["full"] }Para autenticação, use variáveis de ambiente ou o arquivo ~/.aws/credentials:
export AWS_ACCESS_KEY_ID="your_access_key"export AWS_SECRET_ACCESS_KEY="your_secret_key"export AWS_DEFAULT_REGION="us-east-1"Inicialização do cliente
Vamos criar um cliente S3 assíncrono:
use aws_sdk_s3::Client;use aws_config::load_defaults;use aws_config::BehaviorVersion;
#[tokio::main]async fn main() { let config = load_defaults(BehaviorVersion::latest()).await; let client = Client::new(&config); // agora o client está pronto para uso}Upload de arquivo para S3 (Upload)
Para fazer upload de dados, use o método put_object. Os dados podem ser passados como bytes ou a partir de um stream:
use aws_sdk_s3::primitives::ByteStream;use std::path::Path;
async fn upload_file(client: &Client, bucket: &str, key: &str, file_path: &str) -> Result<(), Box<dyn std::error::Error>> { let body = ByteStream::from_path(Path::new(file_path)).await?; client .put_object() .bucket(bucket) .key(key) .body(body) .send() .await?; println!("Arquivo {} enviado para {}/{}", file_path, bucket, key); Ok(())}Download de arquivo (Get Object)
Para obter um objeto e salvá-lo localmente:
use tokio::io::AsyncWriteExt;
async fn download_file(client: &Client, bucket: &str, key: &str, dest_path: &str) -> Result<(), Box<dyn std::error::Error>> { let response = client .get_object() .bucket(bucket) .key(key) .send() .await?; let mut file = tokio::fs::File::create(dest_path).await?; let mut stream = response.body; while let Some(bytes) = stream.try_next().await? { file.write_all(&bytes).await?; } println!("Arquivo {}/{} baixado para {}", bucket, key, dest_path); Ok(())}Listagem de objetos no bucket
Obter a lista de arquivos (chaves) no bucket:
async fn list_objects(client: &Client, bucket: &str) -> Result<(), Box<dyn std::error::Error>> { let objects = client .list_objects_v2() .bucket(bucket) .send() .await?; if let Some(contents) = objects.contents { for obj in contents { if let Some(key) = obj.key { println!("- {}", key); } } } Ok(())}Exclusão de objeto
async fn delete_object(client: &Client, bucket: &str, key: &str) -> Result<(), Box<dyn std::error::Error>> { client .delete_object() .bucket(bucket) .key(key) .send() .await?; println!("Objeto {}/{} excluído", bucket, key); Ok(())}Trabalhando com MinIO e outros armazenamentos compatíveis com S3
Para conectar-se ao MinIO (emulador S3 local) ou Yandex Object Storage, é necessário substituir o endp