去除对redis key过期事件的使用;重构国标级联的注册保活

This commit is contained in:
648540858
2022-08-31 11:29:13 +08:00
parent d47902bdca
commit 2de4c322f6
45 changed files with 513 additions and 693 deletions

View File

@@ -2,9 +2,6 @@ package com.genersoft.iot.vmp.gb28181.event;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent;
import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformCycleRegisterEvent;
import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
@@ -31,36 +28,6 @@ public class EventPublisher {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
/**
* 平台心跳到期事件
* @param platformGbId
*/
public void platformKeepaliveExpireEventPublish(String platformGbId){
PlatformKeepaliveExpireEvent platformKeepaliveExpireEvent = new PlatformKeepaliveExpireEvent(this);
platformKeepaliveExpireEvent.setPlatformGbID(platformGbId);
applicationEventPublisher.publishEvent(platformKeepaliveExpireEvent);
}
/**
* 平台未注册事件
* @param platformGbId
*/
public void platformNotRegisterEventPublish(String platformGbId){
PlatformNotRegisterEvent platformNotRegisterEvent = new PlatformNotRegisterEvent(this);
platformNotRegisterEvent.setPlatformGbID(platformGbId);
applicationEventPublisher.publishEvent(platformNotRegisterEvent);
}
/**
* 平台周期注册事件
* @param paltformGbId
*/
public void platformRegisterCycleEventPublish(String paltformGbId) {
PlatformCycleRegisterEvent platformCycleRegisterEvent = new PlatformCycleRegisterEvent(this);
platformCycleRegisterEvent.setPlatformGbID(paltformGbId);
applicationEventPublisher.publishEvent(platformCycleRegisterEvent);
}
/**
* 设备报警事件

View File

@@ -59,9 +59,25 @@ public class SipSubscribe {
void response(EventResult eventResult);
}
/**
*
*/
public enum EventResultType{
// 超时
timeout,
// 回复
response,
// 事务已结束
transactionTerminated,
// 会话已结束
dialogTerminated,
// 设备未找到
deviceNotFoundEvent
}
public static class EventResult<EventObject>{
public int statusCode;
public String type;
public EventResultType type;
public String msg;
public String callId;
public Dialog dialog;
@@ -76,7 +92,7 @@ public class SipSubscribe {
ResponseEvent responseEvent = (ResponseEvent)event;
Response response = responseEvent.getResponse();
this.dialog = responseEvent.getDialog();
this.type = "response";
this.type = EventResultType.response;
if (response != null) {
this.msg = response.getReasonPhrase();
this.statusCode = response.getStatusCode();
@@ -85,28 +101,28 @@ public class SipSubscribe {
}else if (event instanceof TimeoutEvent) {
TimeoutEvent timeoutEvent = (TimeoutEvent)event;
this.type = "timeout";
this.type = EventResultType.timeout;
this.msg = "消息超时未回复";
this.statusCode = -1024;
this.dialog = timeoutEvent.getClientTransaction().getDialog();
this.callId = this.dialog != null?timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId(): null;
}else if (event instanceof TransactionTerminatedEvent) {
TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event;
this.type = "transactionTerminated";
this.type = EventResultType.transactionTerminated;
this.msg = "事务已结束";
this.statusCode = -1024;
this.callId = transactionTerminatedEvent.getClientTransaction().getDialog().getCallId().getCallId();
this.dialog = transactionTerminatedEvent.getClientTransaction().getDialog();
}else if (event instanceof DialogTerminatedEvent) {
DialogTerminatedEvent dialogTerminatedEvent = (DialogTerminatedEvent)event;
this.type = "dialogTerminated";
this.type = EventResultType.dialogTerminated;
this.msg = "会话已结束";
this.statusCode = -1024;
this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
this.dialog = dialogTerminatedEvent.getDialog();
}else if (event instanceof DeviceNotFoundEvent) {
DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event;
this.type = "deviceNotFoundEvent";
this.type = EventResultType.deviceNotFoundEvent;
this.msg = "设备未找到";
this.statusCode = -1024;
this.dialog = deviceNotFoundEvent.getDialog();

View File

@@ -1,81 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.offline;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.redis.RedisKeyExpirationEventMessageListener;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
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;
/**
* 设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author swwheihei
*/
@Component
public class KeepaliveTimeoutListenerForPlatform extends RedisKeyExpirationEventMessageListener {
private Logger logger = LoggerFactory.getLogger(KeepaliveTimeoutListenerForPlatform.class);
@Autowired
private EventPublisher publisher;
@Autowired
private UserSetting userSetting;
@Autowired
private SipSubscribe sipSubscribe;
@Autowired
private IVideoManagerStorage storager;
public KeepaliveTimeoutListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) {
super(listenerContainer, userSetting);
}
/**
* 监听失效的key
* @param message
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
// 获取失效的key
String expiredKey = message.toString();
// 平台心跳到期,需要重发, 判断是否已经多次未收到心跳回复, 多次未收到,则重新发起注册, 注册尝试多次未得到回复,则认为平台离线
String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.PLATFORM_KEEPALIVE_PREFIX + userSetting.getServerId() + "_";
String PLATFORM_REGISTER_PREFIX = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + userSetting.getServerId() + "_";
String REGISTER_INFO_PREFIX = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_";
if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) {
String platformGbId = expiredKey.substring(PLATFORM_KEEPLIVEKEY_PREFIX.length());
ParentPlatform platform = storager.queryParentPlatByServerGBId(platformGbId);
if (platform != null) {
publisher.platformKeepaliveExpireEventPublish(platformGbId);
}
}else if (expiredKey.startsWith(PLATFORM_REGISTER_PREFIX)) {
String platformGbId = expiredKey.substring(PLATFORM_REGISTER_PREFIX.length(),expiredKey.length());
ParentPlatform platform = storager.queryParentPlatByServerGBId(platformGbId);
if (platform != null) {
publisher.platformRegisterCycleEventPublish(platformGbId);
}
}else if (expiredKey.startsWith(REGISTER_INFO_PREFIX)) {
String callId = expiredKey.substring(REGISTER_INFO_PREFIX.length());
if (sipSubscribe.getErrorSubscribe(callId) != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult();
eventResult.callId = callId;
eventResult.msg = "注册超时";
eventResult.type = "register timeout";
sipSubscribe.getErrorSubscribe(callId).response(eventResult);
}
}
}
}

View File

@@ -1,28 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire;
import org.springframework.context.ApplicationEvent;
/**
* 平台心跳超时事件
*/
public class PlatformKeepaliveExpireEvent extends ApplicationEvent {
/**
* Add default serial version ID
*/
private static final long serialVersionUID = 1L;
private String platformGbID;
public PlatformKeepaliveExpireEvent(Object source) {
super(source);
}
public String getPlatformGbID() {
return platformGbID;
}
public void setPlatformGbID(String platformGbID) {
this.platformGbID = platformGbID;
}
}

View File

@@ -1,87 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.jetbrains.annotations.NotNull;
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 javax.sip.message.Response;
/**
* @description: 平台心跳超时事件
* @author: panll
* @date: 2020年11月5日 10:00
*/
@Component
public class PlatformKeepaliveExpireEventLister implements ApplicationListener<PlatformKeepaliveExpireEvent> {
private final static Logger logger = LoggerFactory.getLogger(PlatformKeepaliveExpireEventLister.class);
@Autowired
private IVideoManagerStorage storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ISIPCommanderForPlatform sipCommanderForPlatform;
@Autowired
private SipSubscribe sipSubscribe;
@Autowired
private EventPublisher publisher;
@Override
public void onApplicationEvent(@NotNull PlatformKeepaliveExpireEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("平台心跳到期事件事件触发平台国标ID" + event.getPlatformGbID());
}
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(event.getPlatformGbID());
if (parentPlatformCatch == null) {
return;
}
if (parentPlatform == null) {
logger.debug("平台心跳到期事件事件触发,但平台已经删除!!! 平台国标ID" + event.getPlatformGbID());
return;
}
parentPlatformCatch.setParentPlatform(parentPlatform);
// 发送心跳
if (parentPlatformCatch.getKeepAliveReply() >= 3) {
// 有3次未收到心跳回复, 设置平台状态为离线, 开始重新注册
logger.warn("有3次未收到心跳回复,标记设置平台状态为离线, 并重新注册 平台国标ID" + event.getPlatformGbID());
storager.updateParentPlatformStatus(event.getPlatformGbID(), false);
publisher.platformNotRegisterEventPublish(event.getPlatformGbID());
parentPlatformCatch.setKeepAliveReply(0);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
}else {
// 再次发送心跳
String callId = sipCommanderForPlatform.keepalive(parentPlatform);
parentPlatformCatch.setKeepAliveReply( parentPlatformCatch.getKeepAliveReply() + 1);
// 存储心跳信息, 并设置状态为未回复, 如果多次过期仍未收到回复,则认为上级平台已经离线
redisCatchStorage.updatePlatformKeepalive(parentPlatform);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
sipSubscribe.addOkSubscribe(callId, (SipSubscribe.EventResult eventResult) ->{
if (eventResult.statusCode == Response.OK) {
// 收到心跳响应信息,
parentPlatformCatch.setKeepAliveReply(0);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
}
} );
}
}
}

View File

@@ -1,24 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
import org.springframework.context.ApplicationEvent;
public class PlatformCycleRegisterEvent extends ApplicationEvent {
/**
* Add default serial version ID
*/
private static final long serialVersionUID = 1L;
private String platformGbID;
public String getPlatformGbID() {
return platformGbID;
}
public void setPlatformGbID(String platformGbID) {
this.platformGbID = platformGbID;
}
public PlatformCycleRegisterEvent(Object source) {
super(source);
}
}

View File

@@ -1,46 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
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 java.util.Timer;
import java.util.TimerTask;
@Component
public class PlatformCycleRegisterEventLister implements ApplicationListener<PlatformCycleRegisterEvent> {
private final static Logger logger = LoggerFactory.getLogger(PlatformCycleRegisterEventLister.class);
@Autowired
private IVideoManagerStorage storager;
@Autowired
private ISIPCommanderForPlatform sipCommanderFroPlatform;
@Autowired
private DynamicTask dynamicTask;
@Override
public void onApplicationEvent(PlatformCycleRegisterEvent event) {
logger.info("上级平台周期注册事件");
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
if (parentPlatform == null) {
logger.info("[ 平台未注册事件 ] 平台已经删除!!! 平台国标ID" + event.getPlatformGbID());
return;
}
String taskKey = "platform-cycle-register" + parentPlatform.getServerGBId();;
SipSubscribe.Event okEvent = (responseEvent)->{
dynamicTask.stop(taskKey);
};
dynamicTask.startCron(taskKey, ()->{
logger.info("[平台注册]再次向平台注册平台国标ID" + event.getPlatformGbID());
sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
}, Integer.parseInt(parentPlatform.getExpires())* 1000);
}
}

View File

@@ -1,25 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
import org.springframework.context.ApplicationEvent;
public class PlatformNotRegisterEvent extends ApplicationEvent {
/**
* Add default serial version ID
*/
private static final long serialVersionUID = 1L;
private String platformGbID;
public PlatformNotRegisterEvent(Object source) {
super(source);
}
public String getPlatformGbID() {
return platformGbID;
}
public void setPlatformGbID(String platformGbID) {
this.platformGbID = platformGbID;
}
}

View File

@@ -1,90 +0,0 @@
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
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 java.util.*;
/**
* @description: 平台未注册事件,来源有二:
* 1、平台新添加
* 2、平台心跳超时
* @author: panll
* @date: 2020年11月24日 10:00
*/
@Component
public class PlatformNotRegisterEventLister implements ApplicationListener<PlatformNotRegisterEvent> {
private final static Logger logger = LoggerFactory.getLogger(PlatformNotRegisterEventLister.class);
@Autowired
private IVideoManagerStorage storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private SIPCommanderFroPlatform sipCommanderFroPlatform;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private SipConfig config;
@Autowired
private DynamicTask dynamicTask;
// @Autowired
// private RedisUtil redis;
@Override
public void onApplicationEvent(PlatformNotRegisterEvent event) {
logger.info("[ 平台未注册事件 ]平台国标ID" + event.getPlatformGbID());
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
if (parentPlatform == null) {
logger.info("[ 平台未注册事件 ] 平台已经删除!!! 平台国标ID" + event.getPlatformGbID());
return;
}
// 查询是否有推流, 如果有则都停止
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(event.getPlatformGbID());
if (sendRtpItems != null && sendRtpItems.size() > 0) {
logger.info("[ 平台未注册事件 ] 停止[ {} ]的所有推流", event.getPlatformGbID());
for (SendRtpItem sendRtpItem : sendRtpItems) {
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId(), null, null);
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
Map<String, Object> param = new HashMap<>();
param.put("vhost", "__defaultVhost__");
param.put("app", sendRtpItem.getApp());
param.put("stream", sendRtpItem.getStreamId());
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
}
}
String taskKey = "platform-not-register-" + parentPlatform.getServerGBId();
SipSubscribe.Event okEvent = (responseEvent)->{
dynamicTask.stop(taskKey);
};
dynamicTask.startCron(taskKey, ()->{
logger.info("[平台注册]再次向平台注册平台国标ID" + event.getPlatformGbID());
sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
}, config.getRegisterTimeInterval()* 1000);
}
}

View File

@@ -30,23 +30,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
@Autowired
private IVideoManagerStorage storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private SIPCommanderFroPlatform sipCommanderFroPlatform;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private SipConfig config;
@Autowired
private UserSetting userSetting;
@Autowired
private IGbStreamService gbStreamService;