| | |
| | | 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; |
| | |
| | | |
| | | 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; |
| | | |
| | | List<Object> cameraList = redisService.getCacheMapValues(CacheConstants.CAMERA_LIST); |
| | | if (cameraList == null || cameraList.isEmpty()) return; |
| | | |
| | | for (Object obj : cameraList) { |
| | | ArdCamera camera = (ArdCamera) obj; |
| | | 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(5000); |
| | | List<PtzParamDTO> list = ptzCacheManager.getAllValidData(DATA_VALID_MS); |
| | | if (!list.isEmpty()) { |
| | | PTZWebSocketUtils.sendMessageAll(list); |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |