Files
LoveACE-EndF/config/manager.py
2025-08-03 16:50:56 +08:00

177 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import os
from pathlib import Path
from typing import Any, Dict, Optional
from loguru import logger
from pydantic import ValidationError
from .models import Settings
class ConfigManager:
"""配置文件管理器"""
def __init__(self, config_file: str = "config.json"):
self.config_file = Path(config_file)
self._settings: Optional[Settings] = None
self._ensure_config_dir()
def _ensure_config_dir(self):
"""确保配置文件目录存在"""
self.config_file.parent.mkdir(parents=True, exist_ok=True)
def _create_default_config(self) -> Settings:
"""创建默认配置"""
logger.info("正在创建默认配置文件...")
return Settings()
def _save_config(self, settings: Settings):
"""保存配置到文件"""
try:
config_dict = settings.dict()
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config_dict, f, indent=2, ensure_ascii=False)
logger.info(f"配置已保存到 {self.config_file}")
except Exception as e:
logger.error(f"保存配置文件失败: {e}")
raise
def _load_config(self) -> Settings:
"""从文件加载配置"""
if not self.config_file.exists():
logger.warning(f"配置文件 {self.config_file} 不存在,将创建默认配置")
settings = self._create_default_config()
self._save_config(settings)
return settings
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
config_data = json.load(f)
# 验证并创建Settings对象
settings = Settings(**config_data)
logger.info(f"成功加载配置文件: {self.config_file}")
return settings
except json.JSONDecodeError as e:
logger.error(f"配置文件JSON格式错误: {e}")
raise
except ValidationError as e:
logger.error(f"配置文件验证失败: {e}")
raise
except Exception as e:
logger.error(f"加载配置文件失败: {e}")
raise
def get_settings(self) -> Settings:
"""获取配置设置"""
if self._settings is None:
self._settings = self._load_config()
return self._settings
def reload_config(self) -> Settings:
"""重新加载配置"""
logger.info("正在重新加载配置...")
self._settings = self._load_config()
return self._settings
def update_config(self, **kwargs) -> Settings:
"""更新配置"""
settings = self.get_settings()
# 创建新的配置字典
config_dict = settings.dict()
# 更新指定的配置项
for key, value in kwargs.items():
if '.' in key:
# 支持嵌套键,如 'database.url'
keys = key.split('.')
current = config_dict
for k in keys[:-1]:
if k not in current:
current[k] = {}
current = current[k]
current[keys[-1]] = value
else:
config_dict[key] = value
try:
# 验证更新后的配置
new_settings = Settings(**config_dict)
self._save_config(new_settings)
self._settings = new_settings
logger.info("配置更新成功")
return new_settings
except ValidationError as e:
logger.error(f"配置更新失败,验证错误: {e}")
raise
def validate_config(self) -> bool:
"""验证配置完整性"""
try:
settings = self.get_settings()
# 检查关键配置项
issues = []
# 检查数据库配置
if not settings.database.url:
issues.append("数据库URL未配置")
# 检查S3配置如果需要使用
if settings.s3.bucket_name and not settings.s3.access_key_id:
issues.append("S3配置不完整缺少access_key_id")
if settings.s3.bucket_name and not settings.s3.secret_access_key:
issues.append("S3配置不完整缺少secret_access_key")
# 检查日志配置
log_dir = Path(settings.log.file_path).parent
if not log_dir.exists():
try:
log_dir.mkdir(parents=True, exist_ok=True)
logger.info(f"创建日志目录: {log_dir}")
except Exception as e:
issues.append(f"无法创建日志目录 {log_dir}: {e}")
if issues:
logger.warning("配置验证发现问题:")
for issue in issues:
logger.warning(f" - {issue}")
return False
logger.info("配置验证通过")
return True
except Exception as e:
logger.error(f"配置验证失败: {e}")
return False
def get_config_summary(self) -> Dict[str, Any]:
"""获取配置摘要(隐藏敏感信息)"""
settings = self.get_settings()
config_dict = settings.dict()
# 隐藏敏感信息
sensitive_keys = [
'database.url',
's3.access_key_id',
's3.secret_access_key'
]
def hide_sensitive(data: Dict[str, Any], keys: list, prefix: str = ""):
for key, value in data.items():
current_key = f"{prefix}.{key}" if prefix else key
if current_key in sensitive_keys:
if isinstance(value, str) and value:
data[key] = value[:8] + "..." if len(value) > 8 else "***"
elif isinstance(value, dict):
hide_sensitive(value, keys, current_key)
summary = config_dict.copy()
hide_sensitive(summary, sensitive_keys)
return summary
# 全局配置管理器实例
config_manager = ConfigManager()