mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-11-03 16:36:44 +00:00 
			
		
		
		
	🚧 💡 add comments for message etc. in mirai adapter
This commit is contained in:
		@@ -1,3 +1,13 @@
 | 
			
		||||
"""
 | 
			
		||||
Mirai-API-HTTP 协议适配
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
协议详情请看: `mirai-api-http 文档`_ 
 | 
			
		||||
 | 
			
		||||
.. mirai-api-http 文档:
 | 
			
		||||
    https://github.com/project-mirai/mirai-api-http/tree/master/docs
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from .bot import MiraiBot
 | 
			
		||||
from .bot_ws import MiraiWebsocketBot
 | 
			
		||||
from .event import *
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ class ActionFailed(BaseActionFailed):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SessionManager:
 | 
			
		||||
    """Bot会话管理器, 提供API主动调用接口"""
 | 
			
		||||
    sessions: Dict[int, Tuple[str, datetime, httpx.AsyncClient]] = {}
 | 
			
		||||
    session_expiry: timedelta = timedelta(minutes=15)
 | 
			
		||||
 | 
			
		||||
@@ -40,19 +41,39 @@ class SessionManager:
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _raise_code(data: Dict[str, Any]) -> Dict[str, Any]:
 | 
			
		||||
        code = data.get('code', 0)
 | 
			
		||||
        logger.opt(colors=True).debug('Mirai API returned data: '
 | 
			
		||||
                                      f'<y>{escape_tag(str(data))}</y>')
 | 
			
		||||
        if code != 0:
 | 
			
		||||
            raise ActionFailed(**data)
 | 
			
		||||
        logger.opt(colors=True).debug(
 | 
			
		||||
            f'Mirai API returned data: <y>{escape_tag(str(data))}</y>')
 | 
			
		||||
        if isinstance(data, dict) and ('code' in data):
 | 
			
		||||
            if data['code'] != 0:
 | 
			
		||||
                raise ActionFailed(**data)
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    async def post(self,
 | 
			
		||||
                   path: str,
 | 
			
		||||
                   *,
 | 
			
		||||
                   params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
 | 
			
		||||
        params = {**(params or {}), 'sessionKey': self.session_key}
 | 
			
		||||
        response = await self.client.post(path, json=params, timeout=3)
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          以POST方式主动提交API请求
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``path: str``: 对应API路径
 | 
			
		||||
          * ``params: Optional[Dict[str, Any]]``: 请求参数 (无需sessionKey)
 | 
			
		||||
 | 
			
		||||
        :返回:
 | 
			
		||||
 | 
			
		||||
          - ``Dict[str, Any]``: API 返回值
 | 
			
		||||
        """
 | 
			
		||||
        response = await self.client.post(
 | 
			
		||||
            path,
 | 
			
		||||
            json={
 | 
			
		||||
                **(params or {}),
 | 
			
		||||
                'sessionKey': self.session_key,
 | 
			
		||||
            },
 | 
			
		||||
            timeout=3,
 | 
			
		||||
        )
 | 
			
		||||
        response.raise_for_status()
 | 
			
		||||
        return self._raise_code(response.json())
 | 
			
		||||
 | 
			
		||||
