事件工厂111

This commit is contained in:
2026-01-01 18:43:14 +08:00
parent 046dd0860f
commit 3ba15d38f9
15 changed files with 1017 additions and 245 deletions

68
models/events/base.py Normal file
View File

@@ -0,0 +1,68 @@
"""
基础事件模型模块
定义了所有 OneBot 11 事件的基类和事件类型枚举。
"""
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Optional
from abc import ABC, abstractmethod
if TYPE_CHECKING:
from core.bot import Bot
class EventType:
"""
事件类型枚举
"""
META = 'meta_event' # 元事件
REQUEST = 'request' # 请求事件
NOTICE = 'notice' # 通知事件
MESSAGE = 'message' # 消息事件
MESSAGE_SENT = 'message_sent' # 消息发送事件
@dataclass
class OneBotEvent(ABC):
"""
OneBot 事件基类
所有具体的事件类型都应该继承自此类
"""
time: int
"""事件发生的时间戳"""
self_id: int
"""收到事件的机器人 QQ 号"""
_bot: Optional["Bot"] = field(default=None, init=False)
"""Bot 实例引用,用于快捷调用 API"""
@property
@abstractmethod
def post_type(self) -> str:
"""
上报类型
"""
pass
@property
def bot(self) -> "Bot":
"""
获取 Bot 实例
:return: Bot 实例
:raises ValueError: 如果 Bot 实例未设置
"""
if self._bot is None:
raise ValueError("Bot instance not set for this event")
return self._bot
@bot.setter
def bot(self, value: "Bot"):
"""
设置 Bot 实例
:param value: Bot 实例
"""
self._bot = value

275
models/events/factory.py Normal file
View File

