[0.6.1] - 2025-09-02
Some checks failed
CI / lint (push) Successful in 2m11s
Deploy / deploy (push) Has been skipped
CI / test (push) Failing after 9m6s

### 🚀 Изменено - Упрощение архитектуры
- **Генерация миниатюр**: Полностью удалена из 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:
2025-09-02 14:39:54 +03:00
parent 7973ba0027
commit 7746d1f38e
21 changed files with 458 additions and 863 deletions

View File

@@ -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);