@@ -61,12 +82,28 @@ class SessionManager:
 | 
			
		||||
                      *,
 | 
			
		||||
                      params: Optional[Dict[str,
 | 
			
		||||
                                            Any]] = None) -> Dict[str, Any]:
 | 
			
		||||
        response = await self.client.get(path,
 | 
			
		||||
                                         params={
 | 
			
		||||
                                             **(params or {}), 'sessionKey':
 | 
			
		||||
                                                 self.session_key
 | 
			
		||||
                                         },
 | 
			
		||||
                                         timeout=3)
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          以GET方式主动提交API请求
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``path: str``: 对应API路径
 | 
			
		||||
          * ``params: Optional[Dict[str, Any]]``: 请求参数 (无需sessionKey)
 | 
			
		||||
 | 
			
		||||
        :返回:
 | 
			
		||||
 | 
			
		||||
          - ``Dict[str, Any]``: API 返回值
 | 
			
		||||
        """
 | 
			
		||||
        response = await self.client.get(
 | 
			
		||||
            path,
 | 
			
		||||
            params={
 | 
			
		||||
                **(params or {}),
 | 
			
		||||
                'sessionKey': self.session_key,
 | 
			
		||||
            },
 | 
			
		||||
            timeout=3,
 | 
			
		||||
        )
 | 
			
		||||
        response.raise_for_status()
 | 
			
		||||
        return self._raise_code(response.json())
 | 
			
		||||
 | 
			
		||||
@@ -108,11 +145,11 @@ class SessionManager:
 | 
			
		||||
        return cls(session_key, client)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get(cls, self_id: int):
 | 
			
		||||
    def get(cls, self_id: int, check_expire: bool = True):
 | 
			
		||||
        if self_id not in cls.sessions:
 | 
			
		||||
            return None
 | 
			
		||||
        key, time, client = cls.sessions[self_id]
 | 
			
		||||
        if datetime.now() - time > cls.session_expiry:
 | 
			
		||||
        if check_expire and (datetime.now() - time > cls.session_expiry):
 | 
			
		||||
            return None
 | 
			
		||||
        return cls(key, client)
 | 
			
		||||
 | 
			
		||||
@@ -129,7 +166,6 @@ class MiraiBot(BaseBot):
 | 
			
		||||
                 *,
 | 
			
		||||
                 websocket: Optional[WebSocket] = None):
 | 
			
		||||
        super().__init__(connection_type, self_id, websocket=websocket)
 | 
			
		||||
        self.api = SessionManager.get(int(self_id))
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
@@ -140,6 +176,13 @@ class MiraiBot(BaseBot):
 | 
			
		||||
    def alive(self) -> bool:
 | 
			
		||||
        return not self.websocket.closed
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def api(self) -> SessionManager:
 | 
			
		||||
        """返回该Bot对象的会话管理实例以提供API主动调用"""
 | 
			
		||||
        api = SessionManager.get(self_id=int(self.self_id))
 | 
			
		||||
        assert api is not None, 'SessionManager has not been initialized'
 | 
			
		||||
        return api
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
    async def check_permission(cls, driver: "Driver", connection_type: str,
 | 
			
		||||
@@ -179,10 +222,12 @@ class MiraiBot(BaseBot):
 | 
			
		||||
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
    async def call_api(self, api: str, **data) -> NoReturn:
 | 
			
		||||
        """由于Mirai的HTTP API特殊性, 该API暂时无法实现"""
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
    def __getattr__(self, key: str) -> NoReturn:
 | 
			
		||||
        """由于Mirai的HTTP API特殊性, 该API暂时无法实现"""
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
 | 
			
		||||
    @overrides(BaseBot)
 | 
			
		||||
 
 | 
			
		||||
@@ -107,6 +107,12 @@ class MiraiWebsocketBot(MiraiBot):
 | 
			
		||||
    def alive(self) -> bool:
 | 
			
		||||
        return not self.websocket.closed
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def api(self) -> SessionManager:
 | 
			
		||||
        api = SessionManager.get(self_id=int(self.self_id), check_expire=False)
 | 
			
		||||
        assert api is not None, 'SessionManager has not been initialized'
 | 
			
		||||
        return api
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    @overrides(MiraiBot)
 | 
			
		||||
    async def check_permission(cls, driver: "Driver", connection_type: str,
 | 
			
		||||
@@ -118,12 +124,23 @@ class MiraiWebsocketBot(MiraiBot):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    @overrides(MiraiBot)
 | 
			
		||||
    def register(cls, driver: "Driver", config: "Config", qq: int):
 | 
			
		||||
        cls.mirai_config = MiraiConfig(**config.dict())
 | 
			
		||||
        cls.active = True
 | 
			
		||||
        assert cls.mirai_config.auth_key is not None
 | 
			
		||||
        assert cls.mirai_config.host is not None
 | 
			
		||||
        assert cls.mirai_config.port is not None
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          注册该Adapter 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``driver: Driver``: 程序所使用的``Driver``
 | 
			
		||||
          * ``config: Config``: 程序配置对象
 | 
			
		||||
          * ``qq: int``: 要使用的Bot的QQ号 **注意: 在使用正向Websocket时必须指定该值!**
 | 
			
		||||
 | 
			
		||||
        :返回:
 | 
			
		||||
 | 
			
		||||
          - ``[type]``: [description]
 | 
			
		||||
        """
 | 
			
		||||
        super().register(driver, config)
 | 
			
		||||
        cls.active = True
 | 
			
		||||
 | 
			
		||||
        async def _bot_connection():
 | 
			
		||||
            session: SessionManager = await SessionManager.new(
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,15 @@ from pydantic import BaseModel, Extra, Field
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Config(BaseModel):
 | 
			
		||||
    """
 | 
			
		||||
    Mirai 配置类
 | 
			
		||||
 | 
			
		||||
    :必填:
 | 
			
		||||
 | 
			
		||||
      - ``mirai_auth_key``: mirai-api-http的auth_key
 | 
			
		||||
      - ``mirai_host``: mirai-api-http的地址
 | 
			
		||||
      - ``mirai_port``: mirai-api-http的端口
 | 
			
		||||
    """
 | 
			
		||||
    auth_key: Optional[str] = Field(None, alias='mirai_auth_key')
 | 
			
		||||
    host: Optional[IPv4Address] = Field(None, alias='mirai_host')
 | 
			
		||||
    port: Optional[int] = Field(None, alias='mirai_port')
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,10 @@
 | 
			
		||||
"""
 | 
			
		||||
\:\:\:warning 警告
 | 
			
		||||
事件中为了使代码更加整洁, 我们采用了与PEP8相符的命名规则取代Mirai原有的驼峰命名
 | 
			
		||||
 | 
			
		||||
部分字段可能与文档在符号上不一致
 | 
			
		||||
\:\:\:
 | 
			
		||||
"""
 | 
			
		||||
from .base import Event, GroupChatInfo, GroupInfo, UserPermission, PrivateChatInfo
 | 
			
		||||
from .message import *
 | 
			
		||||
from .notice import *
 | 
			
		||||
 
 | 
			
		||||
@@ -45,9 +45,9 @@ class PrivateChatInfo(BaseModel):
 | 
			
		||||
 | 
			
		||||
class Event(BaseEvent):
 | 
			
		||||
    """
 | 
			
		||||
    mirai-api-http 协议事件,字段与 mirai-api-http 一致。各事件字段参考 `mirai-api-http 文档`_
 | 
			
		||||
    mirai-api-http 协议事件,字段与 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
 | 
			
		||||
 
 | 
			
		||||
@@ -55,10 +55,6 @@ class NewFriendRequestEvent(RequestEvent):
 | 
			
		||||
            - ``1``: 拒绝添加好友
 | 
			
		||||
            - ``2``: 拒绝添加好友并添加黑名单,不再接收该用户的好友申请
 | 
			
		||||
          * ``message: str``: 回复的信息
 | 
			
		||||
 | 
			
		||||
        :返回:
 | 
			
		||||
 | 
			
		||||
          - ``[type]``: [description]
 | 
			
		||||
        """
 | 
			
		||||
        assert operate > 0
 | 
			
		||||
        return await bot.api.post('/resp/newFriendRequestEvent',
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from nonebot.typing import overrides
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageType(str, Enum):
 | 
			
		||||
    """消息类型枚举类"""
 | 
			
		||||
    SOURCE = 'Source'
 | 
			
		||||
    QUOTE = 'Quote'
 | 
			
		||||
    AT = 'At'
 | 
			
		||||
@@ -25,6 +26,13 @@ class MessageType(str, Enum):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageSegment(BaseMessageSegment):
 | 
			
		||||
    """
 | 
			
		||||
    CQHTTP 协议 MessageSegment 适配。具体方法参考 `mirai-api-http 消息类型`_
 | 
			
		||||
 | 
			
		||||
    .. _mirai-api-http 消息类型:
 | 
			
		||||
        https://github.com/project-mirai/mirai-api-http/blob/master/docs/MessageType.md
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    type: MessageType
 | 
			
		||||
    data: Dict[str, Any]
 | 
			
		||||
 | 
			
		||||
@@ -59,6 +67,7 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
        return self.type == MessageType.PLAIN
 | 
			
		||||
 | 
			
		||||
    def as_dict(self) -> Dict[str, Any]:
 | 
			
		||||
        """导出可以被正常json序列化的结构体"""
 | 
			
		||||
        return {'type': self.type.value, **self.data}
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
@@ -68,6 +77,19 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def quote(cls, id: int, group_id: int, sender_id: int, target_id: int,
 | 
			
		||||
              origin: "MessageChain"):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          生成回复引用消息段 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``id: int``: 被引用回复的原消息的message_id
 | 
			
		||||
          * ``group_id: int``: 被引用回复的原消息所接收的群号,当为好友消息时为0
 | 
			
		||||
          * ``sender_id: int``: 被引用回复的原消息的发送者的QQ号
 | 
			
		||||
          * ``target_id: int``: 被引用回复的原消息的接收者者的QQ号(或群号)
 | 
			
		||||
          * ``origin: MessageChain``: 被引用回复的原消息的消息链对象
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.QUOTE,
 | 
			
		||||
                   id=id,
 | 
			
		||||
                   groupId=group_id,
 | 
			
		||||
@@ -77,18 +99,51 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def at(cls, target: int):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          @某个人 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``target: int``: 群员QQ号
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.AT, target=target)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def at_all(cls):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          @全体成员
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.AT_ALL)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def face(cls, face_id: Optional[int] = None, name: Optional[str] = None):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          发送QQ表情 
 | 
			
		||||
        
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``face_id: Optional[int]``: QQ表情编号,可选,优先高于name
 | 
			
		||||
          * ``name: Optional[str]``: QQ表情拼音,可选
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.FACE, faceId=face_id, name=name)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def plain(cls, text: str):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          纯文本消息 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``text: str``: 文字消息
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.PLAIN, text=text)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
@@ -96,6 +151,21 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
              image_id: Optional[str] = None,
 | 
			
		||||
              url: Optional[str] = None,
 | 
			
		||||
              path: Optional[str] = None):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          图片消息 
 | 
			
		||||
        
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``image_id: Optional[str]``: 图片的image_id,群图片与好友图片格式不同。不为空时将忽略url属性
 | 
			
		||||
          * ``url: Optional[str]``: 图片的URL,发送时可作网络图片的链接
 | 
			
		||||
          * ``path: Optional[str]``: 图片的路径,发送本地图片
 | 
			
		||||
 | 
			
		||||
        :返回:
 | 
			
		||||
 | 
			
		||||
          - ``[type]``: [description]
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.IMAGE, imageId=image_id, url=url, path=path)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
@@ -103,6 +173,15 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
                    image_id: Optional[str] = None,
 | 
			
		||||
                    url: Optional[str] = None,
 | 
			
		||||
                    path: Optional[str] = None):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          闪照消息 
 | 
			
		||||
        
 | 
			
		||||
        :参数:
 | 
			
		||||
          
 | 
			
		||||
          同 ``image``
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.FLASH_IMAGE,
 | 
			
		||||
                   imageId=image_id,
 | 
			
		||||
                   url=url,
 | 
			
		||||
@@ -113,6 +192,17 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
              voice_id: Optional[str] = None,
 | 
			
		||||
              url: Optional[str] = None,
 | 
			
		||||
              path: Optional[str] = None):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          语音消息
 | 
			
		||||
 | 
			
		||||
        :参数: 
 | 
			
		||||
 | 
			
		||||
          * ``voice_id: Optional[str]``: 语音的voice_id,不为空时将忽略url属性
 | 
			
		||||
          * ``url: Optional[str]``: 语音的URL,发送时可作网络语音的链接
 | 
			
		||||
          * ``path: Optional[str]``: 语音的路径,发送本地语音
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.FLASH_IMAGE,
 | 
			
		||||
                   imageId=voice_id,
 | 
			
		||||
                   url=url,
 | 
			
		||||
@@ -120,22 +210,69 @@ class MessageSegment(BaseMessageSegment):
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def xml(cls, xml: str):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          XML消息 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``xml: str``: XML文本
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.XML, xml=xml)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def json(cls, json: str):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          Json消息 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``json: str``: Json文本
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.JSON, json=json)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def app(cls, content: str):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          应用程序消息 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``content: str``: 内容
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.APP, content=content)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def poke(cls, name: str):
 | 
			
		||||
        """
 | 
			
		||||
        :说明:
 | 
			
		||||
 | 
			
		||||
          戳一戳消息 
 | 
			
		||||
 | 
			
		||||
        :参数:
 | 
			
		||||
 | 
			
		||||
          * ``name: str``: 戳一戳的类型
 | 
			
		||||
            - "Poke": 戳一戳
 | 
			
		||||
            - "ShowLove": 比心
 | 
			
		||||
            - "Like": 点赞
 | 
			
		||||
            - "Heartbroken": 心碎
 | 
			
		||||
            - "SixSixSix": 666
 | 
			
		||||
            - "FangDaZhao": 放大招
 | 
			
		||||
        """
 | 
			
		||||
        return cls(type=MessageType.POKE, name=name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MessageChain(BaseMessage):  #type:List[MessageSegment]
 | 
			
		||||
class MessageChain(BaseMessage):
 | 
			
		||||
    """
 | 
			
		||||
    Mirai 协议 Messaqge 适配
 | 
			
		||||
    
 | 
			
		||||
    由于Mirai协议的Message实现较为特殊, 故使用MessageChain命名
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    @overrides(BaseMessage)
 | 
			
		||||
    def __init__(self, message: Union[List[Dict[str, Any]],
 | 
			
		||||
@@ -166,6 +303,7 @@ class MessageChain(BaseMessage):  #type:List[MessageSegment]
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def export(self) -> List[Dict[str, Any]]:
 | 
			
		||||
        """导出为可以被正常json序列化的数组"""
 | 
			
		||||
        return [
 | 
			
		||||
            *map(lambda segment: segment.as_dict(), self.copy())  # type: ignore
 | 
			
		||||
        ]
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user