Merge branch 'wvp-28181-2.0' into main-dev

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
This commit is contained in:
648540858 2023-09-11 11:21:50 +08:00
commit 88350873ee
365 changed files with 3884 additions and 2745 deletions

View File

@ -153,7 +153,7 @@ user-settings:
# 国标是否录制
record-sip: true
# 是否将日志存储进数据库
logInDatebase: true
logInDatabase: true
# 第三方匹配用于从stream钟获取有效信息
thirdPartyGBIdReg: [\s\S]*
```

View File

@ -159,7 +159,9 @@ public class VideoManagerConstants {
public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_";
public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_";
public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_";
public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_";
/**
* Redis Const

View File

@ -51,7 +51,7 @@ public class ApiAccessFilter extends OncePerRequestFilter {
filterChain.doFilter(servletRequest, servletResponse);
if (uriName != null && userSetting != null && userSetting.getLogInDatebase() != null && userSetting.getLogInDatebase()) {
if (uriName != null && userSetting != null && userSetting.getLogInDatabase() != null && userSetting.getLogInDatabase()) {
LogDto logDto = new LogDto();
logDto.setName(uriName);

View File

@ -12,7 +12,10 @@ import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ObjectUtils;
import java.io.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.util.Map;

View File

@ -111,7 +111,7 @@ public class DynamicTask {
}
boolean result = false;
if (!ObjectUtils.isEmpty(futureMap.get(key)) && !futureMap.get(key).isCancelled() && !futureMap.get(key).isDone()) {
result = futureMap.get(key).cancel(true);
result = futureMap.get(key).cancel(false);
futureMap.remove(key);
runnableMap.remove(key);
}
@ -143,7 +143,8 @@ public class DynamicTask {
public void execute(){
if (futureMap.size() > 0) {
for (String key : futureMap.keySet()) {
if (futureMap.get(key).isDone() || futureMap.get(key).isCancelled()) {
ScheduledFuture<?> future = futureMap.get(key);
if (future.isDone() || future.isCancelled()) {
futureMap.remove(key);
runnableMap.remove(key);
}

View File

@ -18,6 +18,7 @@ import org.springframework.util.ObjectUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.ConnectException;
@ -64,6 +65,18 @@ public class ProxyServletConfig {
return queryStr;
}
@Override
protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,
HttpRequest proxyRequest) throws IOException {
HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
response.removeHeaders("Access-Control-Allow-Origin");
response.setHeader("Access-Control-Allow-Credentials","true");
response.removeHeaders("Access-Control-Allow-Credentials");
return response;
}
/**
* 异常处理
*/
@ -181,6 +194,18 @@ public class ProxyServletConfig {
return queryStr;
}
@Override
protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,
HttpRequest proxyRequest) throws IOException {
HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
String origin = servletRequest.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin",origin);
response.setHeader("Access-Control-Allow-Credentials","true");
return response;
}
/**
* 异常处理
*/

View File

@ -4,8 +4,11 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.service.IPlatformService;
import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
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.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
@ -33,6 +36,7 @@ public class SipPlatformRunner implements CommandLineRunner {
@Autowired
private ISIPCommanderForPlatform sipCommanderForPlatform;
private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
@Override
public void run(String... args) throws Exception {
@ -50,9 +54,15 @@ public class SipPlatformRunner implements CommandLineRunner {
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
if (parentPlatformCatchOld != null) {
// 取消订阅
sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
platformService.login(parentPlatform);
});
try {
sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
platformService.login(parentPlatform);
});
} catch (Exception e) {
logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
platformService.offline(parentPlatform, true);
continue;
}
}
// 设置所有平台离线

View File

@ -31,7 +31,7 @@ public class UserSetting {
private Boolean recordSip = Boolean.TRUE;
private Boolean logInDatebase = Boolean.TRUE;
private Boolean logInDatabase = Boolean.TRUE;
private Boolean usePushingAsStatus = Boolean.FALSE;
@ -134,12 +134,12 @@ public class UserSetting {
this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes;
}
public Boolean getLogInDatebase() {
return logInDatebase;
public Boolean getLogInDatabase() {
return logInDatabase;
}
public void setLogInDatebase(Boolean logInDatebase) {
this.logInDatebase = logInDatebase;
public void setLogInDatabase(Boolean logInDatabase) {
this.logInDatabase = logInDatabase;
}
public String getServerId() {

View File

@ -1,8 +1,10 @@
package com.genersoft.iot.vmp.conf.security;
import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
import org.jose4j.json.JsonUtil;
import com.genersoft.iot.vmp.service.IUserService;
import com.genersoft.iot.vmp.storager.dao.dto.User;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
@ -14,45 +16,69 @@ import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.lang.JoseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.security.PrivateKey;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
public class JwtUtils {
@Component
public class JwtUtils implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
private static final String HEADER = "access-token";
private static final String AUDIENCE = "Audience";
private static final long EXPIRED_THRESHOLD = 10 * 60;
private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
private static final String privateKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\",\"d\":\"ed7U_k3rJ4yTk70JtRSIfjKGiEb67BO1TabcymnljKO7RU8nage84zZYuSu_XpQsHk6P1f0Gzxkicghm_Er-FrfVn2pp70Xu52z3yRd6BJUgWLDFk97ngScIyw5OiULKU9SrZk2frDpftNCSUcIgb50F8m0QAnBa_CdPsQKbuuhLv8V8tBAV7F_lAwvSBgu56wRo3hPz5dWH8YeXM7XBfQ9viFMNEKd21sP_j5C7ueUnXT66nBxe3ZJEU3iuMYM6D6dB_KW2GfZC6WmTgvGhhxJD0h7aYmfjkD99MDleB7SkpbvoODOqiQ5Epb7Nyh6kv5u4KUv2CJYtATLZkUeMkQ\",\"p\":\"uBUjWPWtlGksmOqsqCNWksfqJvMcnP_8TDYN7e4-WnHL4N-9HjRuPDnp6kHvCIEi9SEfxm7gNxlRcWegvNQr3IZCz7TnCTexXc5NOklB9OavWFla6u-s3Thn6Tz45-EUjpJr0VJMxhO-KxGmuTwUXBBp4vN6K2qV6rQNFmgkWzk\",\"q\":\"tW_i7cCec56bHkhITL_79dXHz_PLC_f7xlynmlZJGU_d6mqOKmLBNBbTMLnYW8uAFiFzWxDeDHh1o5uF0mSQR-Z1Fg35OftnpbWpy0Cbc2la5WgXQjOwtG1eLYIY2BD3-wQ1VYDBCvowr4FDi-sngxwLqvwmrJ0xjhi99O-Gzcs\",\"dp\":\"q1d5jE85Hz_6M-eTh_lEluEf0NtPEc-vvhw-QO4V-cecNpbrCBdTWBmr4dE3NdpFeJc5ZVFEv-SACyei1MBEh0ItI_pFZi4BmMfy2ELh8ptaMMkTOESYyVy8U7veDq9RnBcr5i1Nqr0rsBkA77-9T6gzdvycBZdzLYAkAmwzEvk\",\"dq\":\"q29A2K08Crs-jmp2Bi8Q_8QzvIX6wSBbwZ4ir24AO-5_HNP56IrPS0yV2GCB0pqCOGb6_Hz_koDvhtuYoqdqvMVAtMoXR3YJBUaVXPt65p4RyNmFwIPe31zHs_BNUTsXVRMw4c16mci03-Af1sEm4HdLfxAp6sfM3xr5wcnhcek\",\"qi\":\"rHPgVTyHUHuYzcxfouyBfb1XAY8nshwn0ddo81o1BccD4Z7zo5It6SefDHjxCAbcmbiCcXBSooLcY-NF5FMv3fg19UE21VyLQltHcVjRRp2tRs4OHcM8yaXIU2x6N6Z6BP2tOksHb9MOBY1wAQzFOAKg_G4Sxev6-_6ud6RISuc\"}";
private static final String publicKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\"}";
/**
* token过期时间(分钟)
*/
public static final long expirationTime = 30;
public static final long expirationTime = 30 * 24 * 60;
public static String createToken(String username, String password, Integer roleId) {
private static RsaJsonWebKey rsaJsonWebKey;
private static IUserService userService;
@Resource
public void setUserService(IUserService userService) {
JwtUtils.userService = userService;
}
@Override
public void afterPropertiesSet() {
try {
/**
rsaJsonWebKey = generateRsaJsonWebKey();
} catch (JoseException e) {
logger.error("生成RsaJsonWebKey报错。", e);
}
}
/**
* 创建密钥对
* @throws JoseException JoseException
*/
private RsaJsonWebKey generateRsaJsonWebKey() throws JoseException {
// 生成一个RSA密钥对该密钥对将用于JWT的签名和验证包装在JWK中
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
// 给JWK一个密钥ID
rsaJsonWebKey.setKeyId(keyId);
return rsaJsonWebKey;
}
public static String createToken(String username) {
try {
/*
* iss (issuer) 发行人
*
* sub (subject) 主题
*
* aud (audience) 接收方 用户
*
* exp (expiration time) 到期时间
*
* nbf (not before) 在此之前不可用
*
* iat (issued at) jwt的签发时间
*/
//Payload
JwtClaims claims = new JwtClaims();
claims.setGeneratedJwtId();
claims.setIssuedAtToNow();
@ -62,9 +88,7 @@ public class JwtUtils {
claims.setSubject("login");
claims.setAudience(AUDIENCE);
//添加自定义参数,必须是字符串类型
claims.setClaim("username", username);
claims.setClaim("password", password);
claims.setClaim("roleId", roleId);
claims.setClaim("userName", username);
//jws
JsonWebSignature jws = new JsonWebSignature();
@ -73,12 +97,10 @@ public class JwtUtils {
jws.setKeyIdHeaderValue(keyId);
jws.setPayload(claims.toJson());
PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyStr)).getPrivateKey();
jws.setKey(privateKey);
jws.setKey(rsaJsonWebKey.getPrivateKey());
//get token
String idToken = jws.getCompactSerialization();
return idToken;
return jws.getCompactSerialization();
} catch (JoseException e) {
logger.error("[Token生成失败] {}", e.getMessage());
}
@ -90,7 +112,6 @@ public class JwtUtils {
return HEADER;
}
public static JwtUser verifyToken(String token) {
JwtUser jwtUser = new JwtUser();
@ -103,7 +124,7 @@ public class JwtUtils {
.setRequireSubject()
//.setExpectedIssuer("")
.setExpectedAudience(AUDIENCE)
.setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
.setVerificationKey(rsaJsonWebKey.getPublicKey())
.build();
JwtClaims claims = consumer.processToClaims(token);
@ -113,26 +134,26 @@ public class JwtUtils {
long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
if (timeRemaining < 5 * 60) {
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
}else {
} else {
jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
}
String username = (String) claims.getClaimValue("username");
String password = (String) claims.getClaimValue("password");
Long roleId = (Long) claims.getClaimValue("roleId");
String username = (String) claims.getClaimValue("userName");
User user = userService.getUserByUsername(username);
jwtUser.setUserName(username);
jwtUser.setPassword(password);
jwtUser.setRoleId(roleId.intValue());
jwtUser.setPassword(user.getPassword());
jwtUser.setRoleId(user.getRole().getId());
return jwtUser;
} catch (InvalidJwtException e) {
if (e.hasErrorCode(ErrorCodes.EXPIRED)) {
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
}else {
} else {
jwtUser.setStatus(JwtUser.TokenStatus.EXCEPTION);
}
return jwtUser;
}catch (Exception e) {
} catch (Exception e) {
logger.error("[Token解析失败] {}", e.getMessage());
jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
return jwtUser;

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

@ -2,12 +2,9 @@ package com.genersoft.iot.vmp.gb28181.bean;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.service.IPlatformService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -24,6 +21,9 @@ public class SubscribeHolder {
@Autowired
private DynamicTask dynamicTask;
@Autowired
private UserSetting userSetting;
private final String taskOverduePrefix = "subscribe_overdue_";
private static ConcurrentHashMap<String, SubscribeInfo> catalogMap = new ConcurrentHashMap<>();
@ -58,7 +58,7 @@ public class SubscribeHolder {
public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) {
mobilePositionMap.put(platformId, subscribeInfo);
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + "MobilePosition_" + platformId;
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "MobilePosition_" + platformId;
// 添加任务处理GPS定时推送
dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(platformId),
subscribeInfo.getGpsInterval() * 1000);
@ -76,7 +76,7 @@ public class SubscribeHolder {
public void removeMobilePositionSubscribe(String platformId) {
mobilePositionMap.remove(platformId);
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + "MobilePosition_" + platformId;
String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "MobilePosition_" + platformId;
// 结束任务处理GPS定时推送
dynamicTask.stop(key);
String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId;

View File

View File

View File

View File

View File

View File

View File

View File

View File

@ -12,13 +12,19 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IPlatformService;
import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
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.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -59,6 +65,8 @@ public class SipRunner implements CommandLineRunner {
@Autowired
private ISIPCommanderForPlatform commanderForPlatform;
private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
@Override
public void run(String... args) throws Exception {
List<Device> deviceList = deviceService.getAllOnlineDevice();
@ -110,7 +118,11 @@ public class SipRunner implements CommandLineRunner {
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
if (platform != null) {
commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId());
try {
commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId());
} catch (InvalidArgumentException | ParseException | SipException e) {
logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
}
}
}
}

View File

@ -25,6 +25,8 @@ public interface ISIPCommanderForPlatform {
void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
/**

View File

@ -21,10 +21,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.*;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@ -83,6 +80,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IInviteStreamService inviteStreamService;
@Autowired
private SSRCFactory ssrcFactory;
@ -518,10 +518,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
errorEvent.run(code, msg, data);
}
});
}else {
} else {
SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode()){
if (code == InviteErrorCode.SUCCESS.getCode()) {
hookEvent.run(code, msg, data);
} else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
logger.info("[上级点播]超时, 用户:{} 通道:{}", username, channelId);

View File

@ -132,7 +132,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
if (CmdType.CATALOG.equals(cmd)) {
logger.info("接收到Catalog通知");
// processNotifyCatalogList(take.getEvt());
processNotifyCatalogList(take.getEvt());
notifyRequestForCatalogProcessor.process(take.getEvt());
} else if (CmdType.ALARM.equals(cmd)) {
logger.info("接收到Alarm通知");
@ -319,6 +319,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
logger.info("[收到Notify-Alarm]{}/{}", device.getDeviceId(), deviceAlarm.getChannelId());
if ("4".equals(deviceAlarm.getAlarmMethod())) {
MobilePosition mobilePosition = new MobilePosition();
mobilePosition.setChannelId(channelId);
mobilePosition.setCreateTime(DateUtil.getNow());
mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
mobilePosition.setTime(deviceAlarm.getAlarmTime());

View File

@ -88,7 +88,11 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
Response response = null;
boolean passwordCorrect = false;
// 注册标志
boolean registerFlag;
boolean registerFlag = true;
if (request.getExpires().getExpires() == 0) {
// 注销成功
registerFlag = false;
}
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
@ -99,11 +103,12 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
userSetting.getSipUseSourceIpAsRemoteAddress());
String requestAddress = remoteAddressInfo.getIp() + ":" + remoteAddressInfo.getPort();
logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress);
String title = registerFlag ? "[注册请求]": "[注销请求]";
logger.info(title + "设备:{}, 开始处理: {}", deviceId, requestAddress);
if (device != null &&
device.getSipTransactionInfo() != null &&
request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
logger.info("[注册请求] 设备:{}, 注册续订: {}",device.getDeviceId(), device.getDeviceId());
logger.info(title + "设备:{}, 注册续订: {}",device.getDeviceId(), device.getDeviceId());
device.setExpires(request.getExpires().getExpires());
device.setIp(remoteAddressInfo.getIp());
device.setPort(remoteAddressInfo.getPort());
@ -123,7 +128,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword();
AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
if (authHead == null && !ObjectUtils.isEmpty(password)) {
logger.info("[注册请求] 设备:{}, 回复401: {}",deviceId, requestAddress);
logger.info(title + " 设备:{}, 回复401: {}",deviceId, requestAddress);
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
@ -138,7 +143,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
// 注册失败
response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
response.setReasonPhrase("wrong password");
logger.info("[注册请求] 设备:{}, 密码/SIP服务器ID错误, 回复403: {}", deviceId, requestAddress);
logger.info(title + " 设备:{}, 密码/SIP服务器ID错误, 回复403: {}", deviceId, requestAddress);
sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
return;
}

View File

@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import gov.nist.javax.sip.message.SIPRequest;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -24,6 +23,9 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
public Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
@Autowired
private IVideoManagerStorage storage;
public void addHandler(String cmdType, IMessageHandler messageHandler) {
messageHandlerMap.put(cmdType, messageHandler);
}
@ -40,7 +42,15 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
return;
}
IMessageHandler messageHandler = messageHandlerMap.get(cmd);
if (messageHandler != null) {
//两个国标平台互相级联时由于上一步判断导致本该在平台处理的消息 放到了设备的处理逻辑
//所以对目录查询单独做了校验
if(messageHandler instanceof CatalogQueryMessageHandler){
ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(device.getDeviceId());
messageHandler.handForPlatform(evt, parentPlatform, element);
return;
}
messageHandler.handForDevice(evt, device, element);
}
}

View File

@ -137,6 +137,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
MobilePosition mobilePosition = new MobilePosition();
mobilePosition.setCreateTime(DateUtil.getNow());
mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
mobilePosition.setChannelId(channelId);
mobilePosition.setTime(deviceAlarm.getAlarmTime());
mobilePosition.setLongitude(deviceAlarm.getLongitude());
mobilePosition.setLatitude(deviceAlarm.getLatitude());

View File

@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.service.IDeviceService;
import com.genersoft.iot.vmp.utils.DateUtil;
import gov.nist.javax.sip.message.SIPRequest;
import org.apache.commons.lang3.ObjectUtils;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -68,7 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
} catch (SipException | InvalidArgumentException | ParseException e) {
logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
}
if (device.getKeepaliveTime() != null && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){
if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) {
logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
return;
}
@ -109,7 +110,11 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
// 不会收到上级平台的心跳信息
// 个别平台保活不回复200OK会判定离线
try {
responseAck((SIPRequest) evt.getRequest(), Response.OK);
} catch (SipException | InvalidArgumentException | ParseException e) {
logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
}
}
}

View File

@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 目录查询的回复
@ -61,6 +62,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
@Autowired
private SipConfig sipConfig;
private AtomicBoolean processing = new AtomicBoolean(false);
@Override
public void afterPropertiesSet() throws Exception {
@ -69,7 +71,6 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
boolean isEmpty = taskQueue.isEmpty();
taskQueue.offer(new HandlerCatchData(evt, device, element));
// 回复200 OK
try {
@ -77,8 +78,8 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
} catch (SipException | InvalidArgumentException | ParseException e) {
logger.error("[命令发送失败] 目录查询回复: {}", e.getMessage());
}
// 如果不为空则说明已经开启消息处理
if (isEmpty) {
// 已经开启消息处理则跳过
if (processing.compareAndSet(false, true)) {
taskExecutor.execute(() -> {
while (!taskQueue.isEmpty()) {
// 全局异常捕获保证下一条可以得到处理
@ -147,11 +148,12 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
}
}
}catch (Exception e) {
} catch (Exception e) {
logger.warn("[收到通道] 发现未处理的异常, \r\n{}", evt.getRequest());
logger.error("[收到通道] 异常内容: ", e);
}
}
processing.set(false);
});
}

Some files were not shown because too many files have changed in this diff Show More