use actix_web::{error::ErrorInternalServerError, web, HttpRequest, HttpResponse, Result}; use log::{info, warn, error}; use crate::app_state::AppState; use crate::thumbnail::{parse_thumbnail_request, find_closest_width, generate_thumbnails}; use crate::s3_utils::{load_file_from_s3, upload_to_s3}; use crate::handlers::serve_file::serve_file; /// Обработчик для скачивания файла и генерации миниатюры, если она недоступна. pub async fn proxy_handler( req: HttpRequest, requested_res: web::Path, state: web::Data, ) -> Result { info!("[proxy_handler] req.path: {}", req.path()); let requested_path = match state.get_path(&requested_res).await { Ok(Some(path)) => path, Ok(None) => { warn!("[proxy_handler] wrong request: {}", req.path()); return Ok(HttpResponse::NotFound().finish()); } Err(e) => { warn!("[proxy_handler] error: {}", e); return Ok(HttpResponse::InternalServerError().finish()); } }; info!("[proxy_handler] requested path: {}", requested_path); // Проверяем, запрошена ли миниатюра if let Some((base_filename, requested_width, extension)) = parse_thumbnail_request(&requested_res) { info!("[proxy_handler] thumbnail requested: {} width: {}, ext: {}", base_filename, requested_width, extension); // Находим ближайший подходящий размер let closest_width = find_closest_width(requested_width); let thumb_filekey = format!("{}_{}", base_filename, closest_width); info!("[proxy_handler] closest width: {}, thumb_filekey: {}", closest_width, thumb_filekey); // Проверяем наличие миниатюры в кэше let cached_files = state.get_cached_file_list().await; if !cached_files.contains(&thumb_filekey) { info!("[proxy_handler] no thumb found"); if cached_files.contains(&base_filename) { info!("[proxy_handler] no original file found"); // Загружаем оригинальный файл из S3 let original_data: Vec = load_file_from_s3(&state.storj_client, &state.storj_bucket, &base_filename).await?; // Генерируем миниатюру для ближайшего подходящего размера let image = image::load_from_memory(&original_data).map_err(|_| { ErrorInternalServerError("Failed to load image for thumbnail generation") })?; let thumbnails_bytes = generate_thumbnails(&image).await?; let thumbnail_bytes = thumbnails_bytes[&closest_width].clone(); // Загружаем миниатюру в S3 upload_to_s3( &state.storj_client, &state.storj_bucket, &thumb_filekey, thumbnail_bytes.clone(), "image/jpeg", ) .await?; info!("[proxy_handler] thumb was saved in storj"); return Ok(HttpResponse::Ok() .content_type("image/jpeg") .body(thumbnail_bytes)); } else { warn!("[proxy_handler] original was not found"); } } else { info!("[proxy_handler] thumb was found"); return serve_file(&thumb_filekey, &state).await; } } // Если запрошен целый файл info!("[proxy_handler] serving full file: {}", requested_path); match serve_file(&requested_path, &state).await { Ok(response) => Ok(response), Err(e) => { error!("[proxy_handler] error: {}", e); Err(e) } } }