🚧 update cqhttp adapter event

This commit is contained in:
yanyongyu 2020-12-13 12:53:16 +08:00
parent 3d4adaa444
commit 12ef3e7bf1
3 changed files with 109 additions and 49 deletions

View File

@ -10,7 +10,7 @@ CQHTTP (OneBot) v11 协议适配
https://github.com/howmanybots/onebot/blob/master/README.md https://github.com/howmanybots/onebot/blob/master/README.md
""" """
from .event import CQHTTPEvent from .event import *
from .message import Message, MessageSegment from .message import Message, MessageSegment
from .utils import log, escape, unescape, _b2s from .utils import log, escape, unescape, _b2s
from .bot import Bot, _check_at_me, _check_nickname, _check_reply, _handle_api_result from .bot import Bot, _check_at_me, _check_nickname, _check_reply, _handle_api_result

View File

@ -16,8 +16,8 @@ from nonebot.exception import RequestDenied
from .utils import log from .utils import log
from .message import Message, MessageSegment from .message import Message, MessageSegment
from .event import Reply, Event, MessageEvent, get_event_model
from .exception import NetworkError, ApiNotAvailable, ActionFailed from .exception import NetworkError, ApiNotAvailable, ActionFailed
from .event import Reply, CQHTTPEvent, MessageEvent, get_event_model
if TYPE_CHECKING: if TYPE_CHECKING:
from nonebot.drivers import Driver, WebSocket from nonebot.drivers import Driver, WebSocket
@ -32,7 +32,7 @@ def get_auth_bearer(access_token: Optional[str] = None) -> Optional[str]:
return param return param
async def _check_reply(bot: "Bot", event: "CQHTTPEvent"): async def _check_reply(bot: "Bot", event: "Event"):
""" """
:说明: :说明:
@ -41,7 +41,7 @@ async def _check_reply(bot: "Bot", event: "CQHTTPEvent"):
:参数: :参数:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: CQHTTPEvent``: CQHTTPEvent 对象 * ``event: Event``: Event 对象
""" """
if not isinstance(event, MessageEvent): if not isinstance(event, MessageEvent):
return return
@ -69,7 +69,7 @@ async def _check_reply(bot: "Bot", event: "CQHTTPEvent"):
event.message.append(MessageSegment.text("")) event.message.append(MessageSegment.text(""))
def _check_at_me(bot: "Bot", event: "CQHTTPEvent"): def _check_at_me(bot: "Bot", event: "Event"):
""" """
:说明: :说明:
@ -78,7 +78,7 @@ def _check_at_me(bot: "Bot", event: "CQHTTPEvent"):
:参数: :参数:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: CQHTTPEvent``: CQHTTPEvent 对象 * ``event: Event``: Event 对象
""" """
if not isinstance(event, MessageEvent): if not isinstance(event, MessageEvent):
return return
@ -123,7 +123,7 @@ def _check_at_me(bot: "Bot", event: "CQHTTPEvent"):
event.message.append(MessageSegment.text("")) event.message.append(MessageSegment.text(""))
def _check_nickname(bot: "Bot", event: "CQHTTPEvent"): def _check_nickname(bot: "Bot", event: "Event"):
""" """
:说明: :说明:
@ -132,7 +132,7 @@ def _check_nickname(bot: "Bot", event: "CQHTTPEvent"):
:参数: :参数:
* ``bot: Bot``: Bot 对象 * ``bot: Bot``: Bot 对象
* ``event: CQHTTPEvent``: CQHTTPEvent 对象 * ``event: Event``: Event 对象
""" """
if not isinstance(event, MessageEvent): if not isinstance(event, MessageEvent):
return return
@ -287,7 +287,7 @@ class Bot(BaseBot):
""" """
:说明: :说明:
调用 `_check_reply <#async-check-reply-bot-event>`_, `_check_at_me <#check-at-me-bot-event>`_, `_check_nickname <#check-nickname-bot-event>`_ 处理事件并转换为 `CQHTTPEvent <#class-event>`_ 调用 `_check_reply <#async-check-reply-bot-event>`_, `_check_at_me <#check-at-me-bot-event>`_, `_check_nickname <#check-nickname-bot-event>`_ 处理事件并转换为 `Event <#class-event>`_
""" """
if not message: if not message:
return return
@ -310,7 +310,7 @@ class Bot(BaseBot):
except Exception as e: except Exception as e:
log("DEBUG", "Event Parser Error", e) log("DEBUG", "Event Parser Error", e)
else: else:
event = CQHTTPEvent.parse_obj(message) event = Event.parse_obj(message)
# Check whether user is calling me # Check whether user is calling me
await _check_reply(self, event) await _check_reply(self, event)
@ -393,7 +393,7 @@ class Bot(BaseBot):
@overrides(BaseBot) @overrides(BaseBot)
async def send(self, async def send(self,
event: CQHTTPEvent, event: Event,
message: Union[str, Message, MessageSegment], message: Union[str, Message, MessageSegment],
at_sender: bool = False, at_sender: bool = False,
**kwargs) -> Any: **kwargs) -> Any:
@ -404,7 +404,7 @@ class Bot(BaseBot):
:参数: :参数:
* ``event: CQHTTPEvent``: CQHTTPEvent 对象 * ``event: Event``: Event 对象
* ``message: Union[str, Message, MessageSegment]``: 要发送的消息 * ``message: Union[str, Message, MessageSegment]``: 要发送的消息
* ``at_sender: bool``: 是否 @ 事件主体 * ``at_sender: bool``: 是否 @ 事件主体
* ``**kwargs``: 覆盖默认参数 * ``**kwargs``: 覆盖默认参数

