sean.zhou
2022-12-12 2d8ded3e77b22e44985265ca4063102662e452c1
src/main/java/com/dji/sample/manage/service/impl/DeviceHmsServiceImpl.java
@@ -43,6 +43,8 @@
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;
/**
@@ -61,17 +63,66 @@
    private ObjectMapper objectMapper;
    @Autowired
    private RedisOpsUtils redisOps;
    @Autowired
    private SendMessageServiceImpl sendMessageService;
    @Autowired
    private WebSocketManageServiceImpl webSocketManageService;
    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();
        String key = RedisConst.HMS_PREFIX + sn;
        // Query all unread hms messages of the device in redis.
        Set<String> hmsMap = RedisOpsUtils.listGetAll(key).stream().map(String::valueOf).collect(Collectors.toSet());
        DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + 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;
        }
        RedisOpsUtils.listRPush(key, unReadList.stream().map(DeviceHmsDTO::getKey).toArray(String[]::new));
        // push to the web
        Collection<ConcurrentWebSocketSession> sessions = webSocketManageService.getValueWithWorkspaceAndUserType(
                device.getWorkspaceId(), UserTypeEnum.WEB.getVal());
        sendMessageService.sendBatch(sessions, CustomWebSocketMessage.builder()
                .bizCode(BizCodeEnum.DEVICE_HMS.getCode())
                .data(TelemetryDTO.<List<DeviceHmsDTO>>builder().sn(sn).host(unReadList).build())
                .timestamp(System.currentTimeMillis())
                .build());
    }
    @Override
@@ -107,7 +158,8 @@
                new LambdaUpdateWrapper<DeviceHmsEntity>()
                        .eq(DeviceHmsEntity::getSn, deviceSn)
                        .eq(DeviceHmsEntity::getUpdateTime, 0L));
        redisOps.del(RedisConst.HMS_PREFIX + deviceSn);
        // Delete unread messages cached in redis.
        RedisOpsUtils.del(RedisConst.HMS_PREFIX + deviceSn);
    }
    private DeviceHmsDTO entity2Dto(DeviceHmsEntity entity) {
@@ -130,4 +182,121 @@
                .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());
        if (HmsEnum.DomainType.DRONE_NEST.getDomain().equals(receiver.getDomainType())) {
            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;
    }
}