From 7ab0e426264707fb85ee38d0a9a73caf41899635 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期六, 29 八月 2026 13:11:40 +0800
Subject: [PATCH] 实现采集器独立实时与历史采样模拟
---
ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDevelopmentSimulator.java | 73 ++++++++++++++++++++++++++++++++++--
1 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDevelopmentSimulator.java b/ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDevelopmentSimulator.java
index c299502..ddac794 100644
--- a/ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDevelopmentSimulator.java
+++ b/ruoyi-device/src/main/java/com/ruoyi/device/bts/BtsDevelopmentSimulator.java
@@ -12,11 +12,18 @@
import com.ruoyi.device.simulator.BtsSimulatorStateStore;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.ChannelTombstone;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorChannelState;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
+import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.DeviceState;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.RecentRequest;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.SimulatorState;
import com.ruoyi.device.simulator.InMemoryBtsSimulatorStateStore;
+import com.ruoyi.device.simulator.DevelopmentCollectorSimulation;
+import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorHistoryPage;
+import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot;
/** 提供由开发后端托管的临时只读 BTS 模拟端点。 */
public final class BtsDevelopmentSimulator implements AutoCloseable
@@ -138,8 +145,7 @@
CollectorState current = requireCollector(collectorId);
List<CollectorState> collectors = new ArrayList<>(state.collectors());
collectors.replaceAll(item -> item.collectorId() == collectorId
- ? new CollectorState(collectorId, current.deviceCode(), ip.trim(), current.mac(), current.name(),
- current.manufacturer(), current.model(), channelCount, online)
+ ? DevelopmentCollectorSimulation.resize(current, ip, channelCount, online, Instant.now())
: item);
persist(new SimulatorState(state.version(), state.devices(), collectors, state.nextDeviceId(),
state.nextCollectorId(), state.tombstones()));
@@ -155,6 +161,45 @@
state.nextCollectorId(), state.tombstones()));
}
+ /** 配置采集器独立采样频率和历史下载故障场景。 */
+ public synchronized void configureCollectorSampling(int collectorId, int sampleIntervalMs,
+ CollectorHistoryFaults historyFaults)
+ {
+ CollectorState current = requireCollector(collectorId);
+ replaceCollector(DevelopmentCollectorSimulation.configureSampling(current, sampleIntervalMs, historyFaults));
+ }
+
+ /** 配置一个稳定 S 通道的固定或动态演示指标。 */
+ public synchronized void configureCollectorChannel(int collectorId, String channelCode,
+ List<CollectorMetricState> metrics)
+ {
+ CollectorState current = requireCollector(collectorId);
+ replaceCollector(DevelopmentCollectorSimulation.configureChannel(current, channelCode, metrics));
+ }
+
+ /** 按每台采集器自己的频率推进实时和历史采样。 */
+ public synchronized void advanceCollectors(Instant now)
+ {
+ List<CollectorState> collectors = state.collectors().stream()
+ .map(collector -> DevelopmentCollectorSimulation.advance(collector, now))
+ .toList();
+ if (!collectors.equals(state.collectors()))
+ persist(new SimulatorState(state.version(), state.devices(), collectors, state.nextDeviceId(),
+ state.nextCollectorId(), state.tombstones()));
+ }
+
+ /** 返回采集器最新实时快照;快照与分页历史保持不同读取路径。 */
+ public synchronized CollectorRealtimeSnapshot collectorRealtime(int collectorId)
+ {
+ return DevelopmentCollectorSimulation.realtime(requireCollector(collectorId));
+ }
+
+ /** 分页下载采集器模拟历史,并应用已配置的重复、冲突、乱序或缺失场景。 */
+ public synchronized CollectorHistoryPage collectorHistory(int collectorId, long offset, int limit)
+ {
+ return DevelopmentCollectorSimulation.history(requireCollector(collectorId), offset, limit);
+ }
+
/** 返回控制页需要的运行状态快照。 */
public synchronized StateSnapshot snapshot()
{
@@ -168,7 +213,9 @@
List<CollectorSnapshot> collectorSnapshots = state.collectors().stream()
.map(collector -> new CollectorSnapshot(collector.collectorId(), collector.deviceCode(),
collector.ip(), collector.mac(), collector.name(), collector.manufacturer(),
- collector.model(), collector.channelCount(), collector.online()))
+ collector.model(), collector.channelCount(), collector.online(), collector.sampleIntervalMs(),
+ collector.channels(), collector.historyFaults(), collector.history().size(),
+ DevelopmentCollectorSimulation.realtime(collector).measurements()))
.toList();
return new StateSnapshot(running, HOST + ":" + port(), deviceSnapshots, collectorSnapshots,
stateStore.loadRecentRequests());
@@ -202,6 +249,14 @@
return new CollectorState(collectorId, "dev-sim-collector-" + collectorId,
ip.trim(), simulatorCollectorMac(collectorId), "dev-sim 采集器 " + collectorId,
"开发模拟器", "Virtual Collector", channelCount, true);
+ }
+
+ private void replaceCollector(CollectorState replacement)
+ {
+ List<CollectorState> collectors = new ArrayList<>(state.collectors());
+ collectors.replaceAll(item -> item.collectorId() == replacement.collectorId() ? replacement : item);
+ persist(new SimulatorState(state.version(), state.devices(), collectors, state.nextDeviceId(),
+ state.nextCollectorId(), state.tombstones()));
}
private String respond(String request)
@@ -442,6 +497,7 @@
|| !isIpv4(collector.ip()) || !ips.add(collector.ip())
|| collector.channelCount() < 1 || collector.channelCount() > MAX_CHANNEL_COUNT)
throw new IllegalStateException("Invalid BTS simulator collector state in Redis");
+ DevelopmentCollectorSimulation.validate(collector);
maximumCollectorId = Math.max(maximumCollectorId, collector.collectorId());
}
java.util.Set<String> tombstoneIds = new java.util.HashSet<>();
@@ -471,6 +527,15 @@
public record ChannelSnapshot(int channelId, boolean online, DeviceWorkStatus workStatus) { }
public record CollectorSnapshot(int collectorId, String deviceCode, String ip, String mac, String name,
- String manufacturer, String model, int channelCount, boolean online) { }
+ String manufacturer, String model, int channelCount, boolean online, int sampleIntervalMs,
+ List<CollectorChannelState> channels, CollectorHistoryFaults historyFaults, int historyRecordCount,
+ List<CollectorMeasurementRecord> latestMeasurements)
+ {
+ public CollectorSnapshot
+ {
+ channels = List.copyOf(channels);
+ latestMeasurements = List.copyOf(latestMeasurements);
+ }
+ }
}
--
Gitblit v1.7.1