| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- """
- 系统配置管理器
- 提供全局配置读取功能,支持缓存和默认值回退
- 业务代码通过此模块读取数据库中的系统配置
- """
- import json
- import logging
- from typing import Any, Optional, Dict
- from datetime import datetime, timedelta
- from threading import Lock
- from sqlalchemy.orm import Session
- from app.database import SessionLocal
- from app.models.config import SystemConfig
- logger = logging.getLogger(__name__)
- class SystemConfigManager:
- """系统配置管理器(单例模式)"""
-
- _instance = None
- _lock = Lock()
-
- # 配置缓存
- _cache: Dict[str, Any] = {}
- _cache_time: Dict[str, datetime] = {}
- _cache_ttl = timedelta(minutes=5) # 缓存5分钟
-
- # 默认值定义
- DEFAULT_VALUES = {
- # 基础配置
- "system_name": "智创空间",
- "system_logo": "",
- "contact_email": "",
- "icp_number": "",
- # 功能开关
- "enable_registration": True,
- "enable_search": True,
- "enable_verification_reminder": True,
- "enable_local_models": True,
- "enable_openclaw": True,
- "enable_openclaw_client": True,
- "enable_openclaw_web": True,
- "openclaw_client_url": "",
- # 限制配置
- "max_tokens_per_request": 4000,
- "max_images_per_request": 4,
- "max_audio_chars": 5000,
- "max_video_duration": 10,
- # 第三方配置(敏感,默认为空)
- "dashscope_api_key": "",
- "alipay_app_id": "",
- "oss_bucket": "",
- "oss_endpoint": "",
- }
-
- def __new__(cls):
- if cls._instance is None:
- with cls._lock:
- if cls._instance is None:
- cls._instance = super().__new__(cls)
- return cls._instance
-
- def _get_db(self) -> Session:
- """获取数据库会话"""
- return SessionLocal()
-
- def _parse_value(self, value_str: str, value_type: str) -> Any:
- """解析配置值"""
- try:
- return json.loads(value_str)
- except (json.JSONDecodeError, TypeError):
- return value_str
-
- def get(self, key: str, default: Any = None) -> Any:
- """
- 获取配置值
- 优先级:Redis缓存 > 本地内存缓存 > 数据库 > 默认值
- Redis 不可用时自动降级到内存缓存。
- """
- # 1. 检查本地内存缓存(最快)
- if key in self._cache:
- cache_time = self._cache_time.get(key)
- if cache_time and datetime.now() - cache_time < self._cache_ttl:
- return self._cache[key]
- # 2. 检查 Redis 缓存
- try:
- from app.core.redis import redis_manager
- r = redis_manager.get_sync_client()
- if r:
- raw = r.get(f"sysconfig:{key}")
- if raw:
- import json as _json
- value = _json.loads(raw)
- # 同步到本地内存缓存
- self._cache[key] = value
- self._cache_time[key] = datetime.now()
- return value
- except Exception:
- pass
- # 3. 从数据库读取
- db = self._get_db()
- try:
- config = db.query(SystemConfig).filter(
- SystemConfig.config_key == key
- ).first()
- if config:
- value = self._parse_value(config.config_value, config.config_type)
- # 写入本地内存缓存
- self._cache[key] = value
- self._cache_time[key] = datetime.now()
- # 写入 Redis 缓存(TTL 5 分钟)
- try:
- from app.core.redis import redis_manager
- import json as _json
- r = redis_manager.get_sync_client()
- if r:
- r.setex(f"sysconfig:{key}", 300, _json.dumps(value))
- except Exception:
- pass
- return value
- except Exception as e:
- logger.warning(f"读取配置 {key} 失败: {e}")
- finally:
- db.close()
- # 4. 返回默认值
- if default is not None:
- return default
- return self.DEFAULT_VALUES.get(key)
-
- def get_string(self, key: str, default: str = "") -> str:
- """获取字符串配置"""
- value = self.get(key, default)
- return str(value) if value is not None else default
-
- def get_int(self, key: str, default: int = 0) -> int:
- """获取整数配置"""
- value = self.get(key, default)
- try:
- return int(value)
- except (ValueError, TypeError):
- return default
-
- def get_float(self, key: str, default: float = 0.0) -> float:
- """获取浮点数配置"""
- value = self.get(key, default)
- try:
- return float(value)
- except (ValueError, TypeError):
- return default
-
- def get_bool(self, key: str, default: bool = False) -> bool:
- """获取布尔配置"""
- value = self.get(key, default)
- if isinstance(value, bool):
- return value
- if isinstance(value, str):
- return value.lower() in ('true', '1', 'yes')
- return bool(value)
-
- def clear_cache(self, key: Optional[str] = None):
- """清除缓存(内存 + Redis)"""
- if key:
- self._cache.pop(key, None)
- self._cache_time.pop(key, None)
- try:
- from app.core.redis import redis_manager
- r = redis_manager.get_sync_client()
- if r:
- r.delete(f"sysconfig:{key}")
- except Exception:
- pass
- else:
- self._cache.clear()
- self._cache_time.clear()
- try:
- from app.core.redis import redis_manager
- r = redis_manager.get_sync_client()
- if r:
- # 删除所有 sysconfig: 前缀的 key
- keys = r.keys("sysconfig:*")
- if keys:
- r.delete(*keys)
- except Exception:
- pass
-
- def refresh(self, key: str) -> Any:
- """强制刷新配置"""
- self.clear_cache(key)
- return self.get(key)
- # 全局单例实例
- config_manager = SystemConfigManager()
- # 便捷函数
- def get_config(key: str, default: Any = None) -> Any:
- """获取配置值"""
- return config_manager.get(key, default)
- def get_config_string(key: str, default: str = "") -> str:
- """获取字符串配置"""
- return config_manager.get_string(key, default)
- def get_config_int(key: str, default: int = 0) -> int:
- """获取整数配置"""
- return config_manager.get_int(key, default)
- def get_config_float(key: str, default: float = 0.0) -> float:
- """获取浮点数配置"""
- return config_manager.get_float(key, default)
- def get_config_bool(key: str, default: bool = False) -> bool:
- """获取布尔配置"""
- return config_manager.get_bool(key, default)
- def clear_config_cache(key: Optional[str] = None):
- """清除配置缓存"""
- config_manager.clear_cache(key)
|