diff --git a/server/main.py b/server/main.py index f1bb2ae..715d1ee 100644 --- a/server/main.py +++ b/server/main.py @@ -1,30 +1,23 @@ import re -from fastapi import Depends, FastAPI, HTTPException, Request, Response -from fastapi.responses import FileResponse, JSONResponse from contextlib import asynccontextmanager +from datetime import datetime from pathlib import Path +from urllib.parse import urlparse + +import httpx import json import structlog from cachetools import TTLCache -import logging -from datetime import datetime +from fastapi import Depends, FastAPI, HTTPException, Request, Response +from fastapi.responses import FileResponse, JSONResponse from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol -from cachetools import TTLCache -from urllib.parse import urlparse - from pack_manager import DATA_DIR, scan_pack, get_cached_manifest, PACKS_DIR from models import PackMeta from middleware import LoggingMiddleware from cli import parse_args, run_test_mode, run_production_mode, run_development_mode from log_manager import init_logging -from fastapi.responses import Response - -import httpx -import base64 -from fastapi.responses import StreamingResponse - from auth import get_current_user, router as auth_router, init_db, verify_jwt from roles import Permissions, has_permission from admin_router import router as admin_router @@ -43,7 +36,6 @@ async def lifespan(app: FastAPI): # Initialize logging init_logging() - #logger = logging.getLogger(__name__) # Determine environment if args.test: @@ -60,8 +52,6 @@ async def lifespan(app: FastAPI): PACKS_DIR.mkdir(exist_ok=True) DATA_DIR.mkdir(exist_ok=True) - BLOCKED_HOSTS = [] - init_db() if args.test: @@ -84,7 +74,17 @@ async def lifespan(app: FastAPI): logger.error(f"Failed to scan pack: {pack_dir.name} - {e}", exc_info=True) logger.info("All packs ready. Server is running.") + + # Initialize proxy client + global proxy_client + proxy_client = httpx.AsyncClient(timeout=60.0, follow_redirects=True) + yield + + # Cleanup proxy client + if proxy_client: + await proxy_client.aclose() + logger.info("Server shutting down...") @@ -432,9 +432,7 @@ def patched_data_received(self, data): return original_data_received(self, data) except Exception as e: client = self.transport.get_extra_info('peername') - logger = logging.getLogger(__name__) - # Показываем первые 200 байт запроса в HEX для диагностики hex_preview = data[:100].hex() if len(data) > 0 else "empty" logger.error(f"Invalid HTTP request from {client}") @@ -444,16 +442,14 @@ def patched_data_received(self, data): try: raw_data = data[:500].decode('utf-8', errors='replace') logger.error(f"Raw request data: {repr(raw_data)}") - except: + except Exception: pass - # Не перевыбрасываем исключение, а возвращаем 400 ответ - # Это важно! Иначе клиент не получит ответ try: response = b"HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: 21\r\n\r\nInvalid HTTP request" self.transport.write(response) self.transport.close() - except: + except Exception: pass return @@ -465,7 +461,6 @@ HttpToolsProtocol.data_received = patched_data_received @app.get("/") async def root(): """Root endpoint""" - logger = logging.getLogger(__name__) logger.info("Root endpoint accessed") return { "status": "ok", @@ -856,8 +851,8 @@ async def get_launcher_full_info(): # Эти эндпоинты позволяют клиентам с сетевыми проблемами # скачивать файлы через сервер Zern -# Создаем HTTP клиент для прокси -proxy_client = httpx.AsyncClient(timeout=60.0, follow_redirects=True) +# HTTP клиент для прокси — создаётся в lifespan, закрывается при shutdown +proxy_client: httpx.AsyncClient | None = None # Кэш для часто запрашиваемых данных (5 минут) proxy_cache = TTLCache(maxsize=50, ttl=300) @@ -1192,12 +1187,6 @@ async def global_exception_handler(request: Request, exc: Exception): ) -# Cleanup on shutdown -@app.on_event("shutdown") -async def shutdown_proxy(): - await proxy_client.close() - - # ====================== ЗАПУСК ====================== if __name__ == "__main__":