From 5f75c0d498242c480fb483d22230dda198f9ba4c Mon Sep 17 00:00:00 2001 From: "sean.zhou" Date: Fri, 4 Nov 2022 21:31:14 +0800 Subject: [PATCH] initial v1.3.0-beta2 --- api/Cloud API Demo.postman_collection.json | 65 +++++++- pom.xml | 13 +- .../com/dji/sample/common/util/JwtUtil.java | 20 ++- .../mqtt/config/MqttMessageChannel.java | 5 + .../mqtt/handler/InboundMessageRouter.java | 86 ++-------- .../mqtt/handler/PropertySetReplyHandler.java | 40 +++++ .../component/mqtt/model/ChannelName.java | 2 + .../component/mqtt/model/DeviceTopicEnum.java | 46 ++++++ .../mqtt/model/EventsResultStatusEnum.java | 2 + .../sample/component/mqtt/model/SetReply.java | 14 ++ .../mqtt/model/SetReplyStatusResultEnum.java | 30 ++++ .../component/mqtt/model/TopicConst.java | 4 + .../mqtt/service/IMessageSenderService.java | 6 +- .../impl/MessageSenderServiceImpl.java | 13 +- .../component/oss/service/IOssService.java | 5 +- .../service/impl/AliyunOssServiceImpl.java | 23 ++- .../oss/service/impl/AmazonS3ServiceImpl.java | 27 +++- .../oss/service/impl/MinIOServiceImpl.java | 46 ++++-- .../oss/service/impl/OssServiceContext.java | 7 +- .../sample/component/redis/RedisConst.java | 2 + .../service/impl/ControlServiceImpl.java | 15 +- .../manage/controller/DeviceController.java | 57 +++---- .../model/enums/DeviceSetPropertyEnum.java | 41 +++++ .../model/enums/StateSwitchReceiver.java | 30 ++++ .../receiver/AlternateLandPointReceiver.java | 2 + .../model/receiver/BackupBatteryReceiver.java | 20 +++ .../model/receiver/BasicDeviceProperty.java | 20 +++ .../DeviceMaintainStatusReceiver.java | 16 ++ .../receiver/DistanceLimitStatusReceiver.java | 57 +++++++ .../receiver/DockWirelessLinkReceiver.java | 38 +++++ .../DroneBatteryMaintenanceInfoReceiver.java | 16 ++ .../model/receiver/HeightLimitReceiver.java | 29 ++++ .../receiver/MaintainStatusReceiver.java | 20 +++ .../model/receiver/NetworkStateReceiver.java | 2 +- .../receiver/ObstacleAvoidanceReceiver.java | 62 ++++++++ .../model/receiver/OsdDockReceiver.java | 49 ++++-- .../receiver/OsdDockTransmissionReceiver.java | 18 --- .../model/receiver/OsdSubDeviceReceiver.java | 9 ++ .../service/IDeviceDictionaryService.java | 4 +- .../sample/manage/service/IDeviceService.java | 33 +++- .../impl/CapacityCameraServiceImpl.java | 3 +- .../impl/DeviceDictionaryServiceImpl.java | 8 +- .../impl/DeviceFirmwareServiceImpl.java | 6 +- .../service/impl/DeviceLogsServiceImpl.java | 20 +-- .../service/impl/DeviceOSDServiceImpl.java | 3 +- .../impl/DevicePayloadServiceImpl.java | 3 +- .../service/impl/DeviceServiceImpl.java | 148 +++++++++++++----- .../service/impl/DockOSDServiceImpl.java | 9 +- .../service/impl/LiveStreamServiceImpl.java | 47 +++--- .../impl/LogsFileIndexServiceImpl.java | 2 +- .../manage/service/impl/UserServiceImpl.java | 19 ++- .../media/service/impl/FileServiceImpl.java | 3 +- .../media/service/impl/MediaServiceImpl.java | 13 ++ .../controller/WaylineFileController.java | 19 +++ .../wayline/model/dto/KmzFileProperties.java | 39 +++++ .../wayline/service/IWaylineFileService.java | 10 ++ .../service/impl/WaylineFileServiceImpl.java | 109 +++++++++++-- .../service/impl/WaylineJobServiceImpl.java | 48 +++--- 58 files changed, 1172 insertions(+), 331 deletions(-) create mode 100644 src/main/java/com/dji/sample/component/mqtt/handler/PropertySetReplyHandler.java create mode 100644 src/main/java/com/dji/sample/component/mqtt/model/DeviceTopicEnum.java create mode 100644 src/main/java/com/dji/sample/component/mqtt/model/SetReply.java create mode 100644 src/main/java/com/dji/sample/component/mqtt/model/SetReplyStatusResultEnum.java create mode 100644 src/main/java/com/dji/sample/manage/model/enums/DeviceSetPropertyEnum.java create mode 100644 src/main/java/com/dji/sample/manage/model/enums/StateSwitchReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/BackupBatteryReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/BasicDeviceProperty.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/DeviceMaintainStatusReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/DistanceLimitStatusReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/DockWirelessLinkReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/DroneBatteryMaintenanceInfoReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/HeightLimitReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/MaintainStatusReceiver.java create mode 100644 src/main/java/com/dji/sample/manage/model/receiver/ObstacleAvoidanceReceiver.java delete mode 100644 src/main/java/com/dji/sample/manage/model/receiver/OsdDockTransmissionReceiver.java create mode 100644 src/main/java/com/dji/sample/wayline/model/dto/KmzFileProperties.java diff --git a/api/Cloud API Demo.postman_collection.json b/api/Cloud API Demo.postman_collection.json index 9c96972..b9af814 100644 --- a/api/Cloud API Demo.postman_collection.json +++ b/api/Cloud API Demo.postman_collection.json @@ -703,6 +703,36 @@ } }, "response": [] + }, + { + "name": "Set Property", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"night_lights_state\": 0\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/{{device_sn}}/property", + "host": [ + "{{base_url}}{{manage_version}}" + ], + "path": [ + "devices", + "{{workspace_id}}", + "devices", + "{{device_sn}}", + "property" + ] + } + }, + "response": [] } ], "auth": { @@ -710,7 +740,7 @@ "apikey": [ { "key": "value", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NjM1NTkxMTAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NjM2NDU1MTAsImlhdCI6MTY2MzU1OTExMCwidXNlcm5hbWUiOiJhZG1pblBDIn0.LG1JXZkuTdMaqnXn5WMJvnysNkHHbc4HLe_qZPWz_nM", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njc0NzcwNTUsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njc1NjM0NTUsImlhdCI6MTY2NzQ3NzA1NSwidXNlcm5hbWUiOiJhZG1pblBDIn0.VMJ0ZKn895uvkMDjg2fw3p4trVCUx9ltVFKeP7QmYpo", "type": "string" }, { @@ -1322,6 +1352,37 @@ } }, "response": [] + }, + { + "name": "Import KMZ File", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "file", + "type": "file", + "src": [] + } + ] + }, + "url": { + "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/waylines/file/upload", + "host": [ + "{{base_url}}{{wayline_version}}" + ], + "path": [ + "workspaces", + "{{workspace_id}}", + "waylines", + "file", + "upload" + ] + } + }, + "response": [] } ], "auth": { @@ -1329,7 +1390,7 @@ "apikey": [ { "key": "value", - "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTU0NDk2MDIsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTU1MzYwMDIsImlhdCI6MTY1NTQ0OTYwMiwidXNlcm5hbWUiOiJhZG1pblBDIn0.YZWHJ65Pl_DT2Ampxk0WC01KD_fNTm_rYVUBIHAZD-4", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njc1MzMwNDMsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njc2MTk0NDMsImlhdCI6MTY2NzUzMzA0MywidXNlcm5hbWUiOiJhZG1pblBDIn0.es0boeLSuSD8ysMft7OP701zYuaAHlrmf68iNCvqvnw", "type": "string" }, { diff --git a/pom.xml b/pom.xml index e71dc5f..ee1fe8c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.dji cloud-api-sample - 1.1.0 + 1.3.0-beta2 cloud-api-sample @@ -156,6 +156,17 @@ org.springframework.boot spring-boot-starter-aop + + + org.dom4j + dom4j + 2.1.3 + + + + jaxen + jaxen + diff --git a/src/main/java/com/dji/sample/common/util/JwtUtil.java b/src/main/java/com/dji/sample/common/util/JwtUtil.java index 629cea1..918f1d7 100644 --- a/src/main/java/com/dji/sample/common/util/JwtUtil.java +++ b/src/main/java/com/dji/sample/common/util/JwtUtil.java @@ -2,7 +2,6 @@ package com.dji.sample.common.util; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; -import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; @@ -85,14 +84,7 @@ public class JwtUtil { * @throws TokenExpiredException */ public static DecodedJWT verifyToken(String token) { - try { - JWTVerifier verifier = JWT.require(algorithm).build(); - return verifier.verify(token); - } catch (Exception e) { - log.error(e.getMessage()); - e.printStackTrace(); - return null; - } + return JWT.require(algorithm).build().verify(token); } /** @@ -101,7 +93,13 @@ public class JwtUtil { * @return custom claim */ public static Optional parseToken(String token) { - DecodedJWT jwt = verifyToken(token); - return jwt == null ? Optional.empty() : Optional.of(new CustomClaim(jwt.getClaims())); + DecodedJWT jwt; + try { + jwt = verifyToken(token); + } catch (Exception e) { + e.printStackTrace(); + return Optional.empty(); + } + return Optional.of(new CustomClaim(jwt.getClaims())); } } diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java index cbf27e0..2edba07 100644 --- a/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java +++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java @@ -157,4 +157,9 @@ public class MqttMessageChannel { return new DirectChannel(); } + @Bean(name = ChannelName.INBOUND_PROPERTY_SET_REPLY) + public MessageChannel propertySetReply() { + return new DirectChannel(); + } + } diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java b/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java index 3047ea5..92458fc 100644 --- a/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java +++ b/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java @@ -1,7 +1,10 @@ package com.dji.sample.component.mqtt.handler; import com.dji.sample.component.mqtt.model.ChannelName; +import com.dji.sample.component.mqtt.model.DeviceTopicEnum; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.integration.annotation.Router; import org.springframework.integration.mqtt.support.MqttHeaders; import org.springframework.integration.router.AbstractMessageRouter; @@ -10,12 +13,9 @@ import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHeaders; import org.springframework.stereotype.Component; -import javax.annotation.Resource; import java.util.Collection; import java.util.Collections; -import java.util.regex.Pattern; - -import static com.dji.sample.component.mqtt.model.TopicConst.*; +import java.util.concurrent.ConcurrentHashMap; /** * @@ -27,47 +27,10 @@ import static com.dji.sample.component.mqtt.model.TopicConst.*; @Slf4j public class InboundMessageRouter extends AbstractMessageRouter { - @Resource(name = ChannelName.INBOUND) - private MessageChannel inboundChannel; - - @Resource(name = ChannelName.INBOUND_STATUS) - private MessageChannel statusChannel; - - @Resource(name = ChannelName.INBOUND_STATE) - private MessageChannel stateChannel; - - @Resource(name = ChannelName.DEFAULT) - private MessageChannel defaultChannel; - - @Resource(name = ChannelName.INBOUND_SERVICE_REPLY) - private MessageChannel serviceReplyChannel; - - @Resource(name = ChannelName.INBOUND_OSD) - private MessageChannel osdChannel; - - @Resource(name = ChannelName.INBOUND_REQUESTS) - private MessageChannel requestsChannel; - - @Resource(name = ChannelName.INBOUND_EVENTS) - private MessageChannel eventsChannel; - - private static final Pattern PATTERN_TOPIC_STATUS = - Pattern.compile("^" + BASIC_PRE + PRODUCT + REGEX_SN + STATUS_SUF + "$"); - - private static final Pattern PATTERN_TOPIC_STATE = - Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + STATE_SUF + "$"); - - private static final Pattern PATTERN_TOPIC_SERVICE_REPLY = - Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + SERVICES_SUF + _REPLY_SUF + "$"); - - private static final Pattern PATTERN_TOPIC_OSD = - Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + OSD_SUF + "$"); + @Autowired + private ApplicationContext applicationContext; - private static final Pattern PATTERN_TOPIC_REQUESTS = - Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + REQUESTS_SUF + "$"); - - private static final Pattern PATTERN_TOPIC_EVENTS = - Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + EVENTS_SUF + "$"); + private static final ConcurrentHashMap channels = new ConcurrentHashMap<>(16); /** * All mqtt broker messages will arrive here before distributing them to different channels. @@ -81,38 +44,15 @@ public class InboundMessageRouter extends AbstractMessageRouter { String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString(); byte[] payload = (byte[])message.getPayload(); - // osd - if (PATTERN_TOPIC_OSD.matcher(topic).matches()) { - return Collections.singleton(osdChannel); - } - log.debug("received topic :{} \t payload :{}", topic, new String(payload)); - // status - if (PATTERN_TOPIC_STATUS.matcher(topic).matches()) { - return Collections.singleton(statusChannel); - } - - // state - if (PATTERN_TOPIC_STATE.matcher(topic).matches()) { - return Collections.singleton(stateChannel); - } - - // services_reply - if (PATTERN_TOPIC_SERVICE_REPLY.matcher(topic).matches()) { - return Collections.singleton(serviceReplyChannel); - } - - // requests - if (PATTERN_TOPIC_REQUESTS.matcher(topic).matches()) { - return Collections.singleton(requestsChannel); - } - - // events - if (PATTERN_TOPIC_EVENTS.matcher(topic).matches()) { - return Collections.singleton(eventsChannel); + DeviceTopicEnum topicEnum = DeviceTopicEnum.find(topic); + if (channels.containsKey(topicEnum.getBeanName())) { + return Collections.singleton(channels.get(topicEnum.getBeanName())); } - return Collections.singleton(defaultChannel); + MessageChannel bean = (MessageChannel) applicationContext.getBean(topicEnum.getBeanName()); + channels.put(topicEnum.getBeanName(), bean); + return Collections.singleton(bean); } } diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/PropertySetReplyHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/PropertySetReplyHandler.java new file mode 100644 index 0000000..9b503eb --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/handler/PropertySetReplyHandler.java @@ -0,0 +1,40 @@ +package com.dji.sample.component.mqtt.handler; + +import com.dji.sample.component.mqtt.model.Chan; +import com.dji.sample.component.mqtt.model.ChannelName; +import com.dji.sample.component.mqtt.model.CommonTopicReceiver; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +/** + * @author sean + * @version 1.2 + * @date 2022/9/9 + */ +@Component +public class PropertySetReplyHandler { + + @Autowired + private ObjectMapper mapper; + + /** + * Handle the reply message from the pilot side to the on-demand video. + * @param message reply message + * @throws IOException + */ + @ServiceActivator(inputChannel = ChannelName.INBOUND_PROPERTY_SET_REPLY) + public void serviceReply(Message message) throws IOException { + byte[] payload = (byte[])message.getPayload(); + + CommonTopicReceiver receiver = mapper.readValue(payload, new TypeReference() {}); + Chan> chan = Chan.getInstance(); + // Put the message to the chan object. + chan.put(receiver); + } +} diff --git a/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java b/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java index 670ff33..1194493 100644 --- a/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java +++ b/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java @@ -70,4 +70,6 @@ public class ChannelName { public static final String INBOUND_EVENTS_FILE_UPLOAD_PROGRESS = "inboundEventsFileUploadProgress"; public static final String INBOUND_REQUESTS_FLIGHT_TASK_RESOURCE_GET = "inboundEventsFlightTaskResourceGet"; + + public static final String INBOUND_PROPERTY_SET_REPLY = "inboundPropertySetReply"; } diff --git a/src/main/java/com/dji/sample/component/mqtt/model/DeviceTopicEnum.java b/src/main/java/com/dji/sample/component/mqtt/model/DeviceTopicEnum.java new file mode 100644 index 0000000..00ab2a7 --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/model/DeviceTopicEnum.java @@ -0,0 +1,46 @@ +package com.dji.sample.component.mqtt.model; + +import lombok.Getter; + +import java.util.Arrays; +import java.util.regex.Pattern; + +import static com.dji.sample.component.mqtt.model.TopicConst.*; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/28 + */ +@Getter +public enum DeviceTopicEnum { + + STATUS(Pattern.compile("^" + BASIC_PRE + PRODUCT + REGEX_SN + STATUS_SUF + "$"), ChannelName.INBOUND_STATUS), + + STATE(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + STATE_SUF + "$"), ChannelName.INBOUND_STATE), + + SERVICE_REPLY(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + SERVICES_SUF + _REPLY_SUF + "$"), ChannelName.INBOUND_SERVICE_REPLY), + + OSD(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + OSD_SUF + "$"), ChannelName.INBOUND_OSD), + + REQUESTS(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + REQUESTS_SUF + "$"), ChannelName.INBOUND_REQUESTS), + + EVENTS(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + EVENTS_SUF + "$"), ChannelName.INBOUND_EVENTS), + + PROPERTY_SET_REPLY(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + PROPERTY_SUF + SET_SUF + _REPLY_SUF + "$"), ChannelName.INBOUND_PROPERTY_SET_REPLY), + + UNKNOWN(null, ChannelName.DEFAULT); + + Pattern pattern; + + String beanName; + + DeviceTopicEnum(Pattern pattern, String beanName) { + this.pattern = pattern; + this.beanName = beanName; + } + + public static DeviceTopicEnum find(String topic) { + return Arrays.stream(DeviceTopicEnum.values()).filter(topicEnum -> topicEnum.pattern.matcher(topic).matches()).findAny().orElse(UNKNOWN); + } +} diff --git a/src/main/java/com/dji/sample/component/mqtt/model/EventsResultStatusEnum.java b/src/main/java/com/dji/sample/component/mqtt/model/EventsResultStatusEnum.java index 321e2f8..dd37ac6 100644 --- a/src/main/java/com/dji/sample/component/mqtt/model/EventsResultStatusEnum.java +++ b/src/main/java/com/dji/sample/component/mqtt/model/EventsResultStatusEnum.java @@ -28,6 +28,8 @@ public enum EventsResultStatusEnum { TIMEOUT("timeout", true), + PARTIALLY_DONE("partially_done", true), + UNKNOWN("unknown", false); String desc; diff --git a/src/main/java/com/dji/sample/component/mqtt/model/SetReply.java b/src/main/java/com/dji/sample/component/mqtt/model/SetReply.java new file mode 100644 index 0000000..2c7f453 --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/model/SetReply.java @@ -0,0 +1,14 @@ +package com.dji.sample.component.mqtt.model; + +import lombok.Data; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/28 + */ +@Data +public class SetReply { + + private Integer result; +} diff --git a/src/main/java/com/dji/sample/component/mqtt/model/SetReplyStatusResultEnum.java b/src/main/java/com/dji/sample/component/mqtt/model/SetReplyStatusResultEnum.java new file mode 100644 index 0000000..5a127e4 --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/model/SetReplyStatusResultEnum.java @@ -0,0 +1,30 @@ +package com.dji.sample.component.mqtt.model; + +import lombok.Getter; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/28 + */ +@Getter +public enum SetReplyStatusResultEnum { + + SUCCESS(0, "success"), + + FAILED(1, "failed"), + + TIMEOUT(2, "timeout"), + + UNKNOWN(-1, "unknown"); + + int val; + + String desc; + + SetReplyStatusResultEnum(int val, String desc) { + this.val = val; + this.desc = desc; + } + +} diff --git a/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java b/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java index dc9df7c..215995a 100644 --- a/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java +++ b/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java @@ -28,6 +28,10 @@ public class TopicConst { public static final String EVENTS_SUF = "/events"; + public static final String PROPERTY_SUF = "/property"; + + public static final String SET_SUF = "/set"; + public static final String REGEX_SN = "[A-Za-z0-9]+"; } \ No newline at end of file diff --git a/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java b/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java index 15079a6..40f7f18 100644 --- a/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java +++ b/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java @@ -3,8 +3,6 @@ package com.dji.sample.component.mqtt.service; import com.dji.sample.component.mqtt.model.CommonTopicResponse; import com.dji.sample.component.mqtt.model.ServiceReply; -import java.util.Optional; - /** * @author sean.zhou * @version 0.1 @@ -33,7 +31,7 @@ public interface IMessageSenderService { * @param response notification of whether the start is successful. * @return */ - Optional publishWithReply(String topic, CommonTopicResponse response); + ServiceReply publishWithReply(String topic, CommonTopicResponse response); /** * Send live streaming start message and receive a response at the same time. @@ -44,5 +42,5 @@ public interface IMessageSenderService { * @param * @return */ - Optional publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime); + T publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime); } diff --git a/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java b/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java index 10bb7e2..89e5093 100644 --- a/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java +++ b/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java @@ -12,7 +12,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; /** @@ -49,28 +48,28 @@ public class MessageSenderServiceImpl implements IMessageSenderService { } } - public Optional publishWithReply(String topic, CommonTopicResponse response) { + public ServiceReply publishWithReply(String topic, CommonTopicResponse response) { return this.publishWithReply(ServiceReply.class, topic, response, 2); } - public Optional publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime) { + public T publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime) { AtomicInteger time = new AtomicInteger(0); // Retry three times - while (time.getAndIncrement() < retryTime) { + while (time.getAndIncrement() <= retryTime) { this.publish(topic, response); Chan> chan = Chan.getInstance(); // If the message is not received in 0.5 seconds then resend it again. - CommonTopicReceiver receiver = chan.get(response.getMethod()); + CommonTopicReceiver receiver = chan.get(response.getTid()); if (receiver == null) { continue; } // Need to match tid and bid. if (receiver.getTid().equals(response.getTid()) && receiver.getBid().equals(response.getBid())) { - return Optional.ofNullable(receiver.getData()); + return receiver.getData(); } } - return Optional.empty(); + throw new RuntimeException("No message reply received."); } } \ No newline at end of file diff --git a/src/main/java/com/dji/sample/component/oss/service/IOssService.java b/src/main/java/com/dji/sample/component/oss/service/IOssService.java index 53746ef..f8441dd 100644 --- a/src/main/java/com/dji/sample/component/oss/service/IOssService.java +++ b/src/main/java/com/dji/sample/component/oss/service/IOssService.java @@ -2,6 +2,7 @@ package com.dji.sample.component.oss.service; import com.dji.sample.media.model.CredentialsDTO; +import java.io.InputStream; import java.net.URL; /** @@ -41,5 +42,7 @@ public interface IOssService { * @param objectKey * @return */ - byte[] getObject(String bucket, String objectKey); + InputStream getObject(String bucket, String objectKey); + + void putObject(String bucket, String objectKey, InputStream input); } diff --git a/src/main/java/com/dji/sample/component/oss/service/impl/AliyunOssServiceImpl.java b/src/main/java/com/dji/sample/component/oss/service/impl/AliyunOssServiceImpl.java index d709b07..d855261 100644 --- a/src/main/java/com/dji/sample/component/oss/service/impl/AliyunOssServiceImpl.java +++ b/src/main/java/com/dji/sample/component/oss/service/impl/AliyunOssServiceImpl.java @@ -4,6 +4,9 @@ import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSException; import com.aliyun.oss.model.OSSObject; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PutObjectRequest; +import com.aliyun.oss.model.PutObjectResult; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.exceptions.ClientException; @@ -93,18 +96,30 @@ public class AliyunOssServiceImpl implements IOssService { } @Override - public byte[] getObject(String bucket, String objectKey) { + public InputStream getObject(String bucket, String objectKey) { OSS ossClient = this.createClient(); OSSObject object = ossClient.getObject(bucket, objectKey); - try (InputStream stream = object.getObjectContent()) { - return stream.readAllBytes(); + try (InputStream input = object.getObjectContent()) { + return input; } catch (IOException e) { e.printStackTrace(); } finally { ossClient.shutdown(); } - return new byte[0]; + return InputStream.nullInputStream(); + } + + @Override + public void putObject(String bucket, String objectKey, InputStream input) { + OSS ossClient = this.createClient(); + if (ossClient.doesObjectExist(bucket, objectKey)) { + ossClient.shutdown(); + throw new RuntimeException("The filename already exists."); + } + PutObjectResult objectResult = ossClient.putObject(new PutObjectRequest(bucket, objectKey, input, new ObjectMetadata())); + ossClient.shutdown(); + log.info("Upload File: {}", objectResult.getETag()); } private OSS createClient() { diff --git a/src/main/java/com/dji/sample/component/oss/service/impl/AmazonS3ServiceImpl.java b/src/main/java/com/dji/sample/component/oss/service/impl/AmazonS3ServiceImpl.java index f2bcdc5..b9cdfd3 100644 --- a/src/main/java/com/dji/sample/component/oss/service/impl/AmazonS3ServiceImpl.java +++ b/src/main/java/com/dji/sample/component/oss/service/impl/AmazonS3ServiceImpl.java @@ -5,9 +5,7 @@ import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration; -import com.amazonaws.services.s3.model.CORSRule; -import com.amazonaws.services.s3.model.S3Object; +import com.amazonaws.services.s3.model.*; import com.amazonaws.services.securitytoken.AWSSecurityTokenService; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; @@ -18,6 +16,7 @@ import com.dji.sample.component.oss.model.OssConfiguration; import com.dji.sample.component.oss.model.enums.OssTypeEnum; import com.dji.sample.component.oss.service.IOssService; import com.dji.sample.media.model.CredentialsDTO; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -34,6 +33,7 @@ import java.util.List; * @version 1.0 * @date 2022/4/27 */ +@Slf4j @Service public class AmazonS3ServiceImpl implements IOssService { @@ -83,18 +83,29 @@ public class AmazonS3ServiceImpl implements IOssService { return true; } - public byte[] getObject(String bucket, String objectKey) { + public InputStream getObject(String bucket, String objectKey) { AmazonS3 client = this.createClient(); S3Object object = client.getObject(bucket, objectKey); - - try (InputStream stream = object.getObjectContent().getDelegateStream()) { - return stream.readAllBytes(); + try (InputStream input = object.getObjectContent().getDelegateStream()) { + return input; } catch (IOException e) { e.printStackTrace(); } finally { client.shutdown(); } - return new byte[0]; + return InputStream.nullInputStream(); + } + + @Override + public void putObject(String bucket, String objectKey, InputStream input) { + AmazonS3 client = this.createClient(); + if (client.doesObjectExist(bucket, objectKey)) { + client.shutdown(); + throw new RuntimeException("The filename already exists."); + } + PutObjectResult objectResult = client.putObject(new PutObjectRequest(bucket, objectKey, input, new ObjectMetadata())); + client.shutdown(); + log.info("Upload File: {}", objectResult.toString()); } private AmazonS3 createClient() { diff --git a/src/main/java/com/dji/sample/component/oss/service/impl/MinIOServiceImpl.java b/src/main/java/com/dji/sample/component/oss/service/impl/MinIOServiceImpl.java index 009a1fb..b162751 100644 --- a/src/main/java/com/dji/sample/component/oss/service/impl/MinIOServiceImpl.java +++ b/src/main/java/com/dji/sample/component/oss/service/impl/MinIOServiceImpl.java @@ -4,10 +4,7 @@ import com.dji.sample.component.oss.model.OssConfiguration; import com.dji.sample.component.oss.model.enums.OssTypeEnum; import com.dji.sample.component.oss.service.IOssService; import com.dji.sample.media.model.CredentialsDTO; -import io.minio.GetObjectArgs; -import io.minio.GetPresignedObjectUrlArgs; -import io.minio.MinioClient; -import io.minio.RemoveObjectArgs; +import io.minio.*; import io.minio.credentials.AssumeRoleProvider; import io.minio.errors.*; import io.minio.http.Method; @@ -15,11 +12,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.Objects; /** * @author sean @@ -30,6 +29,8 @@ import java.security.NoSuchAlgorithmException; @Slf4j public class MinIOServiceImpl implements IOssService { + private MinioClient client; + @Autowired private OssConfiguration configuration; @@ -87,21 +88,44 @@ public class MinIOServiceImpl implements IOssService { } @Override - public byte[] getObject(String bucket, String objectKey) { - MinioClient client = this.createClient(); - try (InputStream objectResponse = client.getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build())) { - return objectResponse.readAllBytes(); - } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) { + public InputStream getObject(String bucket, String objectKey) { + try { + GetObjectResponse object = this.createClient().getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build()); + return new ByteArrayInputStream(object.readAllBytes()); + } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) { e.printStackTrace(); } - return new byte[0]; + return InputStream.nullInputStream(); + } + + @Override + public void putObject(String bucket, String objectKey, InputStream input) { + try { + MinioClient client = this.createClient(); + client.statObject(StatObjectArgs.builder().bucket(bucket).object(objectKey).build()); + throw new RuntimeException("The filename already exists."); + } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) { + log.info("The file does not exist, start uploading."); + try { + ObjectWriteResponse response = client.putObject( + PutObjectArgs.builder().bucket(bucket).object(objectKey).stream(input, input.available(), 0).build()); + log.info("Upload File: {}", response.etag()); + } catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException ex) { + log.error("Failed to upload File {}.", objectKey); + ex.printStackTrace(); + } + } } private MinioClient createClient() { - return MinioClient.builder() + if (Objects.nonNull(this.client)) { + return this.client; + } + this.client = MinioClient.builder() .endpoint(configuration.getEndpoint()) .credentials(configuration.getAccessKey(), configuration.getSecretKey()) .region(configuration.getRegion()) .build(); + return this.client; } } diff --git a/src/main/java/com/dji/sample/component/oss/service/impl/OssServiceContext.java b/src/main/java/com/dji/sample/component/oss/service/impl/OssServiceContext.java index 9ac8059..e131889 100644 --- a/src/main/java/com/dji/sample/component/oss/service/impl/OssServiceContext.java +++ b/src/main/java/com/dji/sample/component/oss/service/impl/OssServiceContext.java @@ -7,6 +7,7 @@ import com.dji.sample.media.model.CredentialsDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.InputStream; import java.net.URL; import java.util.Arrays; import java.util.List; @@ -52,7 +53,11 @@ public class OssServiceContext { return this.ossService.deleteObject(bucket, objectKey); } - public byte[] getObject(String bucket, String objectKey) { + public InputStream getObject(String bucket, String objectKey) { return this.ossService.getObject(bucket, objectKey); } + + public void putObject(String bucket, String objectKey, InputStream stream) { + this.ossService.putObject(bucket, objectKey, stream); + } } diff --git a/src/main/java/com/dji/sample/component/redis/RedisConst.java b/src/main/java/com/dji/sample/component/redis/RedisConst.java index dfbe44f..1fce89d 100644 --- a/src/main/java/com/dji/sample/component/redis/RedisConst.java +++ b/src/main/java/com/dji/sample/component/redis/RedisConst.java @@ -36,4 +36,6 @@ public final class RedisConst { public static final String LOGS_FILE_PREFIX = "logs_file" + DELIMITER; public static final String WAYLINE_JOB = "wayline_job"; + + public static final String OSD_PREFIX = "osd" + DELIMITER; } diff --git a/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java b/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java index 182620c..c5d0201 100644 --- a/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java +++ b/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java @@ -11,6 +11,7 @@ import com.dji.sample.component.websocket.service.IWebSocketManageService; import com.dji.sample.control.service.IControlService; import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.enums.UserTypeEnum; +import com.dji.sample.manage.service.IDeviceService; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; @@ -20,7 +21,6 @@ import org.springframework.integration.mqtt.support.MqttHeaders; import org.springframework.messaging.MessageHeaders; import org.springframework.stereotype.Service; -import java.util.Optional; import java.util.UUID; /** @@ -44,6 +44,9 @@ public class ControlServiceImpl implements IControlService { @Autowired private IWebSocketManageService webSocketManageService; + @Autowired + private IDeviceService deviceService; + @Autowired private ObjectMapper mapper; @@ -53,13 +56,13 @@ public class ControlServiceImpl implements IControlService { if (servicesMethodEnum == ServicesMethodEnum.UNKNOWN) { return ResponseResult.error("The " + serviceIdentifier + " method does not exist."); } - boolean isExist = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + sn) > 0; + boolean isExist = deviceService.checkDeviceOnline(sn); if (!isExist) { return ResponseResult.error("The dock is offline."); } String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + sn + TopicConst.SERVICES_SUF; String bid = UUID.randomUUID().toString(); - Optional serviceReplyOpt = messageSenderService.publishWithReply( + ServiceReply serviceReplyOpt = messageSenderService.publishWithReply( topic, CommonTopicResponse.builder() .tid(UUID.randomUUID().toString()) .bid(bid) @@ -67,11 +70,9 @@ public class ControlServiceImpl implements IControlService { .timestamp(System.currentTimeMillis()) .data("") .build()); - if (serviceReplyOpt.isEmpty()) { - return ResponseResult.error("No message reply received."); - } + ServiceReply serviceReply = mapper.convertValue( - serviceReplyOpt.get(), new TypeReference>() {}); + serviceReplyOpt, new TypeReference>() {}); if (serviceReply.getResult() != ResponseResult.CODE_SUCCESS) { return ResponseResult.error(serviceReply.getResult(), serviceReply.getOutput().getStatus()); } diff --git a/src/main/java/com/dji/sample/manage/controller/DeviceController.java b/src/main/java/com/dji/sample/manage/controller/DeviceController.java index e9d80c0..192f45b 100644 --- a/src/main/java/com/dji/sample/manage/controller/DeviceController.java +++ b/src/main/java/com/dji/sample/manage/controller/DeviceController.java @@ -1,21 +1,20 @@ package com.dji.sample.manage.controller; +import com.dji.sample.common.error.CommonErrorEnum; import com.dji.sample.common.model.PaginationData; import com.dji.sample.common.model.ResponseResult; import com.dji.sample.component.mqtt.model.ChannelName; import com.dji.sample.component.mqtt.model.CommonTopicReceiver; import com.dji.sample.component.mqtt.model.CommonTopicResponse; -import com.dji.sample.component.websocket.service.ISendMessageService; import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO; -import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; +import com.dji.sample.manage.model.enums.DeviceSetPropertyEnum; import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; import com.dji.sample.manage.service.IDeviceService; +import com.fasterxml.jackson.databind.JsonNode; 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 org.springframework.messaging.Message; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -34,9 +33,6 @@ public class DeviceController { @Autowired private IDeviceService deviceService; - @Autowired - private ISendMessageService sendMessageService; - /** * Handles the message that the drone goes online. * @param receiver The drone information is not empty. @@ -50,6 +46,8 @@ public class DeviceController { CommonTopicResponse.builder() .tid(receiver.getTid()) .bid(receiver.getBid()) + .timestamp(System.currentTimeMillis()) + .method(receiver.getMethod()) .build()); } } @@ -68,6 +66,8 @@ public class DeviceController { CommonTopicResponse.builder() .tid(receiver.getTid()) .bid(receiver.getBid()) + .timestamp(System.currentTimeMillis()) + .method(receiver.getMethod()) .build()); } @@ -85,26 +85,6 @@ public class DeviceController { return ResponseResult.success(devicesList); } - /** - * Handle osd topic messages. - * @param message - */ - @ServiceActivator(inputChannel = ChannelName.INBOUND_OSD) - public void osdRealTime(Message message) { - String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); - byte[] payload = (byte[])message.getPayload(); - deviceService.handleOSD(topic, payload); - } - - /** - * Receive the reported firmware version data. - * @param receiver - */ - @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_FIRMWARE_VERSION) - public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { - deviceService.updateFirmwareVersion(receiver); - } - /** * After binding the device to the workspace, the device data can only be seen on the web. * @param device @@ -186,4 +166,27 @@ public class DeviceController { @RequestBody List upgradeDTOS) { return deviceService.createDeviceOtaJob(workspaceId, upgradeDTOS); } + + /** + * Set the property parameters of the drone. + * @param workspaceId + * @param dockSn + * @param param + * @return + */ + @PutMapping("/{workspace_id}/devices/{device_sn}/property") + public ResponseResult devicePropertySet(@PathVariable("workspace_id") String workspaceId, + @PathVariable("device_sn") String dockSn, + @RequestBody JsonNode param) { + if (param.size() != 1) { + return ResponseResult.error(CommonErrorEnum.ILLEGAL_ARGUMENT); + } + String property = param.fieldNames().next(); + Optional propertyEnumOpt = DeviceSetPropertyEnum.find(property); + if (propertyEnumOpt.isEmpty()) { + return ResponseResult.error(CommonErrorEnum.ILLEGAL_ARGUMENT); + } + deviceService.devicePropertySet(workspaceId, dockSn, propertyEnumOpt.get(), param.get(property)); + return ResponseResult.success(); + } } \ No newline at end of file diff --git a/src/main/java/com/dji/sample/manage/model/enums/DeviceSetPropertyEnum.java b/src/main/java/com/dji/sample/manage/model/enums/DeviceSetPropertyEnum.java new file mode 100644 index 0000000..38f9428 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/enums/DeviceSetPropertyEnum.java @@ -0,0 +1,41 @@ +package com.dji.sample.manage.model.enums; + +import com.dji.sample.manage.model.receiver.BasicDeviceProperty; +import com.dji.sample.manage.model.receiver.DistanceLimitStatusReceiver; +import com.dji.sample.manage.model.receiver.HeightLimitReceiver; +import com.dji.sample.manage.model.receiver.ObstacleAvoidanceReceiver; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Optional; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/27 + */ +@Getter +public enum DeviceSetPropertyEnum { + + NIGHT_LIGHTS_STATE("night_lights_state", StateSwitchReceiver.class), + + HEIGHT_LIMIT("height_limit", HeightLimitReceiver.class), + + DISTANCE_LIMIT_STATUS("distance_limit_status", DistanceLimitStatusReceiver.class), + + OBSTACLE_AVOIDANCE("obstacle_avoidance", ObstacleAvoidanceReceiver.class); + + + String property; + + Class clazz; + + DeviceSetPropertyEnum(String property, Class clazz) { + this.property = property; + this.clazz = clazz; + } + + public static Optional find(String property) { + return Arrays.stream(DeviceSetPropertyEnum.values()).filter(propertyEnum -> propertyEnum.property.equals(property)).findAny(); + } +} diff --git a/src/main/java/com/dji/sample/manage/model/enums/StateSwitchReceiver.java b/src/main/java/com/dji/sample/manage/model/enums/StateSwitchReceiver.java new file mode 100644 index 0000000..27fb2a9 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/enums/StateSwitchReceiver.java @@ -0,0 +1,30 @@ +package com.dji.sample.manage.model.enums; + +import com.dji.sample.manage.model.receiver.BasicDeviceProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Objects; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class StateSwitchReceiver extends BasicDeviceProperty { + + public static final int DISABLE = 0; + + public static final int ENABLE = 1; + + private Integer value; + + @Override + public boolean valid() { + return Objects.nonNull(this.value) && (this.value == DISABLE || this.value == ENABLE); + } +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/AlternateLandPointReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/AlternateLandPointReceiver.java index bd69415..fa6924e 100644 --- a/src/main/java/com/dji/sample/manage/model/receiver/AlternateLandPointReceiver.java +++ b/src/main/java/com/dji/sample/manage/model/receiver/AlternateLandPointReceiver.java @@ -15,4 +15,6 @@ public class AlternateLandPointReceiver { private Double longitude; private Double safeLandHeight; + + private Integer isConfigured; } diff --git a/src/main/java/com/dji/sample/manage/model/receiver/BackupBatteryReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/BackupBatteryReceiver.java new file mode 100644 index 0000000..257316d --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/BackupBatteryReceiver.java @@ -0,0 +1,20 @@ +package com.dji.sample.manage.model.receiver; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * @author sean + * @version 1.3 + * @date 2022/11/3 + */ +@Data +public class BackupBatteryReceiver { + + private Integer voltage; + + private Float temperature; + + @JsonProperty("switch") + private Integer batterySwitch; +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/BasicDeviceProperty.java b/src/main/java/com/dji/sample/manage/model/receiver/BasicDeviceProperty.java new file mode 100644 index 0000000..e698a2f --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/BasicDeviceProperty.java @@ -0,0 +1,20 @@ +package com.dji.sample.manage.model.receiver; + +import lombok.Data; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/27 + */ +@Data +public class BasicDeviceProperty { + + public boolean valid() { + return false; + } + + public boolean canPublish(String fieldName, OsdSubDeviceReceiver osd) { + return true; + } +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/DeviceMaintainStatusReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/DeviceMaintainStatusReceiver.java new file mode 100644 index 0000000..05e3ed4 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/DeviceMaintainStatusReceiver.java @@ -0,0 +1,16 @@ +package com.dji.sample.manage.model.receiver; + +import lombok.Data; + +import java.util.List; + +/** + * @author sean + * @version 1.3 + * @date 2022/11/3 + */ +@Data +public class DeviceMaintainStatusReceiver { + + private List maintainStatusArray; +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/DistanceLimitStatusReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/DistanceLimitStatusReceiver.java new file mode 100644 index 0000000..72129c7 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/DistanceLimitStatusReceiver.java @@ -0,0 +1,57 @@ +package com.dji.sample.manage.model.receiver; + +import com.dji.sample.manage.model.enums.StateSwitchReceiver; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Objects; + +/** + * The state of the drone's limited distance + * @author sean + * @version 1.3 + * @date 2022/10/27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DistanceLimitStatusReceiver extends BasicDeviceProperty { + + private Integer state; + + private Integer distanceLimit; + + private static final int DISTANCE_MAX = 8000; + + private static final int DISTANCE_MIN = 15; + + @Override + public boolean valid() { + boolean valid = Objects.nonNull(state) || Objects.nonNull(distanceLimit); + if (Objects.nonNull(state)) { + valid = new StateSwitchReceiver(this.state).valid(); + } + if (Objects.nonNull(distanceLimit)) { + valid &= distanceLimit >= DISTANCE_MIN && distanceLimit <= DISTANCE_MAX; + } + return valid; + } + + @Override + public boolean canPublish(String fieldName, OsdSubDeviceReceiver osd) { + DistanceLimitStatusReceiver distanceLimitStatus = osd.getDistanceLimitStatus(); + switch (fieldName) { + case "state": + return Objects.isNull(distanceLimitStatus.getState()) || + Objects.nonNull(distanceLimitStatus.getState()) && + distanceLimitStatus.getState().intValue() != this.state; + case "distance_limit": + return Objects.isNull(distanceLimitStatus.getDistanceLimit()) || + Objects.nonNull(distanceLimitStatus.getDistanceLimit()) && + distanceLimitStatus.getDistanceLimit().intValue() != this.distanceLimit; + default: + throw new RuntimeException("Property " + fieldName + " does not exist."); + } + } +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/DockWirelessLinkReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/DockWirelessLinkReceiver.java new file mode 100644 index 0000000..83bfb3f --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/DockWirelessLinkReceiver.java @@ -0,0 +1,38 @@ +package com.dji.sample.manage.model.receiver; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * @author sean + * @version 1.3 + * @date 2022/11/3 + */ +@Data +public class DockWirelessLinkReceiver { + + @JsonProperty("4g_freq_band") + private Float fourGFreqBand; + + @JsonProperty("4g_gnd_quality") + private Integer fourGGndQuality; + + @JsonProperty("4g_link_state") + private Integer fourGLinkState; + + @JsonProperty("4g_quality") + private Integer fourGQuality; + + @JsonProperty("4g_uav_quality") + private Integer fourGUavQuality; + + private Integer dongleNumber; + + private Integer linkWorkmode; + + private Float sdrFreqBand; + + private Integer sdrLinkState; + + private Integer sdrQuality; +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/DroneBatteryMaintenanceInfoReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/DroneBatteryMaintenanceInfoReceiver.java new file mode 100644 index 0000000..1718aca --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/DroneBatteryMaintenanceInfoReceiver.java @@ -0,0 +1,16 @@ +package com.dji.sample.manage.model.receiver; + +import lombok.Data; + +/** + * @author sean + * @version 1.4 + * @date 2022/11/3 + */ +@Data +public class DroneBatteryMaintenanceInfoReceiver { + + private Integer maintenanceState; + + private Long maintenanceTimeLeft; +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/HeightLimitReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/HeightLimitReceiver.java new file mode 100644 index 0000000..7a07565 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/HeightLimitReceiver.java @@ -0,0 +1,29 @@ +package com.dji.sample.manage.model.receiver; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Objects; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class HeightLimitReceiver extends BasicDeviceProperty { + + private static final int HEIGHT_LIMIT_MAX = 1500; + + private static final int HEIGHT_LIMIT_MIN = 20; + + private Integer value; + + @Override + public boolean valid() { + return Objects.nonNull(this.value) && this.value >= HEIGHT_LIMIT_MIN && this.value <= HEIGHT_LIMIT_MAX; + } +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/MaintainStatusReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/MaintainStatusReceiver.java new file mode 100644 index 0000000..7896f31 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/MaintainStatusReceiver.java @@ -0,0 +1,20 @@ +package com.dji.sample.manage.model.receiver; + +import lombok.Data; + +/** + * @author sean + * @version 1.3 + * @date 2022/11/3 + */ +@Data +public class MaintainStatusReceiver { + + private Integer state; + + private Integer lastMaintainType; + + private Long lastMaintainTime; + + private Long lastMaintainWorkSorties; +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/NetworkStateReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/NetworkStateReceiver.java index 84698cc..2aac8ae 100644 --- a/src/main/java/com/dji/sample/manage/model/receiver/NetworkStateReceiver.java +++ b/src/main/java/com/dji/sample/manage/model/receiver/NetworkStateReceiver.java @@ -14,5 +14,5 @@ public class NetworkStateReceiver { private Integer quality; - private float rate; + private Float rate; } diff --git a/src/main/java/com/dji/sample/manage/model/receiver/ObstacleAvoidanceReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/ObstacleAvoidanceReceiver.java new file mode 100644 index 0000000..e40a341 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/receiver/ObstacleAvoidanceReceiver.java @@ -0,0 +1,62 @@ +package com.dji.sample.manage.model.receiver; + +import com.dji.sample.manage.model.enums.StateSwitchReceiver; +import lombok.Data; + +import java.util.Objects; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/27 + */ +@Data +public class ObstacleAvoidanceReceiver extends BasicDeviceProperty { + + private Integer horizon; + + private Integer upside; + + private Integer downside; + + @Override + public boolean valid() { + boolean valid = Objects.nonNull(this.horizon) || Objects.nonNull(this.upside) || Objects.nonNull(this.downside); + + StateSwitchReceiver stateSwitch = new StateSwitchReceiver(); + if (Objects.nonNull(this.horizon)) { + stateSwitch.setValue(this.horizon); + valid = stateSwitch.valid(); + } + if (Objects.nonNull(this.upside)) { + stateSwitch.setValue(this.upside); + valid &= stateSwitch.valid(); + } + if (Objects.nonNull(this.downside)) { + stateSwitch.setValue(this.downside); + valid &= stateSwitch.valid(); + } + return valid; + } + + @Override + public boolean canPublish(String fieldName, OsdSubDeviceReceiver osd) { + ObstacleAvoidanceReceiver obstacleAvoidance = osd.getObstacleAvoidance(); + switch (fieldName) { + case "horizon": + return Objects.isNull(obstacleAvoidance.getHorizon()) || + Objects.nonNull(obstacleAvoidance.getHorizon()) && + obstacleAvoidance.getHorizon().intValue() != this.horizon; + case "upside": + return Objects.isNull(obstacleAvoidance.getUpside()) || + Objects.nonNull(obstacleAvoidance.getUpside()) && + obstacleAvoidance.getUpside().intValue() != this.upside; + case "downside": + return Objects.isNull(obstacleAvoidance.getDownside()) || + Objects.nonNull(obstacleAvoidance.getDownside()) && + obstacleAvoidance.getDownside().intValue() != this.downside; + default: + throw new RuntimeException("Property " + fieldName + " does not exist."); + } + } +} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/OsdDockReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/OsdDockReceiver.java index ebd8b34..0cd5196 100644 --- a/src/main/java/com/dji/sample/manage/model/receiver/OsdDockReceiver.java +++ b/src/main/java/com/dji/sample/manage/model/receiver/OsdDockReceiver.java @@ -4,8 +4,8 @@ import lombok.Data; /** * @author sean - * @version 1.0 - * @date 2022/5/11 + * @version 1.3 + * @date 2022/11/3 */ @Data public class OsdDockReceiver { @@ -22,8 +22,6 @@ public class OsdDockReceiver { private Float environmentTemperature; - private Integer environmentHumidity; - private Float temperature; private Integer humidity; @@ -36,32 +34,55 @@ public class OsdDockReceiver { private AlternateLandPointReceiver alternateLandPoint; - private Integer jobNumber; - - private Integer accTime; - private Long firstPowerOn; private PositionStateReceiver positionState; private StorageReceiver storage; + private Integer modeCode; + + private Integer coverState; + + private Integer supplementLightState; + + private Integer emergencyStopState; + + private Integer airConditionerMode; + + private Integer batteryStoreMode; + + private Integer alarmState; + + private Integer putterState; + + private DockSubDeviceReceiver subDevice; + + private Integer jobNumber; + + private Long accTime; + + private Long activationTime; + + private DeviceMaintainStatusReceiver maintainStatus; + private Integer electricSupplyVoltage; private Integer workingVoltage; private Integer workingCurrent; - private Integer backupBatteryVoltage; + private BackupBatteryReceiver backupBattery; - private Integer modeCode; + private DroneBatteryMaintenanceInfoReceiver droneBatteryMaintenanceInfo; - private Integer coverState; + private Integer flighttaskStepCode; - private Integer supplementLightState; + private Integer flighttaskPrepareCapacity; - private Integer putterState; + private DockMediaFileDetailReceiver mediaFileDetail; - private DockSubDeviceReceiver subDevice; + private DockSdrReceiver sdr; + private DockWirelessLinkReceiver wirelessLink; } diff --git a/src/main/java/com/dji/sample/manage/model/receiver/OsdDockTransmissionReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/OsdDockTransmissionReceiver.java deleted file mode 100644 index cdd9abf..0000000 --- a/src/main/java/com/dji/sample/manage/model/receiver/OsdDockTransmissionReceiver.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.dji.sample.manage.model.receiver; - -import lombok.Data; - -/** - * @author sean - * @version 1.1 - * @date 2022/6/17 - */ -@Data -public class OsdDockTransmissionReceiver { - - private Integer flighttaskStepCode; - - private DockMediaFileDetailReceiver mediaFileDetail; - - private DockSdrReceiver sdr; -} diff --git a/src/main/java/com/dji/sample/manage/model/receiver/OsdSubDeviceReceiver.java b/src/main/java/com/dji/sample/manage/model/receiver/OsdSubDeviceReceiver.java index 2cb54df..b39fb09 100644 --- a/src/main/java/com/dji/sample/manage/model/receiver/OsdSubDeviceReceiver.java +++ b/src/main/java/com/dji/sample/manage/model/receiver/OsdSubDeviceReceiver.java @@ -58,4 +58,13 @@ public class OsdSubDeviceReceiver { private List payloads; private StorageReceiver storage; + + private Integer nightLightsState; + + private Integer heightLimit; + + private DistanceLimitStatusReceiver distanceLimitStatus; + + private ObstacleAvoidanceReceiver obstacleAvoidance; + } \ No newline at end of file diff --git a/src/main/java/com/dji/sample/manage/service/IDeviceDictionaryService.java b/src/main/java/com/dji/sample/manage/service/IDeviceDictionaryService.java index 201f82c..97b901b 100644 --- a/src/main/java/com/dji/sample/manage/service/IDeviceDictionaryService.java +++ b/src/main/java/com/dji/sample/manage/service/IDeviceDictionaryService.java @@ -13,10 +13,12 @@ public interface IDeviceDictionaryService { /** * Query the type data of the device based on domain, device type and sub type. + * + * @param domain * @param deviceType * @param subType * @return */ - Optional getOneDictionaryInfoByTypeSubType(Integer deviceType, Integer subType); + Optional getOneDictionaryInfoByTypeSubType(Integer domain, Integer deviceType, Integer subType); } diff --git a/src/main/java/com/dji/sample/manage/service/IDeviceService.java b/src/main/java/com/dji/sample/manage/service/IDeviceService.java index 37e5a44..c048eb4 100644 --- a/src/main/java/com/dji/sample/manage/service/IDeviceService.java +++ b/src/main/java/com/dji/sample/manage/service/IDeviceService.java @@ -8,13 +8,17 @@ import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO; import com.dji.sample.manage.model.dto.TopologyDeviceDTO; +import com.dji.sample.manage.model.enums.DeviceSetPropertyEnum; import com.dji.sample.manage.model.param.DeviceQueryParam; import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; /** @@ -133,10 +137,9 @@ public interface IDeviceService { /** * Handle messages from the osd topic. - * @param topic osd - * @param payload + * @param message osd */ - void handleOSD(String topic, byte[] payload); + void handleOSD(Message message); /** * Update the device information. @@ -205,4 +208,28 @@ public interface IDeviceService { * @return */ ResponseResult createDeviceOtaJob(String workspaceId, List upgradeDTOS); + + /** + * Set the property parameters of the drone. + * @param workspaceId + * @param dockSn + * @param propertyEnum + * @param param + */ + void devicePropertySet(String workspaceId, String dockSn, DeviceSetPropertyEnum propertyEnum, JsonNode param); + + /** + * Set one property parameters of the drone. + * @param topic + * @param propertyEnum + * @param value + */ + void deviceOnePropertySet(String topic, DeviceSetPropertyEnum propertyEnum, Map.Entry value); + + /** + * Determine if the device is online. + * @param sn + * @return + */ + Boolean checkDeviceOnline(String sn); } \ No newline at end of file diff --git a/src/main/java/com/dji/sample/manage/service/impl/CapacityCameraServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/CapacityCameraServiceImpl.java index be5020d..13ddc9b 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/CapacityCameraServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/CapacityCameraServiceImpl.java @@ -5,6 +5,7 @@ import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.redis.RedisOpsUtils; import com.dji.sample.manage.model.dto.CapacityCameraDTO; import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; +import com.dji.sample.manage.model.enums.DeviceDomainEnum; import com.dji.sample.manage.model.receiver.CapacityCameraReceiver; import com.dji.sample.manage.service.ICameraVideoService; import com.dji.sample.manage.service.ICapacityCameraService; @@ -68,7 +69,7 @@ public class CapacityCameraServiceImpl implements ICapacityCameraService { // type-subType-index if (indexArr.length == 3) { Optional dictionaryOpt = dictionaryService - .getOneDictionaryInfoByTypeSubType(indexArr[0], indexArr[1]); + .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.PAYLOAD.getVal(), indexArr[0], indexArr[1]); dictionaryOpt.ifPresent(dictionary -> builder.name(dictionary.getDeviceName())); } diff --git a/src/main/java/com/dji/sample/manage/service/impl/DeviceDictionaryServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceDictionaryServiceImpl.java index f0dbad0..a4574b7 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DeviceDictionaryServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DeviceDictionaryServiceImpl.java @@ -25,16 +25,18 @@ public class DeviceDictionaryServiceImpl implements IDeviceDictionaryService { private IDeviceDictionaryMapper mapper; @Override - public Optional getOneDictionaryInfoByTypeSubType(Integer deviceType, Integer subType) { - if (deviceType == null || subType == null) { + public Optional getOneDictionaryInfoByTypeSubType(Integer domain, Integer deviceType, Integer subType) { + if (domain == null || deviceType == null || subType == null) { return Optional.empty(); } return Optional.ofNullable( entityConvertToDTO( mapper.selectOne( new LambdaQueryWrapper() + .eq(DeviceDictionaryEntity::getDomain, domain) .eq(DeviceDictionaryEntity::getDeviceType, deviceType) - .eq(DeviceDictionaryEntity::getSubType, subType)))); + .eq(DeviceDictionaryEntity::getSubType, subType) + .last(" limit 1 ")))); } /** diff --git a/src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java index 61e2fff..7e8882c 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java @@ -18,6 +18,7 @@ import com.dji.sample.manage.model.entity.DeviceFirmwareEntity; import com.dji.sample.manage.model.enums.UserTypeEnum; import com.dji.sample.manage.model.param.DeviceOtaCreateParam; import com.dji.sample.manage.service.IDeviceFirmwareService; +import com.dji.sample.manage.service.IDeviceService; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; @@ -61,6 +62,9 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { @Autowired private IWebSocketManageService webSocketManageService; + @Autowired + private IDeviceService deviceService; + @Override public Optional getFirmware(String deviceName, String version) { return Optional.ofNullable(entity2Dto(mapper.selectOne( @@ -83,7 +87,7 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { public List getDeviceOtaFirmware(List upgradeDTOS) { List deviceOtaList = new ArrayList<>(); upgradeDTOS.forEach(upgradeDevice -> { - boolean exist = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + upgradeDevice.getSn()) > 0; + boolean exist = deviceService.checkDeviceOnline(upgradeDevice.getSn()); if (!exist) { throw new IllegalArgumentException("Device is offline."); } diff --git a/src/main/java/com/dji/sample/manage/service/impl/DeviceLogsServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceLogsServiceImpl.java index 9e238cb..913e0f2 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DeviceLogsServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DeviceLogsServiceImpl.java @@ -113,7 +113,7 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { } String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + deviceSn + TopicConst.SERVICES_SUF; - Optional serviceReplyOpt = messageSenderService.publishWithReply( + LogsFileUploadList data = messageSenderService.publishWithReply( LogsFileUploadList.class, topic, CommonTopicResponse.builder() @@ -123,10 +123,7 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { .timestamp(System.currentTimeMillis()) .data(Map.of(MapKeyConst.MODULE_LIST, domainList)) .build(), 1); - if (serviceReplyOpt.isEmpty()) { - return ResponseResult.error("No message reply received."); - } - LogsFileUploadList data = serviceReplyOpt.get(); + for (LogsFileUpload file : data.getFiles()) { if (file.getDeviceSn().isBlank()) { file.setDeviceSn(deviceSn); @@ -170,7 +167,7 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { credentialsDTO.setParams(LogsFileUploadList.builder().files(files).build()); String bid = UUID.randomUUID().toString(); - Optional serviceReply = messageSenderService.publishWithReply( + ServiceReply reply = messageSenderService.publishWithReply( TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + deviceSn + TopicConst.SERVICES_SUF, CommonTopicResponse.builder() .tid(UUID.randomUUID().toString()) @@ -180,10 +177,6 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { .data(credentialsDTO) .build()); - if (serviceReply.isEmpty()) { - return ResponseResult.error("No message reply received."); - } - ServiceReply reply = serviceReply.get(); if (ResponseResult.CODE_SUCCESS != reply.getResult()) { return ResponseResult.error(String.valueOf(reply.getResult())); } @@ -207,7 +200,7 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { } String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + deviceSn + TopicConst.SERVICES_SUF; String bid = UUID.randomUUID().toString(); - Optional serviceReply = messageSenderService.publishWithReply(topic, + ServiceReply reply = messageSenderService.publishWithReply(topic, CommonTopicResponse.builder() .tid(UUID.randomUUID().toString()) .bid(bid) @@ -216,10 +209,6 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { .data(param) .build()); - if (serviceReply.isEmpty()) { - return ResponseResult.error("No message reply received."); - } - ServiceReply reply = serviceReply.get(); if (ResponseResult.CODE_SUCCESS != reply.getResult()) { return ResponseResult.error("Error Code : " + reply.getResult()); } @@ -284,7 +273,6 @@ public class DeviceLogsServiceImpl implements IDeviceLogsService { List fileReceivers = output.getExt().getFiles(); if (CollectionUtils.isEmpty(fileReceivers)) { redisOpsUtils.del(RedisConst.LOGS_FILE_PREFIX + sn); - return; } // refresh cache. diff --git a/src/main/java/com/dji/sample/manage/service/impl/DeviceOSDServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceOSDServiceImpl.java index 9fc690d..16ed4be 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DeviceOSDServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DeviceOSDServiceImpl.java @@ -1,6 +1,7 @@ package com.dji.sample.manage.service.impl; import com.dji.sample.component.mqtt.model.CommonTopicReceiver; +import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; import com.dji.sample.component.websocket.model.BizCodeEnum; import com.dji.sample.component.websocket.model.CustomWebSocketMessage; @@ -74,7 +75,7 @@ public class DeviceOSDServiceImpl extends AbstractTSAService { log.warn("Please remount the payload, or restart the drone. Otherwise the data of the payload will not be received."); } - + redisOps.setWithExpire(RedisConst.OSD_PREFIX + device.getDeviceSn(), data, RedisConst.DEVICE_ALIVE_SECOND); wsMessage.getData().setHost(data); sendMessageService.sendBatch(webSessions, wsMessage); diff --git a/src/main/java/com/dji/sample/manage/service/impl/DevicePayloadServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DevicePayloadServiceImpl.java index 123660b..1e6f52b 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DevicePayloadServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DevicePayloadServiceImpl.java @@ -9,6 +9,7 @@ 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; @@ -204,7 +205,7 @@ public class DevicePayloadServiceImpl implements IDevicePayloadService { if (arr.length == 3) { Optional dictionaryOpt = dictionaryService - .getOneDictionaryInfoByTypeSubType(arr[0], arr[1]); + .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.PAYLOAD.getVal(), arr[0], arr[1]); dictionaryOpt.ifPresent(dictionary -> builder.payloadName(dictionary.getDeviceName()) .payloadDesc(dictionary.getDeviceDesc())); diff --git a/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java index 1fecf85..52f012d 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java @@ -20,21 +20,20 @@ import com.dji.sample.component.websocket.service.IWebSocketManageService; import com.dji.sample.manage.dao.IDeviceMapper; import com.dji.sample.manage.model.dto.*; import com.dji.sample.manage.model.entity.DeviceEntity; -import com.dji.sample.manage.model.enums.DeviceDomainEnum; -import com.dji.sample.manage.model.enums.DeviceFirmwareStatusEnum; -import com.dji.sample.manage.model.enums.IconUrlEnum; -import com.dji.sample.manage.model.enums.UserTypeEnum; +import com.dji.sample.manage.model.enums.*; import com.dji.sample.manage.model.param.DeviceOtaCreateParam; import com.dji.sample.manage.model.param.DeviceQueryParam; import com.dji.sample.manage.model.receiver.*; import com.dji.sample.manage.service.*; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.mqtt.support.MqttHeaders; +import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -99,6 +98,9 @@ public class DeviceServiceImpl implements IDeviceService { @Qualifier("gatewayOSDServiceImpl") private ITSAService tsaService; + private static final List INIT_TOPICS_SUFFIX = List.of( + OSD_SUF, STATE_SUF, SERVICES_SUF + _REPLY_SUF, REQUESTS_SUF, EVENTS_SUF, PROPERTY_SUF + SET_SUF + _REPLY_SUF); + @Override public Boolean deviceOffline(String gatewaySn) { this.subscribeTopicOnline(gatewaySn); @@ -111,26 +113,24 @@ public class DeviceServiceImpl implements IDeviceService { Optional gatewayOpt = this.getDeviceBySn(gatewaySn); if (gatewayOpt.isPresent()) { DeviceDTO value = gatewayOpt.get(); - value.setChildDeviceSn(value.getDeviceSn()); value.setBoundTime(null); value.setLoginTime(null); redisOps.setWithExpire(key, value, RedisConst.DEVICE_ALIVE_SECOND); this.pushDeviceOnlineTopo(value.getWorkspaceId(), gatewaySn, gatewaySn); return true; } + // When connecting for the first time DeviceDTO gateway = DeviceDTO.builder() .deviceSn(gatewaySn) - .childDeviceSn(gatewaySn) .domain(DeviceDomainEnum.GATEWAY.getDesc()) .build(); - gatewayOpt.map(DeviceDTO::getWorkspaceId).ifPresent(gateway::setWorkspaceId); redisOps.setWithExpire(key, gateway, RedisConst.DEVICE_ALIVE_SECOND); - this.pushDeviceOnlineTopo(gateway.getWorkspaceId(), gatewaySn, gatewaySn); return true; } - String deviceSn = ((DeviceDTO)(redisOps.get(key))).getChildDeviceSn(); - if (deviceSn.equals(gatewaySn)) { + DeviceDTO deviceDTO = (DeviceDTO) (redisOps.get(key)); + String deviceSn = deviceDTO.getChildDeviceSn(); + if (!StringUtils.hasText(deviceSn)) { return true; } @@ -139,21 +139,23 @@ public class DeviceServiceImpl implements IDeviceService { @Override public Boolean subDeviceOffline(String deviceSn) { - // Cancel drone-related subscriptions. - this.unsubscribeTopicOffline(deviceSn); - payloadService.deletePayloadsByDeviceSn(new ArrayList<>(List.of(deviceSn))); - // If no information about this gateway device exists in the database, the drone is considered to be offline. + // If no information about this device exists in the cache, the drone is considered to be offline. String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; if (!redisOps.checkExist(key) || redisOps.getExpire(key) <= 0) { log.debug("The drone is already offline."); return true; } DeviceDTO device = (DeviceDTO) redisOps.get(key); + // Cancel drone-related subscriptions. + this.unsubscribeTopicOffline(deviceSn); + + payloadService.deletePayloadsByDeviceSn(new ArrayList<>(List.of(deviceSn))); // Publish the latest device topology information in the current workspace. this.pushDeviceOfflineTopo(device.getWorkspaceId(), deviceSn); redisOps.del(key); + redisOps.del(RedisConst.OSD_PREFIX + device.getDeviceSn()); log.debug("{} offline.", deviceSn); return true; } @@ -264,20 +266,14 @@ public class DeviceServiceImpl implements IDeviceService { return; } } - topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + OSD_SUF); - topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + STATE_SUF); - topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + SERVICES_SUF + _REPLY_SUF); - topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + REQUESTS_SUF); - topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + EVENTS_SUF); + String prefix = THING_MODEL_PRE + PRODUCT + sn; + INIT_TOPICS_SUFFIX.forEach(suffix -> topicService.subscribe(prefix + suffix)); } @Override public void unsubscribeTopicOffline(String sn) { - topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + OSD_SUF); - topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + STATE_SUF); - topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + SERVICES_SUF + _REPLY_SUF); - topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + REQUESTS_SUF); - topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + EVENTS_SUF); + String prefix = THING_MODEL_PRE + PRODUCT + sn; + INIT_TOPICS_SUFFIX.forEach(suffix -> topicService.unsubscribe(prefix + suffix)); } @Override @@ -459,7 +455,10 @@ public class DeviceServiceImpl implements IDeviceService { } @Override - public void handleOSD(String topic, byte[] payload) { + @ServiceActivator(inputChannel = ChannelName.INBOUND_OSD) + public void handleOSD(Message message) { + String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); + byte[] payload = (byte[])message.getPayload(); CommonTopicReceiver receiver; try { String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(), @@ -568,7 +567,7 @@ public class DeviceServiceImpl implements IDeviceService { // Query the model information of this gateway device. Optional dictionaryOpt = dictionaryService - .getOneDictionaryInfoByTypeSubType(gateway.getType(), gateway.getSubType()); + .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.GATEWAY.getVal(), gateway.getType(), gateway.getSubType()); dictionaryOpt.ifPresent(entity -> builder.deviceName(entity.getDeviceName()) @@ -598,7 +597,7 @@ public class DeviceServiceImpl implements IDeviceService { // Query the model information of this drone device. Optional dictionaryOpt = dictionaryService - .getOneDictionaryInfoByTypeSubType(device.getType(), device.getSubType()); + .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.SUB_DEVICE.getVal(), device.getType(), device.getSubType()); dictionaryOpt.ifPresent(dictionary -> builder.deviceName(dictionary.getDeviceName()) @@ -767,8 +766,8 @@ public class DeviceServiceImpl implements IDeviceService { assert dock != null; - Optional dockEntityOpt = this.bindDevice2Entity(dock); - Optional droneEntityOpt = this.bindDevice2Entity(drone); + Optional dockEntityOpt = this.bindDevice2Entity(DeviceDomainEnum.DOCK.getVal(), dock); + Optional droneEntityOpt = this.bindDevice2Entity(DeviceDomainEnum.SUB_DEVICE.getVal(), drone); List bindResult = new ArrayList<>(); @@ -855,7 +854,13 @@ public class DeviceServiceImpl implements IDeviceService { } @Override + @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_FIRMWARE_VERSION) public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { + // If the reported version is empty, it will not be processed to prevent misleading page. + if (!StringUtils.hasText(receiver.getFirmwareVersion())) { + return; + } + if (receiver.getDomain() == DeviceDomainEnum.SUB_DEVICE) { final DeviceDTO device = DeviceDTO.builder() .deviceSn(receiver.getSn()) @@ -885,7 +890,7 @@ public class DeviceServiceImpl implements IDeviceService { // The bids in the progress messages reported subsequently are the same. String bid = UUID.randomUUID().toString(); - Optional serviceReplyOpt = messageSender.publishWithReply( + ServiceReply serviceReply = messageSender.publishWithReply( topic, CommonTopicResponse.>>builder() .tid(UUID.randomUUID().toString()) .bid(bid) @@ -893,10 +898,6 @@ public class DeviceServiceImpl implements IDeviceService { .method(ServicesMethodEnum.OTA_CREATE.getMethod()) .data(Map.of(MapKeyConst.DEVICES, deviceOtaFirmwares)) .build()); - if (serviceReplyOpt.isEmpty()) { - return ResponseResult.error("No message reply received."); - } - ServiceReply serviceReply = serviceReplyOpt.get(); if (serviceReply.getResult() != ResponseResult.CODE_SUCCESS) { return ResponseResult.error(serviceReply.getResult(), "Firmware Error Code: " + serviceReply.getResult()); } @@ -910,6 +911,79 @@ public class DeviceServiceImpl implements IDeviceService { return ResponseResult.success(); } + @Override + public void devicePropertySet(String workspaceId, String dockSn, DeviceSetPropertyEnum propertyEnum, JsonNode param) { + boolean dockOnline = this.checkDeviceOnline(dockSn); + if (!dockOnline) { + throw new RuntimeException("Dock is offline."); + } + DeviceDTO deviceDTO = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + dockSn); + boolean deviceOnline = this.checkDeviceOnline(deviceDTO.getChildDeviceSn()); + if (!deviceOnline) { + throw new RuntimeException("Device is offline."); + } + + // Make sure the data is valid. + BasicDeviceProperty basicDeviceProperty = objectMapper.convertValue(param, propertyEnum.getClazz()); + boolean valid = basicDeviceProperty.valid(); + if (!valid) { + throw new IllegalArgumentException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg()); + } + + String topic = THING_MODEL_PRE + PRODUCT + dockSn + PROPERTY_SUF + SET_SUF; + OsdSubDeviceReceiver osd = (OsdSubDeviceReceiver) redisOps.get(RedisConst.OSD_PREFIX + deviceDTO.getChildDeviceSn()); + if (!param.isObject()) { + this.deviceOnePropertySet(topic, propertyEnum, Map.entry(propertyEnum.getProperty(), param)); + return; + } + // If there are multiple parameters, set them separately. + for (Iterator> filed = param.fields(); filed.hasNext(); ) { + Map.Entry node = filed.next(); + boolean isPublish = basicDeviceProperty.canPublish(node.getKey(), osd); + if (!isPublish) { + continue; + } + this.deviceOnePropertySet(topic, propertyEnum, Map.entry(propertyEnum.getProperty(), node)); + } + + } + + @Override + public void deviceOnePropertySet(String topic, DeviceSetPropertyEnum propertyEnum, Map.Entry value) { + if (Objects.isNull(value) || Objects.isNull(value.getValue())) { + throw new IllegalArgumentException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg()); + } + + Map reply = messageSender.publishWithReply( + Map.class, topic, + CommonTopicResponse.builder() + .bid(UUID.randomUUID().toString()) + .tid(UUID.randomUUID().toString()) + .timestamp(System.currentTimeMillis()) + .data(value) + .build(), + 2); + + while (true) { + reply = (Map) reply.get(value.getKey()); + if (value.getValue() instanceof JsonNode) { + break; + } + value = (Map.Entry) value.getValue(); + } + + SetReply setReply = objectMapper.convertValue(reply, SetReply.class); + if (SetReplyStatusResultEnum.SUCCESS.getVal() != setReply.getResult()) { + throw new RuntimeException("Failed to set " + value.getKey() + "; Error Code: " + setReply.getResult()); + } + + } + + public Boolean checkDeviceOnline(String sn) { + String key = RedisConst.DEVICE_ONLINE_PREFIX + sn; + return redisOps.checkExist(key) && redisOps.getExpire(key) > 0; + } + /** * Convert device data transfer object into database entity object. * @param dto @@ -940,15 +1014,17 @@ public class DeviceServiceImpl implements IDeviceService { /** * Convert device binding data object into database entity object. + * + * @param domain * @param receiver * @return */ - private Optional bindDevice2Entity(BindDeviceReceiver receiver) { + private Optional bindDevice2Entity(Integer domain, BindDeviceReceiver receiver) { if (receiver == null) { return Optional.empty(); } int[] droneKey = Arrays.stream(receiver.getDeviceModelKey().split("-")).mapToInt(Integer::parseInt).toArray(); - Optional dictionaryOpt = dictionaryService.getOneDictionaryInfoByTypeSubType(droneKey[1], droneKey[2]); + Optional dictionaryOpt = dictionaryService.getOneDictionaryInfoByTypeSubType(domain, droneKey[1], droneKey[2]); DeviceEntity.DeviceEntityBuilder builder = DeviceEntity.builder(); dictionaryOpt.ifPresent(entity -> diff --git a/src/main/java/com/dji/sample/manage/service/impl/DockOSDServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DockOSDServiceImpl.java index 4c34cd5..562be9d 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/DockOSDServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/DockOSDServiceImpl.java @@ -8,10 +8,10 @@ import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.dto.TelemetryDTO; import com.dji.sample.manage.model.enums.DeviceDomainEnum; import com.dji.sample.manage.model.receiver.OsdDockReceiver; -import com.dji.sample.manage.model.receiver.OsdDockTransmissionReceiver; import org.springframework.stereotype.Service; import java.util.Collection; +import java.util.Objects; /** * @author sean @@ -39,11 +39,10 @@ public class DockOSDServiceImpl extends AbstractTSAService { if (DeviceDomainEnum.DOCK.getDesc().equals(device.getDomain())) { wsMessage.setBizCode(BizCodeEnum.DOCK_OSD.getCode()); OsdDockReceiver data = mapper.convertValue(receiver.getData(), OsdDockReceiver.class); - wsMessage.getData().setHost(data); - if (data.getSubDevice() == null) { - OsdDockTransmissionReceiver transmission = mapper.convertValue(receiver.getData(), OsdDockTransmissionReceiver.class); - wsMessage.getData().setHost(transmission); + if (Objects.nonNull(data.getMaintainStatus())) { + return; } + wsMessage.getData().setHost(data); sendMessageService.sendBatch(webSessions, wsMessage); } } diff --git a/src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java index aee86ca..74d0fd2 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java @@ -104,13 +104,10 @@ public class LiveStreamServiceImpl implements ILiveStreamService { // target topic String respTopic = THING_MODEL_PRE + PRODUCT + data.getDeviceSn() + SERVICES_SUF; - Optional receiveReplyOpt = this.publishLiveStart(respTopic, liveParam); + ServiceReply receiveReply = this.publishLiveStart(respTopic, liveParam); - if (receiveReplyOpt.isEmpty()) { - return ResponseResult.error(LiveErrorEnum.NO_REPLY); - } - if (ResponseResult.CODE_SUCCESS != receiveReplyOpt.get().getResult()) { - return ResponseResult.error(LiveErrorEnum.find(receiveReplyOpt.get().getResult())); + if (ResponseResult.CODE_SUCCESS != receiveReply.getResult()) { + return ResponseResult.error(LiveErrorEnum.find(receiveReply.getResult())); } LiveUrlTypeEnum urlType = LiveUrlTypeEnum.find(liveParam.getUrlType()); @@ -132,7 +129,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { .toString()); break; case RTSP: - String url = receiveReplyOpt.get().getInfo().toString(); + String url = receiveReply.getInfo().toString(); this.resolveUrlUser(url, live); break; case UNKNOWN: @@ -151,12 +148,9 @@ public class LiveStreamServiceImpl implements ILiveStreamService { String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF; - Optional receiveReplyOpt = this.publishLiveStop(respTopic, videoId); - if (receiveReplyOpt.isEmpty()) { - return ResponseResult.error(LiveErrorEnum.NO_REPLY); - } - if (receiveReplyOpt.get().getResult() != 0) { - return ResponseResult.error(LiveErrorEnum.find(receiveReplyOpt.get().getResult())); + ServiceReply receiveReply = this.publishLiveStop(respTopic, videoId); + if (receiveReply.getResult() != 0) { + return ResponseResult.error(LiveErrorEnum.find(receiveReply.getResult())); } return ResponseResult.success(); @@ -177,12 +171,9 @@ public class LiveStreamServiceImpl implements ILiveStreamService { String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF; - Optional receiveReplyOpt = this.publishLiveSetQuality(respTopic, liveParam); - if (receiveReplyOpt.isEmpty()) { - return ResponseResult.error(LiveErrorEnum.NO_REPLY); - } - if (receiveReplyOpt.get().getResult() != 0) { - return ResponseResult.error(LiveErrorEnum.find(receiveReplyOpt.get().getResult())); + ServiceReply receiveReply = this.publishLiveSetQuality(respTopic, liveParam); + if (ResponseResult.CODE_SUCCESS == receiveReply.getResult()) { + return ResponseResult.error(LiveErrorEnum.find(receiveReply.getResult())); } return ResponseResult.success(); @@ -204,18 +195,16 @@ public class LiveStreamServiceImpl implements ILiveStreamService { String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF; - Optional receiveReplyOpt = this.publishLiveLensChange(respTopic, liveParam); - if (receiveReplyOpt.isEmpty()) { - return ResponseResult.error(LiveErrorEnum.NO_REPLY); - } - if (receiveReplyOpt.get().getResult() != 0) { - return ResponseResult.error(LiveErrorEnum.find(receiveReplyOpt.get().getResult())); + ServiceReply receiveReply = this.publishLiveLensChange(respTopic, liveParam); + + if (ResponseResult.CODE_SUCCESS != receiveReply.getResult()) { + return ResponseResult.error(LiveErrorEnum.find(receiveReply.getResult())); } return ResponseResult.success(); } - private Optional publishLiveLensChange(String respTopic, LiveTypeDTO liveParam) { + private ServiceReply publishLiveLensChange(String respTopic, LiveTypeDTO liveParam) { CommonTopicResponse response = new CommonTopicResponse<>(); response.setTid(UUID.randomUUID().toString()); response.setBid(UUID.randomUUID().toString()); @@ -312,7 +301,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { * @param liveParam * @return */ - private Optional publishLiveStart(String topic, LiveTypeDTO liveParam) { + private ServiceReply publishLiveStart(String topic, LiveTypeDTO liveParam) { CommonTopicResponse response = new CommonTopicResponse<>(); response.setTid(UUID.randomUUID().toString()); response.setBid(UUID.randomUUID().toString()); @@ -328,7 +317,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { * @param liveParam * @return */ - private Optional publishLiveSetQuality(String respTopic, LiveTypeDTO liveParam) { + private ServiceReply publishLiveSetQuality(String respTopic, LiveTypeDTO liveParam) { Map data = new ConcurrentHashMap<>(Map.of( "video_id", liveParam.getVideoId(), "video_quality", liveParam.getVideoQuality())); @@ -347,7 +336,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { * @param videoId * @return */ - private Optional publishLiveStop(String topic, String videoId) { + private ServiceReply publishLiveStop(String topic, String videoId) { Map data = new ConcurrentHashMap<>(Map.of("video_id", videoId)); CommonTopicResponse> response = new CommonTopicResponse<>(); response.setTid(UUID.randomUUID().toString()); diff --git a/src/main/java/com/dji/sample/manage/service/impl/LogsFileIndexServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/LogsFileIndexServiceImpl.java index e773828..5eeb5a1 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/LogsFileIndexServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/LogsFileIndexServiceImpl.java @@ -50,7 +50,7 @@ public class LogsFileIndexServiceImpl implements ILogsFileIndexService { files.forEach(file -> { Optional fileOpt = this.getFileIndexByFileId(file.getFileId()); fileOpt.ifPresent(fileUpload -> { - fileUpload.setObjectKey(file.getStatus() ? file.getObjectKey() : ""); + fileUpload.setObjectKey(file.getStatus() ? file.getObjectKey() : null); list.add(fileUpload); }); }); diff --git a/src/main/java/com/dji/sample/manage/service/impl/UserServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/UserServiceImpl.java index 8f3df63..746fe99 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/UserServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/UserServiceImpl.java @@ -1,6 +1,8 @@ package com.dji.sample.manage.service.impl; import com.auth0.jwt.JWT; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -29,6 +31,7 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -115,10 +118,22 @@ public class UserServiceImpl implements IUserService { if (!StringUtils.hasText(token)) { return Optional.empty(); } - CustomClaim customClaim = new CustomClaim(JWT.decode(token).getClaims()); + CustomClaim customClaim; + try { + DecodedJWT jwt = JwtUtil.verifyToken(token); + customClaim = new CustomClaim(jwt.getClaims()); + } catch (TokenExpiredException e) { + customClaim = new CustomClaim(JWT.decode(token).getClaims()); + } catch (Exception e) { + e.printStackTrace(); + return Optional.empty(); + } String refreshToken = JwtUtil.createToken(customClaim.convertToMap()); UserDTO user = entityConvertToDTO(this.getUserByUsername(customClaim.getUsername())); + if (Objects.isNull(user)) { + return Optional.empty(); + } user.setWorkspaceId(customClaim.getWorkspaceId()); user.setAccessToken(refreshToken); return Optional.of(user); @@ -195,7 +210,7 @@ public class UserServiceImpl implements IUserService { */ private UserDTO entityConvertToDTO(UserEntity entity) { if (entity == null) { - return new UserDTO(); + return null; } return UserDTO.builder() .userId(entity.getUserId()) diff --git a/src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java b/src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java index 821594d..182602d 100644 --- a/src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java +++ b/src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java @@ -7,6 +7,7 @@ import com.dji.sample.common.model.PaginationData; import com.dji.sample.component.oss.model.OssConfiguration; import com.dji.sample.component.oss.service.impl.OssServiceContext; import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; +import com.dji.sample.manage.model.enums.DeviceDomainEnum; import com.dji.sample.manage.service.IDeviceDictionaryService; import com.dji.sample.media.dao.IFileMapper; import com.dji.sample.media.model.FileUploadDTO; @@ -133,7 +134,7 @@ public class FileServiceImpl implements IFileService { .mapToInt(Integer::intValue) .toArray(); Optional payloadDict = deviceDictionaryService - .getOneDictionaryInfoByTypeSubType(payloadModel[1], payloadModel[2]); + .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.PAYLOAD.getVal(), payloadModel[1], payloadModel[2]); payloadDict.ifPresent(payload -> builder.payload(payload.getDeviceName())); } return builder.build(); diff --git a/src/main/java/com/dji/sample/media/service/impl/MediaServiceImpl.java b/src/main/java/com/dji/sample/media/service/impl/MediaServiceImpl.java index f632b36..0e0063a 100644 --- a/src/main/java/com/dji/sample/media/service/impl/MediaServiceImpl.java +++ b/src/main/java/com/dji/sample/media/service/impl/MediaServiceImpl.java @@ -3,6 +3,8 @@ package com.dji.sample.media.service.impl; import com.dji.sample.common.model.ResponseResult; import com.dji.sample.component.mqtt.model.*; import com.dji.sample.component.mqtt.service.IMessageSenderService; +import com.dji.sample.manage.model.dto.DeviceDTO; +import com.dji.sample.manage.service.IDeviceService; import com.dji.sample.media.model.FileUploadCallback; import com.dji.sample.media.model.FileUploadDTO; import com.dji.sample.media.model.MediaFileDTO; @@ -39,6 +41,9 @@ public class MediaServiceImpl implements IMediaService { @Autowired private IMessageSenderService messageSenderService; + @Autowired + private IDeviceService deviceService; + @Override public Boolean fastUpload(String workspaceId, String fingerprint) { return fileService.checkExist(workspaceId, fingerprint); @@ -85,6 +90,14 @@ public class MediaServiceImpl implements IMediaService { String jobId = callback.getFile().getExt().getFlightId(); Optional jobOpt = waylineJobService.getJobByJobId(jobId); if (jobOpt.isPresent()) { + // Set the drone sn that shoots the media + Optional dockDTO = deviceService.getDeviceBySn(jobOpt.get().getDockSn()); + dockDTO.ifPresent(dock -> callback.getFile().getExt().setSn(dock.getChildDeviceSn())); + + // set path + String objectKey = callback.getFile().getObjectKey(); + callback.getFile().setPath(objectKey.substring(objectKey.indexOf("/") + 1, objectKey.lastIndexOf("/"))); + int id = fileService.saveFile(jobOpt.get().getWorkspaceId(), callback.getFile()); if (id <= 0) { data.setData(ResponseResult.error()); diff --git a/src/main/java/com/dji/sample/wayline/controller/WaylineFileController.java b/src/main/java/com/dji/sample/wayline/controller/WaylineFileController.java index 93390e4..c4934ca 100644 --- a/src/main/java/com/dji/sample/wayline/controller/WaylineFileController.java +++ b/src/main/java/com/dji/sample/wayline/controller/WaylineFileController.java @@ -9,6 +9,7 @@ import com.dji.sample.wayline.model.param.WaylineQueryParam; import com.dji.sample.wayline.service.IWaylineFileService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -16,6 +17,7 @@ import java.io.IOException; import java.net.URL; import java.sql.SQLException; import java.util.List; +import java.util.Objects; import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; @@ -158,4 +160,21 @@ public class WaylineFileController { boolean isDel = waylineFileService.deleteByWaylineId(workspaceId, waylineId); return isDel ? ResponseResult.success() : ResponseResult.error("Failed to delete wayline."); } + + /** + * Import kmz wayline files. + * @param file + * @return + */ + @PostMapping("/{workspace_id}/waylines/file/upload") + public ResponseResult importKmzFile(HttpServletRequest request, MultipartFile file) { + if (Objects.isNull(file)) { + return ResponseResult.error("No file received."); + } + CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); + String workspaceId = customClaim.getWorkspaceId(); + String creator = customClaim.getUsername(); + waylineFileService.importKmzFile(file, workspaceId, creator); + return ResponseResult.success(); + } } diff --git a/src/main/java/com/dji/sample/wayline/model/dto/KmzFileProperties.java b/src/main/java/com/dji/sample/wayline/model/dto/KmzFileProperties.java new file mode 100644 index 0000000..64e29a2 --- /dev/null +++ b/src/main/java/com/dji/sample/wayline/model/dto/KmzFileProperties.java @@ -0,0 +1,39 @@ +package com.dji.sample.wayline.model.dto; + +/** + * @author sean + * @version 1.3 + * @date 2022/10/27 + */ +public class KmzFileProperties { + + private KmzFileProperties() { + + } + + public static final String WAYLINE_FILE_SUFFIX = ".kmz"; + + public static final String FILE_DIR_FIRST = "wpmz"; + + public static final String FILE_DIR_SECOND_RES = "res"; + + public static final String FILE_DIR_SECOND_TEMPLATE = "template.kml"; + + public static final String FILE_DIR_SECOND_WAYLINES = "waylines.wpml"; + + public static final String TAG_WPML_PREFIX = "wpml:"; + + public static final String TAG_DRONE_INFO = "droneInfo"; + + public static final String TAG_DRONE_ENUM_VALUE = "droneEnumValue"; + + public static final String TAG_DRONE_SUB_ENUM_VALUE = "droneSubEnumValue"; + + public static final String TAG_PAYLOAD_INFO = "payloadInfo"; + + public static final String TAG_PAYLOAD_ENUM_VALUE = "payloadEnumValue"; + + public static final String TAG_PAYLOAD_SUB_ENUM_VALUE = "payloadSubEnumValue"; + + public static final String TAG_TEMPLATE_ID = "templateId"; +} diff --git a/src/main/java/com/dji/sample/wayline/service/IWaylineFileService.java b/src/main/java/com/dji/sample/wayline/service/IWaylineFileService.java index 83f1820..4a722c8 100644 --- a/src/main/java/com/dji/sample/wayline/service/IWaylineFileService.java +++ b/src/main/java/com/dji/sample/wayline/service/IWaylineFileService.java @@ -3,6 +3,7 @@ package com.dji.sample.wayline.service; import com.dji.sample.common.model.PaginationData; import com.dji.sample.wayline.model.dto.WaylineFileDTO; import com.dji.sample.wayline.model.param.WaylineQueryParam; +import org.springframework.web.multipart.MultipartFile; import java.net.URL; import java.sql.SQLException; @@ -71,4 +72,13 @@ public interface IWaylineFileService { * @param waylineId */ Boolean deleteByWaylineId(String workspaceId, String waylineId); + + /** + * Import kmz wayline file. + * @param file + * @param workspaceId + * @param creator + * @return + */ + void importKmzFile(MultipartFile file, String workspaceId, String creator); } diff --git a/src/main/java/com/dji/sample/wayline/service/impl/WaylineFileServiceImpl.java b/src/main/java/com/dji/sample/wayline/service/impl/WaylineFileServiceImpl.java index f12979a..7502950 100644 --- a/src/main/java/com/dji/sample/wayline/service/impl/WaylineFileServiceImpl.java +++ b/src/main/java/com/dji/sample/wayline/service/impl/WaylineFileServiceImpl.java @@ -7,24 +7,36 @@ import com.dji.sample.common.model.Pagination; import com.dji.sample.common.model.PaginationData; import com.dji.sample.component.oss.model.OssConfiguration; import com.dji.sample.component.oss.service.impl.OssServiceContext; +import com.dji.sample.manage.model.enums.DeviceDomainEnum; import com.dji.sample.wayline.dao.IWaylineFileMapper; +import com.dji.sample.wayline.model.dto.KmzFileProperties; import com.dji.sample.wayline.model.dto.WaylineFileDTO; import com.dji.sample.wayline.model.entity.WaylineFileEntity; import com.dji.sample.wayline.model.param.WaylineQueryParam; import com.dji.sample.wayline.service.IWaylineFileService; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Node; +import org.dom4j.io.SAXReader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import static com.dji.sample.wayline.model.dto.KmzFileProperties.WAYLINE_FILE_SUFFIX; /** * @author sean @@ -94,13 +106,17 @@ public class WaylineFileServiceImpl implements IWaylineFileService { file.setWaylineId(UUID.randomUUID().toString()); file.setWorkspaceId(workspaceId); - byte[] object = ossService.getObject(configuration.getBucket(), metadata.getObjectKey()); - if (object.length == 0) { - throw new RuntimeException("The file " + metadata.getObjectKey() + - " does not exist in the bucket[" + configuration.getBucket() + "]."); + if (!StringUtils.hasText(file.getSign())) { + try (InputStream object = ossService.getObject(configuration.getBucket(), metadata.getObjectKey())) { + if (object.available() == 0) { + throw new RuntimeException("The file " + metadata.getObjectKey() + + " does not exist in the bucket[" + configuration.getBucket() + "]."); + } + file.setSign(DigestUtils.md5DigestAsHex(object)); + } catch (IOException e) { + e.printStackTrace(); + } } - - file.setSign(DigestUtils.md5DigestAsHex(object)); int insertId = mapper.insert(file); return insertId > 0 ? file.getId() : insertId; } @@ -146,6 +162,78 @@ public class WaylineFileServiceImpl implements IWaylineFileService { return ossService.deleteObject(configuration.getBucket(), wayline.getObjectKey()); } + @Override + public void importKmzFile(MultipartFile file, String workspaceId, String creator) { + Optional waylineFileOpt = validKmzFile(file); + if (waylineFileOpt.isEmpty()) { + throw new RuntimeException("The file format is incorrect."); + } + + try { + WaylineFileDTO waylineFile = waylineFileOpt.get(); + waylineFile.setWaylineId(workspaceId); + waylineFile.setUsername(creator); + + ossService.putObject(configuration.getBucket(), waylineFile.getObjectKey(), file.getInputStream()); + this.saveWaylineFile(workspaceId, waylineFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private Optional validKmzFile(MultipartFile file) { + String filename = file.getOriginalFilename(); + if (Objects.nonNull(filename) && !filename.endsWith(WAYLINE_FILE_SUFFIX)) { + throw new RuntimeException("The file format is incorrect."); + } + try (ZipInputStream unzipFile = new ZipInputStream(file.getInputStream(), StandardCharsets.UTF_8)) { + + ZipEntry nextEntry = unzipFile.getNextEntry(); + while (Objects.nonNull(nextEntry)) { + boolean isWaylines = (KmzFileProperties.FILE_DIR_FIRST + File.separator + KmzFileProperties.FILE_DIR_SECOND_WAYLINES).equals(nextEntry.getName()); + if (!isWaylines) { + nextEntry = unzipFile.getNextEntry(); + continue; + } + SAXReader reader = new SAXReader(); + Document document = reader.read(unzipFile); + if (!StandardCharsets.UTF_8.name().equals(document.getXMLEncoding())) { + throw new RuntimeException("The file encoding format is incorrect."); + } + + Node droneNode = document.selectSingleNode("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_INFO); + Node payloadNode = document.selectSingleNode("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_INFO); + if (Objects.isNull(droneNode) || Objects.isNull(payloadNode)) { + throw new RuntimeException("The file format is incorrect."); + } + + String type = droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_ENUM_VALUE); + String subType = droneNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_DRONE_SUB_ENUM_VALUE); + String payloadType = payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_ENUM_VALUE); + String payloadSubType = payloadNode.valueOf(KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_PAYLOAD_SUB_ENUM_VALUE); + String templateId = document.valueOf("//" + KmzFileProperties.TAG_WPML_PREFIX + KmzFileProperties.TAG_TEMPLATE_ID); + + if (!StringUtils.hasText(type) || !StringUtils.hasText(subType) || + !StringUtils.hasText(payloadSubType) || !StringUtils.hasText(payloadType) || + !StringUtils.hasText(templateId)) { + throw new RuntimeException("The file format is incorrect."); + } + + return Optional.of(WaylineFileDTO.builder() + .droneModelKey(String.format("%s-%s-%s", DeviceDomainEnum.SUB_DEVICE.getVal(), type, subType)) + .payloadModelKeys(List.of(String.format("%s-%s-%s",DeviceDomainEnum.PAYLOAD.getVal(), payloadType, payloadSubType))) + .objectKey(configuration.getObjectDirPrefix() + File.separator + filename) + .name(filename.substring(0, filename.lastIndexOf(WAYLINE_FILE_SUFFIX))) + .sign(DigestUtils.md5DigestAsHex(file.getInputStream())) + .templateTypes(List.of(Integer.parseInt(templateId))) + .build()); + } + + } catch (IOException | DocumentException e) { + e.printStackTrace(); + } + return Optional.empty(); + } /** * Convert database entity objects into wayline data transfer object. * @param entity @@ -192,6 +280,7 @@ public class WaylineFileServiceImpl implements IWaylineFileService { .map(String::valueOf) .collect(Collectors.joining(","))) .favorited(file.getFavorited()) + .sign(file.getSign()) .build(); } diff --git a/src/main/java/com/dji/sample/wayline/service/impl/WaylineJobServiceImpl.java b/src/main/java/com/dji/sample/wayline/service/impl/WaylineJobServiceImpl.java index 76148db..d3bd695 100644 --- a/src/main/java/com/dji/sample/wayline/service/impl/WaylineJobServiceImpl.java +++ b/src/main/java/com/dji/sample/wayline/service/impl/WaylineJobServiceImpl.java @@ -107,8 +107,8 @@ public class WaylineJobServiceImpl implements IWaylineJobService { } WaylineJobDTO waylineJob = waylineJobOpt.get(); - long expire = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + waylineJob.getDockSn()); - if (expire < 0) { + boolean isOnline = deviceService.checkDeviceOnline(waylineJob.getDockSn()); + if (!isOnline) { throw new RuntimeException("Dock is offline."); } @@ -142,20 +142,16 @@ public class WaylineJobServiceImpl implements IWaylineJobService { .method(ServicesMethodEnum.FLIGHT_TASK_PREPARE.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("Prepare task ====> Error code: {}", serviceReplyOpt.get().getResult()); + ServiceReply serviceReply = messageSender.publishWithReply(topic, response); + if (ResponseResult.CODE_SUCCESS == serviceReply.getResult()) { + log.info("Prepare task ====> Error code: {}", serviceReply.getResult()); this.updateJob(WaylineJobDTO.builder() .workspaceId(waylineJob.getWorkspaceId()) .jobId(waylineJob.getJobId()) .status(WaylineJobStatusEnum.FAILED.getVal()) .endTime(LocalDateTime.now()) - .code(serviceReplyOpt.get().getResult()).build()); - return ResponseResult.error("Prepare task ====> Error code: " + serviceReplyOpt.get().getResult()); + .code(serviceReply.getResult()).build()); + return ResponseResult.error("Prepare task ====> Error code: " + serviceReply.getResult()); } // Issue an immediate task execution command. @@ -184,8 +180,8 @@ public class WaylineJobServiceImpl implements IWaylineJobService { throw new IllegalArgumentException("Job doesn't exist."); } - long expire = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + waylineJob.get().getDockSn()); - if (expire < 0) { + boolean isOnline = deviceService.checkDeviceOnline(waylineJob.get().getDockSn()); + if (!isOnline) { throw new RuntimeException("Dock is offline."); } @@ -202,18 +198,14 @@ public class WaylineJobServiceImpl implements IWaylineJobService { .method(ServicesMethodEnum.FLIGHT_TASK_EXECUTE.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("Execute job ====> Error code: {}", serviceReplyOpt.get().getResult()); + ServiceReply serviceReply = messageSender.publishWithReply(topic, response); + if (serviceReply.getResult() != 0) { + log.info("Execute job ====> Error code: {}", serviceReply.getResult()); this.updateJob(WaylineJobDTO.builder() .jobId(jobId) .status(WaylineJobStatusEnum.FAILED.getVal()) .endTime(LocalDateTime.now()) - .code(serviceReplyOpt.get().getResult()).build()); + .code(serviceReply.getResult()).build()); return false; } @@ -258,8 +250,8 @@ public class WaylineJobServiceImpl implements IWaylineJobService { } private void publishCancelTask(String workspaceId, String dockSn, List jobIds) { - long expire = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + dockSn); - if (expire < 0) { + 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; @@ -272,13 +264,9 @@ public class WaylineJobServiceImpl implements IWaylineJobService { .method(ServicesMethodEnum.FLIGHT_TASK_CANCEL.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("Cancel job ====> Error code: {}", serviceReplyOpt.get().getResult()); + ServiceReply serviceReply = messageSender.publishWithReply(topic, response); + if (serviceReply.getResult() != 0) { + log.info("Cancel job ====> Error code: {}", serviceReply.getResult()); throw new RuntimeException("Failed to cancel the wayline job of " + dockSn); }