View File

@ -4,49 +4,55 @@ from typing import Type, List, Optional
from pydantic import BaseModel from pydantic import BaseModel
from pygtrie import StringTrie from pygtrie import StringTrie
from nonebot.adapters import Event
from nonebot.utils import escape_tag from nonebot.utils import escape_tag
from nonebot.typing import overrides from nonebot.typing import overrides
from nonebot.exception import NoLogException from nonebot.exception import NoLogException
from nonebot.adapters import Event as BaseEvent
from .message import Message from .message import Message
class CQHTTPEvent(Event): class Event(BaseEvent):
"""
CQHTTP 协议事件各事件字段未列出部分参考 `CQHTTP 文档`_
.. _CQHTTP 文档:
https://github.com/howmanybots/onebot/blob/master/README.md
"""
__event__ = "" __event__ = ""
time: int time: int
self_id: int self_id: int
post_type: Literal["message", "notice", "request", "meta_event"] post_type: Literal["message", "notice", "request", "meta_event"]
@overrides(Event) @overrides(BaseEvent)
def get_type(self) -> Literal["message", "notice", "request", "meta_event"]: def get_type(self) -> Literal["message", "notice", "request", "meta_event"]:
return self.post_type return self.post_type
@overrides(Event) @overrides(BaseEvent)
def get_event_name(self) -> str: def get_event_name(self) -> str:
return self.post_type return self.post_type
@overrides(Event) @overrides(BaseEvent)
def get_event_description(self) -> str: def get_event_description(self) -> str:
return str(self.dict()) return str(self.dict())
@overrides(Event) @overrides(BaseEvent)
def get_message(self) -> Message: def get_message(self) -> Message:
raise ValueError("Event has no message!") raise ValueError("Event has no message!")
@overrides(Event) @overrides(BaseEvent)
def get_plaintext(self) -> str: def get_plaintext(self) -> str:
raise ValueError("Event has no message!") raise ValueError("Event has no message!")
@overrides(Event) @overrides(BaseEvent)
def get_user_id(self) -> str: def get_user_id(self) -> str:
raise ValueError("Event has no message!") raise ValueError("Event has no message!")
@overrides(Event) @overrides(BaseEvent)
def get_session_id(self) -> str: def get_session_id(self) -> str:
raise ValueError("Event has no message!") raise ValueError("Event has no message!")
@overrides(Event) @overrides(BaseEvent)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return False return False
@ -107,7 +113,8 @@ class Status(BaseModel):
# Message Events # Message Events
class MessageEvent(CQHTTPEvent): class MessageEvent(Event):
"""消息事件"""
__event__ = "message" __event__ = "message"
post_type: Literal["message"] post_type: Literal["message"]
sub_type: str sub_type: str
@ -119,40 +126,51 @@ class MessageEvent(CQHTTPEvent):
font: int font: int
sender: Sender sender: Sender
to_me: bool = False to_me: bool = False
reply: Optional[Reply] = None """
:说明: 消息是否与机器人有关
@overrides(CQHTTPEvent) :类型: ``bool``
"""
reply: Optional[Reply] = None
"""
:说明: 消息中提取的回复消息内容为 ``get_msg`` API 返回结果
:类型: ``Optional[Reply]``
"""
@overrides(Event)
def get_event_name(self) -> str: def get_event_name(self) -> str:
sub_type = getattr(self, "sub_type", None) sub_type = getattr(self, "sub_type", None)
return f"{self.post_type}.{self.message_type}" + (f".{sub_type}" return f"{self.post_type}.{self.message_type}" + (f".{sub_type}"
if sub_type else "") if sub_type else "")
@overrides(CQHTTPEvent) @overrides(Event)
def get_message(self) -> Message: def get_message(self) -> Message:
return self.message return self.message
@overrides(CQHTTPEvent) @overrides(Event)
def get_plaintext(self) -> str: def get_plaintext(self) -> str:
return self.message.extract_plain_text() return self.message.extract_plain_text()
@overrides(CQHTTPEvent) @overrides(Event)
def get_user_id(self) -> str: def get_user_id(self) -> str:
return str(self.user_id) return str(self.user_id)
@overrides(CQHTTPEvent) @overrides(Event)
def get_session_id(self) -> str: def get_session_id(self) -> str:
return str(self.user_id) return str(self.user_id)
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.to_me return self.to_me
class PrivateMessageEvent(MessageEvent): class PrivateMessageEvent(MessageEvent):
"""私聊消息"""
__event__ = "message.private" __event__ = "message.private"
message_type: Literal["private"] message_type: Literal["private"]
@overrides(CQHTTPEvent) @overrides(Event)
def get_event_description(self) -> str: def get_event_description(self) -> str:
return (f'Message {self.message_id} from {self.user_id} "' + "".join( return (f'Message {self.message_id} from {self.user_id} "' + "".join(
map( map(
@ -162,12 +180,13 @@ class PrivateMessageEvent(MessageEvent):
class GroupMessageEvent(MessageEvent): class GroupMessageEvent(MessageEvent):
"""群消息"""
__event__ = "message.group" __event__ = "message.group"
message_type: Literal["group"] message_type: Literal["group"]
group_id: int group_id: int
anonymous: Anonymous anonymous: Anonymous
@overrides(CQHTTPEvent) @overrides(Event)
def get_event_description(self) -> str: def get_event_description(self) -> str:
return ( return (
f'Message {self.message_id} from {self.user_id}@[群:{self.group_id}] "' f'Message {self.message_id} from {self.user_id}@[群:{self.group_id}] "'
@ -179,12 +198,13 @@ class GroupMessageEvent(MessageEvent):
# Notice Events # Notice Events
class NoticeEvent(CQHTTPEvent): class NoticeEvent(Event):
"""通知事件"""
__event__ = "notice" __event__ = "notice"
post_type: Literal["notice"] post_type: Literal["notice"]
notice_type: str notice_type: str
@overrides(CQHTTPEvent) @overrides(Event)
def get_event_name(self) -> str: def get_event_name(self) -> str:
sub_type = getattr(self, "sub_type", None) sub_type = getattr(self, "sub_type", None)
return f"{self.post_type}.{self.notice_type}" + (f".{sub_type}" return f"{self.post_type}.{self.notice_type}" + (f".{sub_type}"
@ -192,6 +212,7 @@ class NoticeEvent(CQHTTPEvent):
class GroupUploadNoticeEvent(NoticeEvent): class GroupUploadNoticeEvent(NoticeEvent):
"""群文件上传事件"""
__event__ = "notice.group_upload" __event__ = "notice.group_upload"
notice_type: Literal["group_upload"] notice_type: Literal["group_upload"]
user_id: int user_id: int
@ -200,18 +221,20 @@ class GroupUploadNoticeEvent(NoticeEvent):
class GroupAdminNoticeEvent(NoticeEvent): class GroupAdminNoticeEvent(NoticeEvent):
"""群管理员变动"""
__event__ = "notice.group_admin" __event__ = "notice.group_admin"
notice_type: Literal["group_admin"] notice_type: Literal["group_admin"]
sub_type: str sub_type: str
user_id: int user_id: int
group_id: int group_id: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.user_id == self.self_id return self.user_id == self.self_id
class GroupDecreaseNoticeEvent(NoticeEvent): class GroupDecreaseNoticeEvent(NoticeEvent):
"""群成员减少事件"""
__event__ = "notice.group_decrease" __event__ = "notice.group_decrease"
notice_type: Literal["group_decrease"] notice_type: Literal["group_decrease"]
sub_type: str sub_type: str
@ -219,12 +242,13 @@ class GroupDecreaseNoticeEvent(NoticeEvent):
group_id: int group_id: int
operator_id: int operator_id: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.user_id == self.self_id return self.user_id == self.self_id
class GroupIncreaseNoticeEvent(NoticeEvent): class GroupIncreaseNoticeEvent(NoticeEvent):
"""群成员增加事件"""
__event__ = "notice.group_increase" __event__ = "notice.group_increase"
notice_type: Literal["group_increase"] notice_type: Literal["group_increase"]
sub_type: str sub_type: str
@ -232,12 +256,13 @@ class GroupIncreaseNoticeEvent(NoticeEvent):
group_id: int group_id: int
operator_id: int operator_id: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.user_id == self.self_id return self.user_id == self.self_id
class GroupBanNoticeEvent(NoticeEvent): class GroupBanNoticeEvent(NoticeEvent):
"""群禁言事件"""
__event__ = "notice.group_ban" __event__ = "notice.group_ban"
notice_type: Literal["group_ban"] notice_type: Literal["group_ban"]
sub_type: str sub_type: str
@ -246,18 +271,20 @@ class GroupBanNoticeEvent(NoticeEvent):
operator_id: int operator_id: int
duration: int duration: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.user_id == self.self_id return self.user_id == self.self_id
class FriendAddNoticeEvent(NoticeEvent): class FriendAddNoticeEvent(NoticeEvent):
"""好友添加事件"""
__event__ = "notice.friend_add" __event__ = "notice.friend_add"
notice_type: Literal["friend_add"] notice_type: Literal["friend_add"]
user_id: int user_id: int
class GroupRecallNoticeEvent(NoticeEvent): class GroupRecallNoticeEvent(NoticeEvent):
"""群消息撤回事件"""
__event__ = "notice.group_recall" __event__ = "notice.group_recall"
notice_type: Literal["group_recall"] notice_type: Literal["group_recall"]
user_id: int user_id: int
@ -265,12 +292,13 @@ class GroupRecallNoticeEvent(NoticeEvent):
operator_id: int operator_id: int
message_id: int message_id: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.user_id == self.self_id return self.user_id == self.self_id
class FriendRecallNoticeEvent(NoticeEvent): class FriendRecallNoticeEvent(NoticeEvent):
"""好友消息撤回事件"""
__event__ = "notice.friend_recall" __event__ = "notice.friend_recall"
notice_type: Literal["friend_recall"] notice_type: Literal["friend_recall"]
user_id: int user_id: int
@ -278,6 +306,7 @@ class FriendRecallNoticeEvent(NoticeEvent):
class NotifyEvent(NoticeEvent): class NotifyEvent(NoticeEvent):
"""提醒事件"""
__event__ = "notice.notify" __event__ = "notice.notify"
notice_type: Literal["notify"] notice_type: Literal["notify"]
sub_type: str sub_type: str
@ -286,42 +315,46 @@ class NotifyEvent(NoticeEvent):
class PokeNotifyEvent(NotifyEvent): class PokeNotifyEvent(NotifyEvent):
"""戳一戳提醒事件"""
__event__ = "notice.notify.poke" __event__ = "notice.notify.poke"
sub_type: Literal["poke"] sub_type: Literal["poke"]
target_id: int target_id: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.target_id == self.self_id return self.target_id == self.self_id
class LuckyKingNotifyEvent(NotifyEvent): class LuckyKingNotifyEvent(NotifyEvent):
"""群红包运气王提醒事件"""
__event__ = "notice.notify.lucky_king" __event__ = "notice.notify.lucky_king"
sub_type: Literal["lucky_king"] sub_type: Literal["lucky_king"]
target_id: int target_id: int
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.target_id == self.self_id return self.target_id == self.self_id
class HonorNotifyEvent(NotifyEvent): class HonorNotifyEvent(NotifyEvent):
"""群荣誉变更提醒事件"""
__event__ = "notice.notify.honor" __event__ = "notice.notify.honor"
sub_type: Literal["honor"] sub_type: Literal["honor"]
honor_type: str honor_type: str
@overrides(CQHTTPEvent) @overrides(Event)
def is_tome(self) -> bool: def is_tome(self) -> bool:
return self.user_id == self.self_id return self.user_id == self.self_id
# Request Events # Request Events
class RequestEvent(CQHTTPEvent): class RequestEvent(Event):
"""请求事件"""
__event__ = "request" __event__ = "request"
post_type: Literal["request"] post_type: Literal["request"]
request_type: str request_type: str
@overrides(CQHTTPEvent) @overrides(Event)
def get_event_name(self) -> str: def get_event_name(self) -> str:
sub_type = getattr(self, "sub_type", None) sub_type = getattr(self, "sub_type", None)
return f"{self.post_type}.{self.request_type}" + (f".{sub_type}" return f"{self.post_type}.{self.request_type}" + (f".{sub_type}"
@ -329,6 +362,7 @@ class RequestEvent(CQHTTPEvent):
class FriendRequestEvent(RequestEvent): class FriendRequestEvent(RequestEvent):
"""加好友请求事件"""
__event__ = "request.friend" __event__ = "request.friend"
request_type: Literal["friend"] request_type: Literal["friend"]
user_id: int user_id: int
@ -337,6 +371,7 @@ class FriendRequestEvent(RequestEvent):
class GroupRequestEvent(RequestEvent): class GroupRequestEvent(RequestEvent):
"""加群请求/邀请事件"""
__event__ = "request.group" __event__ = "request.group"
request_type: Literal["group"] request_type: Literal["group"]
sub_type: str sub_type: str
@ -347,29 +382,32 @@ class GroupRequestEvent(RequestEvent):
# Meta Events # Meta Events
class MetaEvent(CQHTTPEvent): class MetaEvent(Event):
"""元事件"""
__event__ = "meta_event" __event__ = "meta_event"
post_type: Literal["meta_event"] post_type: Literal["meta_event"]
meta_event_type: str meta_event_type: str
@overrides(CQHTTPEvent) @overrides(Event)
def get_event_name(self) -> str: def get_event_name(self) -> str:
sub_type = getattr(self, "sub_type", None) sub_type = getattr(self, "sub_type", None)
return f"{self.post_type}.{self.meta_event_type}" + (f".{sub_type}" if return f"{self.post_type}.{self.meta_event_type}" + (f".{sub_type}" if
sub_type else "") sub_type else "")
@overrides(CQHTTPEvent) @overrides(Event)
def get_log_string(self) -> str: def get_log_string(self) -> str:
raise NoLogException raise NoLogException
class LifecycleMetaEvent(MetaEvent): class LifecycleMetaEvent(MetaEvent):
"""生命周期元事件"""
__event__ = "meta_event.lifecycle" __event__ = "meta_event.lifecycle"
meta_event_type: Literal["lifecycle"] meta_event_type: Literal["lifecycle"]
sub_type: str sub_type: str
class HeartbeatMetaEvent(MetaEvent): class HeartbeatMetaEvent(MetaEvent):
"""心跳元事件"""
__event__ = "meta_event.heartbeat" __event__ = "meta_event.heartbeat"
meta_event_type: Literal["heartbeat"] meta_event_type: Literal["heartbeat"]
status: Status status: Status
@ -378,12 +416,34 @@ class HeartbeatMetaEvent(MetaEvent):
_t = StringTrie(separator=".") _t = StringTrie(separator=".")
# define `model` first to avoid globals changing while `for`
model = None model = None
for model in globals().values(): for model in globals().values():
if not inspect.isclass(model) or not issubclass(model, CQHTTPEvent): if not inspect.isclass(model) or not issubclass(model, Event):
continue continue
_t["." + model.__event__] = model _t["." + model.__event__] = model
def get_event_model(event_name) -> List[Type[CQHTTPEvent]]: def get_event_model(event_name) -> List[Type[Event]]:
"""
:说明:
根据事件名获取对应 ``Event Model`` ``FallBack Event Model`` 列表
:返回:
- ``List[Type[Event]]``
"""
return [model.value for model in _t.prefixes("." + event_name)][::-1] return [model.value for model in _t.prefixes("." + event_name)][::-1]
__all__ = [
"Event", "MessageEvent", "PrivateMessageEvent", "GroupMessageEvent",
"NoticeEvent", "GroupUploadNoticeEvent", "GroupAdminNoticeEvent",
"GroupDecreaseNoticeEvent", "GroupIncreaseNoticeEvent",
"GroupBanNoticeEvent", "FriendAddNoticeEvent", "GroupRecallNoticeEvent",
"FriendRecallNoticeEvent", "NotifyEvent", "PokeNotifyEvent",
"LuckyKingNotifyEvent", "HonorNotifyEvent", "RequestEvent",
"FriendRequestEvent", "GroupRequestEvent", "MetaEvent",
"LifecycleMetaEvent", "HeartbeatMetaEvent", "get_event_model"
]