package com.dji.sample.wayline.service.impl; 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.dji.sample.common.model.CustomClaim; import com.dji.sample.common.model.Pagination; import com.dji.sample.common.model.PaginationData; import com.dji.sample.component.mqtt.model.CommonTopicResponse; import com.dji.sample.component.mqtt.model.ServiceReply; import com.dji.sample.component.mqtt.model.ServicesMethodEnum; import com.dji.sample.component.mqtt.model.TopicConst; import com.dji.sample.component.mqtt.service.IMessageSenderService; import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.redis.RedisOpsUtils; import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.service.IDeviceService; import com.dji.sample.wayline.dao.IWaylineJobMapper; import com.dji.sample.wayline.model.dto.FlightTaskCreateDTO; import com.dji.sample.wayline.model.dto.FlightTaskFileDTO; import com.dji.sample.wayline.model.dto.WaylineFileDTO; import com.dji.sample.wayline.model.dto.WaylineJobDTO; import com.dji.sample.wayline.model.entity.WaylineJobEntity; import com.dji.sample.wayline.model.param.CreateJobParam; import com.dji.sample.wayline.service.IWaylineFileService; import com.dji.sample.wayline.service.IWaylineJobService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.net.URL; import java.sql.SQLException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; /** * @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 IDeviceService deviceService; @Autowired private IMessageSenderService messageSender; @Autowired private RedisOpsUtils redisOps; @Override public Boolean createJob(CreateJobParam param, CustomClaim customClaim) throws SQLException { if (param == null) { return false; } WaylineJobEntity jobEntity = WaylineJobEntity.builder() .name(param.getName()) .dockSn(param.getDockSn()) .fileId(param.getFileId()) .username(customClaim.getUsername()) .workspaceId(customClaim.getWorkspaceId()) .jobId(UUID.randomUUID().toString()) .type(param.getType()) .build(); int id = mapper.insert(jobEntity); if (id <= 0) { return false; } if (param.isImmediate()) { publishFlightTask(jobEntity.getWorkspaceId(), jobEntity.getJobId()); } return true; } @Override public void publishFlightTask(String workspaceId, String jobId) throws SQLException { // get job Optional waylineJob = this.getJobByJobId(jobId); if (waylineJob.isEmpty()) { throw new IllegalArgumentException("Job doesn't exist."); } long expire = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + waylineJob.get().getDockSn()); if (expire < 0) { throw new RuntimeException("Dock is offline."); } // get wayline file Optional waylineFile = waylineFileService.getWaylineByWaylineId(workspaceId, waylineJob.get().getFileId()); if (waylineFile.isEmpty()) { throw new IllegalArgumentException("Wayline file doesn't exist."); } // get file url URL url = waylineFileService.getObjectUrl(workspaceId, waylineFile.get().getWaylineId()); WaylineJobDTO job = waylineJob.get(); FlightTaskCreateDTO flightTask = FlightTaskCreateDTO.builder() .flightId(jobId) .type(job.getType()) .file(FlightTaskFileDTO.builder() .url(url.toString()) .sign(waylineFile.get().getSign()) .build()) .build(); String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + job.getDockSn() + TopicConst.SERVICES_SUF; CommonTopicResponse response = CommonTopicResponse.builder() .tid(UUID.randomUUID().toString()) .bid(UUID.randomUUID().toString()) .timestamp(System.currentTimeMillis()) .data(flightTask) .method(ServicesMethodEnum.FLIGHTTASK_CREATE.getMethod()) .build(); Optional serviceReplyOpt = messageSender.publishWithReply(topic, response); if (serviceReplyOpt.isEmpty()) { log.info("Timeout to receive reply."); throw new RuntimeException("Timeout to receive reply."); } if (serviceReplyOpt.get().getResult() != 0) { log.info("Error code: {}", serviceReplyOpt.get().getResult()); throw new RuntimeException("Error code: " + serviceReplyOpt.get().getResult()); } job.setBid(response.getBid()); boolean isUpd = this.updateJob(job); if (!isUpd) { throw new SQLException("Failed to update data."); } } @Override public Optional getJobByJobId(String jobId) { WaylineJobEntity jobEntity = mapper.selectOne( new LambdaQueryWrapper() .eq(WaylineJobEntity::getJobId, jobId)); return Optional.ofNullable(entity2Dto(jobEntity)); } @Override public Boolean updateJob(WaylineJobDTO dto) { return mapper.update(this.dto2Entity(dto), new LambdaUpdateWrapper() .eq(WaylineJobEntity::getWorkspaceId, dto.getWorkspaceId()) .eq(WaylineJobEntity::getJobId, dto.getJobId())) > 0; } @Override public PaginationData getJobsByWorkspaceId(String workspaceId, long page, long pageSize) { Page pageData = mapper.selectPage( new Page(page, pageSize), new LambdaQueryWrapper() .eq(WaylineJobEntity::getWorkspaceId, workspaceId)); List records = pageData.getRecords() .stream() .map(this::entity2Dto) .collect(Collectors.toList()); return new PaginationData(records, new Pagination(pageData)); } private WaylineJobEntity dto2Entity(WaylineJobDTO dto) { WaylineJobEntity.WaylineJobEntityBuilder builder = WaylineJobEntity.builder(); if (dto == null) { return builder.build(); } return builder.type(dto.getType()) .bid(dto.getBid()) .name(dto.getJobName()) .build(); } private WaylineJobDTO entity2Dto(WaylineJobEntity entity) { if (entity == null) { return null; } return WaylineJobDTO.builder() .jobId(entity.getJobId()) .bid(entity.getBid()) .updateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getUpdateTime()), ZoneId.systemDefault())) .jobName(entity.getName()) .fileId(entity.getFileId()) .fileName(waylineFileService.getWaylineByWaylineId(entity.getWorkspaceId(), entity.getFileId()) .orElse(WaylineFileDTO.builder().build()).getName()) .dockSn(entity.getDockSn()) .dockName(deviceService.getDeviceBySn(entity.getDockSn()) .orElse(DeviceDTO.builder().build()).getNickname()) .username(entity.getUsername()) .workspaceId(entity.getWorkspaceId()) .type(entity.getType()) .build(); } }