quoter/src/handlers/upload.rs
Untone be8c03eb11
Some checks failed
deploy / deploy (push) Failing after 5s
quota-rollback+logs
2024-11-12 12:29:19 +03:00

98 lines
4.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use actix_multipart::Multipart;
use actix_web::{web, HttpRequest, HttpResponse, Result};
use log::{error, warn};
use crate::app_state::AppState;
use crate::auth::{get_id_by_token, user_added_file};
use crate::s3_utils::{generate_key_with_extension, upload_to_s3};
use futures::TryStreamExt;
use crate::handlers::MAX_WEEK_BYTES;
/// Обработчик для аплоада файлов.
pub async fn upload_handler(
req: HttpRequest,
mut payload: Multipart,
state: web::Data<AppState>,
) -> Result<HttpResponse, actix_web::Error> {
// Получаем токен из заголовка авторизации
let token = req
.headers()
.get("Authorization")
.and_then(|header_value| header_value.to_str().ok());
if token.is_none() {
return Err(actix_web::error::ErrorUnauthorized("Unauthorized")); // Если токен отсутствует, возвращаем ошибку
}
let user_id = get_id_by_token(token.unwrap()).await?;
// Получаем текущую квоту пользователя
let this_week_amount: u64 = state.get_or_create_quota(&user_id).await.unwrap_or(0);
let mut body = "ok".to_string();
while let Ok(Some(field)) = payload.try_next().await {
let mut field = field;
let content_type = field.content_type().unwrap().to_string();
let file_name = field
.content_disposition()
.unwrap()
.get_filename()
.map(|f| f.to_string());
if let Some(name) = file_name {
let mut file_bytes = Vec::new();
let mut file_size: u64 = 0;
// Читаем данные файла
while let Ok(Some(chunk)) = field.try_next().await {
file_size += chunk.len() as u64;
file_bytes.extend_from_slice(&chunk);
}
// Проверяем, что добавление файла не превышает лимит квоты
if this_week_amount + file_size > MAX_WEEK_BYTES {
warn!("Quota would exceed limit: current={}, adding={}, limit={}",
this_week_amount, file_size, MAX_WEEK_BYTES);
return Err(actix_web::error::ErrorUnauthorized("Quota exceeded"));
}
// Загружаем файл в S3 storj с использованием ключа в нижнем регистре
let filekey = generate_key_with_extension(name.clone(), content_type.to_owned());
let orig_path = name.clone();
match upload_to_s3(
&state.storj_client,
&state.bucket,
&filekey,
file_bytes.clone(),
&content_type,
).await {
Ok(_) => {
warn!("file {} uploaded to storj, incrementing quota by {} bytes", filekey, file_size);
// Инкрементируем квоту только после успешной загрузки
if let Err(e) = state.increment_uploaded_bytes(&user_id, file_size).await {
error!("Failed to increment quota: {}", e);
// Можно добавить откат загрузки файла здесь
return Err(e);
}
// Сохраняем информацию о загруженном файле
user_added_file(&mut state.redis.clone(), &user_id, &filekey).await?;
state.set_path(&filekey, &orig_path).await;
// Логируем новое значение квоты
if let Ok(new_quota) = state.get_or_create_quota(&user_id).await {
warn!("New quota for user {}: {} bytes", user_id, new_quota);
}
body = filekey;
}
Err(e) => {
warn!("Failed to upload to storj: {}", e);
return Err(actix_web::error::ErrorInternalServerError(e));
}
}
}
}
Ok(HttpResponse::Ok().body(body))
}