cmvr-es/protos/README.md

5.8 KiB
Raw Blame History

Protobuf 与协议开发指南

protos/ 是 CMVR-ES 配置、gRPC API、共享消息和 QUIC 控制面的契约源。生成代码由 CMake 创建,不应手工编辑或提交。

返回项目总览

目录职责

目录 职责
cmvr/api/ gRPC service 和 command DTO
cmvr/msgs/ 设备、状态和错误等共享消息
cmvr/config/ Proto Text 运行配置 Schema
cmvr/common/ 通用几何等跨领域消息
cmvr/quic_edge/v1/ QUIC reliable control message 和 v1 wire 文档
rbk/ 第三方/兼容协议 Schema

C++ 生成流程

CMakeLists.txt

  1. 递归收集 protos/**/*.proto
  2. 使用 protoc 生成 .pb.h/.pb.cc
  3. 使用 grpc_cpp_plugin 生成 .grpc.pb.h/.grpc.pb.cc
  4. 输出到 build/_protobuf/
  5. 打包为 cmvr_es::proto

build/_protobuf/ 是构建产物,不手改、不提交。

当前使用 file(GLOB_RECURSE ...) 且没有 CONFIGURE_DEPENDS。新增 Proto 文件后必须重新执行 CMake configure

cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMVR_ARCH=x86

cmake --build build -j"$(nproc)"

protocgrpc_cpp_plugin 当前固定从 output/bin/ 使用。干净环境首次构建先执行根 README 的工具引导步骤。

通用兼容规则

已发布协议中禁止:

  • 修改或复用字段号;
  • 修改 enum 数值含义;
  • 修改 oneof tag
  • 修改字段 wire type
  • 修改 gRPC package、service 或 method 全名;
  • 将原本可选的字段改成必填语义;
  • 把同一字段单位从 m 改成 mm 等隐式破坏。

删除字段时同时 reserved 字段号和名称:

message Example {
  reserved 2;
  reserved "old_field";

  string id = 1;
  string new_field = 3;
}

新增字段使用新 tag。需要区分“缺失”和“零值”时使用 proto3 optional,并验证目标语言工具链支持。

破坏性 gRPC 变化应创建版本化 package/service而不是原地改变旧方法。

配置 Proto

配置也必须考虑已部署 .pb.txt

  • 新 scalar 的零值不能自动成为危险默认值;
  • C++ 必须做范围和跨字段校验;
  • enum unknown、oneof 未设置应明确失败;
  • root message 命名保持 XxxRootConfig
  • 字段注释写明单位、范围和安全语义;
  • Schema 变更同步 ../cmvr-es/config/README.md 与样例配置。

TextFormat 使用字段名,因此随意重命名字段同样会破坏旧配置。

gRPC API

推荐一个领域拆分为:

cmvr/api/example_command.proto
cmvr/api/example_service.proto

service 文件 import command 文件。公共 header、错误和时间戳复用 common.proto,不要复制出多个略有差异的定义。

新增 API 后还需要:

  1. 实现 C++ service
  2. 加入 service CMake target
  3. 在 GrpcServerTask 中构造和注册;
  4. 生成 Java client
  5. 增加 handler、reflection 和 grpcurl 测试。

完整流程见 ../cmvr-es/service/README.md

cmvr/api/test_service.proto 当前没有实现或注册,且包含历史拼写 TestReqeust,不要把它作为新 API 模板。

QUIC Edge v1

当前固定契约:

  • packagecmvr.quic_edge.v1
  • protocol_version = 1
  • ALPNcmvr-quic-edge/1
  • reliable streamuint32_be length + EdgeControlEnvelope
  • media DATAGRAM固定 64 字节非 Protobuf header + payload

完整字段和偏移见 cmvr/quic_edge/v1/README.md

破坏 framing、固定头、状态机或时序时必须建立新协议版本、package 和 ALPN不能只修改 Proto。

新增 control envelope payload 时:

  • 使用未占用的新 oneof tag
  • 同步 edge 发送/dispatch 和状态机;
  • 同步 message/session/heartbeat sequence 校验;
  • 同步 Java Gateway
  • 更新 wire 文档;
  • 增加 golden vector 和 fake transport 测试。

Edge 当前入站只实现 RegisterResponse、HeartbeatAck 和 ProtocolError。Proto 中存在的消息不等于两个方向都已实现。

每次 QUIC 连接建立后Edge 的出站 control message_sequence0 重新开始,因此首个 NodeRegisterRequest.message_sequence 当前为 0。Gateway 必须接受该起始值,不能假设从 1 开始;后续只要求同一发送方向严格递增,允许出现间隔。

QUIC stream 与 DATAGRAM 没有跨通道到达顺序保证。Gateway 不能假设 session/descriptor 一定先于媒体到达。

Java 生成

仓库只自动生成 C++。Java 平台应在自己的 Gradle/Maven 工程中锁定:

  • protoc
  • protobuf-java
  • protoc-gen-grpc-java
  • grpc-java

并以 protos/ 作为 import root。

QUIC Gateway 只需普通 Protobuf Java message

output/bin/protoc \
  -I protos \
  --java_out=platform-gateway/src/main/java \
  protos/cmvr/quic_edge/v1/quic_edge.proto

gRPC Java client 还需要 grpc-java plugin。当前 Proto 没有统一 java_packagejava_multiple_files,增加这些 option 时应同步两端生成结果和平台 import。

浏览器不能直接消费自定义 QUIC ALPN不应从这些 Proto 推导“浏览器可直连 Edge”。

Review 与验证

# 重新生成并编译 C++
cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMVR_ARCH=x86
cmake --build build -j"$(nproc)"

# 验证当前自动测试
ctest --test-dir build --output-on-failure

# 验证运行时 reflection
/tmp/grpcurl -plaintext 127.0.0.1:50052 list

评审清单:

  • 新字段只使用新 tag
  • 删除字段同时 reserved number 和 name
  • enum 数值和语义兼容
  • 旧 pb.txt 仍可解析
  • C++ 重新 configure 并生成
  • Java/其他语言生成成功
  • service 已真正注册
  • grpcurl reflection 与预期一致
  • QUIC wire 文档和测试同步更新
  • 破坏性变化采用新版本