148 lines
5.2 KiB
Python
148 lines
5.2 KiB
Python
import asyncio
|
||
from typing import Dict, Tuple, Callable, Optional
|
||
from dataclasses import dataclass
|
||
|
||
from src.chat.message_receive.message import MessageRecvS4U
|
||
from src.common.logger import get_logger
|
||
|
||
logger = get_logger("gift_manager")
|
||
|
||
|
||
@dataclass
|
||
class PendingGift:
|
||
"""等待中的礼物消息"""
|
||
|
||
message: MessageRecvS4U
|
||
total_count: int
|
||
timer_task: asyncio.Task
|
||
callback: Callable[[MessageRecvS4U], None]
|
||
|
||
|
||
class GiftManager:
|
||
"""礼物管理器,提供防抖功能"""
|
||
|
||
def __init__(self):
|
||
"""初始化礼物管理器"""
|
||
self.pending_gifts: Dict[Tuple[str, str], PendingGift] = {}
|
||
self.debounce_timeout = 5.0 # 3秒防抖时间
|
||
|
||
async def handle_gift(
|
||
self, message: MessageRecvS4U, callback: Optional[Callable[[MessageRecvS4U], None]] = None
|
||
) -> bool:
|
||
"""处理礼物消息,返回是否应该立即处理
|
||
|
||
Args:
|
||
message: 礼物消息
|
||
callback: 防抖完成后的回调函数
|
||
|
||
Returns:
|
||
bool: False表示消息被暂存等待防抖,True表示应该立即处理
|
||
"""
|
||
if not message.is_gift:
|
||
return True
|
||
|
||
# 构建礼物的唯一键:(发送人ID, 礼物名称)
|
||
gift_key = (message.message_info.user_info.user_id, message.gift_name)
|
||
|
||
# 如果已经有相同的礼物在等待中,则合并
|
||
if gift_key in self.pending_gifts:
|
||
await self._merge_gift(gift_key, message)
|
||
return False
|
||
|
||
# 创建新的等待礼物
|
||
await self._create_pending_gift(gift_key, message, callback)
|
||
return False
|
||
|
||
async def _merge_gift(self, gift_key: Tuple[str, str], new_message: MessageRecvS4U) -> None:
|
||
"""合并礼物消息"""
|
||
pending_gift = self.pending_gifts[gift_key]
|
||
|
||
# 取消之前的定时器
|
||
if not pending_gift.timer_task.cancelled():
|
||
pending_gift.timer_task.cancel()
|
||
|
||
# 累加礼物数量
|
||
try:
|
||
new_count = int(new_message.gift_count)
|
||
pending_gift.total_count += new_count
|
||
|
||
# 更新消息为最新的(保留最新的消息,但累加数量)
|
||
pending_gift.message = new_message
|
||
pending_gift.message.gift_count = str(pending_gift.total_count)
|
||
pending_gift.message.gift_info = f"{pending_gift.message.gift_name}:{pending_gift.total_count}"
|
||
|
||
except ValueError:
|
||
logger.warning(f"无法解析礼物数量: {new_message.gift_count}")
|
||
# 如果无法解析数量,保持原有数量不变
|
||
|
||
# 重新创建定时器
|
||
pending_gift.timer_task = asyncio.create_task(self._gift_timeout(gift_key))
|
||
|
||
logger.debug(f"合并礼物: {gift_key}, 总数量: {pending_gift.total_count}")
|
||
|
||
async def _create_pending_gift(
|
||
self, gift_key: Tuple[str, str], message: MessageRecvS4U, callback: Optional[Callable[[MessageRecvS4U], None]]
|
||
) -> None:
|
||
"""创建新的等待礼物"""
|
||
try:
|
||
initial_count = int(message.gift_count)
|
||
except ValueError:
|
||
initial_count = 1
|
||
logger.warning(f"无法解析礼物数量: {message.gift_count},默认设为1")
|
||
|
||
# 创建定时器任务
|
||
timer_task = asyncio.create_task(self._gift_timeout(gift_key))
|
||
|
||
# 创建等待礼物对象
|
||
pending_gift = PendingGift(message=message, total_count=initial_count, timer_task=timer_task, callback=callback)
|
||
|
||
self.pending_gifts[gift_key] = pending_gift
|
||
|
||
logger.debug(f"创建等待礼物: {gift_key}, 初始数量: {initial_count}")
|
||
|
||
async def _gift_timeout(self, gift_key: Tuple[str, str]) -> None:
|
||
"""礼物防抖超时处理"""
|
||
try:
|
||
# 等待防抖时间
|
||
await asyncio.sleep(self.debounce_timeout)
|
||
|
||
# 获取等待中的礼物
|
||
if gift_key not in self.pending_gifts:
|
||
return
|
||
|
||
pending_gift = self.pending_gifts.pop(gift_key)
|
||
|
||
logger.info(f"礼物防抖完成: {gift_key}, 最终数量: {pending_gift.total_count}")
|
||
|
||
message = pending_gift.message
|
||
message.processed_plain_text = f"用户{message.message_info.user_info.user_nickname}送出了礼物{message.gift_name} x{pending_gift.total_count}"
|
||
|
||
# 执行回调
|
||
if pending_gift.callback:
|
||
try:
|
||
pending_gift.callback(message)
|
||
except Exception as e:
|
||
logger.error(f"礼物回调执行失败: {e}", exc_info=True)
|
||
|
||
except asyncio.CancelledError:
|
||
# 定时器被取消,不需要处理
|
||
pass
|
||
except Exception as e:
|
||
logger.error(f"礼物防抖处理异常: {e}", exc_info=True)
|
||
|
||
def get_pending_count(self) -> int:
|
||
"""获取当前等待中的礼物数量"""
|
||
return len(self.pending_gifts)
|
||
|
||
async def flush_all(self) -> None:
|
||
"""立即处理所有等待中的礼物"""
|
||
for gift_key in list(self.pending_gifts.keys()):
|
||
pending_gift = self.pending_gifts.get(gift_key)
|
||
if pending_gift and not pending_gift.timer_task.cancelled():
|
||
pending_gift.timer_task.cancel()
|
||
await self._gift_timeout(gift_key)
|
||
|
||
|
||
# 创建全局礼物管理器实例
|
||
gift_manager = GiftManager()
|