225 lines
6.3 KiB
Python
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()
|