BackupMaterialServiceImpl.java 11.7 KB
package com.wondertek.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.wondertek.dto.*;
import com.wondertek.entity.BackupConfig;
import com.wondertek.entity.BackupMaterial;
import com.wondertek.entity.StreamTask;
import com.wondertek.enums.PlayTypeEnum;
import com.wondertek.exception.BusinessException;
import com.wondertek.exception.ServiceException;
import com.wondertek.mapper.BackupConfigMapper;
import com.wondertek.mapper.BackupMaterialMapper;
import com.wondertek.mapper.StreamTaskMapper;
import com.wondertek.service.BackupMaterialService;
import com.wondertek.service.FileService;
import com.wondertek.util.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class BackupMaterialServiceImpl extends ServiceImpl<BackupMaterialMapper, BackupMaterial> implements BackupMaterialService {

    @Resource
    private BackupMaterialMapper backupMaterialMapper;
    @Resource
    private FileService fileService;
    @Value("${file.realPath}")
    private String realPath;
    @Resource
    private BackupConfigMapper backupConfigMapper;
    @Resource
    private StreamTaskMapper streamTaskMapper;
    @Value("${transcode.switchStreamUrl}")
    private String switchStreamUrl;
    @Value("${transcode.swapBackupUrl}")
    private String swapBackupUrl;


    @Override
    public PageBean queryPage(BackupMaterialDto backupMaterialDto) {
        Integer page = backupMaterialDto.getPage();
        Integer size = backupMaterialDto.getSize();



        LambdaQueryWrapper<BackupMaterial> queryWrapper = new LambdaQueryWrapper<>();

        if(StringUtils.isNotBlank(backupMaterialDto.getBackupName())){
            queryWrapper.like(BackupMaterial::getBackupName,backupMaterialDto.getBackupName());
        }


        Page<BackupMaterial> pageInfo = new Page<>(page, size);


        IPage<BackupMaterial> resultPage = backupMaterialMapper.selectPage(pageInfo, queryWrapper);
        return new PageBean(Integer.parseInt(String.valueOf(resultPage.getPages())),resultPage.getTotal(),resultPage.getRecords());
    }

    @Override
    public ResultBean upload(MultipartFile backupFile, BackupUploadVo backupUploadVo) {
        //校验
//        if(!"mp4".equalsIgnoreCase(backupUploadVo.getFileType())){
//            throw new ServiceException("仅支持上传mp4格式的垫片文件!");
//        }
        //校验backupFile后缀名
        String realName = backupFile.getOriginalFilename();
        String suffix = realName.substring(realName.lastIndexOf(".") + 1);
        if (!suffix.equalsIgnoreCase("mp4")) {
            throw new ServiceException("仅支持上传mp4格式的垫片文件!");
        }

        //对应垫片任务
        LambdaQueryWrapper<StreamTask> backupWrapper = new LambdaQueryWrapper<>();
        backupWrapper.eq(StreamTask::getRoomId,backupUploadVo.getRoomId());
        String palyType = backupUploadVo.getBackupOrder() == 1? PlayTypeEnum.BACKUP1.getCode() : PlayTypeEnum.BACKUP2.getCode();
        backupWrapper.eq(StreamTask::getPlayType,palyType);
        StreamTask streamTask = streamTaskMapper.selectOne(backupWrapper);
        if (streamTask == null){
            return ResultBean.error("未找到该直播间对应的垫片任务");
        }
        //文件上传
        String fileId = UUIDUtil.randomUUID();
        String fileName = backupUploadVo.getBackupName() + "." + backupUploadVo.getFileType();
        ///home/wondertek/material_file_assets/dianpian/2025/07/24/roomid/
        String filedir = FileUtils.generateDianPianDir(backupUploadVo.getRoomId().toString(), realPath);
        String destFilePath = filedir + fileName;//文件上传目录,绝对路径
        try {
            fileService.upload(backupFile, destFilePath);
        } catch (Exception e) {
            return ResultBean.error("上传文件异常");
        }
        //保存垫片素材表
        BackupMaterial backupMaterial = new BackupMaterial();
        backupMaterial.setFileId(fileId);
        backupMaterial.setBackupName(backupUploadVo.getBackupName());
        String relativePath = destFilePath.replace(realPath, "");
        backupMaterial.setFilePath(relativePath);
        backupMaterial.setFileType(backupUploadVo.getFileType());
        backupMaterial.setCreatedTime(LocalDateTime.now());
        backupMaterial.setCreatedBy("admin");
        backupMaterialMapper.insert(backupMaterial);
        //添加审片间垫片配置
        LambdaQueryWrapper<BackupConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BackupConfig::getRoomId,backupUploadVo.getRoomId());
        wrapper.eq(BackupConfig::getBackupOrder,backupUploadVo.getBackupOrder());
        BackupConfig backupConfig = backupConfigMapper.selectOne(wrapper);
        if(ObjectUtil.isNull(backupConfig)){
            backupConfig = new BackupConfig();
        }
        backupConfig.setRoomId(backupUploadVo.getRoomId());
        backupConfig.setBackupId(backupMaterial.getId());
        backupConfig.setBackupOrder(backupUploadVo.getBackupOrder());
        backupConfig.setBackupStatus(backupUploadVo.getBackupStatus());
        backupConfig.setBackupPath(relativePath);
        backupConfigMapper.insertOrUpdate(backupConfig);

        //对应垫片任务切源(转码平台演示环境已挂载统一存储),请求转码平台修改垫片任务直播源
        changeChannelSource(streamTask.getTaskId(), destFilePath);
        //判断是否需要修改当前播出流的垫片
        if("1".equals(backupConfig.getBackupStatus())){
            //切换播出流垫片(主、备)
            LambdaQueryWrapper<StreamTask> playWrapper = new LambdaQueryWrapper<>();
            playWrapper.eq(StreamTask::getRoomId,backupUploadVo.getRoomId());
            playWrapper.eq(StreamTask::getPlayType,"play");
            List<StreamTask> playTasks = streamTaskMapper.selectList(playWrapper);
            if(CollectionUtil.isNotEmpty(playTasks)){
                playTasks.forEach(playTask -> {
                    changeBackup(playTask.getTaskId(), destFilePath);
                });
            }
        }

        return ResultBean.ok("上传成功");
    }

    /**
     * 修改转码任务垫片
     * @param taskId
     * @param destFilePath
     */
    private void changeBackup(String taskId, String destFilePath) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("taskId", taskId);
        paramsMap.put("backupUrl", destFilePath);
        HttpResponse execute = null;
        try {
            execute = HttpRequest.post(swapBackupUrl)
                    .header("Content-Type", "application/json")
                    .body(JSONUtils.obj2json(paramsMap)).timeout(30000).execute();
            if (execute.isOk()) {
                log.info("-->请求转码系统换垫片接口,url:{},paramsMap:{}",swapBackupUrl,paramsMap);
                String body = execute.body();
                ResponseData response = JSONUtils.jsonToObject(body, new TypeReference<ResponseData>() {
                });
                if (response.getResultCode().equals("0")) {
                    log.info("请求转码系统换垫片接口成功");
                }else {
                    log.info("请求转码系统换垫片接口响应失败,response:{}",response);
                    throw new ServiceException("请求转码系统换垫片接口响应失败");
                }
            } else {
                log.error("请求转码系统换垫片接口失败,url:{},body:{}", swapBackupUrl, execute.body());
            }
        } catch (Exception e) {
            log.error("请求转码系统换垫片接口失败,url:{}", swapBackupUrl, e);
        }
    }

    private void changeChannelSource(String taskId, String destFilePath) {
        ChangeSourceParam param = new ChangeSourceParam();
        param.setTaskId(taskId);
        SourceUrl sourceUrl = new SourceUrl();
        sourceUrl.setSourceUrl(destFilePath);
        sourceUrl.setPri(0);
        param.setSourceUrls(Arrays.asList(sourceUrl));
        HttpResponse execute = null;
        try {
            execute = HttpRequest.post(switchStreamUrl)
                    .header("Content-Type", "application/json")
                    .body(JSONUtils.obj2json(param)).timeout(30000).execute();
            if (execute.isOk()) {
                log.info("-->请求转码系统切换直播源接口,url:{},paramsMap:{}",switchStreamUrl,param);
                String body = execute.body();
                ResponseData response = JSONUtils.jsonToObject(body, new TypeReference<ResponseData>() {
                });
                if (response.getResultCode().equals("0")) {
                    log.info("请求转码系统切换直播源接口成功");
                }else {
                    log.info("请求转码系统切换直播源接口响应失败,response:{}",response);
                    throw new ServiceException("请求转码系统切换直播源接口响应失败");
                }
            } else {
                log.error("请求转码系统切换直播源接口失败,url:{},body:{}", switchStreamUrl, execute.body());
            }
        } catch (Exception e) {
            log.error("请求转码系统切换直播源接口失败,url:{}", switchStreamUrl, e);
        }
    }

    @Override
    public ResultBean getByRoom(Long roomId) {
        LambdaQueryWrapper<BackupConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BackupConfig::getRoomId,roomId);
        List<BackupConfig> backupConfigs = backupConfigMapper.selectList(wrapper);
        return ResultBean.ok(backupConfigs);
    }

    @Override
    public ResultBean change(BackupChangeDto backupChangeDto) {
        LambdaQueryWrapper<BackupConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BackupConfig::getRoomId,backupChangeDto.getRoomId());
        List<BackupConfig> backupConfigs = backupConfigMapper.selectList(wrapper);
        if(CollectionUtil.isNotEmpty(backupConfigs)){
            backupConfigs.forEach(backupConfig -> {
                if(backupConfig.getBackupId().equals(backupChangeDto.getBackupId())){
                    backupConfig.setBackupStatus("1");
                    //将播放流的垫片配置切到此垫片上,播放流主、备都切换
                    LambdaQueryWrapper<StreamTask> playWrapper = new LambdaQueryWrapper<>();
                    playWrapper.eq(StreamTask::getRoomId,backupChangeDto.getRoomId());
                    playWrapper.eq(StreamTask::getPlayType,"play");
                    List<StreamTask> playTasks = streamTaskMapper.selectList(playWrapper);
                    if(CollectionUtil.isNotEmpty(playTasks)){
                        String backupPath = realPath + backupConfig.getBackupPath();
                        playTasks.forEach(playTask -> {
                            changeBackup(playTask.getTaskId(), backupPath);
                        });
                    }
                }else {
                    //将其他垫片配置切到默认状态
                    backupConfig.setBackupStatus("0");
                }
                backupConfigMapper.updateById(backupConfig);
            });

        }
        return ResultBean.ok();
    }

}