Files
WechatHookBot/utils/decorators.py

183 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
消息处理装饰器模块
提供插件消息处理和定时任务的装饰器
使用工厂模式消除重复代码
"""
from functools import wraps
from typing import Callable, Dict, Union
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger
scheduler = AsyncIOScheduler()
# ==================== 定时任务装饰器 ====================
def schedule(
trigger: Union[str, CronTrigger, IntervalTrigger],
**trigger_args
) -> Callable:
"""
定时任务装饰器
例子:
- @schedule('interval', seconds=30)
- @schedule('cron', hour=8, minute=30, second=30)
- @schedule('date', run_date='2024-01-01 00:00:00')
"""
def decorator(func: Callable):
job_id = f"{func.__module__}.{func.__qualname__}"
@wraps(func)
async def wrapper(self, *args, **kwargs):
return await func(self, *args, **kwargs)
setattr(wrapper, '_is_scheduled', True)
setattr(wrapper, '_schedule_trigger', trigger)
setattr(wrapper, '_schedule_args', trigger_args)
setattr(wrapper, '_job_id', job_id)
return wrapper
return decorator
def add_job_safe(scheduler: AsyncIOScheduler, job_id: str, func: Callable, bot,
trigger: Union[str, CronTrigger, IntervalTrigger], **trigger_args):
"""添加函数到定时任务中,如果存在则先删除现有的任务"""
try:
scheduler.remove_job(job_id)
except Exception:
pass
# 使用统一配置管理器读取调度器配置
try:
from utils.config_manager import get_scheduler_config
scheduler_config = get_scheduler_config()
except Exception:
scheduler_config = {}
# 应用调度器配置
job_kwargs = {
"coalesce": scheduler_config.get("coalesce", True),
"max_instances": scheduler_config.get("max_instances", 1),
"misfire_grace_time": scheduler_config.get("misfire_grace_time", 30)
}
job_kwargs.update(trigger_args)
scheduler.add_job(func, trigger, args=[bot], id=job_id, **job_kwargs)
def remove_job_safe(scheduler: AsyncIOScheduler, job_id: str):
"""从定时任务中移除任务"""
try:
scheduler.remove_job(job_id)
except Exception:
pass
# ==================== 消息装饰器工厂 ====================
def _create_message_decorator(event_type: str, description: str):
"""
消息装饰器工厂函数
生成支持两种调用方式的装饰器:
- @on_xxx_message (无参数使用默认优先级50)
- @on_xxx_message(priority=80) (有参数,自定义优先级)
Args:
event_type: 事件类型字符串,如 'text_message'
description: 装饰器描述,用于生成文档字符串
Returns:
装饰器函数
"""
def decorator_factory(priority=50):
def decorator(func):
# 处理无参数调用: @on_xxx_message 时 priority 实际是被装饰的函数
if callable(priority):
target_func = priority
actual_priority = 50
else:
target_func = func
actual_priority = min(max(priority, 0), 99)
setattr(target_func, '_event_type', event_type)
setattr(target_func, '_priority', actual_priority)
return target_func
# 判断调用方式
if callable(priority):
return decorator(priority)
return decorator
decorator_factory.__doc__ = f"{description}装饰器"
decorator_factory.__name__ = f"on_{event_type}"
return decorator_factory
# ==================== 消息类型定义 ====================
# 事件类型 -> 中文描述 映射表
MESSAGE_DECORATOR_TYPES: Dict[str, str] = {
'text_message': '文本消息',
'image_message': '图片消息',
'voice_message': '语音消息',
'video_message': '视频消息',
'emoji_message': '表情消息',
'file_message': '文件消息',
'quote_message': '引用消息',
'pat_message': '拍一拍',
'at_message': '@消息',
'system_message': '系统消息',
'other_message': '其他消息',
}
# ==================== 生成所有消息装饰器 ====================
# 使用工厂函数生成装饰器
on_text_message = _create_message_decorator('text_message', '文本消息')
on_image_message = _create_message_decorator('image_message', '图片消息')
on_voice_message = _create_message_decorator('voice_message', '语音消息')
on_video_message = _create_message_decorator('video_message', '视频消息')
on_emoji_message = _create_message_decorator('emoji_message', '表情消息')
on_file_message = _create_message_decorator('file_message', '文件消息')
on_quote_message = _create_message_decorator('quote_message', '引用消息')
on_pat_message = _create_message_decorator('pat_message', '拍一拍')
on_at_message = _create_message_decorator('at_message', '@消息')
on_system_message = _create_message_decorator('system_message', '系统消息')
on_other_message = _create_message_decorator('other_message', '其他消息')
# ==================== 导出列表 ====================
__all__ = [
# 定时任务
'scheduler',
'schedule',
'add_job_safe',
'remove_job_safe',
# 消息装饰器
'on_text_message',
'on_image_message',
'on_voice_message',
'on_video_message',
'on_emoji_message',
'on_file_message',
'on_quote_message',
'on_pat_message',
'on_at_message',
'on_system_message',
'on_other_message',
# 工具
'MESSAGE_DECORATOR_TYPES',
'_create_message_decorator',
]