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 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 cachedCameraList = Collections.emptyList(); private volatile long cameraListExpireAt = 0L; /** * 采集任务 */ @Scheduled(initialDelay = 5000, fixedDelay = 1000) public void startCollectTask() { List 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 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 getCameraList() { long now = System.currentTimeMillis(); if (now < cameraListExpireAt) { return cachedCameraList; } synchronized (this) { if (now < cameraListExpireAt) { return cachedCameraList; } List raw = redisService.getCacheMapValues(CacheConstants.CAMERA_LIST); List 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; } } }