refactor: use stateless identity fallback

This commit is contained in:
lingniu
2026-07-01 02:58:38 +08:00
parent 1ce4f80161
commit 7a245215b8
7 changed files with 111 additions and 12 deletions

View File

@@ -0,0 +1,34 @@
package com.lingniu.ingest.identity;
/**
* Stateless production fallback used when a caller has no injected identity service.
*
* <p>Persistent binding belongs to {@link MySqlVehicleIdentityService}; this resolver only keeps
* ingestion flowing with explicit VIN or stable external identifiers.
*/
public final class StatelessVehicleIdentityResolver implements VehicleIdentityResolver {
@Override
public VehicleIdentity resolve(VehicleIdentityLookup lookup) {
if (lookup == null) {
return unknown();
}
if (!lookup.vin().isBlank()) {
return new VehicleIdentity(lookup.vin(), true, VehicleIdentitySource.EXPLICIT_VIN);
}
if (!lookup.deviceId().isBlank()) {
return new VehicleIdentity(lookup.deviceId(), false, VehicleIdentitySource.FALLBACK_DEVICE_ID);
}
if (!lookup.phone().isBlank()) {
return new VehicleIdentity(lookup.phone(), false, VehicleIdentitySource.FALLBACK_PHONE);
}
if (!lookup.plate().isBlank()) {
return new VehicleIdentity(lookup.plate(), false, VehicleIdentitySource.FALLBACK_PLATE);
}
return unknown();
}
private static VehicleIdentity unknown() {
return new VehicleIdentity("unknown", false, VehicleIdentitySource.UNKNOWN);
}
}

View File

@@ -0,0 +1,57 @@
package com.lingniu.ingest.identity;
import com.lingniu.ingest.api.ProtocolId;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class StatelessVehicleIdentityResolverTest {
private final StatelessVehicleIdentityResolver resolver = new StatelessVehicleIdentityResolver();
@Test
void explicitVinWinsWithoutPersistingAnyBinding() {
VehicleIdentity identity = resolver.resolve(new VehicleIdentityLookup(
ProtocolId.MQTT_YUTONG, "LNVIN000000000001", "13900000000", "DEV001", "粤B12345"));
assertThat(identity.vin()).isEqualTo("LNVIN000000000001");
assertThat(identity.resolved()).isTrue();
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.EXPLICIT_VIN);
}
@Test
void fallsBackToStableExternalIdentifiersWithoutMarkingResolved() {
assertThat(resolver.resolve(new VehicleIdentityLookup(
ProtocolId.JT808, "", "13900000001", "DEV001", "粤B12345")))
.satisfies(identity -> {
assertThat(identity.vin()).isEqualTo("DEV001");
assertThat(identity.resolved()).isFalse();
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_DEVICE_ID);
});
assertThat(resolver.resolve(new VehicleIdentityLookup(
ProtocolId.JT808, "", "13900000001", "", "粤B12345")))
.satisfies(identity -> {
assertThat(identity.vin()).isEqualTo("13900000001");
assertThat(identity.resolved()).isFalse();
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_PHONE);
});
assertThat(resolver.resolve(new VehicleIdentityLookup(
ProtocolId.JT808, "", "", "", "粤B12345")))
.satisfies(identity -> {
assertThat(identity.vin()).isEqualTo("粤B12345");
assertThat(identity.resolved()).isFalse();
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.FALLBACK_PLATE);
});
}
@Test
void returnsUnknownWhenNoIdentitySignalExists() {
VehicleIdentity identity = resolver.resolve(new VehicleIdentityLookup(ProtocolId.JT808, "", "", "", ""));
assertThat(identity.vin()).isEqualTo("unknown");
assertThat(identity.resolved()).isFalse();
assertThat(identity.source()).isEqualTo(VehicleIdentitySource.UNKNOWN);
}
}

View File

