You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

126 lines
4.7 KiB

package com.inspect.nvr.service;
import com.alibaba.fastjson.JSONObject;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.inspect.nvr.daHuaCarme.jna.NetSDKLib;
import com.inspect.nvr.daHuaCarme.jna.NetSDKLib.LLong;
import com.inspect.nvr.domain.Infrared.NvrInfo;
import com.inspect.nvr.utils.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* 大华登录服务
*/
@Slf4j
@Service
public class DahuaLoginService {
private static final String ERROR_LOGOUT_KEY = "dahua:error";
@Autowired
private NetSDKLib dhNetSDK;
@Resource
private RedisService redisService;
// 使用 Caffeine 缓存,10分钟未访问自动移除并登出
private final Cache<String, LLong> sessionCache = Caffeine.newBuilder()
// 10分钟未被get()就过期
.expireAfterAccess(10, TimeUnit.MINUTES)
.removalListener((String ip, LLong loginID, RemovalCause cause) -> {
if (loginID != null && (cause == RemovalCause.EXPIRED || cause == RemovalCause.SIZE)) {
log.info("[大华]会话超时自动登出,ip: {},loginID: {}", ip, loginID);
doLogout(ip, loginID);
}
}).build();
public synchronized LLong login(NvrInfo nvrInfo) {
String ip = nvrInfo.getNvrIp();
LLong existLoginID = sessionCache.getIfPresent(ip);
if (existLoginID != null) {
log.info("[大华]登录命中缓存,ip: {},loginID: {}", ip, existLoginID);
return existLoginID;
}
// 执行登录
NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
pstInParam.szIP = nvrInfo.getNvrIp().getBytes();
pstInParam.nPort = nvrInfo.getServerPort();
pstInParam.szUserName = nvrInfo.getAccount().getBytes();
pstInParam.szPassword = nvrInfo.getPassword().getBytes();
NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
LLong loginID = dhNetSDK.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
if (loginID.intValue() == 0) {
int errorCode = dhNetSDK.CLIENT_GetLastError();
throw new RuntimeException("登录失败,错误码:" + errorCode);
}
// 放入缓存,自动开始计时10分钟
sessionCache.put(nvrInfo.getNvrIp(), loginID);
log.info("[大华]登录成功,ip:{},loginID:{}", ip, loginID);
return loginID;
}
/**
* 记录注销失败信息到 Redis
*/
private void recordLogoutError(String ip, LLong loginID, int errorCode) {
JSONObject json = new JSONObject();
json.put("ip", ip);
json.put("userId", loginID);
json.put("errorCode", errorCode);
json.put("time", System.currentTimeMillis());
redisService.redisTemplate.opsForZSet().add(ERROR_LOGOUT_KEY, json.toJSONString(), System.currentTimeMillis());
}
/**
* 登出具体实现
*/
public void doLogout(String ip, LLong loginID) {
if (loginID != null) {
// 执行登出操作
boolean isLogout = dhNetSDK.CLIENT_Logout(loginID);
if (isLogout) {
log.info("[大华]自动注销成功,ip: {},loginID: {}", ip, loginID.longValue());
} else {
int errorCode = dhNetSDK.CLIENT_GetLastError();
log.error("[大华]自动注销失败,ip: {},loginID: {},错误码: {}", ip, loginID.longValue(), errorCode);
// 记录失败日志到 Redis
recordLogoutError(ip, loginID, errorCode);
}
}
}
/**
* 登出
*/
public synchronized void logout(String ip) {
LLong loginID = sessionCache.getIfPresent(ip);
if (loginID != null) {
sessionCache.invalidate(ip);
}
}
/**
* 登出所有用户
*/
public void logoutAll() {
// 获取所有缓存的IP和userID
sessionCache.asMap().forEach((ip, loginID) -> {
doLogout(ip, loginID);
});
// 清空整个缓存
sessionCache.invalidateAll();
log.info("[大华]所有用户已登出");
}
/**
* 检查是否已登录(同时刷新过期时间)
*/
public boolean isLoggedIn(String ip) {
return sessionCache.getIfPresent(ip) != null;
}
}