lingniu-dev dd8f75e0da refactor(gb32960/model): nest InfoBlock by <protocol+version>.<dataType>
Restructure InfoBlock from a flat sealed interface into three nested
sealed interfaces grouped by protocol and version, so every record's
fully-qualified name follows the rule InfoBlock.<protocolVersion>.<dataType>
and the type system enforces strict separation between version variants.

New shape:

  InfoBlock (sealed)
  ├── Gb32960V2016 (sealed)
  │   ├── Vehicle           (20 B, has accel/brake pedal)
  │   ├── DriveMotor        (rpm offset 20000, torque 2 B)
  │   ├── FuelCell          (with N x 1B probe temps)
  │   ├── Engine            (5 B fixed)
  │   ├── Position          (9 B, no coord system)
  │   ├── Extreme           (14 B, 2016-only)
  │   ├── Alarm             (typeCode 0x07, no general alarm levels)
  │   ├── Voltage           (0x08 storage voltage)
  │   └── Temperature       (0x09 storage temperature)
  ├── Gb32960V2025 (sealed)
  │   ├── Vehicle           (18 B, no pedal fields)
  │   ├── DriveMotor        (rpm offset 32000, torque 4 B)
  │   ├── FuelCell          (no current/voltage, no probe list)
  │   ├── Engine            (5 B fixed, identical layout to V2016 but
  │                          duplicated to keep version separation strict)
  │   ├── Position          (10 B, with coordSystem byte)
  │   ├── Alarm             (typeCode 0x06, with generalAlarmLevels)
  │   ├── MinParallelVoltage (0x07 in V2025)
  │   ├── BatteryTemperature (0x08 in V2025)
  │   ├── FuelCellStack     (0x30)
  │   ├── SuperCapacitor    (0x31)
  │   └── SuperCapacitorExtreme (0x32)
  ├── GuangdongFc (sealed)
  │   ├── Stack             (0x30, vendor variant — different field order
  │                          and adds max/min/avg single-cell voltage stats)
  │   ├── Auxiliary         (0x31, air compressor / hydrogen pump / PTC)
  │   ├── DcDc              (0x32 fixed 9 B)
  │   ├── AirConditioner    (0x33 fixed 5 B)
  │   ├── VehicleInfo       (0x34 fixed 7 B)
  │   └── DemoExtension     (0x80 demo extension)
  └── Raw

Even types that share an identical field list (Engine, the two
DriveMotor.Motor inner records, Vehicle when ignoring pedals) are
deliberately duplicated rather than shared, per the rule "数据类型严格按
版本拆分". This lets consumers branch on instanceof / pattern-match
without losing track of which protocol version produced the data.

Knock-on changes (mechanical for the most part):

- All 16 standard parsers (v2016/, v2025/) updated to instantiate the
  matching nested record; e.g.
    new InfoBlock.Vehicle(...)
  becomes
    new InfoBlock.Gb32960V2016.Vehicle(...).
- The 6 Guangdong vendor parsers now return InfoBlock.GuangdongFc.* records
  (previously InfoBlock.GdFcXxx flat records).
- Position/Alarm record pairs split: Position no longer carries a nullable
  coordSystem field (V2025 has its own record with coordSystem; V2016
  has neither), and Alarm no longer carries the protocolVersion tag —
  the nested type already encodes the version.
- Gb32960EventMapper grew three small private "view" records
  (VehicleView, PositionView, AlarmView) plus extract* helpers that try
  V2016 first then fall back to V2025, so downstream payload assembly
  still sees a single uniform view.
- Test files updated to reference the new fully-qualified names.

InfoBlockType enum is left untouched: it is the logical type tag, and
both DriveMotor variants still report InfoBlockType.DRIVE_MOTOR even
though they live under different sealed parents — the *structural*
separation is what matters.

All 30 tests pass (18 existing + 8 selector + 4 vendor parser).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 16:52:57 +08:00

lingniu-vehicle-ingest

羚牛车辆数据接入平台 v2

设计目标

  • 协议接入统一抽象GB/T 32960、JT/T 808、JT/T 1078、JSATL12、MQTT、信达 Push 全部变成可插拔 Inbound Adapter
  • 原子能力化:每个协议一个独立 Maven 模块 + 独立 AutoConfiguration + 独立配置开关
  • 业务 / 实时彻底解耦:本服务只负责 收 → 解析 → 校验 → 规整 → 投递 Kafka,不碰业务库
  • 高并发低延迟Netty + Disruptor + Java 25 虚拟线程;目标单节点 ≥ 5 万 msg/sP99 < 50 ms
  • 可观测、可回放、可灰度:统一 traceId、Envelope、幂等键、DLQ、原始报文冷存

技术栈

类别 选型
语言 Java 25
框架 Spring Boot 3.4.x
网络 Netty 4.1
并发 Disruptor 4 + 虚拟线程 + StructuredTaskScope
消息队列 Kafkavin 分区,保证单车有序)
线上消息格式 Protobuf,调试走 JSON
MQTT 客户端 HiveMQ MQTT Client
会话缓存 Caffeine + Redis 兜底
熔断/限流 Resilience4j 2
可观测 Micrometer + Prometheus + OpenTelemetry
冷存 S3 / OSS / 本地
构建 Maven + Spotless + ArchUnit

模块划分

lingniu-vehicle-ingest/
├── bom/                     依赖版本统一
├── ingest-api/              SPI + sealed 领域事件 + 注解
├── ingest-codec-common/     公共编解码工具BCD/CRC/BCC/bit utils
├── ingest-core/             Pipeline / Dispatcher / Disruptor / Session 桥
├── session-core/            设备会话 + 鉴权 + Token
├── observability/           metrics / tracing / health
├── sink-mq/                 Kafka producer + Protobuf Envelope
├── sink-archive/            原始报文冷存
├── protocol-gb32960/        GB/T 32960
├── protocol-jt808/          JT/T 808
├── protocol-jt1078/         JT/T 1078
├── protocol-jsatl12/        苏标主动安全报警附件
├── inbound-mqtt/            MQTT 接入(宇通等)
├── inbound-xinda-push/      信达 Push 接入(重写)
├── command-gateway/         HTTP → 设备下行命令
└── bootstrap-all/           一体化启动

快速开始

# 要求JDK 25, Maven 3.9+
mvn -v
mvn clean install -DskipTests
cd bootstrap-all && mvn spring-boot:run

迁移说明

本项目是 lingniu-vehicle-data-reception 的 v2 重构,采用 strangler fig 渐进式迁移,旧项目保留只读参考。迁移路径与决策参见 ../REFRACTOR_PLAN.md

核心原则

  1. 本服务不写业务库:历史、行程、在线检测、里程统计全部由 Kafka 下游消费者实现
  2. 协议即插拔:每个 protocol-* / inbound-* 都可独立开关(lingniu.ingest.<name>.enabled
  3. 顺序保证:同一 VIN 严格有序Disruptor hash + Kafka 分区 key
  4. 幂等消费Envelope 带 eventId,下游去重
  5. 原始可回放vehicle.raw.archive topic + 对象存储
Description
No description provided
Readme 129 MiB
Languages
Java 81.7%
Go 12.3%
Python 5.9%