# chongming-gateway chongming 网关本体:基于 **FastAPI + Zenoh** 的配置驱动微服务网关。 把宿主项目里的插件(inline 进程内 / external 独立进程)发布的路由统一挂载为 HTTP 端点, 并提供 Worker 服务发现、负载均衡、超时重试、实例定向、MQTT Bridge、内置登录鉴权 与机器码授权(chongming-license)。 网关只提供**代码**:配置、插件与打包骨架由宿主项目提供(见「运行时约定」)。 --- ## 安装 ```bash # 作为依赖(宿主项目,从私有源安装) uv add chongming-gateway # 开发期可编辑安装(在 chongming-core 仓库内) uv pip install -e utils/gateway ``` 网关自带完整依赖清单(`fastapi` / `granian` / `zenoh` / `chongming-worker` 等), 宿主项目无需重复声明;需要哪些第三方包,见本包 `pyproject.toml`。 ## 快速开始 宿主项目(cwd)下准备 `config.toml` 与 `config/workers//config.toml`, 并保证插件包(`plugins.`)可导入。之后任选一种启动方式: ```bash # 按 config.toml [.server] 启动(三个入口等价,仅默认服务器不同) uv run serve # uvicorn uv run granian # granian uv run gunicorn # gunicorn + uvicorn worker # 或把 ASGI 应用交给任意服务器 uvicorn chongming.app:app --host 0.0.0.0 --port 8000 ``` 网关按 `config/workers//config.toml` 的 `[workers]` 节逐插件读取加载方式 (`load_mode = "inline" | "external"`)与副本数,启动时自动发现并挂载路由。 ## 运行时约定 - **配置**:cwd 下 `config.toml`(环境、服务器、安全、MQTT、缓存、授权等)与 `config/workers/**`(插件注册与路由定义),运行期读取,随宿主项目部署。 - **插件**:网关按 `plugins.` 约定导入插件包,来源不限——`.mbank` 模块银行、 源码目录(开发态 `src/plugins`)或已安装包均可。 - **工作目录**:日志、上传、数据等相对路径均以 cwd 为基准。 ## 机器码授权(chongming-license) 厂商用**私钥**离线签发 `license.lic`(绑定机器指纹 + 插件白名单 + 有效期), 网关内置**公钥**验签,全程无需联网。未授权的插件不加载、不注册路由 (external 插件经 Zenoh 推来的描述符同样被忽略)、管理接口一律 403。 是否启用校验见下方「打包」一节:非授权版产物完全不校验,授权版产物强制校验。 宿主 `config.toml` 的 `[license]` 段(缺省视为未配置,不启用校验): ```toml [license] # 是否执行拒绝。**只在非打包态生效**(uv run serve / 测试)——打包产物的 # 开关由构建期烘焙决定(部署目录的 config.toml 明文可写,以它为准等于放行 # 现场改一行就绕过授权) enabled = false path = "license.lic" # 授权文件路径(相对网关工作目录) public_key = "" # 厂商公钥(base64 裸 32 字节或 PEM);由构建脚本注入, # 授权版还会把公钥烘焙进产物代码,此处仅作镜像/兜底 min_match = 3 # 指纹命中阈值(N-of-M),容忍单块网卡/eMMC 更换 ``` 非打包态也可用 `CHONGMING_LICENSE_MODE=on`(或 `off`)临时开启/关闭, 便于在开发机上验证门禁逻辑。 ### 打包:license 是可选构建项 "是否强制校验"由**构建期烘焙**决定,而不是运行时可写的配置 —— 打包脚本在编译前 生成 `chongming/_build_flags.py`(随代码编译进产物,部署侧不可改): | 构建方式 | 产物 | 行为 | | --- | --- | --- | | 不加 `--license` | 非授权版 | 不校验授权,插件照常加载(与开发态一致) | | `--license` + 厂商公钥 | 授权版 | 强制校验;公钥随代码内置,现场换 `config.toml` 里的公钥也无法自签绕过 | | 旧打包脚本(未烘焙) | 兼容旧语义 | 打包即强制校验 | 即**不配 license 也能正常出包**(非授权版不是"拒绝所有插件"的砖头包), 授权版则无法被现场改配置/环境变量关掉。宿主打包命令: ```bash uv run build --encrypt --license # 授权版产物(读 CHONGMING_LICENSE_PUBKEY / license_public.key) uv run build --encrypt # 非授权版产物:不校验、插件照常加载 ``` 烘焙标记只对打包产物生效——源码运行(含可编辑安装)仍只由上面的配置/环境变量 决定,不会因为上次打了授权版包就把开发态也锁上。 授权管理端点(`/api/v1/license/...`,仅超级管理员): | 端点 | 用途 | | --- | --- | | `GET /license/info` | 机器码、申请码、授权状态、各插件授权情况与硬件来源明细 | | `POST /license/reload` | 重新读取磁盘上的授权文件(不改插件加载状态) | | `POST /license/file` | 导入 `license.lic`:先验签/机器码/有效期,通过才原子替换 | 导入接口**先校验后落盘**:坏文件一律拒绝且不覆盖现有可用授权;通过校验但 白名单含此前未授权的插件时,需**重启网关**才会加载(响应里的 `restart_required` 如实告知)。申请授权时把 `/license/info` 的 `request_code` 发给厂商即可。 ## 目录结构 ```text src/chongming/ ├── __init__.py # 启动入口(serve / granian / gunicorn)与服务器参数转换 └── app/ ├── __init__.py # FastAPI 应用装配(lifespan、中间件、异常处理) ├── core/ # WorkerManager / RouteGenerator / MQTT Bridge / 日志 / 鉴权 / 授权门禁 └── routes/ # 内置管理端点(stats / worker_admin / auth / license) test/ └── test_license_gate.py # 授权门禁测试(自造夹具,直接 python 运行) ``` ## 开发与发布 ```bash # 在 chongming-core 仓库内改代码后,让 venv 用本地源码(联调用) uv pip install -e utils/gateway # 授权门禁测试(自造夹具,可在任意目录直接运行) python test/test_license_gate.py # 发版:构建 wheel 并推私有源 uv build # dist/chongming_gateway--py3-none-any.whl uv run twine upload --repository <私有源> dist/* ``` 发版后依赖方执行 `uv lock --upgrade-package chongming-gateway` 刷新版本 pin。 注意 `uv sync` 会用锁文件版本替换可编辑安装——打包/发版前先确认 venv 指向目标版本。 ## 相关文档 - [项目主 README](../../README.md):整体架构、使用与构建部署 - [Worker 管理与多实例运维](../../docs/worker-management.md):管理端点、扩缩容、实例定向 - [机器码授权指南](../../docs/license.md):密钥管理、签发/激活流程、指纹容错与命令行参考