| | |
| | | import java.util.List; |
| | | import com.alibaba.fastjson2.JSON; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import com.ruoyi.device.bts.BtsDevelopmentSimulator; |
| | | import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord; |
| | |
| | | private final TTestMapper mapper; |
| | | private final ITTestService tests; |
| | | private final BtsDevelopmentSimulator simulator; |
| | | private final TestWarningExceptionService warningExceptions; |
| | | private final Map<String, Instant> lastSnapshotAt = new java.util.concurrent.ConcurrentHashMap<>(); |
| | | private final Map<Long, Instant> lastRawCaptureAt = new java.util.concurrent.ConcurrentHashMap<>(); |
| | | |
| | | public TestDataReceptionServiceImpl(TTestMapper mapper, ITTestService tests, BtsDevelopmentSimulator simulator) |
| | | @Autowired |
| | | public TestDataReceptionServiceImpl(TTestMapper mapper, ITTestService tests, BtsDevelopmentSimulator simulator, |
| | | TestWarningExceptionService warningExceptions) |
| | | { |
| | | this.mapper = mapper; |
| | | this.tests = tests; |
| | | this.simulator = simulator; |
| | | this.warningExceptions = warningExceptions; |
| | | } |
| | | |
| | | /** 保留单元测试及旧调用方构造契约。 */ |
| | | public TestDataReceptionServiceImpl(TTestMapper mapper, ITTestService tests, BtsDevelopmentSimulator simulator) |
| | | { this(mapper, tests, simulator, new TestWarningExceptionService(mapper)); } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | { |
| | | // 模拟器保留通道历史;只接收本次测试开始后产生的设备时间记录,避免顺序测试串入旧事实。 |
| | | if (startedAt != null && record.deviceTime().isBefore(startedAt.toInstant())) continue; |
| | | save(test, binding, record); |
| | | if (save(test, binding, record)) { |
| | | String source = String.join(":", java.util.Objects.toString(binding.getAdapterCode(), ""), |
| | | java.util.Objects.toString(binding.getDevtype(), ""), java.util.Objects.toString(binding.getDevid(), ""), |
| | | java.util.Objects.toString(binding.getSubdevid(), ""), java.util.Objects.toString(binding.getChlid(), "")); |
| | | warningExceptions.evaluate(test, "CABINET", source, "VOLTAGE", BigDecimal.valueOf(record.voltageV()), "V", Date.from(record.deviceTime())); |
| | | warningExceptions.evaluate(test, "CABINET", source, "CURRENT", BigDecimal.valueOf(record.currentA()), "A", Date.from(record.deviceTime())); |
| | | warningExceptions.evaluate(test, "CABINET", source, "CAPACITY", BigDecimal.valueOf(record.capacityAh()), "Ah", Date.from(record.deviceTime())); |
| | | warningExceptions.evaluate(test, "CABINET", source, "ENERGY", BigDecimal.valueOf(record.energyWh()), "Wh", Date.from(record.deviceTime())); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | java.util.Objects.equals(mapping.getChannelCode(), measurement.channelCode()) |
| | | && metricMatches(mapping.getMeasurementCode(), measurement.metricCode())); |
| | | if (!mapped) continue; |
| | | saveCollector(test, battery, measurement); |
| | | if (saveCollector(test, battery, measurement)) |
| | | warningExceptions.evaluate(test, "COLLECTOR", measurement.adapterCode() + ":" + battery.getCollectorId() + ":" + measurement.channelCode(), measurement.metricCode(), measurement.value(), measurement.unit(), Date.from(measurement.deviceTime())); |
| | | } |
| | | } |
| | | |
| | | private void saveCollector(TTest test, TTestBattery battery, CollectorRealtimeMeasurement measurement) |
| | | private boolean saveCollector(TTest test, TTestBattery battery, CollectorRealtimeMeasurement measurement) |
| | | { |
| | | byte[] hash = hash(measurement); |
| | | String old = mapper.selectCollectorSampleContentHash(battery.getCollectorId(), measurement.channelCode(), |
| | |
| | | "采集器实时接收内容冲突 collector=" + battery.getCollectorId() + ", channel=" |
| | | + measurement.channelCode() + ", metric=" + measurement.metricCode() |
| | | + ", seqid=" + measurement.sequenceId()); |
| | | return; |
| | | return false; |
| | | } |
| | | Date receivedAt = new Date(); |
| | | int inserted = mapper.insertCollectorSample(test.getTestId(), battery.getBinding().getBindingId(), battery.getCollectorId(), |
| | |
| | | + measurement.channelCode() + ", metric=" + measurement.metricCode() |
| | | + ", seqid=" + measurement.sequenceId()); |
| | | } |
| | | return inserted > 0; |
| | | } |
| | | |
| | | private void save(TTest test, TTestChannelBinding binding, |
| | | private boolean save(TTest test, TTestChannelBinding binding, |
| | | BtsHistoryRecord record) |
| | | { |
| | | // 模拟器历史 testid 按通道固定;接收事实必须再带测试作用域,避免顺序测试共用全局幂等键。 |
| | |
| | | if (!old.equalsIgnoreCase(HexFormat.of().formatHex(hash))) |
| | | mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(), |
| | | "实时接收内容冲突 testid=" + btsTestId + ", seqid=" + record.sequenceId()); |
| | | return; |
| | | return false; |
| | | } |
| | | int inserted = mapper.insertBtsSample(test.getTestId(), binding.getBindingId(), binding.getChannelId(), |
| | | btsTestId, record.sequenceId(), Date.from(record.deviceTime()), |
| | |
| | | mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(), |
| | | "实时接收并发内容冲突 testid=" + btsTestId + ", seqid=" + record.sequenceId()); |
| | | } |
| | | return inserted > 0; |
| | | } |
| | | |
| | | private byte[] hash(BtsHistoryRecord record) |