Files
multi_camera/app/config.py
qichi.liang 6903ee6f0b refactor: 优化配置管理和异常处理
- 添加YAML配置文件支持
- 改进camera_manager异常处理
- 添加类型提示和URL验证
- 完善依赖注入支持测试
- 新增健康检查API端点
2026-01-02 06:25:36 +08:00

171 lines
5.1 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.

"""
配置文件
支持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())
return value.lower() == "true"
# 加载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)