| | |
| | | import com.ruoyi.device.model.DeviceWorkStatus; |
| | | import com.ruoyi.device.model.RealtimeSnapshot; |
| | | import com.ruoyi.device.registry.DeviceAdapterRegistry; |
| | | import com.ruoyi.system.domain.TDetectionChannel; |
| | | import com.ruoyi.system.domain.vo.AdapterDiscoveryResult; |
| | | import com.ruoyi.system.mapper.TDetectionCabinetMapper; |
| | | import com.ruoyi.system.mapper.TTestMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | |
| | | private static final Duration MINIMUM_CANDIDATE_LIFETIME = Duration.ofSeconds(30); |
| | | private final DeviceDiscoveryCandidateStore candidateStore; |
| | | private final TDetectionCabinetMapper detectionCabinetMapper; |
| | | private final TTestMapper testMapper; |
| | | |
| | | @Autowired |
| | | public DeviceDiscoveryPersistenceService(DeviceDiscoveryCandidateStore candidateStore, |
| | | TDetectionCabinetMapper detectionCabinetMapper) |
| | | { |
| | | this(candidateStore, detectionCabinetMapper, null); |
| | | } |
| | | |
| | | @Autowired |
| | | public DeviceDiscoveryPersistenceService(DeviceDiscoveryCandidateStore candidateStore, |
| | | TDetectionCabinetMapper detectionCabinetMapper, TTestMapper testMapper) |
| | | { |
| | | this.candidateStore = candidateStore; |
| | | this.detectionCabinetMapper = detectionCabinetMapper; |
| | | this.testMapper = testMapper; |
| | | } |
| | | |
| | | /** 执行设备发现和可用通道查询,并将本轮观测写入 Redis 候选。 */ |
| | | public AdapterDiscoveryResult discover(DeviceAdapterRegistry registry, DiscoverySource source) |
| | | { |
| | | return discoverNow(registry, source); |
| | | } |
| | | |
| | | /** 调度器观测;暂停或停止测试且没有其他接收测试时,不再向该适配器请求实时数据。 */ |
| | | public AdapterDiscoveryResult discoverForReception(DeviceAdapterRegistry registry, DiscoverySource source) |
| | | { |
| | | if (!shouldPollReception(source.adapterCode())) |
| | | return new AdapterDiscoveryResult(0, 0, Instant.now()); |
| | | return discoverNow(registry, source); |
| | | } |
| | | |
| | | /** 判断适配器是否仍需为活动测试发起实时请求。 */ |
| | | public boolean shouldPollReception(String adapterCode) |
| | | { |
| | | return testMapper == null || testMapper.hasReceivingTestForAdapter(adapterCode) > 0 |
| | | || testMapper.hasPausedOrEndedTestForAdapter(adapterCode) == 0; |
| | | } |
| | | |
| | | private AdapterDiscoveryResult discoverNow(DeviceAdapterRegistry registry, DiscoverySource source) |
| | | { |
| | | DiscoveryObservation observation = registry.execute(source.adapterCode(), runtime -> { |
| | | List<DetectedChannel> channels = runtime.discoverChannels(); |
| | |
| | | .filter(DetectedChannel::available) |
| | | .map(DetectedChannel::identity) |
| | | .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); |
| | | Map<ChannelIdentity, RealtimeSnapshot> snapshots = available.isEmpty() |
| | | ? Map.of() : runtime.inquire(available); |
| | | Set<ChannelIdentity> requested = receivingIdentities(source.adapterCode(), available); |
| | | Map<ChannelIdentity, RealtimeSnapshot> snapshots = requested.isEmpty() |
| | | ? Map.of() : runtime.inquire(requested); |
| | | return new DiscoveryObservation(channels, snapshots); |
| | | }); |
| | | Instant observedAt = Instant.now(); |
| | |
| | | return new AdapterDiscoveryResult(grouped.size(), detected.size(), observedAt); |
| | | } |
| | | |
| | | private Set<ChannelIdentity> receivingIdentities(String adapterCode, Set<ChannelIdentity> available) |
| | | { |
| | | if (testMapper == null) return available; |
| | | List<TDetectionChannel> receiving = testMapper.selectReceivingChannelsForAdapter(adapterCode); |
| | | if (receiving == null || receiving.isEmpty()) return Set.of(); |
| | | Set<ChannelIdentity> identities = receiving.stream() |
| | | .map(channel -> new ChannelIdentity(adapterCode, channel.getDevtype(), channel.getDevid(), |
| | | channel.getSubdevid(), channel.getChlid())) |
| | | .collect(java.util.stream.Collectors.toCollection(LinkedHashSet::new)); |
| | | identities.retainAll(available); |
| | | return identities; |
| | | } |
| | | |
| | | /** |
| | | * 发现候选与正式设备是两份事实;正式登记后仍需把成功观测同步到 MySQL, |
| | | * 否则开始接收无法取得可靠边界。离线轮询只更新当前状态,不覆盖最后成功观测时间。 |
| | | * 发现候选与正式设备是两份事实;正式登记后仍需把成功观测同步到 MySQL。 |
| | | * 离线轮询只更新当前状态,不覆盖最后成功观测时间;暂停期间不会进入此路径。 |
| | | */ |
| | | private void synchronizeRegisteredFacts(DiscoverySource source, List<DetectedChannel> detected, |
| | | Map<ChannelIdentity, RealtimeSnapshot> snapshots, Instant observedAt) |