从接口的结构设计上考虑有什么可优化的内容:/*
* Copyright (c) 2024, TP-Link Corporation Limited. All rights reserved.
*/
package com.tplink.nbu.cipc.api.service.impl;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import cn.hutool.core.util.RandomUtil;
import io.micrometer.core.instrument.util.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.RunnableWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.tplink.nbu.cipc.api.config.agent.RBucketAgent;
import com.tplink.nbu.cipc.api.config.agent.RMapAgent;
import com.tplink.nbu.cipc.api.constant.DeviceConstant;
import com.tplink.nbu.cipc.api.constant.ErrCode;
import com.tplink.nbu.cipc.api.constant.RelayConstant.StreamType;
import com.tplink.nbu.cipc.api.dto.DistributerDTO.NodeInfo;
import com.tplink.nbu.cipc.api.dto.DistributerDTO.SessionStateEnum;
import com.tplink.nbu.cipc.api.dto.DistributerDTO.StreamSession;
import com.tplink.nbu.cipc.api.dto.PostStreamStatusDTO;
import com.tplink.nbu.cipc.api.dto.PostStreamStatusDTO.PostStream;
import com.tplink.nbu.cipc.api.dto.StreamInfo;
import com.tplink.nbu.cipc.api.dto.UserInfo;
import com.tplink.nbu.cipc.api.exception.BusinessException;
import com.tplink.nbu.cipc.api.grpcclient.RelayClient;
import com.tplink.nbu.cipc.api.monitor.ExceptionPassthroughStat;
import com.tplink.nbu.cipc.api.monitor.StatUtil;
import com.tplink.nbu.cipc.api.property.RelaySessionProperty;
import com.tplink.nbu.cipc.api.service.RegionNodeManageService;
import com.tplink.nbu.cipc.api.service.RelayStatService;
import com.tplink.nbu.cipc.api.service.SourceManageService;
import com.tplink.nbu.cipc.api.service.StreamSessionManageService;
import com.tplink.nbu.cipc.api.util.ContextUtil;
import com.tplink.nbu.cipc.api.util.DesensitizeUtil;
import com.tplink.nbu.cipc.api.util.SourceUtil;
import com.tplink.nbu.common.pii.utils.PIIMaskUtil;
import static com.tplink.nbu.cipc.api.constant.RelayConstant.STATE_PRE_CONNECTION;
import static com.tplink.nbu.cipc.api.constant.ServiceBeanConstant.STREAM_MANAGE_EXECUTOR;
import static com.tplink.nbu.cipc.api.constant.SourceConstant.SERVICE_PASSTHROUGH_OVER_TIME_ARRIVED;
import static com.tplink.nbu.cipc.api.util.RelayServiceUtil.isPlayer;
import static com.tplink.nbu.cipc.api.util.RelayServiceUtil.isPusher;
/**
* Description of this file
*
* @author Wei Hongxu
* @version v1.0
* @since 2024/4/30
*/
@Slf4j
@Service
public class RelayStreamSessionManageServiceImpl implements StreamSessionManageService {
private static final String KEY_POST_STREAM_SESSION = "cipc.relay:postStream.session:%s";
private static final String KEY_GET_STREAM_SESSION = "cipc.relay:getStream.session:%s";
private static final String KEY_STREAM_SESSION = "cipc.relay:stream.session:%s";
private static final String STREAM_SESSION_SPLIT_FLAG = "_";
private static final int UNSET_CONNECTION_TYPE = -1;
private static final int UNSET_STREAM_LATENCY = -1;
@Autowired
private RBucketAgent rBucketAgent;
@Autowired
private RMapAgent rMapAgent;
@Autowired
private RelaySessionProperty relaySessionProperty;
@Autowired
private SourceManageService sourceManageService;
@Autowired
private RelayStatService relayStatService;
@Autowired
private ScheduledExecutorService executorService;
@Autowired
private RelayClient relayClient;
@Autowired
private RegionNodeManageService regionNodeManageService;
@Autowired
@Qualifier(STREAM_MANAGE_EXECUTOR)
private ExecutorService streamManageExecutorService;
@Override
public String initStreamSession(StreamInfo streamInfo, UserInfo userInfo, String streamType, String publicIp) {
String deviceId = streamInfo.getDeviceId();
String streamId = streamInfo.getReqUrl();
String sessionId = RandomUtil.randomString(8);
sessionId = addStream(deviceId, streamType, streamId, sessionId, streamInfo.getPlayerId());
log.info("[{}][{}] initStreamSession. streamId: {} sessionId: {}", streamType, PIIMaskUtil.encrypt(deviceId),
DesensitizeUtil.maskStreamIdString(streamId),
PIIMaskUtil.encrypt(sessionId));
initStreamSession(streamInfo, sessionId, publicIp, userInfo, streamType);
return sessionId;
}
@Override
public void updateStreamState(String deviceId, String streamType, String streamId, String state, String sessionId,
String region, String publicIp, String source, String deviceRegionCode,
String brand) {
updateStreamState(deviceId, streamType, streamId, state, sessionId, UNSET_STREAM_LATENCY, region, publicIp,
UNSET_CONNECTION_TYPE, source, deviceRegionCode, brand);
}
@Override
public StreamSession updateStreamState(String deviceId, String streamType, String streamId, String state,
String sessionId, int streamLatency, String region, String publicIp,
int connectionType, String source,
String deviceRegionCode, String brand) {
String streamSessionId = buildStreamSessionId(streamId, sessionId);
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.get(streamSessionKey);
if (streamSession == null) {
log.warn("[{}] not found session when update, init now. streamId: {} streamType: {} .",
PIIMaskUtil.encrypt(deviceId),
DesensitizeUtil.maskStreamIdString(streamId), streamType);
streamSession = StreamSession.builder()
.deviceId(deviceId)
.streamId(streamId)
.region(region)
.publicIp(publicIp)
.source(source)
.streamType(streamType)
.initTime(System.currentTimeMillis())
.state(state)
.throughElb(false)
.sessionId(sessionId)
.regionCode(deviceRegionCode)
.brand(brand)
.build();
addStream(deviceId, streamType, streamId, sessionId, "");
}
long activeTime = getTtlBySessionState(state, connectionType, DeviceConstant.TYPE_UNKNOWN, streamType);
// 更新会话state
String oldState = streamSession.getState();
streamSession.setState(state);
if (streamLatency != UNSET_STREAM_LATENCY) {
streamSession.setStreamLatency(streamLatency);
}
log.info("[{}]update {} state from {} to {}", DesensitizeUtil.maskStreamIdString(streamId), streamType,
oldState, state);
// 更新会话过期时间
streamSession.setExistTime(getExistTime(activeTime));
String originRegion = streamSession.getRegion();
String originPublicIp = streamSession.getPublicIp();
streamManageExecutorService.submit(RunnableWrapper.of(
() -> processUnexpectedStream(deviceId, streamType, streamId, originRegion,
originPublicIp, region, publicIp, source)));
streamSession.setRegion(region);
streamSession.setPublicIp(publicIp);
if (connectionType != UNSET_CONNECTION_TYPE) {
streamSession.setConnectionType(connectionType);
}
rBucketAgent.set(streamSessionKey, streamSession, getRedisTtl(activeTime),
TimeUnit.SECONDS);
if (SessionStateEnum.INIT.getStateName().equals(state)) {
setSessionSchedule(deviceId, streamId, sessionId, streamType, (int) activeTime);
}
if (StreamType.STREAM_TYPE_DEVICE.equals(streamType)) {
String postStreamKey = buildPostStreamSessionKey(deviceId);
refreshStream(postStreamKey, activeTime);
} else if (StreamType.STREAM_TYPE_PLAYER.equals(streamType)) {
String getStreamKey = buildGetStreamSessionKey(streamId);
refreshStream(getStreamKey, activeTime);
}
return streamSession;
}
private void processUnexpectedStream(String deviceId, String streamType, String streamId, String originRegion,
String originPublicIp, String region, String publicIp, String source) {
try {
NodeInfo nodeInfo;
String targetRegion;
if (isPusher(streamType)) {
if (!isUnexpectedTarget(originRegion, originPublicIp, region, publicIp)) {
return;
}
// 推流到达后,发现同预期不符合,尝试关闭原节点的拉流
nodeInfo = regionNodeManageService.getNodeFromSpecifyRegion(originRegion, originPublicIp);
targetRegion = originRegion;
log.warn(
"[{}][{}]stream reached candidate node: {} {}; original: {} {}, close corresponding get stream on original node ",
streamType,
DesensitizeUtil.maskStreamIdString(streamId), region, publicIp, originRegion, originPublicIp);
} else if (isPlayer(streamType)) {
StreamSession session = queryPostStreamLocation(deviceId, streamId, source);
if (session == null) {
return;
}
if (!isUnexpectedTarget(session.getRegion(), session.getPublicIp(), region, publicIp)) {
return;
}
// 拉流到达后,发现同预期不符,关闭本身
nodeInfo = regionNodeManageService.getNodeFromSpecifyRegion(region, publicIp);
targetRegion = region;
log.warn(
"[{}][{}]stream reached unexpected node: {} {} ; expected: {} {}, close itself on unexpected node",
streamType,
DesensitizeUtil.maskStreamIdString(streamId), region, publicIp, session.getRegion(),
session.getPublicIp());
} else {
log.error("invalid streamType when process unexpected stream.");
throw new BusinessException(ErrCode.INVALID_PARAMS);
}
String relayPrivateIp = nodeInfo.getPrivateIp();
String selfsignNodeUrl = nodeInfo.getSelfsignNodeUrl();
relayClient.stopGetStream(deviceId, streamId, relayPrivateIp, targetRegion, selfsignNodeUrl);
} catch (Exception e) {
log.error("process unexpected stream fail: {}", DesensitizeUtil.maskStreamIdString(streamId), e);
}
}
private boolean isUnexpectedTarget(String originRegion, String originPublicIp, String region, String publicIp) {
if (!originRegion.equals(region)) {
return true;
}
return !originPublicIp.equals(publicIp);
}
@Override
public StreamSession removeStreamSessionWhenNotify(String deviceId, String streamId, String sessionId,
String streamType, String statJson) {
return doRemoveStreamSession(deviceId, streamId, sessionId, streamType, statJson, 0);
}
@Override
public StreamSession removeStreamSessionWhenNodeInvalid(String deviceId, String streamId, String streamType) {
return doRemoveStreamSession(deviceId, streamId, "", streamType, "", -1009);
}
private StreamSession doRemoveStreamSession(String deviceId, String streamId, String sessionId, String streamType,
String statJson, int errorCode) {
// remove map
String streamSessionId = buildStreamSessionId(streamId, sessionId);
if (StreamType.STREAM_TYPE_DEVICE.equals(streamType)) {
String postStreamKey = buildPostStreamSessionKey(deviceId);
removeStream(postStreamKey, streamSessionId);
} else if (StreamType.STREAM_TYPE_PLAYER.equals(streamType)) {
String getStreamKey = buildGetStreamSessionKey(streamId);
removeStream(getStreamKey, sessionId);
}
return removeStreamSession(streamSessionId, statJson, errorCode);
}
private StreamSession removeStreamSession(String streamSessionId, String statJson, int errorCode) {
// remove session
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.getAndDelete(streamSessionKey);
if (StringUtils.hasLength(statJson) && streamSession != null) {
streamSession.setState(SessionStateEnum.ARRIVED.getStateName());
}
relayStatService.printRelayStatRecord(streamSession, statJson, errorCode);
return streamSession;
}
public StreamSession removeStreamSession(String deviceId, String streamId, String sessionId, String streamType) {
return doRemoveStreamSession(deviceId, streamId, sessionId, streamType, "", ErrCode.OK.getErrorCode());
}
@Override
public StreamSession removeStreamSessionWhenPassthroughFail(String deviceId, String streamId, String sessionId,
String streamType, int errorCode) {
String streamSessionId = buildStreamSessionId(streamId, sessionId);
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.get(streamSessionKey);
if (streamSession == null) {
return null;
}
if (SessionStateEnum.ARRIVED.getStateName().equals(streamSession.getState())) {
ExceptionPassthroughStat exceptionPassthroughStat = ExceptionPassthroughStat.builder()
.deviceId(deviceId)
.sessionId(sessionId)
.passthroughErrorCode(errorCode)
.service(SERVICE_PASSTHROUGH_OVER_TIME_ARRIVED)
.streamId(DesensitizeUtil.maskStreamIdString(streamId)).build();
StatUtil.statRecord(exceptionPassthroughStat);
return streamSession;
}
return doRemoveStreamSession(deviceId, streamId, sessionId, streamType, "", errorCode);
}
private void initStreamSession(StreamInfo streamInfo, String sessionId, String publicIp, UserInfo userInfo,
String streamType) {
String deviceId = streamInfo.getDeviceId();
String streamId = streamInfo.getReqUrl();
String region = streamInfo.getRelayRegion();
String streamSessionId = buildStreamSessionId(streamId, sessionId);
String streamSessionKey = buildStreamSessionKey(streamSessionId);
String state = SessionStateEnum.INIT.getStateName();
long activeTime = getTtlBySessionState(state, streamInfo.getPreConnection(),
streamInfo.getDevicePassthroughType(), streamType);
StreamSession streamSession = StreamSession.builder()
.deviceId(deviceId)
.streamId(streamId)
.region(region)
.publicIp(publicIp)
.source(userInfo.getSource())
.streamType(streamType)
.initTime(System.currentTimeMillis())
.state(state)
.throughElb(false)
.sessionId(sessionId)
.existTime(getExistTime(activeTime))
.regionCode(streamInfo.getDeviceRegionCode())
.accountId(userInfo.getAccountId())
.functionType(streamInfo.getType())
.playerId(streamInfo.getPlayerId())
.connectionType(streamInfo.getPreConnection())
.deviceModel(streamInfo.getDeviceModel())
.deviceHwVer(streamInfo.getDeviceHwVer())
.deviceFwVer(streamInfo.getDeviceFwVer())
.trackId(streamInfo.getTrackId())
.brand(ContextUtil.getCurrentBrandName())
.build();
if (!rBucketAgent.isExists(streamSessionKey)) {
rBucketAgent.set(streamSessionKey, streamSession, getRedisTtl(activeTime), TimeUnit.SECONDS);
log.debug("init {}:{} [value:{}]", streamType, streamId, streamSession);
// 每一个session设置一个定时任务用于检测和清理过期会话
setSessionSchedule(deviceId, streamId, sessionId, streamType, (int) activeTime);
}
}
private void addStream(String key, String newStreamId) {
rMapAgent.put(key, newStreamId, System.currentTimeMillis(), relaySessionProperty.getStreamMapTtlSeconds(),
ChronoUnit.SECONDS);
}
private void removeStream(String key, String newStreamId) {
rMapAgent.delete(key, newStreamId);
}
private void refreshStream(String key, long timeToLive) {
rMapAgent.expireAsync(key, timeToLive, ChronoUnit.SECONDS);
}
@Override
public StreamSession queryPostStreamLocation(String deviceId, String streamId, String source) {
return queryPostStreamLocation(deviceId, streamId, source, "");
}
@Override
public StreamSession queryPostStreamLocation(String deviceId, String streamId, String source, String sessionId) {
List<String> streamSessionList = queryPostStreamSessionList(deviceId, source);
return queryPostStreamLocationFromStreamList(deviceId, streamId, source, sessionId, streamSessionList);
}
@Override
public StreamSession queryPostStreamLocationFromStreamList(String deviceId, String streamId, String source,
String sessionId, List<String> streamSessionList) {
if (streamSessionList == null) {
return null;
}
StreamSession targetStreamSession = null;
// 默认streamSessionId = streamId(当sessionId为空) / streamId_sessionId
String defaultStreamSessionId =
StringUtils.isEmpty(sessionId) ? streamId : buildStreamSessionId(streamId, sessionId);
// 根据streamSessionId查找目标会话(可能存在多个,取最新的)
for (String streamSessionId : streamSessionList) {
if (streamSessionId.contains(defaultStreamSessionId)) {
StreamSession tempStreamSession = findTargetStreamSession(deviceId, streamSessionId, source, streamId);
if (targetStreamSession == null) {
targetStreamSession = tempStreamSession;
} else if (tempStreamSession != null
&& tempStreamSession.getInitTime() > targetStreamSession.getInitTime()) {
log.warn(
"multiple post stream session detected, reset the target stream session to the latest one. streamId: {}",
DesensitizeUtil.maskStreamIdString(streamId));
targetStreamSession = tempStreamSession;
}
}
}
return targetStreamSession;
}
private StreamSession findTargetStreamSession(String deviceId, String streamSessionId, String source,
String streamId) {
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.get(streamSessionKey);
//判断合法性
if (streamSession == null) {
return null;
}
String sourceInCache = streamSession.getSource();
if (!sourceManageService.verifySourceValidity(sourceInCache)) {
log.warn("sourceInCache: {}, source: {}", sourceInCache, source);
throw new BusinessException(ErrCode.SOURCE_NOT_SUPPORTED);
}
if (System.currentTimeMillis() > streamSession.getExistTime()) {
log.warn("at lease one session is expired: streamId: {}",
DesensitizeUtil.maskStreamIdString(streamId));
removeStream(buildPostStreamSessionKey(deviceId), streamSessionId);
StreamSession session = rBucketAgent.getAndDelete(streamSessionKey);
relayStatService.printRelayStatRecord(session);
return null;
}
//取最新的会话 防止取到旧会话
return streamSession;
}
@Override
public StreamSession queryPostStreamLocationFromStreamListWithSameDeviceId(String deviceId, String streamId,
String source,
List<String> streamSessionList) {
if (streamSessionList == null) {
return null;
}
StreamSession targetStreamSession = null;
for (String streamSessionId : streamSessionList) {
targetStreamSession = findTargetStreamSession(deviceId, streamSessionId, source, streamId);
if (targetStreamSession != null &&
(SourceUtil.isVmsSource(source) || SourceUtil.isVigiSource(source))) {
return targetStreamSession;
}
if (targetStreamSession != null && SessionStateEnum.ARRIVED.getStateName()
.equals(targetStreamSession.getState())) {
return targetStreamSession;
}
}
return targetStreamSession;
}
@Override
public Map<String, NodeInfo> queryDevicePostStreamLocation(String deviceId, String source) {
return queryPostStreamLocationByBrand(deviceId, source, ContextUtil.getCurrentBrandName());
}
@Override
public String queryPostStreamRegion(String deviceId, String source) {
List<String> streamSessionList = queryPostStreamSessionList(deviceId, source);
if (streamSessionList == null) {
return "";
}
if (streamSessionList.isEmpty()) {
return "";
}
for (String streamSessionId : streamSessionList) {
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.get(streamSessionKey);
if (streamSession == null) {
continue;
}
String sourceInCache = streamSession.getSource();
if (!sourceManageService.verifySourceValidity(sourceInCache)) {
continue;
}
return streamSession.getRegion();
}
return "";
}
@Override
public List<String> queryPostStreamList(String deviceId) {
List<String> postStreamList = new ArrayList<>();
String postStreamKey = buildPostStreamSessionKey(deviceId);
List<String> postStreamIdList = rMapAgent.getAllKeys(postStreamKey);
for (String postStreamId : postStreamIdList) {
// postStreamId = {StreamId}_{SessionId}
String streamId = getStreamIdFromStreamSessionId(postStreamId);
postStreamList.add(streamId);
}
return postStreamList;
}
@Override
public List<String> queryPostStreamSessionList(String deviceId, String source) {
// TODO:source的作用?
String postStreamKey = buildPostStreamSessionKey(deviceId);
return rMapAgent.getAllKeys(postStreamKey);
}
@Override
public PostStreamStatusDTO queryPostStreamStatus(String deviceId, String source) {
List<PostStream> postStreamList = new ArrayList<>();
// 1. 先查设备对应推流有多少条
String postStreamKey = buildPostStreamSessionKey(deviceId);
List<String> postStreamIdList = rMapAgent.getAllKeys(postStreamKey);
if (postStreamIdList == null || postStreamIdList.isEmpty()) {
return new PostStreamStatusDTO(postStreamList);
}
// 2. 再查每个streamId对应拉流有多少个
for (String postStreamId : postStreamIdList) {
String streamId = getStreamIdFromStreamSessionId(postStreamId);
String getStreamKey = buildGetStreamSessionKey(streamId);
List<String> getStreamList = rMapAgent.getAllKeys(getStreamKey);
if (getStreamList != null) {
int playerNum = getStreamList.size();
PostStream postStream = new PostStream(streamId, playerNum);
postStreamList.add(postStream);
}
}
// 3. 进行封装
return new PostStreamStatusDTO(postStreamList);
}
@Override
public Map<String, NodeInfo> queryDevicePostStreamLocation(String deviceId, String source, String brand) {
return queryPostStreamLocationByBrand(deviceId, source, brand);
}
private String buildPostStreamSessionKey(String deviceId) {
return String.format(KEY_POST_STREAM_SESSION, deviceId);
}
private String buildGetStreamSessionKey(String streamId) {
return String.format(KEY_GET_STREAM_SESSION, streamId);
}
private String buildStreamSessionId(String streamId, String sessionId) {
if (StringUtils.isEmpty(sessionId)) {
return streamId;
}
return streamId + STREAM_SESSION_SPLIT_FLAG + sessionId;
}
private String getStreamIdFromStreamSessionId(String streamSessionId) {
String[] list = streamSessionId.split(STREAM_SESSION_SPLIT_FLAG, 2);
return list[0];
}
private String buildStreamSessionKey(String streamSessionId) {
return String.format(KEY_STREAM_SESSION, streamSessionId);
}
private long getExistTime(long activeTime) {
return (long) TimeUtils.secondsToUnit(activeTime, TimeUnit.MILLISECONDS) + System.currentTimeMillis();
}
private String addStream(String deviceId, String streamType, String streamId, String sessionId, String playerId) {
if (StreamType.STREAM_TYPE_DEVICE.equals(streamType)) {
// update deviceId-streamId map
String postStreamKey = buildPostStreamSessionKey(deviceId);
String streamSessionId = buildStreamSessionId(streamId, sessionId);
addStream(postStreamKey, streamSessionId);
return sessionId;
} else if (StreamType.STREAM_TYPE_PLAYER.equals(streamType)) {
// update streamId-sessionId map
sessionId = StringUtils.hasLength(playerId) ? playerId : sessionId;
String getStreamKey = buildGetStreamSessionKey(streamId);
addStream(getStreamKey, sessionId);
return sessionId;
}
log.error("invalid streamType when add stream: {}", streamType);
throw new BusinessException(ErrCode.INVALID_PARAMS);
}
private int getTtlBySessionState(String state, int connectionType, int devicePassthroughType, String streamType) {
if (SessionStateEnum.INIT.getStateName().equals(state)) {
if (connectionType == STATE_PRE_CONNECTION && isPlayer(streamType)) {
if (devicePassthroughType == DeviceConstant.TYPE_IOT_BAT) {
return relaySessionProperty.getInitStatePreConnectionTtlBatCam();
} else {
return relaySessionProperty.getInitStatePreConnectionTtlAcCam();
}
}
return relaySessionProperty.getInitStateTtlSeconds();
} else if (SessionStateEnum.ARRIVED.getStateName().equals(state)) {
return relaySessionProperty.getArrivedStateTtlSeconds();
}
log.error("[{}]invalid state to set ddl.", state);
throw new BusinessException(ErrCode.INTERNAL_SERVER_ERROR);
}
private int getRedisTtl(long activeTime) {
return (int) (activeTime + 1);
}
private void setSessionSchedule(String deviceId, String streamId, String sessionId, String streamType, int delay) {
executorService.schedule(
RunnableWrapper.of(() -> removeStreamSessionAtFixedRate(deviceId, streamId, sessionId, streamType)), delay,
TimeUnit.SECONDS);
}
private void removeStreamSessionAtFixedRate(String deviceId, String streamId, String sessionId, String streamType) {
String streamSessionId = buildStreamSessionId(streamId, sessionId);
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.get(streamSessionKey);
if (streamSession == null) {
return;
}
if (System.currentTimeMillis() > streamSession.getExistTime()) {
removeStreamSession(deviceId, streamId, sessionId, streamType);
} else {
log.debug("[{}][{}]session not expired", sessionId, DesensitizeUtil.maskStreamIdString(streamId));
}
}
private Map<String, NodeInfo> queryPostStreamLocationByBrand(String deviceId, String source, String brand) {
List<String> streamSessionList = queryPostStreamSessionList(deviceId, source);
if (streamSessionList == null) {
return null;
}
Map<String, NodeInfo> nodeInfoMap = new HashMap<>();
for (String streamSessionId : streamSessionList) {
String streamSessionKey = buildStreamSessionKey(streamSessionId);
StreamSession streamSession = rBucketAgent.get(streamSessionKey);
if (streamSession == null) {
continue;
}
String sourceInCache = streamSession.getSource();
if (!sourceManageService.verifySourceValidity(sourceInCache)) {
continue;
}
if (System.currentTimeMillis() > streamSession.getExistTime()) {
log.warn("session is expired: {}", DesensitizeUtil.maskStreamIdString(streamSession.getStreamId()));
removeStream(buildPostStreamSessionKey(deviceId), streamSessionId);
StreamSession session = rBucketAgent.getAndDelete(streamSessionKey);
relayStatService.printRelayStatRecord(session);
continue;
}
String publicIp = streamSession.getPublicIp();
NodeInfo nodeInfo = regionNodeManageService.getNodeFromSpecifyRegion(streamSession.getRegion(), publicIp);
nodeInfoMap.put(streamSession.getStreamId(), nodeInfo);
}
return nodeInfoMap;
}
}