liusuyi
2026-01-20 67fdf3ec49bff5ca53b299eec9d749cc80f1ea18
ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java
@@ -1,5 +1,7 @@
package com.ard.vtdu.service.impl;
import com.ard.common.constant.CacheConstants;
import com.ard.common.core.redis.RedisCache;
import com.ard.common.utils.DateUtils;
import com.ard.vtdu.domain.ArdVtdu;
import com.ard.vtdu.domain.Conf;
@@ -7,13 +9,15 @@
import com.ard.vtdu.service.IArdVtduService;
import com.ard.vtdu.service.IArdMediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import com.ard.common.core.domain.model.LoginUser;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
@@ -29,8 +33,8 @@
    private ArdVtduMapper ardVtduMapper;
    @Resource
    private IArdMediaService ardMediaService;
    @Resource
    private RedisCache redisCache;
    @PostConstruct
    public void initMediaMTX() {
@@ -146,18 +150,19 @@
    //需要删除的(流媒体中多的)
    @Override
    public List<String> diffListToDel(List<ArdVtdu> vtduses, List<String> names) {
        if (vtduses.size() >= names.size()) {
            List<String> nameList = vtduses.stream().map(ArdVtdu::getName)
                    .filter(item -> !names.contains(item))
                    .collect(Collectors.toList());
            return nameList;
        } else {
            List<String> nameList =
                    names.stream().filter(item -> !vtduses.stream().map(ArdVtdu::getName).collect(Collectors.toList()).contains(item))
                    .collect(Collectors.toList());
            return nameList;
        }
        // 先获取本地库非 publisher 的名称集合
        Set<String> localNames = vtduses.stream()
                .map(ArdVtdu::getName)
                .collect(Collectors.toSet());
        // 过滤 MediaMTX 流中非 publisher 流,并判断是否在本地库中
        List<String> toDelete = names.stream()
                .filter(n -> !localNames.contains(n))    // MediaMTX 有,但本地库没有
                .collect(Collectors.toList());
        return toDelete;
    }
    //需要新增的(流媒体中少的)
    @Override
@@ -211,9 +216,70 @@
            List<String> nameList = ardMediaService.getNameList();
            List<ArdVtdu> ardVtduList = this.selectArdVtduList(new ArdVtdu());
            asyncMediaMTX(ardVtduList, nameList);
        }
        catch (Exception e) {
        } catch (Exception e) {
            log.error("同步MediaMTX任务失败", e);
        }
    }
    /**
     * 定时同步流媒体用户
     */
    @Scheduled(fixedRate = 5000)
    public void syncStreamMedia() {
        // Redis:在线 userId(1001)
        Set<String> onlineUserIds = redisCache.getSetKey(CacheConstants.LOGIN_USERID_KEY)
                .stream()
                .map(k -> k.substring(CacheConstants.LOGIN_USERID_KEY.length()))
                .collect(Collectors.toSet());
        // DB:当前流媒体 userId(从 user_1001 提取 1001)
        Set<String> currentStreamUserIds = ardVtduMapper
                .selectArdVtduList(new ArdVtdu())
                .stream()
                .filter(v -> "publisher".equals(v.getRtspSource()))
                .map(ArdVtdu::getName)
                .filter(name -> name != null && name.startsWith("user_"))
                .map(name -> name.substring("user_".length()))
                .collect(Collectors.toSet());
        // 1️⃣ 新增:Redis 有,DB 没有
        onlineUserIds.stream()
                .filter(id -> !currentStreamUserIds.contains(id))
                .forEach(id -> {
                    ArdVtdu vtdu = ArdVtdu.builder()
                            .name("user_" + id)
                            .rtspSource("publisher")
                            .build();
                    insertArdVtdu(vtdu);
                    log.info("用户【{}】添加到流媒体", id);
                });
        // 2️⃣ 删除:DB 有,Redis 没有
        currentStreamUserIds.stream()
                .filter(id -> !onlineUserIds.contains(id))
                .forEach(id -> {
                    deleteArdVtduByName("user_" + id);
                    log.info("用户【{}】移除流媒体", id);
                });
    }
    @EventListener
    public void handleLoginSuccess(AuthenticationSuccessEvent event) {
        Object principal = event.getAuthentication().getPrincipal();
        if (principal instanceof LoginUser) {
            LoginUser loginUser = (LoginUser) principal;  // 传统强制类型转换
            Long userId = loginUser.getUser().getUserId();
            String username = loginUser.getUsername();
            ArdVtdu ardVtdu = ArdVtdu.builder()
                    .name("user_" + userId)      // 用 userId 作为流名称
                    .rtspSource("publisher")          // 或 "publisher",按业务区分
                    .build();
            // 本地库插入
            insertArdVtdu(ardVtdu);
            log.info("用户【{}】登录,立即加入流媒体", username);
        } else {
            log.warn("登录事件 principal 不是 LoginUser,无法获取 userId");
        }
    }
}