ard-work/src/main/java/com/ruoyi/device/camera/factory/CameraSDK.java
@@ -11,7 +11,7 @@ import java.util.Map; /** * 相机SDK策略接口 * 相机SDK策略接口 * 刘苏义 * 2023/11/7 10:48:52 */ @@ -73,6 +73,7 @@ //抓图 String picCutCate(CameraCmd cmd); //获取ptz AjaxResult getPtz(CameraCmd cmd); ard-work/src/main/java/com/ruoyi/device/camera/service/ICameraSdkService.java
@@ -3,6 +3,7 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.device.camera.domain.ArdCameras; import com.ruoyi.device.camera.domain.CameraCmd; import java.util.Map; public interface ICameraSdkService { ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java
@@ -73,7 +73,6 @@ @PostConstruct public void loadCameras() { //清理本地录像缓存文件 String tempPath = ARDConfig.getProfile() + Constants.LOCAL_RECORD_TEMP_PREFIX; FileUtils.deleteFolder(tempPath); @@ -85,6 +84,8 @@ for (ArdCameras ardCamera : ardCameras) { redisCache.setCacheObject(getCacheKey(ardCamera.getId()), ardCamera); } //清空通道 ardChannelMapper.clearArdChannel(); //清空流媒体 vtduService.clearVtdu(); } ard-work/src/main/java/com/ruoyi/device/camera/service/impl/CameraSdkServiceImpl.java
@@ -33,6 +33,9 @@ import javax.annotation.Resource; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -70,6 +73,23 @@ ardCamerasService.resetCameraLoginId(); List<ArdCameras> ardCameras = ardCamerasService.selectArdCamerasListNoDataScope(new ArdCameras()); ardCameras.stream().forEach(ardCamera -> asyncLogin(ardCamera)); //开启登录失败相机重连定时任务 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { log.info("开始执行登录失败相机重连定时任务"); List<Object> ardCameras = redisCache.getListKey(CacheConstants.CAMERA_LIST_KEY); ardCameras.stream() .map(object -> (ArdCameras) object) // 将Object转换为ArdCameras .filter(camera -> !GlobalVariable.loginMap.containsKey(camera.getId())) .forEach(camera -> asyncLogin(camera)); } catch (Exception ex) { log.error("重连相机异常:" + ex.getMessage()); } } }, 30, 30, TimeUnit.SECONDS); // 任务延迟 } catch (Exception ex) { log.error("初始化登录相机异常:" + ex.getMessage()); } ard-work/src/main/java/com/ruoyi/device/channel/mapper/ArdChannelMapper.java
@@ -66,4 +66,11 @@ * @return 结果 */ public int deleteArdChannelByDeviceId(String deviceId); /** * 清空通道 * * @author 刘苏义 * @date 2024/8/10 11:18 */ public int clearArdChannel(); } ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java
@@ -7,15 +7,14 @@ /** * 通道管理Service接口 * * * @author ard * @date 2023-08-19 */ public interface IArdChannelService { public interface IArdChannelService { /** * 查询通道管理 * * * @param id 通道管理主键 * @return 通道管理 */ @@ -23,7 +22,7 @@ /** * 查询通道管理列表 * * * @param ardChannel 通道管理 * @return 通道管理集合 */ @@ -31,7 +30,7 @@ /** * 新增通道管理 * * * @param ardChannel 通道管理 * @return 结果 */ @@ -39,7 +38,7 @@ /** * 修改通道管理 * * * @param ardChannel 通道管理 * @return 结果 */ @@ -47,7 +46,7 @@ /** * 批量删除通道管理 * * * @param ids 需要删除的通道管理主键集合 * @return 结果 */ @@ -55,25 +54,34 @@ /** * 删除通道管理信息 * * * @param id 通道管理主键 * @return 结果 */ public int deleteArdChannelById(String id); /** * 删除通道管理信息 * * @param deviceId 所属设备ID * @return 结果 */ public int deleteArdChannelByDeviceId(String deviceId); public int deleteArdChannelByDeviceId(String deviceId); /** * 清空通道 * * @author 刘苏义 * @date 2024/8/10 11:18 */ public int clearArdChannel(); /** * @return * @Author 刘苏义 * @Description 同步通道信息 * @Date 2024/7/10 13:20 * @Param * @return */ public void asyncChannel(ArdCameras ardCameras, List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList); } ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -6,12 +6,7 @@ import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.device.camera.domain.ArdCameras; import com.ruoyi.device.camera.factory.CameraSDK; import com.ruoyi.device.camera.factory.CameraSDKFactory; import com.ruoyi.device.camera.mapper.ArdCamerasMapper; import com.ruoyi.media.mapper.VtduMapper; import com.ruoyi.media.service.IVtduService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.device.channel.mapper.ArdChannelMapper; import com.ruoyi.device.channel.domain.ArdChannel; @@ -29,8 +24,6 @@ public class ArdChannelServiceImpl implements IArdChannelService { @Resource private ArdChannelMapper ardChannelMapper; @Resource private CameraSDKFactory cameraSDKFactory; @Resource private IVtduService vtduService; /** @@ -101,6 +94,16 @@ } /** * 清空通道 * * @author 刘苏义 * @date 2024/8/10 11:18 */ @Override public int clearArdChannel(){ return ardChannelMapper.clearArdChannel(); } /** * 删除通道管理信息 * * @param deviceId 所属设备ID ard-work/src/main/java/com/ruoyi/utils/sdk/common/GlobalVariable.java
@@ -5,8 +5,11 @@ import lombok.Data; import org.ehcache.impl.internal.concurrent.ConcurrentHashMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** * @ClassName: globalVariable @@ -18,14 +21,14 @@ @Data public class GlobalVariable { //保存相机登录信息 public static Map<String, Object> loginMap = new HashMap<>(); public static Map<String, Object> loginMap = new ConcurrentHashMap<>(); //相机预览字典 public static Map<String, Integer> previewMap = new HashMap<>(); public static Map<String, Integer> previewMap = new ConcurrentHashMap<>(); //线程字典 public static Map<String, String> threadMap = new HashMap<>(); public static Map<String, String> threadMap = new ConcurrentHashMap<>(); //保存相机登录信息(loginId:Camera) public static Map<Integer, Object> loginCameraMap = new HashMap<>(); public static Map<Integer, Object> loginCameraMap = new ConcurrentHashMap<>(); //登录过相机集合 public static ConcurrentHashSet<ArdCameras> loginedSet = new ConcurrentHashSet<>(); } ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java
@@ -37,6 +37,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.io.*; import java.nio.file.Files; @@ -80,6 +81,11 @@ // 网络连接恢复 private static HaveReConnect haveReConnect = new HaveReConnect(); @PostConstruct public void initSdk() { log.info("初始化大华sdk"); LoginModule.init(disConnect, haveReConnect); } /** * 登录 @@ -91,7 +97,6 @@ @Override public AjaxResult login(ArdCameras camera) { try { LoginModule.init(disConnect, haveReConnect); NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex(); NetSDKLib.LLong loginId = LoginModule.login(camera.getIp(), camera.getPort(), camera.getUsername(), camera.getPassword(), m_stDeviceInfo); if (loginId.longValue() <= 0) { @@ -101,7 +106,7 @@ ardCamerasService.updateArdCameras(camera); //删除管理通道 ardChannelService.deleteArdChannelByDeviceId(camera.getId()); log.error("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败:" + getErrorCodePrint()); log.warn("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败:" + getErrorCodePrint()); return AjaxResult.warn(ErrorCode.getErrorCode(LoginModule.netsdk.CLIENT_GetLastError())); } log.debug("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录成功:" + (int) loginId.longValue()); @@ -137,7 +142,6 @@ @Async("globalExecutor") public AjaxResult asyncLogin(ArdCameras camera) { try { LoginModule.init(disConnect, haveReConnect); NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex(); NetSDKLib.LLong loginId = LoginModule.login(camera.getIp(), camera.getPort(), camera.getUsername(), camera.getPassword(), m_stDeviceInfo); if (loginId.longValue() <= 0) { @@ -147,7 +151,7 @@ ardCamerasService.updateArdCameras(camera); //删除管理通道 ardChannelService.deleteArdChannelByDeviceId(camera.getId()); log.error("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败:" + getErrorCodePrint()); log.warn("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败:" + getErrorCodePrint()); return AjaxResult.warn(getErrorCodePrint()); } log.debug("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录成功:" + loginId); ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java
@@ -29,11 +29,10 @@ import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.io.*; import java.math.BigDecimal; @@ -65,9 +64,37 @@ private QueueHandler queueHandler; @Resource ICameraSdkService cameraSdkService; public Object _lock = new Object(); public static HCNetSDK hCNetSDK = HCNetSDK.hCNetSDK; private static HCNetSDK.FExceptionCallBack fExceptionCallBack;//异常回调 @PostConstruct public void initSdk() { log.info("初始化海康sdk"); // 初始化 if (!hCNetSDK.NET_DVR_Init()) { log.debug("SDK初始化失败"); } //打印海康sdk日志 if (Platform.isWindows()) { String WIN_PATH = System.getProperty("user.dir") + File.separator + "ardLog" + File.separator + "logs" + File.separator; hCNetSDK.NET_DVR_SetLogToFile(3, WIN_PATH, true); } else { hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog", true); } if (fExceptionCallBack == null) { fExceptionCallBack = new ExceptionCallBack();//异常回调 //设置异常回调函数(可在回调函数中获取设备上下线状态等) if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, null)) { log.debug("Set fExceptionCallBack function fail"); } else { log.debug("Set fExceptionCallBack function successfully!"); } } //设置连接时间与重连时间 hCNetSDK.NET_DVR_SetConnectTime(2000, 1); hCNetSDK.NET_DVR_SetReconnect(5000, true); } /** * @描述 注册登录 只支持同步登陆,且官方不建议直接在此接口下写耗时操作 @@ -80,24 +107,11 @@ @Override public AjaxResult login(ArdCameras camera) { try { // 初始化 if (!hCNetSDK.NET_DVR_Init()) { log.debug("SDK初始化失败"); } //打印海康sdk日志 if (Platform.isWindows()) { String WIN_PATH = System.getProperty("user.dir") + File.separator + "ardLog" + File.separator + "logs" + File.separator; hCNetSDK.NET_DVR_SetLogToFile(3, WIN_PATH, true); } else { hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog", true); } String m_sDeviceIP = camera.getIp(); String m_sUsername = camera.getUsername(); String m_sPassword = camera.getPassword(); short m_sPort = camera.getPort().shortValue(); //设置连接时间与重连时间 hCNetSDK.NET_DVR_SetConnectTime(2000, 1); hCNetSDK.NET_DVR_SetReconnect(5000, true); //设备信息, 输出参数 HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40(); HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO(); @@ -115,6 +129,7 @@ //是否异步登录:0- 否,1- 是 windowsSDK里是true和false m_strLoginInfo.bUseAsynLogin = false; m_strLoginInfo.write(); //同步登录 int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo); if (lUserID < 0) { @@ -125,20 +140,12 @@ //删除管理通道 ardChannelService.deleteArdChannelByDeviceId(camera.getId()); ardCamerasService.updateArdCameras(camera); log.debug("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败: " + SdkErrorCodeEnum.getDescByCode(errorCode) + "(" + errorCode + ")"); log.warn("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败: " + SdkErrorCodeEnum.getDescByCode(errorCode) + "(" + errorCode + ")"); return AjaxResult.warn("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败: " + SdkErrorCodeEnum.getDescByCode(errorCode) + "(" + errorCode + ")"); } log.debug("Login Success [ " + camera.getIp() + ":" + camera.getPort() + " ]"); if (fExceptionCallBack == null) { fExceptionCallBack = new ExceptionCallBack();//异常回调 //设置异常回调函数(可在回调函数中获取设备上下线状态等) if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, null)) { log.debug("Set fExceptionCallBack function fail"); } else { log.debug("Set fExceptionCallBack function successfully!"); } } GlobalVariable.loginMap.put(camera.getId(), lUserID); GlobalVariable.loginCameraMap.put(lUserID, camera); camera.setLoginId((long) lUserID); @@ -187,29 +194,13 @@ @Async("globalExecutor") public AjaxResult asyncLogin(ArdCameras camera) { try { // 初始化 if (!hCNetSDK.NET_DVR_Init()) { log.error("SDK初始化失败"); return AjaxResult.warn("SDK初始化失败"); } //打印海康sdk日志 if (Platform.isWindows()) { String WIN_PATH = System.getProperty("user.dir") + File.separator + "ardLog" + File.separator + "logs" + File.separator; hCNetSDK.NET_DVR_SetLogToFile(3, WIN_PATH, true); } else { hCNetSDK.NET_DVR_SetLogToFile(3, "/home/ardLog/hiklog", true); } String m_sDeviceIP = camera.getIp(); String m_sUsername = camera.getUsername(); String m_sPassword = camera.getPassword(); short m_sPort = camera.getPort().shortValue(); //设置连接时间与重连时间 hCNetSDK.NET_DVR_SetConnectTime(2000, 1); hCNetSDK.NET_DVR_SetReconnect(5000, true); //设备信息, 输出参数 HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40(); HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO(); // 注册设备-登录参数,包括设备地址、登录用户、密码等 m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN]; System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length()); @@ -233,7 +224,7 @@ //删除管理通道 ardChannelService.deleteArdChannelByDeviceId(camera.getId()); ardCamerasService.updateArdCameras(camera); log.error("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败: " + SdkErrorCodeEnum.getDescByCode(errorCode) + "(" + errorCode + ")"); log.warn("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败: " + SdkErrorCodeEnum.getDescByCode(errorCode) + "(" + errorCode + ")"); return AjaxResult.warn("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败: " + SdkErrorCodeEnum.getDescByCode(errorCode) + "(" + errorCode + ")"); } log.debug("Login Success 【 " + camera.getIp() + ":" + camera.getPort() + " 】"); ard-work/src/main/resources/mapper/device/ArdChannelMapper.xml
@@ -72,4 +72,7 @@ from ard_channel where device_id = #{deviceId} </delete> <delete id="clearArdChannel"> delete from ard_channel </delete> </mapper>