use actix_multipart::Multipart; use actix_web::{web, HttpRequest, HttpResponse, Result}; use log::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, ) -> Result { // Получаем токен из заголовка авторизации 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 { return Err(actix_web::error::ErrorUnauthorized("Quota exceeded")); // Квота превышена } // инкрементируем квоту пользователя let _ = state.increment_uploaded_bytes(&user_id, file_size).await?; // Определяем правильное расширение и ключ для S3 body = generate_key_with_extension(name, content_type.to_owned()); // Загружаем файл в S3 if let Err(e) = upload_to_s3( &state.storj_client, &state.bucket, &body, file_bytes, &content_type, ) .await { warn!("cannot upload to storj: {}", e); } else { warn!("file {} uploaded to storj", body); } // Сохраняем информацию о загруженном файле для пользователя user_added_file(&mut state.redis.clone(), &user_id, &body).await?; } } Ok(HttpResponse::Ok().body(body)) }