Files
soft_bus_edge/README.md

86 lines
6.3 KiB
Markdown
Raw Normal View History

2026-05-13 16:46:07 +08:00
# softbus_edge_agent
独立边缘进程:连接核心 `softbus_daemon`**edgeIngress** TCP 端口,发送 **HELLO**、**DATA_RAWBUS**,以及通过极简 **本地 HTTP**`GET /``GET /ui``POST /propose` 等)触发 **TREE_PROPOSE** 反向同步。
## 目录布局(与 `softbus_daemon` 的 `src/` 对齐)
| 路径 | 说明 |
|------|------|
| `src/device_bus/tree/` | 与核心同源的 `DeviceTreeModel`(本地子树、`TREE_FULL` 落盘加载) |
| `src/device_bus/monitor/` | **udev 串口发现**`EdgeDiscoveryCoordinator`(防抖后组 `TREE_PROPOSE` / `upsert` 向核心注册) |
| `src/device_bus/manager/` | `SerialDeviceManager``CanDeviceManager`(无 Registry / Pipeline`IIngressPort` + 内存池) |
| `src/device_bus/EdgeDeviceBus.*` | 边缘总线编排:加载本地树、**reconcile** 串口与 **SocketCAN** 实例 |
| `src/devices/``src/hardware/` | 与核心同源的 `SerialDevice``SerialQtDriver` 等 |
| `src/message_bus/ingress/` | `EdgeSession``EdgeUplinkWire``EdgeTcpUplinkPort``RawBusMessage` → SBUP 上行) |
协议与核心侧文档对齐:
- 核心权威说明:[softbus_daemon/docs/EDGE_UPLINK_PROTOCOL_v1.md](../softbus_daemon/docs/EDGE_UPLINK_PROTOCOL_v1.md)(若仓库路径不同请自行调整相对链接)。
## 构建
```bash
cmake -S . -B build -DCMAKE_PREFIX_PATH=/path/to/Qt/6.x/gcc_64
cmake --build build
./build/bin/softbus_edge_agent config/edge_manifest.example.json
```
依赖 **Qt6 Core、Network、SerialPort**;若 Qt 安装包含 **SerialBus** 模块CMake 会自动检测并链接,从而在边缘启用 **SocketCAN reconcile**(设备树 `can:...` 节点。未安装时仍可完整构建CAN 节点将被忽略。
## 配置 `edge_manifest.json`(可选)
若默认路径 **`config/edge_manifest.json`** 不存在、或传入的 manifest 路径无法打开、或 JSON 非法,进程会使用**内置默认值**启动(等价于示例 manifest 的字段),并在日志中提示。
仍可通过命令行指定路径覆盖默认文件位置:
```text
./build/bin/softbus_edge_agent /path/to/edge_manifest.json
```
见 [config/edge_manifest.schema.json](config/edge_manifest.schema.json) 与示例 [config/edge_manifest.example.json](config/edge_manifest.example.json)。
要点:
- **`coreHost` / `corePort`**:与 `daemon_config.json``edgeIngress` 一致。
- **`edgeId`**HELLO 与会话绑定;`TREE_PROPOSE` 必须相同。
- **`edgeDiscoveryEnabled`**bool默认 `true`):在 TCP 连接且 **HELLO 成功** 后启动 udev 发现协调器,将串口以 `op: upsert` 写入核心设备树(需 Linux + `libudev`)。设为 `false` 可仅依赖手工 `TREE_PROPOSE` 或核心下发树。
- **`endpoint`**:用于计算 `endpointHash`(与核心一致:`qHash(endpoint)` 即 Qt 默认字符串哈希)。
- **`fakeDeviceId`**:组装 `routingKey = (endpointHash << 32) | deviceId` 与核心 `makeRoutingKey` 一致。
- **`fakeIntervalMs`**:设为 `0` 可关闭假数据定时器;**真实串口**由核心下发的设备树节点驱动(`type`/`endpoint` 可识别为 Serial`params.online` 为 true。节点 `params.deviceId` 会写入上行 `RawBusMessage::deviceId`(未设则 `-1`)。
## 运维 HTTP
`opsListenPort > 0`,监听 `127.0.0.1:opsListenPort`
- `GET /`:返回 `localTreePath` 文件内容(无文件则返回占位 HTML含指向配置页的链接
- **`GET /ui`****阶段 5** 简易配置页——从 **`GET /discovered`** 同源列表选择已发现串口节点,填写 `params.protocol`(如 `modbus_rtu`)、波特率等,提交后由边缘组装 **`op: upsert`** 的 `TREE_PROPOSE` 发往核心(使用当前会话的 **`baseTreeRevision`**,须已 HELLO 且收到过 `TREE_RESULT`)。
- **`POST /register_discovered`**:可由浏览器表单(`application/x-www-form-urlencoded`)或 **JSON** 调用;字段含 `nodeId`(必填,一般为 `edges/<edgeId>/discovered/<stableKey>`)、`devnode`(可选,若不在发现列表中需填 `/dev/tty…`)、`protocol``baudRate``name`。表单提交成功返回简短 **HTML** 确认页JSON 请求返回 `{"accepted":true,"sentNodeId":...}`。若尚未拿到有效 `treeRevision`,返回 **503**
- **`GET /discovered`**:返回最近 udev 发现事件 JSON`{ "items": [ ... ] }`),便于无核心时调试;与 `EdgeDiscoveryCoordinator` 内存环缓冲一致(最多约 64 条)。
- `POST /propose`body 为 **完整** `CTRL_TREE_PROPOSE` JSON`edgeId``baseTreeRevision``entries`),将原样经 TCP 发往核心。
示例:
```bash
curl -s http://127.0.0.1:9080/
curl -s http://127.0.0.1:9080/ui
curl -s http://127.0.0.1:9080/discovered
curl -s -X POST http://127.0.0.1:9080/register_discovered \
-H 'Content-Type: application/json' \
-d '{"nodeId":"edges/edge-dev-1/discovered/12345","protocol":"modbus_rtu","baudRate":115200}'
curl -s -X POST http://127.0.0.1:9080/propose \
-H 'Content-Type: application/json' \
-d '{"edgeId":"edge-dev-1","baseTreeRevision":1,"entries":[{"id":"edges/edge-dev-1/gw","patch":{"name":"gw"}}]}'
```
`entries` 中节点 id 必须满足核心 `DeviceTreeModel::nodeBelongsToEdge` 规则。)
## 本地树文件
`TREE_FULL` 落盘格式为 `{ "treeRevision", "edgeId", "tree": [ ... ] }`。**`EdgeDeviceBus`** 会将其中的 `tree` 当作 `device_tree` 加载,并对 **Serial****CAN**`endpoint` 形如 `can:vcan0``type`/`endpoint` 推断为 CAN执行 **reconcile**:打开设备后读到的数据经 `EdgeTcpUplinkPort` 编码为 `DATA_RAWBUS` 发往核心。与核心真源同步仍通过 **TREE_PROPOSE**(含边缘 **`upsert`** 自动注册)、核心侧 D-Bus `patch_device_tree_node` 或运维 **`push_edge_tree`**。
### 发现 → 注册流程(简要)
1. 边缘连接核心并 **HELLO**;核心下发 **`TREE_FULL`**,本地落盘并 reconcile 已有节点。
2. `edgeDiscoveryEnabled` 为真时,`EdgeDiscoveryCoordinator` 扫描/监听 udev 串口 **add/remove**,在拿到有效 **`baseTreeRevision`**(来自 `TREE_RESULT`)后发送 **`TREE_PROPOSE`**`op: upsert` 注册 `edges/<edgeId>/discovered/<stableKey>`remove 时 **`patch`** `params.online: false`
3. 核心 `applyEdgePropose` 成功后再次 **`TREE_FULL`**;边缘 reload 树文件后对 **Serial/CAN** 执行 reconcile**raw 仅上行**。