Skip to main content

YiriMirai 的架构

为降低耦合度,YiriMirai 在设计时分为四层:基础网络层(mirai-api-http)、基础层(adapters 和事件总线)、模型层(models)、接口层(Mirai 类)。

图示

Mirai

models

SimpleMirai

adapters

Eventbus

mirai-api-http

(画的好丑,将就着看吧)

各层级的功能

基础网络层

基础网络层指 mirai-api-http,它是 YiriMirai 工作的基础。

基础层

基础层指接口适配器和事件总线,它们直接与 mirai-api-http 通信。

模型层

模型层是在基础层之上的抽象。“模型”得名于 pydantic 的 BaseModel

模型层负责将基础层得到的数据解析为 pydantic 模型,以更方便地获取和操作其中的信息。

模型层的模块全部定义于 mirai.models 命名空间中。

以下是模型层包含的主要模块:

mirai.models.api

API 调用相关。

mirai.models.bus

模型事件总线。模型事件总线拓展了事件总线的功能,使之可以使用 mirai.models.events 中定义的事件类型来注册和接收事件。

MiraiSimpleMirai 的一个区别就在于,Mirai 使用了模型事件总线,而 SimpleMirai 使用了普通的事件总线。

mirai.models.entities

数据实体。包含 Friend Group GroupMember,以及群设置等类。

mirai.models.events

事件。定义了各种事件的数据结构。

mirai.models.message

消息链相关。

接口层

接口层指 Mirai 类,负责统筹各层功能,提供用户友好的接口。

再谈 SimpleMirai

SimpleMirai 是 Mirai 的简化版本,它只包含了基础层,并且没有模型层。为什么在 Mirai 之外,另外提供了一个并不好用的 SimpleMirai 类呢?

这来自于 YiriMirai 的架构设计。在诸层级中,模型层被设计为“可抽离”的。它仅提供更加便捷的数据处理方式,而没有增加新的功能。如果不使用模型层,完全可以仅靠基础层实现同样的功能,只是会繁琐一些。

如何界定模型层的边界?凡是涉及到 API、事件等的具体内容的,都应该放在模型层。基础层并不区分不同的 API 或事件的功能的区别。

因此,SimpleMirai 就是抽离了模型层的 Mirai。我们提供 SimpleMirai,作为展示抽离模型层的可能性。

关于 MiraiBaseModel

MiraiBaseModel 定义于 mirai.models.base 模块。它是 YiriMirai 所有 pydantic 模型的基类。

MiraiBaseModel 启用了三项配置:

  1. 允许解析时传入额外的值,并将额外值保存在模型中。
  2. 允许通过别名访问字段。
  3. 自动生成小驼峰风格的别名,以符合 mirai-api-http 的命名。

MiraiBaseModelrepr 方法做了优化,当需要调试打印时,不妨试试使用 repr

MiraiIndexedModel

MiraiIndexedModel 定义于 mirai.models.base 模块,使用了 metaclass,以支持通过子类名获取子类的反射功能。

Event ApiModelMessageComponent 能够自动将数据解析到正确的子类,正是基于 MiraiIndexedModel 的这一反射功能。

YiriMirai 选择通过反射而非查找静态字典来实现这样的功能。尽管这会增加一点冷启动的时间,但并不影响运行时的效率。 更重要的是,反射增强了 YiriMirai 的拓展性。你可以简单地通过继承 Event 类来定义自己的事件,甚至可以通过继承 ApiModel 类来定义自己的 API,这些自定义内容会完美地与内置内容融合在一起,而不需要额外的绑定。