事件响应器进阶
在指南与深入中,我们已经介绍了事件响应器的基本用法以及响应规则、权限控制等功能。在这一节中,我们将介绍事件响应器的组成,内置的响应规则,与第三方响应规则拓展。
事件响应器允许继承,你可以通过直接继承 Matcher
类来创建一个新的事件响应器。
事件响应器组成
事件响应器类型
事件响应器类型 type
即是该响应器所要响应的事件类型,只有在接收到的事件类型与该响应器的类型相同时,才会触发该响应器。如果类型为空字符串 ""
,则响应器将会响应所有类型的事件。事件响应器类型的检查在所有其他检查(权限控制、响应规则)之前进行。
NoneBot 内置了四种常用事件类型:meta_event
、message
、notice
、request
,分别对应元事件、消息、通知、请求。通常情况下,协议适配器会将事件合理地分类至这四种类型中。如果有其他类型的事件需要响应,可以自行定义新的类型。
事件触发权限
事件触发权限 permission
是一个 Permission
对象,这在权限控制一节中已经介绍过。事件触发权限会在事件响应器的类型检查通过后进行检查,如果权限检查通过,则执行响应规则检查。
事件响应规则
事件响应规则 rule
是一个 Rule
对象,这在响应规则一节中已经介绍过。事件响应器的响应规则会在事件响应器的权限检查通过后进行匹配,如果响应规则检查通过,则触发该响应器。
响应优先级
响应优先级 priority
是一个正整数,用于指定响应器的优先级。响应器的优先级越小,越先被触发。如果响应器的优先级相同,则按照响应器的注册顺序进行触发。
阻断
阻断 block
是一个布尔值,用于指定响应器是否阻断事件的传播。如果阻断为 True
,则在该响应器被触发后,事件将不会再传播给其他下一优先级的响应器。
NoneBot 内置的事件响应器中,所有非 command
规则的 message
类型的事件响应器都会阻断事件传递,其他则不会。
在部分情况中,可以使用 stop_propagation
方法动态阻止事件传播,该方法需要 handler 在参数中获取 matcher 实例后调用方法。
有效期
事件响应器的有效期分为 temp
和 expire_time
。temp
是一个布尔值,用于指定响应器是否为临时响应器。如果为 True
,则该响应器在被触发后会被自动销毁。expire_time
是一个 datetime
对象,用于指定响应器的过期时间。如果 expire_time
不为 None
,则在该时间点后,该响应器会被自动销毁。
默认状态
事件响应器的默认状态 default_state
是一个 dict
对象,用于指定响应器的默认状态。在响应器被触发时,响应器将会初始化默认状态然后开始执行事件处理流程。
基本辅助函数
NoneBot 为四种类型的事件响应器提供了五个基本的辅助函数:
on
:创建任何类型的事件响应器。on_metaevent
:创建元事件响应器。on_message
:创建消息事件响应器。on_request
:创建请求事件响应器。on_notice
:创建通知事件响应器。
除了 on
函数具有一个 type
参数外,其余参数均相同:
rule
:响应规则,可以是Rule
对象或者RuleChecker
函数。permission
:事件触发权限,可以是Permission
对象或者PermissionChecker
函数。handlers
:事件处理函数列表。temp
:是否为临时响应器。expire_time
:响应器的过期时间。priority
:响应器的优先级。block
:是否阻断事件传播。state
:响应器的默认状态。
在消息类型的事件响应器的基础上,NoneBot 还内置了一些常用的响应规则,并结合为辅助函数来方便我们快速创建指定功能的响应器。下面我们逐个介绍。
内置响应规则
响应规则的使用方法可以参考 深入 - 响应规则。
startswith
startswith
响应规则用于匹配消息纯文本部分的开头是否与指定字符串(或一系列字符串)相同。可选参数 ignorecase
用于指定是否忽略大小写,默认为 False
。
例如,我们可以创建一个匹配消息开头为 !
或者 /
的规则:
from nonebot.rule import startswith
rule = startswith(("!", "/"), ignorecase=False)
也可以直接使用辅助函数新建一个响应器:
from nonebot import on_startswith
matcher = on_startswith(("!", "/"), ignorecase=False)
endswith
endswith
响应规则用于匹配消息纯文本部分的结尾是否与指定字符串(或一系列字符串)相同。可选参数 ignorecase
用于指定是否忽略大小写,默认为 False
。
例如,我们可以创建一个匹配消息结尾为 .
或者 。
的规则:
from nonebot.rule import endswith
rule = endswith((".", "。"), ignorecase=False)
也可以直接使用辅助函数新建一个响应器:
from nonebot import on_endswith
matcher = on_endswith((".", "。"), ignorecase=False)
fullmatch
fullmatch
响应规则用于匹配消息纯文本部分是否与指定字符串(或一系列字符串)完全相同。可选参数 ignorecase
用于指定是否忽略大小写,默认为 False
。
例如,我们可以创建一个匹配消息为 ping
或者 pong
的规则:
from nonebot.rule import fullmatch
rule = fullmatch(("ping", "pong"), ignorecase=False)
也可以直接使用辅助函数新建一个响应器:
from nonebot import on_fullmatch
matcher = on_fullmatch(("ping", "pong"), ignorecase=False)
keyword
keyword
响应规则用于匹配消息纯文本部分是否包含指定字符串(或一系列字符串)。
例如,我们可以创建一个匹配消息中包含 hello
或者 hi
的规则:
from nonebot.rule import keyword
rule = keyword("hello", "hi")
也可以直接使用辅助函数新建一个响应器:
from nonebot import on_keyword
matcher = on_keyword({"hello", "hi"})
command
command
是最常用的响应规则,它用于匹配消息是否为命令。它会根据配置中的 Command Start 和 Command Separator 来判断消息是否为命令。
例如,当我们配置了 Command Start
为 /
,Command Separator
为 .
时:
from nonebot.rule import command
# 匹配 "/help" 或者 "/帮助" 开头的消息
rule = command("help", "帮助")
# 匹配 "/help.cmd" 开头的消息
rule = command(("help", "cmd"))
也可以直接使用辅助函数新建一个响应器:
from nonebot import on_command
matcher = on_command("help", aliases={"帮助"})
此外,command
响应规则默认允许消息命令与参数 间不加空格,如果需要严格匹配命令与参数间的空白符,可以使用 command
函数的 force_whitespace
参数。force_whitespace
参数可以是 bool 类型或者具体的字符串,默认为 False
。如果为 True
,则命令与参数间必须有任意个数的空白符;如果为字符串,则命令与参数间必须有且与给定字符串一致的空白符。
rule = command("help", force_whitespace=True)
rule = command("help", force_whitespace=" ")
命令解析后的结果可以通过 Command
、RawCommand
、CommandArg
、CommandStart
、CommandWhitespace
依赖注入获取。
shell_command
shell_command
响应规则用于匹配类 shell 命令形式的消息。它首先与 command
响应规则一样进行命令匹配,如果匹配成功,则会进行进一步的参数解析。参数解析采用 argparse
标准库进行,在此基础上添加了消息序列 Message
支持。
例如,我们可以创建一个匹配 /cmd
命令并且带有 -v
选项与默认 -h
帮助选项的规则:
from nonebot.rule import shell_command, ArgumentParser
parser = ArgumentParser()
parser.add_argument("-v", "--verbose", action="store_true")
rule = shell_command("cmd", parser=parser)
更多关于 argparse
的使用方法请参考 argparse 文档。我们也可以选择不提供 parser
参数,这样 shell_command
将不会解析参数,但会提供参数列表 argv
。
直接使用辅助函数新建一个响应器:
from nonebot import on_shell_command
from nonebot.rule import ArgumentParser
parser = ArgumentParser()
parser.add_argument("-v", "--verbose", action="store_true")
matcher = on_shell_command("cmd", parser=parser)
参数解析后的结果可以通过 ShellCommandArgv
、ShellCommandArgs
依赖注入获取。
regex
regex
响应规则用于匹配消息是否与指定正则表达式匹配。
正则表达式匹配使用 search 而非 match,如需从头匹配请使用 r"^xxx"
模式来确保匹配开头。
例如,我们可以创建一个匹配消息中包含字母并且忽略大小写的规则:
from nonebot.rule import regex
rule = regex(r"[a-z]+", flags=re.IGNORECASE)
也可以直接使用辅助函数新建一个响应器:
from nonebot import on_regex
matcher = on_regex(r"[a-z]+", flags=re.IGNORECASE)
正则匹配后的结果可以通过 RegexStr
、RegexGroup
、RegexDict
依赖注入获取。
to_me
to_me
响应规则用于匹配事件是否与机器人相关。
例如:
from nonebot.rule import to_me
rule = to_me()
is_type
is_type
响应规则用于匹配事件类型是否为指定类型(或者一系列类型)。
例如,我们可以创建一个匹配 OneBot v11 私聊和群聊消息事件的规则:
from nonebot.rule import is_type
from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent
rule = is_type(PrivateMessageEvent, GroupMessageEvent)
响应器组
为了更方便的管理一系列功能相近的响应器,NoneBot 提供了两种响应器组,它们可以帮助我们进行响应器的统一管理。
CommandGroup
CommandGroup
可以用于管理一系列具有相同前置命令的子命令响应器。
例如,我们创建 /cmd
、/cmd.sub
、/cmd.help
三个命令,他们具有相同的优先级:
from nonebot import CommandGroup
group = CommandGroup("cmd", priority=10)
cmd = group.command(tuple())
sub_cmd = group.command("sub")
help_cmd = group.command("help")
命令别名 aliases 默认不会添加 CommandGroup
设定的前缀,如果需要为 aliases 添加前缀,可以添加 prefix_aliases=True
参数:
from nonebot import CommandGroup
group = CommandGroup("cmd", prefix_aliases=True)
cmd = group.command(tuple())
help_cmd = group.command("help", aliases={"帮助"})
这样就能成功匹配 /cmd
、/cmd.help
、/cmd.帮助
命令。如果未设置,将默认匹配 /cmd
、/cmd.help
、/帮助
命令。
MatcherGroup
MatcherGroup
可以用于管理一系列具有相同属性的响应器。
例如,我们创建一个具有相同响应规则的响应器组:
from nonebot.rule import to_me
from nonebot import MatcherGroup
group = MatcherGroup(rule=to_me())
matcher1 = group.on_message()
matcher2 = group.on_message()