回调函数
约 2188 字大约 7 分钟
2025-02-07
什么是回调函数
NcatBot 采用回调函数机制来完成事件上报. 当对应事件发生时, NcatBot 会调用这些函数, 并将事件相关信息作为参数传递.
NcatBot 的所有回调函数都只有一个参数, 用于传递所发生事件的信息, 典型的回调函数如下:
def on_xxx_event(msg: BaseMessage): # 同步回调函数
do_something()
从 3.7.0 版本开始, 所有回调函数可以定义为同步函数, 但仍然建议使用异步回调函数.
注册回调函数
回调函数可以通过两种方式注册.
通过修饰器注册回调函数
在回调函数的上一行, 加上回调函数注册修饰器(@bot.xxxx_event()
)来明确回调函数所绑定的 BotClient
实例以及事件类型.
@bot.private_event() # 为 bot 的私聊事件注册回调函数
async def on_private_message(msg: PrivateMessage):
_log.info(msg)
if msg.raw_message == '测试':
await bot.api.post_private_msg(msg.user_id, text="NcatBot 测试成功喵~")
Ncatbot 对回调函数的名字没有要求, 但按照习惯一般命名为 on_[事件类型]
。
回调函数注册修饰器一共有四个,分别是:
BotClient.group_event()
BotClient.private_event()
BotClient.notice_event()
BotClient.request_event()
它们所管辖的事件参考回调函数参数。
提示
注意修饰器的写法,由于历史原因,应写作 bot.group_event()
而不是 bot.group_event
。
通过成员函数添加回调函数(推荐)
BotClient
具有以下成员函数, 用于为相应事件添加回调函数:
class BotClient:
def add_startup_handler(self, func): # 添加启动事件回调函数, 当 Bot 上线(能够收发消息时) 触发
pass # 所有实现略去
def add_group_event_handler(self, func): # 添加群聊事件回调函数, 当收到群聊消息时触发
pass
def add_private_event_handler(self, func): # 添加私聊事件回调函数, 当收到私聊消息时触发
pass
def add_notice_event_handler(self, func): # 添加通知事件回调函数, 当收到通知消息时触发
pass
def add_request_event_handler(self, func): # 添加请求事件回调函数, 当收到请求消息时触发
pass
通过修饰器注册参数时, 由于 Python 传参机制的问题, 无法正确调用类的成员函数. 使用 BotClient
的成员函数添加回调函数, 可以正确调用类的成员函数并传递实例参数.
Bot 启动事件的回调函数
特别的, Bot 启动事件的回调函数只支持通过成员函数添加.
例如:
bot.add_startup_event_handler(lambda: print("NcatBot 启动成功喵~"))
bot.run()
将在 Bot 登录完成可以收发消息后输出 NcatBot 启动成功喵~
.
回调函数参数
所有的回调函数调用时只传递一个参数, 对于类的成员函数, 使用 BotClient.add_xxx_handler
添加时会自动绑定 self
参数, 因此能够正确调用.
调用回调函数时的传参描述了事件的详细信息, 那么如何解析这个参数呢?
Startup 类型回调函数参数
Startup 类型事件不传参, 插件事件的 Event.data
为 None.
Message 类型回调函数参数
此类型包括群聊消息和私聊消息.
@bot.group_event()
async def on_group_message(msg: GroupMessage):
_log.info(msg)
下面给出简介, 详细信息移步解析消息
调用时的传参 msg
是一个 BaseMessage
的派生类, 其成员均符合 OneBot11 标准.
msg
的主要成员表如下:
msg.user_id: Union(str, int)
: 消息发送者 QQ 号.msg.group_id: Union(str, int)
: 消息来源群群号(如果是群聊消息).msg.message_id: Union(str, int)
: 消息 ID.msg.message_type: str
: 消息类型(group
/private
), 群聊或私聊msg.raw_message: str
: 符合 OneBot11 标准的消息字符串, 需手动解析, 不建议使用.msg.sender: Sender
: 消息发送者实例。msg.message: List[dict]
: 符合 OneBot11 标准的数组格式消息, 推荐使用它来进行逻辑判断.msg.self_id: Union(str, int)
: 机器人 QQ 号.msg.time: int
: 事件发生时间戳.
Notice 类型回调函数参数
注意
Notice 事件未来可能被更加精细粒度的事件替代.
传入的 msg
是一个 dict
, 支持的操作见 NapCat 文档.
以下给出几个常见的事件:
私聊消息撤回
参数示例及其解释:
msg = {
"time": 1743865655, # UNIX 时间戳
"self_id": 123456, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"notice_type": "friend_recall", # 通知类型, 消息撤回固定为 `friend_recall`
"user_id": 12345678, # 撤回者 QQ 号
"message_id": 680308254 # 撤回的消息 ID
}
头像双击动作
参数示例及其解释:
msg = {
"time": 1743865776, # UNIX 时间戳
"self_id": 123456, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"notice_type": "poke", # 通知类型, 头像双击动作固定为 `poke`
"sub_type": "double", # 事件子类型, 头像双击动作固定为 `double`
"target_id": 123456, # 被双击的 QQ 号
"user_id": 12345678, # 操作者 QQ 号
"raw_info": [
{'col': '1', 'nm': '', 'type': 'qq', 'uid': 'u_-ev35gBX6zud3K0yA_nskA'}, # 发送者的 QQ 链接
{'jp': 'https://zb.vip.qq.com/v2/pages/nudgeMall?_wv=2&actionId=0', 'src': 'http://tianquan.gtimg.cn/nudgeaction/item/0/expression.jpg', 'type': 'img'}, # 图标
{'txt': '戳了戳', 'type': 'nor'}, # 文本
{'col': '1', 'nm': '', 'tp': '0', 'type': 'qq', 'uid': 'u_sbV_ToZLelyJ73PGan2F-A'}, # 操作者的 QQ 链接
{'txt': '', 'type': 'nor'} # 我不知道这是啥
],
'sender_id': 12345678
}
私聊输入状态更新
参数示例及其解释:
msg = {
"time": 1743866213, # UNIX 时间戳
"self_id": 123456, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"notice_type": "notify", # 通知类型, 输入状态更新固定为 `notify`
"sub_type": "input_status", # 事件子类型, 输入状态更新固定为 `input_status`
"status_text": "对方正在输入...", # 输入状态文本
"event_type": 2, # 输入状态类型, 1 为开始输入, 2 为继续输入
"user_id": 12345678, # 操作者 QQ 号
"group_id": 0 # 群号
}
群成员增加
参数示例及其解释:
msg = {
"time": 1609478707, # UNIX 时间戳
"self_id": 123456789, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"notice_type": "group_increase", # 通知类型, 加群通知固定为 `group_increase`
"sub_type": "approve", # 事件子类型, 管理员同意为 `approve`, 管理员邀请为 `invite`
"group_id": 123456789, # 群号
"operator_id": 987654321, # 操作者 QQ 号
"user_id": 987654321, # 加入者 QQ 号
}
群成员减少
参数示例及其解释:
msg = {
"time": 1609478707, # UNIX 时间戳
"self_id": 123456789, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"notice_type": "group_decrease", # 通知类型, 群成员减少固定为 `group_decrease`
"sub_type": "leave", # 事件子类型, 主动退群为 `leave`, 被踢为 `kick`, Bot 被踢为 `kick_me`
"group_id": 123456789, # 群号
"operator_id": 987654321, # 操作者 QQ 号
"user_id": 987654321, # 离开者 QQ 号
}
禁言相关
参数示例及其解释:
msg = {
"time": 1609478707, # UNIX 时间戳
"self_id": 123456789, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"notice_type": "group_ban", # 通知类型, 群禁言固定为 `group_ban`
"sub_type": "ban", # 事件子类型, 群禁言固定为 `ban`, 解除禁言固定为 `lift_ban`
"group_id": 123456789, # 群号
"operator_id": 987654321, # 操作者 QQ 号
"user_id": 987654321, # 被禁言 QQ 号
"duration": 300 # 禁言时长, 单位秒
}
群文件上传
传入的参数示例及其解释:
msg = {
"time": 1743864886, # UNIX 时间戳
"self_id": 123456, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"group_id": 701784439, # 群号
"user_id": 12345678, # 上传者 QQ 号
"file": {
"id": "24f852ab9a17d7d5dc790b9262092189", # 文件 ID
"name": "文件名", # 文件名
"size": 114514, # 文件大小
"busid": 114 # 文件 busid
}
}
要获取上传的文件, 需要使用 BotAPI.get_file()
方法, 传入 msg["file"]["id"]
作为参数即可.
群消息撤回
传入的参数示例及其解释:
msg = {
"time": 1743865071, # UNIX 时间戳
"self_id": 123456, # 机器人 QQ 号
"post_type": "notice", # 通知类型, 通知类型固定为 `notice`
"group_id": 701784439, # 群号
"user_id": 12345678, # 撤回消息发送者 QQ 号
"notice_type": "group_recall" # 通知类型, 撤回消息固定为 `group_recall`
"operator_id": 12345678, # 操作者 QQ 号
"message_id": 364573752 # 撤回的消息 ID
}
Request 类型回调函数参数
Request 类型一般用于处理好友添加请求或者处理群聊加入请求。
@bot.request_event()
def on_request(msg: Request):
msg.reply_sync(False, "No") # 拒绝请求
传入的 msg
是一个 ncatbot.core.request.Request
对象,其原型如下:
class Request():
"""请求事件, 部分实现省略"""
__slots__ = (
"time", # UNIX 时间戳
"self_id", # 机器人 QQ 号
"request_type", # 请求类型, 加群为 `group`, 加好友为 `friend`
"sub_type", # 子类型, 支持 `add` 和 `invite`, 前者是主动添加, 后者是接受邀请
"group_id", # 群聊 QQ 号, 如果是好友申请, 为 None
"user_id", # 请求者 QQ 号
"comment", # 验证信息
"flag", # flag, 通过请求时应该提供
)
def is_friend_add(self):
return self.request_type == "friend"
def is_group_add(self):
return self.request_type == "group"
async def reply(self, accept: bool = True, comment: str = ""):
pass
def reply_sync(self, accept: bool = True, comment: str = ""):
pass
一般直接使用 reply
或者 reply_sync
方法处理即可.
版权所有
版权归属:huan-yp