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;
|
import com.ard.common.core.domain.model.LoginUser;
|
import com.ard.sample.common.error.CommonErrorEnum;
|
import com.ard.sample.common.model.Pagination;
|
import com.ard.sample.common.model.PaginationData;
|
import com.ard.sample.common.model.ResponseResult;
|
import com.ard.sample.component.mqtt.model.*;
|
import com.ard.sample.component.mqtt.service.IMessageSenderService;
|
import com.ard.common.core.redis.RedisConst;
|
import com.ard.common.core.redis.RedisOpsUtils;
|
import com.ard.sample.manage.model.dto.DeviceDTO;
|
import com.ard.sample.manage.service.IDeviceService;
|
import com.ard.sample.media.model.MediaFileCountDTO;
|
import com.ard.sample.media.model.MediaMethodEnum;
|
import com.ard.sample.media.service.IFileService;
|
import com.ard.sample.wayline.mapper.IWaylineJobMapper;
|
import com.ard.sample.wayline.model.dto.*;
|
import com.ard.sample.wayline.model.entity.WaylineJobEntity;
|
import com.ard.sample.wayline.model.enums.WaylineJobStatusEnum;
|
import com.ard.sample.wayline.model.enums.WaylineMethodEnum;
|
import com.ard.sample.wayline.model.enums.WaylineTaskTypeEnum;
|
import com.ard.sample.wayline.model.param.CreateJobParam;
|
import com.ard.sample.wayline.service.IWaylineFileService;
|
import com.ard.sample.wayline.service.IWaylineJobService;
|
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;
|
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.stereotype.Service;
|
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;
|
import java.time.LocalDateTime;
|
import java.time.ZoneId;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static com.ard.route.util.ToolUtils.kmzPath;
|
|
/**
|
* @author sean
|
* @version 1.1
|
* @date 2022/6/1
|
*/
|
@Service
|
@Transactional
|
@Slf4j
|
public class WaylineJobServiceImpl implements IWaylineJobService {
|
|
@Autowired
|
private IWaylineJobMapper mapper;
|
|
// @Autowired
|
// private IWaylineFileService waylineFileService;
|
|
@Autowired
|
private IArdRouteInformationService _ardRouteInformationService;
|
|
@Resource
|
private OssServiceContext _ossService;
|
|
@Autowired
|
private IDeviceService deviceService;
|
|
@Autowired
|
private IMessageSenderService messageSender;
|
|
@Autowired
|
private ObjectMapper objectMapper;
|
|
@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) {
|
return Optional.empty();
|
}
|
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)) {
|
return Optional.empty();
|
}
|
// Immediate tasks, allocating time on the backend.
|
WaylineJobEntity jobEntity = WaylineJobEntity.builder()
|
.name(param.getName())
|
.dockSn(param.getDockSn())
|
.fileId(param.getFileId())
|
.username(username)
|
.jobId(UUID.randomUUID().toString())
|
.beginTime(beginTime)
|
.endTime(endTime)
|
.status(WaylineJobStatusEnum.PENDING.getVal())
|
.taskType(param.getTaskType())
|
.waylineType(param.getWaylineType())
|
.outOfControlAction(param.getOutOfControlAction())
|
.rthAltitude(param.getRthAltitude())
|
.mediaCount(0)
|
.build();
|
|
return insertWaylineJob(jobEntity);
|
}
|
|
/**
|
* 根据父作业ID创建新的作业
|
*
|
* @param parentId 父作业ID
|
* @return 新创建的作业的DTO对象,如果父作业不存在,则返回Optional.empty()
|
*/
|
@Override
|
public Optional<WaylineJobDTO> createWaylineJobByParent(String parentId) {
|
Optional<WaylineJobDTO> parentJobOpt = this.getJobByJobId(parentId);
|
if (parentJobOpt.isEmpty()) {
|
return Optional.empty();
|
}
|
WaylineJobEntity jobEntity = this.dto2Entity(parentJobOpt.get());
|
jobEntity.setJobId(UUID.randomUUID().toString());
|
jobEntity.setErrorCode(null);
|
jobEntity.setCompletedTime(null);
|
jobEntity.setExecuteTime(null);
|
jobEntity.setStatus(WaylineJobStatusEnum.PENDING.getVal());
|
jobEntity.setParentId(parentId);
|
|
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()) {
|
param.setExecuteTime(System.currentTimeMillis());
|
}
|
Optional<WaylineJobDTO> waylineJobOpt = this.createWaylineJob(param, loginUser.getUsername(),
|
param.getExecuteTime(), param.getExecuteTime());
|
if (waylineJobOpt.isEmpty()) {
|
return ResponseResult.error("创建机场任务失败!");
|
}
|
WaylineJobDTO waylineJob = waylineJobOpt.get();
|
|
boolean isOnline = deviceService.checkDeviceOnline(waylineJob.getDockSn());
|
if (!isOnline) {
|
return ResponseResult.error("机场不在线!");
|
}
|
|
// get wayline file
|
// 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= 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())
|
.executeTime(waylineJob.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())
|
.taskType(waylineJob.getTaskType())
|
.waylineType(waylineJob.getWaylineType())
|
.rthAltitude(waylineJob.getRthAltitude())
|
.outOfControlAction(waylineJob.getOutOfControlAction())
|
.file(WaylineTaskFileDTO.builder()
|
.url(url.toString())
|
// .fingerprint(waylineFile.get().getSign())
|
.fingerprint(md5)
|
.build())
|
.simulateMission(WaylineSimulateMissionDTO.builder()
|
.isEnable(param.getSimulateMission().getIsEnable())
|
.latitude(param.getSimulateMission().getLatitude())
|
.longitude(param.getSimulateMission().getLongitude())
|
.build())
|
.build();
|
|
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT +
|
waylineJob.getDockSn() + TopicConst.SERVICES_SUF;
|
CommonTopicResponse<Object> response = CommonTopicResponse.builder()
|
.tid(UUID.randomUUID().toString())
|
.bid(waylineJob.getJobId())
|
.timestamp(System.currentTimeMillis())
|
.data(flightTask)
|
.method(WaylineMethodEnum.FLIGHT_TASK_PREPARE.getMethod())
|
.build();
|
|
ServiceReply serviceReply = messageSender.publishWithReply(topic, response);
|
if (ResponseResult.CODE_SUCCESS != serviceReply.getResult()) {
|
log.info("Prepare task ====> Error code: {}", serviceReply.getResult());
|
this.updateJob(WaylineJobDTO.builder()
|
.jobId(waylineJob.getJobId())
|
.executeTime(LocalDateTime.now())
|
.status(WaylineJobStatusEnum.FAILED.getVal())
|
.completedTime(LocalDateTime.now())
|
.code(serviceReply.getResult()).build());
|
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.");
|
// }
|
// }
|
|
return ResponseResult.success();
|
}
|
|
/**
|
* 执行飞行任务
|
*
|
* @param jobId 任务ID
|
* @return 如果任务执行成功返回true,否则返回false
|
* @throws IllegalArgumentException 如果任务不存在
|
* @throws RuntimeException 如果设备处于离线状态
|
*/
|
@Override
|
public Boolean executeFlightTask(String jobId) {
|
// get job
|
Optional<WaylineJobDTO> waylineJob = this.getJobByJobId(jobId);
|
if (waylineJob.isEmpty()) {
|
throw new IllegalArgumentException("Job doesn't exist.");
|
}
|
|
boolean isOnline = deviceService.checkDeviceOnline(waylineJob.get().getDockSn());
|
if (!isOnline) {
|
throw new RuntimeException("Dock is offline.");
|
}
|
|
WaylineJobDTO job = waylineJob.get();
|
WaylineTaskCreateDTO flightTask = WaylineTaskCreateDTO.builder().flightId(jobId).build();
|
|
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT +
|
job.getDockSn() + TopicConst.SERVICES_SUF;
|
CommonTopicResponse<Object> response = CommonTopicResponse.builder()
|
.tid(UUID.randomUUID().toString())
|
.bid(jobId)
|
.timestamp(System.currentTimeMillis())
|
.data(flightTask)
|
.method(WaylineMethodEnum.FLIGHT_TASK_EXECUTE.getMethod())
|
.build();
|
|
ServiceReply serviceReply = messageSender.publishWithReply(topic, response);
|
if (ResponseResult.CODE_SUCCESS != serviceReply.getResult()) {
|
log.info("Execute job ====> Error code: {}", serviceReply.getResult());
|
this.updateJob(WaylineJobDTO.builder()
|
.jobId(jobId)
|
.executeTime(LocalDateTime.now())
|
.status(WaylineJobStatusEnum.FAILED.getVal())
|
.completedTime(LocalDateTime.now())
|
.code(serviceReply.getResult()).build());
|
return false;
|
}
|
|
this.updateJob(WaylineJobDTO.builder()
|
.jobId(jobId)
|
.executeTime(LocalDateTime.now())
|
.status(WaylineJobStatusEnum.IN_PROGRESS.getVal())
|
.build());
|
RedisOpsUtils.setWithExpire(RedisConst.WAYLINE_JOB_RUNNING_PREFIX + job.getDockSn(),
|
EventsReceiver.<WaylineTaskProgressReceiver>builder().bid(jobId).sn(job.getDockSn()).build(),
|
RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND);
|
return true;
|
}
|
|
/**
|
* 取消飞行任务
|
*
|
* @param jobIds 需要取消的任务ID集合
|
* @throws IllegalArgumentException 如果任务状态不正确,抛出非法参数异常
|
*/
|
@Override
|
public void cancelFlightTask(Collection<String> jobIds) {
|
List<WaylineJobDTO> waylineJobs = getJobsByConditions(jobIds, WaylineJobStatusEnum.PENDING);
|
|
Set<String> waylineJobIds = waylineJobs.stream().map(WaylineJobDTO::getJobId).collect(Collectors.toSet());
|
// Check if the task status is correct.
|
boolean isErr = !jobIds.removeAll(waylineJobIds) || !jobIds.isEmpty() ;
|
if (isErr) {
|
throw new IllegalArgumentException("These tasks have an incorrect status and cannot be canceled. "
|
+ Arrays.toString(jobIds.toArray()));
|
}
|
|
// Group job id by dock sn.
|
Map<String, List<String>> dockJobs = waylineJobs.stream()
|
.collect(Collectors.groupingBy(WaylineJobDTO::getDockSn,
|
Collectors.mapping(WaylineJobDTO::getJobId, Collectors.toList())));
|
dockJobs.forEach((dockSn, idList) -> this.publishCancelTask(dockSn, idList));
|
|
}
|
|
/**
|
* 发布取消任务
|
*
|
* @param dockSn 设备序列号
|
* @param jobIds 任务ID列表
|
* @throws RuntimeException 如果设备离线或取消任务失败,则抛出运行时异常
|
*/
|
@Override
|
public void publishCancelTask(String dockSn, List<String> jobIds) {
|
boolean isOnline = deviceService.checkDeviceOnline(dockSn);
|
if (!isOnline) {
|
throw new RuntimeException("Dock is offline.");
|
}
|
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + dockSn + TopicConst.SERVICES_SUF;
|
|
CommonTopicResponse<Object> response = CommonTopicResponse.builder()
|
.tid(UUID.randomUUID().toString())
|
.bid(UUID.randomUUID().toString())
|
.timestamp(System.currentTimeMillis())
|
.data(Map.of(MapKeyConst.FLIGHT_IDS, jobIds))
|
.method(WaylineMethodEnum.FLIGHT_TASK_CANCEL.getMethod())
|
.build();
|
|
ServiceReply serviceReply = messageSender.publishWithReply(topic, response);
|
if (ResponseResult.CODE_SUCCESS != serviceReply.getResult()) {
|
log.info("Cancel job ====> Error code: {}", serviceReply.getResult());
|
throw new RuntimeException("Failed to cancel the wayline job of " + dockSn);
|
}
|
|
for (String jobId : jobIds) {
|
this.updateJob(WaylineJobDTO.builder()
|
.jobId(jobId)
|
.status(WaylineJobStatusEnum.CANCEL.getVal())
|
.completedTime(LocalDateTime.now())
|
.build());
|
RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB_TIMED_EXECUTE, RedisConst.DELIMITER + dockSn + RedisConst.DELIMITER + jobId);
|
}
|
|
}
|
|
/**
|
* 根据条件查询作业列表
|
*
|
* @param jobIds 作业ID集合
|
* @param status 作业状态枚举
|
* @return 满足条件的作业DTO列表
|
*/
|
@Override
|
public List<WaylineJobDTO> getJobsByConditions(Collection<String> jobIds, WaylineJobStatusEnum status) {
|
return mapper.selectList(
|
new LambdaQueryWrapper<WaylineJobEntity>()
|
.eq(Objects.nonNull(status), WaylineJobEntity::getStatus, status.getVal())
|
.and(!CollectionUtils.isEmpty(jobIds),
|
wrapper -> jobIds.forEach(id -> wrapper.eq(WaylineJobEntity::getJobId, id).or())))
|
.stream()
|
.map(this::entity2Dto)
|
.collect(Collectors.toList());
|
}
|
|
/**
|
* 根据任务ID获取任务详情
|
*
|
* @param jobId 任务ID
|
* @return Optional<WaylineJobDTO> 包含任务详情的Optional对象,如果不存在则返回空的Optional
|
*/
|
@Override
|
public Optional<WaylineJobDTO> getJobByJobId(String jobId) {
|
WaylineJobEntity jobEntity = mapper.selectOne(
|
new LambdaQueryWrapper<WaylineJobEntity>()
|
.eq(WaylineJobEntity::getJobId, jobId));
|
return Optional.ofNullable(entity2Dto(jobEntity));
|
}
|
|
/**
|
* 更新作业信息
|
*
|
* @param dto 作业信息传输对象
|
* @return 更新成功返回true,否则返回false
|
*/
|
@Override
|
public Boolean updateJob(WaylineJobDTO dto) {
|
return mapper.update(this.dto2Entity(dto),
|
new LambdaUpdateWrapper<WaylineJobEntity>()
|
.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(
|
new Page<WaylineJobEntity>(page, pageSize),
|
new LambdaQueryWrapper<WaylineJobEntity>()
|
.orderByDesc(WaylineJobEntity::getId));
|
List<WaylineJobDTO> records = pageData.getRecords()
|
.stream()
|
.map(this::entity2Dto)
|
.collect(Collectors.toList());
|
|
return new PaginationData<WaylineJobDTO>(records, new Pagination(pageData));
|
}
|
|
|
/**
|
* 根据航班任务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)
|
public void flightTaskResourceGet(CommonTopicReceiver receiver, MessageHeaders headers) {
|
Map<String, String> jobIdMap = objectMapper.convertValue(receiver.getData(), new TypeReference<Map<String, String>>() {});
|
String jobId = jobIdMap.get(MapKeyConst.FLIGHT_ID);
|
|
CommonTopicResponse.CommonTopicResponseBuilder<RequestsReply> builder = CommonTopicResponse.<RequestsReply>builder()
|
.tid(receiver.getTid())
|
.bid(receiver.getBid())
|
.method(RequestsMethodEnum.FLIGHT_TASK_RESOURCE_GET.getMethod())
|
.timestamp(System.currentTimeMillis());
|
|
String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString() + TopicConst._REPLY_SUF;
|
|
DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway());
|
Optional<WaylineJobDTO> waylineJobOpt = this.getJobByJobId(jobId);
|
if (waylineJobOpt.isEmpty()) {
|
builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
|
messageSender.publish(topic, builder.build());
|
return;
|
}
|
|
WaylineJobDTO waylineJob = waylineJobOpt.get();
|
|
// get wayline file
|
// 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;
|
}
|
|
// get file url
|
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());
|
// }
|
// 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(md5)
|
.build())
|
.build()));
|
|
} catch (NullPointerException | IOException e) {
|
e.printStackTrace();
|
builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
|
messageSender.publish(topic, builder.build());
|
return;
|
}
|
|
messageSender.publish(topic, builder.build());
|
|
}
|
|
/**
|
* 上传媒体文件的最高优先级
|
*
|
* @param jobId 作业ID
|
* @throws RuntimeException 如果作业ID不合法或设置优先级失败
|
*/
|
@Override
|
public void uploadMediaHighestPriority(String jobId) {
|
Optional<WaylineJobDTO> jobOpt = getJobByJobId(jobId);
|
if (jobOpt.isEmpty()) {
|
throw new RuntimeException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg());
|
}
|
|
String dockSn = jobOpt.get().getDockSn();
|
String key = RedisConst.MEDIA_HIGHEST_PRIORITY_PREFIX + dockSn;
|
if (RedisOpsUtils.checkExist(key) &&
|
jobId.equals(((MediaFileCountDTO) RedisOpsUtils.get(key)).getJobId())) {
|
return;
|
}
|
|
ServiceReply reply = messageSender.publishWithReply(TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + dockSn + TopicConst.SERVICES_SUF,
|
CommonTopicResponse.builder()
|
.tid(UUID.randomUUID().toString())
|
.bid(UUID.randomUUID().toString())
|
.timestamp(System.currentTimeMillis())
|
.method(MediaMethodEnum.UPLOAD_FLIGHT_TASK_MEDIA_PRIORITIZE.getMethod())
|
.data(Map.of(MapKeyConst.FLIGHT_ID, jobId))
|
.build());
|
if (ResponseResult.CODE_SUCCESS != reply.getResult()) {
|
throw new RuntimeException("Failed to set media job upload priority. Error Code: " + reply.getResult());
|
}
|
}
|
|
/**
|
* 将WaylineJobDTO对象转换为WaylineJobEntity对象
|
*
|
* @param dto WaylineJobDTO对象
|
* @return WaylineJobEntity对象
|
*/
|
private WaylineJobEntity dto2Entity(WaylineJobDTO dto) {
|
WaylineJobEntity.WaylineJobEntityBuilder builder = WaylineJobEntity.builder();
|
if (dto == null) {
|
return builder.build();
|
}
|
if (Objects.nonNull(dto.getBeginTime())) {
|
builder.beginTime(dto.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
}
|
if (Objects.nonNull(dto.getEndTime())) {
|
builder.endTime(dto.getEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
}
|
if (Objects.nonNull(dto.getExecuteTime())) {
|
builder.executeTime(dto.getExecuteTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
}
|
if (Objects.nonNull(dto.getCompletedTime())) {
|
builder.completedTime(dto.getCompletedTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
}
|
return builder.status(dto.getStatus())
|
.mediaCount(dto.getMediaCount())
|
.name(dto.getJobName())
|
.errorCode(dto.getCode())
|
.jobId(dto.getJobId())
|
.fileId(dto.getFileId())
|
.dockSn(dto.getDockSn())
|
.taskType(dto.getTaskType())
|
.waylineType(dto.getWaylineType())
|
.username(dto.getUsername())
|
.rthAltitude(dto.getRthAltitude())
|
.outOfControlAction(dto.getOutOfControlAction())
|
.parentId(dto.getParentId())
|
.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(_ardRouteInformationService.selectArdRouteInformationById(entity.getFileId())
|
.getFileName())
|
.dockSn(entity.getDockSn())
|
.dockName(deviceService.getDeviceBySn(entity.getDockSn())
|
.orElse(DeviceDTO.builder().build()).getNickname())
|
.username(entity.getUsername())
|
.status(WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() &&
|
RedisOpsUtils.checkExist(RedisConst.WAYLINE_JOB_PAUSED_PREFIX + entity.getJobId()) ?
|
WaylineJobStatusEnum.PAUSED.getVal() : entity.getStatus())
|
.code(entity.getErrorCode())
|
.beginTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getBeginTime()), ZoneId.systemDefault()))
|
.endTime(Objects.nonNull(entity.getEndTime()) ?
|
LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getEndTime()), ZoneId.systemDefault()) : null)
|
.executeTime(Objects.nonNull(entity.getExecuteTime()) ?
|
LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getExecuteTime()), ZoneId.systemDefault()) : null)
|
.completedTime(WaylineJobStatusEnum.find(entity.getStatus()).getEnd() ?
|
LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getUpdateTime()), ZoneId.systemDefault()) : null)
|
.taskType(entity.getTaskType())
|
.waylineType(entity.getWaylineType())
|
.rthAltitude(entity.getRthAltitude())
|
.outOfControlAction(entity.getOutOfControlAction())
|
.mediaCount(entity.getMediaCount());
|
|
if (Objects.nonNull(entity.getEndTime())) {
|
builder.endTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getEndTime()), ZoneId.systemDefault()));
|
}
|
if (WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() && RedisOpsUtils.getExpire(entity.getJobId()) > 0) {
|
EventsReceiver<WaylineTaskProgressReceiver> taskProgress = (EventsReceiver<WaylineTaskProgressReceiver>) RedisOpsUtils.get(RedisConst.WAYLINE_JOB_RUNNING_PREFIX + entity.getDockSn());
|
if (Objects.nonNull(taskProgress.getOutput()) && Objects.nonNull(taskProgress.getOutput().getProgress())) {
|
builder.progress(taskProgress.getOutput().getProgress().getPercent());
|
}
|
}
|
|
if (entity.getMediaCount() == 0) {
|
return builder.build();
|
}
|
|
// sync the number of media files
|
String key = RedisConst.MEDIA_HIGHEST_PRIORITY_PREFIX + entity.getDockSn();
|
String countKey = RedisConst.MEDIA_FILE_PREFIX + entity.getDockSn();
|
Object mediaFileCount = RedisOpsUtils.hashGet(countKey, entity.getJobId());
|
if (Objects.nonNull(mediaFileCount)) {
|
builder.uploadedCount(((MediaFileCountDTO) mediaFileCount).getUploadedCount())
|
.uploading(RedisOpsUtils.checkExist(key) && entity.getJobId().equals(((MediaFileCountDTO)RedisOpsUtils.get(key)).getJobId()));
|
return builder.build();
|
}
|
|
int uploadedSize = fileService.getFilesByWorkspaceAndJobId(entity.getJobId()).size();
|
// All media for this job have been uploaded.
|
if (uploadedSize >= entity.getMediaCount()) {
|
return builder.uploadedCount(uploadedSize).build();
|
}
|
RedisOpsUtils.hashSet(countKey, entity.getJobId(),
|
MediaFileCountDTO.builder()
|
.jobId(entity.getJobId())
|
.mediaCount(entity.getMediaCount())
|
.uploadedCount(uploadedSize).build());
|
return builder.build();
|
}
|
}
|