855 协议版本-调整完毕内容

This commit is contained in:
liuwei
2025-04-30 13:22:33 +08:00
parent 869bce8a18
commit 454d084715
88 changed files with 1565 additions and 7816 deletions

View File

@@ -1,7 +1,8 @@
import functools
import time
import traceback
import logging
import asyncio
from loguru import logger
from datetime import datetime
from typing import Callable, Dict, Any, Tuple
@@ -19,14 +20,13 @@ def plugin_stats_decorator(plugin_name: str) -> Callable:
装饰器函数
"""
# 获取日志记录器
logger = logging.getLogger(f"StatsCollector.{plugin_name}")
logger.debug(f"为插件 '{plugin_name}' 应用统计装饰器")
def decorator(func: Callable) -> Callable:
logger.debug(f"装饰 '{plugin_name}'{func.__name__} 方法")
@functools.wraps(func)
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
async def async_wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
# 获取数据库连接
try:
logger.debug(f"[{plugin_name}] 开始处理消息")
@@ -48,7 +48,122 @@ def plugin_stats_decorator(plugin_name: str) -> Callable:
logger.debug(f"[{plugin_name}] 开始执行时间: {datetime.fromtimestamp(start_time).strftime('%Y-%m-%d %H:%M:%S.%f')}")
try:
# 调用原始方法
# 调用原始异步方法
logger.debug(f"[{plugin_name}] 调用原始方法 {func.__name__}")
success, response = await func(self, message)
# 计算执行时间(毫秒)
end_time = time.time()
process_time_ms = (end_time - start_time) * 1000
logger.debug(f"[{plugin_name}] 执行完成,耗时: {process_time_ms:.2f}ms, 结果: {success}, 响应: {response}")
# 记录插件调用
logger.debug(f"[{plugin_name}] 记录插件调用统计")
stats_db.record_plugin_call(
plugin_name=plugin_name,
command=command,
user_id=sender,
group_id=roomid,
success=success,
process_time_ms=process_time_ms
)
logger.info(f"[{plugin_name}] 成功记录插件调用: {command}, 耗时: {process_time_ms:.2f}ms")
# 定义不需要记录错误的正常业务状态
normal_responses = {
"没有权限",
"命令格式错误",
"请先开启功能",
# 可以添加其他正常的业务状态返回
}
# 新增:如果业务代码返回失败,且不属于正常业务状态,则记录错误信息
if not success and response and response not in normal_responses:
logger.debug(f"[{plugin_name}] 业务代码返回失败,记录错误信息: {response}")
try:
stats_db.record_error(
plugin_name=plugin_name,
command=command,
user_id=sender,
group_id=roomid,
error_message=f"业务返回失败: {response}",
stack_trace="业务代码捕获的错误,无堆栈信息"
)
logger.info(f"[{plugin_name}] 成功记录业务失败信息: {response}")
except Exception as err_record_error:
logger.error(f"[{plugin_name}] 记录业务失败信息出错: {err_record_error}")
return success, response
except Exception as e:
# 计算执行时间(毫秒)
end_time = time.time()
process_time_ms = (end_time - start_time) * 1000
# 记录错误
error_message = str(e)
stack_trace = traceback.format_exc()
logger.error(f"[{plugin_name}] 执行出错: {error_message}")
logger.debug(f"[{plugin_name}] 错误堆栈: {stack_trace}")
try:
# 记录插件调用(失败)
logger.debug(f"[{plugin_name}] 记录插件调用失败统计")
stats_db.record_plugin_call(
plugin_name=plugin_name,
command=command, # 使用提取的指令而不是完整内容
user_id=sender,
group_id=roomid,
success=False,
process_time_ms=process_time_ms
)
# 记录错误详情
logger.debug(f"[{plugin_name}] 记录错误详情")
stats_db.record_error(
plugin_name=plugin_name,
command=command, # 使用提取的指令而不是完整内容
user_id=sender,
group_id=roomid,
error_message=error_message[:500] if error_message else "未知错误", # 限制长度并确保不为空
stack_trace=stack_trace[:2000] if stack_trace else "无堆栈信息" # 限制长度并确保不为空
)
logger.info(f"[{plugin_name}] 成功记录插件错误: {command}, 错误: {error_message}")
except Exception as db_error:
logger.error(f"[{plugin_name}] 记录插件统计数据失败: {db_error}")
logger.error(traceback.format_exc())
# 重新抛出异常,让上层处理
raise
except Exception as outer_error:
logger.error(f"[{plugin_name}] 装饰器外层错误: {outer_error}")
logger.error(traceback.format_exc())
# 确保原始函数仍然被调用,即使装饰器出错
return await func(self, message)
@functools.wraps(func)
def sync_wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
# 获取数据库连接
try:
logger.debug(f"[{plugin_name}] 开始处理消息")
db_manager = DBConnectionManager.get_instance()
stats_db = StatsDBOperator(db_manager)
# 提取消息信息
content = message.get("content", "")
sender = message.get("sender", "")
roomid = message.get("roomid", "")
# 提取指令部分(假设指令是第一个单词或空格前的部分)
command = content.strip().split(' ')[0] if content else ""
logger.debug(f"[{plugin_name}] 消息内容: '{content}', 指令: '{command}', 发送者: {sender}, 群ID: {roomid}")
# 记录开始时间
start_time = time.time()
logger.debug(f"[{plugin_name}] 开始执行时间: {datetime.fromtimestamp(start_time).strftime('%Y-%m-%d %H:%M:%S.%f')}")
try:
# 调用原始同步方法
logger.debug(f"[{plugin_name}] 调用原始方法 {func.__name__}")
success, response = func(self, message)
@@ -140,6 +255,10 @@ def plugin_stats_decorator(plugin_name: str) -> Callable:
# 确保原始函数仍然被调用,即使装饰器出错
return func(self, message)
return wrapper
# 根据原始函数是否为异步函数返回相应的包装器
if asyncio.iscoroutinefunction(func):
return async_wrapper
else:
return sync_wrapper
return decorator

View File

@@ -1,7 +1,8 @@
import functools
import time
import traceback
import logging
import asyncio
from loguru import logger
from typing import Callable, Dict, Any, Tuple, Union
from db.connection import DBConnectionManager
@@ -25,7 +26,7 @@ def points_reward_decorator(points_calculator: Union[int, Callable], source_type
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
async def async_wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
# 检查权限
roomid = message.get("roomid", "")
@@ -33,7 +34,74 @@ def points_reward_decorator(points_calculator: Union[int, Callable], source_type
if GroupBotManager.get_group_permission(roomid, feature) == PermissionStatus.DISABLED:
return False, "没有权限"
# 调用原始方法
# 调用原始异步方法
success, response = await func(self, message)
# 如果原始方法执行成功,奖励积分
if success:
try:
# 获取消息信息
sender = message.get("sender", "")
roomid = message.get("roomid", "")
if sender and (roomid or sender):
# 计算奖励积分数量
if callable(points_calculator):
# 如果是函数,调用函数计算积分
points = points_calculator(self, message, success, response)
if not points or points <= 0:
# 如果计算结果为0或负数不奖励积分
return success, response
else:
# 如果是固定值,直接使用
points = points_calculator
# 获取积分来源类型
source = PointSource.CHECKIN
if source_type.lower() == "game":
source = PointSource.GAME
elif source_type.lower() != "checkin":
source = PointSource.OTHER
# 奖励积分
db_manager = DBConnectionManager.get_instance()
points_db = PointsDBOperator(db_manager)
# 如果description是函数调用函数获取描述
desc = description
if callable(description):
desc = description(self, message, success, response, points)
reward_success, reward_result = points_db.add_points(
sender, roomid, points, source,
desc or f"使用 {self.name if hasattr(self, 'name') else '功能'} 获得奖励"
)
logger.info(f"PointsReward.{self.name if hasattr(self, 'name') else 'Unknown'}")
if reward_success:
logger.info(f"用户 {sender} 获得 {points} 积分奖励")
# 如果响应中没有提到积分,添加积分信息
if "积分" not in response:
response += f"\n\n🎁 恭喜获得 {points} 积分奖励!"
else:
logger.warning(f"用户 {sender} 积分奖励失败: {reward_result}")
except Exception as e:
logger.error(f"奖励积分失败: {e}")
logger.error(traceback.format_exc())
return success, response
@functools.wraps(func)
def sync_wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
# 检查权限
roomid = message.get("roomid", "")
if feature and roomid:
if GroupBotManager.get_group_permission(roomid, feature) == PermissionStatus.DISABLED:
return False, "没有权限"
# 调用原始同步方法
success, response = func(self, message)
# 如果原始方法执行成功,奖励积分
@@ -76,7 +144,7 @@ def points_reward_decorator(points_calculator: Union[int, Callable], source_type
desc or f"使用 {self.name if hasattr(self, 'name') else '功能'} 获得奖励"
)
logger = logging.getLogger(f"PointsReward.{self.name if hasattr(self, 'name') else 'Unknown'}")
logger.info(f"PointsReward.{self.name if hasattr(self, 'name') else 'Unknown'}")
if reward_success:
logger.info(f"用户 {sender} 获得 {points} 积分奖励")
@@ -86,13 +154,16 @@ def points_reward_decorator(points_calculator: Union[int, Callable], source_type
else:
logger.warning(f"用户 {sender} 积分奖励失败: {reward_result}")
except Exception as e:
logger = logging.getLogger("PointsReward")
logger.error(f"奖励积分失败: {e}")
logger.error(traceback.format_exc())
return success, response
return wrapper
# 根据原始函数是否为异步函数返回相应的包装器
if asyncio.iscoroutinefunction(func):
return async_wrapper
else:
return sync_wrapper
return decorator
@@ -111,19 +182,90 @@ def plugin_points_cost(points: int, description: str = None, feature: Feature =
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
async def async_wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
try:
# 检查权限
roomid = message.get("roomid", "")
if feature and roomid:
if GroupBotManager.get_group_permission(roomid, feature) == PermissionStatus.DISABLED:
gbm = message.get("gbm")
if gbm and gbm.get_group_permission(roomid, feature) == PermissionStatus.DISABLED:
return False, "没有权限"
# 检查是否开启了积分获取功能 SIGNIN 和 TASK_GAME 如果没有开启,则不扣积分 请用== == PermissionStatus.DISABLED 判断
if GroupBotManager.get_group_permission(roomid,
Feature.SIGNIN) == PermissionStatus.DISABLED and GroupBotManager.get_group_permission(
roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
# 检查是否开启了积分获取功能
if gbm and gbm.get_group_permission(roomid, Feature.SIGNIN) == PermissionStatus.DISABLED and gbm.get_group_permission(
roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
return await func(self, message)
# 获取消息信息
sender = message.get("sender", "")
roomid = message.get("roomid", "")
if not sender or not (roomid or sender):
return await func(self, message)
# 检查用户积分是否足够
db_manager = DBConnectionManager.get_instance()
points_db = PointsDBOperator(db_manager)
plugin_name = self.name if hasattr(self, 'name') else "未知插件"
logger.info(f"PointsCost.{plugin_name}")
user_points = points_db.get_user_points(sender, roomid)
if user_points["total_points"] < points:
# 积分不足
await self.message_util.send_text(
f"❌ 积分不足\n无法使用 {plugin_name} 功能\n"
f"🪙 先参与积分活动[签到,答题/t]赚取吧!\n"
f"💰 有: {user_points['total_points']} | 需: {points} |差: {points - user_points['total_points']} ",
(roomid if roomid else sender), sender
)
logger.info(f"用户 {sender} 积分不足,无法使用功能")
return False, "积分不足"
# 调用原始异步方法
success, response = await func(self, message)
# 如果原始方法执行成功,扣除积分
if success:
deduct_success, deduct_result = points_db.deduct_points(
sender, roomid, points, PointSource.PLUGIN,
description or f"使用 {plugin_name} 功能"
)
if deduct_success:
logger.info(f"用户 {sender} 使用 {plugin_name} 功能扣除 {points} 积分")
# 添加对 response 的类型检查
if isinstance(response, str) and "积分" not in response:
response += f"\n\n💰 已消费 {points} 积分"
await self.message_util.send_text(
f"💰消费 {points} 积分",
(roomid if roomid else sender), sender
)
else:
logger.warning(f"用户 {sender} 积分扣除失败: {deduct_result}")
return success, response
except Exception as e:
logger.error(f"积分消费失败: {e}")
logger.error(traceback.format_exc())
return await func(self, message)
@functools.wraps(func)
def sync_wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
try:
# 检查权限
roomid = message.get("roomid", "")
if feature and roomid:
gbm = message.get("gbm")
if gbm and gbm.get_group_permission(roomid, feature) == PermissionStatus.DISABLED:
return False, "没有权限"
# 检查是否开启了积分获取功能
if gbm and gbm.get_group_permission(roomid, Feature.SIGNIN) == PermissionStatus.DISABLED and gbm.get_group_permission(
roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
return func(self, message)
# 获取消息信息
sender = message.get("sender", "")
roomid = message.get("roomid", "")
@@ -136,7 +278,7 @@ def plugin_points_cost(points: int, description: str = None, feature: Feature =
points_db = PointsDBOperator(db_manager)
plugin_name = self.name if hasattr(self, 'name') else "未知插件"
logger = logging.getLogger(f"PointsCost.{plugin_name}")
logger.info(f"PointsCost.{plugin_name}")
user_points = points_db.get_user_points(sender, roomid)
if user_points["total_points"] < points:
@@ -150,7 +292,7 @@ def plugin_points_cost(points: int, description: str = None, feature: Feature =
logger.info(f"用户 {sender} 积分不足,无法使用功能")
return False, "积分不足"
# 调用原始方法
# 调用原始同步方法
success, response = func(self, message)
# 如果原始方法执行成功,扣除积分
@@ -175,11 +317,14 @@ def plugin_points_cost(points: int, description: str = None, feature: Feature =
return success, response
except Exception as e:
logger = logging.getLogger("PointsCost")
logger.error(f"积分消费失败: {e}")
logger.error(traceback.format_exc())
return func(self, message)
return wrapper
# 根据原始函数是否为异步函数返回相应的包装器
if asyncio.iscoroutinefunction(func):
return async_wrapper
else:
return sync_wrapper
return decorator