| from contextlib import asynccontextmanager |
| from pathlib import Path |
|
|
| from fastapi import FastAPI |
| from fastapi.staticfiles import StaticFiles |
| from fastapi.templating import Jinja2Templates |
|
|
| from app.config.config import settings, sync_initial_settings |
| from app.database.connection import connect_to_db, disconnect_from_db |
| from app.database.initialization import initialize_database |
| from app.exception.exceptions import setup_exception_handlers |
| from app.log.logger import get_application_logger, setup_access_logging |
| from app.middleware.middleware import setup_middlewares |
| from app.router.routes import setup_routers |
| from app.scheduler.scheduled_tasks import start_scheduler, stop_scheduler |
| from app.service.key.key_manager import get_key_manager_instance |
| from app.service.update.update_service import check_for_updates |
| from app.utils.helpers import get_current_version |
|
|
| logger = get_application_logger() |
|
|
| PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent |
| STATIC_DIR = PROJECT_ROOT / "app" / "static" |
| TEMPLATES_DIR = PROJECT_ROOT / "app" / "templates" |
|
|
| |
| templates = Jinja2Templates(directory="app/templates") |
|
|
|
|
| |
| def update_template_globals(app: FastAPI, update_info: dict): |
| |
| |
| |
| app.state.update_info = update_info |
| logger.info(f"Update info stored in app.state: {update_info}") |
|
|
|
|
| |
| async def _setup_database_and_config(app_settings): |
| """Initializes database, syncs settings, and initializes KeyManager.""" |
| initialize_database() |
| logger.info("Database initialized successfully") |
| await connect_to_db() |
| await sync_initial_settings() |
| await get_key_manager_instance(app_settings.API_KEYS, app_settings.VERTEX_API_KEYS) |
| logger.info("Database, config sync, and KeyManager initialized successfully") |
|
|
|
|
| async def _shutdown_database(): |
| """Disconnects from the database.""" |
| await disconnect_from_db() |
|
|
|
|
| def _start_scheduler(): |
| """Starts the background scheduler.""" |
| try: |
| start_scheduler() |
| logger.info("Scheduler started successfully.") |
| except Exception as e: |
| logger.error(f"Failed to start scheduler: {e}") |
|
|
|
|
| def _stop_scheduler(): |
| """Stops the background scheduler.""" |
| stop_scheduler() |
|
|
|
|
| async def _perform_update_check(app: FastAPI): |
| """Checks for updates and stores the info in app.state.""" |
| update_available, latest_version, error_message = await check_for_updates() |
| current_version = get_current_version() |
| update_info = { |
| "update_available": update_available, |
| "latest_version": latest_version, |
| "error_message": error_message, |
| "current_version": current_version, |
| } |
| if not hasattr(app, "state"): |
| from starlette.datastructures import State |
|
|
| app.state = State() |
| app.state.update_info = update_info |
| logger.info(f"Update check completed. Info: {update_info}") |
|
|
|
|
| @asynccontextmanager |
| async def lifespan(app: FastAPI): |
| """ |
| Manages the application startup and shutdown events. |
| |
| Args: |
| app: FastAPI应用实例 |
| """ |
| logger.info("Application starting up...") |
| try: |
| await _setup_database_and_config(settings) |
| await _perform_update_check(app) |
| _start_scheduler() |
|
|
| except Exception as e: |
| logger.critical( |
| f"Critical error during application startup: {str(e)}", exc_info=True |
| ) |
|
|
| yield |
|
|
| logger.info("Application shutting down...") |
| _stop_scheduler() |
| await _shutdown_database() |
|
|
|
|
| def create_app() -> FastAPI: |
| """ |
| 创建并配置FastAPI应用程序实例 |
| |
| Returns: |
| FastAPI: 配置好的FastAPI应用程序实例 |
| """ |
|
|
| |
| current_version = get_current_version() |
| app = FastAPI( |
| title="Gemini Balance API", |
| description="Gemini API代理服务,支持负载均衡和密钥管理", |
| version=current_version, |
| lifespan=lifespan, |
| ) |
|
|
| if not hasattr(app, "state"): |
| from starlette.datastructures import State |
|
|
| app.state = State() |
| app.state.update_info = { |
| "update_available": False, |
| "latest_version": None, |
| "error_message": "Initializing...", |
| "current_version": current_version, |
| } |
|
|
| |
| app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") |
|
|
| |
| setup_middlewares(app) |
|
|
| |
| setup_exception_handlers(app) |
|
|
| |
| setup_routers(app) |
|
|
| |
| setup_access_logging() |
|
|
| return app |
|
|