From 72653c61164eca40d9a9a18271fe5dd96f14a4bd Mon Sep 17 00:00:00 2001 From: yanyongyu Date: Thu, 10 Dec 2020 02:13:25 +0800 Subject: [PATCH] :construction: update messages --- nonebot/adapters/__init__.py | 203 +++++------------------------ nonebot/adapters/cqhttp/event.py | 52 +++++++- nonebot/adapters/cqhttp/message.py | 6 +- nonebot/permission.py | 16 ++- nonebot/plugins/base.py | 13 +- nonebot/rule.py | 26 ++-- 6 files changed, 112 insertions(+), 204 deletions(-) diff --git a/nonebot/adapters/__init__.py b/nonebot/adapters/__init__.py index 01745c28..15c428e8 100644 --- a/nonebot/adapters/__init__.py +++ b/nonebot/adapters/__init__.py @@ -158,6 +158,10 @@ class Event(abc.ABC, BaseModel): def get_log_string(self) -> str: return f"[{self.get_event_name()}]: {self.get_event_description()}" + @abc.abstractmethod + def get_user_id(self) -> str: + raise NotImplementedError + @abc.abstractmethod def get_session_id(self) -> str: raise NotImplementedError @@ -170,169 +174,9 @@ class Event(abc.ABC, BaseModel): def get_plaintext(self) -> str: raise NotImplementedError - -# T = TypeVar("T", bound=BaseModel) - -# class Event(abc.ABC, Generic[T]): -# """ -# Event 基类。提供上报信息的关键信息,其余信息可从原始上报消息获取。 -# """ - -# def __init__(self, raw_event: Union[dict, T]): -# """ -# :参数: - -# * ``raw_event: Union[dict, T]``: 原始上报消息 -# """ -# self._raw_event = raw_event - -# def __repr__(self) -> str: -# return f"" - -# @property -# def raw_event(self) -> Union[dict, T]: -# """原始上报消息""" -# return self._raw_event - -# @property -# @abc.abstractmethod -# def id(self) -> int: -# """事件 ID""" -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def name(self) -> str: -# """事件名称""" -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def self_id(self) -> str: -# """机器人 ID""" -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def time(self) -> int: -# """事件发生时间""" -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def type(self) -> str: -# """事件主类型""" -# raise NotImplementedError - -# @type.setter -# @abc.abstractmethod -# def type(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def detail_type(self) -> str: -# """事件详细类型""" -# raise NotImplementedError - -# @detail_type.setter -# @abc.abstractmethod -# def detail_type(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def sub_type(self) -> Optional[str]: -# """事件子类型""" -# raise NotImplementedError - -# @sub_type.setter -# @abc.abstractmethod -# def sub_type(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def user_id(self) -> Optional[int]: -# """触发事件的主体 ID""" -# raise NotImplementedError - -# @user_id.setter -# @abc.abstractmethod -# def user_id(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def group_id(self) -> Optional[int]: -# """触发事件的主体群 ID""" -# raise NotImplementedError - -# @group_id.setter -# @abc.abstractmethod -# def group_id(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def to_me(self) -> Optional[bool]: -# """事件是否为发送给机器人的消息""" -# raise NotImplementedError - -# @to_me.setter -# @abc.abstractmethod -# def to_me(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def message(self) -> Optional["Message"]: -# """消息内容""" -# raise NotImplementedError - -# @message.setter -# @abc.abstractmethod -# def message(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def reply(self) -> Optional[dict]: -# """回复的消息""" -# raise NotImplementedError - -# @reply.setter -# @abc.abstractmethod -# def reply(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def raw_message(self) -> Optional[str]: -# """原始消息""" -# raise NotImplementedError - -# @raw_message.setter -# @abc.abstractmethod -# def raw_message(self, value) -> None: -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def plain_text(self) -> Optional[str]: -# """纯文本消息""" -# raise NotImplementedError - -# @property -# @abc.abstractmethod -# def sender(self) -> Optional[dict]: -# """消息发送者信息""" -# raise NotImplementedError - -# @sender.setter -# @abc.abstractmethod -# def sender(self, value) -> None: -# raise NotImplementedError + @abc.abstractmethod + def is_tome(self) -> bool: + raise NotImplementedError @dataclass @@ -350,12 +194,12 @@ class MessageSegment(abc.ABC): """ @abc.abstractmethod - def __str__(self): + def __str__(self) -> str: """该消息段所代表的 str,在命令匹配部分使用""" raise NotImplementedError @abc.abstractmethod - def __add__(self, other): + def __add__(self, other) -> "Message": """你需要在这里实现不同消息段的合并: 比如: if isinstance(other, str): @@ -375,10 +219,9 @@ class MessageSegment(abc.ABC): def get(self, key, default=None): return getattr(self, key, default) - @classmethod @abc.abstractmethod - def text(cls, text: str) -> "MessageSegment": - return cls("text", {"text": text}) + def is_text(self) -> bool: + raise NotImplementedError class Message(list, abc.ABC): @@ -405,6 +248,24 @@ class Message(list, abc.ABC): def __str__(self): return ''.join((str(seg) for seg in self)) + @classmethod + def __get_validator__(cls): + yield cls._validate + + @classmethod + def __modify_schema__(cls, field_schema): + field_schema.update( + examples=["foo", { + "type": "text", + "data": { + "text": "bar" + } + }]) + + @classmethod + def _validate(cls, value): + return cls(value) + @staticmethod @abc.abstractmethod def _construct( @@ -467,8 +328,8 @@ class Message(list, abc.ABC): """ index = 0 while index < len(self): - if index > 0 and self[ - index - 1].type == "text" and self[index].type == "text": + if index > 0 and self[index - + 1].is_text() and self[index].is_text(): self[index - 1] += self[index] del self[index] else: @@ -482,7 +343,7 @@ class Message(list, abc.ABC): """ def _concat(x: str, y: MessageSegment) -> str: - return f"{x} {y}" if y.type == "text" else x + return f"{x} {y}" if y.is_text() else x plain_text = reduce(_concat, self, "") return plain_text[1:] if plain_text else plain_text diff --git a/nonebot/adapters/cqhttp/event.py b/nonebot/adapters/cqhttp/event.py index 0d28101b..285c12a6 100644 --- a/nonebot/adapters/cqhttp/event.py +++ b/nonebot/adapters/cqhttp/event.py @@ -237,10 +237,18 @@ class CQHTTPEvent(Event): def get_plaintext(self) -> str: raise ValueError("Event has no message!") + @overrides(Event) + def get_user_id(self) -> str: + raise ValueError("Event has no message!") + @overrides(Event) def get_session_id(self) -> str: raise ValueError("Event has no message!") + @overrides(Event) + def is_tome(self) -> bool: + return False + # Models class Sender(BaseModel): @@ -326,10 +334,18 @@ class MessageEvent(CQHTTPEvent): def get_plaintext(self) -> str: return self.message.extract_plain_text() + @overrides(CQHTTPEvent) + def get_user_id(self) -> str: + return str(self.user_id) + @overrides(CQHTTPEvent) def get_session_id(self) -> str: return str(self.user_id) + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.to_me + class PrivateMessageEvent(MessageEvent): __event__ = "message.private" @@ -340,7 +356,7 @@ class PrivateMessageEvent(MessageEvent): return (f'Message {self.message_id} from {self.user_id} "' + "".join( map( lambda x: escape_tag(str(x)) - if x.type == "text" else f"{escape_tag(str(x))}", + if x.is_text() else f"{escape_tag(str(x))}", self.message)) + '"') @@ -357,7 +373,7 @@ class GroupMessageEvent(MessageEvent): + "".join( map( lambda x: escape_tag(str(x)) - if x.type == "text" else f"{escape_tag(str(x))}", + if x.is_text() else f"{escape_tag(str(x))}", self.message)) + '"') @@ -389,6 +405,10 @@ class GroupAdminNoticeEvent(NoticeEvent): user_id: int group_id: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.user_id == self.self_id + class GroupDecreaseNoticeEvent(NoticeEvent): __event__ = "notice.group_decrease" @@ -398,6 +418,10 @@ class GroupDecreaseNoticeEvent(NoticeEvent): group_id: int operator_id: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.user_id == self.self_id + class GroupIncreaseNoticeEvent(NoticeEvent): __event__ = "notice.group_increase" @@ -407,6 +431,10 @@ class GroupIncreaseNoticeEvent(NoticeEvent): group_id: int operator_id: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.user_id == self.self_id + class GroupBanNoticeEvent(NoticeEvent): __event__ = "notice.group_ban" @@ -417,6 +445,10 @@ class GroupBanNoticeEvent(NoticeEvent): operator_id: int duration: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.user_id == self.self_id + class FriendAddNoticeEvent(NoticeEvent): __event__ = "notice.friend_add" @@ -432,6 +464,10 @@ class GroupRecallNoticeEvent(NoticeEvent): operator_id: int message_id: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.user_id == self.self_id + class FriendRecallNoticeEvent(NoticeEvent): __event__ = "notice.friend_recall" @@ -453,18 +489,30 @@ class PokeNotifyEvent(NotifyEvent): sub_type: Literal["poke"] target_id: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.target_id == self.self_id + class LuckyKingNotifyEvent(NotifyEvent): __event__ = "notice.notify.lucky_king" sub_type: Literal["lucky_king"] target_id: int + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.target_id == self.self_id + class HonorNotifyEvent(NotifyEvent): __event__ = "notice.notify.honor" sub_type: Literal["honor"] honor_type: str + @overrides(CQHTTPEvent) + def is_tome(self) -> bool: + return self.user_id == self.self_id + # Request Events class RequestEvent(CQHTTPEvent): diff --git a/nonebot/adapters/cqhttp/message.py b/nonebot/adapters/cqhttp/message.py index dffd4e4e..49a9c858 100644 --- a/nonebot/adapters/cqhttp/message.py +++ b/nonebot/adapters/cqhttp/message.py @@ -19,7 +19,7 @@ class MessageSegment(BaseMessageSegment): super().__init__(type=type, data=data) @overrides(BaseMessageSegment) - def __str__(self): + def __str__(self) -> str: type_ = self.type data = self.data.copy() @@ -37,6 +37,10 @@ class MessageSegment(BaseMessageSegment): def __add__(self, other) -> "Message": return Message(self) + other + @overrides(BaseMessageSegment) + def is_text(self) -> bool: + return self.type == "text" + @staticmethod def anonymous(ignore_failure: Optional[bool] = None) -> "MessageSegment": return MessageSegment("anonymous", {"ignore": _b2s(ignore_failure)}) diff --git a/nonebot/permission.py b/nonebot/permission.py index 6f2ccd20..b5812186 100644 --- a/nonebot/permission.py +++ b/nonebot/permission.py @@ -201,14 +201,16 @@ def USER(*user: str, perm: Permission = Permission()): # - **说明**: 匹配任意群主群聊消息类型事件 # """ -# async def _superuser(bot: "Bot", event: "Event") -> bool: -# return event.get_type( -# ) == "message" and event.user_id in bot.config.superusers -# SUPERUSER = Permission(_superuser) -# """ -# - **说明**: 匹配任意超级用户消息类型事件 -# """ +async def _superuser(bot: "Bot", event: "Event") -> bool: + return event.get_type() == "message" and event.get_user_id( + ) in bot.config.superusers + + +SUPERUSER = Permission(_superuser) +""" +- **说明**: 匹配任意超级用户消息类型事件 +""" # EVERYBODY = MESSAGE # """ # - **说明**: 匹配任意消息类型事件 diff --git a/nonebot/plugins/base.py b/nonebot/plugins/base.py index 1513dbde..6698f4b0 100644 --- a/nonebot/plugins/base.py +++ b/nonebot/plugins/base.py @@ -11,14 +11,14 @@ say = on_command("say", to_me(), permission=SUPERUSER) @say.handle() async def say_unescape(bot: Bot, event: Event, state: State): - Message = event.message.__class__ + Message = event.get_message().__class__ def _unescape(message: Message, segment: MessageSegment): - if segment.type == "text": + if segment.is_text(): return message.append(str(segment)) return message.append(segment) - message = reduce(_unescape, event.message, Message()) # type: ignore + message = reduce(_unescape, event.get_message(), Message()) # type: ignore await bot.send(message=message, event=event) @@ -27,9 +27,4 @@ echo = on_command("echo", to_me()) @echo.handle() async def echo_escape(bot: Bot, event: Event, state: State): - # Message = event.message.__class__ - # MessageSegment = event.message[0].__class__ - - # message = Message().append( # type: ignore - # MessageSegment.text(str(event.message))) - await bot.send(message=event.message, event=event) + await bot.send(message=event.get_message(), event=event) diff --git a/nonebot/rule.py b/nonebot/rule.py index 31902603..d2c28ffe 100644 --- a/nonebot/rule.py +++ b/nonebot/rule.py @@ -134,10 +134,10 @@ class TrieRule: suffix = None message = event.get_message() message_seg = message[0] - if message_seg.type == "text": + if message_seg.is_text(): prefix = cls.prefix.longest_prefix(str(message_seg).lstrip()) message_seg_r = message[-1] - if message_seg_r.type == "text": + if message_seg_r.is_text(): suffix = cls.suffix.longest_prefix( str(message_seg_r).rstrip()[::-1]) @@ -309,20 +309,18 @@ def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule: return Rule(_regex) -# def to_me() -> Rule: -# """ -# :说明: +def to_me() -> Rule: + """ + :说明: -# 通过 ``event.to_me`` 判断消息是否是发送给机器人 + 通过 ``event.to_me`` 判断事件是否与机器人有关 -# :参数: + :参数: -# * 无 -# """ + * 无 + """ -# async def _to_me(bot: "Bot", event: "Event", state: State) -> bool: -# if event.get_type() != "message": -# return False -# return bool(event.to_me) + async def _to_me(bot: "Bot", event: "Event", state: State) -> bool: + return event.is_tome() -# return Rule(_to_me) + return Rule(_to_me)