# moonbit-mqtt-broker

**中文** | [English](README.md)

[![CI](https://github.com/ChaonanShen/moonbit-mqtt-broker/actions/workflows/ci.yml/badge.svg)](https://github.com/ChaonanShen/moonbit-mqtt-broker/actions/workflows/ci.yml)

一个使用 MoonBit 实现的轻量级、单机 MQTT 3.1.1 Broker。

`0.2.0` 是一个可实际运行的 Linux x86_64 Native 版本，适用于小型部署、
本地开发、互操作测试和 MoonBit MQTT 应用。它支持多个 TCP 或 TLS 客户端、
QoS 0/1/2、通配符订阅、保留消息、Will、Keep Alive、持久会话、可选的重启
持久化、身份认证、ACL、指标、结构化日志和 TOML 配置。

## 0.2.0 新增功能

- 完整的双向 QoS 2，包括重复包处理、重连重放、离线投递、保留消息、Will 和 Snapshot V3 恢复。
- 逻辑字节预算以及默认启用的连接、认证和发布准入限制，让过载行为保持有界。
- 有界原生认证执行器将耗时的 Argon2id 校验移出路由主循环，并通过稳定指标报告饱和状态。

持久化部署升级前，请阅读 [V3 迁移与回滚说明](docs/persistence.zh_CN.md)，并核对[默认资源与限流配置](docs/configuration.zh_CN.md)。

## 快速开始

推荐使用可复现的 Docker 环境，无需在宿主机安装 MoonBit：

```bash
docker build --platform linux/amd64 -t moonbit-mqtt-broker-dev .
scripts/moon-docker.sh run --target native src/cmd/broker -- \
  --listen 0.0.0.0:1883
```

在另一个终端中，使用任意 MQTT 3.1.1 客户端订阅和发布：

```bash
mosquitto_sub -h 127.0.0.1 -p 1883 -t 'demo/#' -q 1
mosquitto_pub -h 127.0.0.1 -p 1883 -t demo/hello -m world -q 1
```

如需完整了解安装、配置文件、持久化和带 TLS 的认证部署，请阅读
[入门指南](docs/getting-started.zh_CN.md)。

## 功能

| 范围 | 0.2.0 支持情况 |
| --- | --- |
| 协议 | 基于 TCP 或 TLS 的 MQTT 3.1.1 |
| 消息投递 | QoS 0/1/2 发布订阅；出站按阶段重放 PUBLISH/PUBREL |
| Topic | `+`、`#` 过滤器，重叠订阅确定性合并，保留消息 |
| 会话 | Clean/Persistent Session、Client ID 接管、有界离线 QoS 1/2 |
| 生命周期 | PING、Keep Alive、QoS 0/1/2 Will、SIGTERM/SIGINT 优雅退出 |
| 持久化 | 可选本地校验快照和严格启动恢复 |
| 安全 | 可选 Argon2id 密码、仅允许式 ACL、Principal 所有权会话 |
| 运维 | TOML 配置、字节预算与连接/认证/发布限流、`$SYS/broker/#` 指标、文本/JSON 日志 |

MQTT 5、WebSocket、共享订阅、Bridge、插件、集群、外部数据库、
WAL 和零丢失持久化明确不在本版本范围内。可选持久化只保证恢复到最近一次
成功提交的快照，不提供同步消息持久化。详细边界见
[兼容性矩阵](docs/compatibility.zh_CN.md)。

## 配置

Broker 已接入[逻辑字节预算与准入策略](docs/resource-budgets.md)。全局/IP 连接
准入在 TLS 前生效，已接纳的 QoS 2 握手不重复扣新发布额度。逻辑字节不是 RSS
上限；密码校验在有界原生 worker 执行器中运行，路由主循环不会同步执行哈希。

建议显式设置资源上限：

```bash
scripts/moon-docker.sh run --target native src/cmd/broker -- \
  --listen 127.0.0.1:1883 \
  --max-connections 128 \
  --max-packet-size 1048576 \
  --max-receive-buffer-size 1048576 \
  --max-sessions 1024 \
  --max-inflight-per-session 16 \
  --max-inflight-total 512 \
  --max-pending-per-session 64 \
  --max-pending-total 1024
```

通过 `--data-dir` 启用本地重启持久化：

```bash
scripts/moon-docker.sh run --target native src/cmd/broker -- \
  --listen 127.0.0.1:1883 \
  --data-dir /workspace/data
```

所有设置也可以从 TOML 加载，命令行参数优先于配置文件：

```bash
broker --config /etc/moonbit-mqtt-broker.toml --check-config
broker --config /etc/moonbit-mqtt-broker.toml --print-effective-config
broker --config /etc/moonbit-mqtt-broker.toml
```

以下命令只显示参数或版本，不会监听端口或创建数据目录：

```bash
scripts/moon-docker.sh run --target native src/cmd/broker -- --help
scripts/moon-docker.sh run --target native src/cmd/broker -- --version
```

## 示例

仓库提供三个可执行的端到端示例：

```bash
examples/basic_pubsub.sh

# 针对已经运行在 HOST PORT 的 Broker：
examples/persistent_session.sh 127.0.0.1 1883

examples/restart_persistence.sh
```

它们分别演示 QoS 0/1 实时投递、持久会话恢复，以及 Broker 重启后的保留消息
和离线 QoS 1 恢复。

## 构建和测试

受支持的开发和 CI 目标是 Ubuntu 24.04 Linux/amd64 Native。容器固定使用
MoonBit `0.10.10+f8a486b6f`、Node.js `22.23.1`、运行时依赖、MQTT.js、
Mosquitto 客户端和行为参考工具。

运行基础质量检查：

```bash
docker build --platform linux/amd64 -t moonbit-mqtt-broker-dev .
scripts/moon-docker.sh fmt --check
scripts/moon-docker.sh check --target native --deny-warn
scripts/moon-docker.sh test --target native --deny-warn
scripts/moon-docker.sh build --target native
```

开发时运行当前工作区的累计回归（正式发布使用下方严格入口）：

```bash
scripts/verify-release-docker.sh
```

累计回归会执行协议和参考 Broker 矩阵、有界稳定性负载、全部示例、TLS、
安全、会话过期、配置文件进程测试、敏感信息扫描、文档检查，以及在干净目录
中重建 mooncakes 发布包。

原生密码认证和完整 native 测试套件需要系统动态库 `libargon2.so.1`。
从 Mooncakes 安装本模块不会安装该系统依赖。项目 Docker 镜像已包含它；
在 Ubuntu/Debian 直接运行时，安装 `libargon2-1`，fixture 和集成检查还需要
`argon2` 命令：

```bash
sudo apt-get install libargon2-1 argon2
```

测试提示缺少 `libargon2.so.1` 时，应安装依赖或使用上述 Docker 命令。
密码 fixture 的生成方法和缺库回归检查见[安全文档](docs/security.zh_CN.md)。

## 严格发布验证

操作步骤、每一阶段的通过标准、失败排查、证据核对与发布记录模板见[发布前测试与验收操作手册](docs/release-verification.zh_CN.md)。

发布前先提交候选代码，再运行：

```bash
scripts/verify-distribution-docker.sh
# 同时运行现有的十分钟稳定性测试：
RELEASE_SOAK=1 scripts/verify-distribution-docker.sh
```

CI 使用同一个入口。它只取已提交的 `HEAD`，放入新建的 Docker 卷，从零运行
完整验证，再对解压后的 Mooncakes 发布包执行 Debug 和 Release 测试。最后
将包中源码编译出的 Broker 放进四种精简 Ubuntu 24.04 环境：无可选库、只有
Argon2、只有 OpenSSL、两者齐全。Broker 环境没有 MoonBit、编译器或客户端
工具；独立客户端容器通过真实连接验证 QoS 1 收发、密码认证和 TLS。
缺库场景必须明确失败且不能崩溃。运行环境使用非 root 用户、只读文件系统，
并禁止访问外部网络。

`test-results/distribution/` 保存提交号、发布包和可执行文件的 SHA-256、
工具链版本、镜像 ID、动态库清单及失败日志；CI 也会上传候选包和验证记录。
任何步骤失败都会返回非零退出码，脚本不会自动发布。代码、版本、依赖或镜像
改变后应重新验证；通过结论只覆盖记录中的 Linux/amd64 环境，不能代表未经
测试的操作系统或工具链。

系统依赖按功能声明：密码认证需要 `libargon2-1`，Ubuntu 24.04 的 TLS 需要
`libssl3t64`（OpenSSL 3），程序运行需要 `libgcc-s1`。`ldd` 不能完整显示
`dlopen` 动态加载的依赖，所以验证同时检查库清单和实际功能。
根目录的本地 `AGENTS.md`/`AGENTS.local.md` 可保持未跟踪状态，其他未跟踪
候选文件和已跟踪文件的未提交修改会阻止验证。未跟踪文件不会进入提交归档。
验证后保持提交和候选包不变，再进行发布。

## 文档

- [入门指南](docs/getting-started.zh_CN.md)
- [配置](docs/configuration.zh_CN.md)
- [安全](docs/security.zh_CN.md)
- [发布前测试与验收操作手册](docs/release-verification.zh_CN.md)
- [本地持久化](docs/persistence.zh_CN.md)
- [兼容性和限制](docs/compatibility.zh_CN.md)
- [架构](docs/architecture.zh_CN.md)

## 许可证和来源

项目使用 Apache License 2.0。运行时依赖、仅测试工具、标准、行为参考、
版本、许可证和使用方式记录在
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) 中。Broker 为原创 MoonBit
代码，没有复制 Aedes 或 Mosquitto 的实现源码。

QoS 2 采用 Method B 去重和按阶段恢复；PUBREC/PUBCOMP 不代表已 fsync，持久性仍以
最新成功提交快照为边界。详见[兼容性](docs/compatibility.zh_CN.md)及[V3 迁移](docs/persistence.zh_CN.md)。