@@ -0,0 +1,275 @@
"""
事件工厂模块
用于根据 JSON 数据创建对应的事件对象。
"""
from typing import Any, Dict
from models.message import MessageSegment
from models.sender import Sender
from .base import OneBotEvent, EventType
from .message import GroupMessageEvent, PrivateMessageEvent, Anonymous
from .notice import (
NoticeEvent, FriendAddNoticeEvent, FriendRecallNoticeEvent,
GroupRecallNoticeEvent, GroupIncreaseNoticeEvent,
GroupDecreaseNoticeEvent, GroupAdminNoticeEvent, GroupBanNoticeEvent,
GroupUploadNoticeEvent, GroupUploadFile
)
from .request import RequestEvent, FriendRequestEvent, GroupRequestEvent
from .meta import MetaEvent, HeartbeatEvent, LifeCycleEvent, HeartbeatStatus
class EventFactory:
"""
事件工厂类
"""
@staticmethod
def create_event(data: Dict[str, Any]) -> OneBotEvent:
"""
根据数据创建事件对象
:param data: 事件数据字典
:return: 对应的事件对象
:raises ValueError: 如果事件类型未知
"""
post_type = data.get("post_type")
# 提取公共字段
common_args = {
"time": data.get("time", 0),
"self_id": data.get("self_id", 0),
}
if post_type == EventType.MESSAGE or post_type == EventType.MESSAGE_SENT:
return EventFactory._create_message_event(data, common_args)
elif post_type == EventType.NOTICE:
return EventFactory._create_notice_event(data, common_args)
elif post_type == EventType.REQUEST:
return EventFactory._create_request_event(data, common_args)
elif post_type == EventType.META:
return EventFactory._create_meta_event(data, common_args)
else:
# 未知类型的事件,抛出异常
raise ValueError(f"Unknown event type: {post_type}")
@staticmethod
def _create_message_event(data: Dict[str, Any], common_args: Dict[str, Any]) -> OneBotEvent:
"""
创建消息事件
:param data: 事件数据
:param common_args: 公共参数
:return: 消息事件对象
"""
message_type = data.get("message_type")
# 解析消息段
message_list = []
raw_message_list = data.get("message", [])
if isinstance(raw_message_list, list):
for item in raw_message_list:
if isinstance(item, dict):
message_list.append(MessageSegment(type=item.get("type", ""), data=item.get("data", {})))
# 解析发送者
sender_data = data.get("sender", {})
sender = Sender(
user_id=sender_data.get("user_id", 0),
nickname=sender_data.get("nickname", ""),
sex=sender_data.get("sex", "unknown"),
age=sender_data.get("age", 0),
card=sender_data.get("card"),
area=sender_data.get("area"),
level=sender_data.get("level"),
role=sender_data.get("role"),
title=sender_data.get("title"),
)
msg_args = {
**common_args,
"message_type": message_type,
"sub_type": data.get("sub_type", ""),
"message_id": data.get("message_id", 0),
"user_id": data.get("user_id", 0),
"message": message_list,
"raw_message": data.get("raw_message", ""),
"font": data.get("font", 0),
"sender": sender,
}
if message_type == "private":
return PrivateMessageEvent(**msg_args)
elif message_type == "group":
anonymous_data = data.get("anonymous")
anonymous = None
if anonymous_data:
anonymous = Anonymous(
id=anonymous_data.get("id", 0),
name=anonymous_data.get("name", ""),
flag=anonymous_data.get("flag", "")
)
return GroupMessageEvent(
**msg_args,
group_id=data.get("group_id", 0),
anonymous=anonymous,
)
else:
# 未知消息类型,抛出异常
raise ValueError(f"Unknown message type: {message_type}")
@staticmethod
def _create_notice_event(data: Dict[str, Any], common_args: Dict[str, Any]) -> OneBotEvent:
"""
创建通知事件
:param data: 事件数据
:param common_args: 公共参数
:return: 通知事件对象
"""
notice_type = data.get("notice_type", "")
# 好友相关通知
if notice_type == "friend_add":
return FriendAddNoticeEvent(
**common_args,
notice_type=notice_type,
user_id=data.get("user_id", 0)
)
elif notice_type == "friend_recall":
return FriendRecallNoticeEvent(
**common_args,
notice_type=notice_type,
user_id=data.get("user_id", 0),
message_id=data.get("message_id", 0)
)
# 群相关通知
elif notice_type == "group_recall":
return GroupRecallNoticeEvent(
**common_args,
notice_type=notice_type,
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
operator_id=data.get("operator_id", 0),
message_id=data.get("message_id", 0)
)
elif notice_type == "group_increase":
return GroupIncreaseNoticeEvent(
**common_args,
notice_type=notice_type,
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
operator_id=data.get("operator_id", 0),
sub_type=data.get("sub_type", "")
)
elif notice_type == "group_decrease":
return GroupDecreaseNoticeEvent(
**common_args,
notice_type=notice_type,
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
operator_id=data.get("operator_id", 0),
sub_type=data.get("sub_type", "")
)
elif notice_type == "group_admin":
return GroupAdminNoticeEvent(
**common_args,
notice_type=notice_type,
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
sub_type=data.get("sub_type", "")
)
elif notice_type == "group_ban":
return GroupBanNoticeEvent(
**common_args,
notice_type=notice_type,
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
operator_id=data.get("operator_id", 0),
duration=data.get("duration", 0),
sub_type=data.get("sub_type", "")
)
elif notice_type == "group_upload":
file_data = data.get("file", {})
file = GroupUploadFile(
id=file_data.get("id", ""),
name=file_data.get("name", ""),
size=file_data.get("size", 0),
busid=file_data.get("busid", 0)
)
return GroupUploadNoticeEvent(
**common_args,
notice_type=notice_type,
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
file=file
)
else:
# 未知通知类型,返回基础通知事件
return NoticeEvent(**common_args, notice_type=notice_type)
@staticmethod
def _create_request_event(data: Dict[str, Any], common_args: Dict[str, Any]) -> OneBotEvent:
"""
创建请求事件
:param data: 事件数据
:param common_args: 公共参数
:return: 请求事件对象
"""
request_type = data.get("request_type", "")
if request_type == "friend":
return FriendRequestEvent(
**common_args,
request_type=request_type,
user_id=data.get("user_id", 0),
comment=data.get("comment", ""),
flag=data.get("flag", "")
)
elif request_type == "group":
return GroupRequestEvent(
**common_args,
request_type=request_type,
sub_type=data.get("sub_type", ""),
group_id=data.get("group_id", 0),
user_id=data.get("user_id", 0),
comment=data.get("comment", ""),
flag=data.get("flag", "")
)
else:
# 未知请求类型,返回基础请求事件
return RequestEvent(**common_args, request_type=request_type)
@staticmethod
def _create_meta_event(data: Dict[str, Any], common_args: Dict[str, Any]) -> OneBotEvent:
"""
创建元事件
:param data: 事件数据
:param common_args: 公共参数
:return: 元事件对象
"""
meta_event_type = data.get("meta_event_type", "")
if meta_event_type == "heartbeat":
status_data = data.get("status", {})
status = HeartbeatStatus(
online=status_data.get("online"),
good=status_data.get("good", True)
)
return HeartbeatEvent(
**common_args,
meta_event_type=meta_event_type,
status=status,
interval=data.get("interval", 0)
)
elif meta_event_type == "lifecycle":
return LifeCycleEvent(
**common_args,
meta_event_type=meta_event_type,
sub_type=data.get("sub_type", "")
)
else:
# 未知元事件类型,返回基础元事件
return MetaEvent(**common_args, meta_event_type=meta_event_type)

