mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-07-27 16:21:28 +00:00
🔖 Release 2.0.0-beta.2
This commit is contained in:
@ -0,0 +1,5 @@
|
||||
{
|
||||
"position": 7,
|
||||
"label": "插件",
|
||||
"collapsible": false
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
description: 规范定义插件配置项
|
||||
---
|
||||
|
||||
# 定义插件配置
|
||||
|
||||
通常,插件可以从配置文件中读取自己的配置项,但是由于额外的全局配置项没有预先定义的问题,导致开发时编辑器无法提示字段与类型,以及运行时没有对配置项直接进行检查。那么就需要一种方式来规范定义插件配置项。
|
||||
|
||||
## 定义配置模型
|
||||
|
||||
在 NoneBot2 中,我们使用强大高效的 [Pydantic](https://pydantic-docs.helpmanual.io/) 来定义配置模型,这个模型可以被用于配置的读取和类型检查等。例如,我们可以定义一个配置模型包含一个 string 类型的配置项:
|
||||
|
||||
```python title=config.py {3,4}
|
||||
from pydantic import BaseModel, Extra
|
||||
|
||||
class Config(BaseModel, extra=Extra.ignore):
|
||||
token: str
|
||||
```
|
||||
|
||||
:::important 参考
|
||||
更多丰富的模型定义方法(默认值、自定义 validator 等),请参考 [Pydantic](https://pydantic-docs.helpmanual.io/) 文档。
|
||||
:::
|
||||
|
||||
## 读取配置
|
||||
|
||||
定义完成配置模型后,我们可以在插件加载时获取全局配置,导入插件自身的配置模型:
|
||||
|
||||
```python title=__init__.py {5}
|
||||
from nonebot import get_driver
|
||||
|
||||
from .config import Config
|
||||
|
||||
plugin_config = Config.parse_obj(get_driver().config)
|
||||
```
|
||||
|
||||
至此,插件已经成功读取了自身所需的配置项,并且具有字段和类型提示,也可以对配置进行运行时修改。
|
@ -0,0 +1,447 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
description: 定义事件处理流程,完成事件响应
|
||||
|
||||
options:
|
||||
menu:
|
||||
weight: 27
|
||||
category: guide
|
||||
---
|
||||
|
||||
# 定义事件处理流程
|
||||
|
||||
在上一章节中,我们已经定义了事件响应器,在这一章中,我们将会为事件响应器填充处理流程。
|
||||
|
||||
## 添加一个处理依赖
|
||||
|
||||
在事件响应器中,事件处理流程由一个或多个处理依赖组成,每个处理依赖都是一个 `Dependent`,详情可以参考[进阶 - 依赖注入](../../advanced/di/dependency-injection.md)。下面介绍如何添加一个处理依赖。
|
||||
|
||||
### 使用 `handle` 装饰器
|
||||
|
||||
```python {3-5}
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.handle()
|
||||
async def handle_func():
|
||||
# do something here
|
||||
```
|
||||
|
||||
如上方示例所示,我们使用 `matcher` 响应器的 `handle` 装饰器装饰了一个函数 `handle_func` 。`handle_func` 函数会被自动转换为 `Dependent` 对象,并被添加到 `matcher` 的事件处理流程中。
|
||||
|
||||
在 `handle_func` 函数中,我们可以编写任何事件响应逻辑,如:操作数据库,发送消息等。上下文信息可以通过依赖注入的方式获取,参考:[获取上下文信息](#获取上下文信息)。发送消息可以通过[事件响应器操作](./matcher-operation.md)或者直接调用 Bot 的方法( API 等,由协议适配器决定)。
|
||||
|
||||
:::warning 注意
|
||||
`handle_func` 函数虽然会被装饰器自动转换为 `Dependent` 对象,但 `handle_func` 仍然为原本的函数,因此 `handle_func` 函数可以进行复用。如:
|
||||
|
||||
```python
|
||||
matcher1 = on_message()
|
||||
matcher2 = on_message()
|
||||
|
||||
@matcher1.handle()
|
||||
@matcher2.handle()
|
||||
async def handle_func():
|
||||
# do something here
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### 使用 `receive` 装饰器
|
||||
|
||||
```python {3-5}
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.receive("id")
|
||||
async def handle_func(e: Event = Received("id")):
|
||||
# do something here
|
||||
```
|
||||
|
||||
`receive` 装饰器与 `handle` 装饰器一样,可以装饰一个函数添加到事件响应器的事件处理流程中。但与 `handle` 装饰器不同的是,`receive` 装饰器会中断当前事件处理流程,等待接收一个新的事件,就像是会话状态等待用户一个新的事件。可以接收的新的事件类型取决于事件响应器的 [`type`](./create-matcher.md#事件响应器类型-type) 更新值以及 [`permission`](./create-matcher.md#事件触发权限-permission) 更新值,可以通过自定义更新方法来控制会话响应(如进行非消息交互、多人会话、跨群会话等)。
|
||||
|
||||
`receive` 装饰器接受一个可选参数 `id`,用于标识当前需要接收的事件,如果不指定,则默认为空 `""`。
|
||||
|
||||
在 `handle_func` 函数中,可以通过依赖注入的方式来获取接收到的事件,参考:[`Received`](#received)、[`LastReceived`](#lastreceived)。
|
||||
|
||||
:::important 提示
|
||||
`receive` 装饰器可以和自身与 `got` 装饰器嵌套使用
|
||||
:::
|
||||
|
||||
:::warning 注意
|
||||
如果存在多个 `receive` 装饰器,则必须指定不相同的多个 `id`;否则相同的 `id` 将会被跳过接收。
|
||||
|
||||
```python
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.receive("id1")
|
||||
@matcher.receive("id2")
|
||||
async def handle_func():
|
||||
# do something here
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### 使用 `got` 装饰器
|
||||
|
||||
```python {3-5}
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.got("key")
|
||||
async def handle_func(key: Message = Arg()):
|
||||
# do something here
|
||||
```
|
||||
|
||||
`got` 装饰器与 `receive` 装饰器一样,会中断当前事件处理流程,等待接收一个新的事件。但与 `receive` 装饰器不同的是,`got` 装饰器用于接收一条消息,并且可以控制是否向用户发送询问 `prompt` 等,更贴近于对话形式会话。
|
||||
|
||||
`got` 装饰器接受一个参数 `key` 和一个可选参数 `prompt`,当 `key` 不存在时,会向用户发送 `prompt` 消息,并等待用户回复。
|
||||
|
||||
在 `handle_func` 函数中,可以通过依赖注入的方式来获取接收到的消息,参考:[`Arg`](#arg)、[`ArgStr`](#argstr)、[`ArgPlainText`](#argplaintext)。
|
||||
|
||||
:::important 提示
|
||||
`got` 装饰器可以和自身与 `receive` 装饰器嵌套使用
|
||||
:::
|
||||
|
||||
### 直接添加
|
||||
|
||||
```python {2}
|
||||
matcher = on_message(
|
||||
handlers=[handle_func, or_dependent]
|
||||
)
|
||||
```
|
||||
|
||||
:::warning 注意
|
||||
通过该方法添加的处理依赖将会处于整个事件处理流程的最前,因此,如果再使用 `handle` 等装饰器,则会在其之后。
|
||||
:::
|
||||
|
||||
## 事件处理流程
|
||||
|
||||
在一个事件响应器中,事件被添加的处理依赖依次执行,直到所有处理依赖都执行完毕,或者遇到了某个处理依赖需要更多的事件来进行下一步的处理。在下一个事件到来并符合响应要求时,继续执行。更多有关 NoneBot 事件分发与处理流程的详细信息,请参考[进阶 - 深入](../../advanced/README.md)。
|
||||
|
||||
## 获取上下文信息
|
||||
|
||||
在事件处理流程中,事件响应器具有自己独立的上下文,例如:当前的事件、机器人等信息,可以通过依赖注入的方式来获取。
|
||||
|
||||
### Bot
|
||||
|
||||
获取当前事件的 Bot 对象。
|
||||
|
||||
```python {7-9}
|
||||
from typing import Union
|
||||
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.ding import Bot as DingBot
|
||||
from nonebot.adapters.onebot.v11 import Bot as OneBotV11Bot
|
||||
|
||||
async def _(foo: Bot): ...
|
||||
async def _(foo: Union[DingBot, OneBotV11Bot]): ...
|
||||
async def _(bot): ... # 兼容性处理
|
||||
```
|
||||
|
||||
### Event
|
||||
|
||||
获取当前事件。
|
||||
|
||||
```python {6-8}
|
||||
from typing import Union
|
||||
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent
|
||||
|
||||
async def _(foo: Event): ...
|
||||
async def _(foo: Union[PrivateMessageEvent, GroupMessageEvent]): ...
|
||||
async def _(event): ... # 兼容性处理
|
||||
```
|
||||
|
||||
### EventType
|
||||
|
||||
获取当前事件的类型。
|
||||
|
||||
```python {3}
|
||||
from nonebot.params import EventType
|
||||
|
||||
async def _(foo: str = EventType()): ...
|
||||
```
|
||||
|
||||
### EventMessage
|
||||
|
||||
获取当前事件的消息。
|
||||
|
||||
```python {4}
|
||||
from nonebot.adapters import Message
|
||||
from nonebot.params import EventMessage
|
||||
|
||||
async def _(foo: str = EventMessage()): ...
|
||||
```
|
||||
|
||||
### EventPlainText
|
||||
|
||||
获取当前事件的消息纯文本部分。
|
||||
|
||||
```python {3}
|
||||
from nonebot.params import EventPlainText
|
||||
|
||||
async def _(foo: str = EventPlainText()): ...
|
||||
```
|
||||
|
||||
### EventToMe
|
||||
|
||||
获取当前事件是否与机器人相关。
|
||||
|
||||
```python {3}
|
||||
from nonebot.params import EventToMe
|
||||
|
||||
async def _(foo: bool = EventToMe()): ...
|
||||
```
|
||||
|
||||
### State
|
||||
|
||||
获取当前事件处理上下文状态,State 为一个字典,用户可以向 State 中添加数据来保存状态等操作。(请注意不要随意覆盖 State 中 NoneBot 的数据)
|
||||
|
||||
```python {4}
|
||||
from nonebot.typing import T_State
|
||||
|
||||
async def _(foo: T_State): ...
|
||||
```
|
||||
|
||||
### Command
|
||||
|
||||
获取当前命令型消息的元组形式命令名。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_command
|
||||
from nonebot.params import Command
|
||||
|
||||
matcher = on_command("cmd")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: Tuple[str, ...] = Command()): ...
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
命令详情只能在首次接收到命令型消息时获取,如果在事件处理后续流程中获取,则会获取到不同的值。
|
||||
:::
|
||||
|
||||
### RawCommand
|
||||
|
||||
获取当前命令型消息的文本形式命令名。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_command
|
||||
from nonebot.params import RawCommand
|
||||
|
||||
matcher = on_command("cmd")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: str = RawCommand()): ...
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
命令详情只能在首次接收到命令型消息时获取,如果在事件处理后续流程中获取,则会获取到不同的值。
|
||||
:::
|
||||
|
||||
### CommandArg
|
||||
|
||||
获取命令型消息命令后跟随的参数。
|
||||
|
||||
```python {8}
|
||||
from nonebot import on_command
|
||||
from nonebot.adapters import Message
|
||||
from nonebot.params import CommandArg
|
||||
|
||||
matcher = on_command("cmd")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: Message = CommandArg()): ...
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
命令详情只能在首次接收到命令型消息时获取,如果在事件处理后续流程中获取,则会获取到不同的值。
|
||||
:::
|
||||
|
||||
### ShellCommandArgs
|
||||
|
||||
获取 shell 命令解析后的参数。
|
||||
|
||||
:::tip 提示
|
||||
如果参数解析失败,则为 [`ParserExit`](../../api/exception.md#ParserExit) 异常,并携带错误码与错误信息。
|
||||
|
||||
由于 `ArgumentParser` 在解析到 `--help` 参数时也会抛出异常,这种情况下错误码为 `0` 且错误信息即为帮助信息。
|
||||
:::
|
||||
|
||||
```python {8,12}
|
||||
from nonebot import on_shell_command
|
||||
from nonebot.params import ShellCommandArgs
|
||||
|
||||
matcher = on_shell_command("cmd", parser)
|
||||
|
||||
# 解析失败
|
||||
@matcher.handle()
|
||||
async def _(foo: ParserExit = ShellCommandArgs()): ...
|
||||
|
||||
# 解析成功
|
||||
@matcher.handle()
|
||||
async def _(foo: Dict[str, Any] = ShellCommandArgs()): ...
|
||||
```
|
||||
|
||||
### ShellCommandArgv
|
||||
|
||||
获取 shell 命令解析前的参数列表。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_shell_command
|
||||
from nonebot.params import ShellCommandArgs
|
||||
|
||||
matcher = on_shell_command("cmd")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: List[str] = ShellCommandArgv()): ...
|
||||
```
|
||||
|
||||
### RegexMatched
|
||||
|
||||
获取正则匹配结果。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_regex
|
||||
from nonebot.params import RegexMatched
|
||||
|
||||
matcher = on_regex("regex")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: str = RegexMatched()): ...
|
||||
```
|
||||
|
||||
### RegexGroup
|
||||
|
||||
获取正则匹配结果的 group 元组。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_regex
|
||||
from nonebot.params import RegexGroup
|
||||
|
||||
matcher = on_regex("regex")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: Tuple[Any, ...] = RegexGroup()): ...
|
||||
```
|
||||
|
||||
### RegexDict
|
||||
|
||||
获取正则匹配结果的 group 字典。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_regex
|
||||
from nonebot.params import RegexDict
|
||||
|
||||
matcher = on_regex("regex")
|
||||
|
||||
@matcher.handle()
|
||||
async def _(foo: Dict[str, Any] = RegexDict()): ...
|
||||
```
|
||||
|
||||
### Matcher
|
||||
|
||||
获取当前事件响应器实例。
|
||||
|
||||
```python {7}
|
||||
from nonebot import on_message
|
||||
from nonebot.matcher import Matcher
|
||||
|
||||
foo = on_message()
|
||||
|
||||
@foo.handle()
|
||||
async def _(matcher: Matcher): ...
|
||||
```
|
||||
|
||||
### Received
|
||||
|
||||
获取某次 `receive` 接收的事件。
|
||||
|
||||
```python {8}
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.params import Received
|
||||
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.receive("id")
|
||||
async def _(foo: Event = Received("id")): ...
|
||||
```
|
||||
|
||||
### LastReceived
|
||||
|
||||
获取最近一次 `receive` 接收的事件。
|
||||
|
||||
```python {8}
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters import Event
|
||||
from nonebot.params import LastReceived
|
||||
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.receive("any")
|
||||
async def _(foo: Event = LastReceived()): ...
|
||||
```
|
||||
|
||||
### Arg
|
||||
|
||||
获取某次 `got` 接收的参数。
|
||||
|
||||
```python {8-9}
|
||||
from nonebot.params import Arg
|
||||
from nonebot import on_message
|
||||
from nonebot.adapters import Message
|
||||
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.got("key")
|
||||
async def _(key: Message = Arg()): ...
|
||||
async def _(foo: Message = Arg("key")): ...
|
||||
```
|
||||
|
||||
### ArgStr
|
||||
|
||||
获取某次 `got` 接收的参数,并转换为字符串。
|
||||
|
||||
```python {7-8}
|
||||
from nonebot import on_message
|
||||
from nonebot.params import ArgStr
|
||||
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.got("key")
|
||||
async def _(key: str = ArgStr()): ...
|
||||
async def _(foo: str = ArgStr("key")): ...
|
||||
```
|
||||
|
||||
### ArgPlainText
|
||||
|
||||
获取某次 `got` 接收的参数的纯文本部分。
|
||||
|
||||
```python {7-8}
|
||||
from nonebot import on_message
|
||||
from nonebot.params import ArgPlainText
|
||||
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.got("key")
|
||||
async def _(key: str = ArgPlainText()): ...
|
||||
async def _(foo: str = ArgPlainText("key")): ...
|
||||
```
|
||||
|
||||
### Exception
|
||||
|
||||
获取事件响应器运行中抛出的异常。
|
||||
|
||||
```python {4}
|
||||
from nonebot.message import run_postprocessor
|
||||
|
||||
@run_postprocessor
|
||||
async def _(e: Exception): ...
|
||||
```
|
||||
|
||||
### Default
|
||||
|
||||
带有默认值的参数,便于复用依赖。
|
||||
|
||||
```python {1}
|
||||
async def _(foo="bar"): ...
|
||||
```
|
@ -0,0 +1,138 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
description: 定义事件响应器,对特定的事件进行处理
|
||||
|
||||
options:
|
||||
menu:
|
||||
weight: 26
|
||||
category: guide
|
||||
---
|
||||
|
||||
# 定义事件响应器
|
||||
|
||||
事件响应器(`Matcher`)是对接收到的事件进行响应的基本单元,所有的事件响应器都继承自 `Matcher` 基类。为了方便开发者编写插件,NoneBot2 在 `nonebot.plugin` 模块中为插件开发定义了一些辅助函数。首先,让我们来了解一下 `Matcher` 由哪些部分组成。
|
||||
|
||||
## 事件响应器的基本组成
|
||||
|
||||
### 事件响应器类型 `type`
|
||||
|
||||
事件响应器的类型即是该响应器所要响应的事件类型,只有在接收到的事件类型与该响应器的类型相同时,才会触发该响应器。如果类型留空,该响应器将会响应所有类型的事件。
|
||||
|
||||
NoneBot 内置了四种主要类型:`meta_event`、`message`、`notice`、`request`。通常情况下,协议适配器会将事件合理地分类至这四种类型中。如果有其他类型的事件需要响应,可以自行定义新的类型。
|
||||
|
||||
<!-- TODO: move session updater to advanced -->
|
||||
|
||||
:::warning 注意
|
||||
当会话状态更新时,会执行 `type_updater` 以更新 `type` 属性,以便会话收到新事件时能够正确匹配。
|
||||
|
||||
`type_updater` 默认将 `type` 修改为 `message`,你也可以自行定义 `type_updater` 来控制 `type` 属性更新。`type_updater` 是一个返回 `str` 的函数,可选依赖注入参数参考类型 `T_TypeUpdater`。
|
||||
|
||||
```python {3-5}
|
||||
matcher = on_request()
|
||||
|
||||
@matcher.type_updater
|
||||
async def update_type():
|
||||
return "message"
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### 事件匹配规则
|
||||
|
||||
事件响应器的匹配规则是一个 `Rule` 对象,它是一系列 `checker` 的集合,当所有的 `checker` 都返回 `True` 时,才会触发该响应器。
|
||||
|
||||
规则编写方法参考[自定义规则](#自定义规则)。
|
||||
|
||||
:::warning 注意
|
||||
当会话状态更新时,`rule` 会被清空,以便会话收到新事件时能够正确匹配。
|
||||
:::
|
||||
|
||||
### 事件触发权限 `permission`
|
||||
|
||||
事件响应器的触发权限是一个 `Permission` 对象,它也是一系列 `checker` 的集合,当其中一个 `checker` 返回 `True` 时,就会触发该响应器。
|
||||
|
||||
权限编写方法参考[自定义权限](#自定义权限)。
|
||||
|
||||
:::warning 注意
|
||||
与 `rule` 不同的是,`permission` 不会在会话状态更新时丢失,因此 `permission` 通常用于会话的响应控制。
|
||||
|
||||
并且,当会话状态更新时,会执行 `permission_updater` 以更新 `permission`。默认情况下,`permission_updater` 会在原有的 `permission` 基础上添加一个 `USER` 条件,以检查事件的 `session_id` 是否与当前会话一致。
|
||||
|
||||
你可以自行定义 `permission_updater` 来控制会话的响应权限更新。`permission_updater` 是一个返回 `Permission` 的函数,可选依赖注入参数参考类型 `T_PermissionUpdater`。
|
||||
|
||||
```python {3-5}
|
||||
matcher = on_message()
|
||||
|
||||
@matcher.permission_updater
|
||||
async def update_type(matcher: Matcher):
|
||||
return matcher.permission # return same without session_id check
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### 优先级 `priority`
|
||||
|
||||
事件响应器的优先级代表事件响应器的执行顺序
|
||||
|
||||
:::warning 警告
|
||||
同一优先级的事件响应器会**同时执行**,优先级数字**越小**越先响应!优先级请从 `1` 开始排序!
|
||||
:::
|
||||
|
||||
### 阻断 `block`
|
||||
|
||||
当有任意事件响应器发出了阻止事件传递信号时,该事件将不再会传递给下一优先级,直接结束处理。
|
||||
|
||||
NoneBot 内置的事件响应器中,所有非 `command` 规则的 `message` 类型的事件响应器都会阻断事件传递,其他则不会。
|
||||
|
||||
在部分情况中,可以使用 `matcher.stop_propagation()` 方法动态阻止事件传播,该方法需要 `handler` 在参数中获取 `matcher` 实例后调用方法。
|
||||
|
||||
```python {5}
|
||||
foo = on_request()
|
||||
|
||||
@foo.handle()
|
||||
async def handle(matcher: Matcher):
|
||||
matcher.stop_propagation()
|
||||
```
|
||||
|
||||
### 有效期 `temp`/`expire_time`
|
||||
|
||||
事件响应器可以设置有效期,当事件响应器超过有效期时,将会被移除。
|
||||
|
||||
- `temp` 属性:配置事件响应器在下一次响应之后移除。
|
||||
- `expire_time` 属性:配置事件响应器在指定时间之后移除。
|
||||
|
||||
## 创建事件响应器
|
||||
|
||||
在前面的介绍中,我们已经了解了事件响应器的组成,接下来我们就可以使用 `nonebot.plugin` 模块中定义的辅助函数来创建事件响应器。
|
||||
|
||||
```python {3}
|
||||
from nonebot import on_message
|
||||
|
||||
matcher = on_message()
|
||||
```
|
||||
|
||||
用于定义事件响应器的辅助函数已经在 `nonebot` 主模块中被 `re-export`,所以直接从 `nonebot` 导入即可。
|
||||
|
||||
辅助函数有以下几种:
|
||||
|
||||
1. `on`: 创建任何类型的事件响应器。
|
||||
2. `on_metaevent`: 创建元事件响应器。
|
||||
3. `on_message`: 创建消息事件响应器。
|
||||
4. `on_request`: 创建请求事件响应器。
|
||||
5. `on_notice`: 创建通知事件响应器。
|
||||
6. `on_startswith`: 创建消息开头匹配事件响应器。
|
||||
7. `on_endswith`: 创建消息结尾匹配事件响应器。
|
||||
8. `on_keyword`: 创建消息关键词匹配事件响应器。
|
||||
9. `on_command`: 创建命令消息事件响应器。
|
||||
10. `on_shell_command`: 创建 shell 命令消息事件响应器。
|
||||
11. `on_regex`: 创建正则表达式匹配事件响应器。
|
||||
12. `CommandGroup`: 创建具有共同命令名称前缀的命令组。
|
||||
13. `MatcherGroup`: 创建具有共同参数的响应器组。
|
||||
|
||||
其中,`on_metaevent` `on_message` `on_request` `on_notice` 函数都是在 `on` 的基础上添加了对应的事件类型 `type`;`on_startswith` `on_endswith` `on_keyword` `on_command` `on_shell_command` `on_regex` 函数都是在 `on_message` 的基础上添加了对应的匹配规则 `rule`。
|
||||
|
||||
## 自定义规则
|
||||
|
||||
<!-- TODO -->
|
||||
|
||||
## 自定义权限
|
@ -0,0 +1,32 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
description: 简单插件示例
|
||||
---
|
||||
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
import Messenger from "@site/src/components/Messenger";
|
||||
|
||||
# 插件示例
|
||||
|
||||
## 命令式问答示例
|
||||
|
||||
import WeatherSource from "!!raw-loader!@site/../tests/examples/weather.py";
|
||||
import WeatherTest from "!!raw-loader!@site/../tests/test_examples/test_weather.py";
|
||||
|
||||
<CodeBlock className="language-python">{WeatherSource}</CodeBlock>
|
||||
|
||||
<Messenger
|
||||
msgs={[
|
||||
{ position: "right", msg: "/天气" },
|
||||
{ position: "left", msg: "你想查询哪个城市的天气呢?" },
|
||||
{ position: "right", msg: "上海" },
|
||||
{ position: "left", msg: "上海的天气是..." },
|
||||
]}
|
||||
/>
|
||||
|
||||
<details>
|
||||
<summary>测试示例</summary>
|
||||
|
||||
<CodeBlock className="language-python">{WeatherTest}</CodeBlock>
|
||||
|
||||
</details>
|
@ -0,0 +1,71 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
description: 插件入门
|
||||
---
|
||||
|
||||
# 插件入门
|
||||
|
||||
## 插件结构
|
||||
|
||||
在编写插件之前,首先我们需要了解一下插件的概念。
|
||||
|
||||
在 NoneBot 中,插件可以是 Python 的一个模块 `module`,也可以是一个包 `package` 。NoneBot 会在导入时对这些模块或包做一些特殊的处理使得他们成为一个插件。插件间应尽量减少耦合,可以进行有限制的插件间调用,NoneBot 能够正确解析插件间的依赖关系。
|
||||
|
||||
下面详细介绍两种插件的结构:
|
||||
|
||||
### 模块插件(单文件形式)
|
||||
|
||||
在合适的路径创建一个 `.py` 文件即可。例如在[创建项目](../create-project.mdx)中创建的项目中,我们可以在 `awesome_bot/plugins/` 目录中创建一个文件 `foo.py`。
|
||||
|
||||
```tree title=Project {4}
|
||||
📦 AweSome-Bot
|
||||
├── 📂 awesome_bot
|
||||
│ └── 📂 plugins
|
||||
| └── 📜 foo.py
|
||||
├── 📜 .env
|
||||
├── 📜 .env.dev
|
||||
├── 📜 .env.prod
|
||||
├── 📜 .gitignore
|
||||
├── 📜 bot.py
|
||||
├── 📜 docker-compose.yml
|
||||
├── 📜 Dockerfile
|
||||
├── 📜 pyproject.toml
|
||||
└── 📜 README.md
|
||||
```
|
||||
|
||||
这个时候它已经可以被称为一个插件了,尽管它还什么都没做。
|
||||
|
||||
### 包插件(文件夹形式)
|
||||
|
||||
在合适的路径创建一个文件夹,并在文件夹内创建文件 `__init__.py` 即可。例如在[创建项目](../create-project.mdx)中创建的项目中,我们可以在 `awesome_bot/plugins/` 目录中创建一个文件夹 `foo`,并在这个文件夹内创建一个文件 `__init__.py`。
|
||||
|
||||
```tree title=Project {4,5}
|
||||
📦 AweSome-Bot
|
||||
├── 📂 awesome_bot
|
||||
│ └── 📂 plugins
|
||||
| └── 📂 foo
|
||||
| └── 📜 __init__.py
|
||||
├── 📜 .env
|
||||
├── 📜 .env.dev
|
||||
├── 📜 .env.prod
|
||||
├── 📜 .gitignore
|
||||
├── 📜 bot.py
|
||||
├── 📜 docker-compose.yml
|
||||
├── 📜 Dockerfile
|
||||
├── 📜 pyproject.toml
|
||||
└── 📜 README.md
|
||||
```
|
||||
|
||||
这个时候 `foo` 就是一个合法的 Python 包了,同时也是合法的 NoneBot 插件,插件内容可以在 `__init__.py` 中编写。
|
||||
|
||||
## 创建插件
|
||||
|
||||
:::danger 警告
|
||||
请注意,插件名称不能存在重复,即所有模块插件的文件名和所有包插件的文件夹名不能存在相同。
|
||||
:::
|
||||
|
||||
除了通过手动创建的方式以外,还可以通过 nb-cli 来创建插件,nb-cli 会为你在合适的位置创建一个模板包插件。
|
||||
|
||||
```bash
|
||||
nb plugin create
|
||||
```
|
@ -0,0 +1,106 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
description: 通过不同方式加载插件
|
||||
|
||||
options:
|
||||
menu:
|
||||
weight: 25
|
||||
category: guide
|
||||
---
|
||||
|
||||
# 加载插件
|
||||
|
||||
:::danger 警告
|
||||
请勿在插件被加载前 `import` 插件模块,这会导致 NoneBot2 无法将其转换为插件而损失部分功能。
|
||||
:::
|
||||
|
||||
加载插件通常在机器人的入口文件进行,例如在[创建项目](../create-project.mdx)中创建的项目中的 `bot.py` 文件。在 NoneBot2 初始化完成后即可加载插件。
|
||||
|
||||
```python title=bot.py {5}
|
||||
import nonebot
|
||||
|
||||
nonebot.init()
|
||||
|
||||
# load your plugin here
|
||||
|
||||
nonebot.run()
|
||||
```
|
||||
|
||||
加载插件的方式有多种,但在底层的加载逻辑是一致的。以下是为加载插件提供的几种方式:
|
||||
|
||||
## `load_plugin`
|
||||
|
||||
通过点分割模块名称来加载插件,通常用于加载单个插件或者是第三方插件。例如:
|
||||
|
||||
```python
|
||||
nonebot.load_plugin("path.to.your.plugin")
|
||||
```
|
||||
|
||||
## `load_plugins`
|
||||
|
||||
加载传入插件目录中的所有插件,通常用于加载一系列本地编写的插件。例如:
|
||||
|
||||
```python
|
||||
nonebot.load_plugins("src/plugins", "path/to/your/plugins")
|
||||
```
|
||||
|
||||
:::warning 警告
|
||||
请注意,插件所在目录应该为相对机器人入口文件可导入的,例如与入口文件在同一目录下。
|
||||
:::
|
||||
|
||||
## `load_all_plugins`
|
||||
|
||||
这种加载方式是以上两种方式的混合,加载所有传入的插件模块名称,以及所有给定目录下的插件。例如:
|
||||
|
||||
```python
|
||||
nonebot.load_all_plugins(["path.to.your.plugin"], ["path/to/your/plugins"])
|
||||
```
|
||||
|
||||
## `load_from_json`
|
||||
|
||||
通过 JSON 文件加载插件,是 [`load_all_plugins`](#load_all_plugins) 的 JSON 变种。通过读取 JSON 文件中的 `plugins` 字段和 `plugin_dirs` 字段进行加载。例如:
|
||||
|
||||
```json title=plugin_config.json
|
||||
{
|
||||
"plugins": ["path.to.your.plugin"],
|
||||
"plugin_dirs": ["path/to/your/plugins"]
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
nonebot.load_from_json("plugin_config.json", encoding="utf-8")
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
如果 JSON 配置文件中的字段无法满足你的需求,可以使用 [`load_all_plugins`](#load_all_plugins) 方法自行读取配置来加载插件。
|
||||
:::
|
||||
|
||||
## `load_from_toml`
|
||||
|
||||
通过 TOML 文件加载插件,是 [`load_all_plugins`](#load_all_plugins) 的 TOML 变种。通过读取 TOML 文件中的 `[tool.nonebot]` Table 中的 `plugins` 和 `plugin_dirs` Array 进行加载。例如:
|
||||
|
||||
```toml title=plugin_config.toml
|
||||
[tool.nonebot]
|
||||
plugins = ["path.to.your.plugin"]
|
||||
plugin_dirs = ["path/to/your/plugins"]
|
||||
```
|
||||
|
||||
```python
|
||||
nonebot.load_from_toml("plugin_config.toml", encoding="utf-8")
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
如果 TOML 配置文件中的字段无法满足你的需求,可以使用 [`load_all_plugins`](#load_all_plugins) 方法自行读取配置来加载插件。
|
||||
:::
|
||||
|
||||
## `load_builtin_plugin`
|
||||
|
||||
加载一个内置插件,是 [`load_plugin`](#load_plugin) 的封装。例如:
|
||||
|
||||
```python
|
||||
nonebot.load_builtin_plugin("echo")
|
||||
```
|
||||
|
||||
## 嵌套插件
|
||||
|
||||
<!-- TODO -->
|
@ -0,0 +1,146 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
description: 使用事件响应器操作,改变事件处理流程
|
||||
|
||||
options:
|
||||
menu:
|
||||
weight: 28
|
||||
category: guide
|
||||
---
|
||||
|
||||
# 事件响应器操作
|
||||
|
||||
在事件处理流程中,我们可以使用事件响应器操作来进行一些交互或改变事件处理流程。
|
||||
|
||||
## send
|
||||
|
||||
向用户回复一条消息。回复的方式或途径由协议适配器自行实现。
|
||||
|
||||
可以是 `str`、[`Message`](../../api/adapters/index.md#Message)、[`MessageSegment`](../../api/adapters/index.md#MessageSegment) 或 [`MessageTemplate`](../../api/adapters/index.md#MessageTemplate)。
|
||||
|
||||
这个操作等同于使用 `bot.send(event, message, **kwargs)` 但不需要自行传入 `event`。
|
||||
|
||||
```python {3}
|
||||
@matcher.handle()
|
||||
async def _():
|
||||
await matcher.send("Hello world!")
|
||||
```
|
||||
|
||||
## finish
|
||||
|
||||
向用户回复一条消息(可选),并立即结束当前事件的整个处理流程。
|
||||
|
||||
参数与 [`send`](#send) 相同。
|
||||
|
||||
```python {3}
|
||||
@matcher.handle()
|
||||
async def _():
|
||||
await matcher.finish("Hello world!")
|
||||
# something never run
|
||||
...
|
||||
```
|
||||
|
||||
## pause
|
||||
|
||||
向用户回复一条消息(可选),并立即结束当前事件处理依赖并等待接收一个新的事件后进入下一个事件处理依赖。
|
||||
|
||||
类似于 `receive` 的行为但可以根据事件来决定是否接收新的事件。
|
||||
|
||||
```python {4}
|
||||
@matcher.handle()
|
||||
async def _():
|
||||
if serious:
|
||||
await matcher.pause("Confirm?")
|
||||
|
||||
@matcher.handle()
|
||||
async def _():
|
||||
...
|
||||
```
|
||||
|
||||
## reject
|
||||
|
||||
向用户回复一条消息(可选),并立即结束当前事件处理依赖并等待接收一个新的事件后再次执行当前事件处理依赖。
|
||||
|
||||
通常用于拒绝当前 `receive` 接收的事件或 `got` 接收的参数(如:不符合格式或标准)。
|
||||
|
||||
```python {4}
|
||||
@matcher.got("arg")
|
||||
async def _(arg: str = ArgPlainText()):
|
||||
if not is_valid(arg):
|
||||
await matcher.reject("Invalid arg!")
|
||||
```
|
||||
|
||||
## reject_arg
|
||||
|
||||
向用户回复一条消息(可选),并立即结束当前事件处理依赖并等待接收一个新的事件后再次执行当前事件处理依赖。
|
||||
|
||||
用于拒绝指定 `got` 接收的参数,通常在嵌套装饰器时使用。
|
||||
|
||||
```python {4}
|
||||
@matcher.got("a")
|
||||
@matcher.got("b")
|
||||
async def _(a: str = ArgPlainText(), b: str = ArgPlainText()):
|
||||
if a not in b:
|
||||
await matcher.reject_arg("a", "Invalid a!")
|
||||
```
|
||||
|
||||
## reject_receive
|
||||
|
||||
向用户回复一条消息(可选),并立即结束当前事件处理依赖并等待接收一个新的事件后再次执行当前事件处理依赖。
|
||||
|
||||
用于拒绝指定 `receive` 接收的事件,通常在嵌套装饰器时使用。
|
||||
|
||||
```python {4}
|
||||
@matcher.receive("a")
|
||||
@matcher.receive("b")
|
||||
async def _(a: Event = Received("a"), b: Event = Received("b")):
|
||||
if a.get_user_id() != b.get_user_id():
|
||||
await matcher.reject_receive("a")
|
||||
```
|
||||
|
||||
## skip
|
||||
|
||||
立即结束当前事件处理依赖,进入下一个事件处理依赖。
|
||||
|
||||
通常在子依赖中使用,用于跳过当前事件处理依赖的执行。
|
||||
|
||||
```python {2}
|
||||
async def dependency(matcher: Matcher):
|
||||
matcher.skip()
|
||||
|
||||
|
||||
@matcher.handle()
|
||||
async def _(sub=Depends(dependency)):
|
||||
# never run
|
||||
...
|
||||
```
|
||||
|
||||
## get_receive
|
||||
|
||||
获取一个 `receive` 接收的事件。
|
||||
|
||||
## set_receive
|
||||
|
||||
设置/覆盖一个 `receive` 接收的事件。
|
||||
|
||||
## get_last_receive
|
||||
|
||||
获取最近一次 `receive` 接收的事件。
|
||||
|
||||
## get_arg
|
||||
|
||||
获取一个 `got` 接收的参数。
|
||||
|
||||
## set_arg
|
||||
|
||||
设置/覆盖一个 `got` 接收的参数。
|
||||
|
||||
## stop_propagation
|
||||
|
||||
阻止事件向更低优先级的事件响应器传播。
|
||||
|
||||
```python
|
||||
@foo.handle()
|
||||
async def _(matcher: Matcher):
|
||||
matcher.stop_propagation()
|
||||
```
|
Reference in New Issue
Block a user