nonebot2/packages/nonebot-adapter-mirai/nonebot/adapters/mirai/event/base.py
2021-11-22 23:21:26 +08:00

159 lines
4.0 KiB
Python

import json
from enum import Enum
from typing_extensions import Literal
from typing import Any, Dict, Type, Optional
from pydantic import Field, BaseModel, ValidationError
from nonebot.log import logger
from nonebot.typing import overrides
from nonebot.utils import escape_tag
from nonebot.adapters import Event as BaseEvent
from nonebot.adapters import Message as BaseMessage
class UserPermission(str, Enum):
"""
:说明:
用户权限枚举类
* ``OWNER``: 群主
* ``ADMINISTRATOR``: 群管理
* ``MEMBER``: 普通群成员
"""
OWNER = "OWNER"
ADMINISTRATOR = "ADMINISTRATOR"
MEMBER = "MEMBER"
class NudgeSubjectKind(str, Enum):
"""
:说明:
戳一戳类型枚举类
* ``Group``: 群
* ``Friend``: 好友
"""
Group = "Group"
Friend = "Friend"
class GroupInfo(BaseModel):
id: int
name: str
permission: UserPermission
class GroupChatInfo(BaseModel):
id: int
name: str = Field(alias="memberName")
permission: UserPermission
group: GroupInfo
class PrivateChatInfo(BaseModel):
id: int
nickname: str
remark: str
class NudgeSubject(BaseModel):
id: int
kind: NudgeSubjectKind
class Event(BaseEvent):
"""
mirai-api-http 协议事件,字段与 mirai-api-http 一致。各事件字段参考 `mirai-api-http 事件类型`_
.. _mirai-api-http 事件类型:
https://github.com/project-mirai/mirai-api-http/blob/master/docs/EventType.md
"""
self_id: int
type: str
@classmethod
def new(cls, data: Dict[str, Any]) -> "Event":
"""
此事件类的工厂函数, 能够通过事件数据选择合适的子类进行序列化
"""
type = data["type"]
def all_subclasses(cls: Type[Event]):
return set(cls.__subclasses__()).union(
[s for c in cls.__subclasses__() for s in all_subclasses(c)]
)
event_class: Optional[Type[Event]] = None
for subclass in all_subclasses(cls):
if subclass.__name__ != type:
continue
event_class = subclass
if event_class is None:
return Event.parse_obj(data)
while event_class and issubclass(event_class, Event):
try:
return event_class.parse_obj(data)
except ValidationError as e:
logger.info(
f"Failed to parse {data} to class {event_class.__name__}: "
f"{e.errors()!r}. Fallback to parent class."
)
event_class = event_class.__base__ # type: ignore
raise ValueError(f"Failed to serialize {data}.")
@overrides(BaseEvent)
def get_type(self) -> Literal["message", "notice", "request", "meta_event"]:
from . import meta, notice, message, request
if isinstance(self, message.MessageEvent):
return "message"
elif isinstance(self, notice.NoticeEvent):
return "notice"
elif isinstance(self, request.RequestEvent):
return "request"
else:
return "meta_event"
@overrides(BaseEvent)
def get_event_name(self) -> str:
return self.type
@overrides(BaseEvent)
def get_event_description(self) -> str:
return escape_tag(str(self.normalize_dict()))
@overrides(BaseEvent)
def get_message(self) -> BaseMessage:
raise ValueError("Event has no message!")
@overrides(BaseEvent)
def get_plaintext(self) -> str:
raise ValueError("Event has no message!")
@overrides(BaseEvent)
def get_user_id(self) -> str:
raise ValueError("Event has no message!")
@overrides(BaseEvent)
def get_session_id(self) -> str:
raise ValueError("Event has no message!")
@overrides(BaseEvent)
def is_tome(self) -> bool:
return False
def normalize_dict(self, **kwargs) -> Dict[str, Any]:
"""
返回可以被json正常反序列化的结构体
"""
return json.loads(self.json(**kwargs))