需求:1.加入了用户积分表;2.加入了指令积分扣除功能;3.加入了积分获得与扣除注解。
This commit is contained in:
120
utils/decorator/plugin_decorators.py
Normal file
120
utils/decorator/plugin_decorators.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import functools
|
||||
import time
|
||||
import traceback
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Callable, Dict, Any, Tuple
|
||||
|
||||
from db.stats_db import StatsDBOperator
|
||||
from db.connection import DBConnectionManager
|
||||
|
||||
|
||||
def plugin_stats_decorator(plugin_name: str) -> Callable:
|
||||
"""插件统计装饰器
|
||||
|
||||
Args:
|
||||
plugin_name: 插件名称
|
||||
|
||||
Returns:
|
||||
装饰器函数
|
||||
"""
|
||||
# 获取日志记录器
|
||||
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]:
|
||||
# 获取数据库连接
|
||||
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)
|
||||
|
||||
# 计算执行时间(毫秒)
|
||||
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")
|
||||
|
||||
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,
|
||||
stack_trace=stack_trace
|
||||
)
|
||||
logger.info(f"[{plugin_name}] 成功记录插件错误: {command}, 错误: {error_message}")
|
||||
except Exception as db_error:
|
||||
logger.error(f"[{plugin_name}] 记录插件统计数据失败: {db_error}")
|
||||
|
||||
# 重新抛出异常,让上层处理
|
||||
raise
|
||||
except Exception as outer_error:
|
||||
logger.error(f"[{plugin_name}] 装饰器外层错误: {outer_error}")
|
||||
logger.error(traceback.format_exc())
|
||||
# 确保原始函数仍然被调用,即使装饰器出错
|
||||
return func(self, message)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
164
utils/decorator/points_decorator.py
Normal file
164
utils/decorator/points_decorator.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import functools
|
||||
import time
|
||||
import traceback
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Callable, Dict, Any, Tuple, Union
|
||||
|
||||
from db.connection import DBConnectionManager
|
||||
from db.points_db import PointsDBOperator, PointSource
|
||||
|
||||
|
||||
def points_reward_decorator(points_calculator: Union[int, Callable], source_type: str = "other",
|
||||
description: str = None):
|
||||
"""积分奖励装饰器
|
||||
|
||||
Args:
|
||||
points_calculator: 积分数量或计算函数,如果是函数,接收(self, message, success, response)参数并返回积分数量
|
||||
source_type: 积分来源类型 (checkin, game, other)
|
||||
description: 积分奖励描述
|
||||
|
||||
Returns:
|
||||
装饰器函数
|
||||
"""
|
||||
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
# 调用原始方法
|
||||
success, response = 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 = logging.getLogger(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 = logging.getLogger("PointsReward")
|
||||
logger.error(f"奖励积分失败: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
return success, response
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def plugin_points_cost(points: int, description: str = None):
|
||||
"""插件积分消费装饰器
|
||||
|
||||
Args:
|
||||
points: 消费积分数量
|
||||
description: 积分消费描述
|
||||
|
||||
Returns:
|
||||
装饰器函数
|
||||
"""
|
||||
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 获取消息信息
|
||||
sender = message.get("sender", "")
|
||||
roomid = message.get("roomid", "")
|
||||
|
||||
if not sender or not (roomid or sender):
|
||||
return func(self, message)
|
||||
|
||||
# 检查用户积分是否足够
|
||||
db_manager = DBConnectionManager.get_instance()
|
||||
points_db = PointsDBOperator(db_manager)
|
||||
|
||||
plugin_name = self.name if hasattr(self, 'name') else "未知插件"
|
||||
logger = logging.getLogger(f"PointsCost.{plugin_name}")
|
||||
|
||||
user_points = points_db.get_user_points(sender, roomid)
|
||||
if user_points["total_points"] < points:
|
||||
# 积分不足
|
||||
wcf = message.get("wcf")
|
||||
if wcf:
|
||||
wcf.send_text(
|
||||
f"❌ 积分不足,无法使用 {plugin_name} 功能\n"
|
||||
f"当前积分: {user_points['total_points']}\n"
|
||||
f"需要积分: {points}\n"
|
||||
f"还差 {points - user_points['total_points']} 积分",
|
||||
(roomid if roomid else sender), sender
|
||||
)
|
||||
logger.info(f"用户 {sender} 积分不足,无法使用功能")
|
||||
return False, "积分不足"
|
||||
|
||||
# 调用原始方法
|
||||
success, response = 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} 使用功能扣除 {points} 积分")
|
||||
|
||||
# 如果响应中没有提到积分,添加积分信息
|
||||
if "积分" not in response:
|
||||
response += f"\n\n💰 已消费 {points} 积分"
|
||||
else:
|
||||
logger.warning(f"用户 {sender} 积分扣除失败: {deduct_result}")
|
||||
|
||||
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
|
||||
|
||||
return decorator
|
||||
Reference in New Issue
Block a user