| | |
| | | package com.ruoyi.web.controller.device; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import org.springframework.core.io.ClassPathResource; |
| | | import org.springframework.core.io.Resource; |
| | | import org.springframework.http.HttpStatus; |
| | |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.server.ResponseStatusException; |
| | | import com.ruoyi.common.annotation.Anonymous; |
| | | import com.ruoyi.device.bts.BtsDevelopmentSimulator; |
| | | import com.ruoyi.device.bts.BtsDevelopmentSimulator.StateSnapshot; |
| | | import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore; |
| | | import com.ruoyi.device.model.DeviceWorkStatus; |
| | | import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorHistoryFaults; |
| | | import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMetricState; |
| | | import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorHistoryPage; |
| | | import com.ruoyi.device.simulator.DevelopmentCollectorSimulation.CollectorRealtimeSnapshot; |
| | | |
| | | /** 本机临时 BTS 模拟器控制 API。 */ |
| | | @Anonymous |
| | |
| | | public class BtsDevelopmentSimulatorController |
| | | { |
| | | private final BtsDevelopmentSimulator simulator; |
| | | private final DeviceDiscoveryCandidateStore candidateStore; |
| | | |
| | | public BtsDevelopmentSimulatorController(BtsDevelopmentSimulator simulator) |
| | | public BtsDevelopmentSimulatorController(BtsDevelopmentSimulator simulator, |
| | | DeviceDiscoveryCandidateStore candidateStore) |
| | | { |
| | | this.simulator = simulator; |
| | | this.candidateStore = candidateStore; |
| | | } |
| | | |
| | | /** 返回临时控制页;匿名放行后仍由本机拦截器限制来源。 */ |
| | |
| | | @GetMapping("/dev/bts-simulator/state") |
| | | public StateSnapshot state() |
| | | { |
| | | return simulator.snapshot(); |
| | | } |
| | | |
| | | /** 人工清空长期状态并恢复一台默认检测柜和采集器。 */ |
| | | @PostMapping("/dev/bts-simulator/reset") |
| | | public StateSnapshot reset() |
| | | { |
| | | simulator.reset(); |
| | | candidateStore.removeAdapter(BtsDevelopmentSimulator.ADAPTER_CODE); |
| | | return simulator.snapshot(); |
| | | } |
| | | |
| | | /** 模拟现场人工统一开关全部检测柜和采集器,不发送任何设备控制命令。 */ |
| | | @PostMapping("/dev/bts-simulator/power") |
| | | public StateSnapshot setPower(@RequestBody SimulatorPowerCommand command) |
| | | { |
| | | if (command == null || command.poweredOn() == null) |
| | | throw badRequest(new IllegalArgumentException("poweredOn must be true or false")); |
| | | simulator.setAllDevicesPoweredOn(command.poweredOn()); |
| | | return simulator.snapshot(); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | /** 添加一台与检测柜分开配置的虚拟采集器。 */ |
| | | @PostMapping("/dev/bts-simulator/collectors") |
| | | public StateSnapshot createCollector(@RequestBody CreateCollectorCommand command) |
| | | { |
| | | try |
| | | { |
| | | simulator.addCollector(command.ip(), command.channelCount()); |
| | | return simulator.snapshot(); |
| | | } |
| | | catch (IllegalArgumentException exception) |
| | | { |
| | | throw badRequest(exception); |
| | | } |
| | | } |
| | | |
| | | /** 修改虚拟采集器的地址、通道数和在线状态。 */ |
| | | @PutMapping("/dev/bts-simulator/collectors/{collectorId}") |
| | | public StateSnapshot updateCollector(@PathVariable int collectorId, |
| | | @RequestBody CollectorStateCommand command) |
| | | { |
| | | try |
| | | { |
| | | simulator.updateCollector(collectorId, command.ip(), command.channelCount(), command.online()); |
| | | return simulator.snapshot(); |
| | | } |
| | | catch (IllegalArgumentException exception) |
| | | { |
| | | throw badRequest(exception); |
| | | } |
| | | } |
| | | |
| | | /** 配置采集器采样频率和可重复的历史下载故障场景。 */ |
| | | @PutMapping("/dev/bts-simulator/collectors/{collectorId}/sampling") |
| | | public StateSnapshot configureCollectorSampling(@PathVariable int collectorId, |
| | | @RequestBody CollectorSamplingCommand command) |
| | | { |
| | | try |
| | | { |
| | | simulator.configureCollectorSampling(collectorId, command.sampleIntervalMs(), |
| | | new CollectorHistoryFaults(command.missingSequences(), command.duplicateSequence(), |
| | | command.conflictingSequence(), command.outOfOrder())); |
| | | return simulator.snapshot(); |
| | | } |
| | | catch (IllegalArgumentException exception) |
| | | { |
| | | throw badRequest(exception); |
| | | } |
| | | } |
| | | |
| | | /** 配置稳定 S 通道的固定和动态测量项。 */ |
| | | @PutMapping("/dev/bts-simulator/collectors/{collectorId}/channels/{channelCode}") |
| | | public StateSnapshot configureCollectorChannel(@PathVariable int collectorId, |
| | | @PathVariable String channelCode, @RequestBody CollectorChannelCommand command) |
| | | { |
| | | try |
| | | { |
| | | List<CollectorMetricState> metrics = command.metrics().stream() |
| | | .map(metric -> new CollectorMetricState(metric.metricCode(), metric.value(), metric.unit())) |
| | | .toList(); |
| | | simulator.configureCollectorChannel(collectorId, channelCode, metrics); |
| | | return simulator.snapshot(); |
| | | } |
| | | catch (IllegalArgumentException | NullPointerException exception) |
| | | { |
| | | throw badRequest(new IllegalArgumentException("Invalid collector channel metrics", exception)); |
| | | } |
| | | } |
| | | |
| | | /** 查询采集器最新实时快照;离线时保留最后观测并明确返回离线事实。 */ |
| | | @GetMapping("/dev/bts-simulator/collectors/{collectorId}/realtime") |
| | | public CollectorRealtimeSnapshot collectorRealtime(@PathVariable int collectorId) |
| | | { |
| | | try |
| | | { |
| | | return simulator.collectorRealtime(collectorId); |
| | | } |
| | | catch (IllegalArgumentException exception) |
| | | { |
| | | throw badRequest(exception); |
| | | } |
| | | } |
| | | |
| | | /** 按偏移量分页下载采集器模拟历史,每页最多 1000 条。 */ |
| | | @GetMapping("/dev/bts-simulator/collectors/{collectorId}/history") |
| | | public CollectorHistoryPage collectorHistory(@PathVariable int collectorId, |
| | | @RequestParam(defaultValue = "0") long offset, @RequestParam(defaultValue = "100") int limit) |
| | | { |
| | | try |
| | | { |
| | | return simulator.collectorHistory(collectorId, offset, limit); |
| | | } |
| | | catch (IllegalArgumentException exception) |
| | | { |
| | | throw badRequest(exception); |
| | | } |
| | | } |
| | | |
| | | /** 删除指定虚拟采集器。 */ |
| | | @DeleteMapping("/dev/bts-simulator/collectors/{collectorId}") |
| | | public StateSnapshot deleteCollector(@PathVariable int collectorId) |
| | | { |
| | | try |
| | | { |
| | | simulator.deleteCollector(collectorId); |
| | | return simulator.snapshot(); |
| | | } |
| | | catch (IllegalArgumentException exception) |
| | | { |
| | | throw badRequest(exception); |
| | | } |
| | | } |
| | | |
| | | /** 修改指定虚拟设备通道的在线和工作状态。 */ |
| | | @PutMapping("/dev/bts-simulator/devices/{deviceId}/channels/{channelId}") |
| | | public StateSnapshot updateChannel(@PathVariable int deviceId, @PathVariable int channelId, |
| | |
| | | |
| | | public record CreateDeviceCommand(String ip, int channelCount) { } |
| | | |
| | | public record SimulatorPowerCommand(Boolean poweredOn) { } |
| | | |
| | | public record DeviceStateCommand(String ip, int channelCount, boolean online) { } |
| | | |
| | | public record ChannelStateCommand(boolean online, DeviceWorkStatus workStatus) { } |
| | | |
| | | public record CreateCollectorCommand(String ip, int channelCount) { } |
| | | |
| | | public record CollectorStateCommand(String ip, int channelCount, boolean online) { } |
| | | |
| | | public record CollectorSamplingCommand(int sampleIntervalMs, List<Long> missingSequences, |
| | | Long duplicateSequence, Long conflictingSequence, boolean outOfOrder) |
| | | { |
| | | public CollectorSamplingCommand |
| | | { |
| | | missingSequences = missingSequences == null ? List.of() : List.copyOf(missingSequences); |
| | | } |
| | | } |
| | | |
| | | public record CollectorChannelCommand(List<CollectorMetricCommand> metrics) { } |
| | | |
| | | public record CollectorMetricCommand(String metricCode, BigDecimal value, String unit) { } |
| | | } |