132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
|
|
"""
|
||
|
|
配置管理模块
|
||
|
|
基于 Pydantic Settings 和 TOML 文件
|
||
|
|
"""
|
||
|
|
from typing import Optional, Dict, Any
|
||
|
|
from pydantic_settings import BaseSettings
|
||
|
|
from pydantic import Field
|
||
|
|
import toml
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import os
|
||
|
|
from utils.launch import args
|
||
|
|
|
||
|
|
class Settings(BaseSettings):
|
||
|
|
"""应用配置"""
|
||
|
|
|
||
|
|
# 应用信息
|
||
|
|
app_name: str = "FastAPI Demo"
|
||
|
|
app_version: str = "1.0.0"
|
||
|
|
description: str = "FastAPI 应用"
|
||
|
|
|
||
|
|
# 服务器配置
|
||
|
|
host: str = "0.0.0.0"
|
||
|
|
port: int = 8000
|
||
|
|
reload: bool = False
|
||
|
|
workers: int = 4
|
||
|
|
|
||
|
|
# 数据库配置
|
||
|
|
database_url: str = "sqlite://db.sqlite3"
|
||
|
|
generate_schemas: bool = False
|
||
|
|
|
||
|
|
# 环境配置
|
||
|
|
env: str = "development"
|
||
|
|
debug: bool = False
|
||
|
|
|
||
|
|
# 日志配置
|
||
|
|
logging_level: str = "INFO"
|
||
|
|
logging_file: Optional[str] = None
|
||
|
|
|
||
|
|
# CORS 配置
|
||
|
|
cors_allow_origins: list = ["*"]
|
||
|
|
cors_allow_credentials: bool = True
|
||
|
|
cors_allow_methods: list = ["*"]
|
||
|
|
cors_allow_headers: list = ["*"]
|
||
|
|
|
||
|
|
# 安全配置
|
||
|
|
secret_key: str = "your-secret-key-change-in-production"
|
||
|
|
algorithm: str = "HS256"
|
||
|
|
access_token_expire_minutes: int = 30
|
||
|
|
|
||
|
|
# 模块系统
|
||
|
|
module_system_type: str = "local"
|
||
|
|
module_system_path: list = ["plugins", "app"]
|
||
|
|
|
||
|
|
class Config:
|
||
|
|
env_file = ".env"
|
||
|
|
extra = "ignore"
|
||
|
|
|
||
|
|
@classmethod
|
||
|
|
def from_toml(cls, config_path: Optional[str] = None) -> "Settings":
|
||
|
|
"""从 TOML 文件加载配置"""
|
||
|
|
|
||
|
|
if config_path is None:
|
||
|
|
# 尝试多个可能的配置路径
|
||
|
|
possible_paths = [
|
||
|
|
"config.toml",
|
||
|
|
"./config.toml",
|
||
|
|
"../config.toml",
|
||
|
|
Path(__file__).parent.parent.parent / "config.toml",
|
||
|
|
]
|
||
|
|
|
||
|
|
for path in possible_paths:
|
||
|
|
if Path(path).exists():
|
||
|
|
config_path = str(path)
|
||
|
|
print(f"📄 加载配置文件: {config_path}")
|
||
|
|
break
|
||
|
|
|
||
|
|
if config_path is None:
|
||
|
|
print("⚠️ 未找到配置文件,使用默认配置")
|
||
|
|
return cls()
|
||
|
|
|
||
|
|
try:
|
||
|
|
config_file = Path(config_path)
|
||
|
|
if not config_file.exists():
|
||
|
|
print(f"⚠️ 配置文件不存在: {config_path}")
|
||
|
|
return cls()
|
||
|
|
|
||
|
|
config_data = toml.load(config_file)
|
||
|
|
|
||
|
|
# 获取默认配置
|
||
|
|
default_config = config_data.get("default", {})
|
||
|
|
|
||
|
|
# 确定环境
|
||
|
|
env = default_config.get("env", "development")
|
||
|
|
|
||
|
|
# 获取环境特定配置
|
||
|
|
env_config = config_data.get(env, {})
|
||
|
|
|
||
|
|
# 合并配置
|
||
|
|
merged_config = {**default_config, **env_config}
|
||
|
|
|
||
|
|
# 处理嵌套配置
|
||
|
|
for section in ["server", "database", "security", "logging", "cors", "module_system"]:
|
||
|
|
if section in config_data:
|
||
|
|
if isinstance(config_data[section], dict):
|
||
|
|
merged_config.update(config_data[section])
|
||
|
|
|
||
|
|
# 从环境特定配置中覆盖
|
||
|
|
for section in ["server", "database", "security", "logging", "cors", "module_system"]:
|
||
|
|
env_section_key = f"{env}.{section}"
|
||
|
|
if env_section_key in config_data:
|
||
|
|
if isinstance(config_data[env_section_key], dict):
|
||
|
|
merged_config.update(config_data[env_section_key])
|
||
|
|
|
||
|
|
print(f"🌍 环境: {env}")
|
||
|
|
return cls(**merged_config)
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"❌ 加载配置失败: {e}")
|
||
|
|
import traceback
|
||
|
|
traceback.print_exc()
|
||
|
|
return cls()
|
||
|
|
|
||
|
|
# 全局配置实例
|
||
|
|
_settings = None
|
||
|
|
|
||
|
|
def get_settings() -> Settings:
|
||
|
|
"""获取配置实例(单例模式)"""
|
||
|
|
global _settings
|
||
|
|
if _settings is None:
|
||
|
|
_settings = Settings.from_toml(args.config)
|
||
|
|
return _settings
|