mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-10-30 22:46:40 +00:00 
			
		
		
		
	✨ implement event parser
This commit is contained in:
		| @@ -9,7 +9,7 @@ from nonebot.adapters import Bot as BaseBot | ||||
| from nonebot.drivers import Driver, HTTPRequest, HTTPResponse | ||||
|  | ||||
| from .config import Config as FeishuConfig | ||||
| from .event import Event | ||||
| from .event import Event, get_event_model | ||||
| from .message import Message, MessageSegment | ||||
| from .utils import log, AESCipher | ||||
|  | ||||
| @@ -17,6 +17,48 @@ if TYPE_CHECKING: | ||||
|     from nonebot.config import Config | ||||
|  | ||||
|  | ||||
| async def _check_reply(bot: "Bot", event: "Event"): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       检查消息中存在的回复,去除并赋值 ``event.reply``, ``event.to_me`` | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``bot: Bot``: Bot 对象 | ||||
|       * ``event: Event``: Event 对象 | ||||
|     """ | ||||
|     ... | ||||
|  | ||||
|  | ||||
| def _check_at_me(bot: "Bot", event: "Event"): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       检查消息开头或结尾是否存在 @机器人,去除并赋值 ``event.to_me`` | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``bot: Bot``: Bot 对象 | ||||
|       * ``event: Event``: Event 对象 | ||||
|     """ | ||||
|     ... | ||||
|  | ||||
|  | ||||
| def _check_nickname(bot: "Bot", event: "Event"): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       检查消息开头是否存在,去除并赋值 ``event.to_me`` | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``bot: Bot``: Bot 对象 | ||||
|       * ``event: Event``: Event 对象 | ||||
|     """ | ||||
|     ... | ||||
|  | ||||
|  | ||||
| class Bot(BaseBot): | ||||
|     """ | ||||
|     飞书 协议 Bot 适配。继承属性参考 `BaseBot <./#class-basebot>`_ 。 | ||||
| @@ -52,7 +94,7 @@ class Bot(BaseBot): | ||||
|  | ||||
|         challenge = data.get("challenge") | ||||
|         if challenge: | ||||
|             return None, HTTPResponse( | ||||
|             return data.get("token"), HTTPResponse( | ||||
|                 200, | ||||
|                 json.dumps({ | ||||
|                     "challenge": challenge | ||||
| @@ -85,8 +127,22 @@ class Bot(BaseBot): | ||||
|           处理事件并转换为 `Event <#class-event>`_ | ||||
|         """ | ||||
|         data = json.loads(message) | ||||
|         print(data) | ||||
|         if data.get("type") == "url_verification": | ||||
|             return | ||||
|  | ||||
|         try: | ||||
|             event = Event.parse_obj(message) | ||||
|             header = data["header"] | ||||
|             event_type = header["event_type"] | ||||
|             models = get_event_model(event_type) | ||||
|             for model in models: | ||||
|                 try: | ||||
|                     event = model.parse_obj(data) | ||||
|                     break | ||||
|                 except Exception as e: | ||||
|                     log("DEBUG", "Event Parser Error", e) | ||||
|             else: | ||||
|                 event = Event.parse_obj(data) | ||||
|             await handle_event(self, event) | ||||
|         except Exception as e: | ||||
|             logger.opt(colors=True, exception=e).error( | ||||
|   | ||||
| @@ -1,5 +1,10 @@ | ||||
| from typing import List, Literal | ||||
| from pydantic import BaseModel, root_validator | ||||
| import inspect | ||||
| import json | ||||
| from nonebot import message | ||||
|  | ||||
| from typing import Any, List, Literal, Optional, Type, Union | ||||
| from pygtrie import StringTrie | ||||
| from pydantic import BaseModel, root_validator, Field | ||||
|  | ||||
| from nonebot.adapters import Event as BaseEvent | ||||
| from nonebot.typing import overrides | ||||
| @@ -7,6 +12,15 @@ from nonebot.typing import overrides | ||||
| from .message import Message, MessageSegment | ||||
|  | ||||
|  | ||||
| class EventHeader(BaseModel): | ||||
|     event_id: str | ||||
|     event_type: str | ||||
|     create_time: str | ||||
|     token: str | ||||
|     app_id: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class Event(BaseEvent): | ||||
|     """ | ||||
|     飞书协议事件。各事件字段参考 `飞书文档`_ | ||||
| @@ -14,16 +28,18 @@ class Event(BaseEvent): | ||||
|     .. _飞书事件列表文档: | ||||
|         https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-list | ||||
|     """ | ||||
|     app_id: int | ||||
|     event_type: str | ||||
|     __event__ = "" | ||||
|     schema_: str = Field("", alias='schema') | ||||
|     header: EventHeader | ||||
|     event: Any | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_type(self) -> str: | ||||
|         return self.event_type | ||||
|         return self.header.event_type | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_name(self) -> str: | ||||
|         return self.event_type | ||||
|         return self.header.event_type | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_description(self) -> str: | ||||
| @@ -69,39 +85,31 @@ class Mention(BaseModel): | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class MessageBody(BaseModel): | ||||
| class EventMessage(BaseModel): | ||||
|     message_id: str | ||||
|     root_id: str | ||||
|     parent_id: str | ||||
|     root_id: Optional[str] | ||||
|     parent_id: Optional[str] | ||||
|     create_time: str | ||||
|     chat_id: str | ||||
|     chat_type: str | ||||
|     message_type: str | ||||
|     content: Message | ||||
|     mentions: List[Mention] | ||||
|  | ||||
|     plaintext: str | ||||
|     mentions: Optional[List[Mention]] | ||||
|  | ||||
|     @root_validator(pre=True) | ||||
|     def gen_message(cls, values: dict): | ||||
|         content = [] | ||||
|         for piece in values["content"]: | ||||
|             for segment in piece: | ||||
|                 content.append( | ||||
|                     MessageSegment(segment["tag"], segment.pop('name', segment))) | ||||
|  | ||||
|         values["content"] = Message(content) | ||||
|     def parse_message(cls, values: dict): | ||||
|         values["content"] = json.loads(values["content"]) | ||||
|         return values | ||||
|  | ||||
|     @root_validator | ||||
|     def gen_plaintext(cls, values: dict): | ||||
|         values["plaintext"] = str(values["content"]) | ||||
|         return values | ||||
|  | ||||
| class MessageEventDetail(BaseModel): | ||||
|     sender: Sender | ||||
|     message: EventMessage | ||||
|  | ||||
|  | ||||
| class MessageEvent(Event): | ||||
|     sender: Sender | ||||
|     message: MessageBody | ||||
|     __event__ = "im.message.receive_v1" | ||||
|     event: MessageEventDetail | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_type(self) -> Literal["message", "notice", "meta_event"]: | ||||
| @@ -115,32 +123,40 @@ class MessageEvent(Event): | ||||
|     def get_event_description(self) -> str: | ||||
|         return ( | ||||
|             f"Message[{super().get_type()}]" | ||||
|             f" {self.message.message_id} from {self.sender.sender_id.user_id}" | ||||
|             f" {self.message.content}") | ||||
|             f" {self.event.message.message_id} from {self.event.sender.sender_id.user_id}" | ||||
|             f" {self.event.message.content}") | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_message(self) -> Message: | ||||
|         return self.message.content | ||||
|         return self.event.message.content | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_plaintext(self) -> str: | ||||
|         return self.message.plaintext | ||||
|         return str(self.event.message.content) | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_user_id(self) -> str: | ||||
|         return self.sender.sender_id.user_id | ||||
|         return self.event.sender.sender_id.user_id | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_session_id(self) -> str: | ||||
|         return self.sender.sender_id.user_id | ||||
|         return self.event.sender.sender_id.user_id | ||||
|  | ||||
|  | ||||
| class PrivateMessageEvent(MessageEvent): | ||||
|     ... | ||||
| class MessageReader(BaseModel): | ||||
|     reader_id: UserId | ||||
|     read_time: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class GroupMessageEvent(MessageEvent): | ||||
|     ... | ||||
| class MessageReadEventDetail(BaseModel): | ||||
|     reader: MessageReader | ||||
|     message_id_list: List[str] | ||||
|  | ||||
|  | ||||
| class MessageReadEvent(Event): | ||||
|     __event__ = "im.message.message_read_v1" | ||||
|     event: MessageReadEventDetail | ||||
|  | ||||
|  | ||||
| class NoticeEvent(Event): | ||||
| @@ -149,3 +165,26 @@ class NoticeEvent(Event): | ||||
|  | ||||
| class MetaEvent(Event): | ||||
|     ... | ||||
|  | ||||
|  | ||||
| _t = StringTrie(separator=".") | ||||
|  | ||||
| # define `model` first to avoid globals changing while `for` | ||||
| model = None | ||||
| for model in globals().values(): | ||||
|     if not inspect.isclass(model) or not issubclass(model, Event): | ||||
|         continue | ||||
|     _t["." + model.__event__] = model | ||||
|  | ||||
|  | ||||
| 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] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user