From a7aaeabc7873a0eafb4a7ecad7f65b018b7a9bc9 Mon Sep 17 00:00:00 2001 From: "sean.zhou" Date: Fri, 24 Feb 2023 19:31:23 +0800 Subject: [PATCH] What's new? 1. Add license for dock. 2. Modify the logic corresponding to the firmware file and device type. 3. Add multiple mqtt clients options. 4. Modify the structure of the interface for obtaining the device list. 5. Fixed some issues. --- sql/cloud_sample.sql | 30 ++- .../sample/common/error/CommonErrorEnum.java | 6 +- .../sample/common/error/StorageErrorEnum.java | 38 ---- .../com/dji/sample/common/util/JwtUtil.java | 57 +++++- .../component/GlobalScheduleService.java | 4 +- .../mqtt/config/MqttConfiguration.java | 71 ++++--- .../mqtt/config/MqttInboundConfiguration.java | 9 +- .../config/MqttOutboundConfiguration.java | 2 +- .../component/mqtt/model/MapKeyConst.java | 2 + .../mqtt/model/MqttClientOptions.java | 31 ++++ .../mqtt/model/MqttProtocolEnum.java | 30 +++ .../component/mqtt/model/MqttUseEnum.java | 19 ++ .../impl/MessageSenderServiceImpl.java | 3 +- .../sample/component/redis/RedisConst.java | 16 +- .../sample/component/redis/RedisOpsUtils.java | 9 + .../service/impl/ControlServiceImpl.java | 3 +- .../manage/controller/DeviceController.java | 2 +- .../controller/DeviceFirmwareController.java | 16 +- .../manage/dao/IDeviceFirmwareMapper.java | 27 +++ .../manage/dao/IFirmwareModelMapper.java | 12 ++ .../model/common/AppLicenseProperties.java | 32 ++++ .../sample/manage/model/dto/DeviceDTO.java | 4 +- .../manage/model/dto/DeviceFirmwareDTO.java | 3 +- .../manage/model/dto/FirmwareModelDTO.java | 24 +++ .../model/dto/LogsUploadCredentialsDTO.java | 5 +- ...tpServerDTO.java => ProductConfigDTO.java} | 8 +- .../manage/model/dto/TopologyDeviceDTO.java | 2 +- .../model/entity/DeviceFirmwareEntity.java | 2 +- .../model/entity/FirmwareModelEntity.java | 37 ++++ .../manage/model/enums/DeviceDomainEnum.java | 68 +------ .../param/DeviceFirmwareUploadParam.java | 3 +- .../receiver/DistanceLimitStatusReceiver.java | 2 +- .../service/IDeviceFirmwareService.java | 11 +- .../sample/manage/service/IDeviceService.java | 2 +- .../manage/service/IFirmwareModelService.java | 18 ++ .../service/impl/AbstractTSAService.java | 4 - .../impl/ConfigProductServiceImpl.java | 5 +- .../impl/DeviceFirmwareServiceImpl.java | 85 +++++---- .../service/impl/DeviceOSDServiceImpl.java | 5 +- .../service/impl/DeviceServiceImpl.java | 135 +++++++------- .../service/impl/DockOSDServiceImpl.java | 2 +- .../impl/FirmwareModelServiceImpl.java | 44 +++++ .../service/impl/GatewayOSDServiceImpl.java | 2 +- .../service/impl/LiveStreamServiceImpl.java | 11 +- .../manage/service/impl/UserServiceImpl.java | 16 +- .../media/service/impl/MediaServiceImpl.java | 45 +++-- .../controller/WaylineJobController.java | 4 +- .../wayline/model/dto/WaylineJobDTO.java | 6 + ...eateDTO.java => WaylineTaskCreateDTO.java} | 5 +- ...skFileDTO.java => WaylineTaskFileDTO.java} | 2 +- ...Progress.java => WaylineTaskProgress.java} | 2 +- ...ssExt.java => WaylineTaskProgressExt.java} | 6 +- ....java => WaylineTaskProgressReceiver.java} | 6 +- .../model/entity/WaylineJobEntity.java | 8 + .../model/enums/WaylineJobStatusEnum.java | 4 +- .../wayline/service/IWaylineJobService.java | 39 +++- .../service/impl/FlightTaskServiceImpl.java | 52 +++--- .../service/impl/WaylineFileServiceImpl.java | 2 +- .../service/impl/WaylineJobServiceImpl.java | 175 ++++++++++++------ src/main/resources/application.yml | 32 +++- 60 files changed, 882 insertions(+), 423 deletions(-) delete mode 100644 src/main/java/com/dji/sample/common/error/StorageErrorEnum.java create mode 100644 src/main/java/com/dji/sample/component/mqtt/model/MqttClientOptions.java create mode 100644 src/main/java/com/dji/sample/component/mqtt/model/MqttProtocolEnum.java create mode 100644 src/main/java/com/dji/sample/component/mqtt/model/MqttUseEnum.java create mode 100644 src/main/java/com/dji/sample/manage/dao/IFirmwareModelMapper.java create mode 100644 src/main/java/com/dji/sample/manage/model/common/AppLicenseProperties.java create mode 100644 src/main/java/com/dji/sample/manage/model/dto/FirmwareModelDTO.java rename src/main/java/com/dji/sample/manage/model/dto/{NtpServerDTO.java => ProductConfigDTO.java} (69%) create mode 100644 src/main/java/com/dji/sample/manage/model/entity/FirmwareModelEntity.java create mode 100644 src/main/java/com/dji/sample/manage/service/IFirmwareModelService.java create mode 100644 src/main/java/com/dji/sample/manage/service/impl/FirmwareModelServiceImpl.java rename src/main/java/com/dji/sample/wayline/model/dto/{FlightTaskCreateDTO.java => WaylineTaskCreateDTO.java} (86%) rename src/main/java/com/dji/sample/wayline/model/dto/{FlightTaskFileDTO.java => WaylineTaskFileDTO.java} (90%) rename src/main/java/com/dji/sample/wayline/model/dto/{FLightTaskProgress.java => WaylineTaskProgress.java} (84%) rename src/main/java/com/dji/sample/wayline/model/dto/{FlightTaskProgressExt.java => WaylineTaskProgressExt.java} (67%) rename src/main/java/com/dji/sample/wayline/model/dto/{FlightTaskProgressReceiver.java => WaylineTaskProgressReceiver.java} (56%) diff --git a/sql/cloud_sample.sql b/sql/cloud_sample.sql index b4fda63..3ff45db 100644 --- a/sql/cloud_sample.sql +++ b/sql/cloud_sample.sql @@ -46,7 +46,7 @@ CREATE TABLE `logs_file_index` ( `file_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The file_id in the logs_file table.', `start_time` bigint NOT NULL COMMENT 'The file start time reported by the dock.', `end_time` bigint NOT NULL COMMENT 'The file end time reported by the dock.', - `size` int NOT NULL COMMENT 'The file size reported by the dock.', + `size` bigint NOT NULL COMMENT 'The file size reported by the dock.', `device_sn` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The sn of the device.', `domain` int NOT NULL COMMENT 'This parameter corresponds to the domain in the device dictionary table.', `create_time` bigint NOT NULL, @@ -132,7 +132,9 @@ VALUES (20,0,77,1,'Mavic 3T',NULL), (21,1,66,0,'Mavic 3E Camera',NULL), (22,1,67,0,'Mavic 3T Camera',NULL), - (23,2,144,0,'DJI RC Pro','Remote control for Mavic 3E/T'); + (23,2,144,0,'DJI RC Pro','Remote control for Mavic 3E/T and Mavic 3M'), + (24,0,77,2,'Mavic 3M',NULL), + (25,1,68,0,'Mavic 3M Camera',NULL); /*!40000 ALTER TABLE `manage_device_dictionary` ENABLE KEYS */; UNLOCK TABLES; @@ -151,7 +153,6 @@ CREATE TABLE `manage_device_firmware` ( `object_key` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'The object key of the firmware package in the bucket.', `file_size` int NOT NULL COMMENT 'The size of the firmware package.', `file_md5` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The md5 of the firmware package.', - `device_name` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'model of the device. This parameter corresponds to the device name in the device dictionary table.', `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `release_note` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The release note of the firmware package.', `release_date` bigint NOT NULL COMMENT 'The release date of the firmware package.', @@ -233,6 +234,22 @@ CREATE TABLE `manage_device_payload` ( +# manage_firmware_model +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `manage_firmware_model`; + +CREATE TABLE `manage_firmware_model` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `firmware_id` varchar(64) NOT NULL, + `device_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'model of the device. This parameter corresponds to the device name in the device dictionary table.', + `create_time` bigint NOT NULL, + `update_time` bigint NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + + + # manage_user # ------------------------------------------------------------ @@ -431,9 +448,11 @@ CREATE TABLE `wayline_job` ( `workspace_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'Which workspace the current job belongs to.', `task_type` int NOT NULL, `wayline_type` int NOT NULL COMMENT 'The template type of the wayline.', - `execute_time` bigint NOT NULL, + `execute_time` bigint DEFAULT NULL COMMENT 'actual begin time', + `completed_time` bigint DEFAULT NULL COMMENT 'actual end time', `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The name of the creator.', - `end_time` bigint DEFAULT NULL COMMENT 'end time of the job.', + `begin_time` bigint NOT NULL COMMENT 'planned begin time', + `end_time` bigint NOT NULL COMMENT 'planned end time', `error_code` int DEFAULT NULL, `status` int NOT NULL COMMENT '1: pending; 2: in progress; 3: success; 4: cancel; 5: failed', `rth_altitude` int NOT NULL COMMENT 'return to home altitude. min: 20m; max: 500m', @@ -441,6 +460,7 @@ CREATE TABLE `wayline_job` ( `media_count` int NOT NULL DEFAULT '0', `create_time` bigint NOT NULL, `update_time` bigint NOT NULL, + `parent_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `job_id_UNIQUE` (`job_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='Wayline mission information of the dock.'; diff --git a/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java b/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java index 290cc42..1ab3b32 100644 --- a/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java +++ b/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java @@ -9,6 +9,10 @@ public enum CommonErrorEnum implements IErrorInfo { ILLEGAL_ARGUMENT(200001, "illegal argument"), + REDIS_DATA_NOT_FOUND(201404, "Redis data does not exist."), + + DEVICE_OFFLINE(212015, "Device is offline."), + GET_ORGANIZATION_FAILED(210230, "Failed to get organization."), DEVICE_BINDING_FAILED(210231, "Failed to bind device."), @@ -21,7 +25,7 @@ public enum CommonErrorEnum implements IErrorInfo { SECRET_INVALID(600100, "secret invalid"), - NO_TOKEN(600101, "accss_token is null"), + NO_TOKEN(600101, "token is null"), TOKEN_EXPIRED(600102, "token is expired"), diff --git a/src/main/java/com/dji/sample/common/error/StorageErrorEnum.java b/src/main/java/com/dji/sample/common/error/StorageErrorEnum.java deleted file mode 100644 index 16b5d2f..0000000 --- a/src/main/java/com/dji/sample/common/error/StorageErrorEnum.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.dji.sample.common.error; - -/** - * @author sean - * @version 1.0 - * @date 2022/5/25 - */ -public enum StorageErrorEnum implements IErrorInfo { - - GENERATE_CREDENTIALS_ERROR(217001, "Failed to generate temporary credentials."), - - NO_BUCKET(217002, "The bucket does not exist."), - - ILLEGAL_PATH_FORMAT(217006, "Illegal path format."), - - FILE_CREATION_FAILED(217007, "File creation failed."), - - DIR_CREATION_FAILED(217008, "Directory creation failed"); - - private String msg; - - private int code; - - StorageErrorEnum(int code, String msg) { - this.msg = msg; - this.code = code; - } - - @Override - public String getErrorMsg() { - return msg; - } - - @Override - public Integer getErrorCode() { - return code; - } -} 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 918f1d7..c04168e 100644 --- a/src/main/java/com/dji/sample/common/util/JwtUtil.java +++ b/src/main/java/com/dji/sample/common/util/JwtUtil.java @@ -9,10 +9,9 @@ import com.dji.sample.common.model.CustomClaim; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; -import java.util.Date; -import java.util.Map; -import java.util.Optional; +import java.util.*; @Slf4j @Component @@ -26,7 +25,7 @@ public class JwtUtil { private static String secret; - private static Algorithm algorithm; + public static Algorithm algorithm; @Value("${jwt.issuer: DJI}") private void setIssuer(String issuer) { @@ -62,15 +61,55 @@ public class JwtUtil { * @param claims custom information * @return token */ - public static String createToken(Map claims) { + public static String createToken(Map claims) { + return JwtUtil.createToken(claims, age, algorithm, subject, issuer); + } + + /** + * + * @param claims + * @param age unit: s + * @param algorithm + * @param subject + * @param issuer + * @return + */ + public static String createToken(Map claims, Long age, Algorithm algorithm, String subject, String issuer) { + if (Objects.isNull(algorithm)) { + throw new IllegalArgumentException(); + } + Date now = new Date(); JWTCreator.Builder builder = JWT.create(); // Add custom information to the token's payload segment. - claims.forEach(builder::withClaim); - String token = builder.withIssuer(issuer) - .withSubject(subject) + claims.forEach((k, v) -> { + if (Objects.nonNull(v.getClass().getClassLoader())) { + log.error("claim can't be set to a custom object."); + return; + } + if (v instanceof Map) { + builder.withClaim(k, (Map) v); + } else if (v instanceof List) { + builder.withClaim(k, (List) v); + } else { + builder.withClaim(k, String.valueOf(v)); + } + }); + + if (StringUtils.hasText(subject)) { + builder.withSubject(subject); + } + + if (StringUtils.hasText(issuer)) { + builder.withIssuer(issuer); + } + + if (Objects.nonNull(age)) { + builder.withExpiresAt(new Date(now.getTime() + age * 1000)); + } + + String token = builder .withIssuedAt(now) - .withExpiresAt(new Date(now.getTime() + age)) .withNotBefore(now) .sign(algorithm); log.debug("token created. " + token); diff --git a/src/main/java/com/dji/sample/component/GlobalScheduleService.java b/src/main/java/com/dji/sample/component/GlobalScheduleService.java index 81229ab..e092ad4 100644 --- a/src/main/java/com/dji/sample/component/GlobalScheduleService.java +++ b/src/main/java/com/dji/sample/component/GlobalScheduleService.java @@ -44,11 +44,13 @@ public class GlobalScheduleService { long expire = RedisOpsUtils.getExpire(key); if (expire <= 30) { DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(key); - if (device.getDomain().equals(DeviceDomainEnum.SUB_DEVICE.getDesc())) { + if (DeviceDomainEnum.SUB_DEVICE.getVal() == device.getDomain()) { deviceService.subDeviceOffline(key.substring(start)); } else { deviceService.unsubscribeTopicOffline(key.substring(start)); deviceService.pushDeviceOfflineTopo(device.getWorkspaceId(), device.getDeviceSn()); + RedisOpsUtils.hashDel(RedisConst.LIVE_CAPACITY, new String[]{key}); + RedisOpsUtils.del(RedisConst.HMS_PREFIX + key); } RedisOpsUtils.del(key); } diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java index 750ba58..69c6398 100644 --- a/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java +++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java @@ -1,5 +1,10 @@ package com.dji.sample.component.mqtt.config; +import com.auth0.jwt.algorithms.Algorithm; +import com.dji.sample.common.util.JwtUtil; +import com.dji.sample.component.mqtt.model.MqttClientOptions; +import com.dji.sample.component.mqtt.model.MqttProtocolEnum; +import com.dji.sample.component.mqtt.model.MqttUseEnum; import lombok.Data; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -7,6 +12,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory; import org.springframework.integration.mqtt.core.MqttPahoClientFactory; +import org.springframework.util.StringUtils; + +import java.util.Map; /** * @@ -16,39 +24,60 @@ import org.springframework.integration.mqtt.core.MqttPahoClientFactory; */ @Configuration @Data -@ConfigurationProperties(prefix = "mqtt") +@ConfigurationProperties public class MqttConfiguration { - private String protocol; - - private String host; - - private Integer port; + private static Map mqtt; - private String username; + public void setMqtt(Map mqtt) { + MqttConfiguration.mqtt = mqtt; + } - private String password; + /** + * Get the configuration options of the basic link of the mqtt client. + * @return + */ + static MqttClientOptions getBasicClientOptions() { + if (!mqtt.containsKey(MqttUseEnum.BASIC)) { + throw new Error("Please configure the basic mqtt connection parameters first, otherwise application cannot be started."); + } + return mqtt.get(MqttUseEnum.BASIC); + } - private String clientId; + /** + * Get the mqtt address of the basic link. + * @return + */ + public static String getBasicMqttAddress() { + return getMqttAddress(getBasicClientOptions()); + } /** - * The topic to subscribe to immediately when client connects. + * Splice the mqtt address according to the parameters of different clients. + * @param options + * @return */ - private String inboundTopic; + private static String getMqttAddress(MqttClientOptions options) { + StringBuilder addr = new StringBuilder() + .append(options.getProtocol().getProtocolAddr()) + .append(options.getHost().trim()) + .append(":") + .append(options.getPort()); + if ((options.getProtocol() == MqttProtocolEnum.WS || options.getProtocol() == MqttProtocolEnum.WSS) + && StringUtils.hasText(options.getPath())) { + addr.append(options.getPath()); + } + return addr.toString(); + } @Bean public MqttConnectOptions mqttConnectOptions() { + MqttClientOptions customizeOptions = getBasicClientOptions(); MqttConnectOptions mqttConnectOptions = new MqttConnectOptions(); - mqttConnectOptions.setServerURIs(new String[]{ - new StringBuilder() - .append(protocol.trim()) - .append("://") - .append(host.trim()) - .append(":") - .append(port) - .toString()}); - mqttConnectOptions.setUserName(username); - mqttConnectOptions.setPassword(password.toCharArray()); + mqttConnectOptions.setServerURIs(new String[]{ getBasicMqttAddress() }); + mqttConnectOptions.setUserName(customizeOptions.getUsername()); + mqttConnectOptions.setPassword(StringUtils.hasText(customizeOptions.getPassword()) ? + customizeOptions.getPassword().toCharArray() : new char[0]); mqttConnectOptions.setAutomaticReconnect(true); mqttConnectOptions.setKeepAliveInterval(10); return mqttConnectOptions; diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java index 3964aaf..40dada5 100644 --- a/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java +++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java @@ -1,6 +1,7 @@ package com.dji.sample.component.mqtt.config; import com.dji.sample.component.mqtt.model.ChannelName; +import com.dji.sample.component.mqtt.model.MqttClientOptions; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -28,9 +29,6 @@ import javax.annotation.Resource; @IntegrationComponentScan public class MqttInboundConfiguration { - @Autowired - private MqttConfiguration mqttConfiguration; - @Autowired private MqttPahoClientFactory mqttClientFactory; @@ -43,9 +41,10 @@ public class MqttInboundConfiguration { */ @Bean(name = "adapter") public MessageProducerSupport mqttInbound() { + MqttClientOptions options = MqttConfiguration.getBasicClientOptions(); MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter( - mqttConfiguration.getClientId() + "_consumer_" + System.currentTimeMillis(), - mqttClientFactory, mqttConfiguration.getInboundTopic().split(",")); + options.getClientId() + "_consumer_" + System.currentTimeMillis(), + mqttClientFactory, options.getInboundTopic().split(",")); DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter(); // use byte types uniformly converter.setPayloadAsBytes(true); diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttOutboundConfiguration.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttOutboundConfiguration.java index 69b919b..a376093 100644 --- a/src/main/java/com/dji/sample/component/mqtt/config/MqttOutboundConfiguration.java +++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttOutboundConfiguration.java @@ -33,7 +33,7 @@ public class MqttOutboundConfiguration { @ServiceActivator(inputChannel = ChannelName.OUTBOUND) public MessageHandler mqttOutbound() { MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler( - mqttConfiguration.getClientId() + "_producer_" + System.currentTimeMillis(), + MqttConfiguration.getBasicClientOptions().getClientId() + "_producer_" + System.currentTimeMillis(), mqttClientFactory); DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter(); // use byte types uniformly diff --git a/src/main/java/com/dji/sample/component/mqtt/model/MapKeyConst.java b/src/main/java/com/dji/sample/component/mqtt/model/MapKeyConst.java index 242fd3d..0e4f498 100644 --- a/src/main/java/com/dji/sample/component/mqtt/model/MapKeyConst.java +++ b/src/main/java/com/dji/sample/component/mqtt/model/MapKeyConst.java @@ -33,4 +33,6 @@ public final class MapKeyConst { public static final String FLIGHT_IDS = "flight_ids"; + public static final String ACL = "acl"; + } diff --git a/src/main/java/com/dji/sample/component/mqtt/model/MqttClientOptions.java b/src/main/java/com/dji/sample/component/mqtt/model/MqttClientOptions.java new file mode 100644 index 0000000..d1168bd --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/model/MqttClientOptions.java @@ -0,0 +1,31 @@ +package com.dji.sample.component.mqtt.model; + +import lombok.Data; + +/** + * @author sean + * @version 1.3 + * @date 2023/1/18 + */ +@Data +public class MqttClientOptions { + + private MqttProtocolEnum protocol; + + private String host; + + private Integer port; + + private String username; + + private String password; + + private String clientId; + + private String path; + + /** + * The topic to subscribe to immediately when client connects. Only required for basic link. + */ + private String inboundTopic; +} diff --git a/src/main/java/com/dji/sample/component/mqtt/model/MqttProtocolEnum.java b/src/main/java/com/dji/sample/component/mqtt/model/MqttProtocolEnum.java new file mode 100644 index 0000000..ac54b1f --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/model/MqttProtocolEnum.java @@ -0,0 +1,30 @@ +package com.dji.sample.component.mqtt.model; + +import lombok.Getter; + +/** + * @author sean + * @version 1.3 + * @date 2023/1/18 + */ +@Getter +public enum MqttProtocolEnum { + + MQTT("tcp"), + + MQTTS("tcp"), + + WS("ws"), + + WSS("wss"); + + String protocol; + + MqttProtocolEnum(String protocol) { + this.protocol = protocol; + } + + public String getProtocolAddr() { + return protocol + "://"; + } +} diff --git a/src/main/java/com/dji/sample/component/mqtt/model/MqttUseEnum.java b/src/main/java/com/dji/sample/component/mqtt/model/MqttUseEnum.java new file mode 100644 index 0000000..3f56704 --- /dev/null +++ b/src/main/java/com/dji/sample/component/mqtt/model/MqttUseEnum.java @@ -0,0 +1,19 @@ +package com.dji.sample.component.mqtt.model; + +/** + * @author sean + * @version 1.3 + * @date 2023/1/18 + */ +public enum MqttUseEnum { + + /** + * The broker is used for basic link. + */ + BASIC, + + /** + * This broker is used for the drc link. + */ + DRC +} 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 89e5093..2a76cf5 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 @@ -31,7 +31,7 @@ public class MessageSenderServiceImpl implements IMessageSenderService { public void publish(String topic, CommonTopicResponse response) { try { - + log.info("send topic: {}, payload: {}", topic, response.toString()); messageGateway.publish(topic, mapper.writeValueAsBytes(response)); } catch (JsonProcessingException e) { log.info("Failed to publish the message. {}", response.toString()); @@ -53,6 +53,7 @@ public class MessageSenderServiceImpl implements IMessageSenderService { } public T publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime) { + log.info("send topic: {}, payload: {}", topic, response.toString()); AtomicInteger time = new AtomicInteger(0); // Retry three times while (time.getAndIncrement() <= retryTime) { 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 39c686b..7ae29db 100644 --- a/src/main/java/com/dji/sample/component/redis/RedisConst.java +++ b/src/main/java/com/dji/sample/component/redis/RedisConst.java @@ -9,6 +9,8 @@ import com.dji.sample.manage.model.enums.DeviceDomainEnum; */ public final class RedisConst { + public static final int WAYLINE_JOB_BLOCK_TIME = 600; + private RedisConst() { } @@ -35,11 +37,23 @@ 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 WAYLINE_JOB_TIMED_EXECUTE = "wayline_job_timed_execute"; + + public static final String WAYLINE_JOB_BLOCK_PREFIX = "wayline_job_block" + DELIMITER; + + public static final String WAYLINE_JOB_RUNNING_PREFIX = "wayline_job_running" + DELIMITER; + + public static final String WAYLINE_JOB_PAUSED_PREFIX = "wayline_job_paused" + DELIMITER; public static final String OSD_PREFIX = "osd" + DELIMITER; public static final String MEDIA_FILE_PREFIX = "media_file" + DELIMITER; public static final String MEDIA_HIGHEST_PRIORITY_PREFIX = "media_highest_priority" + DELIMITER; + + public static final String LIVE_CAPACITY = "live_capacity"; + + public static final String MQTT_ACL_PREFIX = "mqtt_acl" + DELIMITER; + + public static final String FILE_UPLOADING_PREFIX = "file_uploading" + DELIMITER; } diff --git a/src/main/java/com/dji/sample/component/redis/RedisOpsUtils.java b/src/main/java/com/dji/sample/component/redis/RedisOpsUtils.java index f71dd1c..a3e83b3 100644 --- a/src/main/java/com/dji/sample/component/redis/RedisOpsUtils.java +++ b/src/main/java/com/dji/sample/component/redis/RedisOpsUtils.java @@ -251,4 +251,13 @@ public class RedisOpsUtils { return redisTemplate.opsForZSet().score(key, value); } + /** + * ZINCRBY + * @param key + * @param value + * @param delta + */ + public static Double zIncrement(String key, Object value, double delta) { + return redisTemplate.opsForZSet().incrementScore(key, value, delta); + } } 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 43e7fc1..beb1e29 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 @@ -91,7 +91,8 @@ public class ControlServiceImpl implements IControlService { serviceReplyOpt, new TypeReference>() {}); if (ResponseResult.CODE_SUCCESS != serviceReply.getResult()) { return ResponseResult.error(serviceReply.getResult(), - Objects.nonNull(serviceReply.getOutput()) ? serviceReply.getOutput().getStatus() : "error: " + serviceIdentifier); + Objects.nonNull(serviceReply.getOutput()) ? serviceReply.getOutput().getStatus() + : "error: " + serviceIdentifier + serviceReply.getResult()); } if (controlMethodEnum.getProgress()) { RedisOpsUtils.setWithExpire(serviceIdentifier + RedisConst.DELIMITER + bid, sn, 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 602e8c9..9fcc72d 100644 --- a/src/main/java/com/dji/sample/manage/controller/DeviceController.java +++ b/src/main/java/com/dji/sample/manage/controller/DeviceController.java @@ -120,7 +120,7 @@ public class DeviceController { */ @GetMapping("/{workspace_id}/devices/bound") public ResponseResult> getBoundDevicesWithDomain( - @PathVariable("workspace_id") String workspaceId, String domain, + @PathVariable("workspace_id") String workspaceId, Integer domain, @RequestParam(defaultValue = "1") Long page, @RequestParam(value = "page_size", defaultValue = "50") Long pageSize) { PaginationData devices = deviceService.getBoundDevicesWithDomain(workspaceId, page, pageSize, domain); diff --git a/src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java b/src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java index 13b2ff3..45a2770 100644 --- a/src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java +++ b/src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java @@ -18,9 +18,9 @@ import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import javax.validation.constraints.NotNull; -import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; @@ -44,11 +44,13 @@ public class DeviceFirmwareController { */ @GetMapping("/firmware-release-notes/latest") public ResponseResult> getLatestFirmwareNote(@RequestParam("device_name") List deviceNames) { - List releaseNotes = new ArrayList<>(); - deviceNames.forEach(deviceName -> { - Optional latestFirmware = service.getLatestFirmwareReleaseNote(deviceName); - latestFirmware.ifPresent(releaseNotes::add); - }); + + List releaseNotes = deviceNames.stream() + .map(deviceName -> service.getLatestFirmwareReleaseNote(deviceName)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + return ResponseResult.success(releaseNotes); } @@ -98,7 +100,7 @@ public class DeviceFirmwareController { * @return */ @PutMapping("/{workspace_id}/firmwares/{firmware_id}") - public ResponseResult importFirmwareFile(@PathVariable("workspace_id") String workspaceId, + public ResponseResult changeFirmwareStatus(@PathVariable("workspace_id") String workspaceId, @PathVariable("firmware_id") String firmwareId, @Valid @RequestBody DeviceFirmwareUpdateParam param) { diff --git a/src/main/java/com/dji/sample/manage/dao/IDeviceFirmwareMapper.java b/src/main/java/com/dji/sample/manage/dao/IDeviceFirmwareMapper.java index 55653f5..bc4c4a2 100644 --- a/src/main/java/com/dji/sample/manage/dao/IDeviceFirmwareMapper.java +++ b/src/main/java/com/dji/sample/manage/dao/IDeviceFirmwareMapper.java @@ -1,7 +1,12 @@ package com.dji.sample.manage.dao; +import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.dji.sample.manage.model.entity.DeviceFirmwareEntity; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; /** * @author sean @@ -9,4 +14,26 @@ import com.dji.sample.manage.model.entity.DeviceFirmwareEntity; * @date 2022/8/16 */ public interface IDeviceFirmwareMapper extends BaseMapper { + String sql = "") + Page selectPage(Page page, @Param(Constants.WRAPPER)Wrapper wrapper, @Param("device_name") String deviceName); + + @Select(sql + " limit 1 ") + DeviceFirmwareEntity selectOne(@Param(Constants.WRAPPER)Wrapper wrapper, @Param("device_name") String deviceName); } diff --git a/src/main/java/com/dji/sample/manage/dao/IFirmwareModelMapper.java b/src/main/java/com/dji/sample/manage/dao/IFirmwareModelMapper.java new file mode 100644 index 0000000..9cb8ee3 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/dao/IFirmwareModelMapper.java @@ -0,0 +1,12 @@ +package com.dji.sample.manage.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.dji.sample.manage.model.entity.FirmwareModelEntity; + +/** + * @author sean + * @version 1.3 + * @date 2022/12/21 + */ +public interface IFirmwareModelMapper extends BaseMapper { +} diff --git a/src/main/java/com/dji/sample/manage/model/common/AppLicenseProperties.java b/src/main/java/com/dji/sample/manage/model/common/AppLicenseProperties.java new file mode 100644 index 0000000..cc15023 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/common/AppLicenseProperties.java @@ -0,0 +1,32 @@ +package com.dji.sample.manage.model.common; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author sean + * @version 1.3.1 + * @date 2023/1/5 + */ +@Component +@ConfigurationProperties("cloud-api.app") +public class AppLicenseProperties { + + public static String id; + + public static String key; + + public static String license; + + public void setId(String id) { + AppLicenseProperties.id = id; + } + + public void setKey(String key) { + AppLicenseProperties.key = key; + } + + public void setLicense(String license) { + AppLicenseProperties.license = license; + } +} diff --git a/src/main/java/com/dji/sample/manage/model/dto/DeviceDTO.java b/src/main/java/com/dji/sample/manage/model/dto/DeviceDTO.java index ce23314..68466d7 100644 --- a/src/main/java/com/dji/sample/manage/model/dto/DeviceDTO.java +++ b/src/main/java/com/dji/sample/manage/model/dto/DeviceDTO.java @@ -31,14 +31,12 @@ public class DeviceDTO { private String childDeviceSn; - private String domain; + private Integer domain; private Integer type; private Integer subType; - private List gatewaysList; - private List payloadsList; private IconUrlDTO iconUrl; diff --git a/src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java b/src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java index 3d48f78..b59f289 100644 --- a/src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java +++ b/src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java @@ -6,6 +6,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDate; +import java.util.List; /** * @author sean @@ -30,7 +31,7 @@ public class DeviceFirmwareDTO { private String fileMd5; - private String deviceName; + private List deviceName; private String releaseNote; diff --git a/src/main/java/com/dji/sample/manage/model/dto/FirmwareModelDTO.java b/src/main/java/com/dji/sample/manage/model/dto/FirmwareModelDTO.java new file mode 100644 index 0000000..d9f10f5 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/dto/FirmwareModelDTO.java @@ -0,0 +1,24 @@ +package com.dji.sample.manage.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author sean + * @version 1.3 + * @date 2022/12/21 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class FirmwareModelDTO { + + private String firmwareId; + + private List deviceNames; +} diff --git a/src/main/java/com/dji/sample/manage/model/dto/LogsUploadCredentialsDTO.java b/src/main/java/com/dji/sample/manage/model/dto/LogsUploadCredentialsDTO.java index f156c3a..970fc12 100644 --- a/src/main/java/com/dji/sample/manage/model/dto/LogsUploadCredentialsDTO.java +++ b/src/main/java/com/dji/sample/manage/model/dto/LogsUploadCredentialsDTO.java @@ -35,13 +35,16 @@ public class LogsUploadCredentialsDTO { private LogsFileUploadList params; + private String region; + public LogsUploadCredentialsDTO(StsCredentialsDTO sts) { this.bucket = sts.getBucket(); - Long expire = sts.getCredentials().getExpire(); + long expire = sts.getCredentials().getExpire(); sts.getCredentials().setExpire(System.currentTimeMillis() + (expire - 60) * 1000); this.credentials = sts.getCredentials(); this.endpoint = sts.getEndpoint(); this.objectKeyPrefix = sts.getObjectKeyPrefix(); this.provider = sts.getProvider(); + this.region = sts.getRegion(); } } diff --git a/src/main/java/com/dji/sample/manage/model/dto/NtpServerDTO.java b/src/main/java/com/dji/sample/manage/model/dto/ProductConfigDTO.java similarity index 69% rename from src/main/java/com/dji/sample/manage/model/dto/NtpServerDTO.java rename to src/main/java/com/dji/sample/manage/model/dto/ProductConfigDTO.java index 27b05a5..577ba54 100644 --- a/src/main/java/com/dji/sample/manage/model/dto/NtpServerDTO.java +++ b/src/main/java/com/dji/sample/manage/model/dto/ProductConfigDTO.java @@ -12,7 +12,13 @@ import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor -public class NtpServerDTO { +public class ProductConfigDTO { private String ntpServerHost; + + private String appId; + + private String appKey; + + private String appLicense; } diff --git a/src/main/java/com/dji/sample/manage/model/dto/TopologyDeviceDTO.java b/src/main/java/com/dji/sample/manage/model/dto/TopologyDeviceDTO.java index ced5277..ea709cc 100644 --- a/src/main/java/com/dji/sample/manage/model/dto/TopologyDeviceDTO.java +++ b/src/main/java/com/dji/sample/manage/model/dto/TopologyDeviceDTO.java @@ -38,5 +38,5 @@ public class TopologyDeviceDTO { private String gatewaySn; - private String domain; + private Integer domain; } diff --git a/src/main/java/com/dji/sample/manage/model/entity/DeviceFirmwareEntity.java b/src/main/java/com/dji/sample/manage/model/entity/DeviceFirmwareEntity.java index 369f4c6..ced8e39 100644 --- a/src/main/java/com/dji/sample/manage/model/entity/DeviceFirmwareEntity.java +++ b/src/main/java/com/dji/sample/manage/model/entity/DeviceFirmwareEntity.java @@ -43,7 +43,7 @@ public class DeviceFirmwareEntity implements Serializable { @TableField("file_md5") private String fileMd5; - @TableField("device_name") + @TableField(exist = false) private String deviceName; @TableField("release_note") diff --git a/src/main/java/com/dji/sample/manage/model/entity/FirmwareModelEntity.java b/src/main/java/com/dji/sample/manage/model/entity/FirmwareModelEntity.java new file mode 100644 index 0000000..5c8707d --- /dev/null +++ b/src/main/java/com/dji/sample/manage/model/entity/FirmwareModelEntity.java @@ -0,0 +1,37 @@ +package com.dji.sample.manage.model.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author sean + * @version 1.3 + * @date 2022/12/21 + */ +@Data +@TableName("manage_firmware_model") +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class FirmwareModelEntity implements Serializable { + + @TableId(type = IdType.AUTO) + private Long id; + + @TableField("firmware_id") + private String firmwareId; + + @TableField("device_name") + private String deviceName; + + @TableField(value = "create_time", fill = FieldFill.INSERT) + private Long createTime; + + @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) + private Long updateTime; +} diff --git a/src/main/java/com/dji/sample/manage/model/enums/DeviceDomainEnum.java b/src/main/java/com/dji/sample/manage/model/enums/DeviceDomainEnum.java index 76b9c4d..22475b2 100644 --- a/src/main/java/com/dji/sample/manage/model/enums/DeviceDomainEnum.java +++ b/src/main/java/com/dji/sample/manage/model/enums/DeviceDomainEnum.java @@ -1,77 +1,27 @@ package com.dji.sample.manage.model.enums; +import lombok.Getter; + /** * * @author sean.zhou * @date 2021/11/15 * @version 0.1 */ +@Getter public enum DeviceDomainEnum { - SUB_DEVICE(0, "sub-device"), - - GATEWAY(2, "gateway"), - - PAYLOAD(1, "payload"), + SUB_DEVICE(0), - DOCK (3, "dock"), + GATEWAY(2), - UNKNOWN(-1, "unknown"); + PAYLOAD(1), - private int val; + DOCK (3); - private String desc; + int val; - DeviceDomainEnum(int val, String desc) { + DeviceDomainEnum(int val) { this.val = val; - this.desc = desc; - } - - public int getVal() { - return val; } - - public String getDesc() { - return desc; - } - - public static String getDesc(int val) { - if (SUB_DEVICE.val == val) { - return SUB_DEVICE.desc; - } - - if (GATEWAY.val == val) { - return GATEWAY.desc; - } - - if (PAYLOAD.val == val) { - return PAYLOAD.desc; - } - - if (DOCK.val == val) { - return DOCK.desc; - } - return UNKNOWN.desc; - } - - public static int getVal(String desc) { - if (SUB_DEVICE.desc.equals(desc)) { - return SUB_DEVICE.val; - } - - if (GATEWAY.desc.equals(desc)) { - return GATEWAY.val; - } - - if (PAYLOAD.desc.equals(desc)) { - return PAYLOAD.val; - } - - if (DOCK.desc.equals(desc)) { - return DOCK.val; - } - return UNKNOWN.val; - } - - } diff --git a/src/main/java/com/dji/sample/manage/model/param/DeviceFirmwareUploadParam.java b/src/main/java/com/dji/sample/manage/model/param/DeviceFirmwareUploadParam.java index 41a1b31..f48f4f0 100644 --- a/src/main/java/com/dji/sample/manage/model/param/DeviceFirmwareUploadParam.java +++ b/src/main/java/com/dji/sample/manage/model/param/DeviceFirmwareUploadParam.java @@ -3,6 +3,7 @@ package com.dji.sample.manage.model.param; import lombok.Data; import javax.validation.constraints.NotNull; +import java.util.List; /** * @author sean @@ -19,5 +20,5 @@ public class DeviceFirmwareUploadParam { private Boolean status; @NotNull - private String deviceName; + private List deviceName; } 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 index 3ae7a74..1fb2789 100644 --- a/src/main/java/com/dji/sample/manage/model/receiver/DistanceLimitStatusReceiver.java +++ b/src/main/java/com/dji/sample/manage/model/receiver/DistanceLimitStatusReceiver.java @@ -35,7 +35,7 @@ public class DistanceLimitStatusReceiver extends BasicDeviceProperty { valid = StateSwitchEnum.find(state).isPresent(); } if (Objects.nonNull(distanceLimit)) { - valid &= StateSwitchEnum.find(distanceLimit).isPresent(); + valid &= distanceLimit >= DISTANCE_MIN && distanceLimit <= DISTANCE_MAX; } return valid; } diff --git a/src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java b/src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java index 88dc3b0..2d82e7b 100644 --- a/src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java +++ b/src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java @@ -23,11 +23,13 @@ public interface IDeviceFirmwareService { /** * Query specific firmware information based on the device model and firmware version. + * + * @param workspaceId * @param deviceName * @param version * @return */ - Optional getFirmware(String deviceName, String version); + Optional getFirmware(String workspaceId, String deviceName, String version); /** * Get the latest firmware release note for this device model. @@ -38,10 +40,12 @@ public interface IDeviceFirmwareService { /** * Get the firmware information that the device needs to update. + * + * @param workspaceId * @param upgradeDTOS * @return */ - List getDeviceOtaFirmware(List upgradeDTOS); + List getDeviceOtaFirmware(String workspaceId, List upgradeDTOS); /** * Interface to handle device firmware update progress. @@ -80,8 +84,9 @@ public interface IDeviceFirmwareService { /** * Save the file information of the firmware. * @param firmware + * @param deviceNames */ - void saveFirmwareInfo(DeviceFirmwareDTO firmware); + void saveFirmwareInfo(DeviceFirmwareDTO firmware, List deviceNames); /** * Update the file information of the firmware. 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 ff41435..11bb1d7 100644 --- a/src/main/java/com/dji/sample/manage/service/IDeviceService.java +++ b/src/main/java/com/dji/sample/manage/service/IDeviceService.java @@ -180,7 +180,7 @@ public interface IDeviceService { * @param domain * @return */ - PaginationData getBoundDevicesWithDomain(String workspaceId, Long page, Long pageSize, String domain); + PaginationData getBoundDevicesWithDomain(String workspaceId, Long page, Long pageSize, Integer domain); /** * Unbind device base on device's sn. diff --git a/src/main/java/com/dji/sample/manage/service/IFirmwareModelService.java b/src/main/java/com/dji/sample/manage/service/IFirmwareModelService.java new file mode 100644 index 0000000..4aaaa81 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/service/IFirmwareModelService.java @@ -0,0 +1,18 @@ +package com.dji.sample.manage.service; + +import com.dji.sample.manage.model.dto.FirmwareModelDTO; + +/** + * @author sean + * @version 1.3 + * @date 2022/12/21 + */ +public interface IFirmwareModelService { + + /** + * Save the relationship between firmware files and device models. + * @param firmwareModel + */ + void saveFirmwareDeviceName(FirmwareModelDTO firmwareModel); + +} diff --git a/src/main/java/com/dji/sample/manage/service/impl/AbstractTSAService.java b/src/main/java/com/dji/sample/manage/service/impl/AbstractTSAService.java index 56b8217..91e390a 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/AbstractTSAService.java +++ b/src/main/java/com/dji/sample/manage/service/impl/AbstractTSAService.java @@ -1,7 +1,6 @@ package com.dji.sample.manage.service.impl; import com.dji.sample.component.mqtt.model.CommonTopicReceiver; -import com.dji.sample.component.redis.RedisOpsUtils; import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; import com.dji.sample.component.websocket.model.BizCodeEnum; import com.dji.sample.component.websocket.model.CustomWebSocketMessage; @@ -28,9 +27,6 @@ public abstract class AbstractTSAService implements ITSAService { @Autowired protected ObjectMapper mapper; - @Autowired - protected RedisOpsUtils redisOps; - @Autowired private IWebSocketManageService webSocketManageService; diff --git a/src/main/java/com/dji/sample/manage/service/impl/ConfigProductServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/ConfigProductServiceImpl.java index b117586..2b2f59f 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/ConfigProductServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/ConfigProductServiceImpl.java @@ -1,7 +1,8 @@ package com.dji.sample.manage.service.impl; +import com.dji.sample.manage.model.common.AppLicenseProperties; import com.dji.sample.manage.model.common.NtpServerProperties; -import com.dji.sample.manage.model.dto.NtpServerDTO; +import com.dji.sample.manage.model.dto.ProductConfigDTO; import com.dji.sample.manage.service.IRequestsConfigService; import org.springframework.stereotype.Service; @@ -15,6 +16,6 @@ public class ConfigProductServiceImpl implements IRequestsConfigService { @Override public Object getConfig() { - return new NtpServerDTO(NtpServerProperties.host); + return new ProductConfigDTO(NtpServerProperties.host, AppLicenseProperties.id, AppLicenseProperties.key, AppLicenseProperties.license); } } 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 e2f240e..6b99d38 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 @@ -2,6 +2,7 @@ package com.dji.sample.manage.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.dji.sample.common.model.Pagination; import com.dji.sample.common.model.PaginationData; @@ -12,6 +13,7 @@ import com.dji.sample.component.oss.model.OssConfiguration; import com.dji.sample.component.oss.service.impl.OssServiceContext; import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.redis.RedisOpsUtils; +import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; import com.dji.sample.component.websocket.model.CustomWebSocketMessage; import com.dji.sample.component.websocket.service.IWebSocketManageService; import com.dji.sample.component.websocket.service.impl.SendMessageServiceImpl; @@ -24,6 +26,7 @@ import com.dji.sample.manage.model.param.DeviceFirmwareUploadParam; import com.dji.sample.manage.model.param.DeviceOtaCreateParam; import com.dji.sample.manage.service.IDeviceFirmwareService; import com.dji.sample.manage.service.IDeviceService; +import com.dji.sample.manage.service.IFirmwareModelService; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; @@ -79,26 +82,30 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { @Autowired private OssServiceContext ossServiceContext; + @Autowired + private IFirmwareModelService firmwareModelService; + @Override - public Optional getFirmware(String deviceName, String version) { + public Optional getFirmware(String workspaceId, String deviceName, String version) { return Optional.ofNullable(entity2Dto(mapper.selectOne( new LambdaQueryWrapper() - .eq(DeviceFirmwareEntity::getDeviceName, deviceName) - .eq(DeviceFirmwareEntity::getFirmwareVersion, version)))); + .eq(DeviceFirmwareEntity::getWorkspaceId, workspaceId) + .eq(DeviceFirmwareEntity::getFirmwareVersion, version) + .eq(DeviceFirmwareEntity::getStatus, true), + deviceName))); } @Override public Optional getLatestFirmwareReleaseNote(String deviceName) { return Optional.ofNullable(entity2NoteDto(mapper.selectOne( - new LambdaQueryWrapper() - .eq(DeviceFirmwareEntity::getDeviceName, deviceName) + Wrappers.lambdaQuery(DeviceFirmwareEntity.class) .eq(DeviceFirmwareEntity::getStatus, true) - .orderByDesc(DeviceFirmwareEntity::getReleaseDate, DeviceFirmwareEntity::getFirmwareVersion) - .last(" limit 1 ")))); + .orderByDesc(DeviceFirmwareEntity::getReleaseDate, DeviceFirmwareEntity::getFirmwareVersion), + deviceName))); } @Override - public List getDeviceOtaFirmware(List upgradeDTOS) { + public List getDeviceOtaFirmware(String workspaceId, List upgradeDTOS) { List deviceOtaList = new ArrayList<>(); upgradeDTOS.forEach(upgradeDevice -> { boolean exist = deviceService.checkDeviceOnline(upgradeDevice.getSn()); @@ -106,12 +113,9 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { throw new IllegalArgumentException("Device is offline."); } Optional firmwareOpt = this.getFirmware( - upgradeDevice.getDeviceName(), upgradeDevice.getProductVersion()); + workspaceId, upgradeDevice.getDeviceName(), upgradeDevice.getProductVersion()); if (firmwareOpt.isEmpty()) { - throw new IllegalArgumentException("This firmware version does not exist."); - } - if (!firmwareOpt.get().getFirmwareStatus()) { - throw new IllegalArgumentException("This firmware version is not available."); + throw new IllegalArgumentException("This firmware version does not exist or is not available."); } DeviceOtaCreateParam ota = dto2OtaCreateDto(firmwareOpt.get()); ota.setSn(upgradeDevice.getSn()); @@ -131,7 +135,6 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { EventsReceiver eventsReceiver = objectMapper.convertValue(receiver.getData(), new TypeReference>(){}); eventsReceiver.setBid(receiver.getBid()); - eventsReceiver.setSn(sn); EventsOutputReceiver output = eventsReceiver.getOutput(); log.info("SN: {}, {} ===> Upgrading progress: {}", @@ -148,6 +151,13 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { // Determine whether it is the ending state, delete the update state key in redis after the job ends. EventsResultStatusEnum statusEnum = EventsResultStatusEnum.find(output.getStatus()); + Collection sessions = webSocketManageService.getValueWithWorkspaceAndUserType( + device.getWorkspaceId(), UserTypeEnum.WEB.getVal()); + CustomWebSocketMessage build = CustomWebSocketMessage.builder() + .data(eventsReceiver) + .timestamp(System.currentTimeMillis()) + .bizCode(receiver.getMethod()) + .build(); if (upgrade) { if (statusEnum.getEnd()) { // Delete the cache after the update is complete. @@ -158,8 +168,14 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { RedisConst.FIRMWARE_UPGRADING_PREFIX + sn, output.getProgress().getPercent(), RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); } + eventsReceiver.setSn(sn); + webSocketMessageService.sendBatch(sessions, build); } if (childUpgrade) { + if (!StringUtils.hasText(eventsReceiver.getSn())) { + eventsReceiver.setSn(childDeviceSn); + webSocketMessageService.sendBatch(sessions, build); + } if (statusEnum.getEnd()) { RedisOpsUtils.del(RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn); } else { @@ -170,15 +186,6 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { } } - webSocketMessageService.sendBatch( - webSocketManageService.getValueWithWorkspaceAndUserType( - device.getWorkspaceId(), UserTypeEnum.WEB.getVal()), - CustomWebSocketMessage.builder() - .data(eventsReceiver) - .timestamp(System.currentTimeMillis()) - .bizCode(receiver.getMethod()) - .build()); - if (receiver.getNeedReply() != null && receiver.getNeedReply() == 1) { String replyTopic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF; messageSenderService.publish(replyTopic, @@ -194,7 +201,8 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { @Override public Boolean checkFileExist(String workspaceId, String fileMd5) { - return mapper.selectCount(new LambdaQueryWrapper() + return RedisOpsUtils.checkExist(RedisConst.FILE_UPLOADING_PREFIX + workspaceId + fileMd5) || + mapper.selectCount(new LambdaQueryWrapper() .eq(DeviceFirmwareEntity::getWorkspaceId, workspaceId) .eq(DeviceFirmwareEntity::getFileMd5, fileMd5)) > 0; @@ -206,9 +214,8 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { new LambdaQueryWrapper() .eq(DeviceFirmwareEntity::getWorkspaceId, workspaceId) .eq(Objects.nonNull(param.getStatus()), DeviceFirmwareEntity::getStatus, param.getStatus()) - .eq(StringUtils.hasText(param.getDeviceName()), DeviceFirmwareEntity::getDeviceName, param.getDeviceName()) .like(StringUtils.hasText(param.getProductVersion()), DeviceFirmwareEntity::getFirmwareVersion, param.getProductVersion()) - .orderByDesc(DeviceFirmwareEntity::getReleaseDate)); + .orderByDesc(DeviceFirmwareEntity::getReleaseDate), param.getDeviceName()); List data = page.getRecords().stream().map(this::entity2Dto).collect(Collectors.toList()); return new PaginationData(data, new Pagination(page)); @@ -217,14 +224,21 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { @Override public void importFirmwareFile(String workspaceId, String creator, DeviceFirmwareUploadParam param, MultipartFile file) { + String key = RedisConst.FILE_UPLOADING_PREFIX + workspaceId; + String existKey = key + file.getOriginalFilename(); + if (RedisOpsUtils.getExpire(existKey) > 0) { + throw new RuntimeException("Please try again later."); + } + RedisOpsUtils.setWithExpire(existKey, true, RedisConst.DEVICE_ALIVE_SECOND); try (InputStream is = file.getInputStream()) { long size = is.available(); String md5 = DigestUtils.md5DigestAsHex(is); + key += md5; boolean exist = checkFileExist(workspaceId, md5); if (exist) { throw new RuntimeException("The file already exists."); } - + RedisOpsUtils.set(key, System.currentTimeMillis()); Optional firmwareOpt = verifyFirmwareFile(file); if (firmwareOpt.isEmpty()) { throw new RuntimeException("The file format is incorrect."); @@ -234,9 +248,8 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { String objectKey = OssConfiguration.objectDirPrefix + File.separator + firmwareId + FirmwareFileProperties.FIRMWARE_FILE_SUFFIX; ossServiceContext.putObject(OssConfiguration.bucket, objectKey, file.getInputStream()); - log.info("upload success"); + log.info("upload success. {}", file.getOriginalFilename()); DeviceFirmwareDTO firmware = DeviceFirmwareDTO.builder() - .deviceName(param.getDeviceName()) .releaseNote(param.getReleaseNote()) .firmwareStatus(param.getStatus()) .fileMd5(md5) @@ -250,15 +263,20 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { .firmwareId(firmwareId) .build(); - saveFirmwareInfo(firmware); + saveFirmwareInfo(firmware, param.getDeviceName()); } catch (IOException e) { e.printStackTrace(); + } finally { + RedisOpsUtils.del(key); } } @Override - public void saveFirmwareInfo(DeviceFirmwareDTO firmware) { - mapper.insert(dto2Entity(firmware)); + public void saveFirmwareInfo(DeviceFirmwareDTO firmware, List deviceNames) { + DeviceFirmwareEntity entity = dto2Entity(firmware); + mapper.insert(entity); + firmwareModelService.saveFirmwareDeviceName( + FirmwareModelDTO.builder().firmwareId(entity.getFirmwareId()).deviceNames(deviceNames).build()); } @Override @@ -308,7 +326,6 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { } return DeviceFirmwareEntity.builder() .fileName(dto.getFileName()) - .deviceName(dto.getDeviceName()) .fileMd5(dto.getFileMd5()) .fileSize(dto.getFileSize()) .firmwareId(dto.getFirmwareId()) @@ -340,7 +357,7 @@ public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService { return null; } return DeviceFirmwareDTO.builder() - .deviceName(entity.getDeviceName()) + .deviceName(Arrays.asList(entity.getDeviceName().split(","))) .fileMd5(entity.getFileMd5()) .fileSize(entity.getFileSize()) .objectKey(entity.getObjectKey()) 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 16ed4be..b540e08 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 @@ -2,6 +2,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.redis.RedisOpsUtils; import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; import com.dji.sample.component.websocket.model.BizCodeEnum; import com.dji.sample.component.websocket.model.CustomWebSocketMessage; @@ -58,7 +59,7 @@ public class DeviceOSDServiceImpl extends AbstractTSAService { public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, Collection webSessions, CustomWebSocketMessage wsMessage) { - if (DeviceDomainEnum.SUB_DEVICE.getDesc().equals(device.getDomain())) { + if (DeviceDomainEnum.SUB_DEVICE.getVal() == device.getDomain()) { wsMessage.setBizCode(BizCodeEnum.DEVICE_OSD.getCode()); OsdSubDeviceReceiver data = mapper.convertValue(receiver.getData(), OsdSubDeviceReceiver.class); @@ -75,7 +76,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); + RedisOpsUtils.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/DeviceServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java index f37da4b..6677ca8 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 @@ -111,8 +111,6 @@ public class DeviceServiceImpl implements IDeviceService { Optional gatewayOpt = this.getDeviceBySn(gatewaySn); if (gatewayOpt.isPresent()) { DeviceDTO value = gatewayOpt.get(); - value.setBoundTime(null); - value.setLoginTime(null); RedisOpsUtils.setWithExpire(key, value, RedisConst.DEVICE_ALIVE_SECOND); this.pushDeviceOnlineTopo(value.getWorkspaceId(), gatewaySn, gatewaySn); return true; @@ -120,7 +118,7 @@ public class DeviceServiceImpl implements IDeviceService { // When connecting for the first time DeviceEntity gatewayDevice = deviceGatewayConvertToDeviceEntity(gateway); - return firstSaveDevice(gatewayDevice, null); + return onlineSaveDevice(gatewayDevice, null).isPresent(); } DeviceDTO deviceDTO = (DeviceDTO) (RedisOpsUtils.get(key)); @@ -151,6 +149,7 @@ public class DeviceServiceImpl implements IDeviceService { RedisOpsUtils.del(key); RedisOpsUtils.del(RedisConst.OSD_PREFIX + device.getDeviceSn()); + RedisOpsUtils.del(RedisConst.HMS_PREFIX + device.getDeviceSn()); log.debug("{} offline.", deviceSn); return true; } @@ -185,8 +184,8 @@ public class DeviceServiceImpl implements IDeviceService { DeviceQueryParam.builder() .childSn(deviceSn) .build()); - gatewaysList.stream().filter( - gateway -> !gateway.getDeviceSn().equals(deviceGateway.getSn())) + gatewaysList.stream() + .filter(gateway -> !gateway.getDeviceSn().equals(deviceGateway.getSn())) .findAny() .ifPresent(gateway -> { gateway.setChildDeviceSn(""); @@ -194,34 +193,33 @@ public class DeviceServiceImpl implements IDeviceService { }); DeviceEntity gateway = deviceGatewayConvertToDeviceEntity(deviceGateway); - DeviceEntity subDevice = subDeviceConvertToDeviceEntity(deviceGateway.getSubDevices().get(0)); - boolean isSave = firstSaveDevice(gateway, deviceSn) && firstSaveDevice(subDevice, null); - if (!isSave) { + Optional gatewayEntityOpt = onlineSaveDevice(gateway, deviceSn); + if (gatewayEntityOpt.isEmpty()) { + log.error("Failed to go online, please check the status data or code logic."); return false; } - // dock go online - if (deviceGateway.getDomain() != null && DeviceDomainEnum.DOCK.getVal() == deviceGateway.getDomain()) { - Optional deviceOpt = this.getDeviceBySn(deviceGateway.getSn()); - if (deviceOpt.isEmpty()) { - log.info("The dock is not bound and cannot go online. Please refer to the Cloud API document video for binding."); - return false; - } - gateway.setNickname(null); - subDevice.setNickname(null); + DeviceEntity subDevice = subDeviceConvertToDeviceEntity(deviceGateway.getSubDevices().get(0)); + Optional subDeviceEntityOpt = onlineSaveDevice(subDevice, null); + if (subDeviceEntityOpt.isEmpty()) { + log.error("Failed to go online, please check the status data or code logic."); + return false; } - String workspaceId = subDevice.getWorkspaceId(); + subDevice = subDeviceEntityOpt.get(); + gateway = gatewayEntityOpt.get(); - this.subscribeTopicOnline(deviceGateway.getSn()); - if (!StringUtils.hasText(workspaceId)) { - log.info("The drone is not bound and cannot go online. Please refer to the Cloud API document video for binding."); - return true; + // dock go online + if (DeviceDomainEnum.DOCK.getVal() == deviceGateway.getDomain() && !subDevice.getBoundStatus()) { + // Directly bind the drone of the dock to the same workspace as the dock. + bindDevice(DeviceDTO.builder().deviceSn(deviceSn).workspaceId(gateway.getWorkspaceId()).build()); + subDevice.setWorkspaceId(gateway.getWorkspaceId()); } // Subscribe to topic related to drone devices. + this.subscribeTopicOnline(deviceGateway.getSn()); this.subscribeTopicOnline(deviceSn); - this.pushDeviceOnlineTopo(workspaceId, deviceGateway.getSn(), deviceSn); + this.pushDeviceOnlineTopo(subDevice.getWorkspaceId(), deviceGateway.getSn(), deviceSn); log.debug("{} online.", subDevice.getDeviceSn()); return true; @@ -305,34 +303,33 @@ public class DeviceServiceImpl implements IDeviceService { List devicesList = this.getDevicesByParams( DeviceQueryParam.builder() .workspaceId(workspaceId) - .domains(List.of(DeviceDomainEnum.SUB_DEVICE.getVal())) + .domains(List.of(DeviceDomainEnum.GATEWAY.getVal(), DeviceDomainEnum.DOCK.getVal())) .build()); - devicesList.forEach(device -> { - this.spliceDeviceTopo(device); - device.setWorkspaceId(workspaceId); - device.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); - }); + devicesList.stream() + .filter(gateway -> DeviceDomainEnum.DOCK.getVal() == gateway.getDomain() || + RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + gateway.getDeviceSn())) + .forEach(this::spliceDeviceTopo); + return devicesList; } @Override - public void spliceDeviceTopo(DeviceDTO device) { + public void spliceDeviceTopo(DeviceDTO gateway) { - // remote controller - List gatewaysList = getDevicesByParams( - DeviceQueryParam.builder() - .childSn(device.getDeviceSn()) - .build()); - - // payloads - List payloadsList = payloadService - .getDevicePayloadEntitiesByDeviceSn(device.getDeviceSn()); + gateway.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + gateway.getDeviceSn())); + // sub device + if (!StringUtils.hasText(gateway.getChildDeviceSn())) { + return; + } - device.setGatewaysList(gatewaysList); - device.setPayloadsList(payloadsList); + DeviceDTO subDevice = getDevicesByParams(DeviceQueryParam.builder().deviceSn(gateway.getChildDeviceSn()).build()).get(0); + subDevice.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + subDevice.getDeviceSn())); + gateway.setChildren(subDevice); + // payloads + subDevice.setPayloadsList(payloadService.getDevicePayloadEntitiesByDeviceSn(gateway.getChildDeviceSn())); } @Override @@ -377,24 +374,20 @@ public class DeviceServiceImpl implements IDeviceService { TopologyDeviceDTO.TopologyDeviceDTOBuilder builder = TopologyDeviceDTO.builder(); if (device != null) { - int domain = DeviceDomainEnum.getVal(device.getDomain()); - String subType = String.valueOf(device.getSubType()); - String type = String.valueOf(device.getType()); - builder.sn(device.getDeviceSn()) .deviceCallsign(device.getNickname()) .deviceModel(DeviceModelDTO.builder() - .domain(String.valueOf(domain)) - .subType(subType) - .type(type) - .key(domain + "-" + type + "-" + subType) + .domain(String.valueOf(device.getDomain())) + .subType(String.valueOf(device.getSubType())) + .type(String.valueOf(device.getType())) + .key(device.getDomain() + "-" + device.getType() + "-" + device.getSubType()) .build()) .iconUrls(device.getIconUrl()) .onlineStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) .boundStatus(device.getBoundStatus()) .model(device.getDeviceName()) .userId(device.getUserId()) - .domain(DeviceDomainEnum.getDesc(domain)) + .domain(device.getDomain()) .build(); } return builder.build(); @@ -518,6 +511,9 @@ public class DeviceServiceImpl implements IDeviceService { .eq(DeviceEntity::getDeviceSn, entity.getDeviceSn())); // Update the information directly if the device already exists. if (deviceEntity != null) { + if (deviceEntity.getDeviceName().equals(entity.getNickname())) { + entity.setNickname(null); + } entity.setId(deviceEntity.getId()); mapper.updateById(entity); return Optional.of(deviceEntity); @@ -605,7 +601,7 @@ public class DeviceServiceImpl implements IDeviceService { .workspaceId(entity.getWorkspaceId()) .type(entity.getDeviceType()) .subType(entity.getSubType()) - .domain(DeviceDomainEnum.getDesc(entity.getDomain())) + .domain(entity.getDomain()) .iconUrl(IconUrlDTO.builder() .normalUrl(entity.getUrlNormal()) .selectUrl(entity.getUrlSelect()) @@ -666,18 +662,19 @@ public class DeviceServiceImpl implements IDeviceService { } String key = RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(); - DeviceDTO redisDevice = (DeviceDTO)RedisOpsUtils.get(key); - if (Objects.isNull(redisDevice)) { + if (!RedisOpsUtils.checkExist(key)) { return false; } + + DeviceDTO redisDevice = (DeviceDTO)RedisOpsUtils.get(key); redisDevice.setWorkspaceId(device.getWorkspaceId()); RedisOpsUtils.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); - if (DeviceDomainEnum.GATEWAY.getDesc().equals(redisDevice.getDomain())) { + if (DeviceDomainEnum.GATEWAY.getVal() == redisDevice.getDomain()) { this.pushDeviceOnlineTopo(webSocketManageService.getValueWithWorkspace(device.getWorkspaceId()), device.getDeviceSn(), device.getDeviceSn()); } - if (DeviceDomainEnum.SUB_DEVICE.getDesc().equals(redisDevice.getDomain())) { + if (DeviceDomainEnum.SUB_DEVICE.getVal() == redisDevice.getDomain()) { DeviceDTO subDevice = this.getDevicesByParams(DeviceQueryParam.builder() .childSn(device.getChildDeviceSn()) .build()).get(0); @@ -774,11 +771,11 @@ public class DeviceServiceImpl implements IDeviceService { @Override public PaginationData getBoundDevicesWithDomain(String workspaceId, Long page, - Long pageSize, String domain) { + Long pageSize, Integer domain) { Page pagination = mapper.selectPage(new Page<>(page, pageSize), new LambdaQueryWrapper() - .eq(DeviceEntity::getDomain, DeviceDomainEnum.getVal(domain)) + .eq(DeviceEntity::getDomain, domain) .eq(DeviceEntity::getWorkspaceId, workspaceId) .eq(DeviceEntity::getBoundStatus, true)); List devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO) @@ -849,7 +846,7 @@ public class DeviceServiceImpl implements IDeviceService { @Override public ResponseResult createDeviceOtaJob(String workspaceId, List upgradeDTOS) { - List deviceOtaFirmwares = deviceFirmwareService.getDeviceOtaFirmware(upgradeDTOS); + List deviceOtaFirmwares = deviceFirmwareService.getDeviceOtaFirmware(workspaceId, upgradeDTOS); if (deviceOtaFirmwares.isEmpty()) { return ResponseResult.error(); } @@ -976,7 +973,7 @@ public class DeviceServiceImpl implements IDeviceService { .boundTime(dto.getBoundTime() != null ? dto.getBoundTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null) .childSn(dto.getChildDeviceSn()) - .domain(StringUtils.hasText(dto.getDomain()) ? DeviceDomainEnum.getVal(dto.getDomain()) : null) + .domain(dto.getDomain()) .firmwareVersion(dto.getFirmwareVersion()) .compatibleStatus(dto.getFirmwareStatus() == null ? null : DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE != DeviceFirmwareStatusEnum.find(dto.getFirmwareStatus())) @@ -1041,7 +1038,7 @@ public class DeviceServiceImpl implements IDeviceService { .build(); } - private Boolean firstSaveDevice(DeviceEntity device, String deviceSn) { + private Optional onlineSaveDevice(DeviceEntity device, String childSn) { Optional deviceOpt = this.getDeviceBySn(device.getDeviceSn()); if (deviceOpt.isEmpty()) { @@ -1049,15 +1046,19 @@ public class DeviceServiceImpl implements IDeviceService { device.setUrlNormal(IconUrlEnum.NORMAL_PERSON.getUrl()); // Set the icon of the gateway device displayed in the pilot's map when it is selected, required in the TSA module. device.setUrlSelect(IconUrlEnum.SELECT_PERSON.getUrl()); + device.setBoundStatus(false); + } else { + DeviceDTO oldDevice = deviceOpt.get(); + device.setNickname(oldDevice.getNickname()); + device.setBoundStatus(oldDevice.getBoundStatus()); } - deviceOpt.ifPresent(oldDevice -> device.setNickname(oldDevice.getNickname())); - device.setChildSn(deviceSn); + device.setChildSn(childSn); device.setLoginTime(System.currentTimeMillis()); Optional saveDeviceOpt = this.saveDevice(device); if (saveDeviceOpt.isEmpty()) { - return false; + return saveDeviceOpt; } device.setWorkspaceId(saveDeviceOpt.get().getWorkspaceId()); @@ -1065,13 +1066,13 @@ public class DeviceServiceImpl implements IDeviceService { DeviceDTO.builder() .deviceSn(device.getDeviceSn()) .workspaceId(device.getWorkspaceId()) - .childDeviceSn(deviceSn) - .domain(DeviceDomainEnum.getDesc(device.getDomain())) + .childDeviceSn(childSn) + .domain(device.getDomain()) .type(device.getDeviceType()) .subType(device.getSubType()) .build(), RedisConst.DEVICE_ALIVE_SECOND); - return true; + return saveDeviceOpt; } -} +} \ No newline at end of file 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 f0bac72..36cd9b3 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 @@ -35,7 +35,7 @@ public class DockOSDServiceImpl extends AbstractTSAService { Collection webSessions, CustomWebSocketMessage wsMessage) { - if (DeviceDomainEnum.DOCK.getDesc().equals(device.getDomain())) { + if (DeviceDomainEnum.DOCK.getVal() == device.getDomain()) { wsMessage.setBizCode(BizCodeEnum.DOCK_OSD.getCode()); OsdDockReceiver data = mapper.convertValue(receiver.getData(), OsdDockReceiver.class); wsMessage.getData().setHost(data); diff --git a/src/main/java/com/dji/sample/manage/service/impl/FirmwareModelServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/FirmwareModelServiceImpl.java new file mode 100644 index 0000000..6256527 --- /dev/null +++ b/src/main/java/com/dji/sample/manage/service/impl/FirmwareModelServiceImpl.java @@ -0,0 +1,44 @@ +package com.dji.sample.manage.service.impl; + +import com.dji.sample.manage.dao.IFirmwareModelMapper; +import com.dji.sample.manage.model.dto.FirmwareModelDTO; +import com.dji.sample.manage.model.entity.FirmwareModelEntity; +import com.dji.sample.manage.service.IFirmwareModelService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author sean + * @version 1.3 + * @date 2022/12/21 + */ +@Service +@Transactional +public class FirmwareModelServiceImpl implements IFirmwareModelService { + + @Autowired + private IFirmwareModelMapper mapper; + + @Override + public void saveFirmwareDeviceName(FirmwareModelDTO firmwareModel) { + dto2Entity(firmwareModel).forEach(entity -> mapper.insert(entity)); + } + + private List dto2Entity(FirmwareModelDTO dto) { + if (Objects.isNull(dto) || CollectionUtils.isEmpty(dto.getDeviceNames())) { + return Collections.EMPTY_LIST; + } + return dto.getDeviceNames().stream() + .map(deviceName -> FirmwareModelEntity.builder() + .firmwareId(dto.getFirmwareId()) + .deviceName(deviceName).build()) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/dji/sample/manage/service/impl/GatewayOSDServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/GatewayOSDServiceImpl.java index 397c80e..eb788b2 100644 --- a/src/main/java/com/dji/sample/manage/service/impl/GatewayOSDServiceImpl.java +++ b/src/main/java/com/dji/sample/manage/service/impl/GatewayOSDServiceImpl.java @@ -47,7 +47,7 @@ public class GatewayOSDServiceImpl extends AbstractTSAService { public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, Collection webSessions, CustomWebSocketMessage wsMessage) { - if (DeviceDomainEnum.GATEWAY.getDesc().equals(device.getDomain())) { + if (DeviceDomainEnum.GATEWAY.getVal() == device.getDomain()) { wsMessage.setBizCode(BizCodeEnum.GATEWAY_OSD.getCode()); OsdGatewayReceiver data = mapper.convertValue(receiver.getData(), OsdGatewayReceiver.class); 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 9f2cdf5..8b441ba 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 @@ -4,7 +4,6 @@ import com.dji.sample.common.error.LiveErrorEnum; import com.dji.sample.common.model.ResponseResult; import com.dji.sample.component.mqtt.model.CommonTopicResponse; import com.dji.sample.component.mqtt.model.ServiceReply; -import com.dji.sample.component.mqtt.model.StateDataEnum; import com.dji.sample.component.mqtt.service.IMessageSenderService; import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.redis.RedisOpsUtils; @@ -79,7 +78,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { // Solve timing problems for (CapacityDeviceReceiver capacityDeviceReceiver : liveCapacityReceiver.getDeviceList()) { long last = (long) Objects.requireNonNullElse( - RedisOpsUtils.get(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + capacityDeviceReceiver.getSn()), 0L); + RedisOpsUtils.get(RedisConst.LIVE_CAPACITY + capacityDeviceReceiver.getSn()), 0L); if (last > timestamp) { return; } @@ -126,8 +125,8 @@ public class LiveStreamServiceImpl implements ILiveStreamService { .toString()); break; case RTSP: - String url = receiveReply.getInfo().toString(); - this.resolveUrlUser(url, live); + Object url = Objects.requireNonNullElse(receiveReply.getOutput(), receiveReply.getInfo()); + this.resolveUrlUser(String.valueOf(url), live); break; case UNKNOWN: return ResponseResult.error(LiveErrorEnum.URL_TYPE_NOT_SUPPORTED); @@ -186,7 +185,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { if (ResponseResult.CODE_SUCCESS != responseResult.getCode()) { return responseResult; } - if (DeviceDomainEnum.GATEWAY.getDesc().equals(responseResult.getData().getDomain())) { + if (DeviceDomainEnum.GATEWAY.getVal() == responseResult.getData().getDomain()) { return ResponseResult.error(LiveErrorEnum.FUNCTION_NOT_SUPPORT); } @@ -232,7 +231,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService { return ResponseResult.error(LiveErrorEnum.NO_AIRCRAFT); } - if (deviceOpt.get().getDomain().equals(DeviceDomainEnum.DOCK.getDesc())) { + if (DeviceDomainEnum.DOCK.getVal() == deviceOpt.get().getDomain()) { return ResponseResult.success(deviceOpt.get()); } List gatewayList = deviceService.getDevicesByParams( 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 746fe99..d754831 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 @@ -101,13 +101,7 @@ public class UserServiceImpl implements IUserService { String token = JwtUtil.createToken(customClaim.convertToMap()); UserDTO userDTO = entityConvertToDTO(userEntity); - userDTO.setMqttAddr(new StringBuilder() - .append(mqttConfiguration.getProtocol().trim()) - .append("://") - .append(mqttConfiguration.getHost().trim()) - .append(":") - .append(mqttConfiguration.getPort()) - .toString()); + userDTO.setMqttAddr(MqttConfiguration.getBasicMqttAddress()); userDTO.setAccessToken(token); userDTO.setWorkspaceId(workspaceOpt.get().getWorkspaceId()); return ResponseResult.success(userDTO); @@ -218,13 +212,7 @@ public class UserServiceImpl implements IUserService { .userType(entity.getUserType()) .mqttUsername(entity.getMqttUsername()) .mqttPassword(entity.getMqttPassword()) - .mqttAddr(new StringBuilder() - .append(mqttConfiguration.getProtocol().trim()) - .append("://") - .append(mqttConfiguration.getHost().trim()) - .append(":") - .append(mqttConfiguration.getPort()) - .toString()) + .mqttAddr(MqttConfiguration.getBasicMqttAddress()) .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 d14b3de..8265d48 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 @@ -30,7 +30,6 @@ import org.springframework.stereotype.Service; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -116,12 +115,12 @@ public class MediaServiceImpl implements IMediaService { MediaFileCountDTO mediaFileCount = (MediaFileCountDTO) RedisOpsUtils.hashGet(RedisConst.MEDIA_FILE_PREFIX + receiver.getGateway(), jobId); // duplicate data if (receiver.getBid().equals(mediaFileCount.getBid()) && receiver.getTid().equals(mediaFileCount.getTid())) { - System.out.println("相同" + receiver.getBid() + "\t tid:" + receiver.getTid()); messageSenderService.publish(topic, data); return; } - Optional jobOpt = waylineJobService.getJobByJobId(jobId); + DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); + Optional jobOpt = waylineJobService.getJobByJobId(device.getWorkspaceId(), jobId); if (jobOpt.isPresent()) { boolean isSave = parseMediaFile(callback, jobOpt.get()); if (!isSave) { @@ -152,7 +151,8 @@ public class MediaServiceImpl implements IMediaService { // After uploading, delete the key with the highest priority. String highestKey = RedisConst.MEDIA_HIGHEST_PRIORITY_PREFIX + receiver.getGateway(); - if (jobId.equals(Objects.requireNonNullElse(RedisOpsUtils.get(highestKey), ""))) { + if (RedisOpsUtils.checkExist(highestKey) && + jobId.equals(((MediaFileCountDTO) RedisOpsUtils.get(highestKey)).getJobId())) { RedisOpsUtils.del(highestKey); } @@ -192,32 +192,39 @@ public class MediaServiceImpl implements IMediaService { return; } + messageSenderService.publish(headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF, + CommonTopicResponse.builder() + .data(RequestsReply.success()) + .method(receiver.getMethod()) + .timestamp(System.currentTimeMillis()) + .bid(receiver.getBid()) + .tid(receiver.getTid()) + .build()); + String dockSn = receiver.getGateway(); String jobId = map.get(MapKeyConst.FLIGHT_ID).toString(); String key = RedisConst.MEDIA_HIGHEST_PRIORITY_PREFIX + dockSn; - Object preJobId = RedisOpsUtils.get(key); + MediaFileCountDTO countDTO = new MediaFileCountDTO(); + if (RedisOpsUtils.checkExist(key)) { + countDTO = (MediaFileCountDTO) RedisOpsUtils.get(key); + if (jobId.equals(countDTO.getJobId())) { + RedisOpsUtils.setWithExpire(key, countDTO, RedisConst.DEVICE_ALIVE_SECOND * 5); + return; + } - RedisOpsUtils.setWithExpire(key, jobId, - RedisConst.DEVICE_ALIVE_SECOND * 5); + countDTO.setPreJobId(countDTO.getJobId()); + } + countDTO.setJobId(jobId); - DeviceDTO dock = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + dockSn); + RedisOpsUtils.setWithExpire(key, countDTO, RedisConst.DEVICE_ALIVE_SECOND * 5); + DeviceDTO dock = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + dockSn); sendMessageService.sendBatch(webSocketManageService.getValueWithWorkspaceAndUserType(dock.getWorkspaceId(), UserTypeEnum.WEB.getVal()), CustomWebSocketMessage.builder() .timestamp(System.currentTimeMillis()) .bizCode(BizCodeEnum.HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA.getCode()) - .data(MediaFileCountDTO.builder() - .preJobId(Objects.nonNull(preJobId) ? preJobId.toString() : null) - .jobId(jobId).build()) + .data(countDTO) .build()); - messageSenderService.publish(headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF, - CommonTopicResponse.builder() - .data(RequestsReply.success()) - .method(receiver.getMethod()) - .timestamp(System.currentTimeMillis()) - .bid(receiver.getBid()) - .tid(receiver.getTid()) - .build()); } } diff --git a/src/main/java/com/dji/sample/wayline/controller/WaylineJobController.java b/src/main/java/com/dji/sample/wayline/controller/WaylineJobController.java index 49ff96b..f24bdb2 100644 --- a/src/main/java/com/dji/sample/wayline/controller/WaylineJobController.java +++ b/src/main/java/com/dji/sample/wayline/controller/WaylineJobController.java @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.sql.SQLException; -import java.util.List; +import java.util.Set; import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; @@ -68,7 +68,7 @@ public class WaylineJobController { * @throws SQLException */ @DeleteMapping("/{workspace_id}/jobs") - public ResponseResult publishCancelJob(@RequestParam(name = "job_id") List jobIds, + public ResponseResult publishCancelJob(@RequestParam(name = "job_id") Set jobIds, @PathVariable(name = "workspace_id") String workspaceId) throws SQLException { waylineJobService.cancelFlightTask(workspaceId, jobIds); return ResponseResult.success(); diff --git a/src/main/java/com/dji/sample/wayline/model/dto/WaylineJobDTO.java b/src/main/java/com/dji/sample/wayline/model/dto/WaylineJobDTO.java index a4f8486..b797819 100644 --- a/src/main/java/com/dji/sample/wayline/model/dto/WaylineJobDTO.java +++ b/src/main/java/com/dji/sample/wayline/model/dto/WaylineJobDTO.java @@ -38,8 +38,12 @@ public class WaylineJobDTO { private LocalDateTime executeTime; + private LocalDateTime beginTime; + private LocalDateTime endTime; + private LocalDateTime completedTime; + private Integer status; private Integer progress; @@ -57,4 +61,6 @@ public class WaylineJobDTO { private Integer uploadedCount; private Boolean uploading; + + private String parentId; } diff --git a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskCreateDTO.java b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskCreateDTO.java similarity index 86% rename from src/main/java/com/dji/sample/wayline/model/dto/FlightTaskCreateDTO.java rename to src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskCreateDTO.java index c4b281d..b920530 100644 --- a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskCreateDTO.java +++ b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskCreateDTO.java @@ -14,7 +14,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class FlightTaskCreateDTO { +public class WaylineTaskCreateDTO { private String flightId; @@ -24,9 +24,10 @@ public class FlightTaskCreateDTO { private Long executeTime; - private FlightTaskFileDTO file; + private WaylineTaskFileDTO file; private Integer rthAltitude; private Integer outOfControlAction; + } diff --git a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskFileDTO.java b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskFileDTO.java similarity index 90% rename from src/main/java/com/dji/sample/wayline/model/dto/FlightTaskFileDTO.java rename to src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskFileDTO.java index e5858ee..604eb9d 100644 --- a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskFileDTO.java +++ b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskFileDTO.java @@ -14,7 +14,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class FlightTaskFileDTO { +public class WaylineTaskFileDTO { private String url; diff --git a/src/main/java/com/dji/sample/wayline/model/dto/FLightTaskProgress.java b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgress.java similarity index 84% rename from src/main/java/com/dji/sample/wayline/model/dto/FLightTaskProgress.java rename to src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgress.java index e8e8794..fa814e7 100644 --- a/src/main/java/com/dji/sample/wayline/model/dto/FLightTaskProgress.java +++ b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgress.java @@ -8,7 +8,7 @@ import lombok.Data; * @date 2022/6/9 */ @Data -public class FLightTaskProgress { +public class WaylineTaskProgress { private Integer currentStep; diff --git a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskProgressExt.java b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgressExt.java similarity index 67% rename from src/main/java/com/dji/sample/wayline/model/dto/FlightTaskProgressExt.java rename to src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgressExt.java index c75ef1e..bec5eaa 100644 --- a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskProgressExt.java +++ b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgressExt.java @@ -8,9 +8,13 @@ import lombok.Data; * @date 2022/6/9 */ @Data -public class FlightTaskProgressExt { +public class WaylineTaskProgressExt { private Integer currentWaypointIndex; private Integer mediaCount; + + private String flightId; + + private String trackId; } diff --git a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskProgressReceiver.java b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgressReceiver.java similarity index 56% rename from src/main/java/com/dji/sample/wayline/model/dto/FlightTaskProgressReceiver.java rename to src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgressReceiver.java index d2f7c7c..b86bc9b 100644 --- a/src/main/java/com/dji/sample/wayline/model/dto/FlightTaskProgressReceiver.java +++ b/src/main/java/com/dji/sample/wayline/model/dto/WaylineTaskProgressReceiver.java @@ -8,11 +8,11 @@ import lombok.Data; * @date 2022/6/9 */ @Data -public class FlightTaskProgressReceiver { +public class WaylineTaskProgressReceiver { - private FlightTaskProgressExt ext; + private WaylineTaskProgressExt ext; - private FLightTaskProgress progress; + private WaylineTaskProgress progress; private String status; diff --git a/src/main/java/com/dji/sample/wayline/model/entity/WaylineJobEntity.java b/src/main/java/com/dji/sample/wayline/model/entity/WaylineJobEntity.java index 64800a0..68f29f7 100644 --- a/src/main/java/com/dji/sample/wayline/model/entity/WaylineJobEntity.java +++ b/src/main/java/com/dji/sample/wayline/model/entity/WaylineJobEntity.java @@ -74,4 +74,12 @@ public class WaylineJobEntity implements Serializable { @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) private Long updateTime; + @TableField("begin_time") + private Long beginTime; + + @TableField("completed_time") + private Long completedTime; + + @TableField("parent_id") + private String parentId; } diff --git a/src/main/java/com/dji/sample/wayline/model/enums/WaylineJobStatusEnum.java b/src/main/java/com/dji/sample/wayline/model/enums/WaylineJobStatusEnum.java index b33150b..dcd5bb7 100644 --- a/src/main/java/com/dji/sample/wayline/model/enums/WaylineJobStatusEnum.java +++ b/src/main/java/com/dji/sample/wayline/model/enums/WaylineJobStatusEnum.java @@ -22,7 +22,9 @@ public enum WaylineJobStatusEnum { FAILED(5, true), - UNKNOWN(6, true); + PAUSED(6, false), + + UNKNOWN(-1, true); int val; diff --git a/src/main/java/com/dji/sample/wayline/service/IWaylineJobService.java b/src/main/java/com/dji/sample/wayline/service/IWaylineJobService.java index 90d8594..a18da9f 100644 --- a/src/main/java/com/dji/sample/wayline/service/IWaylineJobService.java +++ b/src/main/java/com/dji/sample/wayline/service/IWaylineJobService.java @@ -5,11 +5,13 @@ import com.dji.sample.common.model.PaginationData; import com.dji.sample.common.model.ResponseResult; import com.dji.sample.component.mqtt.model.CommonTopicReceiver; import com.dji.sample.wayline.model.dto.WaylineJobDTO; +import com.dji.sample.wayline.model.enums.WaylineJobStatusEnum; import com.dji.sample.wayline.model.param.CreateJobParam; import org.springframework.messaging.MessageHeaders; import java.sql.SQLException; import java.util.Collection; +import java.util.List; import java.util.Optional; /** @@ -22,10 +24,21 @@ public interface IWaylineJobService { /** * Create wayline job in the database. * @param param - * @param customClaim user info + * @param workspaceId user info + * @param username user info + * @param beginTime The time the job started. + * @param endTime The time the job ended. * @return */ - Optional createWaylineJob(CreateJobParam param, CustomClaim customClaim); + Optional createWaylineJob(CreateJobParam param, String workspaceId, String username, Long beginTime, Long endTime); + + /** + * Create a sub-task based on the information of the parent task. + * @param workspaceId + * @param parentId + * @return + */ + Optional createWaylineJobByParent(String workspaceId, String parentId); /** * Issue wayline mission to the dock. @@ -41,7 +54,7 @@ public interface IWaylineJobService { * @throws SQLException * @return */ - Boolean executeFlightTask(String jobId); + Boolean executeFlightTask(String workspaceId, String jobId); /** * Cancel the task Base on job Ids. @@ -51,12 +64,30 @@ public interface IWaylineJobService { */ void cancelFlightTask(String workspaceId, Collection jobIds); + /** + * Cancel the dock tasks that have been issued but have not yet been executed. + * @param workspaceId + * @param dockSn + * @param jobIds + */ + void publishCancelTask(String workspaceId, String dockSn, List jobIds); + + /** + * Query wayline jobs based on conditions. + * @param workspaceId + * @param jobIds + * @param status + * @return + */ + List getJobsByConditions(String workspaceId, Collection jobIds, WaylineJobStatusEnum status); + /** * Query job information based on job id. + * @param workspaceId * @param jobId * @return job information */ - Optional getJobByJobId(String jobId); + Optional getJobByJobId(String workspaceId, String jobId); /** * Update job data. diff --git a/src/main/java/com/dji/sample/wayline/service/impl/FlightTaskServiceImpl.java b/src/main/java/com/dji/sample/wayline/service/impl/FlightTaskServiceImpl.java index 77ca1cf..224602d 100644 --- a/src/main/java/com/dji/sample/wayline/service/impl/FlightTaskServiceImpl.java +++ b/src/main/java/com/dji/sample/wayline/service/impl/FlightTaskServiceImpl.java @@ -12,8 +12,8 @@ import com.dji.sample.component.websocket.service.IWebSocketManageService; import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.enums.UserTypeEnum; import com.dji.sample.media.model.MediaFileCountDTO; -import com.dji.sample.wayline.model.dto.FlightTaskProgressReceiver; import com.dji.sample.wayline.model.dto.WaylineJobDTO; +import com.dji.sample.wayline.model.dto.WaylineTaskProgressReceiver; import com.dji.sample.wayline.model.enums.WaylineJobStatusEnum; import com.dji.sample.wayline.service.IFlightTaskService; import com.dji.sample.wayline.service.IWaylineJobService; @@ -29,7 +29,7 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.time.LocalDateTime; -import java.util.Objects; +import java.util.*; import java.util.concurrent.TimeUnit; /** @@ -59,12 +59,15 @@ public class FlightTaskServiceImpl implements IFlightTaskService { @Override @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS, outputChannel = ChannelName.OUTBOUND) public void handleProgress(CommonTopicReceiver receiver, MessageHeaders headers) { - EventsReceiver eventsReceiver = mapper.convertValue(receiver.getData(), - new TypeReference>(){}); + String receivedTopic = String.valueOf(headers.get(MqttHeaders.RECEIVED_TOPIC)); + String dockSn = receivedTopic.substring((TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT).length(), + receivedTopic.indexOf(TopicConst.EVENTS_SUF)); + EventsReceiver eventsReceiver = mapper.convertValue(receiver.getData(), + new TypeReference>(){}); eventsReceiver.setBid(receiver.getBid()); eventsReceiver.setSn(receiver.getGateway()); - FlightTaskProgressReceiver output = eventsReceiver.getOutput(); + WaylineTaskProgressReceiver output = eventsReceiver.getOutput(); log.info("Task progress: {}", output.getProgress().toString()); @@ -73,16 +76,19 @@ public class FlightTaskServiceImpl implements IFlightTaskService { } EventsResultStatusEnum statusEnum = EventsResultStatusEnum.find(output.getStatus()); + String key = RedisConst.WAYLINE_JOB_RUNNING_PREFIX + dockSn; + RedisOpsUtils.setWithExpire(key, eventsReceiver, RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); + if (statusEnum.getEnd()) { WaylineJobDTO job = WaylineJobDTO.builder() .jobId(receiver.getBid()) .status(WaylineJobStatusEnum.SUCCESS.getVal()) - .endTime(LocalDateTime.now()) + .completedTime(LocalDateTime.now()) .mediaCount(output.getExt().getMediaCount()) .build(); // record the update of the media count. - if (Objects.nonNull(job.getMediaCount())) { + if (Objects.nonNull(job.getMediaCount()) && job.getMediaCount() != 0) { RedisOpsUtils.hashSet(RedisConst.MEDIA_FILE_PREFIX + receiver.getGateway(), job.getJobId(), MediaFileCountDTO.builder().jobId(receiver.getBid()).mediaCount(job.getMediaCount()).uploadedCount(0).build()); } @@ -93,9 +99,9 @@ public class FlightTaskServiceImpl implements IFlightTaskService { } waylineJobService.updateJob(job); - RedisOpsUtils.del(receiver.getBid()); + RedisOpsUtils.del(key); + RedisOpsUtils.del(RedisConst.WAYLINE_JOB_PAUSED_PREFIX + receiver.getBid()); } - RedisOpsUtils.setWithExpire(receiver.getBid(), eventsReceiver, RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); websocketMessageService.sendBatch( @@ -108,8 +114,7 @@ public class FlightTaskServiceImpl implements IFlightTaskService { .build()); if (receiver.getNeedReply() == 1) { - String topic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF; - messageSender.publish(topic, + messageSender.publish(receivedTopic + TopicConst._REPLY_SUF, CommonTopicResponse.builder() .tid(receiver.getTid()) .bid(receiver.getBid()) @@ -122,39 +127,42 @@ public class FlightTaskServiceImpl implements IFlightTaskService { @Scheduled(initialDelay = 10, fixedRate = 5, timeUnit = TimeUnit.SECONDS) private void checkScheduledJob() { - Object jobIdValue = RedisOpsUtils.zGetMin(RedisConst.WAYLINE_JOB); - log.info("Check the timed jobs of the wayline. {}", jobIdValue); + Object jobIdValue = RedisOpsUtils.zGetMin(RedisConst.WAYLINE_JOB_TIMED_EXECUTE); if (Objects.isNull(jobIdValue)) { return; } - String jobId = String.valueOf(jobIdValue); - double time = RedisOpsUtils.zScore(RedisConst.WAYLINE_JOB, jobIdValue); + log.info("Check the timed tasks of the wayline. {}", jobIdValue); + // format: {workspace_id}:{dock_sn}:{job_id} + String[] jobArr = String.valueOf(jobIdValue).split(RedisConst.DELIMITER); + double time = RedisOpsUtils.zScore(RedisConst.WAYLINE_JOB_TIMED_EXECUTE, jobIdValue); long now = System.currentTimeMillis(); int offset = 30_000; // Expired tasks are deleted directly. if (time < now - offset) { - RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB, jobId); + RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB_TIMED_EXECUTE, jobIdValue); waylineJobService.updateJob(WaylineJobDTO.builder() - .jobId(jobId) + .jobId(jobArr[2]) .status(WaylineJobStatusEnum.FAILED.getVal()) - .endTime(LocalDateTime.now()) + .executeTime(LocalDateTime.now()) + .completedTime(LocalDateTime.now()) .code(HttpStatus.SC_REQUEST_TIMEOUT).build()); return; } if (now <= time && time <= now + offset) { try { - waylineJobService.executeFlightTask(jobId); + waylineJobService.executeFlightTask(jobArr[0], jobArr[2]); } catch (Exception e) { log.info("The scheduled task delivery failed."); waylineJobService.updateJob(WaylineJobDTO.builder() - .jobId(jobId) + .jobId(jobArr[2]) .status(WaylineJobStatusEnum.FAILED.getVal()) - .endTime(LocalDateTime.now()) + .executeTime(LocalDateTime.now()) + .completedTime(LocalDateTime.now()) .code(HttpStatus.SC_INTERNAL_SERVER_ERROR).build()); } finally { - RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB, jobId); + RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB_TIMED_EXECUTE, jobIdValue); } } } 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 60af321..f540b66 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 @@ -187,7 +187,7 @@ public class WaylineFileServiceImpl implements IWaylineFileService { ZipEntry nextEntry = unzipFile.getNextEntry(); while (Objects.nonNull(nextEntry)) { - boolean isWaylines = (KmzFileProperties.FILE_DIR_FIRST + File.separator + KmzFileProperties.FILE_DIR_SECOND_WAYLINES).equals(nextEntry.getName()); + boolean isWaylines = (KmzFileProperties.FILE_DIR_FIRST + "/" + KmzFileProperties.FILE_DIR_SECOND_WAYLINES).equals(nextEntry.getName()); if (!isWaylines) { nextEntry = unzipFile.getNextEntry(); continue; 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 067a3fc..acbeabe 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 @@ -40,9 +40,7 @@ import org.springframework.util.CollectionUtils; import java.net.URL; import java.sql.SQLException; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; +import java.time.*; import java.util.*; import java.util.stream.Collectors; @@ -74,23 +72,29 @@ public class WaylineJobServiceImpl implements IWaylineJobService { @Autowired private IFileService fileService; + private Optional insertWaylineJob(WaylineJobEntity jobEntity) { + int id = mapper.insert(jobEntity); + if (id <= 0) { + return Optional.empty(); + } + return Optional.ofNullable(this.entity2Dto(jobEntity)); + } + @Override - public Optional createWaylineJob(CreateJobParam param, CustomClaim customClaim) { + public Optional createWaylineJob(CreateJobParam param, String workspaceId, String username, Long beginTime, Long endTime) { if (Objects.isNull(param)) { return Optional.empty(); } // Immediate tasks, allocating time on the backend. - if (Objects.isNull(param.getExecuteTime())) { - param.setExecuteTime(System.currentTimeMillis()); - } WaylineJobEntity jobEntity = WaylineJobEntity.builder() .name(param.getName()) .dockSn(param.getDockSn()) .fileId(param.getFileId()) - .username(customClaim.getUsername()) - .workspaceId(customClaim.getWorkspaceId()) + .username(username) + .workspaceId(workspaceId) .jobId(UUID.randomUUID().toString()) - .executeTime(param.getExecuteTime()) + .beginTime(beginTime) + .endTime(endTime) .status(WaylineJobStatusEnum.PENDING.getVal()) .taskType(param.getTaskType()) .waylineType(param.getWaylineType()) @@ -98,16 +102,35 @@ public class WaylineJobServiceImpl implements IWaylineJobService { .rthAltitude(param.getRthAltitude()) .mediaCount(0) .build(); - int id = mapper.insert(jobEntity); - if (id <= 0) { + + return insertWaylineJob(jobEntity); + } + + @Override + public Optional createWaylineJobByParent(String workspaceId, String parentId) { + Optional parentJobOpt = this.getJobByJobId(workspaceId, parentId); + if (parentJobOpt.isEmpty()) { return Optional.empty(); } - return Optional.ofNullable(this.entity2Dto(jobEntity)); + WaylineJobEntity jobEntity = this.dto2Entity(parentJobOpt.get()); + jobEntity.setJobId(UUID.randomUUID().toString()); + jobEntity.setErrorCode(null); + jobEntity.setCompletedTime(null); + jobEntity.setExecuteTime(null); + jobEntity.setStatus(WaylineJobStatusEnum.PENDING.getVal()); + jobEntity.setParentId(parentId); + + return this.insertWaylineJob(jobEntity); } @Override public ResponseResult publishFlightTask(CreateJobParam param, CustomClaim customClaim) throws SQLException { - Optional waylineJobOpt = this.createWaylineJob(param, customClaim); + if (WaylineTaskTypeEnum.IMMEDIATE.getVal() == param.getTaskType()) { + param.setExecuteTime(System.currentTimeMillis()); + } + Optional waylineJobOpt = this.createWaylineJob(param, + customClaim.getWorkspaceId(), customClaim.getUsername(), + param.getExecuteTime(), param.getExecuteTime()); if (waylineJobOpt.isEmpty()) { throw new SQLException("Failed to create wayline job."); } @@ -127,14 +150,14 @@ public class WaylineJobServiceImpl implements IWaylineJobService { // get file url URL url = waylineFileService.getObjectUrl(waylineJob.getWorkspaceId(), waylineFile.get().getWaylineId()); - FlightTaskCreateDTO flightTask = FlightTaskCreateDTO.builder() + WaylineTaskCreateDTO flightTask = WaylineTaskCreateDTO.builder() .flightId(waylineJob.getJobId()) - .executeTime(waylineJob.getExecuteTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()) + .executeTime(waylineJob.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()) .taskType(waylineJob.getTaskType()) .waylineType(waylineJob.getWaylineType()) .rthAltitude(waylineJob.getRthAltitude()) .outOfControlAction(waylineJob.getOutOfControlAction()) - .file(FlightTaskFileDTO.builder() + .file(WaylineTaskFileDTO.builder() .url(url.toString()) .fingerprint(waylineFile.get().getSign()) .build()) @@ -156,22 +179,24 @@ public class WaylineJobServiceImpl implements IWaylineJobService { this.updateJob(WaylineJobDTO.builder() .workspaceId(waylineJob.getWorkspaceId()) .jobId(waylineJob.getJobId()) + .executeTime(LocalDateTime.now()) .status(WaylineJobStatusEnum.FAILED.getVal()) - .endTime(LocalDateTime.now()) + .completedTime(LocalDateTime.now()) .code(serviceReply.getResult()).build()); return ResponseResult.error("Prepare task ====> Error code: " + serviceReply.getResult()); } // Issue an immediate task execution command. if (WaylineTaskTypeEnum.IMMEDIATE.getVal() == waylineJob.getTaskType()) { - if (!executeFlightTask(waylineJob.getJobId())) { + if (!executeFlightTask(waylineJob.getWorkspaceId(), waylineJob.getJobId())) { return ResponseResult.error("Failed to execute job."); } } if (WaylineTaskTypeEnum.TIMED.getVal() == waylineJob.getTaskType()) { - boolean isAdd = RedisOpsUtils.zAdd(RedisConst.WAYLINE_JOB, waylineJob.getJobId(), - waylineJob.getExecuteTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); + boolean isAdd = RedisOpsUtils.zAdd(RedisConst.WAYLINE_JOB_TIMED_EXECUTE, + waylineJob.getWorkspaceId() + RedisConst.DELIMITER + waylineJob.getDockSn() + RedisConst.DELIMITER + waylineJob.getJobId(), + waylineJob.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); if (!isAdd) { return ResponseResult.error("Failed to create scheduled job."); } @@ -181,9 +206,9 @@ public class WaylineJobServiceImpl implements IWaylineJobService { } @Override - public Boolean executeFlightTask(String jobId) { + public Boolean executeFlightTask(String workspaceId, String jobId) { // get job - Optional waylineJob = this.getJobByJobId(jobId); + Optional waylineJob = this.getJobByJobId(workspaceId, jobId); if (waylineJob.isEmpty()) { throw new IllegalArgumentException("Job doesn't exist."); } @@ -194,7 +219,7 @@ public class WaylineJobServiceImpl implements IWaylineJobService { } WaylineJobDTO job = waylineJob.get(); - FlightTaskCreateDTO flightTask = FlightTaskCreateDTO.builder().flightId(jobId).build(); + WaylineTaskCreateDTO flightTask = WaylineTaskCreateDTO.builder().flightId(jobId).build(); String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + job.getDockSn() + TopicConst.SERVICES_SUF; @@ -211,53 +236,45 @@ public class WaylineJobServiceImpl implements IWaylineJobService { log.info("Execute job ====> Error code: {}", serviceReply.getResult()); this.updateJob(WaylineJobDTO.builder() .jobId(jobId) + .executeTime(LocalDateTime.now()) .status(WaylineJobStatusEnum.FAILED.getVal()) - .endTime(LocalDateTime.now()) + .completedTime(LocalDateTime.now()) .code(serviceReply.getResult()).build()); return false; } this.updateJob(WaylineJobDTO.builder() .jobId(jobId) + .executeTime(LocalDateTime.now()) .status(WaylineJobStatusEnum.IN_PROGRESS.getVal()) .build()); - RedisOpsUtils.setWithExpire(jobId, - EventsReceiver.builder().bid(jobId).sn(job.getDockSn()).build(), + RedisOpsUtils.setWithExpire(RedisConst.WAYLINE_JOB_RUNNING_PREFIX + job.getDockSn(), + EventsReceiver.builder().bid(jobId).sn(job.getDockSn()).build(), RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); return true; } @Override public void cancelFlightTask(String workspaceId, Collection jobIds) { - List waylineJobs = mapper.selectList( - new LambdaQueryWrapper() - .or(wrapper -> jobIds.forEach(id -> wrapper.eq(WaylineJobEntity::getJobId, id)))); + List waylineJobs = getJobsByConditions(workspaceId, jobIds, WaylineJobStatusEnum.PENDING); - // Check if the job have ended. - List endJobs = waylineJobs.stream() - .filter(job -> WaylineJobStatusEnum.find(job.getStatus()).getEnd()) - .map(WaylineJobEntity::getName) - .collect(Collectors.toList()); - if (!CollectionUtils.isEmpty(endJobs)) { - throw new IllegalArgumentException("There are jobs that have ended." + Arrays.toString(endJobs.toArray())); - } - - Set ids = waylineJobs.stream().map(WaylineJobEntity::getJobId).collect(Collectors.toSet()); - for (String id : jobIds) { - if (!ids.contains(id)) { - throw new IllegalArgumentException("Job id " + id + " doesn't exist."); - } + Set waylineJobIds = waylineJobs.stream().map(WaylineJobDTO::getJobId).collect(Collectors.toSet()); + // Check if the task status is correct. + boolean isErr = !jobIds.removeAll(waylineJobIds) || !jobIds.isEmpty() ; + if (isErr) { + throw new IllegalArgumentException("These tasks have an incorrect status and cannot be canceled. " + + Arrays.toString(jobIds.toArray())); } // Group job id by dock sn. Map> dockJobs = waylineJobs.stream() - .collect(Collectors.groupingBy(WaylineJobEntity::getDockSn, - Collectors.mapping(WaylineJobEntity::getJobId, Collectors.toList()))); + .collect(Collectors.groupingBy(WaylineJobDTO::getDockSn, + Collectors.mapping(WaylineJobDTO::getJobId, Collectors.toList()))); dockJobs.forEach((dockSn, idList) -> this.publishCancelTask(workspaceId, dockSn, idList)); } - private void publishCancelTask(String workspaceId, String dockSn, List jobIds) { + public void publishCancelTask(String workspaceId, String dockSn, List jobIds) { boolean isOnline = deviceService.checkDeviceOnline(dockSn); if (!isOnline) { throw new RuntimeException("Dock is offline."); @@ -283,17 +300,30 @@ public class WaylineJobServiceImpl implements IWaylineJobService { .workspaceId(workspaceId) .jobId(jobId) .status(WaylineJobStatusEnum.CANCEL.getVal()) - .endTime(LocalDateTime.now()) + .completedTime(LocalDateTime.now()) .build()); - RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB, jobId); + RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB_TIMED_EXECUTE, workspaceId + RedisConst.DELIMITER + dockSn + RedisConst.DELIMITER + jobId); } } + public List getJobsByConditions(String workspaceId, Collection jobIds, WaylineJobStatusEnum status) { + return mapper.selectList( + new LambdaQueryWrapper() + .eq(WaylineJobEntity::getWorkspaceId, workspaceId) + .eq(Objects.nonNull(status), WaylineJobEntity::getStatus, status.getVal()) + .and(!CollectionUtils.isEmpty(jobIds), + wrapper -> jobIds.forEach(id -> wrapper.eq(WaylineJobEntity::getJobId, id).or()))) + .stream() + .map(this::entity2Dto) + .collect(Collectors.toList()); + } + @Override - public Optional getJobByJobId(String jobId) { + public Optional getJobByJobId(String workspaceId, String jobId) { WaylineJobEntity jobEntity = mapper.selectOne( new LambdaQueryWrapper() + .eq(WaylineJobEntity::getWorkspaceId, workspaceId) .eq(WaylineJobEntity::getJobId, jobId)); return Optional.ofNullable(entity2Dto(jobEntity)); } @@ -336,7 +366,8 @@ public class WaylineJobServiceImpl implements IWaylineJobService { String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString() + TopicConst._REPLY_SUF; - Optional waylineJobOpt = this.getJobByJobId(jobId); + DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); + Optional waylineJobOpt = this.getJobByJobId(device.getWorkspaceId(), jobId); if (waylineJobOpt.isEmpty()) { builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT)); messageSender.publish(topic, builder.build()); @@ -357,8 +388,8 @@ public class WaylineJobServiceImpl implements IWaylineJobService { URL url = null; try { url = waylineFileService.getObjectUrl(waylineJob.getWorkspaceId(), waylineFile.get().getWaylineId()); - builder.data(RequestsReply.success(FlightTaskCreateDTO.builder() - .file(FlightTaskFileDTO.builder() + builder.data(RequestsReply.success(WaylineTaskCreateDTO.builder() + .file(WaylineTaskFileDTO.builder() .url(url.toString()) .fingerprint(waylineFile.get().getSign()) .build()) @@ -377,14 +408,15 @@ public class WaylineJobServiceImpl implements IWaylineJobService { @Override public void uploadMediaHighestPriority(String workspaceId, String jobId) { - Optional jobOpt = getJobByJobId(jobId); + Optional jobOpt = getJobByJobId(workspaceId, jobId); if (jobOpt.isEmpty()) { throw new RuntimeException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg()); } String dockSn = jobOpt.get().getDockSn(); String key = RedisConst.MEDIA_HIGHEST_PRIORITY_PREFIX + dockSn; - if (RedisOpsUtils.checkExist(key) && jobId.equals(RedisOpsUtils.get(key).toString())) { + if (RedisOpsUtils.checkExist(key) && + jobId.equals(((MediaFileCountDTO) RedisOpsUtils.get(key)).getJobId())) { return; } @@ -399,7 +431,6 @@ public class WaylineJobServiceImpl implements IWaylineJobService { if (ResponseResult.CODE_SUCCESS != reply.getResult()) { throw new RuntimeException("Failed to set media job upload priority. Error Code: " + reply.getResult()); } - RedisOpsUtils.setWithExpire(key, jobId, RedisConst.DEVICE_ALIVE_SECOND * 5); } private WaylineJobEntity dto2Entity(WaylineJobDTO dto) { @@ -407,16 +438,32 @@ public class WaylineJobServiceImpl implements IWaylineJobService { if (dto == null) { return builder.build(); } + if (Objects.nonNull(dto.getBeginTime())) { + builder.beginTime(dto.getBeginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); + } if (Objects.nonNull(dto.getEndTime())) { builder.endTime(dto.getEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } if (Objects.nonNull(dto.getExecuteTime())) { builder.executeTime(dto.getExecuteTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); } + if (Objects.nonNull(dto.getCompletedTime())) { + builder.completedTime(dto.getCompletedTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); + } return builder.status(dto.getStatus()) .mediaCount(dto.getMediaCount()) .name(dto.getJobName()) .errorCode(dto.getCode()) + .jobId(dto.getJobId()) + .fileId(dto.getFileId()) + .dockSn(dto.getDockSn()) + .workspaceId(dto.getWorkspaceId()) + .taskType(dto.getTaskType()) + .waylineType(dto.getWaylineType()) + .username(dto.getUsername()) + .rthAltitude(dto.getRthAltitude()) + .outOfControlAction(dto.getOutOfControlAction()) + .parentId(dto.getParentId()) .build(); } @@ -436,9 +483,17 @@ public class WaylineJobServiceImpl implements IWaylineJobService { .orElse(DeviceDTO.builder().build()).getNickname()) .username(entity.getUsername()) .workspaceId(entity.getWorkspaceId()) - .status(entity.getStatus()) + .status(WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() && + RedisOpsUtils.checkExist(RedisConst.WAYLINE_JOB_PAUSED_PREFIX + entity.getJobId()) ? + WaylineJobStatusEnum.PAUSED.getVal() : entity.getStatus()) .code(entity.getErrorCode()) - .executeTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getExecuteTime()), ZoneId.systemDefault())) + .beginTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getBeginTime()), ZoneId.systemDefault())) + .endTime(Objects.nonNull(entity.getEndTime()) ? + LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getEndTime()), ZoneId.systemDefault()) : null) + .executeTime(Objects.nonNull(entity.getExecuteTime()) ? + LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getExecuteTime()), ZoneId.systemDefault()) : null) + .completedTime(WaylineJobStatusEnum.find(entity.getStatus()).getEnd() ? + LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getUpdateTime()), ZoneId.systemDefault()) : null) .taskType(entity.getTaskType()) .waylineType(entity.getWaylineType()) .rthAltitude(entity.getRthAltitude()) @@ -449,7 +504,7 @@ public class WaylineJobServiceImpl implements IWaylineJobService { builder.endTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getEndTime()), ZoneId.systemDefault())); } if (WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() && RedisOpsUtils.getExpire(entity.getJobId()) > 0) { - EventsReceiver taskProgress = (EventsReceiver) RedisOpsUtils.get(entity.getJobId()); + EventsReceiver taskProgress = (EventsReceiver) RedisOpsUtils.get(RedisConst.WAYLINE_JOB_RUNNING_PREFIX + entity.getDockSn()); if (Objects.nonNull(taskProgress.getOutput()) && Objects.nonNull(taskProgress.getOutput().getProgress())) { builder.progress(taskProgress.getOutput().getProgress().getPercent()); } @@ -465,7 +520,7 @@ public class WaylineJobServiceImpl implements IWaylineJobService { Object mediaFileCount = RedisOpsUtils.hashGet(countKey, entity.getJobId()); if (Objects.nonNull(mediaFileCount)) { builder.uploadedCount(((MediaFileCountDTO) mediaFileCount).getUploadedCount()) - .uploading(RedisOpsUtils.checkExist(key) && entity.getJobId().equals(RedisOpsUtils.get(key))); + .uploading(RedisOpsUtils.checkExist(key) && entity.getJobId().equals(((MediaFileCountDTO)RedisOpsUtils.get(key)).getJobId())); return builder.build(); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index de9dcfd..75c4872 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -39,14 +39,19 @@ jwt: age: 86400 mqtt: - protocol: tcp - host: Please enter your ip. # 192.168.1.1 - port: 1883 - username: JavaServer - password: 123456 - client-id: 123456 - # Topics that need to be subscribed when initially connecting to mqtt, multiple topics are divided by ",". - inbound-topic: sys/product/+/status,thing/product/+/requests + # @see com.dji.sample.component.mqtt.model.MqttUseEnum + # BASIC parameters are required. + BASIC: + protocol: MQTT # @see com.dji.sample.component.mqtt.model.MqttProtocolEnum + host: Please enter your ip. + port: 1883 + username: JavaServer + password: 123456 + client-id: 123456 + # If the protocol is ws/wss, this value is required. + path: + # Topics that need to be subscribed when initially connecting to mqtt, multiple topics are divided by ",". + inbound-topic: sys/product/+/status,thing/product/+/requests url: manage: @@ -68,7 +73,7 @@ url: prefix: /control version: /api/v1 -# Tutorial: https://help.aliyun.com/document_detail/100624.htm?spm=a2c4g.11186623.0.0.74075e34eIhK7T#concept-xzh-nzk-2gb +# Tutorial: https://www.alibabacloud.com/help/en/object-storage-service/latest/use-a-temporary-credential-provided-by-sts-to-access-oss oss: enable: true provider: ali # @see com.dji.sample.component.OssConfiguration.model.enums.OssTypeEnum @@ -114,4 +119,11 @@ logging: ntp: server: - host: Google.mzr.me \ No newline at end of file + host: Google.mzr.me + +# To create a license for an application: https://developer.dji.com/user/apps/#all +cloud-api: + app: + id: Please enter the app id. + key: Please enter the app key. + license: Please enter the app license. \ No newline at end of file