feat(api): add VehicleEvent.RawArchive sealed variant for raw cold-storage
新增 VehicleEvent.RawArchive 事件类型,承载一帧入站的原始字节,供 ArchiveEventSink 写冷存、后续迭代可回放。携带 command / infoType / rawBytes 三个字段,VIN 与 timestamps 沿用基接口约定。 同步更新两处穷尽 switch: - TopicRouter.route:RawArchive → topics.getRawArchive()(未来 Kafka 需要时会用到) - EnvelopeMapper.toEnvelope:只填 RawArchiveRef.size_bytes,payload oneof 留空 本期 Kafka sink 不处理 raw archive——KafkaEventSink.accepts(RawArchive) 返回 false, 原始字节只落 ArchiveStore,避免 Kafka 消息体被原始报文撑大。未来若接 URI 回填 (archive 写成功后把 URI 放进 Envelope.raw_archive 送 vehicle.raw.archive topic), 再放开过滤。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,8 @@ public sealed interface VehicleEvent
|
|||||||
VehicleEvent.Logout,
|
VehicleEvent.Logout,
|
||||||
VehicleEvent.Heartbeat,
|
VehicleEvent.Heartbeat,
|
||||||
VehicleEvent.MediaMeta,
|
VehicleEvent.MediaMeta,
|
||||||
VehicleEvent.Passthrough {
|
VehicleEvent.Passthrough,
|
||||||
|
VehicleEvent.RawArchive {
|
||||||
|
|
||||||
String eventId();
|
String eventId();
|
||||||
String vin();
|
String vin();
|
||||||
@@ -138,4 +139,28 @@ public sealed interface VehicleEvent
|
|||||||
int passthroughType,
|
int passthroughType,
|
||||||
byte[] data
|
byte[] data
|
||||||
) implements VehicleEvent {}
|
) implements VehicleEvent {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始报文冷存事件:每条成功解码的入站帧由 Dispatcher 产出一条,携带原始字节交
|
||||||
|
* {@code ArchiveEventSink} 写入 ArchiveStore。Kafka sink 默认不处理本类型
|
||||||
|
* (见 {@code KafkaEventSink.accepts})。
|
||||||
|
*
|
||||||
|
* <p>key 组装建议:{@code yyyy/MM/dd/<source>/<vin>/<eventId>.bin},具体由 sink 实现决定。
|
||||||
|
*
|
||||||
|
* @param command 协议主命令码(如 32960 0x02/0x03 等),冗余在事件里便于按命令分片归档
|
||||||
|
* @param infoType 协议子类型(可为 0),同上
|
||||||
|
* @param rawBytes 原始入站字节,不可为 null
|
||||||
|
*/
|
||||||
|
record RawArchive(
|
||||||
|
String eventId,
|
||||||
|
String vin,
|
||||||
|
ProtocolId source,
|
||||||
|
Instant eventTime,
|
||||||
|
Instant ingestTime,
|
||||||
|
String traceId,
|
||||||
|
Map<String, String> metadata,
|
||||||
|
int command,
|
||||||
|
int infoType,
|
||||||
|
byte[] rawBytes
|
||||||
|
) implements VehicleEvent {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,15 @@ public final class EnvelopeMapper {
|
|||||||
.setData(com.google.protobuf.ByteString.copyFrom(
|
.setData(com.google.protobuf.ByteString.copyFrom(
|
||||||
p.data() == null ? new byte[0] : p.data()))
|
p.data() == null ? new byte[0] : p.data()))
|
||||||
.build());
|
.build());
|
||||||
|
case VehicleEvent.RawArchive ra -> {
|
||||||
|
// RawArchive 原则上由 ArchiveEventSink 独占消费,本分支仅在有人显式把它送到
|
||||||
|
// Kafka 时生效:不设 payload oneof,只填 raw_archive ref 里的 size_bytes,
|
||||||
|
// 下游如需真正拉取字节要依赖 archive 写成功后回填的 URI(后续迭代)。
|
||||||
|
int size = ra.rawBytes() == null ? 0 : ra.rawBytes().length;
|
||||||
|
b.setRawArchive(com.lingniu.ingest.sink.mq.proto.RawArchiveRef.newBuilder()
|
||||||
|
.setSizeBytes(size)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return b.build();
|
return b.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,16 @@ public final class KafkaEventSink implements EventSink, AutoCloseable {
|
|||||||
return "kafka";
|
return "kafka";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拒绝 {@link VehicleEvent.RawArchive} —— 原始报文体积大、属于冷存域,本期由
|
||||||
|
* {@code ArchiveEventSink} 独占处理。未来若需要将 raw archive URI 回填到 Kafka 的
|
||||||
|
* {@code vehicle.raw.archive} topic,再放开此过滤并在 Envelope 里填 uri/checksum。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean accepts(VehicleEvent event) {
|
||||||
|
return !(event instanceof VehicleEvent.RawArchive);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> publish(VehicleEvent event) {
|
public CompletableFuture<Void> publish(VehicleEvent event) {
|
||||||
CompletableFuture<Void> cf = new CompletableFuture<>();
|
CompletableFuture<Void> cf = new CompletableFuture<>();
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public final class TopicRouter {
|
|||||||
VehicleEvent.Heartbeat _ -> topics.getSession();
|
VehicleEvent.Heartbeat _ -> topics.getSession();
|
||||||
case VehicleEvent.MediaMeta _ -> topics.getMediaMeta();
|
case VehicleEvent.MediaMeta _ -> topics.getMediaMeta();
|
||||||
case VehicleEvent.Passthrough _ -> topics.getAlarm();
|
case VehicleEvent.Passthrough _ -> topics.getAlarm();
|
||||||
|
case VehicleEvent.RawArchive _ -> topics.getRawArchive();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user