把 NoneBot 接入微信公众号 —— 写一个 Adapter
本篇记录写一个 NoneBot2 Adapter for 微信公众平台 学到的语法
阅读前,默认您已经了解 NoneBot 的构成 并熟悉事件处理流程。
本文均以 微信公众平台使用的 WebHook 方式推送事件为例。
如何写一个 adapter ?
参考 编写适配器
1 | nonebot-adapter-wxmp |
adapter 的结果在官方文档中已有详细介绍,不在此赘述。
adapter 中的处理流程
- 首先由
adapter.py
中注册的 POST 请求处理函数handle_http
处理原始请求。handle_http
进行验签(解密)。 parse_body
负责将 body 转为 dict。payload_to_event
将 dict 使用 pydantic 的 model_validate 转为Event
的派生类。dispatch_event
负责分发事件,调用bot.handle_event(event=event)
处理事件。如果是公众号,需要等待用户send
后再返回 Response。
学到了什么?
抽象类
nonebot 实现了一个 Bot
抽象类,adapter 开发者应该继承基类实现平台 API。
1 | class Bot(abc.ABC): |
1 | from nonebot.adapters import Bot as BaseBot |
如果直接实例化抽象类,将会:
1 | Can't instantiate abstract class Bot with abstract method send |
原因:Python 在尝试实例化抽象类时,会检查类中是否有未实现的抽象方法。
事件回调
需求场景:当使用者调用 bot.send
方法时,需要将 Message
“发送” 给 handle_http
方法响应微信请求,而它们之间通过 NoneBot 的 handle_event 传递事件,没有直接调用关系。
方案一:定义一个全局字典,send
的参数写入字典,handle_http
轮询字典获得数据。(耗性能,高延迟)
方案二:使用 asyncio
1 | class OfficialReplyResponse: |
说明:future = asyncio.get_event_loop().create_future()
将创建一个 Future 对象,相当于一个“占位符”,它等待某个异步操作完成并返回结果。
当使用 future.set_result(resp)
时,asyncio.wait_for(future, timeout)
才会返回结果,否则一直 await。
getattr 魔法函数
异步函数
1 | class _ApiCall(Protocol): |
此时 await o.any_func(a=1)
与 await o.call_api(api="any_func", a=1)
等价
同步函数
1 | class _ApiCall: |
此时 o.any_func(a=1)
与 o.call_api(api="any_func", a=1)
等价
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 符号看象限!
评论