From 210663040bf65ee00b5f86545fdc31bd0356fddf Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 27 八月 2026 16:31:53 +0800
Subject: [PATCH] feat(device): persist simulator discovery in redis
---
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java | 67 +++++++++++++++++++--------------
1 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java
index cc74b8f..dd57211 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceAdapterServiceImpl.java
@@ -3,12 +3,8 @@
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSON;
@@ -16,10 +12,9 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.device.api.DeviceAdapterException;
+import com.ruoyi.device.bts.BtsDevelopmentSimulator;
+import com.ruoyi.device.discovery.DeviceDiscoveryCandidateStore;
import com.ruoyi.device.model.AdapterCapabilities;
-import com.ruoyi.device.model.ChannelIdentity;
-import com.ruoyi.device.model.DetectedChannel;
-import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.device.registry.AdapterInstanceConfig;
import com.ruoyi.device.registry.AdapterRegistryException;
import com.ruoyi.device.registry.DeviceAdapterRegistry;
@@ -29,6 +24,7 @@
import com.ruoyi.system.mapper.TDeviceAdapterMapper;
import com.ruoyi.system.service.DeviceAdapterErrorCodes;
import com.ruoyi.system.service.IDeviceAdapterService;
+import com.ruoyi.system.service.impl.DeviceDiscoveryPersistenceService.DiscoverySource;
@Service
public class DeviceAdapterServiceImpl implements IDeviceAdapterService
@@ -41,13 +37,15 @@
private final TDeviceAdapterMapper mapper;
private final DeviceAdapterRegistry registry;
private final DeviceDiscoveryPersistenceService persistence;
+ private final DeviceDiscoveryCandidateStore candidateStore;
public DeviceAdapterServiceImpl(TDeviceAdapterMapper mapper, DeviceAdapterRegistry registry,
- DeviceDiscoveryPersistenceService persistence)
+ DeviceDiscoveryPersistenceService persistence, DeviceDiscoveryCandidateStore candidateStore)
{
this.mapper = mapper;
this.registry = registry;
this.persistence = persistence;
+ this.candidateStore = candidateStore;
}
/** 按管理端筛选条件查询适配器及其运行状态。 */
@@ -68,6 +66,7 @@
public TDeviceAdapter ensureManagedAdapter(TDeviceAdapter adapter)
{
normalizeAndValidate(adapter);
+ rejectDevelopmentSimulatorDatabaseConfig(adapter);
AdapterCapabilities capabilities = parseCapabilities(adapter.getCapabilities());
if (capabilities.control())
throw error("当前里程碑只允许只读设备适配器", DeviceAdapterErrorCodes.INVALID_CONFIG);
@@ -85,6 +84,7 @@
public int insert(TDeviceAdapter adapter)
{
normalizeAndValidate(adapter);
+ rejectDevelopmentSimulatorDatabaseConfig(adapter);
if (mapper.selectDeviceAdapterByCode(adapter.getAdapterCode()) != null)
throw error("适配器编码已存在", DeviceAdapterErrorCodes.DUPLICATE_CODE);
adapter.setCapabilities(READ_ONLY_CAPABILITIES);
@@ -125,7 +125,7 @@
return rows;
}
- /** 执行一次发现和实时观测,并事务性写入通道事实。 */
+ /** 执行一次发现和实时观测,将未登记设备写入 Redis 候选。 */
@Override
public AdapterDiscoveryResult discover(Long adapterId)
{
@@ -135,18 +135,10 @@
try
{
registry.synchronize(toRuntimeConfig(adapter));
- DiscoveryObservation observation = registry.execute(adapter.getAdapterCode(), runtime -> {
- List<DetectedChannel> channels = runtime.discoverChannels();
- Set<ChannelIdentity> available = channels.stream()
- .filter(DetectedChannel::available)
- .map(DetectedChannel::identity)
- .collect(Collectors.toCollection(LinkedHashSet::new));
- return new DiscoveryObservation(channels, available.isEmpty() ? Map.of() : runtime.inquire(available));
- });
- Instant observedAt = Instant.now();
- AdapterDiscoveryResult result = persistence.persist(adapter, observation.channels(),
- observation.snapshots(), observedAt);
- mapper.updateDiscoverySuccess(adapterId, observedAt);
+ AdapterDiscoveryResult result = persistence.discover(registry, new DiscoverySource(
+ adapter.getAdapterCode(), adapter.getAdapterId(), adapter.getAdapterName(),
+ adapter.getPollIntervalMs()));
+ mapper.updateDiscoverySuccess(adapterId, result.observedAtUtc());
return result;
}
catch (DeviceAdapterException exception)
@@ -159,12 +151,28 @@
}
}
- /** 查询指定适配器已发现且未删除的通道。 */
+ /** 查询指定适配器当前未过期的 Redis 发现通道。 */
@Override
public List<TDetectionChannel> selectChannels(Long adapterId)
{
- selectById(adapterId);
- return mapper.selectDetectionChannelsByAdapterId(adapterId);
+ TDeviceAdapter adapter = selectById(adapterId);
+ return candidateStore.snapshot(Instant.now()).cabinets().stream()
+ .filter(item -> item.adapterCode().equals(adapter.getAdapterCode()))
+ .flatMap(item -> item.channels().stream().map(channel -> {
+ TDetectionChannel value = new TDetectionChannel();
+ value.setAdapterId(adapterId);
+ value.setDevtype(channel.identity().devtype());
+ value.setDevid(channel.identity().devid());
+ value.setSubdevid(channel.identity().subdevid());
+ value.setChlid(channel.identity().chlid());
+ value.setDisplayNo(channel.identity().subdevid() + "-" + channel.identity().chlid());
+ value.setOnlineStatus(channel.online() ? "ONLINE" : "OFFLINE");
+ value.setWorkStatus(channel.workStatus().name());
+ value.setLastSeenAtUtc(channel.observedAt());
+ value.setStatus("0");
+ return value;
+ }))
+ .toList();
}
/** 启动时恢复所有已启用适配器的运行时注册。 */
@@ -220,6 +228,12 @@
}
}
+ private void rejectDevelopmentSimulatorDatabaseConfig(TDeviceAdapter adapter)
+ {
+ if (BtsDevelopmentSimulator.ADAPTER_CODE.equals(adapter.getAdapterCode()))
+ throw error("dev-sim 由开发环境代码固定装配,不能写入数据库", DeviceAdapterErrorCodes.INVALID_CONFIG);
+ }
+
private AdapterInstanceConfig toRuntimeConfig(TDeviceAdapter adapter)
{
return new AdapterInstanceConfig(adapter.getAdapterCode(), adapter.getAdapterType(), adapter.getHost(),
@@ -237,9 +251,4 @@
}
private ServiceException error(String message, int code) { return new ServiceException(message, code); }
-
- private record DiscoveryObservation(List<DetectedChannel> channels,
- Map<ChannelIdentity, RealtimeSnapshot> snapshots)
- {
- }
}
--
Gitblit v1.7.1