mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-05-25 02:09:32 +08:00
refactor: 更新日志格式,增强可读性;移除初始化模块,整合初始化逻辑
This commit is contained in:
@@ -199,7 +199,7 @@ async def sync_initial_settings():
|
||||
|
||||
if type_match:
|
||||
setattr(settings, key, parsed_db_value)
|
||||
logger.info(f"Updated setting '{key}' in memory from database value ({target_type}).")
|
||||
logger.debug(f"Updated setting '{key}' in memory from database value ({target_type}).")
|
||||
updated_in_memory = True
|
||||
else:
|
||||
logger.warning(f"Parsed DB value type mismatch for key '{key}'. Expected {target_type}, got {type(parsed_db_value)}. Skipping update.")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path # Add pathlib import
|
||||
from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
@@ -9,7 +10,6 @@ from app.middleware.middleware import setup_middlewares
|
||||
from app.exception.exceptions import setup_exception_handlers
|
||||
from app.router.routes import setup_routers
|
||||
from app.service.key.key_manager import get_key_manager_instance
|
||||
from app.core.initialization import initialize_app
|
||||
from app.database.connection import connect_to_db, disconnect_from_db
|
||||
from app.database.initialization import initialize_database
|
||||
from app.scheduler.key_checker import start_scheduler, stop_scheduler
|
||||
@@ -17,23 +17,30 @@ from app.service.update.update_service import check_for_updates
|
||||
|
||||
logger = get_application_logger()
|
||||
|
||||
VERSION_FILE_PATH = "VERSION" # Path relative to project root
|
||||
# Define project paths using pathlib
|
||||
# Assuming this file is at app/core/application.py
|
||||
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
VERSION_FILE_PATH = PROJECT_ROOT / "VERSION"
|
||||
STATIC_DIR = PROJECT_ROOT / "app" / "static"
|
||||
TEMPLATES_DIR = PROJECT_ROOT / "app" / "templates"
|
||||
|
||||
|
||||
def _get_current_version(default_version: str = "0.0.0") -> str:
|
||||
"""Reads the current version from the VERSION file."""
|
||||
version_file = VERSION_FILE_PATH # Use Path object
|
||||
try:
|
||||
# Assuming execution from project root d:/develop/pythonProjects/gemini-balance
|
||||
with open(VERSION_FILE_PATH, 'r', encoding='utf-8') as f:
|
||||
# Use Path object's open method
|
||||
with version_file.open('r', encoding='utf-8') as f:
|
||||
version = f.read().strip()
|
||||
if not version:
|
||||
logger.warning(f"VERSION file ('{VERSION_FILE_PATH}') is empty. Using default version '{default_version}'.")
|
||||
logger.warning(f"VERSION file ('{version_file}') is empty. Using default version '{default_version}'.")
|
||||
return default_version
|
||||
return version
|
||||
except FileNotFoundError:
|
||||
logger.warning(f"VERSION file not found at '{VERSION_FILE_PATH}'. Using default version '{default_version}'.")
|
||||
logger.warning(f"VERSION file not found at '{version_file}'. Using default version '{default_version}'.")
|
||||
return default_version
|
||||
except IOError as e:
|
||||
logger.error(f"Error reading VERSION file ('{VERSION_FILE_PATH}'): {e}. Using default version '{default_version}'.")
|
||||
logger.error(f"Error reading VERSION file ('{version_file}'): {e}. Using default version '{default_version}'.")
|
||||
return default_version
|
||||
|
||||
# 初始化模板引擎,并添加全局变量
|
||||
@@ -48,67 +55,87 @@ def update_template_globals(app: FastAPI, update_info: dict):
|
||||
logger.info(f"Update info stored in app.state: {update_info}")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""
|
||||
应用程序生命周期管理器
|
||||
|
||||
Args:
|
||||
app: FastAPI应用实例
|
||||
"""
|
||||
# 启动事件
|
||||
logger.info("Application starting up...")
|
||||
try:
|
||||
# 初始化数据库
|
||||
initialize_database()
|
||||
logger.info("Database initialized successfully")
|
||||
|
||||
# 连接到数据库
|
||||
await connect_to_db()
|
||||
|
||||
# 同步初始配置(DB优先,然后同步回DB)
|
||||
await sync_initial_settings()
|
||||
# --- Helper functions for lifespan ---
|
||||
|
||||
# 初始化KeyManager (使用可能已从DB更新的settings)
|
||||
await get_key_manager_instance(settings.API_KEYS)
|
||||
logger.info("KeyManager initialized successfully")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize application: {str(e)}")
|
||||
# 不重新抛出,允许应用继续运行,但记录错误
|
||||
# raise # 取消注释以在初始化失败时停止应用
|
||||
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()
|
||||
# Initialize KeyManager using potentially updated settings
|
||||
await get_key_manager_instance(app_settings.API_KEYS)
|
||||
logger.info("Database, config sync, and KeyManager initialized successfully")
|
||||
|
||||
# 检查更新 (在核心初始化之后)
|
||||
update_available, latest_version, error_message = await check_for_updates()
|
||||
update_info = {
|
||||
"update_available": update_available,
|
||||
"latest_version": latest_version,
|
||||
"error_message": error_message,
|
||||
"current_version": _get_current_version() # Read from VERSION file
|
||||
}
|
||||
# 将更新信息存储在 app.state 中
|
||||
app.state.update_info = update_info
|
||||
logger.info(f"Update check completed. Info: {update_info}")
|
||||
async def _shutdown_database():
|
||||
"""Disconnects from the database."""
|
||||
await disconnect_from_db()
|
||||
logger.info("Disconnected from database.")
|
||||
|
||||
|
||||
# 启动调度器 (如果初始化成功)
|
||||
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}")
|
||||
|
||||
|
||||
yield # 应用程序运行期间
|
||||
|
||||
# 关闭事件
|
||||
logger.info("Application shutting down...")
|
||||
|
||||
# 停止调度器
|
||||
def _stop_scheduler():
|
||||
"""Stops the background scheduler."""
|
||||
stop_scheduler()
|
||||
logger.info("Scheduler stopped.")
|
||||
|
||||
# 断开数据库连接
|
||||
await disconnect_from_db()
|
||||
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() # Read from VERSION file
|
||||
update_info = {
|
||||
"update_available": update_available,
|
||||
"latest_version": latest_version,
|
||||
"error_message": error_message,
|
||||
"current_version": current_version
|
||||
}
|
||||
# Ensure app.state exists and store update info
|
||||
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}")
|
||||
|
||||
# --- Application Lifespan ---
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""
|
||||
Manages the application startup and shutdown events.
|
||||
|
||||
Args:
|
||||
app: FastAPI应用实例
|
||||
"""
|
||||
# Startup events
|
||||
logger.info("Application starting up...")
|
||||
try:
|
||||
# Setup database, config, and KeyManager
|
||||
await _setup_database_and_config(settings) # Pass settings object
|
||||
|
||||
# Perform update check after core components are ready
|
||||
await _perform_update_check(app)
|
||||
|
||||
# Start the scheduler
|
||||
_start_scheduler()
|
||||
|
||||
except Exception as e:
|
||||
logger.critical(f"Critical error during application startup: {str(e)}", exc_info=True)
|
||||
# Depending on the severity, you might want to prevent the app from fully starting
|
||||
# For now, we log critically and let it yield, potentially in a broken state.
|
||||
# Consider adding more robust error handling here if startup failures should halt the app.
|
||||
|
||||
yield # Application runs
|
||||
|
||||
# Shutdown events
|
||||
logger.info("Application shutting down...")
|
||||
_stop_scheduler()
|
||||
await _shutdown_database()
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""
|
||||
@@ -117,28 +144,33 @@ def create_app() -> FastAPI:
|
||||
Returns:
|
||||
FastAPI: 配置好的FastAPI应用程序实例
|
||||
"""
|
||||
# 初始化应用程序
|
||||
initialize_app()
|
||||
|
||||
# Removed: initialize_app() call
|
||||
|
||||
# 创建FastAPI应用
|
||||
# Read version from file for consistency
|
||||
current_version = _get_current_version()
|
||||
app = FastAPI(
|
||||
title="Gemini Balance API",
|
||||
description="Gemini API代理服务,支持负载均衡和密钥管理",
|
||||
version="1.0.0",
|
||||
version=current_version,
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
# 初始化 app.state (如果尚未存在)
|
||||
# Initialize app.state early to ensure it exists before lifespan potentially uses it
|
||||
if not hasattr(app, "state"):
|
||||
from starlette.datastructures import State
|
||||
app.state = State()
|
||||
# 确保 update_info 即使在 lifespan 之前访问也不会出错
|
||||
app.state.update_info = {"update_available": False, "latest_version": None, "error_message": "Checking...", "current_version": _get_current_version()} # Read from VERSION file for initial state
|
||||
|
||||
# Set a default/initial state for update_info
|
||||
app.state.update_info = {
|
||||
"update_available": False,
|
||||
"latest_version": None,
|
||||
"error_message": "Initializing...",
|
||||
"current_version": current_version # Use version read earlier
|
||||
}
|
||||
|
||||
# 配置静态文件
|
||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||
|
||||
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
||||
|
||||
# 配置中间件
|
||||
setup_middlewares(app)
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
"""
|
||||
应用程序初始化模块
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from app.log.logger import get_initialization_logger
|
||||
|
||||
logger = get_initialization_logger()
|
||||
|
||||
|
||||
def ensure_directories_exist(directories: List[str]) -> None:
|
||||
"""
|
||||
确保指定的目录存在,如果不存在则创建
|
||||
|
||||
Args:
|
||||
directories: 要确保存在的目录列表
|
||||
"""
|
||||
for directory in directories:
|
||||
try:
|
||||
Path(directory).mkdir(parents=True, exist_ok=True)
|
||||
logger.info(f"Ensured directory exists: {directory}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create directory {directory}: {str(e)}")
|
||||
|
||||
|
||||
def initialize_app() -> None:
|
||||
"""
|
||||
初始化应用程序,确保所需的目录和文件都存在
|
||||
"""
|
||||
# 确保必要的目录存在
|
||||
required_directories = [
|
||||
"app/static/css",
|
||||
"app/static/js",
|
||||
"app/static/icons",
|
||||
"app/templates",
|
||||
]
|
||||
|
||||
ensure_directories_exist(required_directories)
|
||||
logger.info("core initialization completed")
|
||||
@@ -35,7 +35,7 @@ class ColoredFormatter(logging.Formatter):
|
||||
|
||||
# 日志格式
|
||||
FORMATTER = ColoredFormatter(
|
||||
"%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s"
|
||||
"%(asctime)s | %(name)-15s | %(levelname)-8s | [%(filename)-20s:%(lineno)-4d] | %(message)s"
|
||||
)
|
||||
|
||||
# 日志级别映射
|
||||
|
||||
Reference in New Issue
Block a user