""" 客户端管理器模块 管理客户端连接和状态 """ 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}")