217 lines
6.5 KiB
Python
217 lines
6.5 KiB
Python
|
|
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()
|