rows) {
- }
- }
}
diff --git a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/event/VehicleEvent.java b/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/event/VehicleEvent.java
index 26bdaf88..d6ee000e 100644
--- a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/event/VehicleEvent.java
+++ b/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/event/VehicleEvent.java
@@ -144,8 +144,8 @@ public sealed interface VehicleEvent
* 原始报文归档事件:每条成功解码的入站帧由 Dispatcher 产出一条,携带原始字节和归档索引信息。
* 32960 历史全字段查询依赖它对应的 {@code archive://...} 文件能够被回读。
*
- * 当前 {@code KafkaEventSink} 默认不发送本类型,{@code EventFileStoreSink} 只保存索引不保存
- * bytes;因此启用新 raw 落盘/转发实现时,必须同时保证 {@link RawArchiveKeys} 的 key 规则一致。
+ *
当前 {@code KafkaEventSink} 会发送本类型的索引信息,RAW bytes 由 archive 落盘保存;
+ * 因此启用 raw 落盘/转发实现时,必须同时保证 {@link RawArchiveKeys} 的 key 规则一致。
*
* @param command 协议主命令码(如 32960 0x02/0x03 等),冗余在事件里便于按命令分片归档
* @param infoType 协议子类型(可为 0),同上
diff --git a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileQuery.java b/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileQuery.java
deleted file mode 100644
index 71233eb2..00000000
--- a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileQuery.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.lingniu.ingest.api.history;
-
-import com.lingniu.ingest.api.ProtocolId;
-
-import java.time.Instant;
-import java.time.LocalDate;
-
-/**
- * Query criteria for the optional file-backed historical event index.
- */
-public record EventFileQuery(
- ProtocolId protocol,
- LocalDate dateFrom,
- LocalDate dateTo,
- Instant eventTimeFrom,
- Instant eventTimeTo,
- Order order,
- int limit,
- String vin,
- String eventType,
- Instant cursorEventTime,
- Instant cursorIngestTime,
- String cursorEventId
-) {
- public enum Order {
- ASC,
- DESC
- }
-
- public EventFileQuery {
- if (protocol == null) {
- throw new IllegalArgumentException("protocol must not be null");
- }
- if (dateFrom == null || dateTo == null) {
- throw new IllegalArgumentException("date range must not be null");
- }
- if (dateTo.isBefore(dateFrom)) {
- throw new IllegalArgumentException("dateTo must not be before dateFrom");
- }
- if (eventTimeFrom != null && eventTimeTo != null && eventTimeTo.isBefore(eventTimeFrom)) {
- throw new IllegalArgumentException("eventTimeTo must not be before eventTimeFrom");
- }
- order = order == null ? Order.ASC : order;
- limit = limit <= 0 ? 100 : limit;
- vin = vin == null || vin.isBlank() ? null : vin.trim();
- eventType = eventType == null || eventType.isBlank() ? null : eventType.trim();
- cursorEventId = cursorEventId == null || cursorEventId.isBlank() ? null : cursorEventId.trim();
- if ((cursorEventTime == null || cursorIngestTime == null || cursorEventId == null)
- && !(cursorEventTime == null && cursorIngestTime == null && cursorEventId == null)) {
- throw new IllegalArgumentException("cursor eventTime, ingestTime and eventId must be provided together");
- }
- }
-
- public EventFileQuery(ProtocolId protocol,
- LocalDate dateFrom,
- LocalDate dateTo,
- Instant eventTimeFrom,
- Instant eventTimeTo,
- Order order,
- int limit,
- String vin,
- String eventType) {
- this(protocol, dateFrom, dateTo, eventTimeFrom, eventTimeTo, order, limit,
- vin, eventType, null, null, null);
- }
-
- public EventFileQuery(ProtocolId protocol,
- LocalDate dateFrom,
- LocalDate dateTo,
- Order order,
- int limit,
- String vin,
- String eventType) {
- this(protocol, dateFrom, dateTo, null, null, order, limit, vin, eventType);
- }
-
- public EventFileQuery(ProtocolId protocol,
- LocalDate dateFrom,
- LocalDate dateTo,
- Order order,
- int limit) {
- this(protocol, dateFrom, dateTo, order, limit, null, null);
- }
-
- public EventFileQuery(ProtocolId protocol,
- LocalDate dateFrom,
- LocalDate dateTo,
- Order order,
- int limit,
- String vin) {
- this(protocol, dateFrom, dateTo, order, limit, vin, null);
- }
-}
diff --git a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileRecord.java b/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileRecord.java
deleted file mode 100644
index 1f93cf64..00000000
--- a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileRecord.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.lingniu.ingest.api.history;
-
-import com.lingniu.ingest.api.ProtocolId;
-
-import java.time.Instant;
-import java.util.Map;
-
-/**
- * Minimal historical event record shared by optional compatibility stores and history queries.
- */
-public record EventFileRecord(
- String eventId,
- ProtocolId protocol,
- String eventType,
- String vin,
- Instant eventTime,
- Instant ingestTime,
- String rawArchiveUri,
- Map metadata,
- String payloadJson
-) {
- public EventFileRecord {
- if (eventId == null || eventId.isBlank()) {
- throw new IllegalArgumentException("eventId must not be blank");
- }
- if (protocol == null) {
- throw new IllegalArgumentException("protocol must not be null");
- }
- if (eventTime == null) {
- throw new IllegalArgumentException("eventTime must not be null");
- }
- if (ingestTime == null) {
- throw new IllegalArgumentException("ingestTime must not be null");
- }
- eventType = eventType == null ? "" : eventType;
- vin = vin == null ? "" : vin;
- rawArchiveUri = rawArchiveUri == null ? "" : rawArchiveUri;
- metadata = metadata == null ? Map.of() : Map.copyOf(metadata);
- payloadJson = payloadJson == null || payloadJson.isBlank() ? "{}" : payloadJson;
- }
-}
diff --git a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileStore.java b/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileStore.java
deleted file mode 100644
index 4864d1c8..00000000
--- a/modules/core/ingest-api/src/main/java/com/lingniu/ingest/api/history/EventFileStore.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.lingniu.ingest.api.history;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Historical event index contract.
- *
- * The default production history path uses TDengine directly. This contract remains in core so
- * optional compatibility implementations can still plug into query code without pulling their
- * storage engines into the default reactor.
- */
-public interface EventFileStore {
-
- default void append(EventFileRecord record) throws IOException {
- appendAll(List.of(record));
- }
-
- void appendAll(List records) throws IOException;
-
- List query(EventFileQuery query) throws IOException;
-
- default EventFileRecord findByRawArchiveUri(String rawArchiveUri) throws IOException {
- return null;
- }
-}
diff --git a/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryController.java b/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryController.java
deleted file mode 100644
index 6ff8f016..00000000
--- a/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryController.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.lingniu.ingest.eventhistory;
-
-import com.lingniu.ingest.api.ProtocolId;
-import com.lingniu.ingest.api.history.EventFileQuery;
-import com.lingniu.ingest.api.history.EventFileRecord;
-import com.lingniu.ingest.api.history.EventFileStore;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.IOException;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.OffsetDateTime;
-import java.time.ZoneId;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 通用历史事件查询接口。
- *
- * 这是跨协议的低层记录查询,返回的是 EventFileStore 中的 envelope/snapshot 记录。
- * GB32960 业务查询应优先使用 {@link Gb32960FrameController},因为它会回读 RAW 并按协议展开全部字段。
- */
-@RestController
-@ConditionalOnProperty(prefix = "lingniu.ingest.event-history", name = "enabled", havingValue = "true")
-@ConditionalOnBean(EventFileStore.class)
-@RequestMapping("/api/event-history")
-public class EventHistoryController {
-
- private static final ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");
-
- private final EventFileStore store;
-
- public EventHistoryController(EventFileStore store) {
- this.store = store;
- }
-
- @GetMapping("/records")
- public List query(
- @RequestParam ProtocolId protocol,
- @RequestParam String dateFrom,
- @RequestParam String dateTo,
- @RequestParam(defaultValue = "ASC") EventFileQuery.Order order,
- @RequestParam(defaultValue = "100") int limit,
- @RequestParam(required = false) String vin,
- @RequestParam(required = false) String eventType,
- @RequestParam(required = false) String cursorEventTime,
- @RequestParam(required = false) String cursorIngestTime,
- @RequestParam(required = false) String cursorEventId) throws IOException {
- return queryRecords(protocol, dateFrom, dateTo, order, limit, vin, eventType,
- cursorEventTime, cursorIngestTime, cursorEventId).stream()
- .map(RecordResponse::from)
- .toList();
- }
-
- private List queryRecords(ProtocolId protocol,
- String dateFrom,
- String dateTo,
- EventFileQuery.Order order,
- int limit,
- String vin,
- String eventType,
- String cursorEventTime,
- String cursorIngestTime,
- String cursorEventId) throws IOException {
- QueryTimeRange range = QueryTimeRange.parse(dateFrom, dateTo);
- return store.query(new EventFileQuery(
- protocol,
- range.dateFrom(),
- range.dateTo(),
- range.eventTimeFrom(),
- range.eventTimeTo(),
- order,
- limit,
- vin,
- eventType,
- instantParam(cursorEventTime),
- instantParam(cursorIngestTime),
- cursorEventId));
- }
-
- private static Instant instantParam(String raw) {
- if (raw == null || raw.isBlank()) {
- return null;
- }
- String value = raw.trim();
- try {
- return OffsetDateTime.parse(value).toInstant();
- } catch (RuntimeException ignored) {
- return LocalDateTime.parse(value).atZone(DEFAULT_ZONE).toInstant();
- }
- }
-
- public record RecordResponse(
- String eventId,
- ProtocolId protocol,
- String eventType,
- String vin,
- String eventTime,
- String ingestTime,
- String rawArchiveUri,
- Map metadata,
- String payloadJson) {
-
- private static RecordResponse from(EventFileRecord record) {
- return new RecordResponse(
- record.eventId(),
- record.protocol(),
- record.eventType(),
- record.vin(),
- record.eventTime().toString(),
- record.ingestTime().toString(),
- record.rawArchiveUri(),
- record.metadata(),
- record.payloadJson());
- }
- }
-}
diff --git a/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryEnvelopeIngestor.java b/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryEnvelopeIngestor.java
index 00ac451f..c3ca06d8 100644
--- a/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryEnvelopeIngestor.java
+++ b/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/EventHistoryEnvelopeIngestor.java
@@ -3,8 +3,6 @@ package com.lingniu.ingest.eventhistory;
import com.google.protobuf.InvalidProtocolBufferException;
import com.lingniu.ingest.api.consumer.EnvelopeBatchIngestor;
import com.lingniu.ingest.api.consumer.EnvelopeIngestResult;
-import com.lingniu.ingest.api.history.EventFileRecord;
-import com.lingniu.ingest.api.history.EventFileStore;
import com.lingniu.ingest.sink.kafka.proto.VehicleEnvelope;
import com.lingniu.ingest.tdenginehistory.TdengineEnvelopeRows;
import com.lingniu.ingest.tdenginehistory.TdengineHistoryWriter;
@@ -16,8 +14,7 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Consumer-side entry point that stores one Kafka envelope value into the
- * historical detail file store.
+ * Consumer-side entry point that stores Kafka envelope values into TDengine history tables.
*
* 当前 32960 本机运行配置没有启用 Kafka consumer;这个类保留给“其他服务把 envelope
* 写回历史库”的解耦部署方式。失败时返回结构化结果,由 Kafka worker 决定是否进 DLQ。
@@ -26,62 +23,24 @@ public final class EventHistoryEnvelopeIngestor implements EnvelopeBatchIngestor
private static final Logger log = LoggerFactory.getLogger(EventHistoryEnvelopeIngestor.class);
- private final EventFileStore store;
- private final TelemetryEnvelopeRecordMapper mapper;
private final TdengineHistoryWriter tdengineWriter;
private final boolean telemetryFieldsEnabled;
- public EventHistoryEnvelopeIngestor(EventFileStore store, TelemetryEnvelopeRecordMapper mapper) {
- this(store, mapper, null);
- }
-
public EventHistoryEnvelopeIngestor(TdengineHistoryWriter tdengineWriter) {
this(tdengineWriter, false);
}
public EventHistoryEnvelopeIngestor(TdengineHistoryWriter tdengineWriter,
boolean telemetryFieldsEnabled) {
- this(null, null, tdengineWriter, false, telemetryFieldsEnabled);
- }
-
- public EventHistoryEnvelopeIngestor(EventFileStore store,
- TelemetryEnvelopeRecordMapper mapper,
- TdengineHistoryWriter tdengineWriter) {
- this(store, mapper, tdengineWriter, true, false);
- }
-
- public EventHistoryEnvelopeIngestor(EventFileStore store,
- TelemetryEnvelopeRecordMapper mapper,
- TdengineHistoryWriter tdengineWriter,
- boolean telemetryFieldsEnabled) {
- this(store, mapper, tdengineWriter, true, telemetryFieldsEnabled);
- }
-
- private EventHistoryEnvelopeIngestor(EventFileStore store,
- TelemetryEnvelopeRecordMapper mapper,
- TdengineHistoryWriter tdengineWriter,
- boolean requireStore,
- boolean telemetryFieldsEnabled) {
- if (store == null) {
- if (requireStore) {
- throw new IllegalArgumentException("store must not be null");
- }
+ if (tdengineWriter == null) {
+ throw new IllegalArgumentException("tdengineWriter must not be null");
}
- if (store != null && mapper == null) {
- throw new IllegalArgumentException("mapper must not be null");
- }
- this.store = store;
- this.mapper = mapper;
this.tdengineWriter = tdengineWriter;
this.telemetryFieldsEnabled = telemetryFieldsEnabled;
}
public void ingest(byte[] kafkaValue) throws IOException {
VehicleEnvelope envelope = parse(kafkaValue);
- if (store != null) {
- EventFileRecord record = mapper.toRecord(envelope);
- store.append(record);
- }
writeTdengineFacts(List.of(envelope));
}
@@ -101,9 +60,8 @@ public final class EventHistoryEnvelopeIngestor implements EnvelopeBatchIngestor
VehicleEnvelope envelope = null;
try {
envelope = parse(kafkaValue);
- EventFileRecord record = store == null ? null : mapper.toRecord(envelope);
results.add(null);
- valid.add(new BatchEntry(results.size() - 1, envelope, record));
+ valid.add(new BatchEntry(results.size() - 1, envelope));
} catch (IllegalArgumentException ex) {
results.add(envelope == null
? EnvelopeIngestResult.invalid(ex.getMessage())
@@ -114,9 +72,6 @@ public final class EventHistoryEnvelopeIngestor implements EnvelopeBatchIngestor
return List.copyOf(results);
}
try {
- if (store != null) {
- store.appendAll(valid.stream().map(BatchEntry::record).toList());
- }
writeTdengineFacts(valid.stream().map(BatchEntry::envelope).toList());
for (BatchEntry entry : valid) {
results.set(entry.index(), EnvelopeIngestResult.stored(
@@ -124,7 +79,7 @@ public final class EventHistoryEnvelopeIngestor implements EnvelopeBatchIngestor
entry.vin()));
}
} catch (IOException ex) {
- log.error("event history TDengine/file-store ingest failed batchSize={} validSize={} firstEventId={} firstVin={}",
+ log.error("event history TDengine ingest failed batchSize={} validSize={} firstEventId={} firstVin={}",
kafkaValues.size(),
valid.size(),
valid.getFirst().envelope().getEventId(),
@@ -140,13 +95,13 @@ public final class EventHistoryEnvelopeIngestor implements EnvelopeBatchIngestor
return List.copyOf(results);
}
- private record BatchEntry(int index, VehicleEnvelope envelope, EventFileRecord record) {
+ private record BatchEntry(int index, VehicleEnvelope envelope) {
private String eventId() {
- return record == null ? envelope.getEventId() : record.eventId();
+ return envelope.getEventId();
}
private String vin() {
- return record == null ? envelope.getVin() : record.vin();
+ return envelope.getVin();
}
}
@@ -162,9 +117,6 @@ public final class EventHistoryEnvelopeIngestor implements EnvelopeBatchIngestor
}
private void writeTdengineFacts(List envelopes) throws IOException {
- if (tdengineWriter == null) {
- return;
- }
var rawFrames = envelopes.stream()
.flatMap(envelope -> TdengineEnvelopeRows.rawFrame(envelope).stream())
.toList();
diff --git a/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/Gb32960DecodedFrameService.java b/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/Gb32960DecodedFrameService.java
index 77370116..562f21db 100644
--- a/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/Gb32960DecodedFrameService.java
+++ b/modules/services/event-history-service/src/main/java/com/lingniu/ingest/eventhistory/Gb32960DecodedFrameService.java
@@ -2,10 +2,6 @@ package com.lingniu.ingest.eventhistory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.lingniu.ingest.api.ProtocolId;
-import com.lingniu.ingest.api.history.EventFileQuery;
-import com.lingniu.ingest.api.history.EventFileRecord;
-import com.lingniu.ingest.api.history.EventFileStore;
import com.lingniu.ingest.protocol.gb32960.codec.Gb32960MessageDecoder;
import com.lingniu.ingest.protocol.gb32960.model.Gb32960Message;
import com.lingniu.ingest.protocol.gb32960.model.InfoBlock;
@@ -38,8 +34,8 @@ import java.util.Map;
/**
* GB32960 RAW 历史帧查询和业务快照组装服务。
*
- * 历史库里保存的是 RAW_ARCHIVE 索引,不保存完整解码后的宽表。查询时先从
- * {@link EventFileStore} 找到 archive:// URI,再读取本地 RAW .bin,用当前协议解析器即时解码。
+ *
TDengine raw_frames 保存 archive:// URI。查询时先从 TDengine 找到 RAW 索引,
+ * 再读取本地 RAW .bin,用当前协议解析器即时解码。
* 这种设计让写入路径保持轻量,也允许后续修复解析器后直接重放历史 RAW 得到新字段。
*
*
snapshot 的聚合单位是 {@code vin + eventTime}。同一时刻可能有多个 32960 子包,
@@ -50,37 +46,20 @@ public final class Gb32960DecodedFrameService {
private static final Logger log = LoggerFactory.getLogger(Gb32960DecodedFrameService.class);
private static final TypeReference