2025-12-07 02:07:14 +08:00
|
|
|
|
"""
|
|
|
|
|
|
配置文件
|
2026-01-02 06:25:36 +08:00
|
|
|
|
支持YAML配置和.env环境变量
|
2025-12-07 02:07:14 +08:00
|
|
|
|
"""
|
|
|
|
|
|
import os
|
2026-01-02 06:25:36 +08:00
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
|
|
|
|
|
|
import yaml
|
2025-12-07 02:07:14 +08:00
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
|
|
|
# 加载环境变量
|
|
|
|
|
|
load_dotenv()
|
|
|
|
|
|
|
2026-01-02 06:25:36 +08:00
|
|
|
|
# 配置文件路径
|
|
|
|
|
|
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())
|
2026-01-03 21:52:21 +08:00
|
|
|
|
|
|
|
|
|
|
# 如果值已经是布尔类型,直接返回
|
|
|
|
|
|
if isinstance(value, bool):
|
|
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
# 如果是字符串,转换为布尔值
|
|
|
|
|
|
if isinstance(value, str):
|
|
|
|
|
|
return value.lower() == "true"
|
|
|
|
|
|
|
|
|
|
|
|
# 其他类型转换为布尔值
|
|
|
|
|
|
return bool(value)
|
2026-01-02 06:25:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 加载YAML配置
|
|
|
|
|
|
yaml_config = _load_yaml_config()
|
|
|
|
|
|
|
|
|
|
|
|
# 验证并获取BASE_URL
|
2025-12-13 10:57:37 +08:00
|
|
|
|
BASE_URL = os.getenv("BASE_URL")
|
2026-01-02 06:25:36 +08:00
|
|
|
|
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")
|
|
|
|
|
|
|
2025-12-07 02:07:14 +08:00
|
|
|
|
CAMERA_URL = f"{BASE_URL}/adaops/blank-layout/camera-view"
|
|
|
|
|
|
|
2026-01-02 06:25:36 +08:00
|
|
|
|
# 摄像头配置
|
|
|
|
|
|
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)
|