新建 erp-health 原生 Rust crate,覆盖设计规格中定义的 5 大业务域: - 16 个 SeaORM Entity(患者/家属/标签/医生/健康档案/体征/化验单/预约/排班/随访/咨询等) - 16 表数据库迁移(含索引、外键、默认值、可回滚) - 40+ API 路由骨架(患者管理/健康数据/预约排班/随访/咨询/医生管理) - 12 个权限声明(health.patient/health-data/appointment/follow-up/consultation/doctor 各 .list/.manage) - DTO / Service / Handler / Event 四层架构,Service 使用 todo!() 占位 - erp-server 集成:模块注册 + AppState FromRef 桥接 + 路由挂载 同步更新 CLAUDE.md 项目进度、wiki 知识库、设计规格文档。
126 lines
5.2 KiB
Markdown
126 lines
5.2 KiB
Markdown
---
|
||
title: WASM 插件系统
|
||
updated: 2026-04-23
|
||
status: stable
|
||
tags: [wasm, plugin, wasmtime, wit]
|
||
---
|
||
|
||
# WASM 插件系统
|
||
|
||
> 从 [[index]] 导航。关联: [[erp-core]] [[architecture]] [[erp-server]]
|
||
|
||
## 1. 设计决策
|
||
|
||
### 为什么选 WASM 而非 Lua / gRPC / dylib?
|
||
|
||
| 方案 | 安全性 | 隔离性 | 性能 | 复杂度 |
|
||
|------|--------|--------|------|--------|
|
||
| **WASM** | 高(沙箱) | 进程内隔离 | 接近原生 | 中 |
|
||
| Lua 脚本 | 中 | 无隔离 | 快 | 低 |
|
||
| 进程外 gRPC | 高 | 进程级隔离 | 网络开销 | 高 |
|
||
| dylib | 低 | 无隔离 | 原生 | 低 |
|
||
|
||
核心权衡:WASM 在安全和性能间取得最佳平衡。Wasmtime v43 Component Model 提供类型安全的 Host-Plugin 接口,Fuel 防止无限循环。
|
||
|
||
### 架构拓扑
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ erp-server │
|
||
│ ┌───────────┐ ┌────────────────────────┐ │
|
||
│ │ EventBus │ │ PluginRuntime(Wasmtime) │ │
|
||
│ │(broadcast)│ │ ┌─────┐ ┌─────┐ │ │
|
||
│ └─────┬─────┘ │ │CRM │ │库存 │ │ │
|
||
│ │ │ └──┬──┘ └──┬──┘ │ │
|
||
│ │ │ Host Bridge(自动注入 │ │
|
||
│ │ │ tenant_id+权限检查) │ │
|
||
│ │ └─────┼──────────────────┘ │
|
||
│ ┌─────┴──────┐ │
|
||
│ │ DB(SeaORM) │ │
|
||
│ └────────────┘ │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 原型验证 (V1-V6)
|
||
|
||
全部通过:WIT+bindgen 编译、Host 调用插件、插件回调 Host API、async 实例化、Fuel 限制、动态加载。
|
||
|
||
## 2. 关键文件 + 数据流
|
||
|
||
### 核心文件
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `crates/erp-plugin-prototype/wit/plugin.wit` | WIT 接口定义(Host API + Plugin API) |
|
||
| `crates/erp-plugin-prototype/src/lib.rs` | Host 运行时:Engine/Store/Linker/HostState |
|
||
| `crates/erp-plugin-prototype/tests/test_plugin_integration.rs` | V1-V6 集成测试 |
|
||
|
||
### WIT 接口概要
|
||
|
||
Host 暴露给插件(`host-api`):`db_insert` `db_query` `db_update` `db_delete` `event_publish` `config_get` `log_write` `current_user` `check_permission`
|
||
|
||
插件导出给 Host(`plugin-api`):`init` `on_tenant_created` `handle_event`
|
||
|
||
### 集成契约
|
||
|
||
| 方向 | 模块 | 接口 | 触发时机 |
|
||
|------|------|------|---------|
|
||
| 被调用 ← | [[erp-server]] | `PluginEngine` | 服务启动时恢复插件 |
|
||
| 调用 → | [[erp-core]] | `EventBus` | 桥接领域事件到插件 |
|
||
| 提供 → | 所有插件 | Host API (9 函数) | 插件运行时 |
|
||
|
||
## 3. 代码逻辑
|
||
|
||
### 插件生命周期
|
||
|
||
```
|
||
安装(manifest+WASM) → 注册权限 → 实例化(Wasmtime) → init()
|
||
→ 日常: db_query/db_insert 通过 data_handler 自动注入 tenant_id + 权限校验
|
||
→ 事件: EventBus → handle_event()
|
||
→ 升级: upload 新 WASM → 增量 DDL → 卸载旧实例 → 加载新实例
|
||
```
|
||
|
||
### 权限系统
|
||
|
||
权限码由 `data_handler.rs` 的 `compute_permission_code()` 自动生成:
|
||
|
||
```
|
||
{manifest_id}.{url_entity_name}.{action_suffix}
|
||
例: erp-crm.customer.list / erp-crm.customer.manage
|
||
```
|
||
|
||
⚡ **权限命名铁律**: `plugin.toml` 中 `permissions[].code` 前缀必须与 `schema.entities[].name` 完全一致,每个实体必须声明 `.list` + `.manage`
|
||
|
||
⚡ **Host API 数据约定**: 所有数据参数用 `list<u8>` + JSON 序列化,Host 自动注入 id/tenant_id/timestamp
|
||
|
||
⚡ **同步调用**: bindgen 生成的 `call_init`/`call_handle_event` 是同步的,只有实例化可以 async
|
||
|
||
### 不变量
|
||
|
||
⚡ Fuel 默认 100 万,耗尽时 WASM trap(`wasm trap: interrupt`)
|
||
⚡ `HasSelf<HostState>` 是 Linker 注册的必要类型参数(`Data<'a> = &'a mut HostState`)
|
||
⚡ Core WASM 必须通过 `wasm-tools component new` 转为 Component 格式才能被 Host 加载
|
||
|
||
## 4. 活跃问题 + 陷阱
|
||
|
||
### 历史教训
|
||
|
||
- CRM 权限码 `tag.manage` vs 实体 `customer_tag` → 三个页面 403(迁移 m000038 修复)
|
||
- CRM WASM 二进制错误存储了测试插件而非 CRM 插件(重新编译修复)
|
||
- 权限未自动分配给 admin 角色 → 403(添加 `grant_permissions_to_admin()`)
|
||
|
||
### 注意事项
|
||
|
||
⚠️ 插件 API 路由用 `Path<(Uuid, String)>` 解析 plugin_id,必须用数据库 UUID 而非 manifest_id
|
||
⚠️ 修改 WIT 后需重编译 Host crate 和所有插件
|
||
|
||
## 5. 变更记录
|
||
|
||
| 日期 | 变更 |
|
||
|------|------|
|
||
| 2026-04-23 | 重构为 5 节结构,插件制作流程移至 `.claude/skills/plugin-development/` |
|
||
| 2026-04-19 | CRM 权限码修复 (m000038) |
|
||
| 2026-04-18 | 插件权限系统审计 |
|
||
|
||
> **插件制作完整流程**: 详见 `.claude/skills/plugin-development/SKILL.md`(WIT 接口 → 创建 crate → 编译 WASM → 集成测试)
|