EG/plugins/user/realtime_communication/clients/client_manager.py
2025-10-30 15:01:29 +08:00

724 lines
24 KiB
Python

"""
客户端管理器模块
管理客户端连接和状态
"""
import time
import threading
import hashlib
from typing import Dict, Any, List, Optional
class ClientManager:
"""
客户端管理器
管理客户端连接和状态
"""
def __init__(self, plugin):
"""
初始化客户端管理器
Args:
plugin: 实时通信插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 客户端配置
self.client_config = {
"enable_authentication": True,
"auth_timeout": 30.0,
"max_clients": 1000,
"enable_heartbeat": True,
"heartbeat_interval": 30.0,
"enable_rate_limiting": True,
"max_messages_per_second": 100,
"enable_banning": True,
"ban_duration": 3600,
"client_timeout": 60.0
}
# 客户端状态
self.client_state = {
"current_clients": 0,
"total_clients": 0,
"authenticated_clients": 0,
"banned_clients": 0
}
# 客户端存储
self.clients = {}
self.client_lock = threading.RLock()
# 客户端统计
self.client_stats = {
"clients_joined": 0,
"clients_left": 0,
"authentication_success": 0,
"authentication_failed": 0,
"messages_sent": 0,
"messages_received": 0,
"banned_clients": 0,
"errors": 0
}
# 黑名单管理
self.banned_ips = {}
self.banned_users = {}
# 回调函数
self.client_callbacks = {
"client_joined": [],
"client_left": [],
"client_authenticated": [],
"client_banned": [],
"client_error": []
}
# 时间戳记录
self.last_heartbeat_check = 0.0
self.last_cleanup = 0.0
print("✓ 客户端管理器已创建")
def initialize(self) -> bool:
"""
初始化客户端管理器
Returns:
是否初始化成功
"""
try:
print("正在初始化客户端管理器...")
self.initialized = True
print("✓ 客户端管理器初始化完成")
return True
except Exception as e:
print(f"✗ 客户端管理器初始化失败: {e}")
self.client_stats["errors"] += 1
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}")
self.client_stats["errors"] += 1
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用客户端管理器"""
try:
self.enabled = False
# 断开所有客户端
self._disconnect_all_clients()
print("✓ 客户端管理器已禁用")
except Exception as e:
print(f"✗ 客户端管理器禁用失败: {e}")
self.client_stats["errors"] += 1
import traceback
traceback.print_exc()
def finalize(self):
"""清理客户端管理器资源"""
try:
# 禁用客户端管理器
if self.enabled:
self.disable()
# 清理回调
self.client_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()
# 定期检查心跳
if current_time - self.last_heartbeat_check > self.client_config["heartbeat_interval"]:
self._check_client_heartbeats(current_time)
self.last_heartbeat_check = current_time
# 定期清理
if current_time - self.last_cleanup > 60.0: # 每分钟清理一次
self._cleanup_banned_clients(current_time)
self.last_cleanup = current_time
except Exception as e:
print(f"✗ 客户端管理器更新失败: {e}")
self.client_stats["errors"] += 1
import traceback
traceback.print_exc()
def _check_client_heartbeats(self, current_time: float):
"""检查客户端心跳"""
try:
if not self.client_config["enable_heartbeat"]:
return
clients_to_disconnect = []
with self.client_lock:
for client_id, client_data in self.clients.items():
last_heartbeat = client_data.get("last_heartbeat", client_data["connect_time"])
if current_time - last_heartbeat > self.client_config["client_timeout"]:
clients_to_disconnect.append(client_id)
for client_id in clients_to_disconnect:
self.disconnect_client(client_id, "timeout")
except Exception as e:
print(f"✗ 客户端心跳检查失败: {e}")
self.client_stats["errors"] += 1
def _cleanup_banned_clients(self, current_time: float):
"""清理过期的黑名单客户端"""
try:
expired_bans = []
for ip, ban_data in self.banned_ips.items():
if current_time - ban_data["ban_time"] > self.client_config["ban_duration"]:
expired_bans.append(ip)
for ip in expired_bans:
del self.banned_ips[ip]
self.client_state["banned_clients"] -= 1
except Exception as e:
print(f"✗ 黑名单清理失败: {e}")
self.client_stats["errors"] += 1
def _disconnect_all_clients(self):
"""断开所有客户端连接"""
try:
with self.client_lock:
client_ids = list(self.clients.keys())
for client_id in client_ids:
self.disconnect_client(client_id, "server_shutdown")
except Exception as e:
print(f"✗ 断开所有客户端连接失败: {e}")
self.client_stats["errors"] += 1
def add_client(self, client_id: str, client_info: Dict[str, Any]) -> bool:
"""
添加客户端
Args:
client_id: 客户端ID
client_info: 客户端信息
Returns:
是否添加成功
"""
try:
if not self.enabled:
return False
# 检查客户端数量限制
with self.client_lock:
if len(self.clients) >= self.client_config["max_clients"]:
print("✗ 客户端数量已达上限")
return False
# 检查IP是否被禁止
client_ip = client_info.get("ip_address", "")
if self._is_ip_banned(client_ip):
print(f"✗ IP地址被禁止: {client_ip}")
return False
# 添加客户端
client_data = {
"client_id": client_id,
"client_info": client_info,
"connect_time": time.time(),
"last_heartbeat": time.time(),
"is_authenticated": False,
"user_id": "",
"username": "",
"permissions": [],
"messages_sent": 0,
"messages_received": 0,
"bytes_sent": 0,
"bytes_received": 0
}
with self.client_lock:
self.clients[client_id] = client_data
self.client_state["current_clients"] = len(self.clients)
self.client_state["total_clients"] += 1
self.client_stats["clients_joined"] += 1
# 触发客户端加入回调
self._trigger_client_callback("client_joined", {
"client_id": client_id,
"client_info": client_info,
"timestamp": time.time()
})
print(f"✓ 客户端已添加: {client_id}")
return True
except Exception as e:
print(f"✗ 添加客户端失败: {e}")
self.client_stats["errors"] += 1
return False
def remove_client(self, client_id: str, reason: str = "unknown") -> bool:
"""
移除客户端
Args:
client_id: 客户端ID
reason: 移除原因
Returns:
是否移除成功
"""
try:
with self.client_lock:
if client_id in self.clients:
client_data = self.clients[client_id]
if client_data["is_authenticated"]:
self.client_state["authenticated_clients"] -= 1
del self.clients[client_id]
self.client_state["current_clients"] = len(self.clients)
self.client_stats["clients_left"] += 1
# 触发客户端离开回调
self._trigger_client_callback("client_left", {
"client_id": client_id,
"reason": reason,
"timestamp": time.time()
})
print(f"✓ 客户端已移除: {client_id} (原因: {reason})")
return True
except Exception as e:
print(f"✗ 移除客户端失败: {e}")
self.client_stats["errors"] += 1
return False
def disconnect_client(self, client_id: str, reason: str = "kicked") -> bool:
"""
断开客户端连接
Args:
client_id: 客户端ID
reason: 断开原因
Returns:
是否断开成功
"""
try:
# 通知WebSocket服务器断开连接
if self.plugin.websocket_server:
self.plugin.websocket_server.disconnect_client(client_id, reason)
# 移除客户端
return self.remove_client(client_id, reason)
except Exception as e:
print(f"✗ 断开客户端连接失败: {e}")
self.client_stats["errors"] += 1
return False
def authenticate_client(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
"""
认证客户端
Args:
client_id: 客户端ID
auth_data: 认证数据
Returns:
是否认证成功
"""
try:
if not self.enabled or not self.client_config["enable_authentication"]:
# 如果未启用认证,直接通过
with self.client_lock:
if client_id in self.clients:
self.clients[client_id]["is_authenticated"] = True
return True
# 使用认证管理器进行认证
if self.plugin.auth_manager:
auth_result = self.plugin.auth_manager.authenticate_client(client_id, auth_data)
if auth_result:
# 更新客户端认证状态
with self.client_lock:
if client_id in self.clients:
self.clients[client_id]["is_authenticated"] = True
self.clients[client_id]["user_id"] = auth_data.get("user_id", "")
self.clients[client_id]["username"] = auth_data.get("username", "")
self.clients[client_id]["permissions"] = auth_data.get("permissions", [])
self.client_state["authenticated_clients"] += 1
self.client_stats["authentication_success"] += 1
# 触发客户端认证回调
self._trigger_client_callback("client_authenticated", {
"client_id": client_id,
"user_id": auth_data.get("user_id", ""),
"username": auth_data.get("username", ""),
"timestamp": time.time()
})
print(f"✓ 客户端认证成功: {client_id}")
return True
else:
self.client_stats["authentication_failed"] += 1
print(f"✗ 客户端认证失败: {client_id}")
return False
else:
print("✗ 认证管理器不可用")
return False
except Exception as e:
print(f"✗ 客户端认证失败: {e}")
self.client_stats["errors"] += 1
return False
def update_client_heartbeat(self, client_id: str) -> bool:
"""
更新客户端心跳
Args:
client_id: 客户端ID
Returns:
是否更新成功
"""
try:
with self.client_lock:
if client_id in self.clients:
self.clients[client_id]["last_heartbeat"] = time.time()
return True
else:
return False
except Exception as e:
print(f"✗ 更新客户端心跳失败: {e}")
self.client_stats["errors"] += 1
return False
def get_client(self, client_id: str) -> Optional[Dict[str, Any]]:
"""
获取客户端信息
Args:
client_id: 客户端ID
Returns:
客户端信息或None
"""
try:
with self.client_lock:
if client_id in self.clients:
return self.clients[client_id].copy()
else:
return None
except Exception as e:
print(f"✗ 获取客户端信息失败: {e}")
self.client_stats["errors"] += 1
return None
def get_all_clients(self) -> Dict[str, Any]:
"""
获取所有客户端信息
Returns:
所有客户端信息字典
"""
try:
with self.client_lock:
return {k: v.copy() for k, v in self.clients.items()}
except Exception as e:
print(f"✗ 获取所有客户端信息失败: {e}")
self.client_stats["errors"] += 1
return {}
def ban_client(self, client_id: str, reason: str = "violation", duration: float = 3600) -> bool:
"""
禁止客户端
Args:
client_id: 客户端ID
reason: 禁止原因
duration: 禁止时长(秒)
Returns:
是否禁止成功
"""
try:
if not self.client_config["enable_banning"]:
return False
client_data = self.get_client(client_id)
if not client_data:
return False
client_ip = client_data["client_info"].get("ip_address", "")
if client_ip:
# 添加到IP黑名单
self.banned_ips[client_ip] = {
"client_id": client_id,
"ban_time": time.time(),
"reason": reason,
"duration": duration
}
self.client_state["banned_clients"] += 1
self.client_stats["banned_clients"] += 1
# 断开客户端连接
self.disconnect_client(client_id, f"banned: {reason}")
# 触发客户端禁止回调
self._trigger_client_callback("client_banned", {
"client_id": client_id,
"ip_address": client_ip,
"reason": reason,
"duration": duration,
"timestamp": time.time()
})
print(f"✓ 客户端已被禁止: {client_id} (IP: {client_ip})")
return True
else:
return False
except Exception as e:
print(f"✗ 禁止客户端失败: {e}")
self.client_stats["errors"] += 1
return False
def _is_ip_banned(self, ip_address: str) -> bool:
"""
检查IP是否被禁止
Args:
ip_address: IP地址
Returns:
IP是否被禁止
"""
try:
if not self.client_config["enable_banning"]:
return False
if ip_address in self.banned_ips:
ban_data = self.banned_ips[ip_address]
if time.time() - ban_data["ban_time"] < ban_data["duration"]:
return True
else:
# 禁止时间已过期,移除
del self.banned_ips[ip_address]
self.client_state["banned_clients"] -= 1
return False
except Exception as e:
print(f"✗ IP禁止检查失败: {e}")
self.client_stats["errors"] += 1
return False
def unban_ip(self, ip_address: str) -> bool:
"""
解除IP禁止
Args:
ip_address: IP地址
Returns:
是否解除成功
"""
try:
if ip_address in self.banned_ips:
del self.banned_ips[ip_address]
self.client_state["banned_clients"] -= 1
print(f"✓ IP禁止已解除: {ip_address}")
return True
else:
print(f"✗ IP未被禁止: {ip_address}")
return False
except Exception as e:
print(f"✗ 解除IP禁止失败: {e}")
self.client_stats["errors"] += 1
return False
def is_client_authenticated(self, client_id: str) -> bool:
"""
检查客户端是否已认证
Args:
client_id: 客户端ID
Returns:
客户端是否已认证
"""
try:
with self.client_lock:
if client_id in self.clients:
return self.clients[client_id]["is_authenticated"]
else:
return False
except Exception as e:
print(f"✗ 客户端认证检查失败: {e}")
self.client_stats["errors"] += 1
return False
def get_client_stats(self) -> Dict[str, Any]:
"""
获取客户端统计信息
Returns:
客户端统计字典
"""
return {
"state": self.client_state.copy(),
"stats": self.client_stats.copy(),
"config": self.client_config.copy()
}
def reset_stats(self):
"""重置客户端统计信息"""
try:
self.client_stats = {
"clients_joined": 0,
"clients_left": 0,
"authentication_success": 0,
"authentication_failed": 0,
"messages_sent": 0,
"messages_received": 0,
"banned_clients": 0,
"errors": 0
}
print("✓ 客户端统计信息已重置")
except Exception as e:
print(f"✗ 客户端统计信息重置失败: {e}")
def set_client_config(self, config: Dict[str, Any]) -> bool:
"""
设置客户端配置
Args:
config: 客户端配置字典
Returns:
是否设置成功
"""
try:
self.client_config.update(config)
print(f"✓ 客户端配置已更新: {self.client_config}")
return True
except Exception as e:
print(f"✗ 客户端配置设置失败: {e}")
return False
def get_client_config(self) -> Dict[str, Any]:
"""
获取客户端配置
Returns:
客户端配置字典
"""
return self.client_config.copy()
def _trigger_client_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发客户端回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.client_callbacks:
for callback in self.client_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 客户端回调执行失败: {callback_type} - {e}")
except Exception as e:
print(f"✗ 客户端回调触发失败: {e}")
def register_client_callback(self, callback_type: str, callback: callable):
"""
注册客户端回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.client_callbacks:
self.client_callbacks[callback_type].append(callback)
print(f"✓ 客户端回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 客户端回调注册失败: {e}")
def unregister_client_callback(self, callback_type: str, callback: callable):
"""
注销客户端回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.client_callbacks:
if callback in self.client_callbacks[callback_type]:
self.client_callbacks[callback_type].remove(callback)
print(f"✓ 客户端回调已注销: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 客户端回调注销失败: {e}")