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.domain.Infrared.NvrInfo;
|
|
import com.inspect.nvr.jna.lincseek.IRNetSDK;
|
|
import com.inspect.nvr.jna.lincseek.IRNetSDKStruct;
|
|
import com.inspect.nvr.jna.lincseek.IRNetSDKStruct.IRNETHANDLE;
|
|
import com.inspect.nvr.utils.redis.RedisService;
|
|
import com.sun.jna.Pointer;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import javax.annotation.Resource;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
@Slf4j
|
|
@Service
|
|
public class LincseekLoginService {
|
|
private static final String ERROR_LOGOUT_KEY = "lincseek:error";
|
|
|
|
@Resource
|
|
private RedisService redisService;
|
|
@Resource
|
|
private IRNetSDK irNetSDK;
|
|
|
|
// 使用 Caffeine 缓存,10分钟未访问自动移除并登出
|
|
private final Cache<String, IRNETHANDLE> sessionCache = Caffeine.newBuilder()
|
|
// 10分钟未被get()就过期
|
|
.expireAfterAccess(10, TimeUnit.MINUTES)
|
|
.removalListener((String ip, IRNETHANDLE handle, RemovalCause cause) -> {
|
|
if (handle != null && (cause == RemovalCause.EXPIRED || cause == RemovalCause.SIZE)) {
|
|
log.info("[朗驰]会话超时自动登出,ip: {},handler: {}", ip, handle);
|
|
doLogout(ip, handle);
|
|
}
|
|
}).build();
|
|
|
|
/**
|
|
* 登录(Caffeine.get 保证同一 IP 的并发请求只执行一次登录)
|
|
*/
|
|
public IRNETHANDLE login(NvrInfo nvrInfo) {
|
|
String ip = nvrInfo.getNvrIp();
|
|
Integer port = nvrInfo.getServerPort();
|
|
if (port == null) {
|
|
throw new IllegalArgumentException("serverPort 不能为空");
|
|
}
|
|
|
|
return sessionCache.get(ip, key -> {
|
|
IRNetSDKStruct.CHANNEL_CLIENTINFO info = IRNetSDKStruct.CHANNEL_CLIENTINFO.createWithUrl(
|
|
"video server", nvrInfo.getAccount(), nvrInfo.getPassword(),
|
|
(byte) nvrInfo.getChannelNumber().intValue(), ip, null, null, 0, null, null);
|
|
IRNETHANDLE handle = irNetSDK.IRNET_ClientStart(ip, info, port.shortValue(), 0);
|
|
|
|
if (IRNETHANDLE.INVALID_HANDLE_VALUE.equals(handle)) {
|
|
throw new RuntimeException("[朗驰]登录失败, ip: " + ip);
|
|
}
|
|
|
|
log.info("[朗驰]登录成功,ip:{},handler:{}", ip, handle);
|
|
return handle;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 记录注销失败信息到 Redis
|
|
*/
|
|
private void recordLogoutError(String ip, Integer userID, int errorCode) {
|
|
JSONObject json = new JSONObject();
|
|
json.put("ip", ip);
|
|
json.put("userID", userID);
|
|
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, IRNETHANDLE handle) {
|
|
if (handle != null) {
|
|
// 调用登出SDK
|
|
boolean isLogout = irNetSDK.IRNET_ClientStop(handle);
|
|
if (isLogout) {
|
|
log.info("[朗驰]登出成功,ip: {},handle: {}", ip, handle);
|
|
} else {
|
|
log.error("[朗驰]登出失败,ip: {},handle: {}", ip, handle);
|
|
// 登出失败日志记录到Redis中
|
|
recordLogoutError(ip, (int) Pointer.nativeValue(handle), -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 登出
|
|
*/
|
|
public synchronized void logout(String ip) {
|
|
IRNETHANDLE handle = sessionCache.getIfPresent(ip);
|
|
if (handle != null) {
|
|
sessionCache.invalidate(ip);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 登出所有用户
|
|
*/
|
|
public void logoutAll() {
|
|
// 获取所有缓存的IP和userID
|
|
sessionCache.asMap().forEach((ip, handle) -> {
|
|
doLogout(ip, handle);
|
|
});
|
|
// 清空整个缓存
|
|
sessionCache.invalidateAll();
|
|
log.info("[朗驰]所有用户已登出");
|
|
}
|
|
|
|
/**
|
|
* 检查是否已登录(同时刷新过期时间)
|
|
*/
|
|
public boolean isLoggedIn(String ip) {
|
|
return sessionCache.getIfPresent(ip) != null;
|
|
}
|
|
}
|