العمل مع S3 والتخزين السحابي في Rust: مكتبة aws-sdk-s3
\n\nأصبحت مخازن الكائنات السحابية، مثل Amazon S3، المعيار لتخزين وتسليم الملفات والنسخ الاحتياطية ومحتوى الوسائط. تقدم Rust، كلغة برمجة نظامية، أدوات قوية وآمنة للتكامل مع هذه الخدمات. المكتبة الرئيسية هي aws-sdk-s3 — SDK الرسمي من Amazon لـ Rust.
في هذه المقالة، سنشرح كيفية إعداد المشروع، وتنفيذ العمليات الأساسية (الرفع، التنزيل، الحذف)، والعمل مع مخازن متوافقة مع S3 (مثل MinIO أو Yandex Object Storage).
\n\nالتثبيت والإعداد
\n\nأضف إلى Cargo.toml:
[dependencies]\naws-sdk-s3 = "1.0"\naws-config = "1.0"\ntokio = { version = "1", features = ["full"] }\n\n\nللمصادقة، يتم استخدام متغيرات البيئة أو ملف ~/.aws/credentials:
export AWS_ACCESS_KEY_ID="your_access_key"\nexport AWS_SECRET_ACCESS_KEY="your_secret_key"\nexport AWS_DEFAULT_REGION="us-east-1"\n\n\nتهيئة العميل
\n\nلنقم بإنشاء عميل S3 غير متزامن:
\n\nuse aws_sdk_s3::Client;\nuse aws_config::load_defaults;\nuse aws_config::BehaviorVersion;\n\n#[tokio::main]\nasync fn main() {\n let config = load_defaults(BehaviorVersion::latest()).await;\n let client = Client::new(&config);\n // الآن العميل جاهز للعمل\n}\n\n\nرفع ملف إلى S3 (Upload)
\n\nلرفع البيانات، يتم استخدام طريقة put_object. يمكن تمرير البيانات كبايتات أو من تيار:
use aws_sdk_s3::primitives::ByteStream;\nuse std::path::Path;\n\nasync fn upload_file(client: &Client, bucket: &str, key: &str, file_path: &str) -> Result<(), Box<dyn std::error::Error>> {\n let body = ByteStream::from_path(Path::new(file_path)).await?;\n \n client\n .put_object()\n .bucket(bucket)\n .key(key)\n .body(body)\n .send()\n .await?;\n \n println!("تم رفع الملف {} إلى {}/{}", file_path, bucket, key);\n Ok(())\n}\n\n\nتنزيل ملف (Get Object)
\n\nلجلب كائن وحفظه محلياً:
\n\nuse tokio::io::AsyncWriteExt;\n\nasync fn download_file(client: &Client, bucket: &str, key: &str, dest_path: &str) -> Result<(), Box<dyn std::error::Error>> {\n let response = client\n .get_object()\n .bucket(bucket)\n .key(key)\n .send()\n .await?;\n \n let mut file = tokio::fs::File::create(dest_path).await?;\n let mut stream = response.body;\n \n while let Some(bytes) = stream.try_next().await? {\n file.write_all(&bytes).await?;\n }\n \n println!("تم تنزيل الملف {}/{} إلى {}", bucket, key, dest_path);\n Ok(())\n}\n\n\nقائمة الكائنات في الحاوية
\n\nالحصول على قائمة الملفات (المفاتيح) في الحاوية:
\n\nasync fn list_objects(client: &Client, bucket: &str) -> Result<(), Box<dyn std::error::Error>> {\n let objects = client\n .list_objects_v2()\n .bucket(bucket)\n .send()\n .await?;\n \n if let Some(contents) = objects.contents {\n for obj in contents {\n if let Some(key) = obj.key {\n println!("- {}", key);\n }\n }\n }\n Ok(())\n}\n\n\nحذف كائن
\n\nasync fn delete_object(client: &Client, bucket: &str, key: &str) -> Result<(), Box<dyn std::error::Error>> {\n client\n .delete_object()\n .bucket(bucket)\n .key(key)\n .send()\n .await?;\n \n println!("تم حذف الكائن {}/{}", bucket, key);\n Ok(())\n}\n\n\nالعمل مع MinIO ومخازن أخرى متوافقة مع S3
\n\nللاتصال بـ MinIO (محاكي S3 محلي) أو Yandex Object Storage، يجب إعادة تعريف نقطة النهاية (endpoint)