""" 配置文件 支持YAML配置和.env环境变量 """ import os from typing import Any, Dict, List, Optional from urllib.parse import urlparse import yaml from dotenv import load_dotenv # 加载环境变量 load_dotenv() # 配置文件路径 CONFIG_FILE = os.getenv("CONFIG_FILE", "config.yaml") def _validate_url(url: str, field_name: str) -> None: """验证URL格式""" if not url: raise ValueError(f"环境变量 {field_name} 未设置") parsed = urlparse(url) if not all([parsed.scheme, parsed.netloc]): raise ValueError(f"{field_name} 格式不正确: {url}") def _load_yaml_config() -> Optional[Dict[str, Any]]: """加载YAML配置文件""" if os.path.exists(CONFIG_FILE): with open(CONFIG_FILE, 'r', encoding='utf-8') as f: return yaml.safe_load(f) return None def _get_config_value( yaml_config: Optional[Dict[str, Any]], env_key: str, yaml_path: List[str], default: Any = None, validator: Optional[callable] = None ) -> Any: """获取配置值,优先级:环境变量 > YAML配置 > 默认值""" # 1. 优先从环境变量获取 env_value = os.getenv(env_key) if env_value is not None: return env_value # 2. 其次从YAML配置获取 if yaml_config: value = yaml_config for key in yaml_path: if isinstance(value, dict) and key in value: value = value[key] else: value = None break if value is not None: if validator: validator(value) return value # 3. 使用默认值 return default def _get_int_value(yaml_config: Optional[Dict[str, Any]], env_key: str, yaml_path: List[str], default: int) -> int: """获取整数配置值""" value = _get_config_value(yaml_config, env_key, yaml_path, str(default)) try: return int(value) except (ValueError, TypeError): return default def _get_bool_value(yaml_config: Optional[Dict[str, Any]], env_key: str, yaml_path: List[str], default: bool) -> bool: """获取布尔配置值""" value = _get_config_value(yaml_config, env_key, yaml_path, str(default).lower()) # 如果值已经是布尔类型,直接返回 if isinstance(value, bool): return value # 如果是字符串,转换为布尔值 if isinstance(value, str): return value.lower() == "true" # 其他类型转换为布尔值 return bool(value) # 加载YAML配置 yaml_config = _load_yaml_config() # 验证并获取BASE_URL BASE_URL = os.getenv("BASE_URL") if BASE_URL is None and yaml_config: BASE_URL = _get_config_value(yaml_config, "BASE_URL", ["camera", "base_url"]) _validate_url(BASE_URL, "BASE_URL") CAMERA_URL = f"{BASE_URL}/adaops/blank-layout/camera-view" # 摄像头配置 def _load_cameras() -> List[Dict[str, Any]]: """加载摄像头配置""" if yaml_config and "cameras" in yaml_config: cameras = yaml_config["cameras"] # 如果cameras中没有url字段,自动生成 for camera in cameras: if 'url' not in camera: room = camera.get('room', '') cam = camera.get('camera', 'mixed') camera['url'] = f"{CAMERA_URL}?room={room}&camera={cam}" return cameras # 硬编码后备配置(不推荐使用) return [ { 'id': 1, 'room': 'cnfzhjyg-igv-251', 'camera': 'mixed', 'name': '1号车', 'url': f"{CAMERA_URL}?room=cnfzhjyg-igv-251&camera=mixed" }, { 'id': 2, 'room': 'cnfzhjyg-igv-2', 'camera': 'mixed', 'name': '2号车', 'url': f"{CAMERA_URL}?room=cnfzhjyg-igv-2&camera=mixed" }, { 'id': 3, 'room': 'cnfzhjyg-igv-3', 'camera': 'mixed', 'name': '3号车', 'url': f"{CAMERA_URL}?room=cnfzhjyg-igv-3&camera=mixed" }, { 'id': 4, 'room': 'cnfzhjyg-igv-5', 'camera': 'mixed', 'name': '5号车', 'url': f"{CAMERA_URL}?room=cnfzhjyg-igv-5&camera=mixed" }, { 'id': 5, 'room': 'cnfzhjyg-igv-6', 'camera': 'mixed', 'name': '6号车', 'url': f"{CAMERA_URL}?room=cnfzhjyg-igv-6&camera=mixed" }, { 'id': 6, 'room': 'cnfzhjyg-igv-7', 'camera': 'mixed', 'name': '7号车', 'url': f"{CAMERA_URL}?room=cnfzhjyg-igv-7&camera=mixed" } ] CAMERAS: List[Dict[str, Any]] = _load_cameras() # Flask配置 DEBUG: bool = _get_bool_value(yaml_config, "FLASK_DEBUG", ["app", "debug"], False) PORT: int = _get_int_value(yaml_config, "PORT", ["app", "port"], 5000) HOST: str = _get_config_value(yaml_config, "HOST", ["app", "host"], "0.0.0.0") # 验证HOST if not HOST: raise ValueError("环境变量 HOST 未设置") # 日志配置 LOG_LEVEL: str = _get_config_value(yaml_config, "LOG_LEVEL", ["logging", "level"], "INFO") LOG_FILE: str = _get_config_value(yaml_config, "LOG_FILE", ["logging", "file"], "logs/multi_camera.log") LOG_MAX_BYTES: int = _get_int_value(yaml_config, "LOG_MAX_BYTES", ["logging", "max_bytes"], 10485760) LOG_BACKUP_COUNT: int = _get_int_value(yaml_config, "LOG_BACKUP_COUNT", ["logging", "backup_count"], 10)