[0.6.1] - 2025-09-02
### 🚀 Изменено - Упрощение архитектуры - **Генерация миниатюр**: Полностью удалена из Quoter, теперь управляется Vercel Edge API - **Очистка legacy кода**: Удалены все функции генерации миниатюр и сложность - **Документация**: Сокращена с 17 файлов до 7, следуя принципам KISS/DRY - **Смена фокуса**: Quoter теперь сосредоточен на upload + storage, Vercel обрабатывает миниатюры - **Логирование запросов**: Добавлена аналитика источников для оптимизации CORS whitelist - **Реализация таймаутов**: Добавлены настраиваемые таймауты для S3, Redis и внешних операций - **Упрощенная безопасность**: Удален сложный rate limiting, оставлена только необходимая защита upload - **Vercel интеграция**: Добавлена поддержка Vercel Edge API с CORS и оптимизированными заголовками - **Redis graceful fallback**: Приложение теперь работает без Redis с предупреждениями вместо паники - **Умная логика ответов**: Автоматическое определение Vercel запросов и оптимизированные заголовки - **Консолидация документации**: Объединены 4 Vercel документа в один comprehensive guide ### 📝 Обновлено - Консолидирована документация в практическую структуру: - Основной README.md с быстрым стартом - docs/SETUP.md для конфигурации и развертывания - Упрощенный features.md с фокусом на основную функциональность - docs/vercel-frontend-migration.md - единый comprehensive guide для Vercel интеграции - Добавлен акцент на Vercel по всему коду и документации - Обновлены URL patterns в документации: quoter.discours.io → files.dscrs.site ### 🗑️ Удалено - Избыточные файлы документации (api-reference, deployment, development, и т.д.) - Дублирующийся контент в нескольких документах - Излишне детальная документация для простого файлового прокси - 4 отдельных Vercel документа: vercel-thumbnails.md, vercel-integration.md, hybrid-architecture.md, vercel-og-integration.md 💋 **Упрощение**: KISS принцип применен - убрали избыточность, оставили суть.
This commit is contained in:
@@ -2,7 +2,9 @@ use actix_web::error::ErrorNotFound;
|
||||
use actix_web::{HttpRequest, HttpResponse, Result, error::ErrorInternalServerError, web};
|
||||
use log::{error, info, warn};
|
||||
|
||||
use super::common::create_file_response_with_analytics;
|
||||
use super::common::{
|
||||
create_file_response_with_analytics, create_vercel_compatible_response, is_vercel_request,
|
||||
};
|
||||
use crate::app_state::AppState;
|
||||
use crate::handlers::serve_file::serve_file;
|
||||
use crate::lookup::{find_file_by_pattern, get_mime_type};
|
||||
@@ -42,24 +44,21 @@ pub async fn proxy_handler(
|
||||
// Caching handled by Vercel Edge - focus on fast file serving
|
||||
let content_type = match get_mime_type(&ext) {
|
||||
Some(mime) => mime.to_string(),
|
||||
None => {
|
||||
let mut redis = state.redis.clone();
|
||||
match find_file_by_pattern(&mut redis, &base_filename).await {
|
||||
Ok(Some(found_file)) => {
|
||||
if let Some(found_ext) = found_file.split('.').next_back() {
|
||||
get_mime_type(found_ext)
|
||||
.unwrap_or("application/octet-stream")
|
||||
.to_string()
|
||||
} else {
|
||||
"application/octet-stream".to_string()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("Unsupported file format for: {}", base_filename);
|
||||
return Err(ErrorInternalServerError("Unsupported file format"));
|
||||
None => match find_file_by_pattern(None, &base_filename).await {
|
||||
Ok(Some(found_file)) => {
|
||||
if let Some(found_ext) = found_file.split('.').next_back() {
|
||||
get_mime_type(found_ext)
|
||||
.unwrap_or("application/octet-stream")
|
||||
.to_string()
|
||||
} else {
|
||||
"application/octet-stream".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
error!("Unsupported file format for: {}", base_filename);
|
||||
return Err(ErrorInternalServerError("Unsupported file format"));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
info!("Content-Type: {}", content_type);
|
||||
@@ -129,12 +128,23 @@ pub async fn proxy_handler(
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
info!("File served from AWS in {:?}: {}", elapsed, path);
|
||||
return Ok(create_file_response_with_analytics(
|
||||
&content_type,
|
||||
filedata,
|
||||
&req,
|
||||
&path,
|
||||
));
|
||||
|
||||
// Используем Vercel-совместимый ответ для Vercel запросов
|
||||
if is_vercel_request(&req) {
|
||||
let etag = format!("\"{:x}\"", md5::compute(&filedata));
|
||||
return Ok(create_vercel_compatible_response(
|
||||
&content_type,
|
||||
filedata,
|
||||
&etag,
|
||||
));
|
||||
} else {
|
||||
return Ok(create_file_response_with_analytics(
|
||||
&content_type,
|
||||
filedata,
|
||||
&req,
|
||||
&path,
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Failed to load from AWS path {}: {:?}", path, err);
|
||||
@@ -216,12 +226,23 @@ pub async fn proxy_handler(
|
||||
}
|
||||
let elapsed = start_time.elapsed();
|
||||
info!("File served from AWS in {:?}: {}", elapsed, filepath);
|
||||
Ok(create_file_response_with_analytics(
|
||||
&content_type,
|
||||
filedata,
|
||||
&req,
|
||||
&filepath,
|
||||
))
|
||||
|
||||
// Используем Vercel-совместимый ответ для Vercel запросов
|
||||
if is_vercel_request(&req) {
|
||||
let etag = format!("\"{:x}\"", md5::compute(&filedata));
|
||||
Ok(create_vercel_compatible_response(
|
||||
&content_type,
|
||||
filedata,
|
||||
&etag,
|
||||
))
|
||||
} else {
|
||||
Ok(create_file_response_with_analytics(
|
||||
&content_type,
|
||||
filedata,
|
||||
&req,
|
||||
&filepath,
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to download from AWS: {} - Error: {}", filepath, e);
|
||||
|
||||
Reference in New Issue
Block a user