package com.dji.sample.manage.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.redis.RedisOpsUtils; import com.dji.sample.manage.dao.IDevicePayloadMapper; import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; import com.dji.sample.manage.model.dto.DevicePayloadDTO; import com.dji.sample.manage.model.entity.DevicePayloadEntity; import com.dji.sample.manage.model.enums.DeviceDomainEnum; import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; import com.dji.sample.manage.service.ICapacityCameraService; import com.dji.sample.manage.service.IDeviceDictionaryService; import com.dji.sample.manage.service.IDevicePayloadService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import java.util.*; import java.util.stream.Collectors; /** * @author sean.zhou * @version 0.1 * @date 2021/11/19 */ @Slf4j @Service @Transactional public class DevicePayloadServiceImpl implements IDevicePayloadService { @Autowired private IDevicePayloadMapper mapper; @Autowired private IDeviceDictionaryService dictionaryService; @Autowired private ICapacityCameraService capacityCameraService; @Override public Integer checkPayloadExist(String payloadSn) { DevicePayloadEntity devicePayload = mapper.selectOne( new LambdaQueryWrapper() .eq(DevicePayloadEntity::getPayloadSn, payloadSn)); return devicePayload != null ? devicePayload.getId() : -1; } private Integer saveOnePayloadEntity(DevicePayloadEntity entity) { int id = this.checkPayloadExist(entity.getPayloadSn()); // If it already exists, update the data directly. if (id > 0) { entity.setId(id); return mapper.updateById(entity); } return mapper.insert(entity) > 0 ? entity.getId() : 0; } @Override public Boolean savePayloadDTOs(List payloadReceiverList) { if (payloadReceiverList.isEmpty()) { return true; } String deviceSn = payloadReceiverList.get(0).getDeviceSn(); String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(key); List payloads = new ArrayList<>(); for (DevicePayloadReceiver payloadReceiver : payloadReceiverList) { int payloadId = this.saveOnePayloadDTO(payloadReceiver); if (payloadId <= 0) { return false; } payloads.add(this.receiver2Dto(payloadReceiver)); } if (payloads.isEmpty()) { payloads = this.getDevicePayloadEntitiesByDeviceSn(deviceSn); } device.setPayloadsList(payloads); RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), device, RedisConst.DEVICE_ALIVE_SECOND); return true; } @Override public Integer saveOnePayloadDTO(DevicePayloadReceiver payloadReceiver) { return this.saveOnePayloadEntity(payloadDTOConvertToEntity(payloadReceiver)); } @Override public List getDevicePayloadEntitiesByDeviceSn(String deviceSn) { return mapper.selectList( new LambdaQueryWrapper() .eq(DevicePayloadEntity::getDeviceSn, deviceSn)) .stream() .map(this::payloadEntityConvertToDTO) .collect(Collectors.toList()); } @Override public void deletePayloadsByDeviceSn(List deviceSns) { deviceSns.forEach(deviceSn -> { mapper.delete( new LambdaQueryWrapper() .eq(DevicePayloadEntity::getDeviceSn, deviceSn)); capacityCameraService.deleteCapacityCameraByDeviceSn(deviceSn); }); } @Override public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { mapper.update(DevicePayloadEntity.builder() .firmwareVersion(receiver.getFirmwareVersion()) .build() , new LambdaUpdateWrapper() .eq(DevicePayloadEntity::getDeviceSn, receiver.getSn())); } @Override public void saveDeviceBasicPayload(List payloadReceiverList, Long timestamp) { if (payloadReceiverList.isEmpty()) { return; } String deviceSn = payloadReceiverList.stream().findAny().get().getDeviceSn(); String key = RedisConst.STATE_PAYLOAD_PREFIX + deviceSn; // Solve timing problems long last = (long) Objects.requireNonNullElse(RedisOpsUtils.get(key), 0L); if (last > timestamp) { return; } // Filter unsaved payload information. Set payloadSns = this.getDevicePayloadEntitiesByDeviceSn(payloadReceiverList.get(0).getDeviceSn()) .stream().map(DevicePayloadDTO::getPayloadSn).collect(Collectors.toSet()); Set newPayloadSns = payloadReceiverList.stream().map(DevicePayloadReceiver::getSn).collect(Collectors.toSet()); Set needToDel = payloadSns.stream().filter(sn -> !newPayloadSns.contains(sn)).collect(Collectors.toSet()); this.deletePayloadsByPayloadsSn(needToDel); List needToSave = payloadReceiverList.stream() .filter(payload -> !payloadSns.contains(payload.getSn())).collect(Collectors.toList()); // Save the new payload information. boolean isSave = this.savePayloadDTOs(needToSave); if (isSave) { RedisOpsUtils.setWithExpire(key, timestamp, RedisConst.DEVICE_ALIVE_SECOND); } log.debug("The result of saving the payloads is {}.", isSave); } @Override public void deletePayloadsByPayloadsSn(Collection payloadSns) { if (CollectionUtils.isEmpty(payloadSns)) { return; } mapper.delete(new LambdaUpdateWrapper() .or(wrapper -> payloadSns.forEach(sn -> wrapper.eq(DevicePayloadEntity::getPayloadSn, sn)))); } /** * Convert database entity objects into payload data transfer object. * @param entity * @return */ private DevicePayloadDTO payloadEntityConvertToDTO(DevicePayloadEntity entity) { DevicePayloadDTO.DevicePayloadDTOBuilder builder = DevicePayloadDTO.builder(); if (entity != null) { builder.payloadSn(entity.getPayloadSn()) .payloadName(entity.getPayloadName()) .payloadDesc(entity.getPayloadDesc()) .payloadIndex(entity.getPayloadIndex()); } return builder.build(); } /** * Convert the received payload object into a database entity object. * @param dto payload * @return */ private DevicePayloadEntity payloadDTOConvertToEntity(DevicePayloadReceiver dto) { if (dto == null) { return new DevicePayloadEntity(); } DevicePayloadEntity.DevicePayloadEntityBuilder builder = DevicePayloadEntity.builder(); // The cameraIndex consists of type and subType and the index of the payload hanging on the drone. // type-subType-index String[] payloadIndexArr = dto.getPayloadIndex().split("-"); try { int[] arr = Arrays.stream(payloadIndexArr) .map(Integer::valueOf) .mapToInt(Integer::intValue) .toArray(); if (arr.length == 3) { Optional dictionaryOpt = dictionaryService .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.PAYLOAD.getVal(), arr[0], arr[1]); dictionaryOpt.ifPresent(dictionary -> builder.payloadName(dictionary.getDeviceName()) .payloadDesc(dictionary.getDeviceDesc())); } builder.payloadType(arr[0]) .subType(arr[1]) .payloadIndex(arr[2]); } catch (NumberFormatException e) { builder.payloadType(Integer.valueOf(payloadIndexArr[0])) .subType(-1) .payloadIndex(Integer.valueOf(payloadIndexArr[2])); } return builder .payloadSn(dto.getSn()) .deviceSn(dto.getDeviceSn()) .build(); } private DevicePayloadDTO receiver2Dto(DevicePayloadReceiver receiver) { DevicePayloadDTO.DevicePayloadDTOBuilder builder = DevicePayloadDTO.builder(); if (receiver == null) { return builder.build(); } return builder.payloadSn(receiver.getSn()) .payloadName(receiver.getPayloadIndex()) .build(); } }