From 18beb63d550184a847298a61b146f05c5b1c13af Mon Sep 17 00:00:00 2001
From: Ju4tCode <42488585+yanyongyu@users.noreply.github.com>
Date: Fri, 24 Mar 2023 16:34:21 +0800
Subject: [PATCH] =?UTF-8?q?:memo:=20Docs:=20=E9=87=8D=E5=86=99=E6=95=99?=
=?UTF-8?q?=E7=A8=8B=E4=B8=8E=E8=BF=9B=E9=98=B6=E6=8C=87=E5=8D=97=20(#1604?=
=?UTF-8?q?)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Johnny Hsieh <32300164+mnixry@users.noreply.github.com>
---
CONTRIBUTING.md | 7 +-
README.md | 2 +-
website/docs/README.md | 20 +-
website/docs/advanced/README.md | 207 ---
website/docs/advanced/adapter.md | 161 +++
website/docs/advanced/dependency.mdx | 1189 +++++++++++++++++
website/docs/advanced/di/_category_.json | 4 -
.../docs/advanced/di/dependency-injection.md | 243 ----
website/docs/advanced/di/overload.md | 76 --
website/docs/advanced/driver.md | 286 ++++
website/docs/advanced/images/Handle-Event.png | Bin 384852 -> 0 bytes
.../advanced/images/plugin_store_publish.png | Bin 105850 -> 0 bytes
.../images/plugin_store_publish_2.png | Bin 131406 -> 0 bytes
website/docs/advanced/matcher-provider.md | 40 +
website/docs/advanced/matcher.md | 304 +++++
website/docs/advanced/permission.md | 95 --
website/docs/advanced/plugin-info.md | 97 ++
website/docs/advanced/plugin-nesting.md | 41 +
website/docs/advanced/publish-plugin.md | 76 --
website/docs/advanced/requiring.md | 37 +
website/docs/advanced/routing.md | 134 ++
website/docs/advanced/rule.md | 75 --
website/docs/advanced/runtime-hook.md | 134 +-
website/docs/advanced/scheduler.md | 147 --
website/docs/advanced/session-updating.md | 59 +
website/docs/advanced/unittest/README.mdx | 106 --
.../docs/advanced/unittest/test-adapters.md | 162 ---
.../unittest/test-matcher-operation.md | 122 --
.../docs/advanced/unittest/test-matcher.md | 159 ---
website/docs/appendices/api-calling.mdx | 128 ++
.../appendices/assets/console-markdown.txt | 6 +
website/docs/appendices/config.mdx | 562 ++++++++
website/docs/appendices/log.md | 102 ++
website/docs/appendices/overload.md | 70 +
website/docs/appendices/permission.mdx | 116 ++
website/docs/appendices/rule.md | 107 ++
website/docs/appendices/session-control.mdx | 389 ++++++
website/docs/appendices/session-state.md | 59 +
website/docs/appendices/whats-next.md | 11 +
website/docs/best-practice/data-storing.md | 61 +
website/docs/best-practice/deployment.mdx | 254 ++++
website/docs/best-practice/error-tracking.md | 64 +
website/docs/best-practice/scheduler.md | 96 ++
website/docs/best-practice/testing/README.mdx | 212 +++
.../testing}/_category_.json | 2 +-
.../docs/best-practice/testing/behavior.mdx | 288 ++++
.../best-practice/testing/mock-network.md | 96 ++
.../question.md => community/contact.md} | 16 +-
website/docs/community/contributing.md | 22 +
website/docs/developer/adapter-writing.md | 6 +
website/docs/developer/plugin-publishing.md | 6 +
website/docs/editor-support.md | 28 +
website/docs/quick-start.mdx | 119 ++
website/docs/start/editor-support.md | 33 -
website/docs/start/install-adapter.mdx | 45 -
website/docs/start/install-driver.mdx | 47 -
website/docs/start/install-plugin.mdx | 45 -
website/docs/start/installation.mdx | 88 --
website/docs/start/nb-cli.md | 83 --
website/docs/tutorial/add-custom-api.md | 42 -
website/docs/tutorial/application.md | 110 ++
website/docs/tutorial/call-api.md | 49 -
website/docs/tutorial/choose-driver.md | 274 ----
website/docs/tutorial/configuration.md | 240 ----
website/docs/tutorial/create-plugin.md | 226 ++++
website/docs/tutorial/create-project.mdx | 79 --
website/docs/tutorial/custom-logger.md | 59 -
website/docs/tutorial/deployment.md | 318 -----
website/docs/tutorial/event-data.mdx | 64 +
website/docs/tutorial/fundamentals.md | 24 +
website/docs/tutorial/handler.mdx | 85 ++
website/docs/tutorial/matcher.md | 58 +
website/docs/tutorial/message.md | 284 ++++
website/docs/tutorial/plugin/_category_.json | 5 -
website/docs/tutorial/plugin/config-plugin.md | 37 -
.../docs/tutorial/plugin/create-handler.md | 529 --------
.../docs/tutorial/plugin/create-matcher.md | 133 --
website/docs/tutorial/plugin/example.mdx | 32 -
website/docs/tutorial/plugin/introduction.md | 71 -
website/docs/tutorial/plugin/load-plugin.md | 138 --
.../docs/tutorial/plugin/matcher-operation.md | 146 --
website/docs/tutorial/process-message.md | 253 ----
website/docs/tutorial/register-adapter.md | 97 --
website/docs/tutorial/store.mdx | 265 ++++
website/docusaurus.config.js | 38 +-
website/sidebars.js | 64 +-
website/src/components/Card/index.tsx | 10 +
website/static/drivers.json | 12 +-
website/static/img/setup.svg | 2 +-
.../versioned_docs/version-2.0.0rc3/README.md | 49 -
.../version-2.0.0rc3/advanced/README.md | 207 ---
.../advanced/di/_category_.json | 4 -
.../advanced/di/dependency-injection.md | 243 ----
.../version-2.0.0rc3/advanced/di/overload.md | 76 --
.../advanced/images/Handle-Event.png | Bin 384852 -> 0 bytes
.../advanced/images/plugin_store_publish.png | Bin 105850 -> 0 bytes
.../images/plugin_store_publish_2.png | Bin 131406 -> 0 bytes
.../version-2.0.0rc3/advanced/permission.md | 95 --
.../advanced/publish-plugin.md | 76 --
.../version-2.0.0rc3/advanced/rule.md | 75 --
.../version-2.0.0rc3/advanced/runtime-hook.md | 171 ---
.../version-2.0.0rc3/advanced/scheduler.md | 147 --
.../advanced/unittest/README.mdx | 106 --
.../advanced/unittest/_category_.json | 4 -
.../advanced/unittest/test-adapters.md | 162 ---
.../unittest/test-matcher-operation.md | 122 --
.../advanced/unittest/test-matcher.md | 159 ---
.../version-2.0.0rc3/api/.gitkeep | 0
.../api/adapters/_category_.json | 3 -
.../version-2.0.0rc3/api/adapters/index.md | 619 ---------
.../version-2.0.0rc3/api/config.md | 194 ---
.../version-2.0.0rc3/api/consts.md | 128 --
.../api/dependencies/_category_.json | 3 -
.../api/dependencies/index.md | 98 --
.../api/dependencies/utils.md | 48 -
.../api/drivers/_category_.json | 3 -
.../version-2.0.0rc3/api/drivers/aiohttp.md | 120 --
.../version-2.0.0rc3/api/drivers/fastapi.md | 290 ----
.../version-2.0.0rc3/api/drivers/httpx.md | 52 -
.../version-2.0.0rc3/api/drivers/index.md | 538 --------
.../version-2.0.0rc3/api/drivers/none.md | 80 --
.../version-2.0.0rc3/api/drivers/quart.md | 254 ----
.../api/drivers/websockets.md | 134 --
.../version-2.0.0rc3/api/exception.md | 260 ----
.../version-2.0.0rc3/api/index.md | 207 ---
.../version-2.0.0rc3/api/log.md | 75 --
.../version-2.0.0rc3/api/matcher.md | 615 ---------
.../version-2.0.0rc3/api/message.md | 89 --
.../version-2.0.0rc3/api/params.md | 388 ------
.../version-2.0.0rc3/api/permission.md | 157 ---
.../api/plugin/_category_.json | 3 -
.../version-2.0.0rc3/api/plugin/index.md | 89 --
.../version-2.0.0rc3/api/plugin/load.md | 157 ---
.../version-2.0.0rc3/api/plugin/manager.md | 122 --
.../version-2.0.0rc3/api/plugin/on.md | 914 -------------
.../version-2.0.0rc3/api/plugin/plugin.md | 116 --
.../version-2.0.0rc3/api/rule.md | 396 ------
.../version-2.0.0rc3/api/typing.md | 219 ---
.../version-2.0.0rc3/api/utils.md | 217 ---
.../version-2.0.0rc3/start/editor-support.md | 33 -
.../start/install-adapter.mdx | 45 -
.../version-2.0.0rc3/start/install-driver.mdx | 47 -
.../version-2.0.0rc3/start/install-plugin.mdx | 45 -
.../version-2.0.0rc3/start/installation.mdx | 88 --
.../version-2.0.0rc3/start/nb-cli.md | 83 --
.../version-2.0.0rc3/start/question.md | 28 -
.../tutorial/add-custom-api.md | 42 -
.../version-2.0.0rc3/tutorial/call-api.md | 49 -
.../tutorial/choose-driver.md | 274 ----
.../tutorial/configuration.md | 240 ----
.../tutorial/create-project.mdx | 79 --
.../tutorial/custom-logger.md | 59 -
.../version-2.0.0rc3/tutorial/deployment.md | 318 -----
.../tutorial/plugin/_category_.json | 5 -
.../tutorial/plugin/config-plugin.md | 37 -
.../tutorial/plugin/create-handler.md | 529 --------
.../tutorial/plugin/create-matcher.md | 133 --
.../tutorial/plugin/example.mdx | 32 -
.../tutorial/plugin/introduction.md | 71 -
.../tutorial/plugin/load-plugin.md | 138 --
.../tutorial/plugin/matcher-operation.md | 146 --
.../tutorial/process-message.md | 253 ----
.../tutorial/register-adapter.md | 97 --
.../version-2.0.0rc3-sidebars.json | 50 -
website/versions.json | 1 -
165 files changed, 6441 insertions(+), 15653 deletions(-)
delete mode 100644 website/docs/advanced/README.md
create mode 100644 website/docs/advanced/adapter.md
create mode 100644 website/docs/advanced/dependency.mdx
delete mode 100644 website/docs/advanced/di/_category_.json
delete mode 100644 website/docs/advanced/di/dependency-injection.md
delete mode 100644 website/docs/advanced/di/overload.md
create mode 100644 website/docs/advanced/driver.md
delete mode 100644 website/docs/advanced/images/Handle-Event.png
delete mode 100644 website/docs/advanced/images/plugin_store_publish.png
delete mode 100644 website/docs/advanced/images/plugin_store_publish_2.png
create mode 100644 website/docs/advanced/matcher-provider.md
create mode 100644 website/docs/advanced/matcher.md
delete mode 100644 website/docs/advanced/permission.md
create mode 100644 website/docs/advanced/plugin-info.md
create mode 100644 website/docs/advanced/plugin-nesting.md
delete mode 100644 website/docs/advanced/publish-plugin.md
create mode 100644 website/docs/advanced/requiring.md
create mode 100644 website/docs/advanced/routing.md
delete mode 100644 website/docs/advanced/rule.md
delete mode 100644 website/docs/advanced/scheduler.md
create mode 100644 website/docs/advanced/session-updating.md
delete mode 100644 website/docs/advanced/unittest/README.mdx
delete mode 100644 website/docs/advanced/unittest/test-adapters.md
delete mode 100644 website/docs/advanced/unittest/test-matcher-operation.md
delete mode 100644 website/docs/advanced/unittest/test-matcher.md
create mode 100644 website/docs/appendices/api-calling.mdx
create mode 100644 website/docs/appendices/assets/console-markdown.txt
create mode 100644 website/docs/appendices/config.mdx
create mode 100644 website/docs/appendices/log.md
create mode 100644 website/docs/appendices/overload.md
create mode 100644 website/docs/appendices/permission.mdx
create mode 100644 website/docs/appendices/rule.md
create mode 100644 website/docs/appendices/session-control.mdx
create mode 100644 website/docs/appendices/session-state.md
create mode 100644 website/docs/appendices/whats-next.md
create mode 100644 website/docs/best-practice/data-storing.md
create mode 100644 website/docs/best-practice/deployment.mdx
create mode 100644 website/docs/best-practice/error-tracking.md
create mode 100644 website/docs/best-practice/scheduler.md
create mode 100644 website/docs/best-practice/testing/README.mdx
rename website/docs/{advanced/unittest => best-practice/testing}/_category_.json (65%)
create mode 100644 website/docs/best-practice/testing/behavior.mdx
create mode 100644 website/docs/best-practice/testing/mock-network.md
rename website/docs/{start/question.md => community/contact.md} (57%)
create mode 100644 website/docs/community/contributing.md
create mode 100644 website/docs/developer/adapter-writing.md
create mode 100644 website/docs/developer/plugin-publishing.md
create mode 100644 website/docs/editor-support.md
create mode 100644 website/docs/quick-start.mdx
delete mode 100644 website/docs/start/editor-support.md
delete mode 100644 website/docs/start/install-adapter.mdx
delete mode 100644 website/docs/start/install-driver.mdx
delete mode 100644 website/docs/start/install-plugin.mdx
delete mode 100644 website/docs/start/installation.mdx
delete mode 100644 website/docs/start/nb-cli.md
delete mode 100644 website/docs/tutorial/add-custom-api.md
create mode 100644 website/docs/tutorial/application.md
delete mode 100644 website/docs/tutorial/call-api.md
delete mode 100644 website/docs/tutorial/choose-driver.md
delete mode 100644 website/docs/tutorial/configuration.md
create mode 100644 website/docs/tutorial/create-plugin.md
delete mode 100644 website/docs/tutorial/create-project.mdx
delete mode 100644 website/docs/tutorial/custom-logger.md
delete mode 100644 website/docs/tutorial/deployment.md
create mode 100644 website/docs/tutorial/event-data.mdx
create mode 100644 website/docs/tutorial/fundamentals.md
create mode 100644 website/docs/tutorial/handler.mdx
create mode 100644 website/docs/tutorial/matcher.md
create mode 100644 website/docs/tutorial/message.md
delete mode 100644 website/docs/tutorial/plugin/_category_.json
delete mode 100644 website/docs/tutorial/plugin/config-plugin.md
delete mode 100644 website/docs/tutorial/plugin/create-handler.md
delete mode 100644 website/docs/tutorial/plugin/create-matcher.md
delete mode 100644 website/docs/tutorial/plugin/example.mdx
delete mode 100644 website/docs/tutorial/plugin/introduction.md
delete mode 100644 website/docs/tutorial/plugin/load-plugin.md
delete mode 100644 website/docs/tutorial/plugin/matcher-operation.md
delete mode 100644 website/docs/tutorial/process-message.md
delete mode 100644 website/docs/tutorial/register-adapter.md
create mode 100644 website/docs/tutorial/store.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/README.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/README.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/di/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/di/dependency-injection.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/di/overload.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/images/Handle-Event.png
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/images/plugin_store_publish.png
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/images/plugin_store_publish_2.png
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/permission.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/publish-plugin.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/rule.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/runtime-hook.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/scheduler.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/unittest/README.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/unittest/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/unittest/test-adapters.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/unittest/test-matcher-operation.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/advanced/unittest/test-matcher.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/.gitkeep
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/adapters/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/adapters/index.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/config.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/consts.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/dependencies/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/dependencies/index.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/dependencies/utils.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/aiohttp.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/fastapi.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/httpx.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/index.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/none.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/quart.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/drivers/websockets.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/exception.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/index.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/log.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/matcher.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/message.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/params.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/permission.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/plugin/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/plugin/index.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/plugin/load.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/plugin/manager.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/plugin/on.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/plugin/plugin.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/rule.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/typing.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/api/utils.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/editor-support.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/install-adapter.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/install-driver.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/install-plugin.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/installation.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/nb-cli.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/start/question.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/add-custom-api.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/call-api.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/choose-driver.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/configuration.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/create-project.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/custom-logger.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/deployment.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/_category_.json
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/config-plugin.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/create-handler.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/create-matcher.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/example.mdx
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/introduction.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/load-plugin.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/plugin/matcher-operation.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/process-message.md
delete mode 100644 website/versioned_docs/version-2.0.0rc3/tutorial/register-adapter.md
delete mode 100644 website/versioned_sidebars/version-2.0.0rc3-sidebars.json
delete mode 100644 website/versions.json
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 194faf02f51f..0b1fe466107a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -66,16 +66,17 @@ yarn start
NoneBot2 文档并没有具体的行文风格规范,但我们建议你尽量写得简单易懂。
-以下是比较重要的排版规范。目前 NoneBot2 文档中仍有部分文档不完全遵守此规范,如果在阅读时发现欢迎提交 PR。
+以下是比较重要的编写与排版规范。目前 NoneBot2 文档中仍有部分文档不完全遵守此规范,如果在阅读时发现欢迎提交 PR。
1. 中文与英文、数字、半角符号之间需要有空格。例:`NoneBot2 是一个可扩展的 Python 异步机器人框架。`
2. 若非英文整句,使用全角标点符号。例:`现在你可以看到机器人回复你:“Hello, World !”。`
3. 直引号`「」`和弯引号`“”`都可接受,但同一份文件里应使用同种引号。
4. **不要使用斜体**,你不需要一种与粗体不同的强调。除此之外,你也可以考虑使用 docusaurus 提供的[告示](https://docusaurus.io/zh-CN/docs/markdown-features/admonitions)功能。
+5. 文档中应以“我们”指代机器人开发者,以“机器人用户”指代机器人的使用者。
-这是社区创始人 richardchien 的中文排版规范,可供参考:。
+以上由[社区创始人 richardchien 的中文排版规范](https://stdrc.cc/style-guides/chinese)补充修改得到。
-如果你需要编辑器提示 Markdown 规范,可以安装 VSCode 上的 markdownlint 插件。
+如果你需要编辑器检查 Markdown 规范,可以在 VSCode 中安装 markdownlint 扩展。
### 参与开发
diff --git a/README.md b/README.md
index ff8375af5421..e1db7aeaef83 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ _✨ 跨平台 Python 异步机器人框架 ✨_
-
+
diff --git a/website/docs/README.md b/website/docs/README.md
index 4e0fffc65f97..2c47bd7864e5 100644
--- a/website/docs/README.md
+++ b/website/docs/README.md
@@ -6,44 +6,44 @@ slug: /
# 概览
-NoneBot2 是一个现代、跨平台、可扩展的 Python 聊天机器人框架,它基于 Python 的类型注解和异步特性,能够为你的需求实现提供便捷灵活的支持。
+NoneBot2 是一个现代、跨平台、可扩展的 Python 聊天机器人框架(下称 NoneBot),它基于 Python 的类型注解和异步优先特性(兼容同步),能够为你的需求实现提供便捷灵活的支持。同时,NoneBot 拥有大量的开发者为其开发插件,用户无需编写任何代码,仅需完成环境配置及插件安装,就可以正常使用 NoneBot。
-需要注意的是,NoneBot2 仅支持 **Python 3.8 以上版本**
+需要注意的是,NoneBot 仅支持 **Python 3.8 以上版本**
## 特色
### 异步优先
-NoneBot2 基于 Python [asyncio](https://docs.python.org/3/library/asyncio.html) 编写,并在异步机制的基础上进行了一定程度的同步函数兼容。
+NoneBot 基于 Python [asyncio](https://docs.python.org/zh-cn/3/library/asyncio.html) 编写,并在异步机制的基础上进行了一定程度的同步函数兼容。
### 完整的类型注解
-NoneBot2 参考 [PEP 484](https://www.python.org/dev/peps/pep-0484/) 等 PEP 完整实现了类型注解,通过 `pyright`/`pylance` 检查。配合编辑器的类型推导功能,能将绝大多数的 Bug 杜绝在编辑器中([编辑器支持](./start/editor-support))。
+NoneBot 参考 [PEP 484](https://www.python.org/dev/peps/pep-0484/) 等 PEP 完整实现了类型注解,通过 Pyright(Pylance) 检查。配合编辑器的类型推导功能,能将绝大多数的 Bug 杜绝在编辑器中([编辑器支持](./editor-support))。
### 开箱即用
-NoneBot2 提供了使用便捷、具有交互式功能的命令行工具--`nb-cli`,使得初次接触 NoneBot2 时更容易上手。详细使用方法请参考各文档章节以及[使用脚手架](./start/nb-cli)。
+NoneBot 提供了使用便捷、具有交互式功能的命令行工具--`nb-cli`,使得用户初次接触 NoneBot 时更容易上手。使用方法请阅读本文档[指南](./quick-start.mdx)以及 [CLI 文档](https://cli.nonebot.dev/)。
### 插件系统
-插件系统是 NoneBot2 的核心,通过它可以实现机器人的模块化以及功能扩展,便于维护和管理。
+插件系统是 NoneBot 的核心,通过它可以实现机器人的模块化以及功能扩展,便于维护和管理。
### 依赖注入系统
-NoneBot2 采用了一套自行定义的依赖注入系统,可以让事件的处理过程更加的简洁、清晰,增加代码的可读性,减少代码冗余。
+NoneBot 采用了一套自行定义的依赖注入系统,可以让事件的处理过程更加的简洁、清晰,增加代码的可读性,减少代码冗余。
#### 什么是依赖注入
-[**“依赖注入”**](https://zh.m.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC)意思是,在编程中,有一种方法可以让你的代码声明它工作和使用所需要的东西,即**“依赖”**。
+[**『依赖注入』**](https://zh.m.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC)意思是,在编程中,有一种方法可以让你的代码声明它工作和使用所需要的东西,即**『依赖』**。
-系统(在这里是指 NoneBot2)将负责做任何需要的事情,为你的代码提供这些必要依赖(即**“注入”**依赖性)
+系统(在这里是指 NoneBot)将负责做任何需要的事情,为你的代码提供这些必要依赖(即**『注入』**依赖性)
这在你有以下情形的需求时非常有用:
- 这部分代码拥有共享的逻辑(同样的代码逻辑多次重复)
- 共享数据库以及网络请求连接会话
- 比如 `httpx.AsyncClient`、`aiohttp.ClientSession` 和 `sqlalchemy.Session`
-- 用户权限检查以及认证
+- 机器人用户权限检查以及认证
- 还有更多...
它在完成上述工作的同时,还能尽量减少代码的耦合和重复
diff --git a/website/docs/advanced/README.md b/website/docs/advanced/README.md
deleted file mode 100644
index a96efe70267e..000000000000
--- a/website/docs/advanced/README.md
+++ /dev/null
@@ -1,207 +0,0 @@
----
-id: index
-sidebar_position: 0
-description: 深入了解 NoneBot2 运行机制
-slug: /advanced/
-
-options:
- menu:
- weight: 10
- category: advanced
----
-
-# 深入
-
-:::danger 警告
-进阶部分尚未更新完成
-:::
-
-## 它如何工作?
-
-如同[概览](../README.md)所言:
-
-> NoneBot2 是一个可扩展的 Python 异步机器人框架,它会对机器人收到的事件进行解析和处理,并以插件化的形式,按优先级分发给事件所对应的事件响应器,来完成具体的功能。
-
-NoneBot2 是一个可以对机器人上报的事件进行处理并完成具体功能的机器人框架,在这里,我们将简要讲述它的工作内容。
-
-**便捷起见,以下内容对 NoneBot2 会被称为 NoneBot,与 NoneBot2 交互的机器人实现会被称为协议端**。
-
-在实际应用中,NoneBot 会充当一个高性能,轻量级的 Python 微服务框架。协议端可以通过 http、websocket 等方式与之通信,这个通信往往是双向的:一方面,协议端可以上报数据给 NoneBot,NoneBot 会处理数据并返回响应给协议端;另一方面,NoneBot 可以主动推送数据给协议端。而 NoneBot 便是围绕双向通信进行工作的。
-
-在开始工作之前,NoneBot 需要进行准备工作:
-
-1. **运行 `nonebot.init` 初始化函数**,它会读取配置文件,并初始化 NoneBot 和后端驱动 `Driver` 对象。
-2. **注册协议适配器 `Adapter`**。
-3. **加载插件**。
-
-准备工作完成后,NoneBot 会利用 uvicorn 启动,并运行 `on_startup` 钩子函数。
-
-随后,倘若一个协议端与 NoneBot 进行了连接,NoneBot 的后端驱动 `Driver` 就会将数据交给 `Adapter`,然后会实例化 `Bot`,NoneBot 便会利用 `Bot` 开始工作,它的工作内容分为两个方面:
-
-1. **事件处理**,`Bot` 会将协议端上报的数据转化为 `Event`(事件),之后 NoneBot 会根据一套既定流程来处理事件。
-
-2. **调用 `API`**,在**事件处理**的过程中,NoneBot 可以通过 `Bot` 调用协议端指定的 `API` 来获取更多数据,或者反馈响应给协议端;NoneBot 也可以通过调用 `API` 向协议端主动请求数据或者主动推送数据。
-
-在**指南**模块,我们已经叙述了[如何配置 NoneBot](../tutorial/configuration.md)、[如何注册协议适配器](../tutorial/register-adapter.md)以及[如何加载插件](../tutorial/plugin/load-plugin.md),这里便不再赘述。
-
-下面,我们将对**事件处理**,**调用 API** 进行说明。
-
-## 事件处理
-
-我们可以先看事件处理的流程图:
-
-![handle-event](./images/Handle-Event.png)
-
-在流程图里,我们可以看到,NoneBot 会有三个阶段来处理事件:
-
-1. **Driver 接收上报数据**
-2. **Adapter 处理原始数据**
-3. **NoneBot 处理 Event**
-
-我们将顺序说明这三个阶段。其中,会将第三个阶段拆分成**概念解释**,**处理 Event**,**特殊异常处理**三个部分来说明。
-
-### Driver 接收上报数据
-
-1. 协议端会通过 websocket 或 http 等方式与 NoneBot 的后端驱动 `Driver` 连接,协议端上报数据后,`Driver` 会将原始数据交给 `Adapter` 处理。
-
-:::warning
-连接之前必须要注册 `Adapter`
-:::
-
-### Adapter 处理原始数据
-
-1. `Adapter` 检查授权许可,并获取 `self-id` 作为唯一识别 id 。
-
-:::tip
-如果协议端通过 websocket 上报数据,这个步骤只会在建立连接时进行,并在之后运行 `on_bot_connect` 钩子函数;通过 http 方式连接时,会在协议端每次上报数据时都进行这个步骤。
-:::
-
-:::warning
-`self-id` 是帐号的唯一识别 ID ,这意味着不能出现相同的 `self-id`。
-:::
-
-2. 根据 `self-id` 实例化 `Adapter` 相应的 `Bot` 。
-
-3. 根据 `Event Model` 将原始数据转化为 NoneBot 可以处理的 `Event` 对象。
-
-:::tip
-`Adapter` 在转换数据格式的同时可以进行一系列的特殊操作,例如 OneBot 适配器会对 reply 信息进行提取。
-:::
-
-4. `Bot` 和 `Event` 交由 NoneBot 进一步处理。
-
-### NoneBot 处理 Event
-
-在讲述这个阶段之前,我们需要先对几个概念进行解释。
-
-#### 概念解释
-
-1. **hook** ,或者说**钩子函数**,它们可以在 NoneBot 处理 `Event` 的不同时刻进行拦截,修改或者扩展,在 NoneBot 中,事件钩子函数分为`事件预处理 hook`、`运行预处理 hook`、`运行后处理 hook` 和`事件后处理 hook`。
-
-:::tip
-关于 `hook` 的更多信息,可以查阅[这里](./runtime-hook.md)。
-:::
-
-2. **Matcher** 与 **matcher**,在**指南**中,我们讲述了[如何注册事件响应器](../tutorial/plugin/create-matcher.md),这里的事件响应器或者说 `Matcher` 并不是一个具体的实例 `instance`,而是一个具有特定属性的类 `class`。只有当 `Matcher` **响应事件**时,才会实例化为具体的 `instance`,也就是 `matcher` 。`matcher` 可以认为是 NoneBot 处理 `Event` 的基本单位,运行 `matcher` 是 NoneBot 工作的主要内容。
-
-3. **handler**,或者说**事件处理函数**,它们可以认为是 NoneBot 处理 `Event` 的最小单位。在不考虑 `hook` 的情况下,**运行 matcher 就是顺序运行 matcher.handlers**,这句话换种表达方式就是,`handler` 只有添加到 `matcher.handlers` 时,才可以参与到 NoneBot 的工作中来。
-
-:::tip
-如何让 `handler` 添加到 `matcher.handlers`?
-
-一方面,我们可以参照[这里](../tutorial/plugin/create-handler.md)利用装饰器来添加;另一方面,我们在用 `on()` 或者 `on_*()` 注册事件响应器时,可以添加 `handlers=[handler1, handler2, ...]` 这样的关键词参数来添加。
-:::
-
-#### 处理 Event
-
-1. **执行事件预处理 hook**, NoneBot 接收到 `Event` 后,会传入到 `事件预处理 hook` 中进行处理。
-
-:::warning
-需要注意的是,执行多个 `事件预处理 hook` 时并无顺序可言,它们是**并发运行**的。这个原则同样适用于其他的 `hook`。
-:::
-
-2. **按优先级升序选出同一优先级的 Matcher**,NoneBot 提供了一个全局字典 `matchers`,这个字典的 `key` 是优先级 `priority`,`value` 是一个 `list`,里面存放着同一优先级的 `Matcher`。在注册 `Matcher` 时,它和优先级 `priority` 会添加到里面。
-
- 在执行 `事件预处理 hook` 后,NoneBot 会对 `matchers` 的 `key` 升序排序并选择出当前最小优先级的 `Matcher`。
-
-3. **根据 Matcher 定义的 Rule、Permission 判断是否运行**,在选出 `Matcher` 后,NoneBot 会将 `bot`,`Event` 传入到 `Matcher.check_rule` 和 `Matcher.check_perm` 两个函数中,两个函数分别对 Matcher 定义的 `Rule`、`Permission` 进行 check,当 check 通过后,这个 `Matcher` 就会响应事件。当同一个优先级的所有 `Matcher` 均没有响应时,NoneBot 会返回到上一个步骤,选择出下一优先级的 `Matcher`。
-
-4. **实例化 matcher 并执行运行预处理 hook**,当 `Matcher` 响应事件后,它便会实例化为 `matcher`,并执行 `运行预处理 hook`。
-
-5. **顺序运行 matcher 的所有 handlers**,`运行预处理 hook` 执行完毕后,便会运行 `matcher`,也就是**顺序运行**它的 `handlers`。
-
-:::tip
-`matcher` 运行 `handlers` 的顺序是:先运行该 `matcher` 的类 `Matcher` 注册时添加的 `handlers`(如果有的话),再按照装饰器装饰顺序运行装饰的 `handlers`。
-:::
-
-6. **执行运行后处理 hook**,`matcher` 的 `handlers` 运行完毕后,会执行 `运行后处理 hook`。
-
-7. **判断是否停止事件传播**,NoneBot 会根据当前优先级所有 `matcher` 的 `block` 参数或者 `StopPropagation` 异常判断是否停止传播 `Event`,如果事件没有停止传播,NoneBot 便会返回到第 2 步, 选择出下一优先级的 `Matcher`。
-
-8. **执行事件后处理 hook**,在 `Event` 停止传播或执行完所有响应的 `Matcher` 后,NoneBot 会执行 `事件后处理 hook`。
-
- 当 `事件后处理 hook` 执行完毕后,当前 `Event` 的处理周期就顺利结束了。
-
-#### 特殊异常处理
-
-在这个阶段,NoneBot 规定了几个特殊的异常,当 NoneBot 捕获到它们时,会用特定的行为来处理它们。
-
-1. **IgnoredException**
-
- 这个异常可以在 `事件预处理 hook` 和 `运行预处理 hook` 抛出。
-
- 当 `事件预处理 hook` 抛出它时,NoneBot 会忽略当前的 `Event`,不进行处理。
-
- 当 `运行预处理 hook` 抛出它时,NoneBot 会忽略当前的 `matcher`,结束当前 `matcher` 的运行。
-
-:::warning
-当 `hook` 需要抛出这个异常时,要写明原因。
-:::
-
-2. **PausedException**
-
- 这个异常可以在 `handler` 中由 `Matcher.pause` 抛出。
-
- 当 NoneBot 捕获到它时,会停止运行当前 `handler` 并结束当前 `matcher` 的运行,并将后续的 `handler` 交给一个临时 `Matcher` 来响应当前交互用户的下一个消息事件,当临时 `Matcher` 响应时,临时 `Matcher` 会运行后续的 `handler`。
-
-3. **RejectedException**
-
- 这个异常可以在 `handler` 中由 `Matcher.reject` 抛出。
-
- 当 NoneBot 捕获到它时,会停止运行当前 `handler` 并结束当前 `matcher` 的运行,并将当前 handler 和后续 `handler` 交给一个临时 `Matcher` 来响应当前交互用户的下一个消息事件,当临时 `Matcher` 响应时,临时 `Matcher` 会运行当前 `handler` 和后续的 `handler` 。
-
-4. **FinishedException**
-
- 这个异常可以在 `handler` 中由 `Matcher.finish` 抛出。
-
- 当 NoneBot 捕获到它时,会停止运行当前 `handler` 并结束当前 `matcher` 的运行。
-
-5. **StopPropagation**
-
- 这个异常一般会在执行 `运行后处理 hook` 后抛出。
-
- 当 NoneBot 捕获到它时, 会停止传播当前 `Event` ,不再寻找下一优先级的 `Matcher` ,直接执行 `事件后处理 hook` 。
-
-## 调用 API
-
-NoneBot 可以通过 `bot` 来调用 `API`,`API` 可以向协议端发送数据,也可以向协议端请求更多的数据。
-
-NoneBot 调用 `API` 会有如下过程:
-
-1. 调用 `calling_api_hook` 预处理钩子。
-
-2. `adapter` 将信息处理为原始数据,并转交 `driver`,`driver` 交给协议端处理。
-
-3. `driver` 接收协议端的结果,交给`adapter` 处理之后将结果反馈给 NoneBot 。
-
-4. 调用 `called_api_hook` 后处理钩子。
-
-在调用 `API` 时同样规定了特殊的异常,叫做 `MockApiException` 。该异常会由预处理钩子和后处理钩子触发,当预处理钩子触发时,NoneBot 会跳过之后的调用过程,直接执行后处理钩子。
-
-:::tip
-不同 `adapter` 规定了不同的 API,对应的 API 列表请参照协议规范。
-:::
-
-一般来说,我们可以用 `bot.*` 来调用 `API`(\*是 `API` 的 `action` 或者 `endpoint`)。
-
-对于发送消息而言,一方面可以调用既有的 `API` ;另一方面 NoneBot 实现了两个便捷方法,`bot.send(event, message, **kwargs)` 方法和可以在 `handler` 中使用的 `Matcher.send(message, **kwargs)` 方法,来向事件主体发送消息。
diff --git a/website/docs/advanced/adapter.md b/website/docs/advanced/adapter.md
new file mode 100644
index 000000000000..2cf883957f19
--- /dev/null
+++ b/website/docs/advanced/adapter.md
@@ -0,0 +1,161 @@
+---
+sidebar_position: 1
+description: 注册适配器与指定平台交互
+
+options:
+ menu:
+ weight: 20
+ category: advanced
+---
+
+# 使用适配器
+
+适配器 (Adapter) 是机器人与平台交互的核心桥梁,它负责在驱动器和机器人插件之间转换与传递消息。
+
+## 适配器功能与组成
+
+适配器通常有两种功能,分别是**接收事件**和**调用平台接口**。其中,接收事件是指将驱动器收到的事件消息转换为 NoneBot 定义的事件模型,然后交由机器人插件处理;调用平台接口是指将机器人插件调用平台接口的数据转换为平台指定的格式,然后交由驱动器发送,并接收接口返回数据。
+
+为了实现这两种功能,适配器通常由四个部分组成:
+
+- **Adapter**:负责转换事件和调用接口,正确创建 Bot 对象并注册到 NoneBot 中。
+- **Bot**:负责存储平台机器人相关信息,并提供回复事件的方法。
+- **Event**:负责定义事件内容,以及事件主体对象。
+- **Message**:负责正确序列化消息,以便机器人插件处理。
+
+## 注册适配器
+
+在使用适配器之前,我们需要先将适配器注册到驱动器中,这样适配器就可以通过驱动器接收事件和调用接口了。我们以 Console 适配器为例,来看看如何注册适配器:
+
+```python {2,5} title=bot.py
+import nonebot
+from nonebot.adapters.console import Adapter
+
+driver = nonebot.get_driver()
+driver.register_adapter(Adapter)
+```
+
+我们首先需要从适配器模块中导入所需要的适配器类,然后通过驱动器的 `register_adapter` 方法将适配器注册到驱动器中即可。
+
+## 获取已注册的适配器
+
+NoneBot 提供了 `get_adapter` 方法来获取已注册的适配器,我们可以通过适配器的名称或类型来获取指定的适配器实例:
+
+```python
+import nonebot
+from nonebot.adapters.console import Adapter
+
+adapters = nonebot.get_adapters()
+console_adapter = nonebot.get_adapter(Adapter)
+console_adapter = nonebot.get_adapter(Adapter.get_name())
+```
+
+## 获取 Bot 对象
+
+当前所有适配器已连接的 Bot 对象可以通过 `get_bots` 方法获取,这是一个以机器人 ID 为键的字典:
+
+```python
+import nonebot
+
+bots = nonebot.get_bots()
+```
+
+我们也可以通过 `get_bot` 方法获取指定 ID 的 Bot 对象。如果省略 ID 参数,将会返回所有 Bot 中的第一个:
+
+```python
+import nonebot
+
+bot = nonebot.get_bot("bot_id")
+```
+
+如果需要获取指定适配器连接的 Bot 对象,我们可以通过适配器的 `bots` 属性获取,这也是一个以机器人 ID 为键的字典:
+
+```python
+import nonebot
+from nonebot.adapters.console import Adapter
+
+console_adapter = nonebot.get_adapter(Adapter)
+bots = console_adapter.bots
+```
+
+Bot 对象都具有一个 `self_id` 属性,它是机器人的唯一 ID,由适配器填写,通常为机器人的帐号 ID 或者 APP ID。
+
+## 获取事件通用信息
+
+适配器的所有事件模型均继承自 `Event` 基类,在[事件类型与重载](../appendices/overload.md)一节中,我们也提到了如何使用基类抽象方法来获取事件通用信息。基类能提供如下信息:
+
+### 事件类型
+
+事件类型通常为 `meta_event`、`message`、`notice`、`request`。
+
+```python
+type: str = event.get_type()
+```
+
+### 事件名称
+
+事件名称由适配器定义,通常用于日志记录。
+
+```python
+name: str = event.get_event_name()
+```
+
+### 事件描述
+
+事件描述由适配器定义,通常用于日志记录。
+
+```python
+description: str = event.get_event_description()
+```
+
+### 事件日志字符串
+
+事件日志字符串由事件名称和事件描述组成,用于日志记录。
+
+```python
+log: str = event.get_log_string()
+```
+
+### 事件主体 ID
+
+事件主体 ID 通常为机器人用户 ID。
+
+```python
+user_id: str = event.get_user_id()
+```
+
+### 事件会话 ID
+
+事件会话 ID 通常为机器人用户 ID 与群聊/频道 ID 组合而成。
+
+```python
+session_id: str = event.get_session_id()
+```
+
+### 事件消息
+
+如果事件包含消息,则可以通过该方法获取,否则会产生异常。
+
+```python
+message: Message = event.get_message()
+```
+
+### 事件纯文本消息
+
+通常为事件消息的纯文本内容,如果事件不包含消息,则会产生异常。
+
+```python
+text: str = event.get_plaintext()
+```
+
+### 事件是否与机器人有关
+
+由适配器实现的判断,通常将事件目标主体为机器人、消息中包含“@机器人”或以“机器人的昵称”开始视为与机器人有关。
+
+```python
+is_tome: bool = event.is_tome()
+```
+
+## 更多
+
+官方支持的适配器和社区贡献的适配器均可在[商店](/store)中查看。如果你想要开发自己的适配器,可以参考[开发文档](../developer/adapter-writing.md)。欢迎通过商店发布你的适配器。
diff --git a/website/docs/advanced/dependency.mdx b/website/docs/advanced/dependency.mdx
new file mode 100644
index 000000000000..14e9a0db0ffb
--- /dev/null
+++ b/website/docs/advanced/dependency.mdx
@@ -0,0 +1,1189 @@
+---
+sidebar_position: 6
+description: 通过依赖注入获取上下文信息
+
+options:
+ menu:
+ weight: 70
+ category: advanced
+---
+
+# 依赖注入
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+在事件处理流程中,事件响应器具有自己独立的上下文,例如:当前的事件、机器人等信息。在 NoneBot 中,这些信息通过依赖注入的方式提供给事件处理函数,可以让代码更加整洁可读、提升复用能力。
+
+在了解如何使用依赖注入获取上下文信息之前,我们需要先了解两个概念:
+
+- `Dependent`:使用依赖注入的函数或其他任意可调用对象。如:事件处理函数、自定义的依赖函数等。
+- `Dependency`:依赖注入的对象。如:当前事件、机器人等。
+
+在之前的文档中,我们已经多次使用了依赖注入来获取事件信息。通过对函数参数依照一定规则填写类型注解,即可获得想要的上下文信息。任何一个事件处理函数在添加到事件处理流程时,都会根据一定规则提前将其解析成一个 `Dependent` 对象,方便运行时进行注入。如果遇到无法解析的参数,将会抛出 `ValueError("Unknown parameter")` 的异常。整个依赖注入系统可以分为两部分:
+
+- 参数解析
+ - 依据一定规则解析函数参数,识别 `Dependency` 依赖。
+ - 生成 `Dependent` 对象。
+- 执行
+ - 根据已经解析的 `Dependency` 依赖,执行调用。
+ - 将所有 `Dependency` 的返回值根据参数名传入并调用 `Dependent` 。
+
+:::danger 警告
+在依赖注入中,类型注解是非常重要的,因为它不仅可以决定依赖注入的对象,还可以触发[重载机制](../appendices/overload.md#重载)。如果类型注解与实际获得数据类型不一致,将会跳过当前 `Dependent` 对象(即事件处理函数)。
+:::
+
+:::tip 提示
+如果对于依赖注入的解析流程有疑问,可以调整[日志等级配置项](../appendices/config.mdx#log-level)为 `TRACE`,查看依赖解析日志。
+:::
+
+## 同步支持
+
+对于依赖注入系统中的 `Dependent` 或者 `Dependency` 对象,均支持同步类型的函数或可调用对象。例如:
+
+```python {6,10}
+from nonebot import on_command
+from nonebot.params import Depends
+
+matcher = on_command("foo")
+
+def dependency() -> str:
+ return "something"
+
+@matcher.handle()
+def _(result: str = Depends(dependency)):
+ ...
+```
+
+## 非依赖参数
+
+在依赖注入解析中,任何无法解析的参数如果带有默认值,将会被视为非依赖参数。这些参数在依赖运行时将不会被注入而使用函数默认值。例如:
+
+```python
+async def _(foo: str = "bar"): ...
+```
+
+## 类型依赖注入
+
+这一类的依赖注入仅需要在函数参数中添加对应的类型注解即可。
+
+### Bot
+
+获取当前事件的 Bot 对象。
+
+通过标注参数为 `Bot` 类型,或者一系列 `Bot` 类型,即可获取到当前事件的 Bot 对象。为兼容性考虑,如果参数名为 `bot` 且无类型注解,也会视为 `Bot` 依赖注入。
+
+
+
+
+```python
+from nonebot.adapters import Bot
+from nonebot.adapters.console import Bot as ConsoleBot
+from nonebot.adapters.onebot.v11 import Bot as OneBotV11Bot
+
+async def _(foo: Bot): ...
+async def _(foo: ConsoleBot | OneBotV11Bot): ...
+async def _(bot): ... # 兼容性处理
+```
+
+
+
+
+```python
+from typing import Union
+
+from nonebot.adapters import Bot
+from nonebot.adapters.console import Bot as ConsoleBot
+from nonebot.adapters.onebot.v11 import Bot as OneBotV11Bot
+
+async def _(foo: Bot): ...
+async def _(foo: Union[ConsoleBot, OneBotV11Bot]): ...
+async def _(bot): ... # 兼容性处理
+```
+
+
+
+
+### Event
+
+获取当前事件。
+
+通过标注参数为 `Event` 类型,或者一系列 `Event` 类型,即可获取到当前事件。为兼容性考虑,如果参数名为 `event` 且无类型注解,也会视为 `Event` 依赖注入。
+
+
+
+
+```python
+from nonebot.adapters import Event
+from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent
+
+async def _(foo: Event): ...
+async def _(foo: PrivateMessageEvent | GroupMessageEvent): ...
+async def _(event): ... # 兼容性处理
+```
+
+
+
+
+```python
+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): ... # 兼容性处理
+```
+
+
+
+
+### State
+
+获取当前[会话状态](../appendices/session-state.md)。
+
+```python
+from nonebot.typing import T_State
+
+async def _(foo: T_State): ...
+```
+
+### Matcher
+
+获取当前事件响应器实例。常用于使用[事件响应器操作](../appendices/session-control.mdx)。
+
+```python
+from nonebot.matcher import Matcher
+
+async def _(matcher: Matcher): ...
+```
+
+### Exception
+
+获取事件响应器运行中抛出的异常。该依赖注入目前仅在事件响应器运行后处理 Hook 中可用。
+
+通过标注参数为异常类型,或者一系列异常类型,即可获取到事件响应器运行中抛出的异常。
+
+
+
+
+```python {5,8}
+from nonebot.message import run_postprocessor
+from nonebot.exception import ActionFailed, NetworkError
+
+@run_postprocessor
+async def _(e: Exception): ...
+
+@run_postprocessor
+async def _(e: ActionFailed | NetworkError): ...
+```
+
+
+
+
+```python {6,9}
+from typing import Union
+from nonebot.message import run_postprocessor
+from nonebot.exception import ActionFailed, NetworkError
+
+@run_postprocessor
+async def _(e: Exception): ...
+
+@run_postprocessor
+async def _(e: Union[ActionFailed, NetworkError]): ...
+```
+
+
+
+
+## 子依赖
+
+在依赖注入系统中,我们可以定义一个子依赖,来执行自定义的操作,提高代码复用性以及处理性能。
+
+### 定义子依赖
+
+子依赖使用 `Depends` 标记进行定义,其参数即依赖的函数或可调用对象,同样会被解析为 `Dependent` 对象,将会在依赖注入期间执行。我们来看一个例子:
+
+
+
+
+```python {4,16}
+from typing import Annotated
+
+from nonebot import on_command
+from nonebot.params import Depends
+from nonebot.matcher import Matcher
+from nonebot.adapters.console import MessageEvent
+
+test = on_command("test")
+
+async def check(event: MessageEvent, matcher: Matcher) -> MessageEvent:
+ if event.get_user_id() in BLACKLIST:
+ await matcher.finish()
+ return event
+
+@test.handle()
+async def _(event: Annotated[MessageEvent, Depends(check)]):
+ ...
+```
+
+
+
+
+```python {2,14}
+from nonebot import on_command
+from nonebot.params import Depends
+from nonebot.matcher import Matcher
+from nonebot.adapters.console import MessageEvent
+
+test = on_command("test")
+
+async def check(event: MessageEvent, matcher: Matcher) -> MessageEvent:
+ if event.get_user_id() in BLACKLIST:
+ await matcher.finish()
+ return event
+
+@test.handle()
+async def _(event: MessageEvent = Depends(check)):
+ ...
+```
+
+
+
+
+在上面的代码中,我们使用 `Depends` 标记定义了一个子依赖 `check`。它判断事件主体用户是否在黑名单中,如果在,则直接结束事件处理流程。如果不在,则返回事件对象,以便事件处理函数可以继续执行。
+
+通过将 `Depends` 包裹的子依赖作为参数的默认值,我们就可以在执行事件处理函数之前执行子依赖,并将其返回值作为参数传入事件处理函数。子依赖和普通的事件处理函数并没有区别,同样可以使用依赖注入,并且可以返回任何类型的值。但需要注意的是,如果事件处理函数参数的类型注解与子依赖返回值的类型**不一致**,将会触发[重载](../appendices/overload.md)而跳过当前事件处理函数。
+
+### 依赖缓存
+
+NoneBot 在执行子依赖时,会将其返回值缓存起来。当我们在使用子依赖时,`Depends` 具有一个参数 `use_cache`,默认为 `True`。此时在事件处理流程中,多次使用同一个子依赖时,将会使用缓存中的结果而不会重复执行。这在很多情景中非常有用,例如:
+
+
+
+
+```python {7}
+import random
+from typing import Annotated
+
+async def random_result() -> int:
+ return random.randint(1, 100)
+
+async def _(x: Annotated[int, Depends(random_result)]):
+ print(x)
+```
+
+
+
+
+```python {6}
+import random
+
+async def random_result() -> int:
+ return random.randint(1, 100)
+
+async def _(x: int = Depends(random_result)):
+ print(x)
+```
+
+
+
+
+此时,在同一事件处理流程中,这个随机函数的返回值将会保持一致。如果我们希望每次都重新执行子依赖,可以将 `use_cache` 设置为 `False`。
+
+
+
+
+```python {7}
+import random
+from typing import Annotated
+
+async def random_result() -> int:
+ return random.randint(1, 100)
+
+async def _(x: Annotated[int, Depends(random_result, use_cache=False)]):
+ print(x)
+```
+
+
+
+
+```python {6}
+import random
+
+async def random_result() -> int:
+ return random.randint(1, 100)
+
+async def _(x: int = Depends(random_result, use_cache=False)):
+ print(x)
+```
+
+
+
+
+:::tip 提示
+缓存的生命周期与当前接收到的事件相同。接收到事件后,子依赖在首次执行时缓存,在该事件处理完成后,缓存就会被清除。
+:::
+
+### 类作为依赖
+
+在前面的事例中,我们使用了函数作为子依赖。实际上,我们还可以使用类作为依赖。当我们在实例化一个类的时候,其实我们就在调用它,类本身也是一个可调用对象。例如:
+
+
+
+
+```python {16}
+from typing import Annotated
+from dataclasses import dataclass
+
+from nonebot.params import Depends
+from nonebot.adapters import Event
+from nonebot.typing import T_State
+
+def get_context(state: T_State) -> dict:
+ return state.setdefault("context", {})
+
+@dataclass
+class ClassDependency:
+ event: Event
+ context: dict = Depends(get_context)
+
+async def _(data: Annotated[ClassDependency, Depends(ClassDependency)]):
+ print(data.event, data.context)
+```
+
+
+
+
+```python {15}
+from dataclasses import dataclass
+
+from nonebot.params import Depends
+from nonebot.adapters import Event
+from nonebot.typing import T_State
+
+def get_context(state: T_State) -> dict:
+ return state.setdefault("context", {})
+
+@dataclass
+class ClassDependency:
+ event: Event
+ context: dict = Depends(get_context)
+
+async def _(data: ClassDependency = Depends(ClassDependency)):
+ print(data.event, data.context)
+```
+
+
+
+
+可以看到,我们使用 `dataclass` 定义了一个类。由于这个类的 `__init__` 方法可以被依赖注入系统解析,因此,我们可以将其作为子依赖进行声明。特别地,对于类依赖,`Depends` 的参数可以为空,NoneBot 将会使用参数的类型注解进行解析与推断:
+
+
+
+
+```python
+from typing import Annotated
+
+async def _(data: Annotated[ClassDependency, Depends()]):
+ print(data.event, data.context)
+```
+
+
+
+
+```python
+async def _(data: ClassDependency = Depends()):
+ print(data.event, data.context)
+```
+
+
+
+
+### 生成器作为依赖
+
+NoneBot 的依赖注入支持依赖项在事件处理流程结束后进行一些额外的工作,比如数据库 session 或者网络 IO 的关闭,互斥锁的解锁等等。同时,由于[依赖缓存](#依赖缓存)的存在,我们可以通过这种方式来实现共享一个 session 等功能。
+
+要实现上述功能,我们可以用生成器函数作为依赖项,我们用 `yield` 关键字取代 `return` 关键字,并在 `yield` 之后进行额外的工作。
+
+我们可以看下述代码段, 使用 `httpx.AsyncClient` 异步网络 IO,并在事件处理流程中共用一个 client:
+
+
+
+
+```python {15}
+from typing import Annotated, AsyncGenerator
+
+import httpx
+from nonebot.params import Depends
+
+async def get_client() -> AsyncGenerator[httpx.AsyncClient, None]:
+ try:
+ async with httpx.AsyncClient() as client:
+ yield client
+ finally:
+ # 在这里进行额外的工作
+
+
+@test.handle()
+async def _(x: Annotated[httpx.AsyncClient, Depends(get_client)]):
+ resp = await x.get("https://v2.nonebot.dev")
+```
+
+
+
+
+```python {15}
+from typing import AsyncGenerator
+
+import httpx
+from nonebot.params import Depends
+
+async def get_client() -> AsyncGenerator[httpx.AsyncClient, None]:
+ try:
+ async with httpx.AsyncClient() as client:
+ yield client
+ finally:
+ # 在这里进行额外的工作
+
+
+@test.handle()
+async def _(x: httpx.AsyncClient = Depends(get_client)):
+ resp = await x.get("https://v2.nonebot.dev")
+```
+
+
+
+
+:::warning 注意
+生成器作为依赖时,其中只能进行一次 `yield`,否则将会触发异常。如果对此有疑问并想探究原因,可以参考 [contextmanager](https://docs.python.org/zh-cn/3/library/contextlib.html#contextlib.contextmanager) 和 [asynccontextmanager](https://docs.python.org/zh-cn/3/library/contextlib.html#contextlib.asynccontextmanager) 文档。事实上,NoneBot 内部就使用了这两个装饰器。
+:::
+
+### 可调用对象作为依赖
+
+在 Python 里,为类定义 `__call__` 方法就可以使得这个类的实例成为一个可调用对象。因此,我们也可以将定义了 `__call__` 方法的类的实例作为依赖。事实上,NoneBot 的[内置响应规则](./matcher.md#内置响应规则)就广泛使用了这种方式,以 `is_type` 规则为例:
+
+```python
+from typing import Type
+from nonebot.adapters import Event
+
+class IsTypeRule:
+ def __init__(self, *types: Type[Event]):
+ self.types = types
+
+ async def __call__(self, event: Event) -> bool:
+ return isinstance(event, self.types)
+```
+
+我们在使用 `is_type` 时,即实例化了 `IsTypeRule` 类,然后将实例作为响应规则依赖项传入。
+
+## 其他依赖注入
+
+这一类的依赖注入通常基于子依赖编写,为我们开发者提供更方便的途径获取上下文信息。
+
+### EventType
+
+获取当前事件的类型。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import EventType
+
+async def _(foo: Annotated[str, EventType()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import EventType
+
+async def _(foo: str = EventType()): ...
+```
+
+
+
+
+### EventMessage
+
+获取当前事件的消息。
+
+
+
+
+```python {5}
+from typing import Annotated
+from nonebot.adapters import Message
+from nonebot.params import EventMessage
+
+async def _(foo: Annotated[Message, EventMessage()]): ...
+```
+
+
+
+
+```python {4}
+from nonebot.adapters import Message
+from nonebot.params import EventMessage
+
+async def _(foo: Message = EventMessage()): ...
+```
+
+
+
+
+### EventPlainText
+
+获取当前事件的消息纯文本部分。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import EventPlainText
+
+async def _(foo: Annotated[str, EventPlainText()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import EventPlainText
+
+async def _(foo: str = EventPlainText()): ...
+```
+
+
+
+
+### EventToMe
+
+获取当前事件是否与机器人相关。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import EventToMe
+
+async def _(foo: Annotated[bool, EventToMe()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import EventToMe
+
+async def _(foo: bool = EventToMe()): ...
+```
+
+
+
+
+### Command
+
+获取当前命令型消息的元组形式命令名。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import Command
+
+async def _(foo: Annotated[tuple[str, ...], Command()]): ...
+```
+
+
+
+
+```python {4}
+from typing import Tuple
+from nonebot.params import Command
+
+async def _(foo: Tuple[str, ...] = Command()): ...
+```
+
+
+
+
+:::tip 提示
+命令详情只能在**触发命令型事件响应器时**获取。如果在事件处理后续流程中获取,则会获取到不同的值。
+:::
+
+### RawCommand
+
+获取当前命令型消息的文本形式命令名。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import RawCommand
+
+async def _(foo: Annotated[str, RawCommand()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import RawCommand
+
+async def _(foo: str = RawCommand()): ...
+```
+
+
+
+
+:::tip 提示
+命令详情只能在**触发命令型事件响应器时**获取。如果在事件处理后续流程中获取,则会获取到不同的值。
+:::
+
+### CommandArg
+
+获取命令型消息命令后跟随的参数。
+
+
+
+
+```python {5}
+from typing import Annotated
+from nonebot.adapters import Message
+from nonebot.params import CommandArg
+
+async def _(foo: Annotated[Message, CommandArg()]): ...
+```
+
+
+
+
+```python {4}
+from nonebot.adapters import Message
+from nonebot.params import CommandArg
+
+async def _(foo: Message = CommandArg()): ...
+```
+
+
+
+
+:::tip 提示
+命令详情只能在**触发命令型事件响应器时**获取。如果在事件处理后续流程中获取,则会获取到不同的值。
+:::
+
+### CommandStart
+
+获取命令型消息命令前缀。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import CommandStart
+
+async def _(foo: Annotated[str, CommandStart()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import CommandStart
+
+async def _(foo: str = CommandStart()): ...
+```
+
+
+
+
+:::tip 提示
+命令详情只能在**触发命令型事件响应器时**获取。如果在事件处理后续流程中获取,则会获取到不同的值。
+:::
+
+### CommandWhitespace
+
+获取命令型消息命令与参数间空白符。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import CommandWhitespace
+
+async def _(foo: Annotated[str, CommandWhitespace()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import CommandWhitespace
+
+async def _(foo: str = CommandWhitespace()): ...
+```
+
+
+
+
+:::tip 提示
+命令详情只能在**触发命令型事件响应器时**获取。如果在事件处理后续流程中获取,则会获取到不同的值。
+:::
+
+### ShellCommandArgv
+
+获取 shell 命令解析前的参数列表,列表中可能包含文本字符串和富文本消息段(如:图片)。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import ShellCommandArgs
+
+async def _(foo: Annotated[list[str | MessageSegment], ShellCommandArgv()]): ...
+```
+
+
+
+
+```python {4}
+from typing import Union, Annotated
+from nonebot.params import ShellCommandArgs
+
+async def _(foo: Annotated[list[Union[str, MessageSegment]], ShellCommandArgv()]): ...
+```
+
+
+
+
+```python {4}
+from typing import List, Union
+from nonebot.params import ShellCommandArgs
+
+async def _(foo: List[Union[str, MessageSegment]] = ShellCommandArgv()): ...
+```
+
+
+
+
+### ShellCommandArgs
+
+获取 shell 命令解析后的参数 Namespace,支持 MessageSegment 富文本(如:图片)。
+
+:::tip 提示
+如果参数解析成功,则为 parser 返回的 Namespace;如果参数解析失败,则为 [`ParserExit`](../api/exception.md#ParserExit) 异常,并携带错误码与错误信息。通过重载机制即可处理两种不同的情况。
+
+由于 `ArgumentParser` 在解析到 `--help` 参数时也会抛出异常,这种情况下错误码为 `0` 且错误信息即为帮助信息。
+:::
+
+
+
+
+```python {14,22}
+from typing import Annotated
+
+from nonebot import on_shell_command
+from nonebot.exception import ParserExit
+from nonebot.params import ShellCommandArgs
+from nonebot.rule import Namespace, ArgumentParser
+
+parser = ArgumentParser("demo")
+# parser.add_argument ...
+matcher = on_shell_command("cmd", parser=parser)
+
+# 解析失败
+@matcher.handle()
+async def _(foo: Annotated[ParserExit, ShellCommandArgs()]):
+ if foo.status == 0:
+ foo.message # help message
+ else:
+ foo.message # error message
+
+# 解析成功
+@matcher.handle()
+async def _(foo: Annotated[Namespace, ShellCommandArgs()]):
+ arg_dict = vars(foo)
+```
+
+
+
+
+```python {12,20}
+from nonebot import on_shell_command
+from nonebot.exception import ParserExit
+from nonebot.params import ShellCommandArgs
+from nonebot.rule import Namespace, ArgumentParser
+
+parser = ArgumentParser("demo")
+# parser.add_argument ...
+matcher = on_shell_command("cmd", parser=parser)
+
+# 解析失败
+@matcher.handle()
+async def _(foo: ParserExit = ShellCommandArgs()):
+ if foo.status == 0:
+ foo.message # help message
+ else:
+ foo.message # error message
+
+# 解析成功
+@matcher.handle()
+async def _(foo: Namespace = ShellCommandArgs()):
+ arg_dict = vars(foo)
+```
+
+
+
+
+### RegexStr
+
+获取正则匹配结果的文本。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import RegexStr
+
+async def _(foo: Annotated[str, RegexStr()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import RegexStr
+
+async def _(foo: str = RegexStr()): ...
+```
+
+
+
+
+### RegexGroup
+
+获取正则匹配结果的 group 元组。
+
+
+
+
+```python {4}
+from typing import Any, Annotated
+from nonebot.params import RegexGroup
+
+async def _(foo: Annotated[tuple[Any, ...], RegexGroup()]): ...
+```
+
+
+
+
+```python {4}
+from typing import Tuple, Any
+from nonebot.params import RegexGroup
+
+async def _(foo: Tuple[Any, ...] = RegexGroup()): ...
+```
+
+
+
+
+### RegexDict
+
+获取正则匹配结果的 group 字典。
+
+
+
+
+```python {4}
+from typing import Any, Annotated
+from nonebot.params import RegexDict
+
+async def _(foo: Annotated[dict[str, Any], RegexDict()]): ...
+```
+
+
+
+
+```python {4}
+from typing import Any, Dict
+from nonebot.params import RegexDict
+
+async def _(foo: Dict[str, Any] = RegexDict()): ...
+```
+
+
+
+
+### Startswith
+
+获取触发响应器的消息前缀字符串。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import Startswith
+
+async def _(foo: Annotated[str, Startswith()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import Startswith
+
+async def _(foo: str = Startswith()): ...
+```
+
+
+
+
+### Endswith
+
+获取触发响应器的消息后缀字符串。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import Endswith
+
+async def _(foo: Annotated[str, Endswith()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import Endswith
+
+async def _(foo: str = Endswith()): ...
+```
+
+
+
+
+### Fullmatch
+
+获取触发响应器的消息字符串。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import Fullmatch
+
+async def _(foo: Annotated[str, Fullmatch()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import Fullmatch
+
+async def _(foo: str = Fullmatch()): ...
+```
+
+
+
+
+### Keyword
+
+获取触发响应器的关键字字符串。
+
+
+
+
+```python {4}
+from typing import Annotated
+from nonebot.params import Keyword
+
+async def _(foo: Annotated[str, Keyword()]): ...
+```
+
+
+
+
+```python {3}
+from nonebot.params import Keyword
+
+async def _(foo: str = Keyword()): ...
+```
+
+
+
+
+### Received
+
+获取某次 `receive` 接收的事件。
+
+
+
+
+```python {7}
+from typing import Annotated
+
+from nonebot.adapters import Event
+from nonebot.params import Received
+
+@matcher.receive("id")
+async def _(foo: Annotated[Event, Received("id")]): ...
+```
+
+
+
+
+```python {5}
+from nonebot.adapters import Event
+from nonebot.params import Received
+
+@matcher.receive("id")
+async def _(foo: Event = Received("id")): ...
+```
+
+
+
+
+### LastReceived
+
+获取最近一次 `receive` 接收的事件。
+
+
+
+
+```python {7}
+from typing import Annotated
+
+from nonebot.adapters import Event
+from nonebot.params import LastReceived
+
+@matcher.receive("any")
+async def _(foo: Annotated[Event, LastReceived()]): ...
+```
+
+
+
+
+```python {5}
+from nonebot.adapters import Event
+from nonebot.params import LastReceived
+
+@matcher.receive("any")
+async def _(foo: Event = LastReceived()): ...
+```
+
+
+
+
+### Arg
+
+获取某次 `got` 接收的参数。如果 `Arg` 参数留空,则使用函数的参数名作为要获取的参数。
+
+
+
+
+```python {7,8}
+from typing import Annotated
+
+from nonebot.params import Arg
+from nonebot.adapters import Message
+
+@matcher.got("key")
+async def _(key: Annotated[Message, Arg()]): ...
+async def _(foo: Annotated[Message, Arg("key")]): ...
+```
+
+
+
+
+```python {5,6}
+from nonebot.params import Arg
+from nonebot.adapters import Message
+
+@matcher.got("key")
+async def _(key: Message = Arg()): ...
+async def _(foo: Message = Arg("key")): ...
+```
+
+
+
+
+### ArgStr
+
+获取某次 `got` 接收的参数,并转换为字符串。如果 `Arg` 参数留空,则使用函数的参数名作为要获取的参数。
+
+
+
+
+```python {6,7}
+from typing import Annotated
+
+from nonebot.params import ArgStr
+
+@matcher.got("key")
+async def _(key: str = ArgStr()): ...
+async def _(foo: str = ArgStr("key")): ...
+```
+
+
+
+
+```python {4,5}
+from nonebot.params import ArgStr
+
+@matcher.got("key")
+async def _(key: Annotated[str, ArgStr()]): ...
+async def _(foo: Annotated[str, ArgStr("key")]): ...
+```
+
+
+
+
+### ArgPlainText
+
+获取某次 `got` 接收的参数的纯文本部分。如果 `Arg` 参数留空,则使用函数的参数名作为要获取的参数。
+
+
+
+
+```python {6,7}
+from typing import Annotated
+
+from nonebot.params import ArgPlainText
+
+@matcher.got("key")
+async def _(key: Annotated[str, ArgPlainText()]): ...
+async def _(foo: Annotated[str, ArgPlainText("key")]): ...
+```
+
+
+
+
+```python {4,5}
+from nonebot.params import ArgPlainText
+
+@matcher.got("key")
+async def _(key: str = ArgPlainText()): ...
+async def _(foo: str = ArgPlainText("key")): ...
+```
+
+
+
diff --git a/website/docs/advanced/di/_category_.json b/website/docs/advanced/di/_category_.json
deleted file mode 100644
index 60e7734e6624..000000000000
--- a/website/docs/advanced/di/_category_.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "label": "依赖注入",
- "position": 5
-}
diff --git a/website/docs/advanced/di/dependency-injection.md b/website/docs/advanced/di/dependency-injection.md
deleted file mode 100644
index 66645709b4ad..000000000000
--- a/website/docs/advanced/di/dependency-injection.md
+++ /dev/null
@@ -1,243 +0,0 @@
----
-sidebar_position: 1
-description: 依赖注入简介
-
-options:
- menu:
- weight: 60
- category: advanced
----
-
-# 简介
-
-受 [FastAPI](https://fastapi.tiangolo.com/tutorial/dependencies/) 启发,NoneBot 同样编写了一个简易的依赖注入模块,使得开发者可以通过事件处理函数参数的类型标注来自动注入依赖。
-
-## 什么是依赖注入?
-
-[依赖注入](https://zh.wikipedia.org/wiki/%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5)
-
-> 在软件工程中,**依赖注入**(dependency injection)的意思为,给予调用方它所需要的事物。 “依赖”是指可被方法调用的事物。依赖注入形式下,调用方不再直接使用“依赖”,取而代之是“注入” 。“注入”是指将“依赖”传递给调用方的过程。在“注入”之后,调用方才会调用该“依赖。 传递依赖给调用方,而不是让让调用方直接获得依赖,这个是该设计的根本需求。
-
-依赖注入往往起到了分离依赖和调用方的作用,这样一方面能让代码更为整洁可读,一方面可以提升代码的复用性。
-
-## 使用依赖注入
-
-以下通过一个简单的例子来说明依赖注入的使用方法:
-
-```python {2,7-8,11}
-from nonebot import on_command
-from nonebot.params import Depends # 1.引用 Depends
-from nonebot.adapters.onebot.v11 import MessageEvent
-
-test = on_command("123")
-
-async def depend(event: MessageEvent): # 2.编写依赖函数
- return {"uid": event.get_user_id(), "nickname": event.sender.nickname}
-
-@test.handle()
-async def _(x: dict = Depends(depend)): # 3.在事件处理函数里声明依赖项
- print(x["uid"], x["nickname"])
-```
-
-如注释所言,可以用三步来说明依赖注入的使用过程:
-
-1. 引用 `Depends` 。
-
-2. 编写依赖函数。依赖函数和普通的事件处理函数并无区别,同样可以接收 `bot`, `event`, `state` 等参数,你可以把它当作一个普通的事件处理函数,但是去除了装饰器(没有使用 `matcher.handle()` 等来装饰),并且可以返回任何类型的值。
-
- 在这里我们接受了 `event`,并以 `onebot` 的 `MessageEvent` 作为类型标注,返回一个新的字典,包括 `uid` 和 `nickname` 两个键值。
-
-3. 在事件处理函数中声明依赖项。依赖项必须要 `Depends` 包裹依赖函数作为默认值。
-
-:::tip
-请注意,参数 `x` 的类型标注将会影响到事件处理函数的运行,与类型标注不符的值将会导致事件处理函数被跳过。
-:::
-
-:::tip
-事实上,bot、event、state 它们本身只是依赖注入的一个特例,它们无需声明这是依赖即可注入。
-:::
-
-虽然声明依赖项的方式和其他参数如 `bot`, `event` 并无二样,但他的参数有一些限制,必须是**可调用对象**,函数自然是可调用对象,类和生成器也是,我们会在接下来的小节说明。
-
-一般来说,当接收到事件时,`NoneBot2` 会进行以下处理:
-
-1. 准备依赖函数所需要的参数。
-2. 调用依赖函数并获得返回值。
-3. 将返回值作为事件处理函数中的参数值传入。
-
-## 依赖缓存
-
-在使用 `Depends` 包裹依赖函数时,有一个参数 `use_cache` ,它默认为 `True` ,这个参数会决定 `Nonebot2` 在依赖注入的处理中是否使用缓存。
-
-```python {11}
-import random
-from nonebot import on_command
-from nonebot.params import Depends
-
-test = on_command("123")
-
-async def always_run():
- return random.randint(1, 100)
-
-@test.handle()
-async def _(x: int = Depends(always_run, use_cache=False)):
- print(x)
-```
-
-:::tip
-缓存是针对单次事件处理来说的,在事件处理中 `Depends` 第一次被调用时,结果存入缓存,在之后都会直接返回缓存中的值,在事件处理结束后缓存就会被清除。
-:::
-
-当使用缓存时,依赖注入会这样处理:
-
-1. 查询缓存,如果缓存中有相应的值,则直接返回。
-2. 准备依赖函数所需要的参数。
-3. 调用依赖函数并获得返回值。
-4. 将返回值存入缓存。
-5. 将返回值作为事件处理函数中的参数值传入。
-
-## 同步支持
-
-我们在编写依赖函数时,可以简单地用同步函数,`NoneBot2` 的内部流程会进行处理:
-
-```python {2,8-9,12}
-from nonebot.log import logger
-from nonebot.params import Depends # 1.引用 Depends
-from nonebot import on_command, on_message
-from nonebot.adapters.onebot.v11 import MessageEvent
-
-test = on_command("123")
-
-def depend(event: MessageEvent): # 2.编写同步依赖函数
- return {"uid": event.get_user_id(), "nickname": event.sender.nickname}
-
-@test.handle()
-async def _(x: dict = Depends(depend)): # 3.在事件处理函数里声明依赖项
- print(x["uid"], x["nickname"])
-```
-
-## Class 作为依赖
-
-我们可以看下面的代码段:
-
-```python
-class A:
- def __init__(self):
- pass
-a = A()
-```
-
-在我们实例化类 `A` 的时候,其实我们就在**调用**它,类本身也是一个**可调用对象**,所以类可以被 `Depends` 包裹成为依赖项。
-
-因此我们对第一节的代码段做一下改造:
-
-```python {2,7-10,13}
-from nonebot import on_command
-from nonebot.params import Depends # 1.引用 Depends
-from nonebot.adapters.onebot.v11 import MessageEvent
-
-test = on_command("123")
-
-class DependClass: # 2.编写依赖类
- def __init__(self, event: MessageEvent):
- self.uid = event.get_user_id()
- self.nickname = event.sender.nickname
-
-@test.handle()
-async def _(x: DependClass = Depends(DependClass)): # 3.在事件处理函数里声明依赖项
- print(x.uid, x.nickname)
-```
-
-依然可以用三步说明如何用类作为依赖项:
-
-1. 引用 `Depends` 。
-2. 编写依赖类。类的 `__init__` 函数可以接收 `bot`, `event`, `state` 等参数,在这里我们接受了 `event`,并以 `onebot` 的 `MessageEvent` 作为类型标注。
-3. 在事件处理函数中声明依赖项。当用类作为依赖项时,它会是一个对应的实例,在这里 `x` 就是 `DependClass` 实例。
-
-### 另一种依赖项声明方式
-
-当使用类作为依赖项时,`Depends` 的参数可以为空,`NoneBot2` 会根据参数的类型标注进行推断并进行依赖注入。
-
-```python
-@test.handle()
-async def _(x: DependClass = Depends()): # 在事件处理函数里声明依赖项
- print(x.uid, x.nickname)
-```
-
-## 生成器作为依赖
-
-:::warning
-`yield` 语句只能写一次,否则会引发异常。
-如果对此有疑问并想探究原因,可以看 [contextmanager](https://docs.python.org/zh-cn/3/library/contextlib.html#contextlib.contextmanager) 和 [asynccontextmanager](https://docs.python.org/zh-cn/3/library/contextlib.html#contextlib.asynccontextmanager) 文档,实际上,`Nonebot2` 的内部就使用了这两个装饰器。
-:::
-
-:::tips
-生成器是 `Python` 高级特性,如果你对此处文档感到疑惑那说明暂时你还用不上这个功能。
-:::
-
-与 `FastAPI` 一样,`NoneBot2` 的依赖注入支持依赖项在事件处理结束后进行一些额外的工作,比如数据库 session 或者网络 IO 的关闭,互斥锁的解锁等等。
-
-要实现上述功能,我们可以用生成器函数作为依赖项,我们用 `yield` 关键字取代 `return` 关键字,并在 `yield` 之后进行额外的工作。
-
-我们可以看下述代码段, 使用 `httpx.AsyncClient` 异步网络 IO:
-
-```python {3,7-10,13}
-import httpx
-from nonebot import on_command
-from nonebot.params import Depends # 1.引用 Depends
-
-test = on_command("123")
-
-async def get_client(): # 2.编写异步生成器函数
- async with httpx.AsyncClient() as client:
- yield client
- print("调用结束")
-
-@test.handle()
-async def _(x: httpx.AsyncClient = Depends(get_client)): # 3.在事件处理函数里声明依赖项
- resp = await x.get("https://v2.nonebot.dev")
- # do something
-```
-
-我们用 `yield` 代码段作为生成器函数的“返回”,在事件处理函数里用返回出来的 `client` 做自己需要的工作。在 `NoneBot2` 结束事件处理时,会执行 `yield` 之后的代码。
-
-## 创造可调用对象作为依赖
-
-:::tips
-魔法方法 `__call__` 是 `Python` 高级特性,如果你对此处文档感到疑惑那说明暂时你还用不上这个功能。
-:::
-
-在 `Python` 的里,类的 `__call__` 方法会让类的实例变成**可调用对象**,我们可以利用这个魔法方法做一个简单的尝试:
-
-```python{3,9-14,16,19}
-from typing import Type
-from nonebot.log import logger
-from nonebot.params import Depends # 1.引用 Depends
-from nonebot import on_command
-from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent
-
-test = on_command("123")
-
-class EventChecker: # 2.编写需要的类
- def __init__(self, EventClass: Type[MessageEvent]):
- self.event_class = EventClass
-
- def __call__(self, event: MessageEvent) -> bool:
- return isinstance(event, self.event_class)
-
-checker = EventChecker(GroupMessageEvent) # 3.将类实例化
-
-@test.handle()
-async def _(x: bool = Depends(checker)): # 4.在事件处理函数里声明依赖项
- if x:
- print("这是群聊消息")
- else:
- print("这不是群聊消息")
-```
-
-这是判断 `onebot` 的消息事件是不是群聊消息事件的一个例子,我们可以用四步来说明这个例子:
-
-1. 引用 `Depends` 。
-2. 编写需要的类。类的 `__init__` 函数接收参数 `EventClass`,它将接收事件类本身。类的 `__call__` 函数将接受消息事件对象,并返回一个 `bool` 类型的判定结果。
-3. 将类实例化。我们传入群聊消息事件作为参数实例化 `checker` 。
-4. 在事件处理函数里声明依赖项。`NoneBot2` 将会调用 `checker` 的 `__call__` 方法,返回给参数 `x` 相应的判断结果。
diff --git a/website/docs/advanced/di/overload.md b/website/docs/advanced/di/overload.md
deleted file mode 100644
index 47dd72992760..000000000000
--- a/website/docs/advanced/di/overload.md
+++ /dev/null
@@ -1,76 +0,0 @@
----
-sidebar_position: 2
-description: 重载事件处理函数
-
-options:
- menu:
- weight: 61
- category: advanced
----
-
-# 事件处理函数重载
-
-当我们在编写 NoneBot2 应用时,常常会遇到这样一个问题:该怎么让同一类型的不同事件执行不同的响应逻辑?又或者如何让不同的 `bot` 针对同一类型的事件作出不同响应?
-
-针对这个问题, NoneBot2 提供一个便捷而高效的解决方案:事件处理函数重载机制。简单地说,`handler`(事件处理函数)会根据其参数的 `type hints`([PEP484 类型标注](https://www.python.org/dev/peps/pep-0484/))来对相对应的 `bot` 和 `event` 进行响应,并且会忽略不符合其参数类型标注的情况。
-
-
-
-:::tip 提示
-如果想了解更多关于 `inspect` 标准库的信息,可以查看[官方文档](https://docs.python.org/zh-cn/3.9/library/inspect.html)。
-:::
-
-下面,我们会以 OneBot 适配器中的群聊消息事件和私聊消息事件为例,对该机制的应用进行简单的介绍。
-
-## 一个例子
-
-首先,我们需要导入需要的方法、类型。
-
-```python
-from nonebot import on_command
-from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent
-```
-
-之后,我们可以注册一个 `Matcher` 来响应消息事件。
-
-```python
-matcher = on_command("test_overload")
-```
-
-最后,我们编写不同的 `handler` 并编写不同的类型标注来实现事件处理函数重载:
-
-```python
-@matcher.handle()
-async def _(bot: Bot, event: GroupMessageEvent):
- await matcher.send("群聊消息事件响应成功!")
-
-
-@matcher.handle()
-async def _(bot: Bot, event: PrivateMessageEvent):
- await matcher.send("私聊消息事件响应成功!")
-```
-
-此时,我们可以在群聊或私聊中对我们的机器人发送 `test_overload`,它会在不同的场景做出不同的应答。
-
-这样一个简单的事件处理函数重载就完成了。
-
-## 进阶
-
-事件处理函数重载机制同样支持被 `matcher.got` 等装饰器装饰的函数。例如:
-
-```python
-@matcher.got("key1", prompt="群事件提问")
-async def _(bot: Bot, event: GroupMessageEvent):
- await matcher.send("群聊消息事件响应成功!")
-
-
-@matcher.got("key2", prompt="私聊事件提问")
-async def _(bot: Bot, event: PrivateMessageEvent):
- await matcher.send("私聊消息事件响应成功!")
-```
-
-只有触发事件符合的函数才会触发装饰器。
-
-:::warning 注意
-bot 和 event 参数具有最高的检查优先级,因此,如果参数类型不符合,所有的依赖项 `Depends` 等都不会被执行。
-:::
diff --git a/website/docs/advanced/driver.md b/website/docs/advanced/driver.md
new file mode 100644
index 000000000000..f921f6b146eb
--- /dev/null
+++ b/website/docs/advanced/driver.md
@@ -0,0 +1,286 @@
+---
+sidebar_position: 0
+description: 选择合适的驱动器运行机器人
+
+options:
+ menu:
+ weight: 10
+ category: advanced
+---
+
+# 选择驱动器
+
+驱动器 (Driver) 是机器人运行的基石,它是机器人初始化的第一步,主要负责数据收发。
+
+:::important 提示
+驱动器的选择通常与机器人所使用的协议适配器相关,如果不知道该选择哪个驱动器,可以先阅读相关协议适配器文档说明。
+:::
+
+:::tip 提示
+如何**安装**驱动器请参考[安装驱动器](../tutorial/store.mdx#安装驱动器)。
+:::
+
+## 驱动器类型
+
+驱动器的类型有两种:
+
+- `ForwardDriver`:即客户端型驱动器,多用于使用 HTTP 轮询,连接 WebSocket 服务器等情形。
+- `ReverseDriver`:即服务端型驱动器,多用于使用 WebHook,接收 WebSocket 客户端连接等情形。
+
+客户端型驱动器具有以下两种功能:
+
+1. 异步发送 HTTP 请求,自定义 `HTTP Method`、`URL`、`Header`、`Body`、`Cookie`、`Proxy`、`Timeout` 等。
+2. 异步建立 WebSocket 连接上下文,自定义 `WebSocket URL`、`Header`、`Cookie`、`Proxy`、`Timeout` 等。
+
+服务端型驱动器通常为 ASGI 应用框架,具有以下功能:
+
+1. 协议适配器自定义 HTTP 上报地址以及对上报数据处理的回调函数。
+2. 协议适配器自定义 WebSocket 连接请求地址以及对 WebSocket 请求处理的回调函数。
+3. 用户可以向 ASGI 应用添加任何服务端相关功能,如:[添加自定义路由](./routing.md)。
+
+## 配置驱动器
+
+驱动器的配置方法已经在[配置](../appendices/config.mdx)章节中简单进行了介绍,这里将详细介绍驱动器配置的格式。
+
+NoneBot 中的客户端和服务端型驱动器可以相互配合使用,但服务端型驱动器**仅能选择一个**。所有驱动器模块都会包含一个 `Driver` 子类,即驱动器类,他可以作为驱动器单独运行。同时,客户端驱动器模块中还会提供一个 `Mixin` 子类,用于在与其他驱动器配合使用时加载。因此,驱动器配置格式采用特殊语法:`[:][+[:]]*`。
+
+其中,`` 代表**驱动器模块路径**;`` 代表**驱动器类名**,默认为 `Driver`;`` 代表**驱动器混入类名**,默认为 `Mixin`。即,我们需要选择一个主要驱动器,然后在其基础上配合使用其他驱动器的功能。主要驱动器可以为客户端或服务端类型,但混入类驱动器只能为客户端类型。
+
+特别的,为了简化内置驱动器模块路径,我们可以使用 `~` 符号作为内置驱动器模块路径的前缀,如 `~fastapi` 代表使用内置驱动器 `fastapi`。NoneBot 内置了多个驱动器适配,但需要安装额外依赖才能使用,具体请参考[安装驱动器](../tutorial/store.mdx#安装驱动器)。常见的驱动器配置如下:
+
+```dotenv
+DRIVER=~fastapi
+DRIVER=~aiohttp
+DRIVER=~httpx+~websockets
+DRIVER=~fastapi+~httpx+~websockets
+```
+
+## 获取驱动器
+
+在 NoneBot 框架初始化完成后,我们就可以通过 `get_driver()` 方法获取全局驱动器实例:
+
+```python
+from nonebot import get_driver
+
+driver = get_driver()
+```
+
+## 内置驱动器
+
+### None
+
+**类型:**服务端驱动器
+
+NoneBot 内置的空驱动器,不提供任何收发数据功能,可以在不需要外部网络连接时使用。
+
+```env
+DRIVER=~none
+```
+
+### FastAPI(默认)
+
+**类型:**服务端驱动器
+
+> FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
+
+[FastAPI](https://fastapi.tiangolo.com/) 是一个易上手、高性能的异步 Web 框架,具有极佳的编写体验。 FastAPI 可以通过类型注解、依赖注入等方式实现输入参数校验、自动生成 API 文档等功能,也可以挂载其他 ASGI、WSGI 应用。
+
+```env
+DRIVER=~fastapi
+```
+
+#### FastAPI 配置项
+
+##### `fastapi_openapi_url`
+
+类型:`str | None`
+默认值:`None`
+说明:`FastAPI` 提供的 `OpenAPI` JSON 定义地址,如果为 `None`,则不提供 `OpenAPI` JSON 定义。
+
+##### `fastapi_docs_url`
+
+类型:`str | None`
+默认值:`None`
+说明:`FastAPI` 提供的 `Swagger` 文档地址,如果为 `None`,则不提供 `Swagger` 文档。
+
+##### `fastapi_redoc_url`
+
+类型:`str | None`
+默认值:`None`
+说明:`FastAPI` 提供的 `ReDoc` 文档地址,如果为 `None`,则不提供 `ReDoc` 文档。
+
+##### `fastapi_include_adapter_schema`
+
+类型:`bool`
+默认值:`True`
+说明:`FastAPI` 提供的 `OpenAPI` JSON 定义中是否包含适配器路由的 `Schema`。
+
+##### `fastapi_reload`
+
+:::warning 警告
+不推荐开启该配置项,在 Windows 平台上开启该功能有可能会造成预料之外的影响!替代方案:使用 `nb-cli` 命令行工具以及参数 `--reload` 启动 NoneBot。
+
+```bash
+nb run --reload
+```
+
+开启该功能后,在 uvicorn 运行时(FastAPI 提供的 ASGI 底层,即 reload 功能的实际来源),asyncio 使用的事件循环会被 uvicorn 从默认的 `ProactorEventLoop` 强制切换到 `SelectorEventLoop`。
+
+> 相关信息参考 [uvicorn#529](https://github.com/encode/uvicorn/issues/529),[uvicorn#1070](https://github.com/encode/uvicorn/pull/1070),[uvicorn#1257](https://github.com/encode/uvicorn/pull/1257)
+
+后者(`SelectorEventLoop`)在 Windows 平台的可使用性不如前者(`ProactorEventLoop`),包括但不限于
+
+1. 不支持创建子进程
+2. 最多只支持 512 个套接字
+3. ...
+
+> 具体信息参考 [Python 文档](https://docs.python.org/zh-cn/3/library/asyncio-platforms.html#windows)
+
+所以,一些使用了 asyncio 的库因此可能无法正常工作,如:
+
+1. [playwright](https://playwright.dev/python/docs/library#incompatible-with-selectoreventloop-of-asyncio-on-windows)
+
+如果在开启该功能后,原本**正常运行**的代码报错,且打印的异常堆栈信息和 asyncio 有关(异常一般为 `NotImplementedError`),
+你可能就需要考虑相关库对事件循环的支持,以及是否启用该功能。
+:::
+
+类型:`bool`
+默认值:`False`
+说明:是否开启 `uvicorn` 的 `reload` 功能,需要在机器人入口文件提供 ASGI 应用路径。
+
+```python title=bot.py
+app = nonebot.get_asgi()
+nonebot.run(app="bot:app")
+```
+
+##### `fastapi_reload_dirs`
+
+类型:`List[str] | None`
+默认值:`None`
+说明:重载监控文件夹列表,默认为 uvicorn 默认值
+
+##### `fastapi_reload_delay`
+
+类型:`float | None`
+默认值:`None`
+说明:重载延迟,默认为 uvicorn 默认值
+
+##### `fastapi_reload_includes`
+
+类型:`List[str] | None`
+默认值:`None`
+说明:要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
+
+##### `fastapi_reload_excludes`
+
+类型:`List[str] | None`
+默认值:`None`
+说明:不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
+
+##### `fastapi_extra`
+
+类型:`Dist[str, Any]`
+默认值:`{}`
+说明:传递给 `FastAPI` 的其他参数
+
+### Quart
+
+**类型:**`ReverseDriver`
+
+> Quart is an asyncio reimplementation of the popular Flask microframework API.
+
+[Quart](https://quart.palletsprojects.com/) 是一个类 Flask 的异步版本,拥有与 Flask 非常相似的接口和使用方法。
+
+```env
+DRIVER=~quart
+```
+
+#### Quart 配置项
+
+##### `quart_reload`
+
+:::warning 警告
+不推荐开启该配置项,在 Windows 平台上开启该功能有可能会造成预料之外的影响!替代方案:使用 `nb-cli` 命令行工具以及参数 `--reload` 启动 NoneBot。
+
+```bash
+nb run --reload
+```
+
+:::
+
+类型:`bool`
+默认值:`False`
+说明:是否开启 `uvicorn` 的 `reload` 功能,需要在机器人入口文件提供 ASGI 应用路径。
+
+```python title=bot.py
+app = nonebot.get_asgi()
+nonebot.run(app="bot:app")
+```
+
+##### `quart_reload_dirs`
+
+类型:`List[str] | None`
+默认值:`None`
+说明:重载监控文件夹列表,默认为 uvicorn 默认值
+
+##### `quart_reload_delay`
+
+类型:`float | None`
+默认值:`None`
+说明:重载延迟,默认为 uvicorn 默认值
+
+##### `quart_reload_includes`
+
+类型:`List[str] | None`
+默认值:`None`
+说明:要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
+
+##### `quart_reload_excludes`
+
+类型:`List[str] | None`
+默认值:`None`
+说明:不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
+
+##### `quart_extra`
+
+类型:`Dist[str, Any]`
+默认值:`{}`
+说明:传递给 `Quart` 的其他参数
+
+### HTTPX
+
+**类型:**`ForwardDriver`
+
+:::warning 注意
+本驱动器仅支持 HTTP 请求,不支持 WebSocket 连接请求。
+:::
+
+> [HTTPX](https://www.python-httpx.org/) is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.
+
+```env
+DRIVER=~httpx
+```
+
+### websockets
+
+**类型:**`ForwardDriver`
+
+:::warning 注意
+本驱动器仅支持 WebSocket 连接请求,不支持 HTTP 请求。
+:::
+
+> [websockets](https://websockets.readthedocs.io/) is a library for building WebSocket servers and clients in Python with a focus on correctness, simplicity, robustness, and performance.
+
+```env
+DRIVER=~websockets
+```
+
+### AIOHTTP
+
+**类型:**`ForwardDriver`
+
+> [AIOHTTP](https://docs.aiohttp.org/): Asynchronous HTTP Client/Server for asyncio and Python.
+
+```env
+DRIVER=~aiohttp
+```
diff --git a/website/docs/advanced/images/Handle-Event.png b/website/docs/advanced/images/Handle-Event.png
deleted file mode 100644
index ab63c4893e381d27e6880a2c8e8777dd62412c4f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 384852
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 #GZ-3%WE
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
z
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