648540858
2023-02-22 019d95cfba07f0231bd5b385f6736883c6e90623
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
 
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import gov.nist.javax.sip.message.SIPRequest;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
 
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
 
/**
 * 目录查询的回复
 */
@Component
public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
 
    private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class);
 
    private final String cmdType = "Catalog";
 
    @Autowired
    private ResponseMessageHandler responseMessageHandler;
 
    private final ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
 
    @Autowired
    private IVideoManagerStorage storager;
 
    @Autowired
    private CatalogDataCatch catalogDataCatch;
 
    @Qualifier("taskExecutor")
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
 
    @Override
    public void afterPropertiesSet() throws Exception {
        responseMessageHandler.addHandler(cmdType, this);
    }
 
    @Override
    public void handForDevice(RequestEvent evt, Device device, Element element) {
        boolean isEmpty = taskQueue.isEmpty();
        taskQueue.offer(new HandlerCatchData(evt, device, element));
        // 回复200 OK
        try {
            responseAck((SIPRequest) evt.getRequest(), Response.OK);
        } catch (SipException | InvalidArgumentException | ParseException e) {
            logger.error("[命令发送失败] 目录查询回复: {}", e.getMessage());
        }
        // 如果不为空则说明已经开启消息处理
        if (isEmpty) {
            taskExecutor.execute(() -> {
                while (!taskQueue.isEmpty()) {
                    // 全局异常捕获,保证下一条可以得到处理
                    try {
                        HandlerCatchData take = taskQueue.poll();
                        Element rootElement = null;
                        try {
                            rootElement = getRootElement(take.getEvt(), take.getDevice().getCharset());
                        } catch (DocumentException e) {
                            logger.error("[xml解析] 失败: ", e);
                            continue;
                        }
                        if (rootElement == null) {
                            logger.warn("[ 收到通道 ] content cannot be null, {}", evt.getRequest());
                            continue;
                        }
                        Element deviceListElement = rootElement.element("DeviceList");
                        Element sumNumElement = rootElement.element("SumNum");
                        Element snElement = rootElement.element("SN");
                        int sumNum = Integer.parseInt(sumNumElement.getText());
 
                        if (sumNum == 0) {
                            logger.info("[收到通道]设备:{}的: 0个", take.getDevice().getDeviceId());
                            // 数据已经完整接收
                            storager.cleanChannelsForDevice(take.getDevice().getDeviceId());
                            catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null);
                        } else {
                            Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
                            if (deviceListIterator != null) {
                                List<DeviceChannel> channelList = new ArrayList<>();
                                // 遍历DeviceList
                                while (deviceListIterator.hasNext()) {
                                    Element itemDevice = deviceListIterator.next();
                                    Element channelDeviceElement = itemDevice.element("DeviceID");
                                    if (channelDeviceElement == null) {
                                        continue;
                                    }
                                    DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null);
                                    deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys());
                                    deviceChannel.setDeviceId(take.getDevice().getDeviceId());
 
                                    channelList.add(deviceChannel);
                                }
                                int sn = Integer.parseInt(snElement.getText());
                                catalogDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, take.getDevice(), channelList);
                                logger.info("[收到通道]设备: {} -> {}个,{}/{}", take.getDevice().getDeviceId(), channelList.size(), catalogDataCatch.get(take.getDevice().getDeviceId()) == null ? 0 : catalogDataCatch.get(take.getDevice().getDeviceId()).size(), sumNum);
                                if (catalogDataCatch.get(take.getDevice().getDeviceId()).size() == sumNum) {
                                    // 数据已经完整接收, 此时可能存在某个设备离线变上线的情况,但是考虑到性能,此处不做处理,
                                    // 目前支持设备通道上线通知时和设备上线时向上级通知
                                    boolean resetChannelsResult = storager.resetChannels(take.getDevice().getDeviceId(), catalogDataCatch.get(take.getDevice().getDeviceId()));
                                    if (!resetChannelsResult) {
                                        String errorMsg = "接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(take.getDevice().getDeviceId()).size() + "条";
                                        catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), errorMsg);
                                    } else {
                                        catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null);
                                    }
                                }
                            }
 
                        }
                    }catch (Exception e) {
                        logger.warn("[收到通道] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest());
                    }
                }
            });
        }
 
    }
 
    @Override
    public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
 
    }
 
    public SyncStatus getChannelSyncProgress(String deviceId) {
        if (catalogDataCatch.get(deviceId) == null) {
            return null;
        } else {
            return catalogDataCatch.getSyncStatus(deviceId);
        }
    }
 
    public boolean isSyncRunning(String deviceId) {
        if (catalogDataCatch.get(deviceId) == null) {
            return false;
        } else {
            return catalogDataCatch.isSyncRunning(deviceId);
        }
    }
 
    public void setChannelSyncReady(Device device, int sn) {
        catalogDataCatch.addReady(device, sn);
    }
 
    public void setChannelSyncEnd(String deviceId, String errorMsg) {
        catalogDataCatch.setChannelSyncEnd(deviceId, errorMsg);
    }
}