hotcoffie
3 years ago
committed by
GitHub
79 changed files with 1163 additions and 1209 deletions
@ -0,0 +1,25 @@ |
|||||
|
package com.genersoft.iot.vmp.gb28181.event.device; |
||||
|
|
||||
|
import org.springframework.context.ApplicationEvent; |
||||
|
|
||||
|
import javax.sip.TimeoutEvent; |
||||
|
|
||||
|
/** |
||||
|
* @author lin |
||||
|
*/ |
||||
|
public class RequestTimeoutEvent extends ApplicationEvent { |
||||
|
public RequestTimeoutEvent(Object source) { |
||||
|
super(source); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private TimeoutEvent timeoutEvent; |
||||
|
|
||||
|
public TimeoutEvent getTimeoutEvent() { |
||||
|
return timeoutEvent; |
||||
|
} |
||||
|
|
||||
|
public void setTimeoutEvent(TimeoutEvent timeoutEvent) { |
||||
|
this.timeoutEvent = timeoutEvent; |
||||
|
} |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
package com.genersoft.iot.vmp.gb28181.event.device; |
||||
|
|
||||
|
import com.genersoft.iot.vmp.gb28181.bean.Device; |
||||
|
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; |
||||
|
import com.genersoft.iot.vmp.service.IDeviceService; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.context.ApplicationListener; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import javax.sip.ClientTransaction; |
||||
|
import javax.sip.address.SipURI; |
||||
|
import javax.sip.header.CallIdHeader; |
||||
|
import javax.sip.header.ToHeader; |
||||
|
import javax.sip.message.Request; |
||||
|
|
||||
|
/** |
||||
|
* @author lin |
||||
|
*/ |
||||
|
@Component |
||||
|
public class RequestTimeoutEventImpl implements ApplicationListener<RequestTimeoutEvent> { |
||||
|
|
||||
|
@Autowired |
||||
|
private IDeviceService deviceService; |
||||
|
|
||||
|
@Override |
||||
|
public void onApplicationEvent(RequestTimeoutEvent event) { |
||||
|
ClientTransaction clientTransaction = event.getTimeoutEvent().getClientTransaction(); |
||||
|
if (clientTransaction != null) { |
||||
|
Request request = clientTransaction.getRequest(); |
||||
|
if (request != null) { |
||||
|
String host = ((SipURI) request.getRequestURI()).getHost(); |
||||
|
int port = ((SipURI) request.getRequestURI()).getPort(); |
||||
|
Device device = deviceService.getDeviceByHostAndPort(host, port); |
||||
|
if (device == null) { |
||||
|
return; |
||||
|
} |
||||
|
deviceService.offline(device.getDeviceId()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,63 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.event.offline; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener; |
|
||||
import com.genersoft.iot.vmp.conf.UserSetting; |
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.data.redis.connection.Message; |
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|
||||
|
|
||||
/** |
|
||||
* @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月6日 上午11:35:46 |
|
||||
*/ |
|
||||
@Component |
|
||||
public class KeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener { |
|
||||
|
|
||||
private Logger logger = LoggerFactory.getLogger(KeepliveTimeoutListener.class); |
|
||||
|
|
||||
@Autowired |
|
||||
private EventPublisher publisher; |
|
||||
|
|
||||
@Autowired |
|
||||
private UserSetting userSetting; |
|
||||
|
|
||||
public KeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) { |
|
||||
super(listenerContainer, userSetting); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void init() { |
|
||||
if (!userSetting.getRedisConfig()) { |
|
||||
// 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用
|
|
||||
setKeyspaceNotificationsConfigParameter(""); |
|
||||
} |
|
||||
super.init(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 监听失效的key,key格式为keeplive_deviceId |
|
||||
* @param message |
|
||||
* @param pattern |
|
||||
*/ |
|
||||
@Override |
|
||||
public void onMessage(Message message, byte[] pattern) { |
|
||||
// 获取失效的key
|
|
||||
String expiredKey = message.toString(); |
|
||||
String KEEPLIVEKEY_PREFIX = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_"; |
|
||||
if(!expiredKey.startsWith(KEEPLIVEKEY_PREFIX)){ |
|
||||
logger.debug("收到redis过期监听,但开头不是"+KEEPLIVEKEY_PREFIX+",忽略"); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
String deviceId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length()); |
|
||||
publisher.outlineEventPublish(deviceId, VideoManagerConstants.EVENT_OUTLINE_TIMEOUT); |
|
||||
} |
|
||||
} |
|
@ -1,40 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.event.offline; |
|
||||
|
|
||||
import org.springframework.context.ApplicationEvent; |
|
||||
|
|
||||
/** |
|
||||
* @description: 离线事件类 |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月6日 上午11:33:13 |
|
||||
*/ |
|
||||
public class OfflineEvent extends ApplicationEvent { |
|
||||
|
|
||||
/** |
|
||||
* |
|
||||
*/ |
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
public OfflineEvent(Object source) { |
|
||||
super(source); |
|
||||
} |
|
||||
|
|
||||
private String deviceId; |
|
||||
|
|
||||
private String from; |
|
||||
|
|
||||
public String getDeviceId() { |
|
||||
return deviceId; |
|
||||
} |
|
||||
|
|
||||
public void setDeviceId(String deviceId) { |
|
||||
this.deviceId = deviceId; |
|
||||
} |
|
||||
|
|
||||
public String getFrom() { |
|
||||
return from; |
|
||||
} |
|
||||
|
|
||||
public void setFrom(String from) { |
|
||||
this.from = from; |
|
||||
} |
|
||||
} |
|
@ -1,98 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.event.offline; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.conf.UserSetting; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; |
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|
||||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; |
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService; |
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.context.ApplicationListener; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
|
||||
|
|
||||
import java.util.List; |
|
||||
|
|
||||
/** |
|
||||
* @description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源: |
|
||||
* 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor} |
|
||||
* 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener} |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月6日 下午1:51:23 |
|
||||
*/ |
|
||||
@Component |
|
||||
public class OfflineEventListener implements ApplicationListener<OfflineEvent> { |
|
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(OfflineEventListener.class); |
|
||||
|
|
||||
@Autowired |
|
||||
private IVideoManagerStorage storager; |
|
||||
|
|
||||
@Autowired |
|
||||
private VideoStreamSessionManager streamSession; |
|
||||
|
|
||||
@Autowired |
|
||||
private RedisUtil redis; |
|
||||
|
|
||||
@Autowired |
|
||||
private UserSetting userSetting; |
|
||||
|
|
||||
@Autowired |
|
||||
private EventPublisher eventPublisher; |
|
||||
|
|
||||
|
|
||||
@Autowired |
|
||||
private IMediaServerService mediaServerService; |
|
||||
|
|
||||
|
|
||||
@Autowired |
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory; |
|
||||
|
|
||||
@Override |
|
||||
public void onApplicationEvent(OfflineEvent event) { |
|
||||
|
|
||||
logger.info("设备离线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom()); |
|
||||
|
|
||||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_" + event.getDeviceId(); |
|
||||
|
|
||||
switch (event.getFrom()) { |
|
||||
// 心跳超时触发的离线事件,说明redis中已删除,无需处理
|
|
||||
case VideoManagerConstants.EVENT_OUTLINE_TIMEOUT: |
|
||||
break; |
|
||||
// 设备主动注销触发的离线事件,需要删除redis中的超时监听
|
|
||||
case VideoManagerConstants.EVENT_OUTLINE_UNREGISTER: |
|
||||
redis.del(key); |
|
||||
break; |
|
||||
default: |
|
||||
boolean exist = redis.hasKey(key); |
|
||||
if (exist) { |
|
||||
redis.del(key); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(event.getDeviceId()); |
|
||||
eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.OFF); |
|
||||
// 处理离线监听
|
|
||||
storager.outline(event.getDeviceId()); |
|
||||
|
|
||||
// TODO 离线取消订阅
|
|
||||
|
|
||||
// 离线释放所有ssrc
|
|
||||
List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(event.getDeviceId(), null, null, null); |
|
||||
if (ssrcTransactions != null && ssrcTransactions.size() > 0) { |
|
||||
for (SsrcTransaction ssrcTransaction : ssrcTransactions) { |
|
||||
mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); |
|
||||
mediaServerService.closeRTPServer(event.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); |
|
||||
streamSession.remove(event.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
@ -1,51 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.event.online; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|
||||
import org.springframework.context.ApplicationEvent; |
|
||||
|
|
||||
/** |
|
||||
* @description: 在线事件类 |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月6日 上午11:32:56 |
|
||||
*/ |
|
||||
public class OnlineEvent extends ApplicationEvent { |
|
||||
|
|
||||
/** |
|
||||
* |
|
||||
*/ |
|
||||
private static final long serialVersionUID = 1L; |
|
||||
|
|
||||
public OnlineEvent(Object source) { |
|
||||
super(source); |
|
||||
} |
|
||||
|
|
||||
private Device device; |
|
||||
|
|
||||
private String from; |
|
||||
|
|
||||
private int expires; |
|
||||
|
|
||||
public Device getDevice() { |
|
||||
return device; |
|
||||
} |
|
||||
|
|
||||
public void setDevice(Device device) { |
|
||||
this.device = device; |
|
||||
} |
|
||||
|
|
||||
public String getFrom() { |
|
||||
return from; |
|
||||
} |
|
||||
|
|
||||
public void setFrom(String from) { |
|
||||
this.from = from; |
|
||||
} |
|
||||
|
|
||||
public int getExpires() { |
|
||||
return expires; |
|
||||
} |
|
||||
|
|
||||
public void setExpires(int expires) { |
|
||||
this.expires = expires; |
|
||||
} |
|
||||
} |
|
@ -1,110 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.event.online; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.conf.SipConfig; |
|
||||
import com.genersoft.iot.vmp.conf.UserSetting; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher; |
|
||||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
|
||||
import com.genersoft.iot.vmp.service.IDeviceService; |
|
||||
import org.slf4j.Logger; |
|
||||
import org.slf4j.LoggerFactory; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.context.ApplicationListener; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants; |
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
|
||||
|
|
||||
import java.text.SimpleDateFormat; |
|
||||
import java.util.List; |
|
||||
|
|
||||
/** |
|
||||
* @description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源: |
|
||||
* 1、设备主动注销,发送注销指令 |
|
||||
* 2、设备未知原因离线,心跳超时 |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月6日 下午1:51:23 |
|
||||
*/ |
|
||||
@Component |
|
||||
public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
|
||||
|
|
||||
private final static Logger logger = LoggerFactory.getLogger(OnlineEventListener.class); |
|
||||
|
|
||||
@Autowired |
|
||||
private IVideoManagerStorage storager; |
|
||||
|
|
||||
@Autowired |
|
||||
private IDeviceService deviceService; |
|
||||
|
|
||||
@Autowired |
|
||||
private RedisUtil redis; |
|
||||
|
|
||||
@Autowired |
|
||||
private SipConfig sipConfig; |
|
||||
|
|
||||
@Autowired |
|
||||
private UserSetting userSetting; |
|
||||
|
|
||||
@Autowired |
|
||||
private EventPublisher eventPublisher; |
|
||||
|
|
||||
@Autowired |
|
||||
private SIPCommander cmder; |
|
||||
|
|
||||
|
|
||||
private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|
||||
|
|
||||
@Override |
|
||||
public void onApplicationEvent(OnlineEvent event) { |
|
||||
|
|
||||
logger.info("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom()); |
|
||||
Device device = event.getDevice(); |
|
||||
if (device == null) { |
|
||||
return; |
|
||||
} |
|
||||
String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_" + event.getDevice().getDeviceId(); |
|
||||
Device deviceInStore = storager.queryVideoDevice(device.getDeviceId()); |
|
||||
device.setOnline(1); |
|
||||
switch (event.getFrom()) { |
|
||||
// 注册时触发的在线事件,先在redis中增加超时超时监听
|
|
||||
case VideoManagerConstants.EVENT_ONLINE_REGISTER: |
|
||||
// 超时时间
|
|
||||
redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut()); |
|
||||
device.setRegisterTime(format.format(System.currentTimeMillis())); |
|
||||
if (deviceInStore == null) { //第一次上线
|
|
||||
logger.info("[{}] 首次注册,查询设备信息以及通道信息", device.getDeviceId()); |
|
||||
cmder.deviceInfoQuery(device); |
|
||||
deviceService.sync(device); |
|
||||
} |
|
||||
break; |
|
||||
// 设备主动发送心跳触发的在线事件
|
|
||||
case VideoManagerConstants.EVENT_ONLINE_KEEPLIVE: |
|
||||
boolean exist = redis.hasKey(key); |
|
||||
// 先判断是否还存在,当设备先心跳超时后又发送心跳时,redis没有监听,需要增加
|
|
||||
if (!exist) { |
|
||||
redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut()); |
|
||||
} else { |
|
||||
redis.expire(key, sipConfig.getKeepaliveTimeOut()); |
|
||||
} |
|
||||
device.setKeepaliveTime(format.format(System.currentTimeMillis())); |
|
||||
break; |
|
||||
// 设备主动发送消息触发的在线事件
|
|
||||
case VideoManagerConstants.EVENT_ONLINE_MESSAGE: |
|
||||
|
|
||||
break; |
|
||||
} |
|
||||
// 处理上线监听
|
|
||||
storager.updateDevice(device); |
|
||||
// 上线添加订阅
|
|
||||
if (device.getSubscribeCycleForCatalog() > 0) { |
|
||||
// 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
|
|
||||
deviceService.addCatalogSubscribe(device); |
|
||||
} |
|
||||
if (device.getSubscribeCycleForMobilePosition() > 0) { |
|
||||
deviceService.addMobilePositionSubscribe(device); |
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,91 @@ |
|||||
|
package com.genersoft.iot.vmp.gb28181.session; |
||||
|
|
||||
|
import com.genersoft.iot.vmp.gb28181.bean.*; |
||||
|
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
||||
|
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
||||
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.time.Instant; |
||||
|
import java.util.*; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
/** |
||||
|
* @author lin |
||||
|
*/ |
||||
|
@Component |
||||
|
public class RecordDataCatch { |
||||
|
|
||||
|
public static Map<String, RecordInfo> data = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
@Autowired |
||||
|
private DeferredResultHolder deferredResultHolder; |
||||
|
|
||||
|
|
||||
|
public int put(String deviceId, String sn, int sumNum, List<RecordItem> recordItems) { |
||||
|
String key = deviceId + sn; |
||||
|
RecordInfo recordInfo = data.get(key); |
||||
|
if (recordInfo == null) { |
||||
|
recordInfo = new RecordInfo(); |
||||
|
recordInfo.setDeviceId(deviceId); |
||||
|
recordInfo.setSn(sn.trim()); |
||||
|
recordInfo.setSumNum(sumNum); |
||||
|
recordInfo.setRecordList(Collections.synchronizedList(new ArrayList<>())); |
||||
|
recordInfo.setLastTime(Instant.now()); |
||||
|
recordInfo.getRecordList().addAll(recordItems); |
||||
|
data.put(key, recordInfo); |
||||
|
}else { |
||||
|
// 同一个设备的通道同步请求只考虑一个,其他的直接忽略
|
||||
|
if (!Objects.equals(sn.trim(), recordInfo.getSn())) { |
||||
|
return 0; |
||||
|
} |
||||
|
recordInfo.getRecordList().addAll(recordItems); |
||||
|
recordInfo.setLastTime(Instant.now()); |
||||
|
} |
||||
|
return recordInfo.getRecordList().size(); |
||||
|
} |
||||
|
|
||||
|
@Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时
|
||||
|
private void timerTask(){ |
||||
|
Set<String> keys = data.keySet(); |
||||
|
// 获取五秒前的时刻
|
||||
|
Instant instantBefore5S = Instant.now().minusMillis(TimeUnit.SECONDS.toMillis(5)); |
||||
|
for (String key : keys) { |
||||
|
RecordInfo recordInfo = data.get(key); |
||||
|
// 超过五秒收不到消息任务超时, 只更新这一部分数据
|
||||
|
if ( recordInfo.getLastTime().isBefore(instantBefore5S)) { |
||||
|
// 处理录像数据, 返回给前端
|
||||
|
String msgKey = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn(); |
||||
|
|
||||
|
WVPResult<RecordInfo> wvpResult = new WVPResult<>(); |
||||
|
wvpResult.setCode(0); |
||||
|
wvpResult.setMsg("success"); |
||||
|
// 对数据进行排序
|
||||
|
Collections.sort(recordInfo.getRecordList()); |
||||
|
wvpResult.setData(recordInfo); |
||||
|
|
||||
|
RequestMessage msg = new RequestMessage(); |
||||
|
msg.setKey(msgKey); |
||||
|
msg.setData(wvpResult); |
||||
|
deferredResultHolder.invokeAllResult(msg); |
||||
|
data.remove(key); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public boolean isComplete(String deviceId, String sn) { |
||||
|
RecordInfo recordInfo = data.get(deviceId + sn); |
||||
|
return recordInfo != null && recordInfo.getRecordList().size() == recordInfo.getSumNum(); |
||||
|
} |
||||
|
|
||||
|
public RecordInfo getRecordInfo(String deviceId, String sn) { |
||||
|
return data.get(deviceId + sn); |
||||
|
} |
||||
|
|
||||
|
public void remove(String deviceId, String sn) { |
||||
|
data.remove(deviceId + sn); |
||||
|
} |
||||
|
} |
@ -1,76 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.transmit.callback; |
|
||||
|
|
||||
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; |
|
||||
import com.genersoft.iot.vmp.gb28181.bean.RecordItem; |
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.RecordInfoResponseMessageHandler; |
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil; |
|
||||
import org.slf4j.Logger; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.Comparator; |
|
||||
import java.util.List; |
|
||||
import java.util.concurrent.TimeUnit; |
|
||||
|
|
||||
@SuppressWarnings("unchecked") |
|
||||
public class CheckForAllRecordsThread extends Thread { |
|
||||
|
|
||||
private String key; |
|
||||
|
|
||||
private RecordInfo recordInfo; |
|
||||
|
|
||||
private RedisUtil redis; |
|
||||
|
|
||||
private Logger logger; |
|
||||
|
|
||||
private DeferredResultHolder deferredResultHolder; |
|
||||
|
|
||||
public CheckForAllRecordsThread(String key, RecordInfo recordInfo) { |
|
||||
this.key = key; |
|
||||
this.recordInfo = recordInfo; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void run() { |
|
||||
|
|
||||
String cacheKey = this.key; |
|
||||
|
|
||||
for (long stop = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); stop > System.nanoTime();) { |
|
||||
List<Object> cacheKeys = redis.scan(cacheKey + "_*"); |
|
||||
List<RecordItem> totalRecordList = new ArrayList<RecordItem>(); |
|
||||
for (int i = 0; i < cacheKeys.size(); i++) { |
|
||||
totalRecordList.addAll((List<RecordItem>) redis.get(cacheKeys.get(i).toString())); |
|
||||
} |
|
||||
if (totalRecordList.size() < this.recordInfo.getSumNum()) { |
|
||||
logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + this.recordInfo.getSumNum() + "项"); |
|
||||
} else { |
|
||||
logger.info("录像数据已全部获取,共 {} 项", this.recordInfo.getSumNum()); |
|
||||
this.recordInfo.setRecordList(totalRecordList); |
|
||||
for (int i = 0; i < cacheKeys.size(); i++) { |
|
||||
redis.del(cacheKeys.get(i).toString()); |
|
||||
} |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
// 自然顺序排序, 元素进行升序排列
|
|
||||
this.recordInfo.getRecordList().sort(Comparator.naturalOrder()); |
|
||||
RequestMessage msg = new RequestMessage(); |
|
||||
msg.setKey(DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn()); |
|
||||
msg.setData(recordInfo); |
|
||||
deferredResultHolder.invokeAllResult(msg); |
|
||||
logger.info("处理完成,返回结果"); |
|
||||
RecordInfoResponseMessageHandler.threadNameList.remove(cacheKey); |
|
||||
} |
|
||||
|
|
||||
public void setRedis(RedisUtil redis) { |
|
||||
this.redis = redis; |
|
||||
} |
|
||||
|
|
||||
public void setDeferredResultHolder(DeferredResultHolder deferredResultHolder) { |
|
||||
this.deferredResultHolder = deferredResultHolder; |
|
||||
} |
|
||||
|
|
||||
public void setLogger(Logger logger) { |
|
||||
this.logger = logger; |
|
||||
} |
|
||||
|
|
||||
} |
|
@ -1,57 +0,0 @@ |
|||||
package com.genersoft.iot.vmp.gb28181.utils; |
|
||||
|
|
||||
import java.text.ParseException; |
|
||||
import java.text.SimpleDateFormat; |
|
||||
import java.util.Date; |
|
||||
import java.util.Locale; |
|
||||
|
|
||||
/** |
|
||||
* @description:时间工具类,主要处理ISO 8601格式转换 |
|
||||
* @author: swwheihei |
|
||||
* @date: 2020年5月8日 下午3:24:42 |
|
||||
*/ |
|
||||
public class DateUtil { |
|
||||
|
|
||||
//private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
|
|
||||
private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss"; |
|
||||
private static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; |
|
||||
|
|
||||
public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { |
|
||||
|
|
||||
SimpleDateFormat oldsdf = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()); |
|
||||
SimpleDateFormat newsdf = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()); |
|
||||
try { |
|
||||
return newsdf.format(oldsdf.parse(formatTime)); |
|
||||
} catch (ParseException e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return ""; |
|
||||
} |
|
||||
|
|
||||
public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) { |
|
||||
|
|
||||
SimpleDateFormat oldsdf = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()); |
|
||||
SimpleDateFormat newsdf = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()); |
|
||||
try { |
|
||||
return newsdf.format(oldsdf.parse(formatTime)); |
|
||||
} catch (ParseException e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return ""; |
|
||||
} |
|
||||
|
|
||||
public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) { |
|
||||
SimpleDateFormat format=new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss); |
|
||||
//设置要读取的时间字符串格式
|
|
||||
Date date; |
|
||||
try { |
|
||||
date = format.parse(formatTime); |
|
||||
Long timestamp=date.getTime()/1000; |
|
||||
//转换为Date类
|
|
||||
return timestamp; |
|
||||
} catch (ParseException e) { |
|
||||
e.printStackTrace(); |
|
||||
} |
|
||||
return 0; |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,58 @@ |
|||||
|
package com.genersoft.iot.vmp.utils; |
||||
|
|
||||
|
|
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.time.Instant; |
||||
|
import java.time.LocalDate; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.ZoneId; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.time.format.DateTimeParseException; |
||||
|
import java.time.temporal.TemporalAccessor; |
||||
|
|
||||
|
import java.util.Locale; |
||||
|
|
||||
|
/** |
||||
|
* 全局时间工具类 |
||||
|
* @author lin |
||||
|
*/ |
||||
|
public class DateUtil { |
||||
|
|
||||
|
private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss"; |
||||
|
public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; |
||||
|
|
||||
|
public static final SimpleDateFormat formatISO8601 = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()); |
||||
|
public static final SimpleDateFormat format = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()); |
||||
|
|
||||
|
public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()).withZone(ZoneId.systemDefault()); |
||||
|
public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()).withZone(ZoneId.systemDefault()); |
||||
|
|
||||
|
public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { |
||||
|
return formatterISO8601.format(formatter.parse(formatTime)); |
||||
|
} |
||||
|
|
||||
|
public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) { |
||||
|
return formatter.format(formatterISO8601.parse(formatTime)); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) { |
||||
|
TemporalAccessor temporalAccessor = formatter.parse(formatTime); |
||||
|
Instant instant = Instant.from(temporalAccessor); |
||||
|
return instant.getEpochSecond(); |
||||
|
} |
||||
|
|
||||
|
public static String getNow() { |
||||
|
LocalDateTime nowDateTime = LocalDateTime.now(); |
||||
|
return formatter.format(nowDateTime); |
||||
|
} |
||||
|
|
||||
|
public static boolean verification(String timeStr, DateTimeFormatter dateTimeFormatter) { |
||||
|
try { |
||||
|
LocalDate.parse(timeStr, dateTimeFormatter); |
||||
|
return true; |
||||
|
}catch (DateTimeParseException exception) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue