package com.ard.work.device.camera.service;
|
|
import com.ard.common.core.constant.CacheConstants;
|
import com.ard.common.redis.service.RedisService;
|
import com.ard.work.api.domian.ArdCamera;
|
import com.ard.work.device.camera.domain.PtzParamDTO;
|
import com.ard.work.websocket.utils.PTZWebSocketUtils;
|
import jakarta.annotation.Resource;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.stereotype.Component;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Set;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
@Slf4j
|
@Component
|
public class PtzTask {
|
|
@Resource
|
private PtzDataCollector ptzDataCollector;
|
|
@Resource
|
private PtzCacheManager ptzCacheManager;
|
|
@Resource
|
private RedisService redisService;
|
|
private final Set<String> runningCamera = ConcurrentHashMap.newKeySet();
|
|
/** 缓存数据有效期: 超过此时间不再推送 */
|
private static final long DATA_VALID_MS = 5_000L;
|
/** 缓存数据淘汰阈值: 超过此时间从内存清掉 */
|
private static final long DATA_EVICT_MS = 60_000L;
|
/** 相机列表本地缓存 TTL */
|
private static final long CAMERA_LIST_TTL_MS = 30_000L;
|
|
private volatile List<ArdCamera> cachedCameraList = Collections.emptyList();
|
private volatile long cameraListExpireAt = 0L;
|
|
/**
|
* 采集任务
|
*/
|
@Scheduled(initialDelay = 5000, fixedDelay = 1000)
|
public void startCollectTask() {
|
List<ArdCamera> cameraList = getCameraList();
|
if (cameraList.isEmpty()) return;
|
|
for (ArdCamera camera : cameraList) {
|
String camId = camera.getId();
|
if (!runningCamera.add(camId)) continue;
|
ptzDataCollector.collectCamera(camera, runningCamera);
|
}
|
}
|
|
/**
|
* 推送任务
|
*/
|
@Scheduled(fixedDelay = 1000)
|
public void pushPTZ() {
|
try {
|
List<PtzParamDTO> list = ptzCacheManager.getAllValidData(DATA_VALID_MS);
|
if (!list.isEmpty()) {
|
PTZWebSocketUtils.sendMessageAll(list);
|
}
|
} catch (Exception e) {
|
log.error("推送PTZ异常", e);
|
}
|
}
|
|
/**
|
* 清理过期缓存,防止已禁用/删除的相机数据残留
|
*/
|
@Scheduled(fixedDelay = 60_000)
|
public void evictStaleCache() {
|
int n = ptzCacheManager.evictStale(DATA_EVICT_MS);
|
if (n > 0) {
|
log.debug("清理过期PTZ缓存 {} 条", n);
|
}
|
}
|
|
/**
|
* 本地缓存相机列表,降低 Redis QPS
|
*/
|
private List<ArdCamera> getCameraList() {
|
long now = System.currentTimeMillis();
|
if (now < cameraListExpireAt) {
|
return cachedCameraList;
|
}
|
synchronized (this) {
|
if (now < cameraListExpireAt) {
|
return cachedCameraList;
|
}
|
List<Object> raw = redisService.getCacheMapValues(CacheConstants.CAMERA_LIST);
|
List<ArdCamera> list;
|
if (raw == null || raw.isEmpty()) {
|
list = Collections.emptyList();
|
} else {
|
list = new ArrayList<>(raw.size());
|
for (Object o : raw) {
|
list.add((ArdCamera) o);
|
}
|
}
|
cachedCameraList = list;
|
cameraListExpireAt = now + CAMERA_LIST_TTL_MS;
|
return list;
|
}
|
}
|
}
|