quoter/src/s3_utils.rs

107 lines
3.8 KiB
Rust
Raw Normal View History

2024-08-31 00:32:37 +00:00
use actix_web::error::ErrorInternalServerError;
use aws_sdk_s3::{error::SdkError, primitives::ByteStream, Client as S3Client};
use mime_guess::mime;
2024-09-23 15:16:47 +00:00
use std::str::FromStr;
2024-08-31 00:32:37 +00:00
/// Загружает файл в S3 хранилище.
pub async fn upload_to_s3(
2024-10-22 06:38:30 +00:00
storj_client: &S3Client,
2024-08-31 00:32:37 +00:00
bucket: &str,
key: &str,
body: Vec<u8>,
content_type: &str,
) -> Result<String, actix_web::Error> {
let body_stream = ByteStream::from(body); // Преобразуем тело файла в поток байтов
2024-10-22 06:38:30 +00:00
storj_client
2024-08-31 00:32:37 +00:00
.put_object()
.bucket(bucket)
.key(key)
.body(body_stream)
.content_type(content_type)
.send()
.await
.map_err(|_| ErrorInternalServerError("Failed to upload file to S3"))?; // Загрузка файла в S3
Ok(key.to_string()) // Возвращаем ключ файла
}
/// Проверяет, существует ли файл в S3.
pub async fn check_file_exists(
2024-10-22 09:24:47 +00:00
s3_client: &S3Client,
2024-08-31 00:32:37 +00:00
bucket: &str,
2024-10-22 09:24:47 +00:00
filepath: &str,
2024-08-31 00:32:37 +00:00
) -> Result<bool, actix_web::Error> {
2024-10-22 09:24:47 +00:00
match s3_client.head_object().bucket(bucket).key(filepath).send().await {
2024-08-31 00:32:37 +00:00
Ok(_) => Ok(true), // Файл найден
Err(SdkError::ServiceError(service_error)) if service_error.err().is_not_found() => {
Ok(false) // Файл не найден
}
Err(e) => Err(ErrorInternalServerError(e.to_string())), // Ошибка при проверке
}
}
/// Загружает файл из S3.
pub async fn load_file_from_s3(
2024-10-22 06:38:30 +00:00
storj_client: &S3Client,
2024-08-31 00:32:37 +00:00
bucket: &str,
key: &str,
) -> Result<Vec<u8>, actix_web::Error> {
2024-10-22 06:38:30 +00:00
let get_object_output = storj_client
2024-08-31 00:32:37 +00:00
.get_object()
.bucket(bucket)
.key(key)
.send()
.await
.map_err(|_| ErrorInternalServerError("Failed to get object from S3"))?;
let data: aws_sdk_s3::primitives::AggregatedBytes = get_object_output
.body
.collect()
.await
.map_err(|_| ErrorInternalServerError("Failed to read object body"))?;
Ok(data.to_vec())
}
/// Генерирует ключ с правильным расширением на основе MIME-типа.
pub fn generate_key_with_extension(base_key: String, mime_type: String) -> String {
let mime: mime::Mime =
mime::Mime::from_str(&mime_type).unwrap_or(mime::APPLICATION_OCTET_STREAM);
if let Some(extensions) = mime_guess::get_mime_extensions_str(mime.as_ref()) {
if let Some(extension) = extensions.first() {
return format!("{}.{}", base_key, extension);
}
}
base_key
}
2024-10-22 09:24:47 +00:00
/// список файлов из S3
pub async fn get_s3_filelist(client: &S3Client, bucket: &str) -> Vec<[std::string::String; 2]> {
let mut filekeys = Vec::new();
// Запрашиваем список файлов из S3
let list_objects_v2 = client.list_objects_v2();
let list_response = list_objects_v2
.bucket(bucket)
.send()
.await
.expect("Failed to list files from Storj");
if let Some(objects) = list_response.contents {
for object in objects.iter() {
if let Some(s3_filepath) = &object.key {
let filepath = match s3_filepath.ends_with("/webp") {
true => &s3_filepath.replace("/webp", ""),
false => s3_filepath,
};
let mut parts = filepath.split('/').collect::<Vec<&str>>(); // Explicit type annotation
let filename = parts.pop().unwrap();
let mut filename_parts = filename.split('.').collect::<Vec<&str>>();
2024-10-22 09:30:27 +00:00
let _ext = filename_parts.pop().unwrap_or_default();
if let Some(filekey) = filename_parts.pop() {
filekeys.push([filekey.to_string(), s3_filepath.to_string()]);
}
2024-10-22 09:24:47 +00:00
}
}
}
filekeys
}