zhenxun_plugin_farm/core/player/playerPool.py

217 lines
6.5 KiB
Python
Raw Normal View History

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()