🚧 add event parser

This commit is contained in:
yanyongyu
2020-12-09 19:57:49 +08:00
parent 2c97902f4e
commit 783efeaf0e
7 changed files with 202 additions and 118 deletions

View File

@ -6,10 +6,10 @@
"""
import abc
from typing_extensions import Literal
from functools import reduce, partial
from dataclasses import dataclass, field
from typing import Any, Dict, Union, TypeVar, Optional, Callable, Iterable, Awaitable, Generic, TYPE_CHECKING
from typing_extensions import Literal
from typing import Any, Dict, Union, Optional, Callable, Iterable, Awaitable, TYPE_CHECKING
from pydantic import BaseModel
@ -162,6 +162,14 @@ class Event(abc.ABC, BaseModel):
def get_session_id(self) -> str:
raise NotImplementedError
@abc.abstractmethod
def get_message(self) -> "Message":
raise NotImplementedError
@abc.abstractmethod
def get_plaintext(self) -> str:
raise NotImplementedError
# T = TypeVar("T", bound=BaseModel)

View File

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

View File

@ -15,9 +15,9 @@ from nonebot.adapters import Bot as BaseBot
from nonebot.exception import RequestDenied
from .utils import log
from .event import Reply, CQHTTPEvent, MessageEvent
from .message import Message, MessageSegment
from .exception import NetworkError, ApiNotAvailable, ActionFailed
from .event import Reply, CQHTTPEvent, MessageEvent, get_event_model
if TYPE_CHECKING:
from nonebot.drivers import Driver, WebSocket
@ -297,7 +297,20 @@ class Bot(BaseBot):
return
try:
event = CQHTTPEvent.parse_obj(message)
post_type = message['post_type']
detail_type = message.get(f"{post_type}_type")
detail_type = f".{detail_type}" if detail_type else ""
sub_type = message.get("sub_type")
sub_type = f".{sub_type}" if sub_type else ""
models = get_event_model(f".{post_type}{detail_type}{sub_type}")
for model in models:
try:
event = model.parse_obj(message)
break
except Exception as e:
log("DEBUG", "Event Parser Error", e)
else:
event = CQHTTPEvent.parse_obj(message)
# Check whether user is calling me
await _check_reply(self, event)

View File

@ -1,7 +1,9 @@
from typing import Optional
import inspect
from typing_extensions import Literal
from typing import Type, List, Optional
from pydantic import BaseModel
from pygtrie import StringTrie
from nonebot.adapters import Event
from nonebot.utils import escape_tag
from nonebot.typing import overrides
@ -210,6 +212,7 @@ from .message import Message
class CQHTTPEvent(Event):
__event__ = ""
time: int
self_id: int
post_type: Literal["message", "notice", "request", "meta_event"]
@ -226,6 +229,14 @@ class CQHTTPEvent(Event):
def get_event_description(self) -> str:
return str(self.dict())
@overrides(Event)
def get_message(self) -> Message:
raise ValueError("Event has no message!")
@overrides(Event)
def get_plaintext(self) -> str:
raise ValueError("Event has no message!")
# Models
class Sender(BaseModel):
@ -284,6 +295,7 @@ class Status(BaseModel):
# Message Events
class MessageEvent(CQHTTPEvent):
__event__ = "message"
post_type: Literal["message"]
sub_type: str
user_id: int
@ -302,8 +314,17 @@ class MessageEvent(CQHTTPEvent):
return f"{self.post_type}.{self.message_type}" + (f".{sub_type}"
if sub_type else "")
@overrides(CQHTTPEvent)
def get_message(self) -> Message:
return self.message
@overrides(CQHTTPEvent)
def get_plaintext(self) -> str:
return self.message.extract_plain_text()
class PrivateMessageEvent(MessageEvent):
__event__ = "message.private"
message_type: Literal["private"]
@overrides(CQHTTPEvent)
@ -316,6 +337,7 @@ class PrivateMessageEvent(MessageEvent):
class GroupMessageEvent(MessageEvent):
__event__ = "message.group"
message_type: Literal["group"]
group_id: int
anonymous: Anonymous
@ -333,6 +355,7 @@ class GroupMessageEvent(MessageEvent):
# Notice Events
class NoticeEvent(CQHTTPEvent):
__event__ = "notice"
post_type: Literal["notice"]
notice_type: str
@ -344,6 +367,7 @@ class NoticeEvent(CQHTTPEvent):
class GroupUploadNoticeEvent(NoticeEvent):
__event__ = "notice.group_upload"
notice_type: Literal["group_upload"]
user_id: int
group_id: int
@ -351,6 +375,7 @@ class GroupUploadNoticeEvent(NoticeEvent):
class GroupAdminNoticeEvent(NoticeEvent):
__event__ = "notice.group_admin"
notice_type: Literal["group_admin"]
sub_type: str
user_id: int
@ -358,6 +383,7 @@ class GroupAdminNoticeEvent(NoticeEvent):
class GroupDecreaseNoticeEvent(NoticeEvent):
__event__ = "notice.group_decrease"
notice_type: Literal["group_decrease"]
sub_type: str
user_id: int
@ -366,6 +392,7 @@ class GroupDecreaseNoticeEvent(NoticeEvent):
class GroupIncreaseNoticeEvent(NoticeEvent):
__event__ = "notice.group_increase"
notice_type: Literal["group_increase"]
sub_type: str
user_id: int
@ -374,6 +401,7 @@ class GroupIncreaseNoticeEvent(NoticeEvent):
class GroupBanNoticeEvent(NoticeEvent):
__event__ = "notice.group_ban"
notice_type: Literal["group_ban"]
sub_type: str
user_id: int
@ -383,11 +411,13 @@ class GroupBanNoticeEvent(NoticeEvent):
class FriendAddNoticeEvent(NoticeEvent):
__event__ = "notice.friend_add"
notice_type: Literal["friend_add"]
user_id: int
class GroupRecallNoticeEvent(NoticeEvent):
__event__ = "notice.group_recall"
notice_type: Literal["group_recall"]
user_id: int
group_id: int
@ -396,12 +426,14 @@ class GroupRecallNoticeEvent(NoticeEvent):
class FriendRecallNoticeEvent(NoticeEvent):
__event__ = "notice.friend_recall"
notice_type: Literal["friend_recall"]
user_id: int
message_id: int
class NotifyEvent(NoticeEvent):
__event__ = "notice.notify"
notice_type: Literal["notify"]
sub_type: str
user_id: int
@ -409,19 +441,26 @@ class NotifyEvent(NoticeEvent):
class PokeNotifyEvent(NotifyEvent):
__event__ = "notice.notify.poke"
sub_type: Literal["poke"]
target_id: int
class LuckyKingNotifyEvent(NotifyEvent):
__event__ = "notice.notify.lucky_king"
sub_type: Literal["lucky_king"]
target_id: int
class HonorNotifyEvent(NotifyEvent):
__event__ = "notice.notify.honor"
sub_type: Literal["honor"]
honor_type: str
# Request Events
class RequestEvent(CQHTTPEvent):
__event__ = "request"
post_type: Literal["request"]
request_type: str
@ -433,6 +472,7 @@ class RequestEvent(CQHTTPEvent):
class FriendRequestEvent(RequestEvent):
__event__ = "request.friend"
request_type: Literal["friend"]
user_id: int
comment: str
@ -440,6 +480,7 @@ class FriendRequestEvent(RequestEvent):
class GroupRequestEvent(RequestEvent):
__event__ = "request.group"
request_type: Literal["group"]
sub_type: str
group_id: int
@ -450,6 +491,7 @@ class GroupRequestEvent(RequestEvent):
# Meta Events
class MetaEvent(CQHTTPEvent):
__event__ = "meta_event"
post_type: Literal["meta_event"]
meta_event_type: str
@ -465,11 +507,26 @@ class MetaEvent(CQHTTPEvent):
class LifecycleMetaEvent(MetaEvent):
__event__ = "meta_event.lifecycle"
meta_event_type: Literal["lifecycle"]
sub_type: str
class HeartbeatMetaEvent(MetaEvent):
__event__ = "meta_event.heartbeat"
meta_event_type: Literal["heartbeat"]
status: Status
interval: int
_t = StringTrie(separator=".")
model = None
for model in globals().values():
if not inspect.isclass(model) or not issubclass(model, CQHTTPEvent):
continue
_t["." + model.__event__] = model
def get_event_model(event_name) -> List[Type[CQHTTPEvent]]:
return [model.value for model in _t.prefixes("." + event_name)][::-1]