116
models/events/message.py Normal file
View File

@@ -0,0 +1,116 @@
"""
消息事件模型模块
定义了消息相关的事件类,包括 MessageEvent, PrivateMessageEvent, GroupMessageEvent。
"""
from dataclasses import dataclass, field
from typing import List, Optional
from models.message import MessageSegment
from models.sender import Sender
from .base import OneBotEvent, EventType
@dataclass
class Anonymous:
"""
匿名信息
"""
id: int = 0
"""匿名用户 ID"""
name: str = ""
"""匿名用户名称"""
flag: str = ""
"""匿名用户 flag"""
@dataclass
class MessageEvent(OneBotEvent):
"""
消息事件基类
"""
message_type: str
"""消息类型: private (私聊), group (群聊)"""
sub_type: str
"""
消息子类型
如果是私聊消息,可能是 friend, group, other, normal, anonymous, notice
如果是群聊消息,可能是 normal, anonymous, notice
"""
message_id: int
"""消息 ID"""
user_id: int
"""发送者 QQ 号"""
message: List[MessageSegment] = field(default_factory=list)
"""消息内容列表"""
raw_message: str = ""
"""原始消息内容"""
font: int = 0
"""字体"""
sender: Optional[Sender] = None
"""发送者信息"""
@property
def post_type(self) -> str:
return EventType.MESSAGE
async def reply(self, message: str, auto_escape: bool = False):
"""
回复消息(抽象方法,由子类实现)
:param message: 回复内容
:param auto_escape: 是否自动转义
"""
raise NotImplementedError("reply method must be implemented by subclasses")
@dataclass
class PrivateMessageEvent(MessageEvent):
"""
私聊消息事件
"""
async def reply(self, message: str, auto_escape: bool = False):
"""
回复私聊消息
:param message: 回复内容
:param auto_escape: 是否自动转义
"""
await self.bot.send_private_msg(
user_id=self.user_id, message=message, auto_escape=auto_escape
)
@dataclass
class GroupMessageEvent(MessageEvent):
"""
群聊消息事件
"""
group_id: int = 0
"""群号"""
anonymous: Optional[Anonymous] = None
"""匿名信息"""
async def reply(self, message: str, auto_escape: bool = False):
"""
回复群聊消息
:param message: 回复内容
:param auto_escape: 是否自动转义
"""
await self.bot.send_group_msg(
group_id=self.group_id, message=message, auto_escape=auto_escape
)

67
models/events/meta.py Normal file
View File

@@ -0,0 +1,67 @@
"""
元事件模型模块
定义了元事件相关的事件类,包括心跳事件和生命周期事件。
"""
from dataclasses import dataclass, field
from typing import Optional
from .base import OneBotEvent, EventType
@dataclass
class HeartbeatStatus:
"""
心跳状态接口
"""
online: Optional[bool] = None # 是否在线
good: bool = True # 状态是否良好
class LifeCycleSubType:
"""
生命周期子类型枚举
"""
ENABLE = 'enable' # 启用
DISABLE = 'disable' # 禁用
CONNECT = 'connect' # 连接
@dataclass
class MetaEvent(OneBotEvent):
"""
元事件基类
"""
meta_event_type: str
"""元事件类型"""
@property
def post_type(self) -> str:
return EventType.META
@dataclass
class HeartbeatEvent(MetaEvent):
"""
心跳事件,用于确认连接状态
"""
meta_event_type: str = 'heartbeat'
"""元事件类型:心跳事件"""
status: HeartbeatStatus = field(default_factory=HeartbeatStatus)
"""状态信息"""
interval: int = 0
"""心跳间隔时间(ms)"""
@dataclass
class LifeCycleEvent(MetaEvent):
"""
生命周期事件,用于通知框架生命周期变化
"""
meta_event_type: str = 'lifecycle'
"""元事件类型:生命周期事件"""
sub_type: LifeCycleSubType = LifeCycleSubType.ENABLE
"""子类型:启用、禁用、连接"""

