| | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.MapKeyConst; |
| | | import com.dji.sample.component.mqtt.model.TopicConst; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.service.impl.SendMessageServiceImpl; |
| | | import com.dji.sample.component.websocket.service.impl.WebSocketManageServiceImpl; |
| | | import com.dji.sample.manage.dao.IDeviceHmsMapper; |
| | |
| | | import com.dji.sample.manage.model.dto.DeviceHmsDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | import com.dji.sample.manage.model.entity.DeviceHmsEntity; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.enums.HmsEnum; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.model.param.DeviceHmsQueryParam; |
| | | import com.dji.sample.manage.model.receiver.DeviceHmsReceiver; |
| | | import com.dji.sample.manage.model.receiver.HmsArgsReceiver; |
| | | import com.dji.sample.manage.service.IDeviceHmsService; |
| | | import com.dji.sample.manage.service.IDeviceRedisService; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.util.*; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | @Slf4j |
| | | public class DeviceHmsServiceImpl implements IDeviceHmsService { |
| | | |
| | | @Autowired |
| | |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private SendMessageServiceImpl sendMessageService; |
| | | |
| | | @Autowired |
| | | private WebSocketManageServiceImpl webSocketManageService; |
| | | |
| | | @Autowired |
| | | private IDeviceRedisService deviceRedisService; |
| | | |
| | | private static final Pattern PATTERN_KEY = Pattern.compile( |
| | | HmsEnum.FormatKeyEnum.KEY_START + |
| | | "(" + |
| | | Arrays.stream(HmsEnum.FormatKeyEnum.values()) |
| | | .map(HmsEnum.FormatKeyEnum::getKey) |
| | | .collect(Collectors.joining("|")) + |
| | | ")"); |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_HMS) |
| | | public void handleHms(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString(); |
| | | String sn = topic.substring((TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT).length(), |
| | | topic.indexOf(TopicConst.EVENTS_SUF)); |
| | | |
| | | DeviceHmsEntity entity = DeviceHmsEntity.builder() |
| | | .bid(receiver.getBid()) |
| | | .tid(receiver.getTid()) |
| | | .createTime(receiver.getTimestamp()) |
| | | .updateTime(0L) |
| | | .sn(sn) |
| | | .build(); |
| | | // Query all unread hms messages of the device in redis. |
| | | Set<String> hmsMap = deviceRedisService.getAllHmsKeys(sn); |
| | | |
| | | List<DeviceHmsDTO> unReadList = new ArrayList<>(); |
| | | objectMapper.convertValue(((Map) (receiver.getData())).get(MapKeyConst.LIST), |
| | | new TypeReference<List<DeviceHmsReceiver>>() {}) |
| | | .forEach(hmsReceiver -> { |
| | | final DeviceHmsEntity hms = entity.clone(); |
| | | this.fillEntity(hms, hmsReceiver); |
| | | // The same unread hms are no longer incremented. |
| | | if (hmsMap.contains(hms.getHmsKey())) { |
| | | return; |
| | | } |
| | | this.fillMessage(hms, hmsReceiver.getArgs()); |
| | | unReadList.add(entity2Dto(hms)); |
| | | mapper.insert(hms); |
| | | }); |
| | | |
| | | if (unReadList.isEmpty()) { |
| | | return; |
| | | } |
| | | deviceRedisService.addEndHmsKeys(sn, unReadList.stream().map(DeviceHmsDTO::getKey).toArray(String[]::new)); |
| | | // push to the web |
| | | Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(sn); |
| | | if (deviceOpt.isEmpty()) { |
| | | return; |
| | | } |
| | | sendMessageService.sendBatch(deviceOpt.get().getWorkspaceId(), UserTypeEnum.WEB.getVal(), |
| | | BizCodeEnum.DEVICE_HMS.getCode(), TelemetryDTO.<List<DeviceHmsDTO>>builder().sn(sn).host(unReadList).build()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | new LambdaUpdateWrapper<DeviceHmsEntity>() |
| | | .eq(DeviceHmsEntity::getSn, deviceSn) |
| | | .eq(DeviceHmsEntity::getUpdateTime, 0L)); |
| | | redisOps.del(RedisConst.HMS_PREFIX + deviceSn); |
| | | // Delete unread messages cached in redis. |
| | | deviceRedisService.delHmsKeysBySn(deviceSn); |
| | | } |
| | | |
| | | private DeviceHmsDTO entity2Dto(DeviceHmsEntity entity) { |
| | |
| | | .build(); |
| | | } |
| | | |
| | | /** |
| | | * Populate the received data into the entity. Please refer to the documentation for splicing rules. |
| | | * @param dto |
| | | * @param receiver |
| | | */ |
| | | private void fillEntity(DeviceHmsEntity dto, DeviceHmsReceiver receiver) { |
| | | dto.setLevel(receiver.getLevel()); |
| | | dto.setModule(receiver.getModule()); |
| | | dto.setHmsId(UUID.randomUUID().toString()); |
| | | Optional<DeviceDomainEnum> domainEnumOpt = Optional.ofNullable(receiver.getDeviceType()) |
| | | .map(type -> type.split("-")).map(type -> type[0]).map(Integer::parseInt).map(DeviceDomainEnum::find); |
| | | if (domainEnumOpt.isEmpty()) { |
| | | throw new RuntimeException("设备类型不匹配,请检查数据"); |
| | | } |
| | | if (DeviceDomainEnum.DOCK == domainEnumOpt.get()) { |
| | | dto.setHmsKey(HmsEnum.HmsFaqIdEnum.DOCK_TIP.getText() + receiver.getCode()); |
| | | return; |
| | | } |
| | | StringBuilder key = new StringBuilder(HmsEnum.HmsFaqIdEnum.FPV_TIP.getText()).append(receiver.getCode()); |
| | | |
| | | if (receiver.getInTheSky() == HmsEnum.IN_THE_SKY.getVal()) { |
| | | key.append(HmsEnum.IN_THE_SKY.getText()); |
| | | } |
| | | dto.setHmsKey(key.toString()); |
| | | } |
| | | |
| | | /** |
| | | * Replace wildcards in messages according to the relevant rules. |
| | | * Please refer to the documentation for splicing rules. |
| | | * @param dto |
| | | * @param args |
| | | */ |
| | | private void fillMessage(DeviceHmsEntity dto, HmsArgsReceiver args) { |
| | | HmsMessage hmsMessage = HmsJsonUtil.get(dto.getHmsKey()); |
| | | String zh = StringUtils.hasText(hmsMessage.getZh()) ? hmsMessage.getZh() : String.format("未知错误(%s)", dto.getHmsKey()); |
| | | String en = StringUtils.hasText(hmsMessage.getEn()) ? hmsMessage.getEn() : String.format("Unknown(%s)", dto.getHmsKey());// |
| | | |
| | | dto.setMessageZh(format(Locale.CHINESE.getLanguage(), zh, args)); |
| | | dto.setMessageEn(format(Locale.ENGLISH.getLanguage(), en, args)); |
| | | } |
| | | |
| | | /** |
| | | * Set the matching parameters for key. |
| | | * @param l language: zh or en |
| | | * @param hmsArgs |
| | | * @return |
| | | */ |
| | | private List<String> fillKeyArgs(String l, HmsArgsReceiver hmsArgs) { |
| | | List<String> args = new ArrayList<>(); |
| | | args.add(Objects.nonNull(hmsArgs.getAlarmId()) ? Long.toHexString(hmsArgs.getAlarmId()) : null); |
| | | args.add(Objects.nonNull(hmsArgs.getComponentIndex()) ? String.valueOf(hmsArgs.getComponentIndex() + 1) : null); |
| | | if (Objects.nonNull(hmsArgs.getSensorIndex())) { |
| | | args.add(String.valueOf(hmsArgs.getSensorIndex() + 1)); |
| | | |
| | | HmsEnum.HmsBatteryIndexEnum hmsBatteryIndexEnum = HmsEnum.HmsBatteryIndexEnum.find(hmsArgs.getSensorIndex()); |
| | | HmsEnum.HmsDockCoverIndexEnum hmsDockCoverIndexEnum = HmsEnum.HmsDockCoverIndexEnum.find(hmsArgs.getSensorIndex()); |
| | | HmsEnum.HmsChargingRodIndexEnum hmsChargingRodIndexEnum = HmsEnum.HmsChargingRodIndexEnum.find(hmsArgs.getSensorIndex()); |
| | | |
| | | switch (l) { |
| | | case "zh": |
| | | args.add(hmsBatteryIndexEnum.getZh()); |
| | | args.add(hmsDockCoverIndexEnum.getZh()); |
| | | args.add(hmsChargingRodIndexEnum.getZh()); |
| | | break; |
| | | case "en": |
| | | args.add(hmsBatteryIndexEnum.getEn()); |
| | | args.add(hmsDockCoverIndexEnum.getEn()); |
| | | args.add(hmsChargingRodIndexEnum.getEn()); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | } |
| | | return args; |
| | | } |
| | | |
| | | /** |
| | | * Returns a formatted string using the specified locale, format string, and arguments. |
| | | * @param l language: zh or en |
| | | * @param format |
| | | * @param hmsArgs |
| | | * @return |
| | | */ |
| | | private String format(String l, String format, HmsArgsReceiver hmsArgs) { |
| | | List<String> args = fillKeyArgs(l, hmsArgs); |
| | | List<String> list = parse(format); |
| | | StringBuilder sb = new StringBuilder(); |
| | | for (String word : list) { |
| | | if (!StringUtils.hasText(word)) { |
| | | continue; |
| | | } |
| | | HmsEnum.FormatKeyEnum keyEnum = HmsEnum.FormatKeyEnum.find(word.substring(1)); |
| | | sb.append(HmsEnum.FormatKeyEnum.KEY_START != word.charAt(0) || HmsEnum.FormatKeyEnum.UNKNOWN == keyEnum ? |
| | | word : args.get(keyEnum.getIndex())); |
| | | } |
| | | return sb.toString(); |
| | | } |
| | | |
| | | /** |
| | | * Finds format specifiers in the format string. |
| | | * @param s |
| | | * @return |
| | | */ |
| | | private List<String> parse(String s) { |
| | | List<String> list = new ArrayList<>(); |
| | | Matcher matcher = PATTERN_KEY.matcher(s); |
| | | for (int i = 0; i < s.length(); ) { |
| | | if (matcher.find(i)) { |
| | | if (matcher.start() != i) { |
| | | list.add(s.substring(i, matcher.start())); |
| | | } |
| | | list.add(matcher.group()); |
| | | i = matcher.end(); |
| | | } else { |
| | | list.add(s.substring(i)); |
| | | break; |
| | | } |
| | | } |
| | | return list; |
| | | } |
| | | } |