modify: rust 插件

This commit is contained in:
2026-08-31 17:18:03 +08:00
commit e59ecfc0e3
22 changed files with 3689 additions and 0 deletions
+126
View File
@@ -0,0 +1,126 @@
# chongming-worker-rs —— 进程插件 Rust SDK
chongming 进程插件线协议([docs/plugin-wire-protocol.md](../../docs/plugin-wire-protocol.md))的 **Rust 参考实现**
(多语言演进规划阶段 1,见 [docs/multi-language-plugin-plan.md](../../docs/multi-language-plugin-plan.md))。
与 Python SDK(`utils/worker/`)行为等价:同一 `<type>` 下可混布部署,网关负载均衡在
两实现间透明分发。**已通过协议级 15/15 与混布对拍 6/6 端到端验证。**
## 模块结构
| 模块 | 职责 | 对位(Python SDK) |
| ---- | ---- | ---- |
| `config.rs` | 全局 config.toml(`[zenoh].json5_path`)+ 插件 `[workers]` 节展平 + mqtt_topics | `process.py: load_plugin_config` |
| `descriptor.rs` | 端点 TOML 解析 → 路由描述符(defaults 合并 / subject / path / route_id) | `route_config.py` + `routes_publisher.py` |
| `envelope.rs` | 请求信封解析(meta.method / user_info / data,非信封载荷按 GET) | `runtime.py` |
| `error.rs` | 非流式错误格式 / 流式 error 收尾块 | `runtime.py` |
| `publisher.rs` | 描述符 PUT / DELETE / 10s 周期重发布 | `routes_publisher.py` |
| `serve.rs` | worker_serve 主流程:liveliness token + Queryable + 信号处理 | `process.py: worker_serve` |
## 插件开发三步
```rust
use chongming_worker_rs::prelude::*;
let mut registry = HandlerRegistry::new();
// 普通端点
registry.register("rsdemo.hello", "GET", |req: Request| async move {
Ok(Reply::Json(json!({"greeting": "Hello!"})))
});
// 流式端点(SSE 逐块)
registry.register("rsdemo.stream", "POST", |req: Request| async move {
let stream = async_stream::stream! {
for i in 0..5 { yield Ok(json!({"index": i})); }
};
Ok(Reply::Stream(Box::pin(stream)))
});
serve::serve("rsdemo", Arc::new(registry), ServeOptions::default()).await?;
```
端点 TOML 定义与 Python 插件共用同一套格式(`config/workers/<type>/*.toml`),
描述符生成规则逐字段对位(`docs/plugin-wire-protocol.md` §2.2)。
## 模型生成(TOML 是唯一事实来源)
请求/响应模型由端点 TOML 的 `params` / `response_model` 声明**自动生成**
(对齐 Python `gen_models`,命名约定一致:`hello` + `GET` → `HelloGetRequest`):
```bash
# 项目根目录
cargo run --bin gen_models -- --types rsdemo,demo --out utils/worker-rs/generated_models.rs
```
生成文件(crate 根 `generated_models.rs`,勿手动修改)每个插件类型一个 mod,
结构体带 serde derive,字段类型映射对齐网关(str/int/float/bool/any/list/dict)。
**一致性保证(比 Python 更强)**:生成文件头部写入 `FINGERPRINT`(端点 TOML 内容 hash)。
插件启动时(`check_models_fingerprint`)重算指纹比对——**TOML 变更而未重新生成模型
即告警并提示重跑 gen_models**,杜绝模型与配置漂移。
```rust
// 插件内使用生成模型(强类型 handler)
let req: generated_models::rsdemo::HelloGetRequest = serde_json::from_value(request.data)?;
let resp = generated_models::rsdemo::HelloGetResponse {
greeting: format!("Hello, {}!", req.name),
worker_id: Some(request.worker_id),
timestamp: now_ts(),
};
```
类型映射规则(对齐网关 `route_generator` 的 TYPE_MAP):
| TOML 声明 | Rust 类型 | 说明 |
| ---- | ---- | ---- |
| `str` | `String` | |
| `int` | `i64` | |
| `float` | `f64` | |
| `bool` | `bool` | |
| `any` | `serde_json::Value` | |
| `list[X]` / `List[X]` | `Vec<X>` | 递归映射 |
| `dict[K,V]` / `Dict[K,V]` | `HashMap<K,V>` | 递归映射 |
| 其他 | `serde_json::Value` | 宽松兜底 |
语义对齐:`params` 全部必填;`response_model` 中 `required = false` 的字段生成
`Option<T>` + `skip_serializing_if`(空值不输出)。
## 本地验证
前置:本地 Zenoh Router(替代 zenohd,`mode=router` 监听 7447):
```bash
.venv/bin/python utils/worker-rs/scripts/zenoh_router.py &
```
协议级端到端验证(路由注册 / RPC / 流式 / 错误 / 摘除 / 自愈,15 项断言):
```bash
cargo build --examples
.venv/bin/python utils/worker-rs/scripts/verify_e2e.py --type rsdemo
```
Python + Rust 同 type 混布对拍(描述符 hash 一致 / 双副本发现 / RPC 等价 / 互不干扰):
```bash
.venv/bin/python utils/worker-rs/scripts/verify_mixed.py
```
参考插件(`examples/demo.rs`)支持两个 type:
```bash
# 项目根目录(config.toml 相对路径)
utils/worker-rs/target/debug/examples/demo --type rsdemo # 独立演示插件
utils/worker-rs/target/debug/examples/demo --type demo # 与 Python demo 混布对拍
```
**独立插件形态**(插件开发者实际使用的方式):`workers/rsdemo/` 是一个完整独立的
插件 crate(path 依赖本 SDK),与 Python 示例 `workers/demo/` 对位,含端点实现、
生成模型与说明文档——建议新插件以此为模板。
## 与 Python SDK 的差异(有意为之)
| 差异 | 说明 |
| ---- | ---- |
| 契约校验 | Python 在 worker 进程内做 TOML↔注册表↔模型三方校验(硬失败退出);Rust 侧降级为**发布前自检**:无 handler 的端点告警并跳过,不发布残缺路由 |
| 模型生成 | Rust 有 gen_models 等价物(`--bin gen_models`):从端点 TOML 生成强类型结构体 + **启动时指纹校验**(TOML 变更未重生成即告警,比 Python 只查模型存在性更强) |
| handler 注入 | worker_id 经 `Request.worker_id` 注入(Python 为函数参数);user_info 经 `Request.user_info` |