Files
personal-experiment/config_manager.py
T
2026-03-06 17:07:57 +08:00

225 lines
6.3 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
配置管理模块
集中管理所有配置参数,支持从命令行参数、配置文件和环境变量加载配置
"""
import os
import sys
import json
from typing import Dict, Any, Optional
from pathlib import Path
from dataclasses import dataclass, field
@dataclass
class MonitorConfig:
"""监控配置数据类"""
# 目标配置
target_ip: str = "8.8.8.8"
# 时间配置
delay_threshold: float = 30.0
ping_interval: float = 5.0
ping_timeout: float = 5.0
ping_count: int = 1
# 功能开关
enable_logging: bool = False
enable_notifications: bool = False
enable_desktop_notifications: bool = False
# 日志配置
log_dir: str = "logs"
max_log_files: int = 10
# 关机配置
shutdown_delay: int = 5
shutdown_message: str = "网络连接丢失,系统即将关机"
# 参数范围限制
min_delay_threshold: float = 1.0
max_delay_threshold: float = 3600.0
min_ping_interval: float = 1.0
max_ping_interval: float = 300.0
def __post_init__(self):
"""初始化后验证参数范围"""
self.delay_threshold = self._clamp(
self.delay_threshold,
self.min_delay_threshold,
self.max_delay_threshold
)
self.ping_interval = self._clamp(
self.ping_interval,
self.min_ping_interval,
self.max_ping_interval
)
@staticmethod
def _clamp(value: float, min_val: float, max_val: float) -> float:
"""限制数值在指定范围内"""
return max(min_val, min(value, max_val))
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
'target_ip': self.target_ip,
'delay_threshold': self.delay_threshold,
'ping_interval': self.ping_interval,
'ping_timeout': self.ping_timeout,
'ping_count': self.ping_count,
'enable_logging': self.enable_logging,
'enable_notifications': self.enable_notifications,
'enable_desktop_notifications': self.enable_desktop_notifications,
'log_dir': self.log_dir,
'max_log_files': self.max_log_files,
'shutdown_delay': self.shutdown_delay,
'shutdown_message': self.shutdown_message
}
class ConfigManager:
"""配置管理器(单例模式)"""
_instance: Optional['ConfigManager'] = None
def __new__(cls):
"""实现单例模式"""
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
"""初始化配置管理器"""
if self._initialized:
return
self._config: Optional[MonitorConfig] = None
self._config_file: Optional[Path] = None
self._initialized = True
def load_from_args(self) -> MonitorConfig:
"""
从命令行参数加载配置
Returns:
配置对象
"""
config = MonitorConfig()
if len(sys.argv) > 1:
config.target_ip = sys.argv[1]
if len(sys.argv) > 2:
try:
config.delay_threshold = float(sys.argv[2])
except ValueError:
pass
if len(sys.argv) > 3:
try:
config.ping_interval = float(sys.argv[3])
except ValueError:
pass
self._config = config
return config
def load_from_file(self, file_path: str) -> MonitorConfig:
"""
从配置文件加载配置
Args:
file_path: 配置文件路径
Returns:
配置对象
"""
config = MonitorConfig()
config_path = Path(file_path)
if config_path.exists():
try:
with open(config_path, 'r', encoding='utf-8') as f:
data = json.load(f)
for key, value in data.items():
if hasattr(config, key):
setattr(config, key, value)
except (json.JSONDecodeError, IOError):
pass
self._config = config
self._config_file = config_path
return config
def load_from_dict(self, data: Dict[str, Any]) -> MonitorConfig:
"""
从字典加载配置
Args:
data: 配置字典
Returns:
配置对象
"""
config = MonitorConfig()
for key, value in data.items():
if hasattr(config, key):
setattr(config, key, value)
self._config = config
return config
def get_config(self) -> MonitorConfig:
"""
获取当前配置
Returns:
配置对象
"""
if self._config is None:
self._config = self.load_from_args()
return self._config
def save_to_file(self, file_path: Optional[str] = None) -> None:
"""
保存配置到文件
Args:
file_path: 配置文件路径,如果为None则使用之前的路径
"""
if self._config is None:
raise RuntimeError("没有配置可保存")
save_path = Path(file_path) if file_path else self._config_file
if save_path:
save_path.parent.mkdir(parents=True, exist_ok=True)
with open(save_path, 'w', encoding='utf-8') as f:
json.dump(self._config.to_dict(), f, indent=2, ensure_ascii=False)
self._config_file = save_path
def update_config(self, **kwargs) -> None:
"""
更新配置
Args:
**kwargs: 要更新的配置项
"""
if self._config is None:
self._config = MonitorConfig()
for key, value in kwargs.items():
if hasattr(self._config, key):
setattr(self._config, key, value)
def reset(self) -> None:
"""重置配置为默认值"""
self._config = MonitorConfig()