Update docs

This commit is contained in:
Richard Chien 2020-01-31 13:08:17 +08:00
parent da7c62a259
commit 389e83b4f7
5 changed files with 67 additions and 72 deletions

View File

@ -46,7 +46,7 @@ module.exports = {
'nl-processor', 'nl-processor',
'tuling', 'tuling',
'notice-and-request', 'notice-and-request',
'calling-cqhttp-api', 'cqhttp',
'scheduler', 'scheduler',
'usage', 'usage',
'whats-next', 'whats-next',

View File

@ -1,44 +1,31 @@
# 计划任务 # 计划任务
nonebot 内置了 apscheduler NoneBot 可选地内置了计划任务功能,在指南的 [添加计划任务](../guide/scheduler.md) 已经进行了简单的介绍。这里列出更多常见的用法。
通过`from nonebot import scheduler`获取,
这是一个`AsyncIOScheduler`的实例,
详细用法可见[官方文档](https://apscheduler.readthedocs.io/)。
这里列出一些常见的用法。
## 固定的计划任务 ## 固定的计划任务
利用固定的*触发器*trigger来触发某些任务 可以利用固定的*触发器*trigger来触发某些任务。
### 一次性任务 ### 一次性任务
`date`触发器 [`date` 触发器](https://apscheduler.readthedocs.io/en/stable/modules/triggers/date.html#module-apscheduler.triggers.date) 固定时间触发,仅触发一次:
[完整文档](https://apscheduler.readthedocs.io/en/stable/modules/triggers/date.html#module-apscheduler.triggers.date)
固定时间触发,仅触发一次
```python ```python
from datetime import datetime from datetime import datetime
@nonebot.scheduler.scheduled_job( @nonebot.scheduler.scheduled_job(
'cron', 'date',
run_date=datetime(2021, 1, 1, 0, 0), run_date=datetime(2021, 1, 1, 0, 0),
# timezone=None, # timezone=None,
) )
async def _(): async def _():
await bot.send_group_msg(group_id=672076603, await bot.send_group_msg(group_id=123456,
message="2021新年快乐") message="2021新年快乐")
``` ```
### 定期任务 ### 定期任务
`cron`触发器 [`cron` 触发器](https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html#module-apscheduler.triggers.cron) 从 `start_date` 开始到 `end_date` 结束,根据类似 [Cron](https://wiki.archlinux.org/index.php/Cron_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)) 的规则触发任务:
[完整文档](https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html#module-apscheduler.triggers.cron)
从`start_date`开始,每一个固定时间触发,到`end_date`结束
比如每小时、每个工作日早上8点
```python ```python
@nonebot.scheduler.scheduled_job( @nonebot.scheduler.scheduled_job(
@ -54,18 +41,15 @@ async def _():
# start_date=None, # start_date=None,
# end_date=None, # end_date=None,
# timezone=None, # timezone=None,
) )
async def _(): async def _():
await bot.send_group_msg(group_id=672076603, await bot.send_group_msg(group_id=123456,
message="起床啦!") message="起床啦!")
``` ```
### 间隔任务 ### 间隔任务
`interval`触发器 [`interval` 触发器](https://apscheduler.readthedocs.io/en/stable/modules/triggers/interval.html#module-apscheduler.triggers.interval) 从 `start_date` 开始,每间隔一段时间触发,到 `end_date` 结束:
[完整文档](https://apscheduler.readthedocs.io/en/stable/modules/triggers/interval.html#module-apscheduler.triggers.interval)
从`start_date`开始,每间隔一段时间触发,到`end_date`结束
```python ```python
@nonebot.scheduler.scheduled_job( @nonebot.scheduler.scheduled_job(
@ -77,20 +61,17 @@ async def _():
# seconds=0, # seconds=0,
# start_date=time.now(), # start_date=time.now(),
# end_date=None, # end_date=None,
) )
async def _(): async def _():
has_new_item = check_new_item() has_new_item = check_new_item()
if has_new_item: if has_new_item:
await bot.send_group_msg(group_id=672076603, await bot.send_group_msg(group_id=123456,
message="RC更新啦!") message="XX有更新啦!")
``` ```
## 动态的计划任务 ## 动态的计划任务
有时,我们需要机器人在运行的过程中,添加一些计划任务, 有时,我们需要机器人在运行的过程中,添加或删除计划任务,那么我们就需要 `scheduler.add_job` 来帮忙。这里,我们以*一次性任务*为例,其他类型的任务可以用相同的方法:
那么我们就需要 `scheduler.add_job` 来帮忙
这里,我们以*一次性任务*为例,其他类型的任务可以用相同的方法
```python ```python
import datetime import datetime
@ -112,27 +93,22 @@ async def _(session: CommandSession):
# 添加任务 # 添加任务
scheduler.add_job( scheduler.add_job(
func=session.send, # 要添加任务的函数,不要带参数 func=session.send, # 要添加任务的函数,不要带参数
trigger=trigger, # 触发器 trigger=trigger, # 触发器
args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号 args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号
# kwargs=None, # kwargs=None,
misfire_grace_time=60, # 允许的误差时间,建议不要省略 misfire_grace_time=60, # 允许的误差时间,建议不要省略
# jobstore='default', # 任务储存库,在下一小节中说明 # jobstore='default', # 任务储存库,在下一小节中说明
) )
``` ```
## 储存任务 <!-- ## 持久化存储任务
有时,我们动态添加的一些计划任务需要长时间储存, 有时,我们动态添加的一些计划任务需要持久化储存,否则任务会在重启后丢失,这时我们就需要 `jobstore` 来帮忙。
而普通储存的任务会在重启后丢失,
那么我们就需要 `jobstore` 来帮忙
apscheduler 可以将任务存储在内存中或数据库中, APScheduler 可以将任务存储在内存中或数据库中,默认 jobstore 将所有任务储存在内存中,关闭后即丢失。这里,我们以 SQLite 为例,将任务添加到数据库中。
默认 jobstore 将所有任务储存在内存中,关闭后即丢失。
这里,我们以 SQLite 为例,将任务添加到数据库中, 我们先创建一个数据库:
我们先创建一个数据库
```python ```python
import asyncio import asyncio
@ -151,10 +127,9 @@ scheduler.add_jobstore(store, alias='my_job_store')
之后,我们在添加新任务时,可以指定任务的储存库 之后,我们在添加新任务时,可以指定任务的储存库
```python ```python
bot = get_bot() async def alarm(*args, **kwargs):
bot = get_bot()
def alarm(*args, **kwargs): await bot.send(*args, **kwargs)
asyncio.run(bot.send(*args, **kwargs))
@on_command('提醒收菜') @on_command('提醒收菜')
async def _(session: CommandSession): async def _(session: CommandSession):
@ -173,7 +148,7 @@ async def _(session: CommandSession):
'message': '起床收菜啦!', 'message': '起床收菜啦!',
}, },
misfire_grace_time=60, misfire_grace_time=60,
jobstore='my_job_store', # 任务储存库,指定为刚才创建的储存库 jobstore='my_job_store', # 任务储存库,指定为刚才创建的储存库
) )
``` ```
@ -183,4 +158,4 @@ async def _(session: CommandSession):
所以必须将任务转化为同步任务再储存。 所以必须将任务转化为同步任务再储存。
并且 `apscheduler` 中的 `AsyncIOScheduler` 在执行同步任务时会新建一个执行器executor 并且 `apscheduler` 中的 `AsyncIOScheduler` 在执行同步任务时会新建一个执行器executor
导致这个任务里无法使用 `asyncio.get_running_loop()` 来获取事件循环, 导致这个任务里无法使用 `asyncio.get_running_loop()` 来获取事件循环,
只能使用 `asyncio.run(...)` 来运行异步函数。 只能使用 `asyncio.run(...)` 来运行异步函数。 -->

View File

@ -2,22 +2,38 @@
如果需要对 web 框架进行更详细的控制,可以通过 `bot.server_app` 访问到内部的 Quart 对象,之后可以像使用 Quart 的 app 对象一样添加路由、设置生命周期处理函数等。 如果需要对 web 框架进行更详细的控制,可以通过 `bot.server_app` 访问到内部的 Quart 对象,之后可以像使用 Quart 的 app 对象一样添加路由、设置生命周期处理函数等。
::: tip 提示
Quart 是一个与 Flask 具有相同 API 的异步 web 框架,其用法可以参考 [官方文档](https://pgjones.gitlab.io/quart/)。
:::
## 自定义路由 ## 自定义路由
### 简单的主页 这里以一个简单的管理页面为例:
```python ```python
from nonebot import get_bot import nonebot
bot = get_bot()
@bot.server_app.route('/') bot = nonebot.get_bot() # 在此之前必须已经 init
async def hello_world():
await bot.send_private_msg(1002647525, '你的主页被访问了') @bot.server_app.route('/admin')
return '欢迎来到我的主页' async def admin():
await bot.send_private_msg(12345678, '你的主页被访问了')
return '欢迎来到管理页面'
``` ```
启动 nonebot 后访问 <http://127.0.0.1:8080/>,你会看见主页的欢迎词,并收到机器人的提醒。 启动 NoneBot 后访问 <http://127.0.0.1:8080/admin>,你会看见管理页面的欢迎词,并收到机器人的提醒。
### 更多应用 ## 处理生命周期事件
Quart 是一个与 Flask 具有相同 API 的异步 web 框架,其用法可以参考[Flask官方文档](https://flask.palletsprojects.com/)或它的[简中翻译版本](http://docs.jinkan.org/docs/flask/),关于 Quart 可以参考[Quart官方文档](https://pgjones.gitlab.io/quart/) 有时可能需要在 NoneBot 启动时初始化数据库连接池,例如:
```python
import nonebot
bot = nonebot.get_bot() # 在此之前必须已经 init
@bot.server_app.before_serving
async def init_db():
# 这会在 NoneBot 启动后立即运行
pass
```

View File

@ -201,7 +201,3 @@ async def _(session: CommandSession):
``` ```
观察看看有什么不同,以及它的回复是否符合我们对代码的理解。如果成功的话,此时你已经完成了一个**可交互的**天气查询命令的雏形,只需要再接入天气 API 就可以真正投入使用了! 观察看看有什么不同,以及它的回复是否符合我们对代码的理解。如果成功的话,此时你已经完成了一个**可交互的**天气查询命令的雏形,只需要再接入天气 API 就可以真正投入使用了!
## 获取对话细节
如果我们需要获取对话中更多的细节,如发送者的群名片、群专属头衔、性别等参数,可以通过 `session.ctx` 获取原始的数据。数据格式详见[CQHTTP文档](https://cqhttp.cc/docs/#/Post?id=%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8)。

View File

@ -1,10 +1,18 @@
# 主动调用 CQHTTP 接口 # CQHTTP 事件和 API
到目前为止,我们都在调用 `CommandSession` 类的 `send()` 方法,而这个方法只能回复给消息的发送方,不能手动指定发送者,因此当我们需要实现将收到的消息经过处理后转发给另一个接收方这样的功能时,这个方法就用不了了 到目前为止,我们都在使用 NoneBot 显式提供的接口,但实际上 CQHTTP 插件还提供了更多的事件数据和 API可能利用这些它们实现更加自由的逻辑
幸运的是,`NoneBot` 类是继承自 [python-aiocqhttp] 的 `CQHttp` 类的,而这个类实现了一个 `__getattr__()` 方法,由此提供了直接通过 bot 对象调用 CQHTTP 的 API 的能力。 ## 事件数据
[python-aiocqhttp]: https://github.com/richardchien/python-aiocqhttp 在 [发生了什么?](./whats-happened.md) 中我们提到,收到 酷Q 事件后CQHTTP 通过反向 WebSocket 给 NoneBot 发送事件数据。这些数据被 NoneBot 放在了 `session.ctx` 中,是一个字典,你可以通过断点调试或打印等方式查看它的内容,其中的字段名和含义见 CQHTTP 的 [事件列表](https://cqhttp.cc/docs/#/Post?id=事件列表) 中的「上报数据」。
## API 调用
前面我们已经多次调用 `CommandSession` 类的 `send()` 方法,而这个方法只能回复给消息的发送方,不能手动指定发送者,因此当我们需要实现将收到的消息经过处理后转发给另一个接收方这样的功能时,这个方法就用不了了。
幸运的是,`NoneBot` 类是继承自 [python-aiocqhttp] 的 `CQHttp` 类的,而这个类实现了 `__getattr__()` 魔术方法,由此提供了直接通过 bot 对象调用 CQHTTP 的 API 的能力。
[python-aiocqhttp]: https://github.com/cqmoe/python-aiocqhttp
::: tip 提示 ::: tip 提示
如果你在使用 HTTP 通信,要调用 CQHTTP API 要在 `config.py` 中添加: 如果你在使用 HTTP 通信,要调用 CQHTTP API 要在 `config.py` 中添加: