yeg
2026-08-27 a4f06a9095a2eab0bb48b406c4609be6e70b8854
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.ruoyi.system.service.impl;
 
import java.math.BigDecimal;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.device.model.DetectedChannel;
import com.ruoyi.device.model.ChannelIdentity;
import com.ruoyi.device.model.DetectedDeviceMetadata;
import com.ruoyi.device.model.RealtimeSnapshot;
import com.ruoyi.system.domain.TDetectionCabinet;
import com.ruoyi.system.domain.TDetectionChannel;
import com.ruoyi.system.domain.TDeviceAdapter;
import com.ruoyi.system.domain.vo.AdapterDiscoveryResult;
import com.ruoyi.system.mapper.TDeviceAdapterMapper;
 
@Service
public class DeviceDiscoveryPersistenceService
{
    private final TDeviceAdapterMapper mapper;
 
    public DeviceDiscoveryPersistenceService(TDeviceAdapterMapper mapper)
    {
        this.mapper = mapper;
    }
 
    /** 在事务内 upsert 本轮发现和实时观测;未返回通道保持原记录不变。 */
    @Transactional(rollbackFor = Exception.class)
    public AdapterDiscoveryResult persist(TDeviceAdapter adapter, List<DetectedChannel> detected,
            Map<ChannelIdentity, RealtimeSnapshot> snapshots, Instant observedAt)
    {
        Map<CabinetKey, List<DetectedChannel>> cabinets = detected.stream().collect(
                java.util.stream.Collectors.groupingBy(
                        item -> new CabinetKey(item.identity().devtype(), item.identity().devid()),
                        LinkedHashMap::new, java.util.stream.Collectors.toList()));
 
        for (Map.Entry<CabinetKey, List<DetectedChannel>> entry : cabinets.entrySet())
        {
            Long cabinetId = ensureCabinet(adapter, entry.getKey(), entry.getValue(), observedAt);
            for (DetectedChannel item : entry.getValue())
                mapper.upsertDetectedChannel(toChannel(adapter.getAdapterId(), cabinetId, item,
                        snapshots.get(item.identity()), observedAt));
        }
        return new AdapterDiscoveryResult(cabinets.size(), detected.size(), observedAt);
    }
 
    private Long ensureCabinet(TDeviceAdapter adapter, CabinetKey key, List<DetectedChannel> channels,
            Instant observedAt)
    {
        Long cabinetId = mapper.selectCabinetIdByIdentity(adapter.getAdapterId(), key.devtype(), key.devid());
        TDetectionCabinet cabinet = new TDetectionCabinet();
        cabinet.setCabinetId(cabinetId);
        cabinet.setAdapterId(adapter.getAdapterId());
        cabinet.setCabinetCode(adapter.getAdapterCode() + "-" + key.devtype() + "-" + key.devid());
        DetectedDeviceMetadata metadata = channels.get(0).deviceMetadata();
        cabinet.setCabinetName(metadata.name() == null
                ? adapter.getAdapterName() + " " + key.devtype() + "-" + key.devid()
                : metadata.name());
        cabinet.setManufacturer(metadata.manufacturer());
        cabinet.setModel(metadata.model());
        cabinet.setMacAddress(metadata.macAddress());
        cabinet.setCapacity(BigDecimal.ONE);
        cabinet.setChannelCount(channels.size());
        cabinet.setVendorDeviceType(key.devtype());
        cabinet.setVendorDeviceId(key.devid());
        cabinet.setIpAddress(channels.stream().map(DetectedChannel::serverIp).filter(value -> value != null && !value.isBlank())
                .findFirst().orElse(null));
        cabinet.setOnlineStatus(channels.stream().anyMatch(DetectedChannel::available) ? "ONLINE" : "OFFLINE");
        cabinet.setLastSeenAtUtc(observedAt);
        if (cabinetId == null)
        {
            try
            {
                mapper.insertDetectedCabinet(cabinet);
                return cabinet.getCabinetId();
            }
            catch (DuplicateKeyException concurrentInsert)
            {
                cabinetId = mapper.selectCabinetIdByIdentity(adapter.getAdapterId(), key.devtype(), key.devid());
                if (cabinetId == null) throw concurrentInsert;
                cabinet.setCabinetId(cabinetId);
            }
        }
        mapper.updateDetectedCabinet(cabinet);
        return cabinetId;
    }
 
    private TDetectionChannel toChannel(Long adapterId, Long cabinetId, DetectedChannel detected,
            RealtimeSnapshot snapshot, Instant observedAt)
    {
        TDetectionChannel channel = new TDetectionChannel();
        channel.setAdapterId(adapterId);
        channel.setCabinetId(cabinetId);
        channel.setDevtype(detected.identity().devtype());
        channel.setDevid(detected.identity().devid());
        channel.setSubdevid(detected.identity().subdevid());
        channel.setChlid(detected.identity().chlid());
        channel.setDisplayNo(detected.identity().subdevid() + "-" + detected.identity().chlid());
        channel.setOnlineStatus(detected.available() ? "ONLINE" : "OFFLINE");
        channel.setWorkStatus(snapshot == null || snapshot.workStatus() == null
                ? "UNKNOWN" : snapshot.workStatus().name());
        channel.setLastSeenAtUtc(observedAt);
        channel.setStatus("0");
        return channel;
    }
 
    private record CabinetKey(int devtype, int devid)
    {
    }
}