730 lines
22 KiB
Python
730 lines
22 KiB
Python
"""
|
||
网络工具类模块
|
||
提供网络同步插件所需的工具函数
|
||
"""
|
||
|
||
import time
|
||
import hashlib
|
||
import zlib
|
||
import base64
|
||
from typing import Dict, Any, List, Optional, Union
|
||
import json
|
||
import struct
|
||
import threading
|
||
|
||
class NetworkUtils:
|
||
"""
|
||
网络工具类
|
||
提供网络同步插件所需的工具函数
|
||
"""
|
||
|
||
def __init__(self, plugin):
|
||
"""
|
||
初始化网络工具类
|
||
|
||
Args:
|
||
plugin: 网络同步插件实例
|
||
"""
|
||
self.plugin = plugin
|
||
self.enabled = False
|
||
self.initialized = False
|
||
|
||
# 工具配置
|
||
self.utils_config = {
|
||
"enable_caching": True,
|
||
"cache_size": 1000,
|
||
"enable_compression": True,
|
||
"compression_level": 6,
|
||
"enable_checksum": True,
|
||
"max_retry_attempts": 3,
|
||
"retry_delay": 1.0
|
||
}
|
||
|
||
# 缓存管理
|
||
self.cache = {}
|
||
self.cache_lock = threading.RLock()
|
||
|
||
# 性能统计
|
||
self.utils_stats = {
|
||
"cache_hits": 0,
|
||
"cache_misses": 0,
|
||
"compressions": 0,
|
||
"decompressions": 0,
|
||
"checksums_calculated": 0,
|
||
"data_processed": 0,
|
||
"functions_called": 0
|
||
}
|
||
|
||
# 回调函数
|
||
self.utils_callbacks = {
|
||
"cache_updated": [],
|
||
"performance_alert": []
|
||
}
|
||
|
||
# 时间戳记录
|
||
self.last_cache_cleanup = 0.0
|
||
self.last_utility_call = 0.0
|
||
|
||
print("✓ 网络工具类已创建")
|
||
|
||
def initialize(self) -> bool:
|
||
"""
|
||
初始化网络工具类
|
||
|
||
Returns:
|
||
是否初始化成功
|
||
"""
|
||
try:
|
||
self.initialized = True
|
||
print("✓ 网络工具类初始化完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 网络工具类初始化失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def enable(self) -> bool:
|
||
"""
|
||
启用网络工具类
|
||
|
||
Returns:
|
||
是否启用成功
|
||
"""
|
||
try:
|
||
if not self.initialized:
|
||
print("✗ 网络工具类未初始化")
|
||
return False
|
||
|
||
self.enabled = True
|
||
print("✓ 网络工具类已启用")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 网络工具类启用失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def disable(self):
|
||
"""禁用网络工具类"""
|
||
try:
|
||
self.enabled = False
|
||
print("✓ 网络工具类已禁用")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 网络工具类禁用失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def finalize(self):
|
||
"""清理网络工具类资源"""
|
||
try:
|
||
self.disable()
|
||
self.cache.clear()
|
||
self.utils_callbacks.clear()
|
||
self.initialized = False
|
||
print("✓ 网络工具类资源已清理")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 网络工具类资源清理失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def update(self, dt: float):
|
||
"""
|
||
更新网络工具类状态
|
||
|
||
Args:
|
||
dt: 时间增量
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return
|
||
|
||
current_time = time.time()
|
||
self.last_utility_call = current_time
|
||
|
||
# 定期清理缓存
|
||
if current_time - self.last_cache_cleanup > 60.0: # 每分钟清理一次
|
||
self._cleanup_cache()
|
||
self.last_cache_cleanup = current_time
|
||
|
||
except Exception as e:
|
||
print(f"✗ 网络工具类更新失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def _cleanup_cache(self):
|
||
"""清理缓存"""
|
||
try:
|
||
with self.cache_lock:
|
||
if len(self.cache) > self.utils_config["cache_size"]:
|
||
# 移除最旧的一半缓存项
|
||
items_to_remove = len(self.cache) - (self.utils_config["cache_size"] // 2)
|
||
keys_to_remove = list(self.cache.keys())[:items_to_remove]
|
||
|
||
for key in keys_to_remove:
|
||
del self.cache[key]
|
||
|
||
print(f"✓ 缓存已清理,移除了 {items_to_remove} 项")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 缓存清理失败: {e}")
|
||
|
||
def calculate_checksum(self, data: bytes) -> str:
|
||
"""
|
||
计算数据校验和
|
||
|
||
Args:
|
||
data: 要计算校验和的数据
|
||
|
||
Returns:
|
||
校验和字符串
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
self.utils_stats["checksums_calculated"] += 1
|
||
|
||
checksum = hashlib.md5(data).hexdigest()
|
||
return checksum
|
||
|
||
except Exception as e:
|
||
print(f"✗ 校验和计算失败: {e}")
|
||
return ""
|
||
|
||
def compress_data(self, data: bytes) -> Optional[bytes]:
|
||
"""
|
||
压缩数据
|
||
|
||
Args:
|
||
data: 要压缩的数据
|
||
|
||
Returns:
|
||
压缩后的数据或None
|
||
"""
|
||
try:
|
||
if not self.utils_config["enable_compression"]:
|
||
return data
|
||
|
||
self.utils_stats["functions_called"] += 1
|
||
self.utils_stats["compressions"] += 1
|
||
|
||
compressed_data = zlib.compress(data, self.utils_config["compression_level"])
|
||
self.utils_stats["data_processed"] += len(data) - len(compressed_data)
|
||
|
||
return compressed_data
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据压缩失败: {e}")
|
||
return None
|
||
|
||
def decompress_data(self, data: bytes) -> Optional[bytes]:
|
||
"""
|
||
解压缩数据
|
||
|
||
Args:
|
||
data: 要解压缩的数据
|
||
|
||
Returns:
|
||
解压缩后的数据或None
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
self.utils_stats["decompressions"] += 1
|
||
|
||
decompressed_data = zlib.decompress(data)
|
||
return decompressed_data
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据解压缩失败: {e}")
|
||
return None
|
||
|
||
def encode_base64(self, data: bytes) -> str:
|
||
"""
|
||
Base64编码
|
||
|
||
Args:
|
||
data: 要编码的数据
|
||
|
||
Returns:
|
||
编码后的字符串
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
encoded_data = base64.b64encode(data).decode('utf-8')
|
||
return encoded_data
|
||
|
||
except Exception as e:
|
||
print(f"✗ Base64编码失败: {e}")
|
||
return ""
|
||
|
||
def decode_base64(self, data: str) -> Optional[bytes]:
|
||
"""
|
||
Base64解码
|
||
|
||
Args:
|
||
data: 要解码的字符串
|
||
|
||
Returns:
|
||
解码后的数据或None
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
decoded_data = base64.b64decode(data.encode('utf-8'))
|
||
return decoded_data
|
||
|
||
except Exception as e:
|
||
print(f"✗ Base64解码失败: {e}")
|
||
return None
|
||
|
||
def generate_cache_key(self, data: Any) -> str:
|
||
"""
|
||
生成缓存键
|
||
|
||
Args:
|
||
data: 要生成键的数据
|
||
|
||
Returns:
|
||
缓存键字符串
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
# 生成数据的哈希值作为缓存键
|
||
data_str = str(data)
|
||
cache_key = hashlib.sha256(data_str.encode('utf-8')).hexdigest()
|
||
return cache_key
|
||
|
||
except Exception as e:
|
||
print(f"✗ 缓存键生成失败: {e}")
|
||
return str(hash(data))
|
||
|
||
def cache_get(self, key: str) -> Optional[Any]:
|
||
"""
|
||
从缓存获取数据
|
||
|
||
Args:
|
||
key: 缓存键
|
||
|
||
Returns:
|
||
缓存数据或None
|
||
"""
|
||
try:
|
||
if not self.utils_config["enable_caching"]:
|
||
return None
|
||
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
with self.cache_lock:
|
||
if key in self.cache:
|
||
self.utils_stats["cache_hits"] += 1
|
||
return self.cache[key]["data"]
|
||
else:
|
||
self.utils_stats["cache_misses"] += 1
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"✗ 缓存获取失败: {e}")
|
||
return None
|
||
|
||
def cache_set(self, key: str, data: Any, ttl: float = 300.0) -> bool:
|
||
"""
|
||
设置缓存数据
|
||
|
||
Args:
|
||
key: 缓存键
|
||
data: 要缓存的数据
|
||
ttl: 生存时间(秒)
|
||
|
||
Returns:
|
||
是否设置成功
|
||
"""
|
||
try:
|
||
if not self.utils_config["enable_caching"]:
|
||
return False
|
||
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
with self.cache_lock:
|
||
self.cache[key] = {
|
||
"data": data,
|
||
"timestamp": time.time(),
|
||
"ttl": ttl
|
||
}
|
||
|
||
# 触发缓存更新回调
|
||
self._trigger_utils_callback("cache_updated", {
|
||
"key": key,
|
||
"operation": "set"
|
||
})
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 缓存设置失败: {e}")
|
||
return False
|
||
|
||
def cache_delete(self, key: str) -> bool:
|
||
"""
|
||
删除缓存数据
|
||
|
||
Args:
|
||
key: 缓存键
|
||
|
||
Returns:
|
||
是否删除成功
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
with self.cache_lock:
|
||
if key in self.cache:
|
||
del self.cache[key]
|
||
|
||
# 触发缓存更新回调
|
||
self._trigger_utils_callback("cache_updated", {
|
||
"key": key,
|
||
"operation": "delete"
|
||
})
|
||
|
||
return True
|
||
else:
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"✗ 缓存删除失败: {e}")
|
||
return False
|
||
|
||
def retry_operation(self, operation: callable, *args, **kwargs) -> Optional[Any]:
|
||
"""
|
||
重试操作
|
||
|
||
Args:
|
||
operation: 要重试的操作
|
||
*args: 操作参数
|
||
**kwargs: 操作关键字参数
|
||
|
||
Returns:
|
||
操作结果或None
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
max_attempts = self.utils_config["max_retry_attempts"]
|
||
delay = self.utils_config["retry_delay"]
|
||
|
||
for attempt in range(max_attempts):
|
||
try:
|
||
result = operation(*args, **kwargs)
|
||
return result
|
||
except Exception as e:
|
||
if attempt < max_attempts - 1:
|
||
print(f"✗ 操作失败,{delay}秒后重试 ({attempt + 1}/{max_attempts}): {e}")
|
||
time.sleep(delay)
|
||
else:
|
||
print(f"✗ 操作最终失败: {e}")
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"✗ 重试操作失败: {e}")
|
||
return None
|
||
|
||
def format_bytes(self, bytes_count: int) -> str:
|
||
"""
|
||
格式化字节数
|
||
|
||
Args:
|
||
bytes_count: 字节数
|
||
|
||
Returns:
|
||
格式化后的字符串
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
if bytes_count < 1024:
|
||
return f"{bytes_count} B"
|
||
elif bytes_count < 1024 * 1024:
|
||
return f"{bytes_count / 1024:.2f} KB"
|
||
elif bytes_count < 1024 * 1024 * 1024:
|
||
return f"{bytes_count / (1024 * 1024):.2f} MB"
|
||
else:
|
||
return f"{bytes_count / (1024 * 1024 * 1024):.2f} GB"
|
||
|
||
except Exception as e:
|
||
print(f"✗ 字节格式化失败: {e}")
|
||
return f"{bytes_count} B"
|
||
|
||
def calculate_bandwidth(self, bytes_count: int, duration: float) -> float:
|
||
"""
|
||
计算带宽
|
||
|
||
Args:
|
||
bytes_count: 字节数
|
||
duration: 持续时间(秒)
|
||
|
||
Returns:
|
||
带宽(B/s)
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
if duration <= 0:
|
||
return 0.0
|
||
|
||
bandwidth = bytes_count / duration
|
||
return bandwidth
|
||
|
||
except Exception as e:
|
||
print(f"✗ 带宽计算失败: {e}")
|
||
return 0.0
|
||
|
||
def get_local_ip(self) -> Optional[str]:
|
||
"""
|
||
获取本地IP地址
|
||
|
||
Returns:
|
||
本地IP地址或None
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
import socket
|
||
# 获取本地IP地址
|
||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
||
# 连接到一个远程地址(不需要真实连接)
|
||
s.connect(("8.8.8.8", 80))
|
||
local_ip = s.getsockname()[0]
|
||
|
||
return local_ip
|
||
|
||
except Exception as e:
|
||
print(f"✗ 本地IP获取失败: {e}")
|
||
return None
|
||
|
||
def is_valid_port(self, port: int) -> bool:
|
||
"""
|
||
检查端口是否有效
|
||
|
||
Args:
|
||
port: 端口号
|
||
|
||
Returns:
|
||
端口是否有效
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
return 1 <= port <= 65535
|
||
|
||
except Exception as e:
|
||
print(f"✗ 端口检查失败: {e}")
|
||
return False
|
||
|
||
def get_system_info(self) -> Dict[str, Any]:
|
||
"""
|
||
获取系统信息
|
||
|
||
Returns:
|
||
系统信息字典
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
import platform
|
||
import psutil
|
||
|
||
system_info = {
|
||
"platform": platform.system(),
|
||
"platform_version": platform.version(),
|
||
"architecture": platform.architecture()[0],
|
||
"processor": platform.processor(),
|
||
"cpu_count": psutil.cpu_count(),
|
||
"memory_total": psutil.virtual_memory().total,
|
||
"memory_available": psutil.virtual_memory().available
|
||
}
|
||
|
||
return system_info
|
||
|
||
except Exception as e:
|
||
print(f"✗ 系统信息获取失败: {e}")
|
||
return {}
|
||
|
||
def get_network_interfaces(self) -> List[Dict[str, Any]]:
|
||
"""
|
||
获取网络接口信息
|
||
|
||
Returns:
|
||
网络接口信息列表
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
import psutil
|
||
|
||
interfaces = []
|
||
net_if_addrs = psutil.net_if_addrs()
|
||
|
||
for interface_name, interface_addresses in net_if_addrs.items():
|
||
interface_info = {
|
||
"name": interface_name,
|
||
"addresses": []
|
||
}
|
||
|
||
for address in interface_addresses:
|
||
interface_info["addresses"].append({
|
||
"family": str(address.family),
|
||
"address": address.address,
|
||
"netmask": address.netmask,
|
||
"broadcast": address.broadcast
|
||
})
|
||
|
||
interfaces.append(interface_info)
|
||
|
||
return interfaces
|
||
|
||
except Exception as e:
|
||
print(f"✗ 网络接口信息获取失败: {e}")
|
||
return []
|
||
|
||
def measure_latency(self, host: str, port: int, timeout: float = 5.0) -> Optional[float]:
|
||
"""
|
||
测量网络延迟
|
||
|
||
Args:
|
||
host: 主机地址
|
||
port: 端口号
|
||
timeout: 超时时间
|
||
|
||
Returns:
|
||
延迟时间(秒)或None
|
||
"""
|
||
try:
|
||
self.utils_stats["functions_called"] += 1
|
||
|
||
import socket
|
||
import time
|
||
|
||
start_time = time.time()
|
||
|
||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||
sock.settimeout(timeout)
|
||
result = sock.connect_ex((host, port))
|
||
|
||
if result == 0:
|
||
end_time = time.time()
|
||
latency = end_time - start_time
|
||
return latency
|
||
else:
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"✗ 延迟测量失败: {e}")
|
||
return None
|
||
|
||
def get_utils_stats(self) -> Dict[str, Any]:
|
||
"""
|
||
获取工具统计信息
|
||
|
||
Returns:
|
||
工具统计字典
|
||
"""
|
||
return self.utils_stats.copy()
|
||
|
||
def reset_utils_stats(self):
|
||
"""重置工具统计信息"""
|
||
try:
|
||
self.utils_stats = {
|
||
"cache_hits": 0,
|
||
"cache_misses": 0,
|
||
"compressions": 0,
|
||
"decompressions": 0,
|
||
"checksums_calculated": 0,
|
||
"data_processed": 0,
|
||
"functions_called": 0
|
||
}
|
||
print("✓ 工具统计信息已重置")
|
||
except Exception as e:
|
||
print(f"✗ 工具统计信息重置失败: {e}")
|
||
|
||
def set_utils_config(self, config: Dict[str, Any]) -> bool:
|
||
"""
|
||
设置工具配置
|
||
|
||
Args:
|
||
config: 工具配置字典
|
||
|
||
Returns:
|
||
是否设置成功
|
||
"""
|
||
try:
|
||
self.utils_config.update(config)
|
||
print(f"✓ 工具配置已更新: {self.utils_config}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"✗ 工具配置设置失败: {e}")
|
||
return False
|
||
|
||
def get_utils_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取工具配置
|
||
|
||
Returns:
|
||
工具配置字典
|
||
"""
|
||
return self.utils_config.copy()
|
||
|
||
def _trigger_utils_callback(self, callback_type: str, data: Dict[str, Any]):
|
||
"""
|
||
触发工具回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
data: 回调数据
|
||
"""
|
||
try:
|
||
if callback_type in self.utils_callbacks:
|
||
for callback in self.utils_callbacks[callback_type]:
|
||
try:
|
||
callback(data)
|
||
except Exception as e:
|
||
print(f"✗ 工具回调执行失败: {e}")
|
||
except Exception as e:
|
||
print(f"✗ 工具回调触发失败: {e}")
|
||
|
||
def register_utils_callback(self, callback_type: str, callback: callable):
|
||
"""
|
||
注册工具回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
callback: 回调函数
|
||
"""
|
||
try:
|
||
if callback_type in self.utils_callbacks:
|
||
self.utils_callbacks[callback_type].append(callback)
|
||
print(f"✓ 工具回调已注册: {callback_type}")
|
||
else:
|
||
print(f"✗ 无效的回调类型: {callback_type}")
|
||
except Exception as e:
|
||
print(f"✗ 工具回调注册失败: {e}")
|
||
|
||
def unregister_utils_callback(self, callback_type: str, callback: callable):
|
||
"""
|
||
注销工具回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
callback: 回调函数
|
||
"""
|
||
try:
|
||
if callback_type in self.utils_callbacks:
|
||
if callback in self.utils_callbacks[callback_type]:
|
||
self.utils_callbacks[callback_type].remove(callback)
|
||
print(f"✓ 工具回调已注销: {callback_type}")
|
||
except Exception as e:
|
||
print(f"✗ 工具回调注销失败: {e}") |