nonebot2/nonebot/adapters/__init__.py

457 lines
12 KiB
Python
Raw Normal View History

2020-10-01 23:52:56 +08:00
"""
协议适配基类
============
2020-10-01 23:52:56 +08:00
各协议请继承以下基类并使用 ``driver.register_adapter`` 注册适配器
"""
2020-07-05 20:39:34 +08:00
2020-07-18 18:18:43 +08:00
import abc
2020-08-13 15:23:04 +08:00
from functools import reduce, partial
2020-08-10 13:06:02 +08:00
from dataclasses import dataclass, field
2020-07-11 17:32:03 +08:00
2020-12-03 00:59:32 +08:00
from pydantic import BaseModel
2020-07-11 17:32:03 +08:00
from nonebot.config import Config
2020-08-14 17:41:24 +08:00
from nonebot.typing import Driver, Message, WebSocket
2020-12-03 00:59:32 +08:00
from nonebot.typing import Any, Dict, Union, Optional, NoReturn, Callable, Iterable, Awaitable, TypeVar, Generic
2020-07-11 17:32:03 +08:00
2020-07-05 20:39:34 +08:00
2020-07-18 18:18:43 +08:00
class BaseBot(abc.ABC):
2020-10-01 23:52:56 +08:00
"""
Bot 基类用于处理上报消息并提供 API 调用接口
"""
2020-07-05 20:39:34 +08:00
2020-07-18 18:18:43 +08:00
@abc.abstractmethod
2020-08-01 22:03:40 +08:00
def __init__(self,
2020-08-13 15:23:04 +08:00
driver: Driver,
2020-08-07 17:51:57 +08:00
connection_type: str,
2020-08-01 22:03:40 +08:00
config: Config,
2020-08-13 15:23:04 +08:00
self_id: str,
2020-08-01 22:03:40 +08:00
*,
2020-10-01 23:52:56 +08:00
websocket: Optional[WebSocket] = None):
"""
:参数:
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
* ``driver: Driver``: Driver 对象
* ``connection_type: str``: http 或者 websocket
* ``config: Config``: Config 对象
* ``self_id: str``: 机器人 ID
* ``websocket: Optional[WebSocket]``: Websocket 连接对象
"""
2020-08-13 15:23:04 +08:00
self.driver = driver
2020-10-01 23:52:56 +08:00
"""Driver 对象"""
2020-08-07 17:51:57 +08:00
self.connection_type = connection_type
2020-10-01 23:52:56 +08:00
"""连接类型"""
2020-08-07 17:51:57 +08:00
self.config = config
2020-10-01 23:52:56 +08:00
"""Config 配置对象"""
2020-08-07 17:51:57 +08:00
self.self_id = self_id
2020-10-01 23:52:56 +08:00
"""机器人 ID"""
2020-08-07 17:51:57 +08:00
self.websocket = websocket
2020-10-01 23:52:56 +08:00
"""Websocket 连接对象"""
2020-08-07 17:51:57 +08:00
2020-08-13 15:23:04 +08:00
def __getattr__(self, name: str) -> Callable[..., Awaitable[Any]]:
return partial(self.call_api, name)
2020-08-07 17:51:57 +08:00
@property
@abc.abstractmethod
def type(self) -> str:
2020-10-01 23:52:56 +08:00
"""Adapter 类型"""
2020-07-11 17:32:03 +08:00
raise NotImplementedError
@classmethod
@abc.abstractmethod
async def check_permission(cls, driver: Driver, connection_type: str,
headers: dict,
body: Optional[dict]) -> Union[str, NoReturn]:
2020-11-13 01:46:26 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
检查连接请求是否合法的函数如果合法则返回当前连接 ``唯一标识符``通常为机器人 ID如果不合法则抛出 ``RequestDenied`` 异常
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
* ``driver: Driver``: Driver 对象
* ``connection_type: str``: 连接类型
* ``headers: dict``: 请求头
* ``body: Optional[dict]``: 请求数据WebSocket 连接该部分为空
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
:返回:
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
- ``str``: 连接唯一标识符
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
:异常:
2020-11-30 11:08:00 +08:00
2020-11-13 01:46:26 +08:00
- ``RequestDenied``: 请求非法
"""
raise NotImplementedError
2020-07-18 18:18:43 +08:00
@abc.abstractmethod
2020-07-11 17:32:03 +08:00
async def handle_message(self, message: dict):
2020-10-01 23:52:56 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
处理上报消息的函数转换为 ``Event`` 事件后调用 ``nonebot.message.handle_event`` 进一步处理事件
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
* ``message: dict``: 收到的上报消息
"""
2020-07-11 17:32:03 +08:00
raise NotImplementedError
2020-07-18 18:18:43 +08:00
@abc.abstractmethod
2020-10-01 23:52:56 +08:00
async def call_api(self, api: str, **data):
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
调用机器人 API 接口可以通过该函数或直接通过 bot 属性进行调用
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
* ``api: str``: API 名称
* ``**data``: API 数据
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
:示例:
.. code-block:: python
2020-11-13 01:46:26 +08:00
await bot.call_api("send_msg", message="hello world"})
2020-10-01 23:52:56 +08:00
await bot.send_msg(message="hello world")
"""
2020-07-11 17:32:03 +08:00
raise NotImplementedError
@abc.abstractmethod
2020-10-06 17:03:05 +08:00
async def send(self, event: "BaseEvent",
message: Union[str, "BaseMessage",
"BaseMessageSegment"], **kwargs):
2020-10-01 23:52:56 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
调用机器人基础发送消息接口
2020-11-30 11:08:00 +08:00
2020-10-01 23:52:56 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-10-06 17:03:05 +08:00
* ``event: Event``: 上报事件
* ``message: Union[str, Message, MessageSegment]``: 要发送的消息
2020-10-01 23:52:56 +08:00
* ``**kwargs``
"""
raise NotImplementedError
2020-07-11 17:32:03 +08:00
2020-12-03 00:59:32 +08:00
T = TypeVar("T", dict, BaseModel)
class BaseEvent(abc.ABC, Generic[T]):
2020-10-01 23:52:56 +08:00
"""
Event 基类提供上报信息的关键信息其余信息可从原始上报消息获取
"""
2020-07-11 17:32:03 +08:00
2020-12-03 00:59:32 +08:00
def __init__(self, raw_event: T):
2020-09-29 23:10:29 +08:00
"""
2020-10-01 23:52:56 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-12-03 00:59:32 +08:00
* ``raw_event: T``: 原始上报消息
2020-09-29 23:10:29 +08:00
"""
2020-12-03 00:59:32 +08:00
self._raw_event: T = raw_event
2020-08-10 14:50:12 +08:00
def __repr__(self) -> str:
2020-08-25 18:02:18 +08:00
return f"<Event {self.self_id}: {self.name} {self.time}>"
@property
2020-12-03 00:59:32 +08:00
def raw_event(self) -> T:
2020-10-01 23:52:56 +08:00
"""原始上报消息"""
return self._raw_event
2020-08-25 18:02:18 +08:00
@property
@abc.abstractmethod
def id(self) -> int:
2020-10-01 23:52:56 +08:00
"""事件 ID"""
2020-08-25 18:02:18 +08:00
raise NotImplementedError
@property
@abc.abstractmethod
def name(self) -> str:
2020-10-01 23:52:56 +08:00
"""事件名称"""
2020-08-25 18:02:18 +08:00
raise NotImplementedError
@property
@abc.abstractmethod
def self_id(self) -> str:
2020-10-01 23:52:56 +08:00
"""机器人 ID"""
raise NotImplementedError
2020-08-10 14:50:12 +08:00
@property
2020-08-25 18:02:18 +08:00
@abc.abstractmethod
def time(self) -> int:
2020-10-01 23:52:56 +08:00
"""事件发生时间"""
2020-08-25 18:02:18 +08:00
raise NotImplementedError
@property
2020-08-08 23:08:01 +08:00
@abc.abstractmethod
2020-08-11 16:54:45 +08:00
def type(self) -> str:
2020-10-01 23:52:56 +08:00
"""事件主类型"""
2020-07-11 17:32:03 +08:00
raise NotImplementedError
2020-08-10 14:50:12 +08:00
@type.setter
2020-08-08 23:08:01 +08:00
@abc.abstractmethod
2020-08-11 16:54:45 +08:00
def type(self, value) -> None:
2020-08-08 23:08:01 +08:00
raise NotImplementedError
2020-08-10 14:50:12 +08:00
@property
@abc.abstractmethod
2020-08-11 16:54:45 +08:00
def detail_type(self) -> str:
2020-10-01 23:52:56 +08:00
"""事件详细类型"""
2020-08-10 14:50:12 +08:00
raise NotImplementedError
2020-08-10 14:50:12 +08:00
@detail_type.setter
@abc.abstractmethod
2020-08-11 16:54:45 +08:00
def detail_type(self, value) -> None:
2020-08-10 14:50:12 +08:00
raise NotImplementedError
2020-08-08 23:08:01 +08:00
2020-08-10 14:50:12 +08:00
@property
@abc.abstractmethod
2020-08-11 16:54:45 +08:00
def sub_type(self) -> Optional[str]:
2020-10-01 23:52:56 +08:00
"""事件子类型"""
2020-08-10 14:50:12 +08:00
raise NotImplementedError
2020-08-08 23:08:01 +08:00
2020-08-10 14:50:12 +08:00
@sub_type.setter
@abc.abstractmethod
2020-08-11 16:54:45 +08:00
def sub_type(self, value) -> None:
2020-08-10 14:50:12 +08:00
raise NotImplementedError
2020-08-08 23:08:01 +08:00
2020-08-17 16:09:41 +08:00
@property
@abc.abstractmethod
def user_id(self) -> Optional[int]:
2020-10-01 23:52:56 +08:00
"""触发事件的主体 ID"""
2020-08-17 16:09:41 +08:00
raise NotImplementedError
@user_id.setter
@abc.abstractmethod
def user_id(self, value) -> None:
raise NotImplementedError
@property
@abc.abstractmethod
def group_id(self) -> Optional[int]:
2020-10-01 23:52:56 +08:00
"""触发事件的主体群 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]:
2020-10-01 23:52:56 +08:00
"""事件是否为发送给机器人的消息"""
raise NotImplementedError
@to_me.setter
@abc.abstractmethod
def to_me(self, value) -> None:
raise NotImplementedError
2020-08-14 17:41:24 +08:00
@property
@abc.abstractmethod
def message(self) -> Optional[Message]:
2020-10-01 23:52:56 +08:00
"""消息内容"""
2020-08-14 17:41:24 +08:00
raise NotImplementedError
@message.setter
@abc.abstractmethod
def message(self, value) -> None:
raise NotImplementedError
2020-08-28 11:54:21 +08:00
@property
@abc.abstractmethod
def reply(self) -> Optional[dict]:
2020-10-01 23:52:56 +08:00
"""回复的消息"""
2020-08-28 11:54:21 +08:00
raise NotImplementedError
@reply.setter
@abc.abstractmethod
def reply(self, value) -> None:
raise NotImplementedError
2020-08-14 17:41:24 +08:00
@property
@abc.abstractmethod
def raw_message(self) -> Optional[str]:
2020-10-01 23:52:56 +08:00
"""原始消息"""
2020-08-14 17:41:24 +08:00
raise NotImplementedError
@raw_message.setter
@abc.abstractmethod
def raw_message(self, value) -> None:
raise NotImplementedError
2020-08-17 16:09:41 +08:00
@property
@abc.abstractmethod
def plain_text(self) -> Optional[str]:
2020-10-01 23:52:56 +08:00
"""纯文本消息"""
2020-08-17 16:09:41 +08:00
raise NotImplementedError
@property
@abc.abstractmethod
def sender(self) -> Optional[dict]:
2020-10-01 23:52:56 +08:00
"""消息发送者信息"""
2020-08-17 16:09:41 +08:00
raise NotImplementedError
@sender.setter
@abc.abstractmethod
def sender(self, value) -> None:
raise NotImplementedError
2020-08-10 14:50:12 +08:00
@dataclass
class BaseMessageSegment(abc.ABC):
2020-10-03 18:18:43 +08:00
"""消息段基类"""
2020-08-10 14:50:12 +08:00
type: str
2020-10-03 18:18:43 +08:00
"""
- 类型: ``str``
- 说明: 消息段类型
"""
data: Dict[str, Any] = field(default_factory=lambda: {})
2020-10-03 18:18:43 +08:00
"""
- 类型: ``Dict[str, Union[str, list]]``
- 说明: 消息段数据
"""
2020-08-10 14:50:12 +08:00
@abc.abstractmethod
def __str__(self):
"""该消息段所代表的 str在命令匹配部分使用"""
2020-08-10 14:50:12 +08:00
raise NotImplementedError
2020-07-11 17:32:03 +08:00
2020-08-10 14:50:12 +08:00
@abc.abstractmethod
def __add__(self, other):
"""你需要在这里实现不同消息段的合并:
比如
if isinstance(other, str):
...
elif isinstance(other, MessageSegment):
...
注意不能返回 self需要返回一个新生成的对象
"""
2020-08-10 14:50:12 +08:00
raise NotImplementedError
2020-08-08 23:08:01 +08:00
2020-10-09 00:10:50 +08:00
def __getitem__(self, key):
return getattr(self, key)
def __setitem__(self, key, value):
return setattr(self, key, value)
2020-11-01 19:20:18 +08:00
def get(self, key, default=None):
return getattr(self, key, default)
@classmethod
@abc.abstractmethod
def text(cls, text: str) -> "BaseMessageSegment":
return cls("text", {"text": text})
2020-08-08 23:08:01 +08:00
class BaseMessage(list, abc.ABC):
2020-10-03 18:18:43 +08:00
"""消息数组"""
2020-07-11 17:32:03 +08:00
2020-07-18 18:18:43 +08:00
def __init__(self,
2020-12-03 00:59:32 +08:00
message: Union[str, dict, list, BaseModel, BaseMessageSegment,
2020-08-11 10:44:05 +08:00
"BaseMessage"] = None,
2020-07-18 18:18:43 +08:00
*args,
**kwargs):
2020-10-03 18:18:43 +08:00
"""
:参数:
2020-11-30 11:08:00 +08:00
2020-12-03 00:59:32 +08:00
* ``message: Union[str, dict, list, BaseModel, MessageSegment, Message]``: 消息内容
2020-10-03 18:18:43 +08:00
"""
2020-07-18 18:18:43 +08:00
super().__init__(*args, **kwargs)
2020-12-03 00:59:32 +08:00
if isinstance(message, (str, dict, list, BaseModel)):
2020-07-18 18:18:43 +08:00
self.extend(self._construct(message))
elif isinstance(message, BaseMessage):
self.extend(message)
elif isinstance(message, BaseMessageSegment):
self.append(message)
2020-07-11 17:32:03 +08:00
def __str__(self):
return ''.join((str(seg) for seg in self))
2020-07-18 18:18:43 +08:00
@staticmethod
2020-08-08 23:08:01 +08:00
@abc.abstractmethod
2020-08-11 10:44:05 +08:00
def _construct(msg: Union[str, dict, list]) -> Iterable[BaseMessageSegment]:
2020-07-18 18:18:43 +08:00
raise NotImplementedError
def __add__(
self, other: Union[str, BaseMessageSegment,
"BaseMessage"]) -> "BaseMessage":
result = self.__class__(self)
if isinstance(other, str):
result.extend(self._construct(other))
elif isinstance(other, BaseMessageSegment):
result.append(other)
elif isinstance(other, BaseMessage):
result.extend(other)
return result
def __radd__(self, other: Union[str, BaseMessageSegment, "BaseMessage"]):
result = self.__class__(other)
return result.__add__(self)
def append(self, obj: Union[str, BaseMessageSegment]) -> "BaseMessage":
2020-10-03 18:18:43 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
添加一个消息段到消息数组末尾
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
* ``obj: Union[str, MessageSegment]``: 要添加的消息段
"""
2020-07-18 18:18:43 +08:00
if isinstance(obj, BaseMessageSegment):
super().append(obj)
2020-07-18 18:18:43 +08:00
elif isinstance(obj, str):
self.extend(self._construct(obj))
else:
raise ValueError(f"Unexpected type: {type(obj)} {obj}")
return self
def extend(
self, obj: Union["BaseMessage",
Iterable[BaseMessageSegment]]) -> "BaseMessage":
2020-10-03 18:18:43 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
拼接一个消息数组或多个消息段到消息数组末尾
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
:参数:
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
* ``obj: Union[Message, Iterable[MessageSegment]]``: 要添加的消息数组
"""
2020-07-18 18:18:43 +08:00
for segment in obj:
self.append(segment)
return self
def reduce(self) -> None:
2020-10-03 18:18:43 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
缩减消息数组即按 MessageSegment 的实现拼接相邻消息段
2020-10-03 18:18:43 +08:00
"""
2020-07-18 18:18:43 +08:00
index = 0
while index < len(self):
if index > 0 and self[
index - 1].type == "text" and self[index].type == "text":
self[index - 1] += self[index]
2020-07-18 18:18:43 +08:00
del self[index]
else:
index += 1
def extract_plain_text(self) -> str:
2020-10-03 18:18:43 +08:00
"""
:说明:
2020-11-30 11:08:00 +08:00
2020-10-03 18:18:43 +08:00
提取消息内纯文本消息
"""
2020-07-18 18:18:43 +08:00
def _concat(x: str, y: BaseMessageSegment) -> str:
return f"{x} {y}" if y.type == "text" else x
2020-07-18 18:18:43 +08:00
plain_text = reduce(_concat, self, "")
2020-12-03 00:59:32 +08:00
return plain_text.strip()