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.
 
 

123 lines
4.3 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.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;
}
}