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(
|
|
|
|
|
s3_client: &S3Client,
|
|
|
|
|
bucket: &str,
|
|
|
|
|
key: &str,
|
|
|
|
|
body: Vec<u8>,
|
|
|
|
|
content_type: &str,
|
|
|
|
|
) -> Result<String, actix_web::Error> {
|
|
|
|
|
let body_stream = ByteStream::from(body); // Преобразуем тело файла в поток байтов
|
|
|
|
|
s3_client
|
|
|
|
|
.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(
|
|
|
|
|
s3_client: &S3Client,
|
|
|
|
|
bucket: &str,
|
2024-10-21 21:36:42 +00:00
|
|
|
|
file_key: &str,
|
2024-08-31 00:32:37 +00:00
|
|
|
|
) -> Result<bool, actix_web::Error> {
|
2024-10-21 21:36:42 +00:00
|
|
|
|
match s3_client.head_object().bucket(bucket).key(file_key).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(
|
|
|
|
|
s3_client: &S3Client,
|
|
|
|
|
bucket: &str,
|
|
|
|
|
key: &str,
|
|
|
|
|
) -> Result<Vec<u8>, actix_web::Error> {
|
|
|
|
|
let get_object_output = s3_client
|
|
|
|
|
.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
|
|
|
|
|
}
|