nonebot / adapter-onebot

NoneBot2 OneBot 适配器 / OneBot adapter for nonebot2
https://onebot.adapters.nonebot.dev
MIT License
73 stars 28 forks source link

请问如何在定时任务函数中获得onebot的bot对象? #68

Closed li1553770945 closed 1 year ago

li1553770945 commented 1 year ago

我在文档中发现了send_private_msg这个函数,我想要在定时任务中使用,因此我使用了nonebot_plugin_apscheduler插件,并且定义了async def notify_weather_warn()函数,使用scheduler.add_job添加了一个任务。

由于定时任务无法使用依赖注入,所以如果要发送消息,只能拿到Bot对象,然后使用bot对象的API。如果使用nonebot.get_bot()方法,得到的是一个nonebot.bot,而不是onebot的bot对象。我尝试了下直接强行使用nonebot.get_bot()得到的bot对象调用只有onebot才有的方法,相关代码为: print(await bot.get_login_info()),但是报错RuntimeError: Not within a websocket context

这个报错看起来像是一个网络报错,但是我可以确认其他的插件是能正常收发消息的,所以应该不是网络问题,是我的使用方法有问题,请问一下正确的使用方法是什么呢?

相关完整代码如下:

from nonebot import get_driver,require,get_bot

from nonebot.adapters.onebot.v11 import Message,MessageSegment
from nonebot.adapters.onebot.v11 import Bot as OneBot

require("nonebot_plugin_apscheduler")
require("weather")
from ..weather.weather import get_warn_from_api
from ..weather import get_default_city
from nonebot_plugin_apscheduler import scheduler

from .config import Config

global_config = get_driver().config
config = Config.parse_obj(global_config)

notify_user = config.shedular_notify_user

async def notify_weather_warn():
    bot = get_bot()
    private_users = notify_user['weather_warn_private']
    for user in private_users:
        city = await get_default_city(user_id=user)
        if city is None:
            return
        warn = get_warn_from_api(city)
        if warn is None:
            return
        msg = Message(MessageSegment.text(warn))    
        print(await bot.get_login_info())
        # await bot.send_private_msg(user_id=int(user),message=msg)

scheduler.add_job(notify_weather_warn,"interval",seconds=10)
he0119 commented 1 year ago

可以贴上详细的报错吗?想看看调用栈。

li1553770945 commented 1 year ago

您好,完整的报错如下:

06-12 23:31:38 [ERROR] logging | Job "notify_weather_warn (trigger: interval[0:00:10], next run at: 2023-06-12 23:31:47 CST)" raised an exception
Traceback (most recent call last):
  File "F:\python\girlfriend-assistant\bot.py", line 13, in <module>
    nonebot.run()
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\__init__.py", line 309, in run
    get_driver().run(*args, **kwargs)
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\drivers\quart.py", line 175, in run
    uvicorn.run(
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\uvicorn\main.py", line 578, in run
    server.run()
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\uvicorn\server.py", line 61, in run
    return asyncio.run(self.serve(sockets=sockets))
  File "D:\Python11\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
  File "D:\Python11\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
  File "D:\Python11\Lib\asyncio\base_events.py", line 640, in run_until_complete
    self.run_forever()
  File "D:\Python11\Lib\asyncio\windows_events.py", line 321, in run_forever
    super().run_forever()
  File "D:\Python11\Lib\asyncio\base_events.py", line 607, in run_forever
    self._run_once()
  File "D:\Python11\Lib\asyncio\base_events.py", line 1919, in _run_once
    handle._run()
  File "D:\Python11\Lib\asyncio\events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
> File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\apscheduler\executors\base_py3.py", line 30, in run_coroutine_job
    retval = await job.func(*job.args, **job.kwargs)
  File "F:\python\girlfriend-assistant\girlfriend-assistant\plugins\shedular_notify\__init__.py", line 35, in notify_weather_warn
    print(await bot.get_login_info())
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\internal\adapter\bot.py", line 120, in call_api
    raise exception
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\internal\adapter\bot.py", line 98, in call_api
    result = await self.adapter._call_api(self, api, **data)
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\adapters\onebot\v11\adapter.py", line 138, in _call_api
    await websocket.send(json_data)
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\internal\driver\model.py", line 205, in send
    await self.send_text(data)
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\nonebot\drivers\quart.py", line 285, in send_text
    await self.websocket.send(data)
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\werkzeug\local.py", line 311, in __get__
    obj = instance._get_current_object()
  File "F:\python\girlfriend-assistant\.venv\Lib\site-packages\werkzeug\local.py", line 508, in _get_current_object
    raise RuntimeError(unbound_message) from None
RuntimeError: Not within a websocket context
li1553770945 commented 1 year ago

image image

其他插件是能够正常收发消息的,所以网络应该没问题,我怀疑我拿到的Bot对象不是正确的,是一个没有被初始化的Bot对象,导致提示websocket报错。

yanyongyu commented 1 year ago

你可以暂时使用fastapi驱动器解决,这个报错是quart驱动器内部逻辑导致的

li1553770945 commented 1 year ago

确实,换了fastapi就好了,感谢!

yanyongyu commented 1 year ago

这个问题是quart驱动器的一个bug,会在之后修复