ard-sample/src/main/java/com/ard/sample/wayline/service/impl/WaylineJobServiceImpl.java
@@ -1,5 +1,8 @@
package com.ard.sample.wayline.service.impl;
import com.ard.oss.service.impl.OssServiceContext;
import com.ard.route.domain.route.ArdRouteInformation;
import com.ard.route.service.IArdRouteInformationService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -29,6 +32,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
@@ -37,6 +41,11 @@
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.SQLException;
import java.time.Instant;
@@ -44,6 +53,8 @@
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import static com.ard.route.util.ToolUtils.kmzPath;
/**
 * @author sean
@@ -58,8 +69,14 @@
    @Autowired
    private IWaylineJobMapper mapper;
//    @Autowired
//    private IWaylineFileService waylineFileService;
    @Autowired
    private IWaylineFileService waylineFileService;
    private IArdRouteInformationService _ardRouteInformationService;
    @Resource
    private OssServiceContext _ossService;
    @Autowired
    private IDeviceService deviceService;
@@ -73,6 +90,12 @@
    @Autowired
    private IFileService fileService;
    /**
     * 插入航路作业
     *
     * @param jobEntity 航路作业实体
     * @return 航路作业DTO的Optional包装对象,如果插入失败则返回Optional.empty()
     */
    private Optional<WaylineJobDTO> insertWaylineJob(WaylineJobEntity jobEntity) {
        int id = mapper.insert(jobEntity);
        if (id <= 0) {
@@ -81,6 +104,15 @@
        return Optional.ofNullable(this.entity2Dto(jobEntity));
    }
    /**
     * 创建航线任务
     *
     * @param param    任务参数
     * @param username 用户名
     * @param beginTime 开始时间
     * @param endTime   结束时间
     * @return Optional<WaylineJobDTO> 返回创建的航线任务对象,若创建失败则返回Optional.empty()
     */
    @Override
    public Optional<WaylineJobDTO> createWaylineJob(CreateJobParam param, String username, Long beginTime, Long endTime) {
        if (Objects.isNull(param)) {
@@ -106,6 +138,12 @@
        return insertWaylineJob(jobEntity);
    }
    /**
     * 根据父作业ID创建新的作业
     *
     * @param parentId 父作业ID
     * @return 新创建的作业的DTO对象,如果父作业不存在,则返回Optional.empty()
     */
    @Override
    public Optional<WaylineJobDTO> createWaylineJobByParent(String parentId) {
        Optional<WaylineJobDTO> parentJobOpt = this.getJobByJobId(parentId);
@@ -123,6 +161,14 @@
        return this.insertWaylineJob(jobEntity);
    }
    /**
     * 发布飞行任务
     *
     * @param param 任务参数
     * @param loginUser 登录用户
     * @return ResponseResult 返回结果
     * @throws SQLException SQL异常
     */
    @Override
    public ResponseResult publishFlightTask(CreateJobParam param, LoginUser loginUser) throws SQLException {
        if (WaylineTaskTypeEnum.IMMEDIATE.getVal() == param.getTaskType()) {
@@ -141,13 +187,29 @@
        }
        // get wayline file
        Optional<WaylineFileDTO> waylineFile = waylineFileService.getWaylineByWaylineId(waylineJob.getFileId());
        if (waylineFile.isEmpty()) {
//        Optional<WaylineFileDTO> waylineFile = waylineFileService.getWaylineByWaylineId(waylineJob.getFileId());
//        if (waylineFile.isEmpty()) {
//            return ResponseResult.error("机场任务航线不存在!");
//        }
        // 换航线表
        ArdRouteInformation ardRouteOpt = _ardRouteInformationService.selectArdRouteInformationById(waylineJob.getFileId());
        if (ardRouteOpt == null) {
            return ResponseResult.error("机场任务航线不存在!");
        }
        // get file url
        URL url = waylineFileService.getObjectUrl(waylineFile.get().getWaylineId());
//        URL url = waylineFileService.getObjectUrl(waylineFile.get().getWaylineId());
        URL url= null;
        String minioUrl = ardRouteOpt.getMinioUpPath();
        String md5 = "";
        try (InputStream inputStream = _ossService.getObject(kmzPath,minioUrl))
        {
            md5 = DigestUtils.md5Hex(inputStream);
            url = new URL(ardRouteOpt.getUpPath());
        }
        catch (Exception e) {
            return ResponseResult.error("机场任务航线文件地址错误!" + e.getMessage());
        }
        WaylineTaskCreateDTO flightTask = WaylineTaskCreateDTO.builder()
                .flightId(waylineJob.getJobId())
@@ -158,7 +220,13 @@
                .outOfControlAction(waylineJob.getOutOfControlAction())
                .file(WaylineTaskFileDTO.builder()
                        .url(url.toString())
                        .fingerprint(waylineFile.get().getSign())
//                        .fingerprint(waylineFile.get().getSign())
                        .fingerprint(md5)
                        .build())
                .simulateMission(WaylineSimulateMissionDTO.builder()
                        .isEnable(param.getSimulateMission().getIsEnable())
                        .latitude(param.getSimulateMission().getLatitude())
                        .longitude(param.getSimulateMission().getLongitude())
                        .build())
                .build();
@@ -184,25 +252,34 @@
            return ResponseResult.error("Prepare task ====> Error code: " + serviceReply.getResult());
        }
        // 飞行命令先注释掉
        // Issue an immediate task execution command.
        if (WaylineTaskTypeEnum.IMMEDIATE.getVal() == waylineJob.getTaskType()) {
            if (!executeFlightTask(waylineJob.getJobId())) {
                return ResponseResult.error("Failed to execute job.");
            }
        }
        if (WaylineTaskTypeEnum.TIMED.getVal() == waylineJob.getTaskType()) {
            boolean isAdd = RedisOpsUtils.zAdd(RedisConst.WAYLINE_JOB_TIMED_EXECUTE,
                     waylineJob.getDockSn() + RedisConst.DELIMITER + waylineJob.getJobId(),
                    waylineJob.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
            if (!isAdd) {
                return ResponseResult.error("Failed to create scheduled job.");
            }
        }
//        if (WaylineTaskTypeEnum.IMMEDIATE.getVal() == waylineJob.getTaskType()) {
//            if (!executeFlightTask(waylineJob.getJobId())) {
//                return ResponseResult.error("Failed to execute job.");
//            }
//        }
//
//        if (WaylineTaskTypeEnum.TIMED.getVal() == waylineJob.getTaskType()) {
//            boolean isAdd = RedisOpsUtils.zAdd(RedisConst.WAYLINE_JOB_TIMED_EXECUTE,
//                     waylineJob.getDockSn() + RedisConst.DELIMITER + waylineJob.getJobId(),
//                    waylineJob.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
//            if (!isAdd) {
//                return ResponseResult.error("Failed to create scheduled job.");
//            }
//        }
        return ResponseResult.success();
    }
    /**
     * 执行飞行任务
     *
     * @param jobId 任务ID
     * @return 如果任务执行成功返回true,否则返回false
     * @throws IllegalArgumentException 如果任务不存在
     * @throws RuntimeException 如果设备处于离线状态
     */
    @Override
    public Boolean executeFlightTask(String jobId) {
        // get job
@@ -252,6 +329,12 @@
        return true;
    }
    /**
     * 取消飞行任务
     *
     * @param jobIds 需要取消的任务ID集合
     * @throws IllegalArgumentException 如果任务状态不正确,抛出非法参数异常
     */
    @Override
    public void cancelFlightTask(Collection<String> jobIds) {
        List<WaylineJobDTO> waylineJobs = getJobsByConditions(jobIds, WaylineJobStatusEnum.PENDING);
@@ -272,6 +355,13 @@
    }
    /**
     * 发布取消任务
     *
     * @param dockSn 设备序列号
     * @param jobIds   任务ID列表
     * @throws RuntimeException 如果设备离线或取消任务失败,则抛出运行时异常
     */
    @Override
    public void publishCancelTask(String dockSn, List<String> jobIds) {
        boolean isOnline = deviceService.checkDeviceOnline(dockSn);
@@ -305,6 +395,13 @@
    }
    /**
     * 根据条件查询作业列表
     *
     * @param jobIds 作业ID集合
     * @param status 作业状态枚举
     * @return 满足条件的作业DTO列表
     */
    @Override
    public List<WaylineJobDTO> getJobsByConditions(Collection<String> jobIds, WaylineJobStatusEnum status) {
        return mapper.selectList(
@@ -317,6 +414,12 @@
                .collect(Collectors.toList());
    }
    /**
     * 根据任务ID获取任务详情
     *
     * @param jobId 任务ID
     * @return Optional<WaylineJobDTO> 包含任务详情的Optional对象,如果不存在则返回空的Optional
     */
    @Override
    public Optional<WaylineJobDTO> getJobByJobId(String jobId) {
        WaylineJobEntity jobEntity = mapper.selectOne(
@@ -325,6 +428,12 @@
        return Optional.ofNullable(entity2Dto(jobEntity));
    }
    /**
     * 更新作业信息
     *
     * @param dto 作业信息传输对象
     * @return 更新成功返回true,否则返回false
     */
    @Override
    public Boolean updateJob(WaylineJobDTO dto) {
        return mapper.update(this.dto2Entity(dto),
@@ -332,6 +441,13 @@
                        .eq(WaylineJobEntity::getJobId, dto.getJobId())) > 0;
    }
    /**
     * 根据工作区ID获取工作线任务分页数据
     *
     * @param page     页码,从1开始
     * @param pageSize 每页显示条数
     * @return PaginationData 包含工作线任务分页数据的对象
     */
    @Override
    public PaginationData<WaylineJobDTO> getJobsByWorkspaceId(long page, long pageSize) {
        Page<WaylineJobEntity> pageData = mapper.selectPage(
@@ -347,6 +463,18 @@
    }
    /**
     * 根据航班任务ID获取航班任务资源
     *
     * @param receiver 接收到的消息对象
     * @param headers  消息头信息
     *
     * @Override 覆盖父类方法
     * @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_FLIGHT_TASK_RESOURCE_GET, outputChannel = ChannelName.OUTBOUND)
     *             指定输入通道和输出通道
     * @Transactional(isolation = Isolation.READ_UNCOMMITTED)
     *             设置事务隔离级别为未提交读
     */
    @Override
    @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_FLIGHT_TASK_RESOURCE_GET, outputChannel = ChannelName.OUTBOUND)
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
@@ -373,8 +501,16 @@
        WaylineJobDTO waylineJob = waylineJobOpt.get();
        // get wayline file
        Optional<WaylineFileDTO> waylineFile = waylineFileService.getWaylineByWaylineId(waylineJob.getFileId());
        if (waylineFile.isEmpty()) {
//        Optional<WaylineFileDTO> waylineFile = waylineFileService.getWaylineByWaylineId(waylineJob.getFileId());
//        if (waylineFile.isEmpty()) {
//            builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
//            messageSender.publish(topic, builder.build());
//            return;
//        }
        // 修改航线文件名称,从ard_route_information航线表中取;
        // 换航线表
        ArdRouteInformation ardRouteOpt = _ardRouteInformationService.selectArdRouteInformationById(waylineJob.getFileId());
        if (ardRouteOpt == null) {
            builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
            messageSender.publish(topic, builder.build());
            return;
@@ -382,16 +518,25 @@
        // get file url
        URL url = null;
        try {
            url = waylineFileService.getObjectUrl(waylineFile.get().getWaylineId());
        String minioUrl = ardRouteOpt.getMinioUpPath();
        String md5 = "";
        try (InputStream inputStream = _ossService.getObject(kmzPath,minioUrl))
        {
            md5 = DigestUtils.md5Hex(inputStream);
            url = new URL(ardRouteOpt.getUpPath());
//        }
//        try {
//            url = waylineFileService.getObjectUrl(waylineFile.get().getWaylineId());
//            url = new URL(ardRouteOpt.getUpPath());
            builder.data(RequestsReply.success(WaylineTaskCreateDTO.builder()
                    .file(WaylineTaskFileDTO.builder()
                            .url(url.toString())
                            .fingerprint(waylineFile.get().getSign())
//                            .fingerprint(waylineFile.get().getSign())
                            .fingerprint(md5)
                            .build())
                    .build()));
        } catch (SQLException | NullPointerException e) {
        } catch (NullPointerException | IOException e) {
            e.printStackTrace();
            builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
            messageSender.publish(topic, builder.build());
@@ -402,6 +547,12 @@
    }
    /**
     * 上传媒体文件的最高优先级
     *
     * @param jobId 作业ID
     * @throws RuntimeException 如果作业ID不合法或设置优先级失败
     */
    @Override
    public void uploadMediaHighestPriority(String jobId) {
        Optional<WaylineJobDTO> jobOpt = getJobByJobId(jobId);
@@ -429,6 +580,12 @@
        }
    }
    /**
     * 将WaylineJobDTO对象转换为WaylineJobEntity对象
     *
     * @param dto WaylineJobDTO对象
     * @return WaylineJobEntity对象
     */
    private WaylineJobEntity dto2Entity(WaylineJobDTO dto) {
        WaylineJobEntity.WaylineJobEntityBuilder builder = WaylineJobEntity.builder();
        if (dto == null) {
@@ -462,17 +619,25 @@
                .build();
    }
    /**
     * 将实体对象转换为数据传输对象
     *
     * @param entity WaylineJobEntity 实体对象
     * @return WaylineJobDTO 数据传输对象
     */
    private WaylineJobDTO entity2Dto(WaylineJobEntity entity) {
        if (entity == null) {
            return null;
        }
        // 修改航线文件名称,从ard_route_information航线表中取;
        WaylineJobDTO.WaylineJobDTOBuilder builder = WaylineJobDTO.builder()
                .jobId(entity.getJobId())
                .jobName(entity.getName())
                .fileId(entity.getFileId())
                .fileName(waylineFileService.getWaylineByWaylineId(entity.getFileId())
                        .orElse(WaylineFileDTO.builder().build()).getName())
//                .fileName(waylineFileService.getWaylineByWaylineId(entity.getFileId())
//                        .orElse(WaylineFileDTO.builder().build()).getName())
                .fileName(_ardRouteInformationService.selectArdRouteInformationById(entity.getFileId())
                        .getFileName())
                .dockSn(entity.getDockSn())
                .dockName(deviceService.getDeviceBySn(entity.getDockSn())
                        .orElse(DeviceDTO.builder().build()).getNickname())