Преглед изворни кода

设备信息增加最近注册时间和最近心跳时间,心跳超时时间变为可配置

64850858 пре 4 година
родитељ
комит
83411ad127

+ 3 - 1
sql/mysql.sql

@@ -12,9 +12,11 @@ create table device
     transport          varchar(50) null,
     streamMode         varchar(50) null,
     online             varchar(50) null,
-    registerTimeMillis int          null,
+    registerTime       varchar(50) null,
+    keepaliveTime      varchar(50) null,
     ip                 varchar(50) not null,
     port               int          not null,
+    expires            int          not null,
     hostAddress        varchar(50) not null
 );
 

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@@ -23,4 +23,5 @@ public class VManageBootstrap extends LogManager {
 		VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
  
 	}
+
 }

+ 3 - 1
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@@ -39,7 +39,9 @@ public class VideoManagerConstants {
 	public static final String EVENT_ONLINE_REGISTER = "1";
 	
 	public static final String EVENT_ONLINE_KEEPLIVE = "2";
-	
+
+	public static final String EVENT_ONLINE_MESSAGE = "3";
+
 	public static final String EVENT_OUTLINE_UNREGISTER = "1";
 	
 	public static final String EVENT_OUTLINE_TIMEOUT = "2";

+ 6 - 0
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java

@@ -31,6 +31,9 @@ public class SipConfig {
 	@Value("${sip.ptz.speed:50}")
 	Integer speed;
 
+	@Value("${sip.keepaliveTimeOut:180}")
+	Integer keepaliveTimeOut;
+
 	public String getMonitorIp() {
 		return monitorIp;
 	}
@@ -63,4 +66,7 @@ public class SipConfig {
 		return speed;
 	}
 
+	public Integer getKeepaliveTimeOut() {
+		return keepaliveTimeOut;
+	}
 }

+ 23 - 10
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -66,19 +66,24 @@ public class Device {
 	/**
 	 * 注册时间
 	 */
-	private Long registerTimeMillis;
+	private String registerTime;
 
 
 	/**
 	 * 心跳时间
 	 */
-	private Long KeepaliveTimeMillis;
+	private String keepaliveTime;
 
 	/**
 	 * 通道个数
 	 */
 	private int channelCount;
 
+	/**
+	 * 注册有效期
+	 */
+	private int expires;
+
 	public String getDeviceId() {
 		return deviceId;
 	}
@@ -175,19 +180,27 @@ public class Device {
 		this.channelCount = channelCount;
 	}
 
-	public Long getRegisterTimeMillis() {
-		return registerTimeMillis;
+	public String getRegisterTime() {
+		return registerTime;
+	}
+
+	public void setRegisterTime(String registerTime) {
+		this.registerTime = registerTime;
+	}
+
+	public String getKeepaliveTime() {
+		return keepaliveTime;
 	}
 
-	public void setRegisterTimeMillis(Long registerTimeMillis) {
-		this.registerTimeMillis = registerTimeMillis;
+	public void setKeepaliveTime(String keepaliveTime) {
+		this.keepaliveTime = keepaliveTime;
 	}
 
-	public Long getKeepaliveTimeMillis() {
-		return KeepaliveTimeMillis;
+	public int getExpires() {
+		return expires;
 	}
 
-	public void setKeepaliveTimeMillis(Long keepaliveTimeMillis) {
-		KeepaliveTimeMillis = keepaliveTimeMillis;
+	public void setExpires(int expires) {
+		this.expires = expires;
 	}
 }

+ 3 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.event;
 
+import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent;
 import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,9 +23,9 @@ public class EventPublisher {
 	@Autowired
     private ApplicationEventPublisher applicationEventPublisher;
 	
-	public void onlineEventPublish(String deviceId, String from) {
+	public void onlineEventPublish(Device device, String from) {
 		OnlineEvent onEvent = new OnlineEvent(this);
-		onEvent.setDeviceId(deviceId);
+		onEvent.setDevice(device);
 		onEvent.setFrom(from);
         applicationEventPublisher.publishEvent(onEvent);
     }

+ 7 - 6
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.event.online;
 
+import com.genersoft.iot.vmp.gb28181.bean.Device;
 import org.springframework.context.ApplicationEvent;
 
 /**    
@@ -18,18 +19,18 @@ public class OnlineEvent extends ApplicationEvent {
 		super(source);
 	}
 
-	private String deviceId;
+	private Device device;
 	
 	private String from;
 
-	public String getDeviceId() {
-		return deviceId;
+	public Device getDevice() {
+		return device;
 	}
 
-	public void setDeviceId(String deviceId) {
-		this.deviceId = deviceId;
+	public void setDevice(Device device) {
+		this.device = device;
 	}
-	
+
 	public String getFrom() {
 		return from;
 	}

+ 28 - 16
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java

@@ -1,5 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.event.online;
 
+import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -10,6 +12,9 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
 /**
  * @Description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源:
  *               1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
@@ -28,39 +33,46 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
 	@Autowired
     private RedisUtil redis;
 
+	@Autowired
+    private SipConfig sipConfig;
+
+	private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
 	@Override
 	public void onApplicationEvent(OnlineEvent event) {
 		
 		if (logger.isDebugEnabled()) {
-			logger.debug("设备上线事件触发,deviceId:" + event.getDeviceId() + ",from:" + event.getFrom());
+			logger.debug("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom());
 		}
-		
-		String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDeviceId();
-		boolean needUpdateStorager = false;
+		Device device = event.getDevice();
+		String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + event.getDevice().getDeviceId();
 
 		switch (event.getFrom()) {
 		// 注册时触发的在线事件,先在redis中增加超时超时监听
 		case VideoManagerConstants.EVENT_ONLINE_REGISTER:
-			// TODO 超时时间暂时写死为180秒
-			redis.set(key, event.getDeviceId(), 180);
-			needUpdateStorager = true;
+			// 超时时间
+			redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut());
+			device.setRegisterTime(format.format(new Date(System.currentTimeMillis())));
 			break;
-		// 设备主动发送心跳触发的线事件
+		// 设备主动发送心跳触发的线事件
 		case VideoManagerConstants.EVENT_ONLINE_KEEPLIVE:
 			boolean exist = redis.hasKey(key);
 			// 先判断是否还存在,当设备先心跳超时后又发送心跳时,redis没有监听,需要增加
 			if (!exist) {
-				needUpdateStorager = true;
-				redis.set(key, event.getDeviceId(), 180);
+				redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut());
 			} else {
-				redis.expire(key, 180);
+				redis.expire(key, sipConfig.getKeepaliveTimeOut());
 			}
+			device.setKeepaliveTime(format.format(new Date(System.currentTimeMillis())));
+			break;
+		// 设备主动发送消息触发的在线事件
+		case VideoManagerConstants.EVENT_ONLINE_MESSAGE:
+
 			break;
 		}
-		
-		if (needUpdateStorager) {
-			// 处理离线监听
-			storager.online(event.getDeviceId());
-		}
+
+		device.setOnline(1);
+		// 处理上线监听
+		storager.updateDevice(device);
 	}
 }

+ 7 - 6
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java

@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
 
 import java.io.ByteArrayInputStream;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 
 import javax.sip.address.SipURI;
@@ -226,7 +227,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 			String name = rootElement.getName();
 			Element deviceIdElement = rootElement.element("DeviceID");
 			String deviceId = deviceIdElement.getText();
-
+			Device device = storager.queryVideoDevice(deviceId);
 			if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求
 				logger.info("接收到DeviceStatus查询消息");
 				FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
@@ -259,7 +260,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 					deferredResultHolder.invokeResult(msg);
 
 					if (offLineDetector.isOnline(deviceId)) {
-						publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
+						publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
 					} else {
 					}
 				}
@@ -452,6 +453,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 			String requestName = rootElement.getName();
 			Element deviceIdElement = rootElement.element("DeviceID");
 			String deviceId = deviceIdElement.getTextTrim().toString();
+			Device device = storager.queryVideoDevice(deviceId);
 			if (requestName.equals("Query")) {
 				logger.info("接收到DeviceInfo查询消息");
 				FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
@@ -468,7 +470,6 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 				}
 			} else {
 				logger.debug("接收到DeviceInfo应答消息");
-				Device device = storager.queryVideoDevice(deviceId);
 				if (device == null) {
 					return;
 				}
@@ -489,7 +490,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 				// 回复200 OK
 				responseAck(evt);
 				if (offLineDetector.isOnline(deviceId)) {
-					publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
+					publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
 				}
 			}
 		} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
@@ -669,7 +670,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 					// 回复200 OK
 					responseAck(evt);
 					if (offLineDetector.isOnline(deviceId)) {
-						publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
+						publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
 					}
 				}
 			}
@@ -776,7 +777,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 				// 回复200 OK
 				responseAck(evt);
 				if (offLineDetector.isOnline(deviceId)) {
-					publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
+					publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
 				} else {
 				}
 			}else {

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/NotifyRequestProcessor.java

@@ -216,13 +216,13 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
 			Element rootElement = getRootElement(evt);
 			Element deviceIdElement = rootElement.element("DeviceID");
 			String deviceId = deviceIdElement.getText();
+			Device device = storager.queryVideoDevice(deviceId);
 			Element deviceListElement = rootElement.element("DeviceList");
 			if (deviceListElement == null) {
 				return;
 			}
 			Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
 			if (deviceListIterator != null) {
-				Device device = storager.queryVideoDevice(deviceId);
 				if (device == null) {
 					return;
 				}
@@ -324,7 +324,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
 				// 回复200 OK
 				response200Ok(evt);
 				if (offLineDetector.isOnline(deviceId)) {
-					publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
+					publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
 				}
 			}
 		} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {

+ 17 - 11
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java

@@ -2,7 +2,10 @@ package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
 
 import java.security.NoSuchAlgorithmException;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
 import java.util.Calendar;
+import java.util.Date;
 import java.util.Locale;
 
 import javax.sip.InvalidArgumentException;
@@ -70,7 +73,11 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
 			boolean passwordCorrect = false;
 			// 注册标志  0:未携带授权头或者密码错误  1:注册成功   2:注销成功
 			int registerFlag = 0;
-			Device device = null;
+			FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
+			AddressImpl address = (AddressImpl) fromHeader.getAddress();
+			SipUri uri = (SipUri) address.getURI();
+			String deviceId = uri.getUser();
+			Device device = storager.queryVideoDevice(deviceId);
 			AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); 
 			// 校验密码是否正确
 			if (authorhead != null) {
@@ -103,13 +110,17 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
 				response.addHeader(dateHeader);
 
 				ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
+				if (expiresHeader == null) {
+					response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
+					getServerTransaction(evt).sendResponse(response);
+					return;
+				}
 				// 添加Contact头
 				response.addHeader(request.getHeader(ContactHeader.NAME));
 				// 添加Expires头
 				response.addHeader(request.getExpires());
 				
 				// 获取到通信地址等信息
-				FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
 				ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
 				String received = viaHeader.getReceived();
 				int rPort = viaHeader.getRPort();
@@ -119,10 +130,7 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
 					rPort = viaHeader.getPort();
 				}
 				//
-				AddressImpl address = (AddressImpl) fromHeader.getAddress();
-				SipUri uri = (SipUri) address.getURI();
-				String deviceId = uri.getUser();
-				device = storager.queryVideoDevice(deviceId);
+
 				if (device == null) {
 					device = new Device();
 					device.setStreamMode("UDP");
@@ -132,11 +140,12 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
 				device.setPort(rPort);
 				device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
 				// 注销成功
-				if (expiresHeader != null && expiresHeader.getExpires() == 0) {
+				if (expiresHeader.getExpires() == 0) {
 					registerFlag = 2;
 				}
 				// 注册成功
 				else {
+					device.setExpires(expiresHeader.getExpires());
 					registerFlag = 1;
 					// 判断TCP还是UDP
 					boolean isTcp = false;
@@ -154,10 +163,7 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
 			// 下发catelog查询目录
 			if (registerFlag == 1 ) {
 				logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress);
-				device.setRegisterTimeMillis(System.currentTimeMillis());
-				storager.updateDevice(device);
-				publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER);
-
+				publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER);
 				// 重新注册更新设备和通道,以免设备替换或更新后信息无法更新
 				handler.onRegister(device);
 			} else if (registerFlag == 2) {

+ 9 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java

@@ -27,6 +27,9 @@ public interface DeviceMapper {
                 "ip," +
                 "port," +
                 "hostAddress," +
+                "expires," +
+                "registerTime," +
+                "keepaliveTime," +
                 "online" +
             ") VALUES (" +
                 "#{deviceId}," +
@@ -39,6 +42,9 @@ public interface DeviceMapper {
                 "#{ip}," +
                 "#{port}," +
                 "#{hostAddress}," +
+                "#{expires}," +
+                "#{registerTime}," +
+                "#{keepaliveTime}," +
                 "#{online}" +
             ")")
     int add(Device device);
@@ -56,6 +62,9 @@ public interface DeviceMapper {
                 "<if test=\"port != null\">, port=${port}</if>" +
                 "<if test=\"hostAddress != null\">, hostAddress='${hostAddress}'</if>" +
                 "<if test=\"online != null\">, online=${online}</if>" +
+                "<if test=\"registerTime != null\">, registerTime='${registerTime}'</if>" +
+                "<if test=\"keepaliveTime != null\">, keepaliveTime='${keepaliveTime}'</if>" +
+                "<if test=\"expires != null\">, expires=${expires}</if>" +
                 "WHERE deviceId='${deviceId}'"+
             " </script>"})
     int update(Device device);

+ 3 - 1
src/main/resources/all-application.yml

@@ -63,8 +63,10 @@ sip:
     domain: 4401020049
     # [可选]
     id: 44010200492000000001
-    # [可选] 默认设备认证密码,后续扩展使用设备单独密码
+    # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
     password: admin123
+    # [可选] 心跳超时时间, 建议设置为心跳周期的三倍
+    keepaliveTimeOut: 180
 
 #zlm服务器配置
 media:

+ 1 - 1
src/main/resources/application-dev.yml

@@ -39,7 +39,7 @@ sip:
     domain: 4401020049
     # [可选]
     id: 44010200492000000001
-    # [可选] 默认设备认证密码,后续扩展使用设备单独密码
+    # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
     password: admin123
 
 #zlm服务器配置

BIN
src/main/resources/wvp.sqlite


+ 17 - 13
web_src/src/components/DeviceList.vue

@@ -14,22 +14,16 @@
 				<!-- <devicePlayer ref="devicePlayer"></devicePlayer> -->
 				<!--设备列表-->
 				<el-table :data="deviceList" border style="width: 100%" :height="winHeight">
-					<el-table-column prop="name" label="名称" width="180" align="center">
+					<el-table-column prop="name" label="名称"  align="center">
 					</el-table-column>
-					<el-table-column prop="deviceId" label="设备编号" width="240" align="center">
-					</el-table-column>
-					<el-table-column label="地址" width="180" align="center">
-						<template slot-scope="scope">
-							<div slot="reference" class="name-wrapper">
-								<el-tag size="medium">{{ scope.row.hostAddress }}</el-tag>
-							</div>
-						</template>
+					<el-table-column prop="deviceId" label="设备编号" width="180" align="center">
 					</el-table-column>
+
 					<el-table-column prop="manufacturer" label="厂家" align="center">
 					</el-table-column>
-					<el-table-column prop="model" label="固件版本" align="center">
+					<el-table-column prop="model" label="固件版本" align="center" width="120">
 					</el-table-column>
-					<el-table-column label="流传输模式" align="center" width="160">
+					<el-table-column label="流传输模式" align="center" width="120">
             <template slot-scope="scope">
               <el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择">
                 <el-option key="UDP" label="UDP" value="UDP"></el-option>
@@ -40,7 +34,7 @@
 					</el-table-column>
 					<el-table-column prop="channelCount" label="通道数" align="center">
 					</el-table-column>
-					<el-table-column label="状态" width="80" align="center">
+					<el-table-column label="状态" width="120" align="center">
 						<template slot-scope="scope">
 							<div slot="reference" class="name-wrapper">
 								<el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag>
@@ -48,7 +42,17 @@
 							</div>
 						</template>
 					</el-table-column>
-
+          <el-table-column prop="keepaliveTime" label="最近心跳" align="center" width="140">
+          </el-table-column>
+          <el-table-column prop="registerTime" label="最近注册" align="center" width="140">
+          </el-table-column>
+          <el-table-column label="地址" width="180" align="center">
+            <template slot-scope="scope">
+              <div slot="reference" class="name-wrapper">
+                <el-tag size="medium">{{ scope.row.hostAddress }}</el-tag>
+              </div>
+            </template>
+          </el-table-column>
 					<el-table-column label="操作" width="360" align="center" fixed="right">
 						<template slot-scope="scope">
 							<el-button size="mini" :ref="scope.row.deviceId + 'refbtn' "  v-if="scope.row.online!=0" icon="el-icon-refresh"  @click="refDevice(scope.row)">刷新</el-button>