import threading import time from typing import Any from zhenxun.services.log import logger class CPlayerPool: """ 用户池管理类 管理用户对象的生命周期,支持自动清理超时用户 """ def __init__(self, timeoutSeconds: int = 300, cleanupInterval: int = 3600): """ 初始化用户池 Args: timeoutSeconds: 用户超时时间(秒),默认5分钟 cleanupInterval: 清理间隔(秒),默认1小时 """ self._players: dict[str, dict[str, Any]] = {} self._lock = threading.RLock() self.timeoutSeconds = timeoutSeconds self.cleanupInterval = cleanupInterval # 启动后台清理线程 self._cleanupThread = threading.Thread(target=self._cleanupWorker, daemon=True) self._running = True self._cleanupThread.start() logger.debug( f"用户池初始化完成,超时时间: {timeoutSeconds}秒, 清理间隔: {cleanupInterval}秒" ) def createUser(self, uid: str, userObj: Any) -> bool: """ 创建并管理用户对象 Args: uid: 用户ID userObj: 用户对象 Returns: bool: 是否创建成功 """ with self._lock: if uid in self._players: logger.debug(f"用户 {uid} 已存在,正在覆盖") # 可以选择返回False或者覆盖,这里选择覆盖 # return False self._players[uid] = { "object": userObj, "lastActive": time.time(), "activeCount": 0, } logger.debug(f"用户 {uid} 创建并开始管理") return True def getUser(self, uid: str) -> Any | None: """ 获取用户对象并刷新活跃时间 Args: uid: 用户ID Returns: Optional[Any]: 用户对象,如果不存在或已超时则返回None """ with self._lock: userData = self._players.get(uid) if not userData: logger.debug(f"用户 {uid} 不存在") return None # 检查是否已超时(防御性检查) currentTime = time.time() if currentTime - userData["lastActive"] > self.timeoutSeconds: logger.debug(f"用户 {uid} 在获取操作期间已超时") self._removeUser(uid) return None # 刷新活跃时间 userData["lastActive"] = currentTime userData["activeCount"] += 1 logger.debug(f"用户 {uid} 获取成功,活跃次数: {userData['activeCount']}") return userData["object"] def updateUser(self, uid: str, userObj: Any) -> bool: """ 更新用户对象 Args: uid: 用户ID userObj: 新的用户对象 Returns: bool: 是否更新成功 """ with self._lock: if uid not in self._players: logger.debug(f"用户 {uid} 不存在,无法更新") return False self._players[uid]["object"] = userObj self._players[uid]["lastActive"] = time.time() logger.debug(f"用户 {uid} 更新成功") return True def removeUser(self, uid: str) -> bool: """ 主动移除用户 Args: uid: 用户ID Returns: bool: 是否移除成功 """ with self._lock: return self._removeUser(uid) def _removeUser(self, uid: str) -> bool: """内部移除用户方法""" if uid in self._players: userData = self._players.pop(uid) # 如果需要清理资源,可以在这里处理 if hasattr(userData["object"], "close"): try: userData["object"].close() except Exception as e: logger.debug(f"关闭用户 {uid} 时出错: {e}") logger.debug(f"用户 {uid} 已移除,总活跃次数: {userData['activeCount']}") return True return False def _cleanupWorker(self): """后台清理线程的工作函数""" while self._running: try: self._cleanupExpiredUsers() except Exception as e: logger.debug(f"清理工作线程出错: {e}") # 休眠指定间隔 time.sleep(self.cleanupInterval) def _cleanupExpiredUsers(self): """清理超时用户""" currentTime = time.time() expiredUsers = [] # 首先收集过期的用户ID,避免在迭代中修改字典 with self._lock: for uid, userData in self._players.items(): if currentTime - userData["lastActive"] > self.timeoutSeconds: expiredUsers.append(uid) # 移除过期用户 for uid in expiredUsers: with self._lock: # 再次检查,防止在收集和移除之间用户被更新 if ( uid in self._players and currentTime - self._players[uid]["lastActive"] > self.timeoutSeconds ): self._removeUser(uid) if expiredUsers: logger.debug(f"已清理 {len(expiredUsers)} 个过期用户: {expiredUsers}") def getActiveUsers(self) -> dict[str, dict[str, Any]]: """ 获取当前活跃用户信息 Returns: Dict: 用户信息字典 """ with self._lock: # 返回副本避免外部修改 return { uid: { "lastActive": data["lastActive"], "activeCount": data["activeCount"], "timeRemaining": self.timeoutSeconds - (time.time() - data["lastActive"]), } for uid, data in self._players.items() } def userCount(self) -> int: """获取当前用户数量""" with self._lock: return len(self._players) def shutdown(self): """关闭用户池,清理资源""" self._running = False if self._cleanupThread.is_alive(): self._cleanupThread.join(timeout=5) # 清理所有用户 with self._lock: uids = list(self._players.keys()) for uid in uids: self._removeUser(uid) logger.debug("用户池关闭完成") g_pUserPool = CPlayerPool()