@@ -3,7 +3,7 @@ package com.lingniu.ingest.inbound.mqtt.client;
import com.lingniu.ingest.api.ProtocolId; import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.pipeline.RawFrame; import com.lingniu.ingest.api.pipeline.RawFrame;
import com.lingniu.ingest.core.dispatcher.Dispatcher; import com.lingniu.ingest.core.dispatcher.Dispatcher;
import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver;
import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentity;
import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityLookup;
import com.lingniu.ingest.identity.VehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentityResolver;
@@ -53,7 +53,7 @@ public final class MqttEndpointManager implements AutoCloseable {
public MqttEndpointManager(MqttInboundProperties props, public MqttEndpointManager(MqttInboundProperties props,
MqttProfileRegistry profileRegistry, MqttProfileRegistry profileRegistry,
Dispatcher dispatcher) { Dispatcher dispatcher) {
this(props, profileRegistry, new InMemoryVehicleIdentityService(), dispatcher); this(props, profileRegistry, new StatelessVehicleIdentityResolver(), dispatcher);
} }
public MqttEndpointManager(MqttInboundProperties props, public MqttEndpointManager(MqttInboundProperties props,
@@ -62,7 +62,7 @@ public final class MqttEndpointManager implements AutoCloseable {
Dispatcher dispatcher) { Dispatcher dispatcher) {
this.props = props; this.props = props;
this.profileRegistry = profileRegistry; this.profileRegistry = profileRegistry;
this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver;
this.dispatcher = dispatcher; this.dispatcher = dispatcher;
} }

View File

@@ -6,7 +6,7 @@ import com.lingniu.ingest.api.event.LocationPayload;
import com.lingniu.ingest.api.event.RealtimePayload; import com.lingniu.ingest.api.event.RealtimePayload;
import com.lingniu.ingest.api.event.VehicleEvent; import com.lingniu.ingest.api.event.VehicleEvent;
import com.lingniu.ingest.api.spi.EventMapper; import com.lingniu.ingest.api.spi.EventMapper;
import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver;
import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentity;
import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityLookup;
import com.lingniu.ingest.identity.VehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentityResolver;
@@ -31,11 +31,11 @@ public final class YutongEventMapper implements EventMapper<MqttPayload> {
private final VehicleIdentityResolver identityResolver; private final VehicleIdentityResolver identityResolver;
public YutongEventMapper() { public YutongEventMapper() {
this(new InMemoryVehicleIdentityService()); this(new StatelessVehicleIdentityResolver());
} }
public YutongEventMapper(VehicleIdentityResolver identityResolver) { public YutongEventMapper(VehicleIdentityResolver identityResolver) {
this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver;
} }
@Override @Override

View File

@@ -5,7 +5,7 @@ import com.lingniu.ingest.api.annotation.EventEmit;
import com.lingniu.ingest.api.annotation.MessageMapping; import com.lingniu.ingest.api.annotation.MessageMapping;
import com.lingniu.ingest.api.annotation.ProtocolHandler; import com.lingniu.ingest.api.annotation.ProtocolHandler;
import com.lingniu.ingest.api.event.VehicleEvent; import com.lingniu.ingest.api.event.VehicleEvent;
import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver;
import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentity;
import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityLookup;
import com.lingniu.ingest.identity.VehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentityResolver;
@@ -25,11 +25,11 @@ public final class Jt1078MalformedRtpHandler {
private final VehicleIdentityResolver identityResolver; private final VehicleIdentityResolver identityResolver;
public Jt1078MalformedRtpHandler() { public Jt1078MalformedRtpHandler() {
this(new InMemoryVehicleIdentityService()); this(new StatelessVehicleIdentityResolver());
} }
public Jt1078MalformedRtpHandler(VehicleIdentityResolver identityResolver) { public Jt1078MalformedRtpHandler(VehicleIdentityResolver identityResolver) {
this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver;
} }
@MessageMapping(command = Jt1078MediaMessageId.MALFORMED_RTP, desc = "JT1078 RTP 入口坏包兜底") @MessageMapping(command = Jt1078MediaMessageId.MALFORMED_RTP, desc = "JT1078 RTP 入口坏包兜底")

View File

@@ -2,7 +2,7 @@ package com.lingniu.ingest.protocol.jt1078.media;
import com.lingniu.ingest.api.ProtocolId; import com.lingniu.ingest.api.ProtocolId;
import com.lingniu.ingest.api.pipeline.RawFrame; import com.lingniu.ingest.api.pipeline.RawFrame;
import com.lingniu.ingest.identity.InMemoryVehicleIdentityService; import com.lingniu.ingest.identity.StatelessVehicleIdentityResolver;
import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentity;
import com.lingniu.ingest.identity.VehicleIdentityLookup; import com.lingniu.ingest.identity.VehicleIdentityLookup;
import com.lingniu.ingest.identity.VehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentityResolver;
@@ -19,12 +19,12 @@ public final class Jt1078MalformedRtpEventPublisher {
private final Consumer<RawFrame> dispatcher; private final Consumer<RawFrame> dispatcher;
public Jt1078MalformedRtpEventPublisher(Consumer<RawFrame> dispatcher) { public Jt1078MalformedRtpEventPublisher(Consumer<RawFrame> dispatcher) {
this(new InMemoryVehicleIdentityService(), dispatcher); this(new StatelessVehicleIdentityResolver(), dispatcher);
} }
public Jt1078MalformedRtpEventPublisher(VehicleIdentityResolver identityResolver, public Jt1078MalformedRtpEventPublisher(VehicleIdentityResolver identityResolver,
Consumer<RawFrame> dispatcher) { Consumer<RawFrame> dispatcher) {
this.identityResolver = identityResolver == null ? new InMemoryVehicleIdentityService() : identityResolver; this.identityResolver = identityResolver == null ? new StatelessVehicleIdentityResolver() : identityResolver;
this.dispatcher = dispatcher; this.dispatcher = dispatcher;
} }

View File

@@ -5,6 +5,7 @@ import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration;
import com.lingniu.ingest.api.event.VehicleEvent; import com.lingniu.ingest.api.event.VehicleEvent;
import com.lingniu.ingest.api.sink.EventSink; import com.lingniu.ingest.api.sink.EventSink;
import com.lingniu.ingest.identity.VehicleIdentity; import com.lingniu.ingest.identity.VehicleIdentity;
import com.lingniu.ingest.identity.VehicleIdentityRegistry;
import com.lingniu.ingest.identity.VehicleIdentityResolver; import com.lingniu.ingest.identity.VehicleIdentityResolver;
import com.lingniu.ingest.identity.VehicleIdentitySource; import com.lingniu.ingest.identity.VehicleIdentitySource;
import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration; import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration;
@@ -71,6 +72,7 @@ class Jt1078AutoConfigurationTest {
IngestCoreAutoConfiguration.class, IngestCoreAutoConfiguration.class,
SessionCoreAutoConfiguration.class, SessionCoreAutoConfiguration.class,
VehicleIdentityAutoConfiguration.class)) VehicleIdentityAutoConfiguration.class))
.withUserConfiguration(SupportBeans.class)
.withPropertyValues( .withPropertyValues(
"lingniu.ingest.jt1078.enabled=true", "lingniu.ingest.jt1078.enabled=true",
"lingniu.ingest.jt1078.media-stream.enabled=false", "lingniu.ingest.jt1078.media-stream.enabled=false",
@@ -141,6 +143,12 @@ class Jt1078AutoConfigurationTest {
}; };
} }
@Bean
VehicleIdentityRegistry vehicleIdentityRegistry() {
return binding -> {
};
}
@Bean(destroyMethod = "close") @Bean(destroyMethod = "close")
DisruptorEventBus disruptorEventBus(CapturingSink sink) { DisruptorEventBus disruptorEventBus(CapturingSink sink) {
return new DisruptorEventBus(1024, "blocking", List.of(sink)); return new DisruptorEventBus(1024, "blocking", List.of(sink));