Commit 6868577e329dea7b48b33a2e5d662ad855edb341
1 parent
d3fa1dd2
将录像文件统计改为独立线程进行,实现超时返回已接收结果
Showing
2 changed files
with
147 additions
and
46 deletions
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.transmit.callback; | |
| 2 | + | |
| 3 | +import java.util.ArrayList; | |
| 4 | +import java.util.Comparator; | |
| 5 | +import java.util.List; | |
| 6 | +import java.util.concurrent.TimeUnit; | |
| 7 | + | |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; | |
| 9 | +import com.genersoft.iot.vmp.gb28181.bean.RecordItem; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor; | |
| 11 | +import com.genersoft.iot.vmp.utils.redis.RedisUtil; | |
| 12 | + | |
| 13 | +import org.slf4j.Logger; | |
| 14 | + | |
| 15 | +@SuppressWarnings("unchecked") | |
| 16 | +public class CheckForAllRecordsThread extends Thread { | |
| 17 | + | |
| 18 | + private String key; | |
| 19 | + | |
| 20 | + private RecordInfo recordInfo; | |
| 21 | + | |
| 22 | + private RedisUtil redis; | |
| 23 | + | |
| 24 | + private Logger logger; | |
| 25 | + | |
| 26 | + private DeferredResultHolder deferredResultHolder; | |
| 27 | + | |
| 28 | + public CheckForAllRecordsThread(String key, RecordInfo recordInfo) { | |
| 29 | + this.key = key; | |
| 30 | + this.recordInfo = recordInfo; | |
| 31 | + } | |
| 32 | + | |
| 33 | + public void run() { | |
| 34 | + | |
| 35 | + String cacheKey = this.key; | |
| 36 | + | |
| 37 | + for (long stop = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); stop > System.nanoTime();) { | |
| 38 | + List<Object> cacheKeys = redis.scan(cacheKey + "_*"); | |
| 39 | + List<RecordItem> totalRecordList = new ArrayList<RecordItem>(); | |
| 40 | + for (int i = 0; i < cacheKeys.size(); i++) { | |
| 41 | + totalRecordList.addAll((List<RecordItem>) redis.get(cacheKeys.get(i).toString())); | |
| 42 | + } | |
| 43 | + if (totalRecordList.size() < this.recordInfo.getSumNum()) { | |
| 44 | + logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + this.recordInfo.getSumNum() + "项"); | |
| 45 | + } else { | |
| 46 | + logger.info("录像数据已全部获取,共" + this.recordInfo.getSumNum() + "项"); | |
| 47 | + this.recordInfo.setRecordList(totalRecordList); | |
| 48 | + for (int i = 0; i < cacheKeys.size(); i++) { | |
| 49 | + redis.del(cacheKeys.get(i).toString()); | |
| 50 | + } | |
| 51 | + break; | |
| 52 | + } | |
| 53 | + } | |
| 54 | + // 自然顺序排序, 元素进行升序排列 | |
| 55 | + this.recordInfo.getRecordList().sort(Comparator.naturalOrder()); | |
| 56 | + RequestMessage msg = new RequestMessage(); | |
| 57 | + String deviceId = recordInfo.getDeviceId(); | |
| 58 | + msg.setDeviceId(deviceId); | |
| 59 | + msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); | |
| 60 | + msg.setData(recordInfo); | |
| 61 | + deferredResultHolder.invokeResult(msg); | |
| 62 | + logger.info("处理完成,返回结果"); | |
| 63 | + MessageRequestProcessor.threadNameList.remove(cacheKey); | |
| 64 | + } | |
| 65 | + | |
| 66 | + public void setRedis(RedisUtil redis) { | |
| 67 | + this.redis = redis; | |
| 68 | + } | |
| 69 | + | |
| 70 | + public void setDeferredResultHolder(DeferredResultHolder deferredResultHolder) { | |
| 71 | + this.deferredResultHolder = deferredResultHolder; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public void setLogger(Logger logger) { | |
| 75 | + this.logger = logger; | |
| 76 | + } | |
| 77 | + | |
| 78 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
| ... | ... | @@ -23,6 +23,7 @@ import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; |
| 23 | 23 | import com.genersoft.iot.vmp.gb28181.bean.RecordItem; |
| 24 | 24 | import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; |
| 25 | 25 | import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
| 26 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread; | |
| 26 | 27 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 27 | 28 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 28 | 29 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| ... | ... | @@ -43,14 +44,17 @@ import org.dom4j.io.SAXReader; |
| 43 | 44 | import org.slf4j.Logger; |
| 44 | 45 | import org.slf4j.LoggerFactory; |
| 45 | 46 | import org.springframework.util.StringUtils; |
| 47 | + | |
| 46 | 48 | /** |
| 47 | 49 | * @Description:MESSAGE请求处理器 |
| 48 | 50 | * @author: swwheihei |
| 49 | 51 | * @date: 2020年5月3日 下午5:32:41 |
| 50 | 52 | */ |
| 51 | - | |
| 53 | +@SuppressWarnings(value={"unchecked", "rawtypes"}) | |
| 52 | 54 | public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 53 | 55 | |
| 56 | + public static volatile List<String> threadNameList = new ArrayList(); | |
| 57 | + | |
| 54 | 58 | private UserSetup userSetup = (UserSetup) SpringBeanFactory.getBean("userSetup"); |
| 55 | 59 | |
| 56 | 60 | private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class); |
| ... | ... | @@ -240,10 +244,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 240 | 244 | try { |
| 241 | 245 | Element rootElement = getRootElement(evt); |
| 242 | 246 | String deviceId = XmlUtil.getText(rootElement, "DeviceID"); |
| 243 | - String result = XmlUtil.getText(rootElement, "Result"); | |
| 247 | + //String result = XmlUtil.getText(rootElement, "Result"); | |
| 244 | 248 | // 回复200 OK |
| 245 | 249 | responseAck(evt); |
| 246 | - if (!XmlUtil.isEmpty(result)) { | |
| 250 | + if (rootElement.getName().equals("Response")) {//} !XmlUtil.isEmpty(result)) { | |
| 247 | 251 | // 此处是对本平台发出DeviceControl指令的应答 |
| 248 | 252 | JSONObject json = new JSONObject(); |
| 249 | 253 | XmlUtil.node2Json(rootElement, json); |
| ... | ... | @@ -272,11 +276,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 272 | 276 | try { |
| 273 | 277 | Element rootElement = getRootElement(evt); |
| 274 | 278 | String deviceId = XmlUtil.getText(rootElement, "DeviceID"); |
| 275 | - String result = XmlUtil.getText(rootElement, "Result"); | |
| 276 | 279 | // 回复200 OK |
| 277 | 280 | responseAck(evt); |
| 278 | - //if (!XmlUtil.isEmpty(result)) { | |
| 279 | - // 此处是对本平台发出DeviceControl指令的应答 | |
| 281 | + if (rootElement.getName().equals("Response")) { | |
| 282 | + // 此处是对本平台发出DeviceControl指令的应答 | |
| 280 | 283 | JSONObject json = new JSONObject(); |
| 281 | 284 | XmlUtil.node2Json(rootElement, json); |
| 282 | 285 | if (logger.isDebugEnabled()) { |
| ... | ... | @@ -287,9 +290,9 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 287 | 290 | msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG); |
| 288 | 291 | msg.setData(json); |
| 289 | 292 | deferredResultHolder.invokeResult(msg); |
| 290 | - // } else { | |
| 291 | - // // 此处是上级发出的DeviceConfig指令 | |
| 292 | - //} | |
| 293 | + } else { | |
| 294 | + // 此处是上级发出的DeviceConfig指令 | |
| 295 | + } | |
| 293 | 296 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { |
| 294 | 297 | e.printStackTrace(); |
| 295 | 298 | } |
| ... | ... | @@ -304,11 +307,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 304 | 307 | try { |
| 305 | 308 | Element rootElement = getRootElement(evt); |
| 306 | 309 | String deviceId = XmlUtil.getText(rootElement, "DeviceID"); |
| 307 | - String result = XmlUtil.getText(rootElement, "Result"); | |
| 308 | 310 | // 回复200 OK |
| 309 | 311 | responseAck(evt); |
| 310 | - //if (!XmlUtil.isEmpty(result)) { | |
| 311 | - // 此处是对本平台发出DeviceControl指令的应答 | |
| 312 | + if (rootElement.getName().equals("Response")) { | |
| 313 | + // 此处是对本平台发出DeviceControl指令的应答 | |
| 312 | 314 | JSONObject json = new JSONObject(); |
| 313 | 315 | XmlUtil.node2Json(rootElement, json); |
| 314 | 316 | if (logger.isDebugEnabled()) { |
| ... | ... | @@ -319,9 +321,9 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 319 | 321 | msg.setType(DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD); |
| 320 | 322 | msg.setData(json); |
| 321 | 323 | deferredResultHolder.invokeResult(msg); |
| 322 | - // } else { | |
| 323 | - // // 此处是上级发出的DeviceConfig指令 | |
| 324 | - //} | |
| 324 | + } else { | |
| 325 | + // 此处是上级发出的DeviceConfig指令 | |
| 326 | + } | |
| 325 | 327 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { |
| 326 | 328 | e.printStackTrace(); |
| 327 | 329 | } |
| ... | ... | @@ -336,7 +338,6 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 336 | 338 | try { |
| 337 | 339 | Element rootElement = getRootElement(evt); |
| 338 | 340 | String deviceId = XmlUtil.getText(rootElement, "DeviceID"); |
| 339 | - String result = XmlUtil.getText(rootElement, "Result"); | |
| 340 | 341 | // 回复200 OK |
| 341 | 342 | responseAck(evt); |
| 342 | 343 | if (rootElement.getName().equals("Response")) {// !XmlUtil.isEmpty(result)) { |
| ... | ... | @@ -648,8 +649,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 648 | 649 | Element recordListElement = rootElement.element("RecordList"); |
| 649 | 650 | if (recordListElement == null || recordInfo.getSumNum() == 0) { |
| 650 | 651 | logger.info("无录像数据"); |
| 651 | - // responseAck(evt); | |
| 652 | - // return; | |
| 652 | + RequestMessage msg = new RequestMessage(); | |
| 653 | + msg.setDeviceId(deviceId); | |
| 654 | + msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); | |
| 655 | + msg.setData(recordInfo); | |
| 656 | + deferredResultHolder.invokeResult(msg); | |
| 653 | 657 | } else { |
| 654 | 658 | Iterator<Element> recordListIterator = recordListElement.elementIterator(); |
| 655 | 659 | List<RecordItem> recordList = new ArrayList<RecordItem>(); |
| ... | ... | @@ -679,44 +683,63 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 679 | 683 | record.setRecorderId(XmlUtil.getText(itemRecord, "RecorderID")); |
| 680 | 684 | recordList.add(record); |
| 681 | 685 | } |
| 682 | - // recordList.sort(Comparator.naturalOrder()); | |
| 683 | 686 | recordInfo.setRecordList(recordList); |
| 684 | 687 | } |
| 685 | 688 | |
| 686 | - // 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回 | |
| 687 | - if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) { | |
| 688 | - // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分 | |
| 689 | - String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; | |
| 690 | - | |
| 691 | - redis.set(cacheKey + "_" + uuid, recordList, 90); | |
| 692 | - List<Object> cacheKeys = redis.scan(cacheKey + "_*"); | |
| 693 | - List<RecordItem> totalRecordList = new ArrayList<RecordItem>(); | |
| 694 | - for (int i = 0; i < cacheKeys.size(); i++) { | |
| 695 | - totalRecordList.addAll((List<RecordItem>) redis.get(cacheKeys.get(i).toString())); | |
| 689 | + // 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题 | |
| 690 | + String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; | |
| 691 | + redis.set(cacheKey + "_" + uuid, recordList, 90); | |
| 692 | + if (!threadNameList.contains(cacheKey)) { | |
| 693 | + threadNameList.add(cacheKey); | |
| 694 | + CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo); | |
| 695 | + chk.setName(cacheKey); | |
| 696 | + chk.setDeferredResultHolder(deferredResultHolder); | |
| 697 | + chk.setRedis(redis); | |
| 698 | + chk.setLogger(logger); | |
| 699 | + chk.start(); | |
| 700 | + if (logger.isDebugEnabled()) { | |
| 701 | + logger.debug("Start Thread " + cacheKey + "."); | |
| 696 | 702 | } |
| 697 | - if (totalRecordList.size() < recordInfo.getSumNum()) { | |
| 698 | - logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + recordInfo.getSumNum() + "项"); | |
| 699 | - return; | |
| 700 | - } | |
| 701 | - logger.info("录像数据已全部获取,共" + recordInfo.getSumNum() + "项"); | |
| 702 | - recordInfo.setRecordList(totalRecordList); | |
| 703 | - for (int i = 0; i < cacheKeys.size(); i++) { | |
| 704 | - redis.del(cacheKeys.get(i).toString()); | |
| 703 | + } else { | |
| 704 | + if (logger.isDebugEnabled()) { | |
| 705 | + logger.debug("Thread " + cacheKey + " already started."); | |
| 705 | 706 | } |
| 706 | 707 | } |
| 707 | - // 自然顺序排序, 元素进行升序排列 | |
| 708 | - recordInfo.getRecordList().sort(Comparator.naturalOrder()); | |
| 708 | + | |
| 709 | + // 存在录像且如果当前录像明细个数小于总条数,说明拆包返回,需要组装,暂不返回 | |
| 710 | + // if (recordInfo.getSumNum() > 0 && recordList.size() > 0 && recordList.size() < recordInfo.getSumNum()) { | |
| 711 | + // // 为防止连续请求该设备的录像数据,返回数据错乱,特增加sn进行区分 | |
| 712 | + // String cacheKey = CACHE_RECORDINFO_KEY + deviceId + sn; | |
| 713 | + | |
| 714 | + // redis.set(cacheKey + "_" + uuid, recordList, 90); | |
| 715 | + // List<Object> cacheKeys = redis.scan(cacheKey + "_*"); | |
| 716 | + // List<RecordItem> totalRecordList = new ArrayList<RecordItem>(); | |
| 717 | + // for (int i = 0; i < cacheKeys.size(); i++) { | |
| 718 | + // totalRecordList.addAll((List<RecordItem>) redis.get(cacheKeys.get(i).toString())); | |
| 719 | + // } | |
| 720 | + // if (totalRecordList.size() < recordInfo.getSumNum()) { | |
| 721 | + // logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + recordInfo.getSumNum() + "项"); | |
| 722 | + // return; | |
| 723 | + // } | |
| 724 | + // logger.info("录像数据已全部获取,共" + recordInfo.getSumNum() + "项"); | |
| 725 | + // recordInfo.setRecordList(totalRecordList); | |
| 726 | + // for (int i = 0; i < cacheKeys.size(); i++) { | |
| 727 | + // redis.del(cacheKeys.get(i).toString()); | |
| 728 | + // } | |
| 729 | + // } | |
| 730 | + // // 自然顺序排序, 元素进行升序排列 | |
| 731 | + // recordInfo.getRecordList().sort(Comparator.naturalOrder()); | |
| 709 | 732 | } |
| 710 | 733 | // 走到这里,有以下可能:1、没有录像信息,第一次收到recordinfo的消息即返回响应数据,无redis操作 |
| 711 | 734 | // 2、有录像数据,且第一次即收到完整数据,返回响应数据,无redis操作 |
| 712 | 735 | // 3、有录像数据,在超时时间内收到多次包组装后数量足够,返回数据 |
| 713 | 736 | |
| 714 | - RequestMessage msg = new RequestMessage(); | |
| 715 | - msg.setDeviceId(deviceId); | |
| 716 | - msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); | |
| 717 | - msg.setData(recordInfo); | |
| 718 | - deferredResultHolder.invokeResult(msg); | |
| 719 | - logger.info("处理完成,返回结果"); | |
| 737 | + // RequestMessage msg = new RequestMessage(); | |
| 738 | + // msg.setDeviceId(deviceId); | |
| 739 | + // msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); | |
| 740 | + // msg.setData(recordInfo); | |
| 741 | + // deferredResultHolder.invokeResult(msg); | |
| 742 | + // logger.info("处理完成,返回结果"); | |
| 720 | 743 | } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { |
| 721 | 744 | e.printStackTrace(); |
| 722 | 745 | } |
| ... | ... | @@ -799,4 +822,4 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { |
| 799 | 822 | public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { |
| 800 | 823 | this.redisCatchStorage = redisCatchStorage; |
| 801 | 824 | } |
| 802 | -} | |
| 825 | +} | |
| 803 | 826 | \ No newline at end of file | ... | ... |