797 lines
43 KiB
Markdown
797 lines
43 KiB
Markdown
# Chongming-Zenoh
|
||
|
||
基于 **FastAPI + Zenoh + MQTT + Vue 3** 的**配置驱动微服务网关平台**。
|
||
|
||
通过 TOML 配置文件定义 RPC 端点,自动生成 Pydantic 模型与 FastAPI 路由,同时暴露 **HTTP** 和 **MQTT** 双通道。底层基于 Zenoh 分布式消息协议实现 RPC 通信,Worker 插件可独立开发、按副本数水平扩展。
|
||
|
||
---
|
||
|
||
## 核心特性
|
||
|
||
| 特性 | 说明 |
|
||
| --------------------- | -------------------------------------------------------------------- |
|
||
| **FastAPI + Uvicorn** | 高性能异步 Web 框架,自动生成 OpenAPI 文档 |
|
||
| **Zenoh 服务发现** | 基于 liveliness 的 Worker 注册与 RPC 调用,负载均衡 + 超时重试 |
|
||
| **MQTT 集成** | amqtt Broker(内嵌或外部),MQTT ↔ Worker 双向桥接 |
|
||
| **动态路由生成** | 扫描 `config/workers/*/*.toml` 自动注册 HTTP 路由 |
|
||
| **Worker 框架** | `@rpc_method` 装饰器 + `Plugin` 基类统一生命周期 + Pydantic 模型绑定 |
|
||
| **启动契约校验** | TOML 路由 ↔ `@rpc_method` ↔ 生成模型三方一致性校验,fail fast |
|
||
| **混合部署** | inline(网关进程内)与 external(独立进程)两种插件模式按插件粒度共存 |
|
||
| **动态路由注册** | external 插件经 Zenoh 注册路由,网关动态挂载/摘除 HTTP 端点 |
|
||
| **进程插件隔离** | 进程插件与网关零导入关系,仅经 Zenoh 通讯,可独立打包到不同容器 |
|
||
| **自动化模型生成** | `gen_models` 根据 TOML 配置生成请求/响应模型 |
|
||
| **插件脚手架** | `gen_plugin` 一键生成风格统一的 Worker 插件骨架 |
|
||
| **JWT 鉴权** | Rust 实现,路由级 `auth_required` 控制 |
|
||
| **Argon2id 密码哈希** | Rust 实现的高性能密码安全方案 |
|
||
| **异步 SQLite** | aiosqlite + SQLModel,多进程并发安全 |
|
||
| **本地文件存储** | 内置文件上传/下载端点 |
|
||
| **流媒体代理** | ffmpeg + MediaMTX RTSP 流转发 |
|
||
| **构建打包** | PyInstaller / Nuitka 一键打包为独立可执行文件 |
|
||
| **Vue 3 前端** | Element Plus UI、Pinia 状态管理、类型安全的 API 客户端 |
|
||
| **Worker 运维管理** | 前端经 Zenoh 向单个副本下发 restart/stop/改配置指令(超管),前端可视化列表 + 分页管理 |
|
||
|
||
---
|
||
|
||
## 项目结构
|
||
|
||
```text
|
||
chongming-zenoh/
|
||
├── config.toml # 应用主配置
|
||
├── pyproject.toml # 项目依赖与脚本入口
|
||
├── config/ # 配置文件目录
|
||
│ ├── zenoh_config.json5 # Zenoh 会话配置
|
||
│ └── workers/ # Worker 路由定义(TOML)
|
||
│ ├── config.toml # 旧式全局插件注册(仅作兜底兼容)
|
||
│ ├── auth/ # 鉴权插件(config.toml = 插件注册 + 运行时配置)
|
||
│ ├── doubao/ # 豆包视觉理解插件
|
||
│ ├── aibox_sophon_adapter/ # AI Box 设备心跳监控插件
|
||
│ └── example/ # 示例插件(四则运算 / MQTT 端点)
|
||
├── src/
|
||
│ ├── chongming/ # 核心应用
|
||
│ │ ├── app/
|
||
│ │ │ ├── core/ # WorkerManager, RouteGenerator, MQTTBridge, contracts(契约校验), auth
|
||
│ │ │ └── routes/ # 内置路由(文件上传等)
|
||
│ ├── chongming-web/ # Vue 3 前端
|
||
│ │ └── src/
|
||
│ │ ├── api/generated/ # 自动生成 API 客户端
|
||
│ │ ├── views/ # 页面组件
|
||
│ │ └── router/ # Vue Router 配置
|
||
│ └── plugins/ # Worker 插件源码(inline 模式)
|
||
│ ├── auth/ # JWT 鉴权
|
||
│ ├── doubao/ # 豆包 AI(支持 AICC 安全通道)
|
||
│ ├── aibox_sophon_adapter/ # 设备心跳 + 告警
|
||
│ └── example/ # 演示示例
|
||
├── workers/ # 进程插件(external 模式,本地开发目录,不入库;
|
||
│ └── demo/ # 生产在独立容器部署,示例见本地目录)
|
||
├── utils/ # 独立工具包
|
||
│ ├── bytedance/ # 字节跳动安全通信 SDK
|
||
│ ├── cli/ # 命令脚本集合(build / gen_models / gen_plugin,chongming-cli)
|
||
│ ├── config/ # TOML 配置加载
|
||
│ ├── database/ # 异步 SQLite 封装
|
||
│ ├── jwt/ # Rust JWT 编解码
|
||
│ ├── password/ # Rust Argon2id 哈希
|
||
│ ├── request/ # Zenoh RPC 客户端
|
||
│ ├── stream_manager/ # ffmpeg RTSP 流管理
|
||
│ └── worker/ # Worker 框架核心
|
||
├── data/
|
||
│ ├── storage/chongming/ # SQLite 数据库文件
|
||
│ └── uploads/ # 文件上传目录
|
||
├── logs/ # 日志目录
|
||
├── resources/ # 模块银行打包资源
|
||
├── test_mqtt_e2e.py # MQTT 端到端测试
|
||
├── publisher.py / subscriber.py # MQTT 收发示例
|
||
└── README.md
|
||
```
|
||
|
||
---
|
||
|
||
## 多仓库结构与开发工作流
|
||
|
||
本仓库(**chongming-core**)只跟踪网关核心代码,其余资产分布在独立仓库中:
|
||
|
||
| 目录 / 包 | 独立仓库 | 说明 |
|
||
| ---------------- | ----------------------------------------------- | -------------------------- |
|
||
| `src/chongming/` | 本仓库(chongming-core) | 网关核心(FastAPI + Zenoh)|
|
||
| `utils/<name>/` | `chongming-utils-*`(9 个,见「工具包列表」) | 工具包,由 `uv sync` 按 git 源安装 |
|
||
| `utils/cli/` | `chongming-utils-cli`(规划中,暂以 path 源安装)| 命令脚本集合(build / build_plugin / gen_models / gen_plugin) |
|
||
| `src/plugins/` | `chongming-plugins` | Worker 插件源码 |
|
||
| `config/` | `chongming-config` | 应用与 Worker 路由配置 |
|
||
| `src/chongming-web/` | `chongming-web` | Vue 3 前端 |
|
||
|
||
### 首次克隆(开发环境引导)
|
||
|
||
```bash
|
||
git clone http://124.71.68.6:3000/chongming/chongming-core.git chongming-zenoh
|
||
cd chongming-zenoh
|
||
git clone http://124.71.68.6:3000/chongming/chongming-plugins.git src/plugins
|
||
git clone http://124.71.68.6:3000/chongming/chongming-config.git config
|
||
git clone http://124.71.68.6:3000/chongming/chongming-web.git src/chongming-web
|
||
uv sync # utils/* 由 uv 按 pyproject 的 git 源自动安装,无需手工 clone
|
||
```
|
||
|
||
### 开发与发布检查清单
|
||
|
||
**修改 `utils/<name>`(工具包)**:
|
||
|
||
1. 在 `utils/<name>` 内提交并 push 到对应远程
|
||
2. 回主仓库执行 `uv lock --upgrade-package <包名>` 刷新版本 pin
|
||
3. `uv sync` 后运行相关测试
|
||
4. 主仓库提交 `uv.lock`
|
||
|
||
**修改 `src/plugins/` / `config/` / `src/chongming-web/`**:
|
||
|
||
1. 在对应子仓库内提交并 push
|
||
2. 回主仓库启动验证(`uv run serve` + 相关测试)
|
||
|
||
**发布前总检查**:
|
||
|
||
- [ ] 所有子仓库 `git status` 干净且已 push
|
||
- [ ] `uv.lock` 与各 git 源最新提交一致
|
||
- [ ] 配置中无硬编码凭据——密钥一律走环境变量:
|
||
`VOLC_ACCESSKEY`(豆包 Ark Key)、`AIBOX_MQTT_URI`(AI Box 外部 Broker URI)
|
||
- [ ] `uv run python test_mqtt_e2e.py` 等测试通过
|
||
|
||
---
|
||
|
||
## 快速开始
|
||
|
||
### 环境要求
|
||
|
||
- Python >= 3.12
|
||
- Rust 工具链(用于编译 `jwt` / `password` 扩展)
|
||
- Node.js >= 22(前端开发)
|
||
- [uv](https://docs.astral.sh/uv/) 包管理器
|
||
- ffmpeg(可选,stream_manager 需要)
|
||
|
||
### 安装与启动
|
||
|
||
> 首次克隆:先按「多仓库结构与开发工作流」拉取 `src/plugins` / `config` / `src/chongming-web` 子仓库,再执行以下步骤。
|
||
|
||
```bash
|
||
# 同步依赖(自动编译 Rust 扩展 + 安装 Python 包)
|
||
uv sync
|
||
|
||
# 启动服务(开发模式,热重载)
|
||
uv run serve
|
||
```
|
||
|
||
服务启动后:
|
||
|
||
| 通道 | 地址 | 说明 |
|
||
| ------- | ---------------------------- | ---------------- |
|
||
| HTTP | `http://localhost:8000` | REST API |
|
||
| Swagger | `http://localhost:8000/docs` | OpenAPI 交互文档 |
|
||
| MQTT | `mqtt://localhost:1883` | 内嵌 Broker |
|
||
|
||
### 前端开发
|
||
|
||
```bash
|
||
cd src/chongming-web
|
||
npm install
|
||
npm run dev # http://localhost:5173
|
||
```
|
||
|
||
---
|
||
|
||
## 架构与数据流
|
||
|
||
```mermaid
|
||
graph TB
|
||
HTTP[HTTP 客户端] -->|REST API| API[FastAPI 动态路由]
|
||
MQTT[MQTT 客户端] -->|chongming/+/+| BRIDGE[MQTT Bridge<br/>纯客户端模式]
|
||
|
||
REG[RouteRegistry<br/>订阅 chongming/routes/**] -->|动态挂载/摘除 HTTP 路由| API
|
||
API --> WM[WorkerManager<br/>随机负载均衡 + 超时重试]
|
||
BRIDGE --> WM
|
||
|
||
subgraph GW[网关进程 chongming]
|
||
API
|
||
REG
|
||
BRIDGE
|
||
WM
|
||
end
|
||
|
||
WM -->|Zenoh Query| IW[inline Worker 副本<br/>网关进程内加载]
|
||
WM -->|Zenoh Query| EW[external Worker 进程<br/>独立容器,零网关依赖]
|
||
EW -.->|发布路由描述符<br/>chongming/routes/**| REG
|
||
|
||
IW --> DB[(SQLite)]
|
||
EW --> DB
|
||
EW -->|AI 调用| AI[豆包 API]
|
||
```
|
||
|
||
**启动流程**:
|
||
|
||
```
|
||
uv run serve → FastAPI lifespan:
|
||
1. setup_storage() — 本地文件系统存储
|
||
2. setup_zenoh() — Zenoh peer 会话
|
||
3. setup_mqtt_broker() — 内嵌 amqtt Broker(子进程 + 文件锁单例;
|
||
`use_embedded_broker=false` 时跳过,改用外部 Broker)
|
||
4. setup_worker_manager() — WorkerManager + 定期 liveliness 刷新 + 网关登记(register_gateway,参与全局分摊)+ 该插件副本数经 resolved_count 按 launch_worker_count 从 cache/toml 解析
|
||
5. load_workers() — 按插件 [workers].load_mode 分派:
|
||
inline → 进程内 import 插件 → 启动 Worker 协程
|
||
external → 跳过(独立进程运行,盘扫条目仅观测)
|
||
5.1 setup_route_registry() — 常驻订阅 chongming/routes/**,external 插件路由动态挂载/摘除
|
||
6. validate_contracts() — inline 插件三方契约校验,失败终止启动
|
||
7. register_routes() — inline 插件盘扫生成 HTTP 路由
|
||
8. setup_mqtt() — MQTT Bridge(inline 主题静态收集 + external 主题动态推送;基于共享缓存的分布式锁保证全局单实例)
|
||
```
|
||
|
||
---
|
||
|
||
## Worker 管理系统
|
||
|
||
通过 Zenoh 向 `worker/<type>/<worker_id>/__admin__` 管理端点下发指令,**精细化控制单个 Worker 副本**(inline 与 external 进程插件共用同一管理协议)。提供 REST 管理端点 + Vue 前端页面,操作需超级管理员鉴权。
|
||
|
||
### 管理协议
|
||
|
||
每个用 Worker 框架(`chongming_worker.runtime.create_workers`)创建的副本都会注册一个管理 Queryable:
|
||
|
||
```text
|
||
worker/<type>/<worker_id>/__admin__
|
||
```
|
||
|
||
| 指令 | 说明 |
|
||
| ----------- | ---------------------------------------------------------------------- |
|
||
| `status` | 查询副本状态 |
|
||
| `restart` | 重启该副本,副本槽位(index)由管理循环驱动,重新生成新 `worker_id`(`worker-<index>-<epoch>-<pid>`)并经 liveliness 更新 |
|
||
| `stop` | 停止该副本 |
|
||
| `drain` | **优雅排空**:摘除 liveliness/业务 Queryable 隔绝新请求,等待正在处理的在途请求完成后再退出,管理循环不重建(数量-1) |
|
||
| `rescale` | 按 `data.scale` 把**当前进程内**该类型副本数调整为指定值(`data:{"scale":N}`),并把 `[workers].count` 写回本进程侧配置 |
|
||
| `config_set`| 更新 `[workers.config]` 运行时配置(路由配置除外);成功则写回配置并重启该类型全部对应副本,任一失败返回失败信息 |
|
||
|
||
### REST 管理端点(仅超管)
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
| ------ | --------------------------------------- | -------------------------------------- |
|
||
| `GET` | `/api/v1/admin/workers` | 盘点全部副本(inline 本地注册 + external liveliness 发现) |
|
||
| `POST` | `/api/v1/admin/workers/restart` | 重启单个副本(`worker_type` / `worker_id` 查询参数) |
|
||
| `POST` | `/api/v1/admin/workers/<type>/stop` | 停止 single 副本 / 某插件全部副本 |
|
||
| `GET` | `/api/v1/admin/workers/<type>/config` | 读取该插件的现有 `[workers.config]`(展示当前值) |
|
||
| `POST` | `/api/v1/admin/workers/<type>/config` | 更新配置(body `{updates:{k:v}}`),下发并重启 |
|
||
| `POST` | `/api/v1/admin/workers/<type>/scale` | 调整该类型副本数(body `{count:N}`),扩缩容 + 持久化 |
|
||
|
||
> 旧版运行时未声明 `__admin__` 管理能力时,管理指令会超时(HTTP 502,见日志提示)。
|
||
|
||
### 配置热更新(路由配置除外)
|
||
|
||
- worker 回写插件 `config.toml` 的 `[workers]` 段(保留其他段),**拒绝写保留键**(路由/加载控制键如 `type` / `module` / `count` 等)。
|
||
- `Plugin.reload(new_config)` 在互斥锁下先 `on_cleanup()` 释放旧资源、再 `on_init()` 用新配置重建客户端(如 AI/DB client),使配置**立即生效、无需重启网关**。
|
||
- 仅 index0 副本落盘避免并发写冲突,其余副本同样应用新配置;任一失败则返回失败明细且不触发重启方式的成功确认。
|
||
|
||
### 副本数量管理(扩缩容)
|
||
|
||
同类 worker 的副本数可随时调整,并**持久化到配置**(重启网关后保持):
|
||
|
||
- **扩容**:新增副本槽位(`WorkerPool` 新增 `_managed_worker` 管理循环,新副本注册 liveliness 后可被负载均衡)。
|
||
- **缩容**:随机挑选多余副本触发 **`drain`(优雅排空)**——先摘除 liveliness/业务 Queryable **隔绝新请求**,等待正在处理的**在途请求完成**后再关闭该副本(`in-flight` 计数实现),避免中断业务;管理循环不重建。
|
||
- **目标数量持久化**:`rescale` 把 `[workers].count` 写回 `config.toml`,网关/进程重启后按新数量加载。
|
||
- **统一协议**:inline 与 external 共用。网关对 inline 直接调整本进程 `WorkerPool`;对 external 经 Zenoh 向任一存活副本下发 `rescale`,由其**所在进程内**的池扩缩并写回自身配置(无需重启整个进程/容器)。
|
||
|
||
### 全局副本数协调(多网关)
|
||
|
||
多个网关共享同一份 `chongming-cache`(根 `config.toml` 的 `[cache]` 段)时,副本数「count」语义为**该类 worker 的全局目标总量**,由 chongming-cache 作为**单一事实来源**,各网关按在线数量自动分摊。这样只在任意一台网关执行扩缩容,即可全局生效。
|
||
|
||
- **单一事实来源**:`count` 存于 cache 键 `worker:cm:counts:<type>`,在线网关 id 列表存 `worker:cm:gateways`,各网关分摊配额存 `worker:cm:quota:<type>:<gw>`(可观测)。
|
||
- **网关登记/注销 + 心跳租约**:网关启动时 `register_gateway()` 加入在线列表,并每 15s `heartbeat_gateway()` 刷新自身时间戳;超过租约(60s)未心跳的死网关会被自动清理(crash/kill -9 也不残留,避免配额失真)。当前由 `CHONGMING_GATEWAY_ID` 环境变量指定(多实例需唯一,尤其**同宿主多网关必须显式指定**;缺省回退 `hostname`,稳定且重启不变,不残留);关闭时 `unregister_gateway()` 移除,其余网关实时重算分摊。
|
||
- **分摊算法**:`own_quota()` 将全局总量按在线网关 sorted(id) 均分,余量按序补前若干。`/admin/workers/<type>/scale`(body `{count:<全局总量>}`)写全局 count 后,各网关把自己的 session 副本调到自己的 quota。
|
||
- **共享方式与后端**:单实例本机 `diskcache` 即可;**多实例必须共享同一 cache 后端**(同一共享卷的 diskcache 或 redis),否则各写各的 cache 无法收敛成全局量。
|
||
- **启动优先级开关**:根 `config.toml` 的 `[cache].launch_worker_count` 决定网关启动时副本数的来源:
|
||
|
||
```toml
|
||
[cache]
|
||
backend = "diskcache" # "diskcache"(默认) | "redis"
|
||
cache_store_path = "./cache_data"
|
||
launch_worker_count = "toml" # "toml"(默认)=启动用 toml 的 count 覆盖并写回 cache;"cache"=cache 为单一事实来源,toml 仅在缺失时引导
|
||
```
|
||
|
||
- **进程插件(external)不受该开关影响**:网关只对 **inline** 插件用 cache 解析启动副本数(见「启动流程」第 5 步 `load_workers`);external 插件由外部编排按其自身配置 `config/workers/<type>/config.toml` 的 `count` 启动,不经网关、也不读 cache。运行时 `scale` 对 external 仍走「向存活副本下发 rescale」路径,同样与该开关无关。
|
||
|
||
### 前端管理页
|
||
|
||
`Worker 管理`(`/workers`,深色主题):
|
||
|
||
- **登录**:经 auth 插件 `POST /auth/login` 领取管理 Token(无需手填 JWT),从 JWT 解析当前用户与超管标识。
|
||
- **鉴权**:仅 `is_superuser=true` 可管理;权限不足时前端/后端弹出对应提示(403)。
|
||
- **列表分页**:展示副本(插件类型 / 副本 ID / 模式 inline|external / 状态),内置分页。
|
||
- **操作**:单副本重启、批量重启(选中)、插件级重启全部副本、更新插件配置(弹窗展示现有配置值,点行带入编辑)、**调整副本数量**(当前数 + `el-input-number` 设目标 + 应用,可扩缩容)。
|
||
- **auth 核心插件**:配置不可更改,不在列表中展示(`Worker` 列表自动过滤 `worker_type == "auth"`)。
|
||
- 调小副本数会**触发优雅排空**并在前端确认提示中说明。
|
||
|
||
### external(进程)插件同样可管理
|
||
|
||
external 副本走同一 `__admin__` Queryable,路由发现、指令下发与扩缩容(`rescale`)与 inline 一致。**前提**:
|
||
|
||
1. external 容器运行的是含管理能力(`__admin__` + `reload` + `rescale`)的新版 `chongming-worker` 框架;
|
||
2. `config_set` / `rescale` 由副本在**其进程 cwd** 下写 `config/workers/<type>/config.toml`,external 容器需挂载与网关同款配置目录才能写回网关侧配置(含 `[workers].count` 持久化);
|
||
3. 纯自定义语言(如 Rust `rsdemo`)进程插件需自行实现 `__admin__` Queryable + liveliness + 数量管理,否则只能发现、无法改写配置或扩缩容。
|
||
|
||
---
|
||
|
||
## 端点类型与路由注册
|
||
|
||
### 端点类型
|
||
|
||
TOML 文件中的节类型决定端点暴露方式:
|
||
|
||
| 节类型 | HTTP 路由 | OpenAPI 文档 | MQTT | 请求模型命名 |
|
||
| -------- | --------- | ------------ | ---- | ------------------------------------- |
|
||
| `[GET]` | ✅ | ✅ | ✅ | `XxxGetRequest / XxxGetResponse` |
|
||
| `[POST]` | ✅ | ✅ | ✅ | `XxxPostRequest / XxxPostResponse` |
|
||
| `[MQTT]` | ❌ | ❌ | ✅ | `XxxMqttRequest`(无 response_model) |
|
||
|
||
### 两种路由注册方式
|
||
|
||
#### 方式一:TOML 动态路由(标准 JSON 端点)
|
||
|
||
通过 `config/workers/<插件>/*.toml` 定义端点,自动生成 FastAPI 路由。适用于参数和响应可被 Pydantic 模型描述的标准接口。
|
||
|
||
```toml
|
||
# config/workers/example/add.toml
|
||
[GET]
|
||
summary = "加法运算"
|
||
params = ["a: float", "b: float"]
|
||
|
||
[GET.response_model]
|
||
result = { type = "float", required = true }
|
||
```
|
||
|
||
#### 方式二:插件自定义路由(特殊端点)
|
||
|
||
当端点无法用 TOML 描述时(如 `multipart/form-data` 上传),插件暴露 `APIRouter` 实例,网关自动发现并注册。
|
||
|
||
```python
|
||
# src/plugins/<name>/routes.py
|
||
from fastapi import APIRouter, UploadFile, File
|
||
|
||
router = APIRouter(prefix="/<prefix>", tags=["<worker_type>"])
|
||
|
||
@router.post("/upload")
|
||
async def upload(file: UploadFile = File(...)):
|
||
...
|
||
```
|
||
|
||
> **约定**:插件 `__init__.py` 中导入 `router` 实例(`from .routes import router`),网关通过 `getattr(module, "router", None)` 自动发现。
|
||
|
||
### 流式端点(SSE)
|
||
|
||
基于 Zenoh Query/Reply 原生"多回复"实现流式输出:Worker 的 `@rpc_method` 返回生成器时,
|
||
框架逐块 `query.reply()` 推送(见 `utils/worker` README「流式端点」),网关以 SSE
|
||
(`text/event-stream`)逐块转发给 HTTP 客户端。**无额外端口、无额外进程、无新依赖**;
|
||
未声明 `stream` 的端点行为与之前完全一致。
|
||
|
||
#### TOML 配置
|
||
|
||
在方法节中声明 `stream = true`(示例 `config/workers/example/stream_chat.toml`):
|
||
|
||
```toml
|
||
[POST]
|
||
summary = "模拟 AI 流式对话(SSE,逐 token 输出)"
|
||
auth_required = false
|
||
stream = true
|
||
timeout = 300.0 # 流总寿命上限(秒,zenoh query deadline 硬上限)
|
||
stream_idle_timeout = 10.0 # 网关侧连续无数据块的最大间隔(秒)
|
||
params = ["prompt: str", "tokens: int"]
|
||
```
|
||
|
||
| 字段 | 默认值 | 说明 |
|
||
| --- | --- | --- |
|
||
| `stream` | `false` | 流式端点:以 SSE(`text/event-stream`)输出 |
|
||
| `timeout` | `3.0` | 流总寿命上限(秒)。**流式端点必须配大**(如 300s),到期后 zenoh 丢弃后续回复 |
|
||
| `stream_idle_timeout` | `10.0` | 空闲超时(秒):超过该间隔无新数据块则网关终止流 |
|
||
|
||
> `timeout`(总寿命硬上限)与 `stream_idle_timeout`(空闲超时)是两回事,流式场景两个都要配。
|
||
|
||
#### 请求与响应
|
||
|
||
- 请求与普通端点一致(GET 走 query/path 参数,POST/PUT/PATCH 走 body 模型),鉴权依赖同样生效
|
||
- 响应为 `text/event-stream`,每块一个 `data: {json}\n\n` 事件(SSE 标准分帧)
|
||
- 响应头:`Cache-Control: no-cache`、`X-Accel-Buffering: no`(配合反代关闭缓冲)
|
||
- OpenAPI 不声明流式端点的响应 schema(逐块 JSON dict,无法用单一模型描述)
|
||
|
||
```bash
|
||
curl -N -X POST localhost:8000/api/v1/calc/stream_chat \
|
||
-H 'Content-Type: application/json' -d '{"prompt":"你好","tokens":3}'
|
||
# data: {"token":"你好·1","index":0}
|
||
# data: {"token":"你好·2","index":1}
|
||
# data: {"token":"你好·3","index":2}
|
||
# data: {"done":true}
|
||
```
|
||
|
||
#### 错误语义
|
||
|
||
| 场景 | 表现 |
|
||
| --- | --- |
|
||
| 无可用 worker(首个数据块前) | HTTP 503(与普通端点一致) |
|
||
| Worker 中途异常 / 流式端点初始化失败 | SSE error 事件 `data: {"error":"..."}` 收尾(HTTP 200 已提交,无法再改状态码) |
|
||
| 空闲超时 | SSE error 事件 `data: {"error":"流式空闲超时 ..."}` 收尾 |
|
||
| 客户端断开 | 网关终止迭代,Worker 侧 reply 失败自动停流,不空转 |
|
||
|
||
#### 部署注意
|
||
|
||
生产环境经 nginx 反代时需关闭缓冲,否则 SSE 会被整段缓冲、失去逐块即时性:
|
||
|
||
```nginx
|
||
location /api/v1/ {
|
||
proxy_buffering off;
|
||
}
|
||
```
|
||
|
||
#### 本地联调前注意
|
||
|
||
流式能力在 `chongming-worker` 框架(`utils/worker/`,独立仓库)。**本地未 push 的框架改动
|
||
不会自动生效**——venv 里安装的是 `uv sync` 从 git 源拉取的旧版副本,旧版 `@rpc_method`
|
||
不认 `stream` 参数,会报 `TypeError: rpc_method() got an unexpected keyword argument 'stream'`
|
||
并连锁导致契约校验失败(启动终止)。本地联调时先以可编辑方式装入 venv:
|
||
|
||
```bash
|
||
uv pip install -e utils/worker
|
||
```
|
||
|
||
正式发布仍走「开发与发布检查清单」流程(工具包 push → `uv lock --upgrade-package
|
||
chongming-worker` → `uv sync`,可编辑安装会被锁文件版本替换)。
|
||
|
||
#### 测试
|
||
|
||
```
|
||
uv run python test_stream_worker.py # Worker 框架流式回复单测
|
||
uv run python test_stream_gateway.py # 网关 call_stream 单测
|
||
uv run python test_stream_e2e_zenoh.py # 真实 Zenoh 会话端到端(peer 模式,无需 router)
|
||
uv run python test_stream_route.py # 路由层 SSE 输出与兼容性回归(非流式端点不变)
|
||
```
|
||
|
||
---
|
||
|
||
## 进程插件与混合部署
|
||
|
||
两种插件运行模式**按插件粒度共存**,在 `config/workers/<name>/config.toml` 的 `[workers]` 节声明:
|
||
|
||
```toml
|
||
load_mode = "inline" # 默认:插件在网关进程内加载
|
||
load_mode = "external" # 独立进程运行,经 Zenoh 注册路由
|
||
```
|
||
|
||
**inline 插件**(`src/plugins/`,chongming-plugins 仓库):
|
||
|
||
- 网关进程内 import;路由由网关盘扫 TOML 生成;契约校验在网关启动时执行
|
||
|
||
**external 进程插件**(本地开发目录 `workers/`,自包含项目,不入库):
|
||
|
||
- 与网关**零导入关系**:只依赖 `chongming-worker` SDK + zenoh,仅经 Zenoh 通讯
|
||
- 路由注册:worker 启动时 put 描述符到 `chongming/routes/<type>/...`,退出时 delete;每 10s 周期重发布自愈
|
||
- 服务发现:liveliness `worker/<type>/<id>`(与 inline 副本同一机制,网关无需改动)
|
||
- worker 进程自读 TOML 并在**自己进程内**做契约校验(`chongming_worker.contracts`);
|
||
网关 RouteRegistry **常驻订阅**描述符后动态挂载/摘除 HTTP 路由(type 级 2s 防抖)。
|
||
路由注册与网关侧插件盘扫(`config/workers/*/config.toml`)解耦:**网关容器无需
|
||
放置 external 插件的配置文件**,盘扫发现的 external 条目仅用于启动日志观测;
|
||
inline 插件仍按盘扫在网关进程内加载,不受影响
|
||
- 每个插件是**自包含项目**(`workers/<name>/` = 打包 zip 根 = 容器工作目录,
|
||
开发即产物),代码结构与 inline 插件完全一致(Plugin 基类 + router/ + models/),
|
||
示例见本地 `workers/demo/`;新项目用 `uv run gen_plugin <name> --process` 生成骨架
|
||
- 运行(在插件项目根 `workers/<name>/` 下):
|
||
|
||
```bash
|
||
cd workers/demo
|
||
uv run chongming-worker --type demo # 本地调试(首次先 uv sync 装依赖)
|
||
./start.sh # 与容器一致的启动方式(uv sync + 启动)
|
||
```
|
||
|
||
- 生产部署:进程插件与网关**分别打包到不同容器**
|
||
- 网关容器:`chongming` + 依赖
|
||
- 进程插件容器:插件代码 + `chongming-worker` + 依赖
|
||
- 隔离性由 `test_worker_isolation.py` 保证(阻断 chongming 导入 + AST 检查 import 语句)
|
||
|
||
### 进程插件打包
|
||
|
||
`build_plugin` 把插件项目根直接压缩为可部署 zip(开发目录即产物,
|
||
插件代码 + 配置 + 依赖清单 + 容器入口都在 `workers/<name>/` 内):
|
||
|
||
```bash
|
||
uv run build_plugin demo # → dist/demo.zip
|
||
uv run build_plugin demo --output /tmp/pkg
|
||
```
|
||
|
||
产物布局(= 项目根,zip 根即容器工作目录):
|
||
|
||
```text
|
||
workers/<name>/ 插件代码(模块 workers.<name>)
|
||
config/workers/<name>/ 插件注册 + 端点配置
|
||
config/zenoh_config.json5 Zenoh 会话配置
|
||
config.toml 最小根配置(仅 [zenoh] 节,worker 启动必需)
|
||
pyproject.toml uv 依赖清单(chongming-worker 内网 git 源)
|
||
start.sh 容器入口:uv sync + chongming-worker --type <name>
|
||
```
|
||
|
||
- 打包自动排除 `__pycache__` / `*.pyc` / `.venv` 等,`start.sh` 权限强制 0o755
|
||
- 插件扩展依赖(可选):直接在项目根 `pyproject.toml` 的 dependencies 中追加
|
||
- 容器内部署:`unzip <name>.zip -d /app && cd /app && ./start.sh`(镜像需预装 uv)
|
||
- 打包前校验:`workers/<name>/` 项目根、项目内 `config/workers/<name>/config.toml`
|
||
(含 `[workers]` 节)、`config/zenoh_config.json5` 与根 `config.toml`(含 `[zenoh]`)必须存在,
|
||
`load_mode` 非 `external` 时告警
|
||
- 插件配置随 zip 部署在**插件容器**(worker 自读);网关侧无需放置(RouteRegistry 常驻订阅 Zenoh 路由描述符,与盘扫解耦)
|
||
|
||
---
|
||
|
||
## MQTT 协议
|
||
|
||
### Topic 约定
|
||
|
||
| 方向 | Topic | 说明 |
|
||
| ---- | -------------------------------- | ------------------------------ |
|
||
| 请求 | `chongming/<type>/<op>` | MQTT → Worker |
|
||
| 响应 | `chongming/<type>/<op>/response` | Worker → MQTT(`None` 时跳过) |
|
||
|
||
### Broker 来源(内嵌 vs 外部)
|
||
|
||
网关默认启动内嵌 amqtt Broker(子进程 + 文件锁单例),`[<env>.mqtt].use_embedded_broker` 控制 Broker 来源:
|
||
|
||
```toml
|
||
[development.mqtt]
|
||
enabled = true
|
||
host = "0.0.0.0" # true 时为内嵌 Broker 监听地址;false 时为外部 Broker 地址
|
||
port = 1883
|
||
use_embedded_broker = true # true(默认)网关启动 amqtt Broker;false 连接外部 Broker
|
||
```
|
||
|
||
- `use_embedded_broker = true`(默认):网关启动内嵌 amqtt Broker 子进程,MQTT Bridge 作为客户端连回自身。
|
||
- `use_embedded_broker = false`:网关**不启动** Broker,MQTT Bridge 直接连接 `host:port` 指向的外部 MQTT Broker(如独立部署的 EMQX/Mosquitto)。`host` 需改为外部 Broker 地址,`enabled = false` 时整个 MQTT 通道关闭。
|
||
|
||
### Broker 认证(用户名/密码)
|
||
|
||
`[<env>.mqtt].username` / `password` 配置 Broker 认证(可选,默认匿名):
|
||
|
||
```toml
|
||
[development.mqtt]
|
||
enabled = true
|
||
host = "0.0.0.0"
|
||
port = 1883
|
||
username = "chongming" # 可选;内嵌/外部 Broker 均生效
|
||
password = "change-me"
|
||
```
|
||
|
||
- **内嵌 Broker**(`use_embedded_broker=true`):配置后启用认证(amqtt FileAuthPlugin + argon2 哈希),所有客户端(含网关 Bridge)必须携带该账号密码连接;未配置则保持匿名。
|
||
- **外部 Broker**:网关 Bridge 以该账号密码连接,broker 侧需自行创建对应账号。
|
||
- 客户端连接示例:`mqtt://chongming:change-me@localhost:1883/`(密码含特殊字符时需百分号编码,如 `@` → `%40`;网关 Bridge 内部自动处理)。
|
||
- 注意:密码明文存放于配置,生产环境建议使用外部 Broker + 环境变量注入。
|
||
|
||
### 自定义订阅主题
|
||
|
||
除内置的 `chongming/<type>/<op>` 接口外,可将外部 MQTT 主题桥接到任意 Worker。**推荐在插件自己的配置** `config/workers/<type>/config.toml` 中通过 `[[workers.mqtt_topics]]` 声明(目标 worker 即该插件本身):
|
||
|
||
```toml
|
||
# config/workers/aibox_sophon_adapter/config.toml
|
||
[[workers.mqtt_topics]]
|
||
topic = "box/aibox_sophon/board_ping" # 支持 +(单级)/ #(多级,须在末尾)通配符
|
||
subject = "aibox_sophon_adapter.board_ping" # 可选,{1} {2}... 对应通配符捕获值
|
||
response_topic = "/board_ping/response" # 可选,响应主题;默认 "<实际主题>/response"
|
||
```
|
||
|
||
- `subject` 缺省为 `<插件类型>.<topic 最后一段>`;`response_topic` 缺省为 `<实际匹配主题>/response`。
|
||
- 网关发现插件时自动收集所有 `[[workers.mqtt_topics]]`,MQTT Bridge 一并订阅并路由。
|
||
- 多条自定义主题按配置顺序匹配,先匹配者优先;内置 `chongming/...` 接口最后兜底。
|
||
- 全局 `[<env>.mqtt].custom_topics` 仍可作为通用兜底(不依赖具体插件时使用,可选)。
|
||
|
||
### MQTT Bridge 单例(多实例免重复响应)
|
||
|
||
MQTT Bridge 是**网关进程内**的 MQTT 客户端组件,负责订阅主题并把请求经 `WorkerManager` 转发给 Worker、回发 `/response`。为了让「同一条请求只被消费一次、只回一份响应」,Bridge 的启动采用**基于共享缓存的分布式锁**(`chongming-cache` 提供,`DistributedLock`),而不再使用本机文件锁。
|
||
|
||
- **抢锁机制**:启动时 `set_nx`(SET NX + TTL 租约)原子抢锁,key 为 `mqtt_bridge`;抢到锁的网关才启动 Bridge,其余网关跳过。
|
||
- **租约续约**:持锁网关后台定期 `touch` 续约;若持锁网关宕机/失联,租约到期后锁自动释放,其他网关可重新抢到(重启后生效)。
|
||
- **受保护释放**:关闭时仅当 token 仍匹配(仍是自己持有)才删除,绝不误删其他网关抢到的锁。
|
||
|
||
```toml
|
||
[cache]
|
||
backend = "redis" # 跨主机收敛必须用 redis(或共享卷 diskcache)
|
||
```
|
||
|
||
- **关键条件**:跨机器收敛依赖**共享缓存后端**(与「全局副本数协调」同一 `[cache]`,单一事实来源)。仅 `redis`(或共享卷的 `diskcache`)后端时,不同物理机上的网关才会看到同一把锁,真正全局单 Bridge。
|
||
- **`use_embedded_broker = true`(各机内嵌独立 Broker)**:各机 Broker 互不相连、本身不产生重复响应;此时全局单 Bridge 只会连到持锁网关那台机器的 Broker。
|
||
- **`use_embedded_broker = false`(共享外部 Broker)**:原先 N 台网关的 N 个 Bridge 会共同订阅同一批主题,导致一条请求被各消费一次、各回一份响应;改用分布式锁后全局只有一个 Bridge 消费,彻底规避重复响应。
|
||
|
||
### 请求负载格式(信封协议)
|
||
|
||
MQTT 请求负载为信封结构,控制字段与业务数据分离:
|
||
|
||
```json
|
||
{
|
||
"meta": {
|
||
"method": "GET", // 可选,默认 GET;MQTT 专用端点需显式 "MQTT"
|
||
"timeout": 30, // 可选,RPC 超时(秒),默认 30
|
||
"cacheable": false // 可选,是否允许结果缓存,默认 false
|
||
},
|
||
"data": { "a": 3, "b": 5 } // 业务参数,传给 Worker
|
||
}
|
||
```
|
||
|
||
- 非信封格式的负载会被网关丢弃并告警(严格协议,设备侧请按此格式发布)。
|
||
- HTTP 通道由网关自动组装信封(注入 method / user_info),无需调用方关心。
|
||
|
||
### 快速测试
|
||
|
||
```bash
|
||
# 终端 1:启动服务
|
||
uv run serve
|
||
|
||
# 终端 2:端到端测试
|
||
python test_mqtt_e2e.py
|
||
|
||
# 手动测试
|
||
python subscriber.py # 监听所有响应
|
||
python publisher.py example add '{"a":3,"b":5}' # 调用 add
|
||
```
|
||
|
||
---
|
||
|
||
## 开发指南
|
||
|
||
### 添加新 Worker 插件
|
||
|
||
```text
|
||
1. 创建 src/plugins/<name>/ — __init__.py(Plugin 子类), global_var.py, router/, models/
|
||
2. 创建 config/workers/<name>/config.toml,在 [workers] 节注册插件
|
||
(type / module / factory / cleanup / count + [workers.config] 运行时配置)
|
||
3. 创建 config/workers/<name>/*.toml 端点定义
|
||
4. 运行 uv run gen_models 生成模型
|
||
5. 实现 router/<op>.py,引用 models/pydantic.py 中的模型
|
||
6. 更新 router/__init__.py 导入
|
||
```
|
||
|
||
> 推荐用脚手架一步生成骨架:`uv run gen_plugin <name> [operation ...]`。
|
||
> 启动时网关会做**契约校验**:TOML 路由缺少对应 `@rpc_method` 将导致启动失败,
|
||
> 模型缺失/孤儿等不一致以警告日志提示。
|
||
|
||
### 为现有插件添加新端点
|
||
|
||
```text
|
||
1. 创建 config/workers/<name>/<op>.toml
|
||
2. 运行 uv run gen_models
|
||
3. 创建 router/<op>.py → 引用生成的模型
|
||
4. 更新 router/__init__.py
|
||
5. 重启服务
|
||
```
|
||
|
||
流式端点(SSE)在此基础上额外两步:TOML 方法节声明 `stream = true` 并配大 `timeout`;
|
||
`@rpc_method(..., stream=True)` 函数返回生成器(yield 逐块),详见上文「流式端点(SSE)」。
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
uv run serve # 启动开发服务
|
||
uv run gen_plugin <name> # 生成统一风格插件骨架
|
||
uv run gen_models # 生成 Pydantic 模型
|
||
uv run build # 构建打包(PyInstaller/Nuitka)
|
||
uv run chongming-worker --type <name> # 独立 Worker 进程(项目根下本地调试,load_mode=external)
|
||
chongming-worker --type <name> # 独立 Worker 进程(容器入口)
|
||
uv pip install -e utils/<name> # 安装/更新工具包
|
||
```
|
||
|
||
---
|
||
|
||
## 插件列表
|
||
|
||
| 插件 | 路径 | 功能 |
|
||
| ------------------------ | ----------------------------------- | ------------------------------------------------------- |
|
||
| **auth** | `src/plugins/auth/` | 用户注册/登录/资料管理,JWT 鉴权,管理员初始化 |
|
||
| **doubao** | `src/plugins/doubao/` | 豆包视觉理解,支持 AICC 安全通信通道 |
|
||
| **aibox_sophon_adapter** | `src/plugins/aibox_sophon_adapter/` | AI Box 设备心跳监控、离线检测、告警上报与查询、视频上传 |
|
||
| **example** | `src/plugins/example/` | 四则运算 + 心跳演示(含 MQTT 端点示例) |
|
||
| **demo**(进程插件示例) | `workers/demo/`(本地自包含项目,不入库) | 独立进程运行(load_mode=external),经 Zenoh 注册路由 |
|
||
|
||
---
|
||
|
||
## 工具包列表
|
||
|
||
| 包名 | 路径 | 语言 | 说明 |
|
||
| ---------------------------- | ----------------------- | ----------- | ---------------------------------------------- |
|
||
| **chongming-config** | `utils/config/` | Python | TOML 配置加载,TypedDict 类型安全 |
|
||
| **chongming-database** | `utils/database/` | Python | aiosqlite + SQLModel 异步数据库封装 |
|
||
| **chongming-jwt** | `utils/jwt/` | Rust + PyO3 | JWT 编解码,支持 HS256/384/512 + RS256/384/512 |
|
||
| **chongming-password** | `utils/password/` | Rust + PyO3 | Argon2id 密码哈希与验证 |
|
||
| **chongming-request** | `utils/request/` | Python | Zenoh RPC 直连客户端 |
|
||
| **chongming-worker** | `utils/worker/` | Python | Worker 框架核心:装饰器、运行时、契约校验、独立进程入口(`chongming-worker`) |
|
||
| **chongming-stream-manager** | `utils/stream_manager/` | Python | ffmpeg + MediaMTX RTSP 流代理管理 |
|
||
| **bytedance** | `utils/bytedance/` | Python | 字节跳动 AICC 安全通信 SDK(Jeddak 等) |
|
||
|
||
---
|
||
|
||
## 配置说明
|
||
|
||
- **应用配置**:根目录 `config.toml`,包含环境、服务器、安全、MQTT 等全局设置
|
||
- **插件加载模式**:按插件粒度声明在 `config/workers/<name>/config.toml` 的 `[workers]` 节
|
||
- `load_mode = "inline"`(默认):插件在网关进程内加载
|
||
- `load_mode = "external"`:插件以独立进程运行(进程编排交给 Docker/K8s,
|
||
进程入口 `uv run chongming-worker --type <name>`),经 Zenoh 在 `chongming/routes/**`
|
||
注册路由,网关动态挂载 HTTP 端点(RouteRegistry 常驻订阅,无需在网关侧保留插件配置)
|
||
- 两种模式可同时存在(混合部署)
|
||
- **进程插件与网关完全隔离**:进程插件只依赖 `chongming-worker` SDK + zenoh,
|
||
与网关(`chongming` 包)零导入关系,仅通过 Zenoh(`chongming/routes/**` 注册路由、
|
||
`worker/<type>/<id>` 服务发现)通讯。`workers/` 目录仅为开发便利,
|
||
**生产部署时进程插件与网关分别打包到不同容器**:
|
||
- 网关容器:`chongming`(含 `src/chongming/`)+ 依赖
|
||
- 进程插件容器:插件代码(`workers/<name>/`)+ `chongming-worker` + 依赖,
|
||
入口 `chongming-worker --type <name>`),
|
||
打包: `uv run build_plugin <name>` → `dist/<name>.zip`(见「进程插件打包」)
|
||
- **Zenoh 配置**:`config/zenoh_config.json5`
|
||
- **插件注册**:`config/workers/<name>/config.toml` 的 `[workers]` 节,定义加载方式、副本数与运行时配置(旧全局 `config/workers/config.toml` 仅作兜底兼容)
|
||
- **路由定义**:`config/workers/<name>/*.toml`,每个端点一个文件
|
||
|
||
详细配置说明见 [`config/README.md`](config/README.md)。
|
||
|
||
---
|
||
|
||
## 构建部署
|
||
|
||
```bash
|
||
# PyInstaller 打包
|
||
uv run build pyinstaller
|
||
|
||
# Nuitka 打包
|
||
uv run build nuitka
|
||
|
||
# 仅重新打包 .mbank 模块文件(第三方依赖不变时,更新只需替换 mbank 文件)
|
||
uv run build --only mbank
|
||
|
||
# 只执行指定步骤,跳过其余流程
|
||
uv run build --only mbank,prepare,vue
|
||
```
|
||
|
||
构建过程包括:模块加密打包 → 资源复制 → PyInstaller/Nuitka 打包 → 数据库初始化 → 前端编译 → VFS 挂载。
|
||
|
||
`--only <step>` 可选步骤:`mbank`(模块打包)、`prepare`(准备构建目录)、
|
||
`obfuscate`(PyArmor 混淆,仅 pyinstaller 模式)、`pack`(PyInstaller/Nuitka 打包)、
|
||
`clean`(清理临时文件)、`vue`(Vue 前端构建);可逗号分隔或重复传多个。
|
||
|
||
详见 [插件开发指南](src/plugins/README.md)。
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
uv run serve # 启动开发服务器
|
||
uv run gen_plugin <name> # 生成统一风格插件骨架(--process 生成进程插件项目)
|
||
uv run gen_models # 生成 Pydantic 模型
|
||
uv run build pyinstaller # PyInstaller 打包
|
||
uv run build nuitka # Nuitka 打包
|
||
uv run build_plugin <name> # 进程插件打包 → dist/<name>.zip
|
||
chongming-worker --type <name> # 独立 Worker 进程(进程插件容器入口)
|
||
uv pip install -e utils/<name> # 安装/更新工具包子包
|
||
```
|
||
|
||
### TOML 配置字段速查
|
||
|
||
| 字段 | 位置 | 说明 |
|
||
| -------------------- | --------------------- | --------------------------------------- |
|
||
| `count` | `<插件>/config.toml` | Worker 副本数(`[workers]` 节) |
|
||
| `launch_worker_count`| `根 config.toml` | 启动时副本数来源:`"toml"`=用 toml count 覆盖 cache(默认);`"cache"`=以 cache 为单一事实来源(`[cache]` 节) |
|
||
| `router_prefix` | `<插件>/config.toml` | API 路由前缀 |
|
||
| `defaults.timeout` | `<插件>/config.toml` | 默认超时(秒) |
|
||
| `defaults.cacheable` | `<插件>/config.toml` | 是否缓存 RPC 结果 |
|
||
| `params` | `<操作>.toml` | 参数列表(`"name: type"` 格式) |
|
||
| `auth_required` | `<操作>.toml` | 是否需要 JWT 鉴权 |
|
||
| `internal` | `<操作>.toml` | `true` 则仅限内部 RPC,不注册 HTTP 路由 |
|
||
| `cacheable` | `<操作>.toml` | 端点是否可缓存 |
|
||
| `summary` | `<操作>.toml` | 端点描述(用于 OpenAPI / 日志) |
|
||
| `stream` | `<操作>.toml` | `true` 则流式输出(SSE),需同时配大 `timeout` |
|
||
| `stream_idle_timeout`| `<操作>.toml` | 流式空闲超时(秒,默认 10),超时无新数据块则终止流 |
|
||
|
||
---
|
||
|
||
## 内置插件
|
||
|
||
| 插件 | HTTP 前缀 | MQTT 主题前缀 | 说明 |
|
||
| ------------------------ | --------- | ------------------------ | ------------------------------------ |
|
||
| **auth** | `/auth` | `auth.*` | 注册、登录、JWT 鉴权、个人信息、改密 |
|
||
| **doubao** | `/doubao` | `doubao.*` | 火山引擎豆包视觉理解模型 |
|
||
| **example** | `/calc` | `example.*` | 四则运算 + 访问计数 + MQTT 心跳示例 |
|
||
| **aibox_sophon_adapter** | `/aibox` | `aibox_sophon_adapter.*` | AI Box 设备心跳适配 + 视频上传 |
|
||
|
||
---
|
||
|
||
## 更多文档
|
||
|
||
- [配置说明](config/README.md)
|
||
- [插件开发指南](src/plugins/README.md)
|
||
- [进程插件开发指南(external 模式,从开发到部署)](docs/process-plugin.md)
|
||
- [前端开发指南](src/chongming-web/README.md)
|
||
- [Worker 框架](utils/worker/README.md)
|