# 整体架构

了解 melobot 的核心架构与简单工作细节是介绍更多内容的基本前提。下图展示了 melobot 的核心架构层：

```{image} /_static/main-framework.png
:alt: main-framework
:width: 250px
:align: center
```

melobot 的核心理念是获取输入，经过处理，产生输出。因此理论上任何可以被抽象为 IO 的操作，都可以写出对应的扩展。

melobot 将各种格式、规范或风格的输入输出行为都抽象为 melobot 规范的“协议”。对于协议的输入部分，抽象为“事件”来处理，而对于协议的输出部分，抽象为“行为”来处理。而对于输出可能产生的返回值或状态信息，抽象为“回应”来处理。随后基于此构建了精细的处理流程。

接下来简单说明各层的具体功能，此部分较为抽象，阅后有所印象即可。

## 输入输出层

输入层主要包含一类部件：源。源对象分为两种：输入源，输出源。当一个源对象同时实现了输入源和输出源的功能时，称为输入输出源。

**每个源对象类只能对应一种协议。而每种协议至少有一个源对象类。**

输入源产生或从某处接收数据，并将这些数据转为“输入包”（输入实体），传递给上层的适配器处理。输出源接收来自上层适配器的“输出包”（输出实体），将其转换为数据输出到某处，或产生一些具体操作。

例如：

- `melobot.protocols.console` 协议：输入源读取控制台 stdin 作为输入数据，输出源将输出数据写入控制台 stdout 或 stderr
- `melobot.protocols.onebot` 协议：输入源与 OneBot 实现端通信获取输入数据，输出源与 OneBot 实现端通信发送操作

输出源对象在接收输出包完成“输出”操作后，会返回一个“回应包”给适配器，适配器就知道是否应该产生“回应”，或产生怎样的“回应”。

## 适配器层

适配器层主要包含一类部件：适配器。

**每个适配器对象类只能对应一种协议；而每种协议必须有且只有一个适配器对象类。**

适配器主要负责三件事：

1. 将来自输入源的输入包转化为符合 melobot 规范的“事件”
2. 提供产生“行为”的方法或工具。在产生“行为”后，转化为“输出包”传递给输出源
3. 决定“行为”是否产生“回应”，如果产生还需传递给“行为”给发起行为的调用处

产生的事件、行为、回应必须且只能对应一种协议。

```python
# 所有适配器都会产生继承 RootEvent 基类型的事件
from melobot.handle import Event as RootEvent
# 例如 OneBotEvent 就是继承于此，但内部可能有更细的继承关系
from melobot.protocols.onebot.v11 import Event as OneBotEvent
# 例如再继承并细化得到 MessageEvent 事件
from melobot.protocols.onebot.v11 import MessageEvent
```

```python
from melobot.protocols.onebot.v11 import Adapter, on_message

@on_message()
async def _(adapter: Adapter) -> None:
    # 让适配器产生行为操作
    handle_group = await adapter.send(...)
    # 因为 OneBot 适配器总是产生回应，因此你总是可以拿到回应对象
    echo = await handle_group[0]
    assert echo is not None
```

## 处理流层

处理流层实现了处理流的创建、运行和销毁。

所有事件在被他们的适配器创建出来后，会被统一送到 melobot 的分发部件。它们将按照处理流规则，在这里被分发给不同的处理流。

处理流对象可以容纳很多处理结点，从而形成一个图结构。事件处理的过程，其实就是遍历各个处理结点的过程。而在处理流运行时，也可以进入其他流形成嵌套处理，因此是十分灵活的。

```{admonition} 提示
:class: tip
为了保证遍历的顺利进行，处理流内部的图是有向无环图结构（DAG）。
```

melobot 允许你自行搭建处理流。而处理流对象本身是无状态的，这意味着可以在多处复用。

为了避免频繁的手动创建处理流，melobot 提供了注册函数为处理流的方法，也就是早期提到的“事件绑定方法”。

```python
# 以下所有装饰器方法，本质上都是从函数生成单结点处理流对象
from melobot.handle import on_event, on_start_match
from melobot.protocols.onebot.v11 import on_message

async def process_func(...) -> None: ...
def process_func2(...) -> None: ...

flow1 = on_event(process_func)
flow2 = on_message(process_func2)
```

## 会话控制层

会话控制层实现了会话的生成、维持和销毁。

会话是事件处理的高级形态。会话机制提供了对事件序列（不同时间点发生的事件形成的序列）的处理，并保证安全、高效的并发，还让事件处理过程变得拥有“交互性”。

只能在处理流运行过程中进入会话。但处理流不会主动进入会话，进入会话必须手动调用相关方法，或在“事件绑定方法”中指定相关参数。

会话过程中的“暂停和恢复”完全依赖于会话规则，这赋予了会话管理无与伦比的自由性。

## 插件管理层

插件管理层实现了插件声明的功能组件，并在 bot 运行时依靠这些声明创建插件。

插件管理层提供了用于组织 melobot 功能扩展的部件。melobot 插件机制的特点是：

- 依靠异步依赖的自动满足，因此可以无序加载。
- 可以在指定的 bot 生命周期后，在任何位置动态加载。
- 依靠共享对象，实现无导入依赖的跨插件数据传递
- 依靠导出函数，实现无导入依赖的跨插件通信

## bot 管理层

bot 管理层实现了 melobot 外层的重要接口，并统一地封装到 bot 对象中。

包含的功能有：

- 添加指定协议的输入、输出源
- 添加指定协议的适配器
- 加载插件
- 提供一些动态功能的接口
- 查询或获取一些内部对象

此外，bot 对象也用于启动和管理整个 bot 程序。

## 总结

本篇主要说明了 melobot 各层的功能及一些工作细节。

下一篇将重点说明：bot 的生命周期。
