| | |
| | | value.setSubdevid(channel.identity().subdevid()); |
| | | value.setChlid(channel.identity().chlid()); |
| | | value.setDisplayNo(channel.identity().subdevid() + "-" + channel.identity().chlid()); |
| | | value.setOnlineStatus("UNKNOWN"); |
| | | value.setWorkStatus("UNKNOWN"); |
| | | value.setOnlineStatus(channel.online() ? "ONLINE" : "OFFLINE"); |
| | | value.setWorkStatus(persistedWorkStatus(channel.workStatus(), channel.online())); |
| | | value.setLastSeenAtUtc(null); |
| | | detectionCabinetMapper.insertDetectionChannel(value); |
| | | } |
| | | // 登记瞬间的候选也是一次有效观测,立即写入正式事实,避免等待下一轮轮询才显示在线。 |
| | | detectionCabinetMapper.updateRegisteredCabinetObservation(candidate.adapterCode(), candidate.devtype(), |
| | | candidate.devid(), candidate.online() ? "ONLINE" : "OFFLINE", candidate.observedAt(), |
| | | candidate.online()); |
| | | candidate.channels().forEach(channel -> detectionCabinetMapper.updateRegisteredChannelObservation( |
| | | candidate.adapterCode(), channel.identity().devtype(), channel.identity().devid(), |
| | | channel.identity().subdevid(), channel.identity().chlid(), channel.online() ? "ONLINE" : "OFFLINE", |
| | | channel.online() ? persistedWorkStatus(channel.workStatus(), true) : "UNOBSERVABLE", |
| | | channel.observedAt(), channel.online())); |
| | | return rows; |
| | | } |
| | | catch (DuplicateKeyException exception) |
| | |
| | | |
| | | private Map<String, CabinetCandidate> candidatesByCode() |
| | | { |
| | | return candidateStore.snapshot(Instant.now()).cabinets().stream() |
| | | .collect(java.util.stream.Collectors.toMap(CabinetCandidate::deviceCode, item -> item)); |
| | | return candidateStore.snapshot(Instant.now()).cabinets().stream().collect(java.util.stream.Collectors.toMap( |
| | | item -> stableCandidateKey(item.adapterCode(), item.devtype(), item.devid()), item -> item, |
| | | (left, right) -> right)); |
| | | } |
| | | |
| | | private TDetectionCabinet applyRealtimeState(TDetectionCabinet cabinet, |
| | | Map<String, CabinetCandidate> candidates) |
| | | { |
| | | CabinetCandidate candidate = candidates.get(cabinet.getCabinetCode()); |
| | | CabinetCandidate candidate = candidates.get(stableCandidateKey(cabinet.getAdapterCode(), |
| | | cabinet.getVendorDeviceType(), cabinet.getVendorDeviceId())); |
| | | if (candidate == null) candidate = candidateStore.findCabinet(cabinet.getCabinetCode(), Instant.now()).orElse(null); |
| | | cabinet.setOnlineStatus(candidate != null && candidate.online() ? ONLINE : OFFLINE); |
| | | return cabinet; |
| | | } |
| | | |
| | | private String stableCandidateKey(String adapterCode, Integer devtype, Integer devid) |
| | | { |
| | | return adapterCode + "-" + devtype + "-" + devid; |
| | | } |
| | | |
| | | private boolean isActive(CabinetCandidate candidate) |
| | |
| | | return candidate.channels().stream().anyMatch(channel -> ACTIVE_WORK_STATUSES.contains(channel.workStatus())); |
| | | } |
| | | |
| | | /** 将设备观测状态转换为最终数据库允许的通道事实状态。 */ |
| | | private String persistedWorkStatus(DeviceWorkStatus status, boolean online) |
| | | { |
| | | if (!online || status == null || status == DeviceWorkStatus.UNKNOWN |
| | | || status == DeviceWorkStatus.UNOBSERVABLE) return "UNOBSERVABLE"; |
| | | return switch (status) |
| | | { |
| | | case PAUSED -> "PAUSED"; |
| | | case PROTECTED -> "ABNORMAL"; |
| | | case FINISHED, STOPPED -> "ENDED"; |
| | | default -> "RUNNING"; |
| | | }; |
| | | } |
| | | |
| | | private ServiceException buildDuplicateException(TDetectionCabinet detectionCabinet, DuplicateKeyException cause) |
| | | { |
| | | String message = checkCabinetCodeUnique(detectionCabinet) ? "MAC地址已存在" : "设备编码已存在"; |