159
models/events/notice.py Normal file
View File

@@ -0,0 +1,159 @@
"""
通知事件模型模块
定义了通知相关的事件类,包括好友通知和群组通知等。
"""
from dataclasses import dataclass, field
from .base import OneBotEvent, EventType
@dataclass
class NoticeEvent(OneBotEvent):
"""
通知事件基类
"""
notice_type: str
"""通知类型"""
@property
def post_type(self) -> str:
return EventType.NOTICE
@dataclass
class FriendAddNoticeEvent(NoticeEvent):
"""
好友添加通知
"""
user_id: int = 0
"""新好友 QQ 号"""
@dataclass
class FriendRecallNoticeEvent(NoticeEvent):
"""
好友消息撤回通知
"""
user_id: int = 0
"""消息发送者 QQ 号"""
message_id: int = 0
"""被撤回的消息 ID"""
@dataclass
class GroupNoticeEvent(NoticeEvent):
"""
群组通知事件基类
"""
group_id: int = 0
"""群号"""
user_id: int = 0
"""用户 QQ 号"""
@dataclass
class GroupRecallNoticeEvent(GroupNoticeEvent):
"""
群消息撤回通知
"""
operator_id: int = 0
"""操作者 QQ 号"""
message_id: int = 0
"""被撤回的消息 ID"""
@dataclass
class GroupIncreaseNoticeEvent(GroupNoticeEvent):
"""
群成员增加通知
"""
operator_id: int = 0
"""操作者 QQ 号"""
sub_type: str = ""
"""
子类型
approve: 管理员同意入群
invite: 管理员邀请入群
"""
@dataclass
class GroupDecreaseNoticeEvent(GroupNoticeEvent):
"""
群成员减少通知
"""
operator_id: int = 0
"""操作者 QQ 号(如果是主动退群,则和 user_id 相同)"""
sub_type: str = ""
"""
子类型
leave: 主动退群
kick: 成员被踢
kick_me: 登录号被踢
disband: 群被解散
"""
@dataclass
class GroupAdminNoticeEvent(GroupNoticeEvent):
"""
群管理员变动通知
"""
sub_type: str = ""
"""
子类型
set: 设置管理员
unset: 取消管理员
"""
@dataclass
class GroupBanNoticeEvent(GroupNoticeEvent):
"""
群禁言通知
"""
operator_id: int = 0
"""操作者 QQ 号(管理员)"""
duration: int = 0
"""禁言时长(秒)0 表示解除禁言"""
sub_type: str = ""
"""
子类型
ban: 禁言
lift_ban: 解除禁言
"""
@dataclass
class GroupUploadFile:
"""
群文件信息
"""
id: str = ""
"""文件 ID"""
name: str = ""
"""文件名"""
size: int = 0
"""文件大小(Byte)"""
busid: int = 0
"""文件总线 ID"""
@dataclass
class GroupUploadNoticeEvent(GroupNoticeEvent):
"""
群文件上传通知
"""
file: GroupUploadFile = field(default_factory=GroupUploadFile)
"""文件信息"""

61
models/events/request.py Normal file
View File

@@ -0,0 +1,61 @@
"""
请求事件模型模块
定义了请求相关的事件类。
"""
from dataclasses import dataclass
from .base import OneBotEvent, EventType
@dataclass
class RequestEvent(OneBotEvent):
"""
请求事件基类
"""
request_type: str
"""请求类型"""
@property
def post_type(self) -> str:
return EventType.REQUEST
@dataclass
class FriendRequestEvent(RequestEvent):
"""
加好友请求事件
"""
user_id: int = 0
"""发送请求的 QQ 号"""
comment: str = ""
"""验证信息"""
flag: str = ""
"""请求 flag在调用处理请求的 API 时需要传入此 flag"""
@dataclass
class GroupRequestEvent(RequestEvent):
"""
加群请求/邀请事件
"""
sub_type: str = ""
"""
子类型
add: 加群请求
invite: 邀请登录号入群
"""
group_id: int = 0
"""群号"""
user_id: int = 0
"""发送请求的 QQ 号"""
comment: str = ""
"""验证信息"""
flag: str = ""
"""请求 flag在调用处理请求的 API 时需要传入此 flag"""