nonebot-bison
nonebot-bison copied to clipboard
提案:传送带(Conveyor)与包裹(Parcel)
—— 作为一个送快递的插件,有自己的传送带不是很正常吗(
起因
目前 Bison 的工作流程是:
Platform 进入 scheduler 接受调度,scheduler检测到 Platform 产出新的 Post 后,会调用 Post 的渲染方法,经 Theme 渲染出可发送消息,传入 send 模块进行发送。 https://github.com/MountainDash/nonebot-bison/blob/2a33d5143d2eb0b2fff261c02ec106ce3ed9d6c4/nonebot_bison/scheduler/scheduler.py#L96-L107 https://github.com/MountainDash/nonebot-bison/blob/2a33d5143d2eb0b2fff261c02ec106ce3ed9d6c4/nonebot_bison/scheduler/scheduler.py#L118-L127
可以发现目前这种写法将 Platform、Theme、Send 四大模块耦合在了一处。
设想
为此应该有一种思路可以将四者拆分开来,在这里,我的想法是增设一个模块,其功能是负责接收这样一份份的数据,并按规则分发给其他的处理部分进行处理。 ~作为一个送快递的插件,~ 每一个 Platfrom 可以视为一个推文包裹(Post Parcel)的接收站,在接收到包裹后,会将包裹放入传送带(Conveyor),由传送带上的处理装置对包裹进行识别,分发到渲染(Theme)模块进行渲染,生成消息包裹(Message Parcel),重新放到传送带上,分发到发送(Send)模块进行消息的发送。这样就只需要 Platform、Theme、Send 三个模块单独连接 Conveyor 模块,而不需要他们直接结合。
这样可以将 Post 类纯数据化,而不需要像现在这样在内部实现一个调用 Theme 模块功能的成员方法。
此外,Conveyor 的实现还能方便于几乎在程序的各个位置发送通知消息的能力 —— 只需要在想发送消息的位置,向传送带放入一个消息包裹就能实现。(~虽然是单方面的就是了~)
设计
-
Parcel,即包裹,分为控制部分(ParcelHeader)、负载部分(ParcelPayload)
- 控制部分: 包含conveyor_name、parcel_tag,用以控制包裹的传送行为,确定该包裹应被那个处理程序接收
- 负载部分:需要传送的实际内容,是需要加工的数据
-
Conveyor, 即传送带,负责接收(put)和获取(get)允许类型的包裹,可以存在多条不同的传送带,比如 render conveyor 负责将推文包裹送往Theme进行渲染,delivery conveyor 负责将渲染出的消息包裹送往发送模块进行发送。不过考虑到 Bison 本身的处理繁忙程度,这两个 conveyor 可以合为一个 main conveyor 来进行分发。同时增设一条 notify conveyor 来处理上文提到的从各处发来的额外通知消息包裹。
-
ConveyorManager,即传送带管理器,负责传送带的创建、获取、关停和包裹处理程序的注册等。
- 创建:创建
传送带 并存储到内部字典中 - 获取:按 name 获取某条传送带,进行操作
- 关停:关停某条或者全部传送带
- 包裹处理程序注册:提供
@parcel_processor_register(conveyor_name, parcel_tag)
装饰器,该装饰器装饰一个接收Parcel的函数,用以将匹配的包裹分配给该函数进行处理
或许ConveyorManager的功能可以直接由Conveyor的metaclass实现,上述功能即为其类方法
- 创建:创建
-
ParcelProcessLoop,即包裹处理循环,传送带上存在包裹时,进行分发处理,否则 await 等待,考虑在
nonebot.get_driver().on_startup()
时启动
pipeline?
maybe?
pipeline?