📝 update doc

This commit is contained in:
yanyongyu 2020-12-31 17:58:09 +08:00
parent 938b5bf275
commit 49201f5346
28 changed files with 552 additions and 1116 deletions

View File

@ -111,6 +111,12 @@ module.exports = context => ({
"creating-a-handler",
"end-or-start"
]
},
{
title: "协议适配",
collapsable: false,
sidebar: "auto",
children: ["cqhttp-guide", "ding-guide"]
}
],
"/advanced/": [

View File

@ -1 +1 @@
# 重载事件处理函数
# 事件处理函数重载

View File

@ -174,6 +174,98 @@ await bot.send_msg(message="hello world")
## _class_ `MessageSegment`
基类:`abc.ABC`
消息段基类
### `type`
* 类型: `str`
* 说明: 消息段类型
### `data`
* 类型: `Dict[str, Union[str, list]]`
* 说明: 消息段数据
## _class_ `Message`
基类:`list`, `abc.ABC`
消息数组
### `__init__(message=None, *args, **kwargs)`
* **参数**
* `message: Union[str, list, dict, MessageSegment, Message, Any]`: 消息内容
### `append(obj)`
* **说明**
添加一个消息段到消息数组末尾
* **参数**
* `obj: Union[str, MessageSegment]`: 要添加的消息段
### `extend(obj)`
* **说明**
拼接一个消息数组或多个消息段到消息数组末尾
* **参数**
* `obj: Union[Message, Iterable[MessageSegment]]`: 要添加的消息数组
### `reduce()`
* **说明**
缩减消息数组,即按 MessageSegment 的实现拼接相邻消息段
### `extract_plain_text()`
* **说明**
提取消息内纯文本消息
## _class_ `Event`
基类:`abc.ABC`, `pydantic.main.BaseModel`
@ -329,95 +421,3 @@ Event 基类。提供获取关键信息的方法,其余信息可直接获取
* `bool`
## _class_ `MessageSegment`
基类:`abc.ABC`
消息段基类
### `type`
* 类型: `str`
* 说明: 消息段类型
### `data`
* 类型: `Dict[str, Union[str, list]]`
* 说明: 消息段数据
## _class_ `Message`
基类:`list`, `abc.ABC`
消息数组
### `__init__(message=None, *args, **kwargs)`
* **参数**
* `message: Union[str, list, dict, MessageSegment, Message, Any]`: 消息内容
### `append(obj)`
* **说明**
添加一个消息段到消息数组末尾
* **参数**
* `obj: Union[str, MessageSegment]`: 要添加的消息段
### `extend(obj)`
* **说明**
拼接一个消息数组或多个消息段到消息数组末尾
* **参数**
* `obj: Union[Message, Iterable[MessageSegment]]`: 要添加的消息数组
### `reduce()`
* **说明**
缩减消息数组,即按 MessageSegment 的实现拼接相邻消息段
### `extract_plain_text()`
* **说明**
提取消息内纯文本消息

View File

@ -5,6 +5,12 @@ sidebarDepth: 0
# NoneBot.adapters.cqhttp 模块
## CQHTTP (OneBot) v11 协议适配
协议详情请看: [CQHTTP](https://github.com/howmanybots/onebot/blob/master/README.md) | [OneBot](https://github.com/howmanybots/onebot/blob/master/README.md)
# NoneBot.adapters.cqhttp.utils 模块
## `escape(s, *, escape_comma=True)`
@ -40,10 +46,7 @@ sidebarDepth: 0
* `s: str`: 需要转义的字符串
## _exception_ `CQHTTPAdapterException`
基类:[`nonebot.exception.AdapterException`](../exception.md#nonebot.exception.AdapterException)
# NoneBot.adapters.cqhttp.exception 模块
## _exception_ `ActionFailed`
@ -81,10 +84,7 @@ sidebarDepth: 0
* `retcode: Optional[int]`: 错误码
## _exception_ `ApiNotAvailable`
基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException`
# NoneBot.adapters.cqhttp.bot 模块
## _async_ `_check_reply(bot, event)`
@ -285,6 +285,8 @@ CQHTTP 协议 Bot 适配。继承属性参考 [BaseBot](./#class-basebot) 。
* `ActionFailed`: API 调用失败
# NoneBot.adapters.cqhttp.message 模块
## _class_ `MessageSegment`
@ -299,140 +301,68 @@ CQHTTP 协议 MessageSegment 适配。具体方法参考协议消息段类型或
CQHTTP 协议 Message 适配。
# NoneBot.adapters.cqhttp.permission 模块
## `PRIVATE`
* **说明**: 匹配任意私聊消息类型事件
## `PRIVATE_FRIEND`
* **说明**: 匹配任意好友私聊消息类型事件
## `PRIVATE_GROUP`
* **说明**: 匹配任意群临时私聊消息类型事件
## `PRIVATE_OTHER`
* **说明**: 匹配任意其他私聊消息类型事件
## `GROUP`
* **说明**: 匹配任意群聊消息类型事件
## `GROUP_MEMBER`
* **说明**: 匹配任意群员群聊消息类型事件
:::warning 警告
该权限通过 event.sender 进行判断且不包含管理员以及群主!
:::
## `GROUP_ADMIN`
* **说明**: 匹配任意群管理员群聊消息类型事件
## `GROUP_OWNER`
* **说明**: 匹配任意群主群聊消息类型事件
# NoneBot.adapters.cqhttp.event 模块
## _class_ `Event`
基类:[`nonebot.adapters.Event`](README.md#nonebot.adapters.Event)
CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https://github.com/howmanybots/onebot/blob/master/README.md)
### `get_type()`
* **说明**
获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。
* **返回**
* `Literal["message", "notice", "request", "meta_event"]`
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
### `get_event_description()`
* **说明**
获取事件描述的方法,通常为事件具体内容。
* **返回**
* `str`
### `get_message()`
* **说明**
获取事件消息内容的方法。
* **返回**
* `Message`
### `get_plaintext()`
* **说明**
获取消息纯文本的方法,通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
* **返回**
* `str`
### `get_user_id()`
* **说明**
获取事件主体 id 的方法,通常是用户 id 。
* **返回**
* `str`
### `get_session_id()`
* **说明**
获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。
* **返回**
* `str`
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
CQHTTP 协议事件,字段与 CQHTTP 一致。各事件字段参考 [CQHTTP 文档](https://github.com/howmanybots/onebot/blob/master/README.md)
## _class_ `MessageEvent`
@ -472,102 +402,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
### `get_message()`
* **说明**
获取事件消息内容的方法。
* **返回**
* `Message`
### `get_plaintext()`
* **说明**
获取消息纯文本的方法,通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
* **返回**
* `str`
### `get_user_id()`
* **说明**
获取事件主体 id 的方法,通常是用户 id 。
* **返回**
* `str`
### `get_session_id()`
* **说明**
获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。
* **返回**
* `str`
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `PrivateMessageEvent`
基类:`nonebot.adapters.cqhttp.event.MessageEvent`
@ -575,22 +409,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
私聊消息
### `get_event_description()`
* **说明**
获取事件描述的方法,通常为事件具体内容。
* **返回**
* `str`
## _class_ `GroupMessageEvent`
基类:`nonebot.adapters.cqhttp.event.MessageEvent`
@ -598,22 +416,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群消息
### `get_event_description()`
* **说明**
获取事件描述的方法,通常为事件具体内容。
* **返回**
* `str`
## _class_ `NoticeEvent`
基类:`nonebot.adapters.cqhttp.event.Event`
@ -621,22 +423,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
通知事件
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
## _class_ `GroupUploadNoticeEvent`
基类:`nonebot.adapters.cqhttp.event.NoticeEvent`
@ -651,22 +437,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群管理员变动
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `GroupDecreaseNoticeEvent`
基类:`nonebot.adapters.cqhttp.event.NoticeEvent`
@ -674,22 +444,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群成员减少事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `GroupIncreaseNoticeEvent`
基类:`nonebot.adapters.cqhttp.event.NoticeEvent`
@ -697,22 +451,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群成员增加事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `GroupBanNoticeEvent`
基类:`nonebot.adapters.cqhttp.event.NoticeEvent`
@ -720,22 +458,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群禁言事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `FriendAddNoticeEvent`
基类:`nonebot.adapters.cqhttp.event.NoticeEvent`
@ -750,22 +472,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群消息撤回事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `FriendRecallNoticeEvent`
基类:`nonebot.adapters.cqhttp.event.NoticeEvent`
@ -787,22 +493,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
戳一戳提醒事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `LuckyKingNotifyEvent`
基类:`nonebot.adapters.cqhttp.event.NotifyEvent`
@ -810,22 +500,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群红包运气王提醒事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `HonorNotifyEvent`
基类:`nonebot.adapters.cqhttp.event.NotifyEvent`
@ -833,22 +507,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
群荣誉变更提醒事件
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `RequestEvent`
基类:`nonebot.adapters.cqhttp.event.Event`
@ -856,22 +514,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
请求事件
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
## _class_ `FriendRequestEvent`
基类:`nonebot.adapters.cqhttp.event.RequestEvent`
@ -893,45 +535,6 @@ CQHTTP 协议事件。各事件字段未列出部分参考 [CQHTTP 文档](https
元事件
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
### `get_log_string()`
* **说明**
获取事件日志信息的方法,通常你不需要修改这个方法,只有当希望 NoneBot 隐藏该事件日志时,可以抛出 `NoLogException` 异常。
* **返回**
* `str`
* **异常**
* `NoLogException`
## _class_ `LifecycleMetaEvent`
基类:`nonebot.adapters.cqhttp.event.MetaEvent`

View File

@ -5,6 +5,12 @@ sidebarDepth: 0
# NoneBot.adapters.ding 模块
## 钉钉群机器人 协议适配
协议详情请看: [钉钉文档](https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p)
# NoneBot.adapters.ding.exception 模块
## _exception_ `DingAdapterException`
@ -38,11 +44,6 @@ sidebarDepth: 0
## _exception_ `ApiNotAvailable`
基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.ding.exception.DingAdapterException`
## _exception_ `NetworkError`
基类:[`nonebot.exception.NetworkError`](../exception.md#nonebot.exception.NetworkError), `nonebot.adapters.ding.exception.DingAdapterException`
@ -71,6 +72,8 @@ sidebarDepth: 0
发消息的 session 已经过期。
# NoneBot.adapters.ding.bot 模块
## _class_ `Bot`
@ -94,22 +97,6 @@ sidebarDepth: 0
### _async_ `handle_message(message)`
* **说明**
处理上报消息的函数,转换为 `Event` 事件后调用 `nonebot.message.handle_event` 进一步处理事件。
* **参数**
* `message: dict`: 收到的上报消息
### _async_ `call_api(api, event=None, **data)`
@ -190,295 +177,7 @@ sidebarDepth: 0
* `ActionFailed`: API 调用失败
## _class_ `Event`
基类:[`nonebot.adapters.Event`](README.md#nonebot.adapters.Event)
钉钉 协议 Event 适配。各事件字段参考 [钉钉文档](https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p)
### `get_type()`
* **说明**
获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。
* **返回**
* `Literal["message", "notice", "request", "meta_event"]`
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
### `get_event_description()`
* **说明**
获取事件描述的方法,通常为事件具体内容。
* **返回**
* `str`
### `get_message()`
* **说明**
获取事件消息内容的方法。
* **返回**
* `Message`
### `get_plaintext()`
* **说明**
获取消息纯文本的方法,通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
* **返回**
* `str`
### `get_user_id()`
* **说明**
获取事件主体 id 的方法,通常是用户 id 。
* **返回**
* `str`
### `get_session_id()`
* **说明**
获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。
* **返回**
* `str`
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
## _class_ `ConversationType`
基类:`str`, `enum.Enum`
An enumeration.
### `_member_type_`
`builtins.str` 的别名
## _class_ `MessageEvent`
基类:`nonebot.adapters.ding.event.Event`
### `get_type()`
* **说明**
获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。
* **返回**
* `Literal["message", "notice", "request", "meta_event"]`
### `get_event_name()`
* **说明**
获取事件名称的方法。
* **返回**
* `str`
### `get_event_description()`
* **说明**
获取事件描述的方法,通常为事件具体内容。
* **返回**
* `str`
### `get_message()`
* **说明**
获取事件消息内容的方法。
* **返回**
* `Message`
### `get_plaintext()`
* **说明**
获取消息纯文本的方法,通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
* **返回**
* `str`
### `get_user_id()`
* **说明**
获取事件主体 id 的方法,通常是用户 id 。
* **返回**
* `str`
### `get_session_id()`
* **说明**
获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。
* **返回**
* `str`
## _class_ `PrivateMessageEvent`
基类:`nonebot.adapters.ding.event.MessageEvent`
## _class_ `GroupMessageEvent`
基类:`nonebot.adapters.ding.event.MessageEvent`
### `is_tome()`
* **说明**
获取事件是否与机器人有关的方法。
* **返回**
* `bool`
# NoneBot.adapters.ding.message 模块
## _class_ `MessageSegment`
@ -488,13 +187,45 @@ An enumeration.
钉钉 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。
### _static_ `atAll()`
@全体
### _static_ `atMobiles(*mobileNumber)`
@指定手机号人员
### _static_ `text(text)`
发送 `text` 类型消息
### _static_ `image(picURL)`
发送 `image` 类型消息
### _static_ `extension(dict_)`
"标记 text 文本的 extension 属性,需要与 text 消息段相加。
### _static_ `markdown(title, text)`
发送 `markdown` 类型消息
### _static_ `actionCardSingleBtn(title, text, singleTitle, singleURL)`
发送 `actionCardSingleBtn` 类型消息
### _static_ `actionCardMultiBtns(title, text, btns, hideAvatar=False, btnOrientation='1')`
发送 `actionCardMultiBtn` 类型消息
* **参数**
@ -508,6 +239,8 @@ An enumeration.
### _static_ `feedCard(links)`
发送 `feedCard` 类型消息
* **参数**
@ -521,3 +254,40 @@ An enumeration.
基类:[`nonebot.adapters.Message`](README.md#nonebot.adapters.Message)
钉钉 协议 Message 适配。
# NoneBot.adapters.ding.event 模块
## _class_ `Event`
基类:[`nonebot.adapters.Event`](README.md#nonebot.adapters.Event)
钉钉协议事件。各事件字段参考 [钉钉文档](https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p)
## _class_ `ConversationType`
基类:`str`, `enum.Enum`
An enumeration.
## _class_ `MessageEvent`
基类:`nonebot.adapters.ding.event.Event`
消息事件
## _class_ `PrivateMessageEvent`
基类:`nonebot.adapters.ding.event.MessageEvent`
私聊消息事件
## _class_ `GroupMessageEvent`
基类:`nonebot.adapters.ding.event.MessageEvent`
群消息事件

View File

@ -66,53 +66,3 @@ fastapi 使用的 logger
### `run(host=None, port=None, *, app=None, **kwargs)`
使用 `uvicorn` 启动 FastAPI
### _async_ `_handle_http(adapter, request, data=Body(Ellipsis))`
用于处理 HTTP 类型请求的函数
### _async_ `_handle_ws_reverse(adapter, websocket)`
用于处理 WebSocket 类型请求的函数
## _class_ `WebSocket`
基类:[`nonebot.drivers.WebSocket`](README.md#nonebot.drivers.WebSocket)
### _property_ `closed`
* **类型**
`bool`
* **说明**
连接是否已经关闭
### _async_ `accept()`
接受 WebSocket 连接请求
### _async_ `close(code=1000)`
关闭 WebSocket 连接请求
### _async_ `receive()`
接收一条 WebSocket 信息
### _async_ `send(data)`
发送一条 WebSocket 信息

View File

@ -40,16 +40,3 @@ NoneBot 使用 [loguru](https://github.com/Delgan/loguru) 来记录日志信息
```python
from nonebot.log import logger
```
## _class_ `LoguruHandler`
基类:`logging.Handler`
### `emit(record)`
Do whatever it takes to actually log the specified logging record.
This version is intended to be implemented by subclasses and so
raises a NotImplementedError.

View File

@ -229,7 +229,7 @@ sidebarDepth: 0
* **参数**
* `type_: str`: 事件响应器类型,与 `event.type` 一致时触发,空字符串表示任意
* `type_: str`: 事件响应器类型,与 `event.get_type()` 一致时触发,空字符串表示任意
* `rule: Optional[Rule]`: 匹配规则

View File

@ -200,7 +200,7 @@ Rule(async_function, run_sync(sync_function))
* **说明**
通过 `event.to_me` 判断事件是否与机器人有关
通过 `event.is_tome()` 判断事件是否与机器人有关

View File

@ -0,0 +1,78 @@
# CQHTTP 协议使用指南
## 配置 CQHTTP 协议端(以 QQ 为例)
单纯运行 NoneBot 实例并不会产生任何效果,因为此刻 QQ 这边还不知道 NoneBot 的存在,也就无法把消息发送给它,因此现在需要使用一个无头 QQ 来把消息等事件上报给 NoneBot。
QQ 协议端举例:
- [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) (基于 [MiraiGo](https://github.com/Mrs4s/MiraiGo))
- [cqhttp-mirai-embedded](https://github.com/yyuueexxiinngg/cqhttp-mirai/tree/embedded)
- [Mirai](https://github.com/mamoe/mirai) + [cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai)
- [Mirai](https://github.com/mamoe/mirai) + [Mirai Native](https://github.com/iTXTech/mirai-native) + [CQHTTP](https://github.com/richardchien/coolq-http-api)
- [OICQ-http-api](https://github.com/takayama-lily/onebot) (基于 [OICQ](https://github.com/takayama-lily/oicq))
这里以 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 为例
1. 下载 go-cqhttp 对应平台的 release 文件,[点此前往](https://github.com/Mrs4s/go-cqhttp/releases)
2. 运行 exe 文件或者使用 `./go-cqhttp` 启动
3. 生成默认配置文件并修改默认配置
```hjson{2,3,35-36,42}
{
uin: 机器人QQ号
password: 机器人密码
encrypt_password: false
password_encrypted: ""
enable_db: true
access_token: ""
relogin: {
enabled: true
relogin_delay: 3
max_relogin_times: 0
}
_rate_limit: {
enabled: false
frequency: 1
bucket_size: 1
}
ignore_invalid_cqcode: false
force_fragmented: false
heartbeat_interval: 0
http_config: {
enabled: false
host: "0.0.0.0"
port: 5700
timeout: 0
post_urls: {}
}
ws_config: {
enabled: false
host: "0.0.0.0"
port: 6700
}
ws_reverse_servers: [
{
enabled: true
reverse_url: ws://127.0.0.1:8080/cqhttp/ws
reverse_api_url: ws://you_websocket_api.server
reverse_event_url: ws://you_websocket_event.server
reverse_reconnect_interval: 3000
}
]
post_message_format: array
use_sso_address: false
debug: false
log_level: ""
web_ui: {
enabled: false
host: 127.0.0.1
web_ui_port: 9999
web_input: false
}
}
```
其中 `ws://127.0.0.1:8080/cqhttp/ws` 中的 `127.0.0.1``8080` 应分别对应 nonebot 配置的 HOST 和 PORT。
`cqhttp` 是前述 `register_adapter` 时传入的第一个参数,代表设置的 `CQHTTPBot` 适配器的路径,你可以对不同的适配器设置不同路径以作区别。

View File

@ -6,14 +6,14 @@
```python{1,2,8,9}
@weather.handle()
async def handle_first_receive(bot: Bot, event: Event, state: State):
args = str(event.message).strip() # 首次发送命令时跟随的参数,例:/天气 上海则args为上海
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
args = str(event.get_message()).strip() # 首次发送命令时跟随的参数,例:/天气 上海则args为上海
if args:
state["city"] = args # 如果用户发送了参数则直接赋值
@weather.got("city", prompt="你想查询哪个城市的天气呢?")
async def handle_city(bot: Bot, event: Event, state: State):
async def handle_city(bot: Bot, event: Event, state: T_State):
city = state["city"]
if city not in ["上海", "北京"]:
await weather.reject("你想查询的城市暂不支持,请重新输入!")
@ -53,12 +53,12 @@ async def handle_city(bot: Bot, event: Event, state: State):
```python
@matcher.receive()
async def handle(bot: Bot, event: Event, state: State):
async def handle(bot: Bot, event: Event, state: T_State):
state["key"] = "hello"
@matcher.got("key2", prompt="{key}!")
async def handle2(bot: Bot, event: Event, state: State):
async def handle2(bot: Bot, event: Event, state: T_State):
pass
```
@ -75,17 +75,55 @@ async def handle(bot: Bot, event: Event, state: State):
### 事件处理函数参数
事件处理函数类型为 `Callable[[Bot, Event, State], Union[Awaitable[None], Awaitable[NoReturn]]]`
事件处理函数类型为:
- `Callable[[Bot, Event, T_State, Matcher], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot, Event, T_State], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot, Event, Matcher], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot, T_State, Matcher], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot, Event], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot, T_State], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot, Matcher], Union[Awaitable[None], Awaitable[NoReturn]]]`
- `Callable[[Bot], Union[Awaitable[None], Awaitable[NoReturn]]]`
简单说就是:除了 `bot` 参数,其他都是可选的。
以下函数都是合法的事件处理函数(仅列举常用的):
```python
async def handle(bot: Bot, event: Event, state: T_State):
pass
async def handle(bot: Bot, event: Event, state: T_State, matcher: Matcher):
pass
async def handle(bot: Bot, event: Event):
pass
async def handle(bot: Bot, state: T_State):
pass
async def handle(bot: Bot):
pass
```
:::danger 警告
函数的参数名固定不能修改!
:::
参数分别为:
1. [nonebot.adapters.Bot](../api/adapters/#class-bot): 即事件上报连接对应的 Bot 对象,为 BaseBot 的子类。特别注意,此处的类型注释可以替换为指定的 Bot 类型,例如:`nonebot.adapters.cqhttp.Bot`,只有在上报事件的 Bot 类型与类型注释相符时才会执行该处理函数!可用于多平台进行不同的处理。
2. [nonebot.adapters.Event](../api/adapters/#class-event): 即上报事件对象,可以获取到上报的所有信息。
3. [state](../api/typing.md#state): 状态字典,可以存储任意的信息,其中还包含一些特殊的值以获取 NoneBot 内部处理时的一些信息,如:
3. [state](../api/typing.md#t-state): 状态字典,可以存储任意的信息,其中还包含一些特殊的值以获取 NoneBot 内部处理时的一些信息,如:
- `state["_current_key"]`: 存储当前 `got` 获取的参数名
- `state["_prefix"]`, `state["_suffix"]`: 存储当前 TRIE 匹配的前缀/后缀,可以通过该值获取用户命令的原始命令
:::tip 提示
NoneBot 会对不同类型的参数进行不同的操作,详情查看 [事件处理函数重载](../advanced/overloaded-handlers.md)
:::
### 参数处理函数 args_parser
在使用 `got` 获取用户输入参数时需要对用户的消息进行处理以转换为我们所需要的信息。在默认情况下NoneBot 会把用户的消息字符串原封不动的赋值给 `state[key]` 。可以通过以下两种方式修改默认处理逻辑:
@ -93,11 +131,11 @@ async def handle(bot: Bot, event: Event, state: State):
- `@matcher.args_parser` 装饰器:直接装饰一个函数作为参数处理器
- `got(key, prompt, args_parser)`:直接把函数作为参数传入
参数处理函数类型为:`Callable[[Bot, Event, State], Union[Awaitable[None], Awaitable[NoReturn]]]`,即:
参数处理函数类型为:`Callable[[Bot, Event, T_State], Union[Awaitable[None], Awaitable[NoReturn]]]`,即:
```python
async def parser(bot: Bot, event: Event, state: State):
state[state["_current_key"]] = str(event.message)
async def parser(bot: Bot, event: Event, state: T_State):
state[state["_current_key"]] = str(event.get_message())
```
特别的,`state["_current_key"]` 中存储了当前获取的参数名
@ -132,15 +170,15 @@ matcher = on_command("test")
# 修改默认参数处理
@matcher.args_parser
async def parse(bot: Bot, event: Event, state: State):
print(state["_current_key"], ":", str(event.message))
state[state["_current_key"]] = str(event.message)
print(state["_current_key"], ":", str(event.get_message()))
state[state["_current_key"]] = str(event.get_message())
@matcher.handle()
async def first_receive(bot: Bot, event: Event, state: State):
# 获取用户原始命令,如:/test
print(state["_prefix"]["raw_command"])
# 处理用户输入参数,如:/test arg1 arg2
raw_args = str(event.message).strip()
raw_args = str(event.get_message()).strip()
if raw_args:
arg_list = raw_args.split()
# 将参数存入state以阻止后续再向用户询问参数

View File

@ -7,15 +7,15 @@
```python
from nonebot import on_command
from nonebot.rule import to_me
from nonebot.typing import State
from nonebot.adapters.cqhttp import Bot, Event
from nonebot.typing import T_State
from nonebot.adapters import Bot, Event
weather = on_command("天气", rule=to_me(), priority=5)
@weather.handle()
async def handle_first_receive(bot: Bot, event: Event, state: State):
args = str(event.message).strip() # 首次发送命令时跟随的参数,例:/天气 上海则args为上海
async def handle_first_receive(bot: Bot, event: Event, state: T_State):
args = str(event.get_message()).strip() # 首次发送命令时跟随的参数,例:/天气 上海则args为上海
if args:
state["city"] = args # 如果用户发送了参数则直接赋值
@ -63,7 +63,7 @@ weather = on_command("天气", rule=to_me(), permission=Permission(), priority=5
### 事件响应器类型 type
事件响应器类型其实就是对应事件的类型 `Event.type` NoneBot 提供了一个基础类型事件响应器 `on()` 以及一些其他内置的事件响应器。
事件响应器类型其实就是对应事件的类型 `Event.get_type()` NoneBot 提供了一个基础类型事件响应器 `on()` 以及一些其他内置的事件响应器。
以下所有类型的事件响应器都是由 `on(type, rule)` 的形式进行了简化封装。
@ -92,6 +92,7 @@ weather = on_command("天气", rule=to_me(), permission=Permission(), priority=5
```bash
nb plugin install nonebot_plugin_test
```
:::
### 阻断 block

3
docs/guide/ding-guide.md Normal file
View File

@ -0,0 +1,3 @@
# 钉钉机器人使用指南
~~TODO~~

View File

@ -57,86 +57,19 @@ python bot.py
09-14 21:02:00 [INFO] uvicorn | Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
```
## 配置 CQHTTP 协议端(以 QQ 为例)
## 配置协议端
单纯运行 NoneBot 实例并不会产生任何效果,因为此刻 QQ 这边还不知道 NoneBot 的存在,也就无法把消息发送给它,因此现在需要使用一个无头 QQ 来把消息等事件上报给 NoneBot。
`bot.py` 文件中使用 `register_adapter` 注册协议适配之后即可配置协议端来完成与 NoneBot 的通信,详细配置方法参考:
QQ 协议端举例:
- [配置 CQHTTP](./cqhttp-guide.md)
- [配置钉钉](./ding-guide.md)
- [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) (基于 [MiraiGo](https://github.com/Mrs4s/MiraiGo))
- [cqhttp-mirai-embedded](https://github.com/yyuueexxiinngg/cqhttp-mirai/tree/embedded)
- [Mirai](https://github.com/mamoe/mirai) + [cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai)
- [Mirai](https://github.com/mamoe/mirai) + [Mirai Native](https://github.com/iTXTech/mirai-native) + [CQHTTP](https://github.com/richardchien/coolq-http-api)
- [OICQ-http-api](https://github.com/takayama-lily/onebot) (基于 [OICQ](https://github.com/takayama-lily/oicq))
NoneBot 接受的上报地址与 `Driver` 有关,默认使用的 `FastAPI Driver` 所接受的上报地址有:
这里以 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 为例
1. 下载 go-cqhttp 对应平台的 release 文件,[点此前往](https://github.com/Mrs4s/go-cqhttp/releases)
2. 运行 exe 文件或者使用 `./go-cqhttp` 启动
3. 生成默认配置文件并修改默认配置
```hjson{2,3,35-36,42}
{
uin: 机器人QQ号
password: 机器人密码
encrypt_password: false
password_encrypted: ""
enable_db: true
access_token: ""
relogin: {
enabled: true
relogin_delay: 3
max_relogin_times: 0
}
_rate_limit: {
enabled: false
frequency: 1
bucket_size: 1
}
ignore_invalid_cqcode: false
force_fragmented: false
heartbeat_interval: 0
http_config: {
enabled: false
host: "0.0.0.0"
port: 5700
timeout: 0
post_urls: {}
}
ws_config: {
enabled: false
host: "0.0.0.0"
port: 6700
}
ws_reverse_servers: [
{
enabled: true
reverse_url: ws://127.0.0.1:8080/cqhttp/ws
reverse_api_url: ws://you_websocket_api.server
reverse_event_url: ws://you_websocket_event.server
reverse_reconnect_interval: 3000
}
]
post_message_format: array
use_sso_address: false
debug: false
log_level: ""
web_ui: {
enabled: false
host: 127.0.0.1
web_ui_port: 9999
web_input: false
}
}
```
其中 `ws://127.0.0.1:8080/cqhttp/ws` 中的 `127.0.0.1``8080` 应分别对应 nonebot 配置的 HOST 和 PORT。
`cqhttp` 是前述 `register_adapter` 时传入的第一个参数,代表设置的 `CQHTTPBot` 适配器的路径,你可以对不同的适配器设置不同路径以作区别。
## 配置钉钉
~~TODO~~
- `/{adapter name}/`: HTTP POST 上报
- `/{adapter name}/http/`: HTTP POST 上报
- `/{adapter name}/ws`: WebSocket 上报
- `/{adapter name}/ws/`: WebSocket 上报
## 历史性的第一次对话

View File

@ -4,28 +4,49 @@ sidebarDepth: 0
---
NoneBot.adapters.cqhttp 模块
============================
=============================
.. automodule:: nonebot.adapters.cqhttp
NoneBot.adapters.cqhttp.utils 模块
===================================
.. automodule:: nonebot.adapters.cqhttp.utils
:members:
:show-inheritance:
NoneBot.adapters.cqhttp.exception 模块
=======================================
.. automodule:: nonebot.adapters.cqhttp.exception
:members:
:show-inheritance:
NoneBot.adapters.cqhttp.bot 模块
=================================
.. automodule:: nonebot.adapters.cqhttp.bot
:members:
:private-members:
:show-inheritance:
NoneBot.adapters.cqhttp.message 模块
=====================================
.. automodule:: nonebot.adapters.cqhttp.message
:members:
:private-members:
:show-inheritance:
NoneBot.adapters.cqhttp.permission 模块
========================================
.. automodule:: nonebot.adapters.cqhttp.permission
:members:
:show-inheritance:
NoneBot.adapters.cqhttp.event 模块
===================================
.. automodule:: nonebot.adapters.cqhttp.event
:members:

View File

@ -4,26 +4,39 @@ sidebarDepth: 0
---
NoneBot.adapters.ding 模块
============================
===========================
.. automodule:: nonebot.adapters.ding
NoneBot.adapters.ding.exception 模块
=====================================
.. automodule:: nonebot.adapters.ding.exception
:members:
:show-inheritance:
NoneBot.adapters.ding.bot 模块
===============================
.. automodule:: nonebot.adapters.ding.bot
:members:
:private-members:
:show-inheritance:
.. automodule:: nonebot.adapters.ding.event
:members:
:private-members:
:show-inheritance:
NoneBot.adapters.ding.message 模块
===================================
.. automodule:: nonebot.adapters.ding.message
:members:
:private-members:
:show-inheritance:
NoneBot.adapters.ding.event 模块
=================================
.. automodule:: nonebot.adapters.ding.event
:members:
:show-inheritance:

View File

@ -72,6 +72,7 @@ html_static_path = ['_static']
# -- Options for autodoc extension ----------------------------------------------
autodoc_default_options = {'member-order': 'bysource'}
autodoc_inherit_docstrings = False
# -- Options for todo extension ----------------------------------------------

View File

@ -11,6 +11,7 @@ CQHTTP (OneBot) v11 协议适配
"""
from .event import *
from .permission import *
from .message import Message, MessageSegment
from .utils import log, escape, unescape, _b2s
from .bot import Bot, _check_at_me, _check_nickname, _check_reply, _handle_api_result

View File

@ -14,7 +14,7 @@ from .message import Message
class Event(BaseEvent):
"""
CQHTTP 协议事件各事件字段未列出部分参考 `CQHTTP 文档`_
CQHTTP 协议事件字段与 CQHTTP 一致各事件字段参考 `CQHTTP 文档`_
.. _CQHTTP 文档:
https://github.com/howmanybots/onebot/blob/master/README.md

View File

@ -0,0 +1,86 @@
from typing import TYPE_CHECKING
from nonebot.permission import Permission
from .event import PrivateMessageEvent, GroupMessageEvent
if TYPE_CHECKING:
from nonebot.adapters import Bot, Event
async def _private(bot: "Bot", event: "Event") -> bool:
return isinstance(event, PrivateMessageEvent)
async def _private_friend(bot: "Bot", event: "Event") -> bool:
return isinstance(event, PrivateMessageEvent) and event.sub_type == "friend"
async def _private_group(bot: "Bot", event: "Event") -> bool:
return isinstance(event, PrivateMessageEvent) and event.sub_type == "group"
async def _private_other(bot: "Bot", event: "Event") -> bool:
return isinstance(event, PrivateMessageEvent) and event.sub_type == "other"
PRIVATE = Permission(_private)
"""
- **说明**: 匹配任意私聊消息类型事件
"""
PRIVATE_FRIEND = Permission(_private_friend)
"""
- **说明**: 匹配任意好友私聊消息类型事件
"""
PRIVATE_GROUP = Permission(_private_group)
"""
- **说明**: 匹配任意群临时私聊消息类型事件
"""
PRIVATE_OTHER = Permission(_private_other)
"""
- **说明**: 匹配任意其他私聊消息类型事件
"""
async def _group(bot: "Bot", event: "Event") -> bool:
return isinstance(event, GroupMessageEvent)
async def _group_member(bot: "Bot", event: "Event") -> bool:
return isinstance(event,
GroupMessageEvent) and event.sender.role == "member"
async def _group_admin(bot: "Bot", event: "Event") -> bool:
return isinstance(event, GroupMessageEvent) and event.sender.role == "admin"
async def _group_owner(bot: "Bot", event: "Event") -> bool:
return isinstance(event, GroupMessageEvent) and event.sender.role == "owner"
GROUP = Permission(_group)
"""
- **说明**: 匹配任意群聊消息类型事件
"""
GROUP_MEMBER = Permission(_group_member)
"""
- **说明**: 匹配任意群员群聊消息类型事件
\:\:\:warning 警告
该权限通过 event.sender 进行判断且不包含管理员以及群主
\:\:\:
"""
GROUP_ADMIN = Permission(_group_admin)
"""
- **说明**: 匹配任意群管理员群聊消息类型事件
"""
GROUP_OWNER = Permission(_group_owner)
"""
- **说明**: 匹配任意群主群聊消息类型事件
"""
__all__ = [
"PRIVATE", "PRIVATE_FRIEND", "PRIVATE_GROUP", "PRIVATE_OTHER", "GROUP",
"GROUP_MEMBER", "GROUP_ADMIN", "GROUP_OWNER"
]

View File

@ -5,8 +5,7 @@
协议详情请看: `钉钉文档`_
.. _钉钉文档:
https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p/
https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p
"""
from .utils import log

View File

@ -12,7 +12,7 @@ from .message import Message
class Event(BaseEvent):
"""
钉钉 协议 Event 适配各事件字段参考 `钉钉文档`_
钉钉协议事件各事件字段参考 `钉钉文档`_
.. _钉钉文档:
https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p
@ -68,6 +68,7 @@ class ConversationType(str, Enum):
class MessageEvent(Event):
"""消息事件"""
msgtype: str
text: TextMessage
msgId: str
@ -126,12 +127,14 @@ class MessageEvent(Event):
class PrivateMessageEvent(MessageEvent):
"""私聊消息事件"""
chatbotCorpId: str
senderStaffId: Optional[str]
conversationType: ConversationType = ConversationType.private
class GroupMessageEvent(MessageEvent):
"""群消息事件"""
atUsers: List[AtUsersItem]
conversationType: ConversationType = ConversationType.group
conversationTitle: str

View File

@ -36,28 +36,32 @@ class MessageSegment(BaseMessageSegment):
@staticmethod
def atAll() -> "MessageSegment":
"""@全体"""
return MessageSegment("at", {"isAtAll": True})
@staticmethod
def atMobiles(*mobileNumber: str) -> "MessageSegment":
"""@指定手机号人员"""
return MessageSegment("at", {"atMobiles": list(mobileNumber)})
@staticmethod
def text(text: str) -> "MessageSegment":
"""发送 ``text`` 类型消息"""
return MessageSegment("text", {"content": text})
@staticmethod
def image(picURL: str) -> "MessageSegment":
"""发送 ``image`` 类型消息"""
return MessageSegment("image", {"picURL": picURL})
@staticmethod
def extension(dict_: dict) -> "MessageSegment":
""""标记 text 文本的 extension 属性,需要与 text 消息段相加。
"""
""""标记 text 文本的 extension 属性,需要与 text 消息段相加。"""
return MessageSegment("extension", dict_)
@staticmethod
def markdown(title: str, text: str) -> "MessageSegment":
"""发送 ``markdown`` 类型消息"""
return MessageSegment(
"markdown",
{
@ -69,6 +73,7 @@ class MessageSegment(BaseMessageSegment):
@staticmethod
def actionCardSingleBtn(title: str, text: str, singleTitle: str,
singleURL) -> "MessageSegment":
"""发送 ``actionCardSingleBtn`` 类型消息"""
return MessageSegment(
"actionCard", {
"title": title,
@ -86,10 +91,11 @@ class MessageSegment(BaseMessageSegment):
btnOrientation: str = '1',
) -> "MessageSegment":
"""
发送 ``actionCardMultiBtn`` 类型消息
:参数:
* ``btnOrientation``: 0按钮竖直排列 1按钮横向排列
* ``btns``: [{ "title": title, "actionURL": actionURL }, ...]
"""
return MessageSegment(
@ -104,6 +110,8 @@ class MessageSegment(BaseMessageSegment):
@staticmethod
def feedCard(links: list) -> "MessageSegment":
"""
发送 ``feedCard`` 类型消息
:参数:
* ``links``: [{ "title": xxx, "messageURL": xxx, "picURL": xxx }, ...]

View File

@ -140,7 +140,7 @@ class Matcher(metaclass=MatcherMeta):
:参数:
* ``type_: str``: 事件响应器类型 ``event.type`` 一致时触发空字符串表示任意
* ``type_: str``: 事件响应器类型 ``event.get_type()`` 一致时触发空字符串表示任意
* ``rule: Optional[Rule]``: 匹配规则
* ``permission: Optional[Permission]``: 权限
* ``handlers: Optional[List[T_Handler]]``: 事件处理函数列表

View File

@ -133,75 +133,6 @@ def USER(*user: str, perm: Permission = Permission()):
return Permission(_user)
# async def _private(bot: "Bot", event: "Event") -> bool:
# return event.get_type() == "message" and event.detail_type == "private"
# async def _private_friend(bot: "Bot", event: "Event") -> bool:
# return (event.get_type() == "message" and event.detail_type == "private" and
# event.sub_type == "friend")
# async def _private_group(bot: "Bot", event: "Event") -> bool:
# return (event.get_type() == "message" and event.detail_type == "private" and
# event.sub_type == "group")
# async def _private_other(bot: "Bot", event: "Event") -> bool:
# return (event.get_type() == "message" and event.detail_type == "private" and
# event.sub_type == "other")
# PRIVATE = Permission(_private)
# """
# - **说明**: 匹配任意私聊消息类型事件
# """
# PRIVATE_FRIEND = Permission(_private_friend)
# """
# - **说明**: 匹配任意好友私聊消息类型事件
# """
# PRIVATE_GROUP = Permission(_private_group)
# """
# - **说明**: 匹配任意群临时私聊消息类型事件
# """
# PRIVATE_OTHER = Permission(_private_other)
# """
# - **说明**: 匹配任意其他私聊消息类型事件
# """
# async def _group(bot: "Bot", event: "Event") -> bool:
# return event.get_type() == "message" and event.detail_type == "group"
# async def _group_member(bot: "Bot", event: "Event") -> bool:
# return (event.get_type() == "message" and event.detail_type == "group" and
# event.sender.get("role") == "member")
# async def _group_admin(bot: "Bot", event: "Event") -> bool:
# return (event.get_type() == "message" and event.detail_type == "group" and
# event.sender.get("role") == "admin")
# async def _group_owner(bot: "Bot", event: "Event") -> bool:
# return (event.get_type() == "message" and event.detail_type == "group" and
# event.sender.get("role") == "owner")
# GROUP = Permission(_group)
# """
# - **说明**: 匹配任意群聊消息类型事件
# """
# GROUP_MEMBER = Permission(_group_member)
# """
# - **说明**: 匹配任意群员群聊消息类型事件
# \:\:\:warning 警告
# 该权限通过 event.sender 进行判断且不包含管理员以及群主!
# \:\:\:
# """
# GROUP_ADMIN = Permission(_group_admin)
# """
# - **说明**: 匹配任意群管理员群聊消息类型事件
# """
# GROUP_OWNER = Permission(_group_owner)
# """
# - **说明**: 匹配任意群主群聊消息类型事件
# """
async def _superuser(bot: "Bot", event: "Event") -> bool:
return event.get_type() == "message" and event.get_user_id(
) in bot.config.superusers

View File

@ -421,7 +421,6 @@ def on_command(cmd: Union[str, Tuple[str, ...]],
"""
async def _strip_cmd(bot: "Bot", event: "Event", state: T_State):
print(event.dict())
message = event.get_message()
segment = message.pop(0)
new_message = message.__class__(
@ -784,10 +783,14 @@ class MatcherGroup:
- ``Type[Matcher]``
"""
async def _strip_cmd(bot, event, state: T_State):
message = event.message
event.message = message.__class__(
str(message)[len(state["_prefix"]["raw_command"]):].strip())
async def _strip_cmd(bot: "Bot", event: "Event", state: T_State):
message = event.get_message()
segment = message.pop(0)
new_message = message.__class__(
str(segment)
[len(state["_prefix"]["raw_command"]):].strip()) # type: ignore
for new_segment in reversed(new_message):
message.insert(0, new_segment)
handlers = kwargs.pop("handlers", [])
handlers.insert(0, _strip_cmd)

View File

@ -314,7 +314,7 @@ def to_me() -> Rule:
"""
:说明:
通过 ``event.to_me`` 判断事件是否与机器人有关
通过 ``event.is_tome()`` 判断事件是否与机器人有关
:参数:

View File

@ -12,6 +12,7 @@ sidebar: auto
- 修复非 text 类型 CQ 码 data 未进行去转义
- 修复内置插件为进行去转义,修改内置插件为 cqhttp 定制
- 出于**CQ 码安全性考虑**,使用 cqhttp 的 `bot.send` 或者 `matcher.send` 时默认对字符串进行转义
- 移动 cqhttp 相关 `Permission``nonebot.adapters.cqhttp` 包内
## v2.0.0a7