initial v1.3.1
Added:
1. Device communication backup link switching.
2. Priority report of the media file uploading.
3. Upload firmware file.
4. HMS updated.
Fixed:
1. Closing the stream prematurely.
Note: There is a change in the structure of the table 'manage_device_firmware'.
55 files modified
11 files added
1 files deleted
| | |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Get All Firmwares", |
| | | "request": { |
| | | "method": "GET", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/firmwares?page=1&page_size=50", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "firmwares" |
| | | ], |
| | | "query": [ |
| | | { |
| | | "key": "device_name", |
| | | "value": null, |
| | | "disabled": true |
| | | }, |
| | | { |
| | | "key": "product_version", |
| | | "value": null, |
| | | "disabled": true |
| | | }, |
| | | { |
| | | "key": "status", |
| | | "value": "true", |
| | | "disabled": true |
| | | }, |
| | | { |
| | | "key": "page", |
| | | "value": "1" |
| | | }, |
| | | { |
| | | "key": "page_size", |
| | | "value": "50" |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Import Firmware File", |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "formdata", |
| | | "formdata": [ |
| | | { |
| | | "key": "file", |
| | | "type": "file", |
| | | "src": [] |
| | | }, |
| | | { |
| | | "key": "release_note", |
| | | "value": "123", |
| | | "type": "text" |
| | | }, |
| | | { |
| | | "key": "device_name", |
| | | "value": "DJI Dock", |
| | | "type": "text" |
| | | }, |
| | | { |
| | | "key": "status", |
| | | "value": "0", |
| | | "type": "text" |
| | | } |
| | | ] |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/firmwares/file/upload", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "firmwares", |
| | | "file", |
| | | "upload" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Change Firmware Status", |
| | | "request": { |
| | | "method": "PUT", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"status\": false\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | | } |
| | | } |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/firmwares/{{firmware_id}}", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "firmwares", |
| | | "{{firmware_id}}" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | } |
| | | ], |
| | | "auth": { |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njc0NzcwNTUsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njc1NjM0NTUsImlhdCI6MTY2NzQ3NzA1NSwidXNlcm5hbWUiOiJhZG1pblBDIn0.VMJ0ZKn895uvkMDjg2fw3p4trVCUx9ltVFKeP7QmYpo", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NzAzMTU2MDEsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NzA0MDIwMDEsImlhdCI6MTY3MDMxNTYwMSwidXNlcm5hbWUiOiJhZG1pblBDIn0.yh8SkHZVsoIXo_vtlTGNB-ZX92XayalGe_q7mNRVcdI", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Set Media Highest", |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs/{{job_id}}/media-highest", |
| | | "host": [ |
| | | "{{base_url}}{{wayline_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "jobs", |
| | | "{{job_id}}", |
| | | "media-highest" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | } |
| | | ], |
| | | "auth": { |
| | |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"action\": 0\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | | } |
| | | } |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{control_version}}/devices/4TADK7E000000H/jobs/debug_mode_close", |
| | | "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/jobs/alarm_state_switch", |
| | | "host": [ |
| | | "{{base_url}}{{control_version}}" |
| | | ], |
| | | "path": [ |
| | | "devices", |
| | | "4TADK7E000000H", |
| | | "{{device_sn}}", |
| | | "jobs", |
| | | "debug_mode_close" |
| | | "alarm_state_switch" |
| | | ] |
| | | } |
| | | }, |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njg0MzE5MzQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njg1MTgzMzQsImlhdCI6MTY2ODQzMTkzNCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QU9xHBeQPHJ2V1vXQcGGWRQ-gYEOWDpaTTXIQga85BU", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njk2MzMzMzQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njk3MTk3MzQsImlhdCI6MTY2OTYzMzMzNCwidXNlcm5hbWUiOiJhZG1pblBDIn0.OoIfdpyI5eL6bFm8akq8_stzClQU41YpIJkx6_kxVHU", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | |
| | | <groupId>com.dji</groupId> |
| | | <artifactId>cloud-api-sample</artifactId> |
| | | <version>1.3.0</version> |
| | | <version>1.3.1</version> |
| | | <name>cloud-api-sample</name> |
| | | |
| | | <properties> |
| | |
| | | `firmware_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'uuid', |
| | | `file_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined' COMMENT 'The file name of the firmware package, including the file suffix', |
| | | `firmware_version` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'It needs to be formatted according to the official firmware version. 00.00.0000', |
| | | `file_url` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The download address for the firmware package.', |
| | | `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.', |
| | | `user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'The name of the creator.', |
| | | `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Availability of the firmware package. 1: available; 0: unavailable', |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL, |
| | |
| | | UNIQUE KEY `UNIQUE_firmware_id` (`firmware_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='Firmware file information'; |
| | | |
| | | LOCK TABLES `manage_device_firmware` WRITE; |
| | | /*!40000 ALTER TABLE `manage_device_firmware` DISABLE KEYS */; |
| | | |
| | | INSERT INTO `manage_device_firmware` (`id`, `firmware_id`, `file_name`, `firmware_version`, `file_url`, `file_size`, `file_md5`, `device_name`, `release_note`, `release_date`, `status`, `create_time`, `update_time`) |
| | | VALUES |
| | | (1,'1','Matrice_M30_Series_UAV_V04.01.00.20_Only_For_Pilot.zip','04.01.0020','https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/Matrice_M30_Series_UAV_V04.01.00.20_Only_For_Pilot.zip',605830726,'601630a5c753cd6665974cc8fd791bf5','Matrice 30','release note',1663232356810,1,1663232356810,1663232356810); |
| | | |
| | | /*!40000 ALTER TABLE `manage_device_firmware` ENABLE KEYS */; |
| | | UNLOCK TABLES; |
| | | |
| | | |
| | | # manage_device_hms |
| | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | /** |
| | | * Subscribe to the devices that exist in the redis when the program starts, |
| | | * to prevent the data from being different from the pilot side due to program interruptions. |
| | |
| | | public void run(String... args) throws Exception { |
| | | int start = RedisConst.DEVICE_ONLINE_PREFIX.length(); |
| | | |
| | | redisOps.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*") |
| | | RedisOpsUtils.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*") |
| | | .forEach(key -> deviceService.subscribeTopicOnline(key.substring(start))); |
| | | |
| | | } |
| | |
| | | package com.dji.sample.component; |
| | | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import org.springframework.validation.BindException; |
| | | import org.springframework.web.bind.MethodArgumentNotValidException; |
| | | import org.springframework.web.bind.annotation.ControllerAdvice; |
| | | import org.springframework.web.bind.annotation.ExceptionHandler; |
| | |
| | | return ResponseResult.error("A null object appeared."); |
| | | } |
| | | |
| | | @ExceptionHandler(MethodArgumentNotValidException.class) |
| | | public ResponseResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { |
| | | @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class}) |
| | | public ResponseResult methodArgumentNotValidExceptionHandler(BindException e) { |
| | | e.printStackTrace(); |
| | | return ResponseResult.error(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); |
| | | } |
| | | |
| | |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import com.dji.sample.wayline.service.IWaylineJobService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | private IMqttTopicService topicService; |
| | | |
| | | @Autowired |
| | | private IMqttTopicService topicService; |
| | | private IWaylineJobService waylineJobService; |
| | | |
| | | /** |
| | | * Check the status of the devices every 30 seconds. It is recommended to use cache. |
| | |
| | | private void deviceStatusListen() { |
| | | int start = RedisConst.DEVICE_ONLINE_PREFIX.length(); |
| | | |
| | | redisOps.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*").forEach(key -> { |
| | | long expire = redisOps.getExpire(key); |
| | | RedisOpsUtils.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*").forEach(key -> { |
| | | long expire = RedisOpsUtils.getExpire(key); |
| | | if (expire <= 30) { |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(key); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(key); |
| | | if (device.getDomain().equals(DeviceDomainEnum.SUB_DEVICE.getDesc())) { |
| | | deviceService.subDeviceOffline(key.substring(start)); |
| | | } else { |
| | | deviceService.unsubscribeTopicOffline(key.substring(start)); |
| | | deviceService.pushDeviceOfflineTopo(device.getWorkspaceId(), device.getDeviceSn()); |
| | | } |
| | | redisOps.del(key); |
| | | RedisOpsUtils.del(key); |
| | | } |
| | | }); |
| | | |
| | |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_EVENTS_HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA) |
| | | public MessageChannel eventsHighestPriorityUploadFlightTaskMedia() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | } |
| | |
| | | public static final String INBOUND_PROPERTY_SET_REPLY = "inboundPropertySetReply"; |
| | | |
| | | public static final String INBOUND_REQUESTS_CONFIG = "inboundRequestsConfig"; |
| | | |
| | | public static final String INBOUND_EVENTS_HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA = "inboundEventsHighestPriorityUploadFlightTaskMedia"; |
| | | } |
| | |
| | | |
| | | PROPERTY_SET_REPLY(Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + PROPERTY_SUF + SET_SUF + _REPLY_SUF + "$"), ChannelName.INBOUND_PROPERTY_SET_REPLY), |
| | | |
| | | UNKNOWN(null, ChannelName.DEFAULT); |
| | | UNKNOWN(Pattern.compile("^.*$"), ChannelName.DEFAULT); |
| | | |
| | | Pattern pattern; |
| | | |
| | |
| | | |
| | | FILE_UPLOAD_PROGRESS("fileupload_progress", ChannelName.INBOUND_EVENTS_FILE_UPLOAD_PROGRESS), |
| | | |
| | | HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA("highest_priority_upload_flighttask_media", ChannelName.INBOUND_EVENTS_HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA), |
| | | |
| | | UNKNOWN("Unknown", ChannelName.DEFAULT); |
| | | |
| | | private String method; |
| | |
| | | package com.dji.sample.component.oss.model; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | |
| | | */ |
| | | @ConfigurationProperties(prefix = "oss") |
| | | @Component |
| | | @Data |
| | | public class OssConfiguration { |
| | | |
| | | /** |
| | | * @see com.dji.sample.component.oss.model.enums.OssTypeEnum |
| | | */ |
| | | private String provider; |
| | | public static String provider; |
| | | |
| | | /** |
| | | * Whether to use the object storage service. |
| | | */ |
| | | private boolean enable; |
| | | public static boolean enable; |
| | | |
| | | /** |
| | | * The protocol needs to be included at the beginning of the address. |
| | | */ |
| | | private String endpoint; |
| | | public static String endpoint; |
| | | |
| | | private String accessKey; |
| | | public static String accessKey; |
| | | |
| | | private String secretKey; |
| | | public static String secretKey; |
| | | |
| | | private String region; |
| | | public static String region; |
| | | |
| | | private Long expire; |
| | | public static Long expire; |
| | | |
| | | private String roleSessionName; |
| | | public static String roleSessionName; |
| | | |
| | | private String roleArn; |
| | | public static String roleArn; |
| | | |
| | | private String bucket; |
| | | public static String bucket; |
| | | |
| | | private String objectDirPrefix; |
| | | public static String objectDirPrefix; |
| | | |
| | | public void setProvider(String provider) { |
| | | this.provider = provider; |
| | | OssConfiguration.provider = provider; |
| | | } |
| | | |
| | | public void setEnable(boolean enable) { |
| | | this.enable = enable; |
| | | OssConfiguration.enable = enable; |
| | | } |
| | | |
| | | public void setEndpoint(String endpoint) { |
| | | this.endpoint = endpoint; |
| | | OssConfiguration.endpoint = endpoint; |
| | | } |
| | | |
| | | public void setAccessKey(String accessKey) { |
| | | this.accessKey = accessKey; |
| | | OssConfiguration.accessKey = accessKey; |
| | | } |
| | | |
| | | public void setSecretKey(String secretKey) { |
| | | this.secretKey = secretKey; |
| | | OssConfiguration.secretKey = secretKey; |
| | | } |
| | | |
| | | public void setRegion(String region) { |
| | | this.region = region; |
| | | OssConfiguration.region = region; |
| | | } |
| | | |
| | | public void setExpire(Long expire) { |
| | | this.expire = expire; |
| | | OssConfiguration.expire = expire; |
| | | } |
| | | |
| | | public void setRoleSessionName(String roleSessionName) { |
| | | this.roleSessionName = roleSessionName; |
| | | OssConfiguration.roleSessionName = roleSessionName; |
| | | } |
| | | |
| | | public void setRoleArn(String roleArn) { |
| | | this.roleArn = roleArn; |
| | | OssConfiguration.roleArn = roleArn; |
| | | } |
| | | |
| | | public void setBucket(String bucket) { |
| | | this.bucket = bucket; |
| | | OssConfiguration.bucket = bucket; |
| | | } |
| | | |
| | | public void setObjectDirPrefix(String objectDirPrefix) { |
| | | this.objectDirPrefix = objectDirPrefix; |
| | | OssConfiguration.objectDirPrefix = objectDirPrefix; |
| | | } |
| | | } |
| | | |
| | |
| | | InputStream getObject(String bucket, String objectKey); |
| | | |
| | | void putObject(String bucket, String objectKey, InputStream input); |
| | | |
| | | void createClient(); |
| | | } |
| | |
| | | import com.aliyun.oss.OSS; |
| | | import com.aliyun.oss.OSSClientBuilder; |
| | | import com.aliyun.oss.OSSException; |
| | | import com.aliyun.oss.model.OSSObject; |
| | | import com.aliyun.oss.model.ObjectMetadata; |
| | | import com.aliyun.oss.model.PutObjectRequest; |
| | | import com.aliyun.oss.model.PutObjectResult; |
| | |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | | import java.util.Date; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | @Slf4j |
| | | public class AliyunOssServiceImpl implements IOssService { |
| | | |
| | | @Autowired |
| | | public OssConfiguration configuration; |
| | | |
| | | private OSS ossClient; |
| | | |
| | | @Override |
| | | public String getOssType() { |
| | | return OssTypeEnum.ALIYUN.getType(); |
| | |
| | | |
| | | try { |
| | | DefaultProfile profile = DefaultProfile.getProfile( |
| | | configuration.getRegion(), configuration.getAccessKey(), configuration.getSecretKey()); |
| | | OssConfiguration.region, OssConfiguration.accessKey, OssConfiguration.secretKey); |
| | | IAcsClient client = new DefaultAcsClient(profile); |
| | | |
| | | AssumeRoleRequest request = new AssumeRoleRequest(); |
| | | request.setDurationSeconds(configuration.getExpire()); |
| | | request.setRoleArn(configuration.getRoleArn()); |
| | | request.setRoleSessionName(configuration.getRoleSessionName()); |
| | | request.setDurationSeconds(OssConfiguration.expire); |
| | | request.setRoleArn(OssConfiguration.roleArn); |
| | | request.setRoleSessionName(OssConfiguration.roleSessionName); |
| | | |
| | | AssumeRoleResponse response = client.getAcsResponse(request); |
| | | return new CredentialsDTO(response.getCredentials(), configuration.getExpire()); |
| | | return new CredentialsDTO(response.getCredentials(), OssConfiguration.expire); |
| | | |
| | | } catch (ClientException e) { |
| | | log.debug("Failed to obtain sts."); |
| | |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | if (!StringUtils.hasText(bucket) || !StringUtils.hasText(objectKey)) { |
| | | return null; |
| | | } |
| | | OSS ossClient = this.createClient(); |
| | | // First check if the object can be fetched. |
| | | boolean isExist = ossClient.doesObjectExist(bucket, objectKey); |
| | | if (!isExist) { |
| | |
| | | } |
| | | |
| | | return ossClient.generatePresignedUrl(bucket, objectKey, |
| | | new Date(System.currentTimeMillis() + configuration.getExpire() * 1000)); |
| | | new Date(System.currentTimeMillis() + OssConfiguration.expire * 1000)); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | OSS ossClient = this.createClient(); |
| | | if (!ossClient.doesObjectExist(bucket, objectKey)) { |
| | | ossClient.shutdown(); |
| | | return true; |
| | | } |
| | | ossClient.deleteObject(bucket, objectKey); |
| | | ossClient.shutdown(); |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public InputStream getObject(String bucket, String objectKey) { |
| | | OSS ossClient = this.createClient(); |
| | | OSSObject object = ossClient.getObject(bucket, objectKey); |
| | | |
| | | try (InputStream input = object.getObjectContent()) { |
| | | return input; |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | ossClient.shutdown(); |
| | | } |
| | | return InputStream.nullInputStream(); |
| | | return ossClient.getObject(bucket, objectKey).getObjectContent(); |
| | | } |
| | | |
| | | @Override |
| | | public void putObject(String bucket, String objectKey, InputStream input) { |
| | | OSS ossClient = this.createClient(); |
| | | if (ossClient.doesObjectExist(bucket, objectKey)) { |
| | | ossClient.shutdown(); |
| | | throw new RuntimeException("The filename already exists."); |
| | | } |
| | | PutObjectResult objectResult = ossClient.putObject(new PutObjectRequest(bucket, objectKey, input, new ObjectMetadata())); |
| | | ossClient.shutdown(); |
| | | log.info("Upload File: {}", objectResult.getETag()); |
| | | } |
| | | |
| | | private OSS createClient() { |
| | | return new OSSClientBuilder() |
| | | .build(configuration.getEndpoint(), configuration.getAccessKey(), configuration.getSecretKey()); |
| | | public void createClient() { |
| | | if (Objects.nonNull(this.ossClient)) { |
| | | return; |
| | | } |
| | | this.ossClient = new OSSClientBuilder() |
| | | .build(OssConfiguration.endpoint, OssConfiguration.accessKey, OssConfiguration.secretKey); |
| | | } |
| | | } |
| | |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | @Service |
| | | public class AmazonS3ServiceImpl implements IOssService { |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | private AmazonS3 client; |
| | | |
| | | @Override |
| | | public String getOssType() { |
| | | return OssTypeEnum.AWS.getType(); |
| | |
| | | public CredentialsDTO getCredentials() { |
| | | AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard() |
| | | .withCredentials(new AWSStaticCredentialsProvider( |
| | | new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey()))) |
| | | .withRegion(configuration.getRegion()).build(); |
| | | new BasicAWSCredentials(OssConfiguration.accessKey, OssConfiguration.secretKey))) |
| | | .withRegion(OssConfiguration.region).build(); |
| | | |
| | | AssumeRoleRequest request = new AssumeRoleRequest() |
| | | .withRoleArn(configuration.getRoleArn()) |
| | | .withRoleSessionName(configuration.getRoleSessionName()) |
| | | .withDurationSeconds(Math.toIntExact(configuration.getExpire())); |
| | | .withRoleArn(OssConfiguration.roleArn) |
| | | .withRoleSessionName(OssConfiguration.roleSessionName) |
| | | .withDurationSeconds(Math.toIntExact(OssConfiguration.expire)); |
| | | AssumeRoleResult result = stsClient.assumeRole(request); |
| | | Credentials credentials = result.getCredentials(); |
| | | stsClient.shutdown(); |
| | | return new CredentialsDTO(credentials); |
| | | } |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | AmazonS3 client = this.createClient(); |
| | | URL url = client.generatePresignedUrl(bucket, objectKey, |
| | | new Date(System.currentTimeMillis() + configuration.getExpire() * 1000), HttpMethod.GET); |
| | | client.shutdown(); |
| | | return url; |
| | | return client.generatePresignedUrl(bucket, objectKey, |
| | | new Date(System.currentTimeMillis() + OssConfiguration.expire * 1000), HttpMethod.GET); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | AmazonS3 client = this.createClient(); |
| | | if (!client.doesObjectExist(bucket, objectKey)) { |
| | | client.shutdown(); |
| | | return true; |
| | | } |
| | | client.deleteObject(bucket, objectKey); |
| | | client.shutdown(); |
| | | return true; |
| | | } |
| | | |
| | | public InputStream getObject(String bucket, String objectKey) { |
| | | AmazonS3 client = this.createClient(); |
| | | S3Object object = client.getObject(bucket, objectKey); |
| | | try (InputStream input = object.getObjectContent().getDelegateStream()) { |
| | | return input; |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | client.shutdown(); |
| | | } |
| | | return InputStream.nullInputStream(); |
| | | return client.getObject(bucket, objectKey).getObjectContent().getDelegateStream(); |
| | | } |
| | | |
| | | @Override |
| | | public void putObject(String bucket, String objectKey, InputStream input) { |
| | | AmazonS3 client = this.createClient(); |
| | | if (client.doesObjectExist(bucket, objectKey)) { |
| | | client.shutdown(); |
| | | throw new RuntimeException("The filename already exists."); |
| | | } |
| | | PutObjectResult objectResult = client.putObject(new PutObjectRequest(bucket, objectKey, input, new ObjectMetadata())); |
| | | client.shutdown(); |
| | | log.info("Upload File: {}", objectResult.toString()); |
| | | } |
| | | |
| | | private AmazonS3 createClient() { |
| | | return AmazonS3ClientBuilder.standard() |
| | | public void createClient() { |
| | | if (Objects.nonNull(this.client)) { |
| | | return; |
| | | } |
| | | this.client = AmazonS3ClientBuilder.standard() |
| | | .withCredentials( |
| | | new AWSStaticCredentialsProvider( |
| | | new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey()))) |
| | | .withRegion(configuration.getRegion()) |
| | | new BasicAWSCredentials(OssConfiguration.accessKey, OssConfiguration.secretKey))) |
| | | .withRegion(OssConfiguration.region) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | */ |
| | | @PostConstruct |
| | | private void configCORS() { |
| | | if (!configuration.isEnable() || !OssTypeEnum.AWS.getType().equals(configuration.getProvider())) { |
| | | if (!OssConfiguration.enable || !OssTypeEnum.AWS.getType().equals(OssConfiguration.provider)) { |
| | | return; |
| | | } |
| | | List<CORSRule.AllowedMethods> allowedMethods = new ArrayList<>(); |
| | |
| | | .withAllowedHeaders(List.of(AuthInterceptor.PARAM_TOKEN)) |
| | | .withAllowedMethods(allowedMethods); |
| | | |
| | | AmazonS3 client = this.createClient(); |
| | | |
| | | client.setBucketCrossOriginConfiguration(this.configuration.getBucket(), |
| | | client.setBucketCrossOriginConfiguration(OssConfiguration.bucket, |
| | | new BucketCrossOriginConfiguration().withRules(rule)); |
| | | client.shutdown(); |
| | | |
| | | } |
| | | } |
| | |
| | | import io.minio.errors.*; |
| | | import io.minio.http.Method; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | |
| | | public class MinIOServiceImpl implements IOssService { |
| | | |
| | | private MinioClient client; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | |
| | | @Override |
| | | public String getOssType() { |
| | | return OssTypeEnum.MINIO.getType(); |
| | |
| | | @Override |
| | | public CredentialsDTO getCredentials() { |
| | | try { |
| | | AssumeRoleProvider provider = new AssumeRoleProvider(configuration.getEndpoint(), configuration.getAccessKey(), |
| | | configuration.getSecretKey(), Math.toIntExact(configuration.getExpire()), |
| | | null, configuration.getRegion(), null, null, null, null); |
| | | return new CredentialsDTO(provider.fetch(), configuration.getExpire()); |
| | | AssumeRoleProvider provider = new AssumeRoleProvider(OssConfiguration.endpoint, OssConfiguration.accessKey, |
| | | OssConfiguration.secretKey, Math.toIntExact(OssConfiguration.expire), |
| | | null, OssConfiguration.region, null, null, null, null); |
| | | return new CredentialsDTO(provider.fetch(), OssConfiguration.expire); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | log.debug("Failed to obtain sts."); |
| | | e.printStackTrace(); |
| | |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | try { |
| | | return new URL( |
| | | this.createClient() |
| | | .getPresignedObjectUrl( |
| | | client.getPresignedObjectUrl( |
| | | GetPresignedObjectUrlArgs.builder() |
| | | .method(Method.GET) |
| | | .bucket(bucket) |
| | | .object(objectKey) |
| | | .expiry(Math.toIntExact(configuration.getExpire())) |
| | | .expiry(Math.toIntExact(OssConfiguration.expire)) |
| | | .build())); |
| | | } catch (ErrorResponseException | InsufficientDataException | InternalException | |
| | | InvalidKeyException | InvalidResponseException | IOException | |
| | | NoSuchAlgorithmException | XmlParserException | ServerException e) { |
| | | log.error("The file does not exist on the OssConfiguration."); |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("The file does not exist on the OssConfiguration."); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | MinioClient client = this.createClient(); |
| | | try { |
| | | client.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectKey).build()); |
| | | } catch (MinioException | NoSuchAlgorithmException | IOException | InvalidKeyException e) { |
| | |
| | | @Override |
| | | public InputStream getObject(String bucket, String objectKey) { |
| | | try { |
| | | GetObjectResponse object = this.createClient().getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build()); |
| | | GetObjectResponse object = client.getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build()); |
| | | return new ByteArrayInputStream(object.readAllBytes()); |
| | | } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) { |
| | | e.printStackTrace(); |
| | |
| | | @Override |
| | | public void putObject(String bucket, String objectKey, InputStream input) { |
| | | try { |
| | | MinioClient client = this.createClient(); |
| | | client.statObject(StatObjectArgs.builder().bucket(bucket).object(objectKey).build()); |
| | | throw new RuntimeException("The filename already exists."); |
| | | } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) { |
| | |
| | | } |
| | | } |
| | | |
| | | private MinioClient createClient() { |
| | | public void createClient() { |
| | | if (Objects.nonNull(this.client)) { |
| | | return this.client; |
| | | return; |
| | | } |
| | | this.client = MinioClient.builder() |
| | | .endpoint(configuration.getEndpoint()) |
| | | .credentials(configuration.getAccessKey(), configuration.getSecretKey()) |
| | | .region(configuration.getRegion()) |
| | | .endpoint(OssConfiguration.endpoint) |
| | | .credentials(OssConfiguration.accessKey, OssConfiguration.secretKey) |
| | | .region(OssConfiguration.region) |
| | | .build(); |
| | | return this.client; |
| | | } |
| | | } |
| | |
| | | @Autowired |
| | | private OssServiceContext ossServiceContext; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Before("execution(public * com.dji.sample.component.oss.service.impl.OssServiceContext.*(..))") |
| | | public void before() { |
| | | if (!this.configuration.isEnable()) { |
| | | if (!OssConfiguration.enable) { |
| | | throw new IllegalArgumentException("Please enable OssConfiguration."); |
| | | } |
| | | if (this.ossServiceContext.getOssService() == null) { |
| | | throw new IllegalArgumentException("Please check the OssConfiguration configuration."); |
| | | } |
| | | this.ossServiceContext.createClient(); |
| | | } |
| | | } |
| | |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | |
| | | |
| | | private IOssService ossService; |
| | | |
| | | private OssConfiguration configuration; |
| | | |
| | | @Autowired |
| | | public OssServiceContext(List<IOssService> ossServices, OssConfiguration configuration) { |
| | | this.configuration = configuration; |
| | | if (!configuration.isEnable()) { |
| | | if (!OssConfiguration.enable) { |
| | | return; |
| | | } |
| | | this.ossService = ossServices.stream() |
| | | .filter(ossService -> ossService.getOssType().equals(configuration.getProvider())) |
| | | .filter(ossService -> ossService.getOssType().equals(OssConfiguration.provider)) |
| | | .findFirst() |
| | | .orElseThrow(() -> new IllegalArgumentException("Oss provider is illegal. Optional: " + |
| | | Arrays.toString(Arrays.stream(OssTypeEnum.values()).map(OssTypeEnum::getType).toArray()))); |
| | |
| | | } |
| | | |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | if (!StringUtils.hasText(bucket) || !StringUtils.hasText(objectKey)) { |
| | | throw new IllegalArgumentException(); |
| | | } |
| | | return this.ossService.getObjectUrl(bucket, objectKey); |
| | | } |
| | | |
| | |
| | | public void putObject(String bucket, String objectKey, InputStream stream) { |
| | | this.ossService.putObject(bucket, objectKey, stream); |
| | | } |
| | | |
| | | void createClient() { |
| | | this.ossService.createClient(); |
| | | } |
| | | } |
| | |
| | | public static final String WAYLINE_JOB = "wayline_job"; |
| | | |
| | | 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; |
| | | } |
| | |
| | | @Component |
| | | public class RedisOpsUtils { |
| | | |
| | | private static RedisTemplate<String, Object> redisTemplate; |
| | | |
| | | @Autowired |
| | | private RedisTemplate<String, Object> redisTemplate; |
| | | public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { |
| | | RedisOpsUtils.redisTemplate = redisTemplate; |
| | | } |
| | | |
| | | /** |
| | | * HSET |
| | |
| | | * @param field |
| | | * @param value |
| | | */ |
| | | public void hashSet(String key, String field, Object value) { |
| | | public static void hashSet(String key, String field, Object value) { |
| | | redisTemplate.opsForHash().put(key, field, value); |
| | | } |
| | | |
| | |
| | | * @param field |
| | | * @return |
| | | */ |
| | | public Object hashGet(String key, String field) { |
| | | public static Object hashGet(String key, String field) { |
| | | return redisTemplate.opsForHash().get(key, field); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Set<Object> hashKeys(String key) { |
| | | public static Set<Object> hashKeys(String key) { |
| | | return redisTemplate.opsForHash().keys(key); |
| | | } |
| | | |
| | |
| | | * @param field |
| | | * @return |
| | | */ |
| | | public boolean hashCheck(String key, String field) { |
| | | public static boolean hashCheck(String key, String field) { |
| | | return redisTemplate.opsForHash().hasKey(key, field); |
| | | } |
| | | |
| | |
| | | * @param fields |
| | | * @return |
| | | */ |
| | | public boolean hashDel(String key, Object[] fields) { |
| | | public static boolean hashDel(String key, Object[] fields) { |
| | | return redisTemplate.opsForHash().delete(key, fields) > 0; |
| | | } |
| | | |
| | | /** |
| | | * HLEN |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public static long hashLen(String key) { |
| | | return redisTemplate.opsForHash().size(key); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param timeout |
| | | * @return |
| | | */ |
| | | public boolean expireKey(String key, long timeout) { |
| | | public static boolean expireKey(String key, long timeout) { |
| | | return redisTemplate.expire(key, timeout, TimeUnit.SECONDS); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @param value |
| | | */ |
| | | public void set(String key, Object value) { |
| | | public static void set(String key, Object value) { |
| | | redisTemplate.opsForValue().set(key, value); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Object get(String key) { |
| | | public static Object get(String key) { |
| | | return redisTemplate.opsForValue().get(key); |
| | | } |
| | | |
| | |
| | | * @param value |
| | | * @param expire |
| | | */ |
| | | public void setWithExpire(String key, Object value, long expire) { |
| | | public static void setWithExpire(String key, Object value, long expire) { |
| | | redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public long getExpire(String key) { |
| | | public static long getExpire(String key) { |
| | | return redisTemplate.getExpire(key, TimeUnit.SECONDS); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public boolean checkExist(String key) { |
| | | public static boolean checkExist(String key) { |
| | | return redisTemplate.hasKey(key); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public boolean del(String key) { |
| | | return this.checkExist(key) && redisTemplate.delete(key); |
| | | public static boolean del(String key) { |
| | | return RedisOpsUtils.checkExist(key) && redisTemplate.delete(key); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param pattern |
| | | * @return |
| | | */ |
| | | public Set<String> getAllKeys(String pattern) { |
| | | public static Set<String> getAllKeys(String pattern) { |
| | | return redisTemplate.keys(pattern); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @param value |
| | | */ |
| | | public void listRPush(String key, Object... value) { |
| | | public static void listRPush(String key, Object... value) { |
| | | if (value.length == 0) { |
| | | return; |
| | | } |
| | |
| | | * @param end |
| | | * @return |
| | | */ |
| | | public List<Object> listGet(String key, long start, long end) { |
| | | public static List<Object> listGet(String key, long start, long end) { |
| | | return redisTemplate.opsForList().range(key, start, end); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public List<Object> listGetAll(String key) { |
| | | public static List<Object> listGetAll(String key) { |
| | | return redisTemplate.opsForList().range(key, 0, -1); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Long listLen(String key) { |
| | | public static Long listLen(String key) { |
| | | return redisTemplate.opsForList().size(key); |
| | | } |
| | | |
| | |
| | | * @param value |
| | | * @param score |
| | | */ |
| | | public Boolean zAdd(String key, Object value, double score) { |
| | | public static Boolean zAdd(String key, Object value, double score) { |
| | | return redisTemplate.opsForZSet().add(key, value, score); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @param value |
| | | */ |
| | | public Boolean zRemove(String key, Object... value) { |
| | | public static Boolean zRemove(String key, Object... value) { |
| | | return redisTemplate.opsForZSet().remove(key, value) > 0; |
| | | } |
| | | /** |
| | |
| | | * @param end |
| | | * @return |
| | | */ |
| | | public Set<Object> zRange(String key, long start, long end) { |
| | | public static Set<Object> zRange(String key, long start, long end) { |
| | | return redisTemplate.opsForZSet().range(key, start, end); |
| | | } |
| | | |
| | |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Object zGetMin(String key) { |
| | | public static Object zGetMin(String key) { |
| | | Set<Object> objects = zRange(key, 0, 0); |
| | | if (CollectionUtils.isEmpty(objects)) { |
| | | return null; |
| | |
| | | * @param value |
| | | * @return |
| | | */ |
| | | public Double zScore(String key, Object value) { |
| | | public static Double zScore(String key, Object value) { |
| | | return redisTemplate.opsForZSet().score(key, value); |
| | | } |
| | | |
| | |
| | | |
| | | CHARGE_OPEN("charge_open"), |
| | | |
| | | CHARGE_CLOSE("charge_close"); |
| | | CHARGE_CLOSE("charge_close"), |
| | | |
| | | FILE_UPLOAD_CALLBACK("file_upload_callback"), |
| | | |
| | | HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA("HIGHEST_PRIORITY_UPLOAD_FLIGHTTASK_MEDIA"); |
| | | |
| | | private String code; |
| | | |
| | |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | |
| | | public class WebSocketManageServiceImpl implements IWebSocketManageService { |
| | | |
| | | private static final ConcurrentHashMap<String, ConcurrentWebSocketSession> SESSIONS = new ConcurrentHashMap<>(16); |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | |
| | | @Override |
| | | public void put(String key, ConcurrentWebSocketSession val) { |
| | | String[] name = key.split("/"); |
| | |
| | | String sessionId = val.getId(); |
| | | String workspaceKey = RedisConst.WEBSOCKET_PREFIX + name[0]; |
| | | String userTypeKey = RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])).getDesc(); |
| | | redisOps.hashSet(workspaceKey, sessionId, name[2]); |
| | | redisOps.hashSet(userTypeKey, sessionId, name[2]); |
| | | RedisOpsUtils.hashSet(workspaceKey, sessionId, name[2]); |
| | | RedisOpsUtils.hashSet(userTypeKey, sessionId, name[2]); |
| | | SESSIONS.put(sessionId, val); |
| | | redisOps.expireKey(workspaceKey, RedisConst.WEBSOCKET_ALIVE_SECOND); |
| | | redisOps.expireKey(userTypeKey, RedisConst.WEBSOCKET_ALIVE_SECOND); |
| | | RedisOpsUtils.expireKey(workspaceKey, RedisConst.WEBSOCKET_ALIVE_SECOND); |
| | | RedisOpsUtils.expireKey(userTypeKey, RedisConst.WEBSOCKET_ALIVE_SECOND); |
| | | } |
| | | |
| | | @Override |
| | |
| | | log.debug("The key is out of format. [{workspaceId}/{userType}/{userId}]"); |
| | | return; |
| | | } |
| | | redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + name[0], new String[] {sessionId}); |
| | | redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])).getDesc(), new String[] {sessionId}); |
| | | RedisOpsUtils.hashDel(RedisConst.WEBSOCKET_PREFIX + name[0], new String[] {sessionId}); |
| | | RedisOpsUtils.hashDel(RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])).getDesc(), new String[] {sessionId}); |
| | | SESSIONS.remove(sessionId); |
| | | } |
| | | |
| | |
| | | } |
| | | String key = RedisConst.WEBSOCKET_PREFIX + workspaceId; |
| | | |
| | | return redisOps.hashKeys(key) |
| | | return RedisOpsUtils.hashKeys(key) |
| | | .stream() |
| | | .map(SESSIONS::get) |
| | | .filter(Objects::nonNull) |
| | |
| | | @Override |
| | | public Collection<ConcurrentWebSocketSession> getValueWithWorkspaceAndUserType(String workspaceId, Integer userType) { |
| | | String key = RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(userType).getDesc(); |
| | | return redisOps.hashKeys(key) |
| | | return RedisOpsUtils.hashKeys(key) |
| | | .stream() |
| | | .map(SESSIONS::get) |
| | | .filter(Objects::nonNull) |
| New file |
| | |
| | | package com.dji.sample.control.model.dto; |
| | | |
| | | import com.dji.sample.manage.model.enums.StateSwitchEnum; |
| | | import com.dji.sample.manage.model.receiver.BasicDeviceProperty; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/11/25 |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class AlarmState extends BasicDeviceProperty { |
| | | |
| | | private Integer action; |
| | | |
| | | @Override |
| | | public boolean valid() { |
| | | return Objects.nonNull(action) && StateSwitchEnum.find(action).isPresent(); |
| | | } |
| | | } |
| | |
| | | @NoArgsConstructor |
| | | public class BatteryStoreMode extends BasicDeviceProperty { |
| | | |
| | | private Integer value; |
| | | private Integer action; |
| | | |
| | | @Override |
| | | public boolean valid() { |
| | | return Objects.nonNull(value) && BatteryStoreModeEnum.find(value).isPresent(); |
| | | return Objects.nonNull(action) && BatteryStoreModeEnum.find(action).isPresent(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.control.model.dto; |
| | | |
| | | import com.dji.sample.control.model.enums.LinkWorkModeEnum; |
| | | import com.dji.sample.manage.model.receiver.BasicDeviceProperty; |
| | | import com.fasterxml.jackson.annotation.JsonProperty; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/11/25 |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class LinkWorkMode extends BasicDeviceProperty { |
| | | |
| | | @JsonProperty("link_workmode") |
| | | private Integer linkWorkMode; |
| | | |
| | | @Override |
| | | public boolean valid() { |
| | | return Objects.nonNull(linkWorkMode) && LinkWorkModeEnum.find(linkWorkMode).isPresent(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.control.model.enums; |
| | | |
| | | import lombok.Getter; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/11/25 |
| | | */ |
| | | @Getter |
| | | public enum LinkWorkModeEnum { |
| | | |
| | | SDR_ONLY(0), |
| | | |
| | | SDR_WITH_4G(1); |
| | | |
| | | int mode; |
| | | |
| | | LinkWorkModeEnum(Integer mode) { |
| | | this.mode = mode; |
| | | } |
| | | |
| | | public static Optional<LinkWorkModeEnum> find(int mode) { |
| | | return Arrays.stream(LinkWorkModeEnum.values()).filter(modeEnum -> modeEnum.mode == mode).findAny(); |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.control.model.enums; |
| | | |
| | | import com.dji.sample.control.model.dto.AlarmState; |
| | | import com.dji.sample.control.model.dto.BatteryStoreMode; |
| | | import com.dji.sample.manage.model.enums.StateSwitchReceiver; |
| | | import com.dji.sample.control.model.dto.LinkWorkMode; |
| | | import com.dji.sample.manage.model.receiver.BasicDeviceProperty; |
| | | import lombok.Getter; |
| | | |
| | |
| | | SUPPLEMENT_LIGHT_CLOSE("supplement_light_close", false, null), |
| | | |
| | | RETURN_HOME("return_home", false, null), |
| | | |
| | | SDR_WORKMODE_SWITCH("sdr_workmode_switch", false, null), |
| | | |
| | | DEVICE_REBOOT("device_reboot", true, null), |
| | | |
| | |
| | | |
| | | CHARGE_CLOSE("charge_close", true, null), |
| | | |
| | | BATTERY_MAINTENANCE_SWITCH("battery_maintenance_switch", true, StateSwitchReceiver.class), |
| | | BATTERY_MAINTENANCE_SWITCH("battery_maintenance_switch", true, AlarmState.class), |
| | | |
| | | ALARM_STATE_SWITCH("alarm_state_switch", true, StateSwitchReceiver.class), |
| | | ALARM_STATE_SWITCH("alarm_state_switch", true, AlarmState.class), |
| | | |
| | | BATTERY_STORE_MODE_SWITCH("battery_store_mode_switch", true, BatteryStoreMode.class), |
| | | |
| | | SDR_WORK_MODE_SWITCH("sdr_workmode_switch", false, LinkWorkMode.class), |
| | | |
| | | UNKNOWN("unknown", false, null); |
| | | |
| | |
| | | public class ControlServiceImpl implements IControlService { |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private IMessageSenderService messageSenderService; |
| | | |
| | | @Autowired |
| | |
| | | return ResponseResult.error("The " + serviceIdentifier + " method does not exist."); |
| | | } |
| | | |
| | | Object data = ""; |
| | | // Add parameter validation. |
| | | if (Objects.nonNull(controlMethodEnum.getClazz())) { |
| | | if (Objects.isNull(param)) { |
| | |
| | | if (!basicDeviceProperty.valid()) { |
| | | return ResponseResult.error(CommonErrorEnum.ILLEGAL_ARGUMENT); |
| | | } |
| | | data = basicDeviceProperty; |
| | | } |
| | | |
| | | boolean isExist = deviceService.checkDeviceOnline(sn); |
| | |
| | | .bid(bid) |
| | | .method(serviceIdentifier) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .data(Objects.requireNonNullElse(param, "")) |
| | | .data(data) |
| | | .build()); |
| | | |
| | | ServiceReply<EventsOutputReceiver> serviceReply = mapper.convertValue( |
| | | serviceReplyOpt, new TypeReference<ServiceReply<EventsOutputReceiver>>() {}); |
| | | if (ResponseResult.CODE_SUCCESS != serviceReply.getResult()) { |
| | | return ResponseResult.error(serviceReply.getResult(), serviceReply.getOutput().getStatus()); |
| | | return ResponseResult.error(serviceReply.getResult(), |
| | | Objects.nonNull(serviceReply.getOutput()) ? serviceReply.getOutput().getStatus() : "error: " + serviceIdentifier); |
| | | } |
| | | if (controlMethodEnum.getProgress()) { |
| | | redisOps.setWithExpire(serviceIdentifier + RedisConst.DELIMITER + bid, sn, |
| | | RedisOpsUtils.setWithExpire(serviceIdentifier + RedisConst.DELIMITER + bid, sn, |
| | | RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); |
| | | } |
| | | return ResponseResult.success(); |
| | |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS, outputChannel = ChannelName.OUTBOUND) |
| | | public void handleControlProgress(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | String key = receiver.getMethod() + RedisConst.DELIMITER + receiver.getBid(); |
| | | if (redisOps.getExpire(key) <= 0) { |
| | | if (RedisOpsUtils.getExpire(key) <= 0) { |
| | | return; |
| | | } |
| | | String sn = redisOps.get(key).toString(); |
| | | String sn = RedisOpsUtils.get(key).toString(); |
| | | |
| | | EventsReceiver<EventsOutputReceiver> eventsReceiver = mapper.convertValue(receiver.getData(), |
| | | new TypeReference<EventsReceiver<EventsOutputReceiver>>(){}); |
| | |
| | | |
| | | if (eventsReceiver.getOutput().getProgress().getPercent() == 100 || |
| | | EventsResultStatusEnum.find(eventsReceiver.getOutput().getStatus()).getEnd()) { |
| | | redisOps.del(key); |
| | | RedisOpsUtils.del(key); |
| | | } |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | webSocketMessageService.sendBatch( |
| | | webSocketManageService.getValueWithWorkspaceAndUserType( |
| | | device.getWorkspaceId(), UserTypeEnum.WEB.getVal()), |
| | |
| | | package com.dji.sample.manage.controller; |
| | | |
| | | import com.dji.sample.common.model.CustomClaim; |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareNoteDTO; |
| | | import com.dji.sample.manage.model.dto.FirmwareFileProperties; |
| | | import com.dji.sample.manage.model.param.DeviceFirmwareQueryParam; |
| | | import com.dji.sample.manage.model.param.DeviceFirmwareUpdateParam; |
| | | import com.dji.sample.manage.model.param.DeviceFirmwareUploadParam; |
| | | import com.dji.sample.manage.service.IDeviceFirmwareService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | 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 static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | */ |
| | | @RestController |
| | | @RequestMapping("${url.manage.prefix}${url.manage.version}/workspaces") |
| | | @Validated |
| | | public class DeviceFirmwareController { |
| | | |
| | | @Autowired |
| | |
| | | return ResponseResult.success(releaseNotes); |
| | | } |
| | | |
| | | /** |
| | | * Query firmware information based on parameters. |
| | | * @param workspaceId |
| | | * @param param |
| | | * @return |
| | | */ |
| | | @GetMapping("/{workspace_id}/firmwares") |
| | | public ResponseResult<PaginationData<DeviceFirmwareDTO>> getAllFirmwarePagination( |
| | | @PathVariable("workspace_id") String workspaceId, @Valid DeviceFirmwareQueryParam param) { |
| | | |
| | | PaginationData<DeviceFirmwareDTO> data = service.getAllFirmwarePagination(workspaceId, param); |
| | | return ResponseResult.success(data); |
| | | } |
| | | |
| | | /** |
| | | * Import firmware file for device upgrades. |
| | | * @param request |
| | | * @param workspaceId |
| | | * @param file |
| | | * @param param |
| | | * @return |
| | | */ |
| | | @PostMapping("/{workspace_id}/firmwares/file/upload") |
| | | public ResponseResult importFirmwareFile(HttpServletRequest request, @PathVariable("workspace_id") String workspaceId, |
| | | @NotNull(message = "No file received.") MultipartFile file, |
| | | @Valid DeviceFirmwareUploadParam param) { |
| | | |
| | | if (!file.getOriginalFilename().endsWith(FirmwareFileProperties.FIRMWARE_FILE_SUFFIX)) { |
| | | return ResponseResult.error("The file format is incorrect."); |
| | | } |
| | | |
| | | CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); |
| | | String creator = customClaim.getUsername(); |
| | | |
| | | service.importFirmwareFile(workspaceId, creator, param, file); |
| | | return ResponseResult.success(); |
| | | } |
| | | |
| | | /** |
| | | * Change the firmware availability status. |
| | | * @param workspaceId |
| | | * @param firmwareId |
| | | * @param param |
| | | * @return |
| | | */ |
| | | @PutMapping("/{workspace_id}/firmwares/{firmware_id}") |
| | | public ResponseResult importFirmwareFile(@PathVariable("workspace_id") String workspaceId, |
| | | @PathVariable("firmware_id") String firmwareId, |
| | | @Valid @RequestBody DeviceFirmwareUpdateParam param) { |
| | | |
| | | service.updateFirmwareInfo(DeviceFirmwareDTO.builder() |
| | | .firmwareId(firmwareId).firmwareStatus(param.getStatus()).build()); |
| | | return ResponseResult.success(); |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | |
| | | private String productVersion; |
| | | |
| | | private String fileUrl; |
| | | private String objectKey; |
| | | |
| | | private Long fileSize; |
| | | |
| | |
| | | private LocalDate releasedTime; |
| | | |
| | | private Boolean firmwareStatus; |
| | | |
| | | private String workspaceId; |
| | | |
| | | private String username; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.dto; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/12/1 |
| | | */ |
| | | public class FirmwareFileProperties { |
| | | |
| | | private FirmwareFileProperties() { |
| | | |
| | | } |
| | | |
| | | public static final String FIRMWARE_FILE_SUFFIX = ".zip"; |
| | | |
| | | public static final String FIRMWARE_SIG_FILE_SUFFIX = ".sig"; |
| | | |
| | | public static final String FIRMWARE_CONFIG_FILE_SUFFIX = ".cfg"; |
| | | |
| | | public static final String FIRMWARE_FILE_DELIMITER = "_"; |
| | | |
| | | public static final int FILENAME_VERSION_INDEX = 2; |
| | | |
| | | public static final int FILENAME_RELEASE_DATE_INDEX = 3; |
| | | |
| | | public static final String FILENAME_RELEASE_DATE_FORMAT = "yyyyMMdd"; |
| | | |
| | | } |
| | |
| | | @TableField("firmware_version") |
| | | private String firmwareVersion; |
| | | |
| | | @TableField("file_url") |
| | | private String fileUrl; |
| | | @TableField("object_key") |
| | | private String objectKey; |
| | | |
| | | @TableField("file_size") |
| | | private Long fileSize; |
| | |
| | | @TableField("status") |
| | | private Boolean status; |
| | | |
| | | @TableField("workspace_id") |
| | | private String workspaceId; |
| | | |
| | | @TableField("user_name") |
| | | private String username; |
| | | |
| | | @TableField(value = "create_time", fill = FieldFill.INSERT) |
| | | private Long createTime; |
| | | |
| | |
| | | package com.dji.sample.manage.model.enums; |
| | | |
| | | import com.dji.sample.manage.model.receiver.BasicDeviceProperty; |
| | | import com.dji.sample.manage.model.receiver.DistanceLimitStatusReceiver; |
| | | import com.dji.sample.manage.model.receiver.HeightLimitReceiver; |
| | | import com.dji.sample.manage.model.receiver.ObstacleAvoidanceReceiver; |
| | | import com.dji.sample.manage.model.receiver.*; |
| | | import lombok.Getter; |
| | | |
| | | import java.util.Arrays; |
| | |
| | | @Getter |
| | | public enum DeviceSetPropertyEnum { |
| | | |
| | | NIGHT_LIGHTS_STATE("night_lights_state", StateSwitchReceiver.class), |
| | | NIGHT_LIGHTS_STATE("night_lights_state", NightLightsStateReceiver.class), |
| | | |
| | | HEIGHT_LIMIT("height_limit", HeightLimitReceiver.class), |
| | | |
| New file |
| | |
| | | package com.dji.sample.manage.model.enums; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/10/28 |
| | | */ |
| | | public enum StateSwitchEnum { |
| | | |
| | | DISABLE, ENABLE; |
| | | |
| | | public static Optional<StateSwitchEnum> find(int value) { |
| | | return Arrays.stream(StateSwitchEnum.values()).filter(state -> state.ordinal() == value).findAny(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.param; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/12/1 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class DeviceFirmwareQueryParam { |
| | | |
| | | private String deviceName; |
| | | |
| | | private String productVersion; |
| | | |
| | | private Boolean status; |
| | | |
| | | @NotNull |
| | | private Long page; |
| | | |
| | | @NotNull |
| | | private Long pageSize; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.param; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/12/6 |
| | | */ |
| | | @Data |
| | | public class DeviceFirmwareUpdateParam { |
| | | |
| | | @NotNull |
| | | private Boolean status; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.param; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/12/1 |
| | | */ |
| | | @Data |
| | | public class DeviceFirmwareUploadParam { |
| | | |
| | | @NotNull |
| | | private String releaseNote; |
| | | |
| | | @NotNull |
| | | private Boolean status; |
| | | |
| | | @NotNull |
| | | private String deviceName; |
| | | } |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import com.dji.sample.manage.model.enums.StateSwitchReceiver; |
| | | import com.dji.sample.manage.model.enums.StateSwitchEnum; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.Objects; |
| | |
| | | * @version 1.3 |
| | | * @date 2022/10/27 |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | |
| | | public boolean valid() { |
| | | boolean valid = Objects.nonNull(state) || Objects.nonNull(distanceLimit); |
| | | if (Objects.nonNull(state)) { |
| | | valid = new StateSwitchReceiver(this.state).valid(); |
| | | valid = StateSwitchEnum.find(state).isPresent(); |
| | | } |
| | | if (Objects.nonNull(distanceLimit)) { |
| | | valid &= distanceLimit >= DISTANCE_MIN && distanceLimit <= DISTANCE_MAX; |
| | | valid &= StateSwitchEnum.find(distanceLimit).isPresent(); |
| | | } |
| | | return valid; |
| | | } |
| | |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.Objects; |
| | |
| | | * @version 1.3 |
| | | * @date 2022/10/28 |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import com.dji.sample.manage.model.enums.StateSwitchEnum; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.util.Objects; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/11/25 |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class NightLightsStateReceiver extends BasicDeviceProperty { |
| | | |
| | | private Integer value; |
| | | |
| | | @Override |
| | | public boolean valid() { |
| | | return Objects.nonNull(value) && StateSwitchEnum.find(value).isPresent(); |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import com.dji.sample.manage.model.enums.StateSwitchReceiver; |
| | | import com.dji.sample.manage.model.enums.StateSwitchEnum; |
| | | import lombok.Data; |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.util.Objects; |
| | | |
| | |
| | | * @version 1.3 |
| | | * @date 2022/10/27 |
| | | */ |
| | | @EqualsAndHashCode(callSuper = true) |
| | | @Data |
| | | public class ObstacleAvoidanceReceiver extends BasicDeviceProperty { |
| | | |
| | |
| | | public boolean valid() { |
| | | boolean valid = Objects.nonNull(this.horizon) || Objects.nonNull(this.upside) || Objects.nonNull(this.downside); |
| | | |
| | | StateSwitchReceiver stateSwitch = new StateSwitchReceiver(); |
| | | if (Objects.nonNull(this.horizon)) { |
| | | stateSwitch.setValue(this.horizon); |
| | | valid = stateSwitch.valid(); |
| | | valid = StateSwitchEnum.find(horizon).isPresent(); |
| | | } |
| | | if (Objects.nonNull(this.upside)) { |
| | | stateSwitch.setValue(this.upside); |
| | | valid &= stateSwitch.valid(); |
| | | valid &= StateSwitchEnum.find(upside).isPresent(); |
| | | } |
| | | if (Objects.nonNull(this.downside)) { |
| | | stateSwitch.setValue(this.downside); |
| | | valid &= stateSwitch.valid(); |
| | | valid &= StateSwitchEnum.find(downside).isPresent(); |
| | | } |
| | | return valid; |
| | | } |
| | |
| | | package com.dji.sample.manage.service; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareNoteDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO; |
| | | import com.dji.sample.manage.model.param.DeviceFirmwareQueryParam; |
| | | import com.dji.sample.manage.model.param.DeviceFirmwareUploadParam; |
| | | import com.dji.sample.manage.model.param.DeviceOtaCreateParam; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | |
| | | * @param headers |
| | | */ |
| | | void handleOtaProgress(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | |
| | | /** |
| | | * Query firmware version information by page. |
| | | * |
| | | * @param workspaceId |
| | | * @param param |
| | | * @return |
| | | */ |
| | | PaginationData<DeviceFirmwareDTO> getAllFirmwarePagination(String workspaceId, DeviceFirmwareQueryParam param); |
| | | |
| | | /** |
| | | * Checks for file existence based on md5. |
| | | * |
| | | * @param workspaceId |
| | | * @param fileMd5 |
| | | * @return |
| | | */ |
| | | Boolean checkFileExist(String workspaceId, String fileMd5); |
| | | |
| | | /** |
| | | * Import firmware file for device upgrades. |
| | | * @param workspaceId |
| | | * @param creator |
| | | * @param param |
| | | * @param file |
| | | */ |
| | | void importFirmwareFile(String workspaceId, String creator, DeviceFirmwareUploadParam param, MultipartFile file); |
| | | |
| | | /** |
| | | * Save the file information of the firmware. |
| | | * @param firmware |
| | | */ |
| | | void saveFirmwareInfo(DeviceFirmwareDTO firmware); |
| | | |
| | | /** |
| | | * Update the file information of the firmware. |
| | | * @param firmware |
| | | */ |
| | | void updateFirmwareInfo(DeviceFirmwareDTO firmware); |
| | | } |
| | |
| | | @Autowired |
| | | private IDeviceDictionaryService dictionaryService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public List<CapacityCameraDTO> getCapacityCameraByDeviceSn(String deviceSn) { |
| | | return (List<CapacityCameraDTO>) redisOps.hashGet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn); |
| | | return (List<CapacityCameraDTO>) RedisOpsUtils.hashGet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteCapacityCameraByDeviceSn(String deviceSn) { |
| | | return redisOps.hashDel(StateDataEnum.LIVE_CAPACITY.getDesc(), new String[]{deviceSn}); |
| | | return RedisOpsUtils.hashDel(StateDataEnum.LIVE_CAPACITY.getDesc(), new String[]{deviceSn}); |
| | | } |
| | | |
| | | @Override |
| | | public void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn, Long timestamp) { |
| | | List<CapacityCameraDTO> capacity = capacityCameraReceivers.stream() |
| | | .map(this::receiver2Dto).collect(Collectors.toList()); |
| | | redisOps.hashSet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn, capacity); |
| | | redisOps.setWithExpire(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + deviceSn, timestamp, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.hashSet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn, capacity); |
| | | RedisOpsUtils.setWithExpire(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + deviceSn, timestamp, RedisConst.DEVICE_ALIVE_SECOND); |
| | | } |
| | | |
| | | @Override |
| | |
| | | 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.extension.plugins.pagination.Page; |
| | | import com.dji.sample.common.model.Pagination; |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.mqtt.model.*; |
| | | import com.dji.sample.component.mqtt.service.impl.MessageSenderServiceImpl; |
| | | 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.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.component.websocket.service.impl.SendMessageServiceImpl; |
| | | import com.dji.sample.manage.dao.IDeviceFirmwareMapper; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareNoteDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO; |
| | | import com.dji.sample.manage.model.dto.*; |
| | | import com.dji.sample.manage.model.entity.DeviceFirmwareEntity; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.model.param.DeviceFirmwareQueryParam; |
| | | 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 org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.DigestUtils; |
| | | import org.springframework.util.StringUtils; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.time.Instant; |
| | | import java.time.LocalDate; |
| | | import java.time.ZoneId; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | import java.util.zip.ZipEntry; |
| | | import java.util.zip.ZipInputStream; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | |
| | | @Autowired |
| | | private IDeviceFirmwareMapper mapper; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private MessageSenderServiceImpl messageSenderService; |
| | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private OssServiceContext ossServiceContext; |
| | | |
| | | @Override |
| | | public Optional<DeviceFirmwareDTO> getFirmware(String deviceName, String version) { |
| | | return Optional.ofNullable(entity2Dto(mapper.selectOne( |
| | |
| | | new LambdaQueryWrapper<DeviceFirmwareEntity>() |
| | | .eq(DeviceFirmwareEntity::getDeviceName, deviceName) |
| | | .eq(DeviceFirmwareEntity::getStatus, true) |
| | | .orderByDesc(DeviceFirmwareEntity::getReleaseDate) |
| | | .orderByDesc(DeviceFirmwareEntity::getReleaseDate, DeviceFirmwareEntity::getFirmwareVersion) |
| | | .last(" limit 1 ")))); |
| | | } |
| | | |
| | |
| | | log.error("SN: {}, {} ===> Error code: {}", sn, receiver.getMethod(), eventsReceiver.getResult()); |
| | | } |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | String childDeviceSn = device.getChildDeviceSn(); |
| | | boolean upgrade = redisOps.getExpire(RedisConst.FIRMWARE_UPGRADING_PREFIX + sn) > 0; |
| | | boolean childUpgrade = redisOps.getExpire(RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn) > 0; |
| | | boolean upgrade = RedisOpsUtils.getExpire(RedisConst.FIRMWARE_UPGRADING_PREFIX + sn) > 0; |
| | | boolean childUpgrade = RedisOpsUtils.getExpire(RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn) > 0; |
| | | |
| | | // Determine whether it is the ending state, delete the update state key in redis after the job ends. |
| | | EventsResultStatusEnum statusEnum = EventsResultStatusEnum.find(output.getStatus()); |
| | | if (upgrade) { |
| | | if (statusEnum.getEnd()) { |
| | | // Delete the cache after the update is complete. |
| | | redisOps.del(RedisConst.FIRMWARE_UPGRADING_PREFIX + sn); |
| | | RedisOpsUtils.del(RedisConst.FIRMWARE_UPGRADING_PREFIX + sn); |
| | | } else { |
| | | // Update the update progress of the dock in redis. |
| | | redisOps.setWithExpire( |
| | | RedisOpsUtils.setWithExpire( |
| | | RedisConst.FIRMWARE_UPGRADING_PREFIX + sn, output.getProgress().getPercent(), |
| | | RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); |
| | | } |
| | | } |
| | | if (childUpgrade) { |
| | | if (statusEnum.getEnd()) { |
| | | redisOps.del(RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn); |
| | | RedisOpsUtils.del(RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn); |
| | | } else { |
| | | // Update the update progress of the drone in redis. |
| | | redisOps.setWithExpire( |
| | | RedisOpsUtils.setWithExpire( |
| | | RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn, output.getProgress().getPercent(), |
| | | RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Boolean checkFileExist(String workspaceId, String fileMd5) { |
| | | return mapper.selectCount(new LambdaQueryWrapper<DeviceFirmwareEntity>() |
| | | .eq(DeviceFirmwareEntity::getWorkspaceId, workspaceId) |
| | | .eq(DeviceFirmwareEntity::getFileMd5, fileMd5)) |
| | | > 0; |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<DeviceFirmwareDTO> getAllFirmwarePagination(String workspaceId, DeviceFirmwareQueryParam param) { |
| | | Page<DeviceFirmwareEntity> page = mapper.selectPage(new Page<>(param.getPage(), param.getPageSize()), |
| | | new LambdaQueryWrapper<DeviceFirmwareEntity>() |
| | | .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)); |
| | | |
| | | List<DeviceFirmwareDTO> data = page.getRecords().stream().map(this::entity2Dto).collect(Collectors.toList()); |
| | | return new PaginationData<DeviceFirmwareDTO>(data, new Pagination(page)); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public void importFirmwareFile(String workspaceId, String creator, DeviceFirmwareUploadParam param, MultipartFile file) { |
| | | try (InputStream is = file.getInputStream()) { |
| | | long size = is.available(); |
| | | String md5 = DigestUtils.md5DigestAsHex(is); |
| | | boolean exist = checkFileExist(workspaceId, md5); |
| | | if (exist) { |
| | | throw new RuntimeException("The file already exists."); |
| | | } |
| | | |
| | | Optional<DeviceFirmwareDTO> firmwareOpt = verifyFirmwareFile(file); |
| | | if (firmwareOpt.isEmpty()) { |
| | | throw new RuntimeException("The file format is incorrect."); |
| | | } |
| | | |
| | | String firmwareId = UUID.randomUUID().toString(); |
| | | String objectKey = OssConfiguration.objectDirPrefix + File.separator + firmwareId + FirmwareFileProperties.FIRMWARE_FILE_SUFFIX; |
| | | |
| | | ossServiceContext.putObject(OssConfiguration.bucket, objectKey, file.getInputStream()); |
| | | log.info("upload success"); |
| | | DeviceFirmwareDTO firmware = DeviceFirmwareDTO.builder() |
| | | .deviceName(param.getDeviceName()) |
| | | .releaseNote(param.getReleaseNote()) |
| | | .firmwareStatus(param.getStatus()) |
| | | .fileMd5(md5) |
| | | .objectKey(objectKey) |
| | | .fileName(file.getOriginalFilename()) |
| | | .workspaceId(workspaceId) |
| | | .username(creator) |
| | | .fileSize(size) |
| | | .productVersion(firmwareOpt.get().getProductVersion()) |
| | | .releasedTime(firmwareOpt.get().getReleasedTime()) |
| | | .firmwareId(firmwareId) |
| | | .build(); |
| | | |
| | | saveFirmwareInfo(firmware); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void saveFirmwareInfo(DeviceFirmwareDTO firmware) { |
| | | mapper.insert(dto2Entity(firmware)); |
| | | } |
| | | |
| | | @Override |
| | | public void updateFirmwareInfo(DeviceFirmwareDTO firmware) { |
| | | mapper.update(dto2Entity(firmware), |
| | | new LambdaUpdateWrapper<DeviceFirmwareEntity>() |
| | | .eq(DeviceFirmwareEntity::getFirmwareId, firmware.getFirmwareId())); |
| | | } |
| | | |
| | | /** |
| | | * Parse firmware file information. |
| | | * @param file |
| | | * @return |
| | | */ |
| | | private Optional<DeviceFirmwareDTO> verifyFirmwareFile(MultipartFile file) { |
| | | try (ZipInputStream unzipFile = new ZipInputStream(file.getInputStream(), StandardCharsets.UTF_8)) { |
| | | ZipEntry nextEntry = unzipFile.getNextEntry(); |
| | | while (Objects.nonNull(nextEntry)) { |
| | | String configName = nextEntry.getName(); |
| | | if (!configName.contains(File.separator) && configName.endsWith(FirmwareFileProperties.FIRMWARE_CONFIG_FILE_SUFFIX + FirmwareFileProperties.FIRMWARE_SIG_FILE_SUFFIX)) { |
| | | String[] filenameArr = configName.split(FirmwareFileProperties.FIRMWARE_FILE_DELIMITER); |
| | | String date = filenameArr[FirmwareFileProperties.FILENAME_RELEASE_DATE_INDEX]; |
| | | int index = date.indexOf("."); |
| | | if (index != -1) { |
| | | date = date.substring(0, index); |
| | | } |
| | | return Optional.of(DeviceFirmwareDTO.builder() |
| | | .releasedTime(LocalDate.parse( |
| | | date, |
| | | DateTimeFormatter.ofPattern(FirmwareFileProperties.FILENAME_RELEASE_DATE_FORMAT))) |
| | | // delete the string v. |
| | | .productVersion(filenameArr[FirmwareFileProperties.FILENAME_VERSION_INDEX].substring(1)) |
| | | .build()); |
| | | } |
| | | nextEntry = unzipFile.getNextEntry(); |
| | | } |
| | | |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return Optional.empty(); |
| | | } |
| | | |
| | | private DeviceFirmwareEntity dto2Entity(DeviceFirmwareDTO dto) { |
| | | if (dto == null) { |
| | | return null; |
| | | } |
| | | return DeviceFirmwareEntity.builder() |
| | | .fileName(dto.getFileName()) |
| | | .deviceName(dto.getDeviceName()) |
| | | .fileMd5(dto.getFileMd5()) |
| | | .fileSize(dto.getFileSize()) |
| | | .firmwareId(dto.getFirmwareId()) |
| | | .firmwareVersion(dto.getProductVersion()) |
| | | .objectKey(dto.getObjectKey()) |
| | | .releaseDate(Objects.nonNull(dto.getReleasedTime()) ? |
| | | dto.getReleasedTime().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli() : null) |
| | | .releaseNote(dto.getReleaseNote()) |
| | | .status(dto.getFirmwareStatus()) |
| | | .workspaceId(dto.getWorkspaceId()) |
| | | .username(dto.getUsername()) |
| | | .build(); |
| | | } |
| | | |
| | | private DeviceFirmwareNoteDTO entity2NoteDto (DeviceFirmwareEntity entity) { |
| | | if (entity == null) { |
| | | return null; |
| | |
| | | .deviceName(entity.getDeviceName()) |
| | | .fileMd5(entity.getFileMd5()) |
| | | .fileSize(entity.getFileSize()) |
| | | .fileUrl(entity.getFileUrl()) |
| | | .objectKey(entity.getObjectKey()) |
| | | .firmwareId(entity.getFirmwareId()) |
| | | .fileName(entity.getFileName()) |
| | | .productVersion(entity.getFirmwareVersion()) |
| | | .releasedTime(LocalDate.ofInstant(Instant.ofEpochMilli(entity.getReleaseDate()), ZoneId.systemDefault())) |
| | | .releaseNote(entity.getReleaseNote()) |
| | | .firmwareStatus(entity.getStatus()) |
| | | .workspaceId(entity.getWorkspaceId()) |
| | | .username(entity.getUsername()) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | } |
| | | return DeviceOtaCreateParam.builder() |
| | | .fileSize(dto.getFileSize()) |
| | | .fileUrl(dto.getFileUrl()) |
| | | .fileUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket, dto.getObjectKey()).toString()) |
| | | .fileName(dto.getFileName()) |
| | | .md5(dto.getFileMd5()) |
| | | .productVersion(dto.getProductVersion()) |
| | |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private SendMessageServiceImpl sendMessageService; |
| | | |
| | | @Autowired |
| | |
| | | .build(); |
| | | String key = RedisConst.HMS_PREFIX + sn; |
| | | // Query all unread hms messages of the device in redis. |
| | | Set<String> hmsMap = redisOps.listGetAll(key).stream().map(String::valueOf).collect(Collectors.toSet()); |
| | | Set<String> hmsMap = RedisOpsUtils.listGetAll(key).stream().map(String::valueOf).collect(Collectors.toSet()); |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | |
| | | List<DeviceHmsDTO> unReadList = new ArrayList<>(); |
| | | objectMapper.convertValue(((Map) (receiver.getData())).get(MapKeyConst.LIST), |
| | |
| | | if (unReadList.isEmpty()) { |
| | | return; |
| | | } |
| | | redisOps.listRPush(key, unReadList.stream().map(DeviceHmsDTO::getKey).toArray(String[]::new)); |
| | | RedisOpsUtils.listRPush(key, unReadList.stream().map(DeviceHmsDTO::getKey).toArray(String[]::new)); |
| | | // push to the web |
| | | Collection<ConcurrentWebSocketSession> sessions = webSocketManageService.getValueWithWorkspaceAndUserType( |
| | | device.getWorkspaceId(), UserTypeEnum.WEB.getVal()); |
| | |
| | | .eq(DeviceHmsEntity::getSn, deviceSn) |
| | | .eq(DeviceHmsEntity::getUpdateTime, 0L)); |
| | | // Delete unread messages cached in redis. |
| | | redisOps.del(RedisConst.HMS_PREFIX + deviceSn); |
| | | RedisOpsUtils.del(RedisConst.HMS_PREFIX + deviceSn); |
| | | } |
| | | |
| | | private DeviceHmsDTO entity2Dto(DeviceHmsEntity entity) { |
| | |
| | | @Autowired |
| | | private ICapacityCameraService capacityCameraService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public Integer checkPayloadExist(String payloadSn) { |
| | | DevicePayloadEntity devicePayload = mapper.selectOne( |
| | |
| | | |
| | | String deviceSn = payloadReceiverList.get(0).getDeviceSn(); |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(key); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(key); |
| | | List<DevicePayloadDTO> payloads = new ArrayList<>(); |
| | | |
| | | for (DevicePayloadReceiver payloadReceiver : payloadReceiverList) { |
| | |
| | | payloads = this.getDevicePayloadEntitiesByDeviceSn(deviceSn); |
| | | } |
| | | device.setPayloadsList(payloads); |
| | | redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), device, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), device, RedisConst.DEVICE_ALIVE_SECOND); |
| | | return true; |
| | | } |
| | | |
| | |
| | | String deviceSn = payloadReceiverList.stream().findAny().get().getDeviceSn(); |
| | | String key = RedisConst.STATE_PAYLOAD_PREFIX + deviceSn; |
| | | // Solve timing problems |
| | | long last = (long) Objects.requireNonNullElse(redisOps.get(key), 0L); |
| | | long last = (long) Objects.requireNonNullElse(RedisOpsUtils.get(key), 0L); |
| | | if (last > timestamp) { |
| | | return; |
| | | } |
| | |
| | | // Save the new payload information. |
| | | boolean isSave = this.savePayloadDTOs(needToSave); |
| | | if (isSave) { |
| | | redisOps.setWithExpire(key, timestamp, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.setWithExpire(key, timestamp, RedisConst.DEVICE_ALIVE_SECOND); |
| | | } |
| | | log.debug("The result of saving the payloads is {}.", isSave); |
| | | } |
| | |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | @Autowired |
| | |
| | | private ITSAService tsaService; |
| | | |
| | | private static final List<String> INIT_TOPICS_SUFFIX = List.of( |
| | | OSD_SUF, STATE_SUF, SERVICES_SUF + _REPLY_SUF, REQUESTS_SUF, EVENTS_SUF, PROPERTY_SUF + SET_SUF + _REPLY_SUF); |
| | | OSD_SUF, STATE_SUF, SERVICES_SUF + _REPLY_SUF, EVENTS_SUF, PROPERTY_SUF + SET_SUF + _REPLY_SUF); |
| | | |
| | | @Override |
| | | public Boolean deviceOffline(StatusGatewayReceiver gateway) { |
| | |
| | | // Only the remote controller is logged in and the aircraft is not connected. |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + gatewaySn; |
| | | |
| | | boolean exist = redisOps.checkExist(key); |
| | | boolean exist = RedisOpsUtils.checkExist(key); |
| | | if (!exist) { |
| | | Optional<DeviceDTO> gatewayOpt = this.getDeviceBySn(gatewaySn); |
| | | if (gatewayOpt.isPresent()) { |
| | | DeviceDTO value = gatewayOpt.get(); |
| | | value.setBoundTime(null); |
| | | value.setLoginTime(null); |
| | | redisOps.setWithExpire(key, value, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.setWithExpire(key, value, RedisConst.DEVICE_ALIVE_SECOND); |
| | | this.pushDeviceOnlineTopo(value.getWorkspaceId(), gatewaySn, gatewaySn); |
| | | return true; |
| | | } |
| | |
| | | return firstSaveDevice(gatewayDevice, null); |
| | | } |
| | | |
| | | DeviceDTO deviceDTO = (DeviceDTO) (redisOps.get(key)); |
| | | DeviceDTO deviceDTO = (DeviceDTO) (RedisOpsUtils.get(key)); |
| | | String deviceSn = deviceDTO.getChildDeviceSn(); |
| | | if (!StringUtils.hasText(deviceSn)) { |
| | | return true; |
| | |
| | | |
| | | // If no information about this device exists in the cache, the drone is considered to be offline. |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | if (!redisOps.checkExist(key) || redisOps.getExpire(key) <= 0) { |
| | | if (!RedisOpsUtils.checkExist(key) || RedisOpsUtils.getExpire(key) <= 0) { |
| | | log.debug("The drone is already offline."); |
| | | return true; |
| | | } |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(key); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(key); |
| | | // Cancel drone-related subscriptions. |
| | | this.unsubscribeTopicOffline(deviceSn); |
| | | |
| | |
| | | // Publish the latest device topology information in the current workspace. |
| | | this.pushDeviceOfflineTopo(device.getWorkspaceId(), deviceSn); |
| | | |
| | | redisOps.del(key); |
| | | redisOps.del(RedisConst.OSD_PREFIX + device.getDeviceSn()); |
| | | RedisOpsUtils.del(key); |
| | | RedisOpsUtils.del(RedisConst.OSD_PREFIX + device.getDeviceSn()); |
| | | log.debug("{} offline.", deviceSn); |
| | | return true; |
| | | } |
| | |
| | | String deviceSn = deviceGateway.getSubDevices().get(0).getSn(); |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | // change log: Use redis instead of |
| | | long time = redisOps.getExpire(key); |
| | | long gatewayTime = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + deviceGateway.getSn()); |
| | | long time = RedisOpsUtils.getExpire(key); |
| | | long gatewayTime = RedisOpsUtils.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + deviceGateway.getSn()); |
| | | |
| | | if (time > 0 && gatewayTime > 0) { |
| | | redisOps.expireKey(key, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.expireKey(key, RedisConst.DEVICE_ALIVE_SECOND); |
| | | DeviceDTO device = DeviceDTO.builder().loginTime(LocalDateTime.now()).deviceSn(deviceSn).build(); |
| | | DeviceDTO gateway = DeviceDTO.builder() |
| | | .loginTime(LocalDateTime.now()) |
| | |
| | | .childDeviceSn(deviceSn).build(); |
| | | this.updateDevice(gateway); |
| | | this.updateDevice(device); |
| | | String workspaceId = ((DeviceDTO)(redisOps.get(key))).getWorkspaceId(); |
| | | String workspaceId = ((DeviceDTO)(RedisOpsUtils.get(key))).getWorkspaceId(); |
| | | if (StringUtils.hasText(workspaceId)) { |
| | | this.subscribeTopicOnline(deviceSn); |
| | | this.subscribeTopicOnline(deviceGateway.getSn()); |
| | |
| | | devicesList.forEach(device -> { |
| | | this.spliceDeviceTopo(device); |
| | | device.setWorkspaceId(workspaceId); |
| | | device.setStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); |
| | | device.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); |
| | | }); |
| | | return devicesList; |
| | | } |
| | |
| | | |
| | | this.getDeviceTopoForPilot(sn) |
| | | .ifPresent(pilotMessage::setData); |
| | | boolean exist = redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | boolean exist = RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | pilotMessage.getData().setOnlineStatus(exist); |
| | | pilotMessage.getData().setGatewaySn(gatewaySn.equals(sn) ? "" : gatewaySn); |
| | | |
| | |
| | | .key(domain + "-" + type + "-" + subType) |
| | | .build()) |
| | | .iconUrls(device.getIconUrl()) |
| | | .onlineStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) |
| | | .onlineStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) |
| | | .boundStatus(device.getBoundStatus()) |
| | | .model(device.getDeviceName()) |
| | | .userId(device.getUserId()) |
| | |
| | | topic.indexOf(OSD_SUF)); |
| | | |
| | | // Real-time update of device status in memory |
| | | redisOps.expireKey(RedisConst.DEVICE_ONLINE_PREFIX + from, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.expireKey(RedisConst.DEVICE_ONLINE_PREFIX + from, RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + from); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + from); |
| | | |
| | | if (device == null) { |
| | | Optional<DeviceDTO> deviceOpt = this.getDeviceBySn(from); |
| | |
| | | } |
| | | device = deviceOpt.get(); |
| | | if (!StringUtils.hasText(device.getWorkspaceId())) { |
| | | this.unsubscribeTopicOffline(from); |
| | | return; |
| | | } |
| | | redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + from, device, |
| | | RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + from, device, |
| | | RedisConst.DEVICE_ALIVE_SECOND); |
| | | this.subscribeTopicOnline(from); |
| | | } |
| | |
| | | return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.NOT_UPGRADE.getVal()).build(); |
| | | } |
| | | // Query whether the device is updating firmware. |
| | | Object progress = redisOps.get(RedisConst.FIRMWARE_UPGRADING_PREFIX + entity.getDeviceSn()); |
| | | Object progress = RedisOpsUtils.get(RedisConst.FIRMWARE_UPGRADING_PREFIX + entity.getDeviceSn()); |
| | | if (Objects.nonNull(progress)) { |
| | | return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.UPGRADING.getVal()).firmwareProgress((int)progress).build(); |
| | | } |
| | |
| | | } |
| | | |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(); |
| | | DeviceDTO redisDevice = (DeviceDTO)redisOps.get(key); |
| | | DeviceDTO redisDevice = (DeviceDTO)RedisOpsUtils.get(key); |
| | | if (Objects.isNull(redisDevice)) { |
| | | return false; |
| | | } |
| | | redisDevice.setWorkspaceId(device.getWorkspaceId()); |
| | | redisOps.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | if (DeviceDomainEnum.GATEWAY.getDesc().equals(redisDevice.getDomain())) { |
| | | this.pushDeviceOnlineTopo(webSocketManageService.getValueWithWorkspace(device.getWorkspaceId()), |
| | |
| | | .eq(DeviceEntity::getBoundStatus, true)); |
| | | List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO) |
| | | .peek(device -> { |
| | | device.setStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); |
| | | device.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); |
| | | if (StringUtils.hasText(device.getChildDeviceSn())) { |
| | | Optional<DeviceDTO> childOpt = this.getDeviceBySn(device.getChildDeviceSn()); |
| | | childOpt.ifPresent(child -> { |
| | | child.setStatus( |
| | | redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + child.getDeviceSn())); |
| | | RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + child.getDeviceSn())); |
| | | child.setWorkspaceName(device.getWorkspaceName()); |
| | | device.setChildren(child); |
| | | }); |
| | |
| | | @Override |
| | | public void unbindDevice(String deviceSn) { |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | DeviceDTO redisDevice = (DeviceDTO) redisOps.get(key); |
| | | DeviceDTO redisDevice = (DeviceDTO) RedisOpsUtils.get(key); |
| | | redisDevice.setWorkspaceId(""); |
| | | redisOps.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | DeviceDTO device = DeviceDTO.builder() |
| | | .deviceSn(deviceSn) |
| | |
| | | return Optional.empty(); |
| | | } |
| | | DeviceDTO device = devicesList.get(0); |
| | | device.setStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn)); |
| | | device.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn)); |
| | | return Optional.of(device); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | // Record the device state that needs to be updated. |
| | | deviceOtaFirmwares.forEach(deviceOta -> redisOps.setWithExpire( |
| | | deviceOtaFirmwares.forEach(deviceOta -> RedisOpsUtils.setWithExpire( |
| | | RedisConst.FIRMWARE_UPGRADING_PREFIX + deviceOta.getSn(), |
| | | bid, |
| | | RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND)); |
| | |
| | | if (!dockOnline) { |
| | | throw new RuntimeException("Dock is offline."); |
| | | } |
| | | DeviceDTO deviceDTO = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + dockSn); |
| | | DeviceDTO deviceDTO = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + dockSn); |
| | | boolean deviceOnline = this.checkDeviceOnline(deviceDTO.getChildDeviceSn()); |
| | | if (!deviceOnline) { |
| | | throw new RuntimeException("Device is offline."); |
| | |
| | | } |
| | | |
| | | String topic = THING_MODEL_PRE + PRODUCT + dockSn + PROPERTY_SUF + SET_SUF; |
| | | OsdSubDeviceReceiver osd = (OsdSubDeviceReceiver) redisOps.get(RedisConst.OSD_PREFIX + deviceDTO.getChildDeviceSn()); |
| | | // OsdSubDeviceReceiver osd = (OsdSubDeviceReceiver) RedisOpsUtils.get(RedisConst.OSD_PREFIX + deviceDTO.getChildDeviceSn()); |
| | | if (!param.isObject()) { |
| | | this.deviceOnePropertySet(topic, propertyEnum, Map.entry(propertyEnum.getProperty(), param)); |
| | | return; |
| | |
| | | // If there are multiple parameters, set them separately. |
| | | for (Iterator<Map.Entry<String, JsonNode>> filed = param.fields(); filed.hasNext(); ) { |
| | | Map.Entry<String, JsonNode> node = filed.next(); |
| | | boolean isPublish = basicDeviceProperty.canPublish(node.getKey(), osd); |
| | | boolean isPublish = basicDeviceProperty.canPublish(node.getKey(), null); |
| | | if (!isPublish) { |
| | | continue; |
| | | } |
| | |
| | | |
| | | public Boolean checkDeviceOnline(String sn) { |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + sn; |
| | | return redisOps.checkExist(key) && redisOps.getExpire(key) > 0; |
| | | return RedisOpsUtils.checkExist(key) && RedisOpsUtils.getExpire(key) > 0; |
| | | } |
| | | |
| | | /** |
| | |
| | | // 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()); |
| | | } |
| | | |
| | | deviceOpt.ifPresent(oldDevice -> device.setNickname(oldDevice.getNickname())); |
| | | device.setChildSn(deviceSn); |
| | | device.setLoginTime(System.currentTimeMillis()); |
| | | |
| | |
| | | } |
| | | device.setWorkspaceId(saveDeviceOpt.get().getWorkspaceId()); |
| | | |
| | | redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), |
| | | RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), |
| | | DeviceDTO.builder() |
| | | .deviceSn(device.getDeviceSn()) |
| | | .workspaceId(device.getWorkspaceId()) |
| | |
| | | @Autowired |
| | | private IMessageSenderService messageSender; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public List<CapacityDeviceDTO> getLiveCapacity(String workspaceId) { |
| | | |
| | |
| | | |
| | | // Query the live capability of each drone. |
| | | return devicesList.stream() |
| | | .filter(device -> redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) |
| | | .filter(device -> RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) |
| | | .map(device -> CapacityDeviceDTO.builder() |
| | | .name(Objects.requireNonNullElse(device.getNickname(), device.getDeviceName())) |
| | | .sn(device.getDeviceSn()) |
| | |
| | | // Solve timing problems |
| | | for (CapacityDeviceReceiver capacityDeviceReceiver : liveCapacityReceiver.getDeviceList()) { |
| | | long last = (long) Objects.requireNonNullElse( |
| | | redisOps.get(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + capacityDeviceReceiver.getSn()), 0L); |
| | | RedisOpsUtils.get(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + capacityDeviceReceiver.getSn()), 0L); |
| | | if (last > timestamp) { |
| | | return; |
| | | } |
| | |
| | | String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF; |
| | | |
| | | ServiceReply receiveReply = this.publishLiveSetQuality(respTopic, liveParam); |
| | | if (ResponseResult.CODE_SUCCESS == receiveReply.getResult()) { |
| | | if (ResponseResult.CODE_SUCCESS != receiveReply.getResult()) { |
| | | return ResponseResult.error(LiveErrorEnum.find(receiveReply.getResult())); |
| | | } |
| | | |
| | |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Autowired |
| | | private OssServiceContext ossServiceContext; |
| | | |
| | | @Override |
| | |
| | | List<String> fileIds = new ArrayList<>(); |
| | | logsFiles.forEach(file -> { |
| | | if (file.getStatus()) { |
| | | ossService.deleteObject(configuration.getBucket(), file.getObjectKey()); |
| | | ossService.deleteObject(OssConfiguration.bucket, file.getObjectKey()); |
| | | } |
| | | fileIds.add(file.getFileId()); |
| | | }); |
| | |
| | | if (Objects.isNull(logsFile)) { |
| | | return null; |
| | | } |
| | | return ossService.getObjectUrl(configuration.getBucket(), logsFile.getObjectKey()); |
| | | return ossService.getObjectUrl(OssConfiguration.bucket, logsFile.getObjectKey()); |
| | | } |
| | | |
| | | private LogsFileEntity receiver2Entity(LogsExtFileReceiver receiver) { |
| | |
| | | public ResponseResult<PaginationData<MediaFileDTO>> getFilesList(@RequestParam(defaultValue = "1") Long page, |
| | | @RequestParam(name = "page_size", defaultValue = "10") Long pageSize, |
| | | @PathVariable(name = "workspace_id") String workspaceId) { |
| | | PaginationData<MediaFileDTO> filesList = fileService.getJobsPaginationByWorkspaceId(workspaceId, page, pageSize); |
| | | PaginationData<MediaFileDTO> filesList = fileService.getMediaFilesPaginationByWorkspaceId(workspaceId, page, pageSize); |
| | | return ResponseResult.success(filesList); |
| | | } |
| | | |
| New file |
| | |
| | | package com.dji.sample.media.model; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/11/22 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class MediaFileCountDTO { |
| | | |
| | | private String tid; |
| | | |
| | | private String bid; |
| | | |
| | | private String preJobId; |
| | | |
| | | private String jobId; |
| | | |
| | | private Integer mediaCount; |
| | | |
| | | private Integer uploadedCount; |
| | | } |
| | |
| | | private String fingerprint; |
| | | |
| | | private LocalDateTime createTime; |
| | | |
| | | private String jobId; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.media.model; |
| | | |
| | | import lombok.Getter; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.3 |
| | | * @date 2022/11/23 |
| | | */ |
| | | @Getter |
| | | public enum MediaMethodEnum { |
| | | |
| | | UPLOAD_FLIGHT_TASK_MEDIA_PRIORITIZE("upload_flighttask_media_prioritize"); |
| | | |
| | | private String method; |
| | | |
| | | MediaMethodEnum(String method) { |
| | | this.method = method; |
| | | } |
| | | } |
| | |
| | | * @param pageSize |
| | | * @return |
| | | */ |
| | | PaginationData<MediaFileDTO> getJobsPaginationByWorkspaceId(String workspaceId, long page, long pageSize); |
| | | PaginationData<MediaFileDTO> getMediaFilesPaginationByWorkspaceId(String workspaceId, long page, long pageSize); |
| | | |
| | | /** |
| | | * Get the download address of the file. |
| | |
| | | * @return |
| | | */ |
| | | URL getObjectUrl(String workspaceId, String fileId); |
| | | |
| | | /** |
| | | * Query all media files of a job. |
| | | * @param workspaceId |
| | | * @param jobId |
| | | * @return |
| | | */ |
| | | List<MediaFileDTO> getFilesByWorkspaceAndJobId(String workspaceId, String jobId); |
| | | } |
| | |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.media.model.FileUploadDTO; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | * @return |
| | | */ |
| | | void handleFileUploadCallBack(CommonTopicReceiver receiver); |
| | | |
| | | /** |
| | | * Handles the highest priority message about media uploads. |
| | | * @param receiver |
| | | * @param headers |
| | | */ |
| | | void handleHighestPriorityUploadFlightTaskMedia(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | } |
| | |
| | | @Autowired |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | private Optional<MediaFileEntity> getMediaByFingerprint(String workspaceId, String fingerprint) { |
| | | MediaFileEntity fileEntity = mapper.selectOne(new LambdaQueryWrapper<MediaFileEntity>() |
| | | .eq(MediaFileEntity::getWorkspaceId, workspaceId) |
| | |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<MediaFileDTO> getJobsPaginationByWorkspaceId(String workspaceId, long page, long pageSize) { |
| | | public PaginationData<MediaFileDTO> getMediaFilesPaginationByWorkspaceId(String workspaceId, long page, long pageSize) { |
| | | Page<MediaFileEntity> pageData = mapper.selectPage( |
| | | new Page<MediaFileEntity>(page, pageSize), |
| | | new LambdaQueryWrapper<MediaFileEntity>() |
| | |
| | | throw new IllegalArgumentException("{} doesn't exist."); |
| | | } |
| | | |
| | | return ossService.getObjectUrl(configuration.getBucket(), mediaFileOpt.get().getObjectKey()); |
| | | return ossService.getObjectUrl(OssConfiguration.bucket, mediaFileOpt.get().getObjectKey()); |
| | | } |
| | | |
| | | @Override |
| | | public List<MediaFileDTO> getFilesByWorkspaceAndJobId(String workspaceId, String jobId) { |
| | | return mapper.selectList(new LambdaQueryWrapper<MediaFileEntity>() |
| | | .eq(MediaFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(MediaFileEntity::getJobId, jobId)) |
| | | .stream() |
| | | .map(this::entityConvertToDto).collect(Collectors.toList()); |
| | | } |
| | | |
| | | /** |
| | |
| | | .payload(entity.getPayload()) |
| | | .createTime(LocalDateTime.ofInstant( |
| | | Instant.ofEpochMilli(entity.getCreateTime()), ZoneId.systemDefault())) |
| | | .drone(entity.getDrone()); |
| | | .drone(entity.getDrone()) |
| | | .jobId(entity.getJobId()); |
| | | |
| | | } |
| | | |
| | |
| | | package com.dji.sample.media.service.impl; |
| | | |
| | | import com.dji.sample.common.error.CommonErrorEnum; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.mqtt.model.*; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | 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.manage.service.IDeviceService; |
| | | import com.dji.sample.media.model.FileUploadCallback; |
| | | import com.dji.sample.media.model.FileUploadDTO; |
| | | import com.dji.sample.media.model.MediaFileCountDTO; |
| | | import com.dji.sample.media.model.MediaFileDTO; |
| | | import com.dji.sample.media.service.IFileService; |
| | | import com.dji.sample.media.service.IMediaService; |
| | |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | 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; |
| | | |
| | |
| | | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private ISendMessageService sendMessageService; |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | @Override |
| | | public Boolean fastUpload(String workspaceId, String fingerprint) { |
| | |
| | | |
| | | String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + receiver.getGateway() |
| | | + TopicConst.EVENTS_SUF + TopicConst._REPLY_SUF; |
| | | CommonTopicResponse<Object> data = CommonTopicResponse.builder() |
| | | CommonTopicResponse<RequestsReply> data = CommonTopicResponse.<RequestsReply>builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .method(EventsMethodEnum.FILE_UPLOAD_CALLBACK.getMethod()) |
| | | .data(RequestsReply.success()) |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .build(); |
| | | if (callback.getResult() == ResponseResult.CODE_SUCCESS) { |
| | | String jobId = callback.getFile().getExt().getFlightId(); |
| | | Optional<WaylineJobDTO> jobOpt = waylineJobService.getJobByJobId(jobId); |
| | | if (jobOpt.isPresent()) { |
| | | // Set the drone sn that shoots the media |
| | | Optional<DeviceDTO> dockDTO = deviceService.getDeviceBySn(jobOpt.get().getDockSn()); |
| | | dockDTO.ifPresent(dock -> callback.getFile().getExt().setSn(dock.getChildDeviceSn())); |
| | | |
| | | // set path |
| | | String objectKey = callback.getFile().getObjectKey(); |
| | | callback.getFile().setPath(objectKey.substring(objectKey.indexOf("/") + 1, objectKey.lastIndexOf("/"))); |
| | | if (callback.getResult() != ResponseResult.CODE_SUCCESS) { |
| | | messageSenderService.publish(topic, data); |
| | | return; |
| | | } |
| | | |
| | | int id = fileService.saveFile(jobOpt.get().getWorkspaceId(), callback.getFile()); |
| | | if (id <= 0) { |
| | | data.setData(ResponseResult.error()); |
| | | } |
| | | String jobId = callback.getFile().getExt().getFlightId(); |
| | | |
| | | 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<WaylineJobDTO> jobOpt = waylineJobService.getJobByJobId(jobId); |
| | | if (jobOpt.isPresent()) { |
| | | boolean isSave = parseMediaFile(callback, jobOpt.get()); |
| | | if (!isSave) { |
| | | data.setData(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT)); |
| | | } |
| | | } |
| | | |
| | | messageSenderService.publish(topic, data); |
| | | |
| | | notifyUploadedCount(mediaFileCount, receiver, jobId); |
| | | } |
| | | |
| | | /** |
| | | * update the uploaded count and notify web side |
| | | * @param mediaFileCount |
| | | * @param receiver |
| | | * @param jobId |
| | | */ |
| | | private void notifyUploadedCount(MediaFileCountDTO mediaFileCount, CommonTopicReceiver receiver, String jobId) { |
| | | mediaFileCount.setBid(receiver.getBid()); |
| | | mediaFileCount.setTid(receiver.getTid()); |
| | | mediaFileCount.setUploadedCount(mediaFileCount.getUploadedCount() + 1); |
| | | |
| | | String key = RedisConst.MEDIA_FILE_PREFIX + receiver.getGateway(); |
| | | // After all the files of the job are uploaded, delete the media file key. |
| | | if (mediaFileCount.getUploadedCount() >= mediaFileCount.getMediaCount()) { |
| | | RedisOpsUtils.hashDel(key, new String[]{jobId}); |
| | | |
| | | // 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), ""))) { |
| | | RedisOpsUtils.del(highestKey); |
| | | } |
| | | |
| | | if (RedisOpsUtils.hashLen(key) == 0) { |
| | | RedisOpsUtils.del(key); |
| | | } |
| | | } else { |
| | | RedisOpsUtils.hashSet(key, jobId, mediaFileCount); |
| | | } |
| | | |
| | | DeviceDTO dock = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); |
| | | sendMessageService.sendBatch(webSocketManageService.getValueWithWorkspaceAndUserType(dock.getWorkspaceId(), UserTypeEnum.WEB.getVal()), |
| | | CustomWebSocketMessage.builder() |
| | | .bizCode(BizCodeEnum.FILE_UPLOAD_CALLBACK.getCode()) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .data(mediaFileCount) |
| | | .build()); |
| | | } |
| | | |
| | | private Boolean parseMediaFile(FileUploadCallback callback, WaylineJobDTO job) { |
| | | // Set the drone sn that shoots the media |
| | | Optional<DeviceDTO> dockDTO = deviceService.getDeviceBySn(job.getDockSn()); |
| | | dockDTO.ifPresent(dock -> callback.getFile().getExt().setSn(dock.getChildDeviceSn())); |
| | | |
| | | // set path |
| | | String objectKey = callback.getFile().getObjectKey(); |
| | | callback.getFile().setPath(objectKey.substring(objectKey.indexOf("/") + 1, objectKey.lastIndexOf("/"))); |
| | | |
| | | return fileService.saveFile(job.getWorkspaceId(), callback.getFile()) > 0; |
| | | } |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA, outputChannel = ChannelName.OUTBOUND) |
| | | public void handleHighestPriorityUploadFlightTaskMedia(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | Map map = objectMapper.convertValue(receiver.getData(), Map.class); |
| | | if (map.isEmpty() || !map.containsKey(MapKeyConst.FLIGHT_ID)) { |
| | | return; |
| | | } |
| | | |
| | | 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); |
| | | |
| | | RedisOpsUtils.setWithExpire(key, jobId, |
| | | 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()) |
| | | .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()); |
| | | } |
| | | } |
| | |
| | | @Autowired |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public StsCredentialsDTO getSTSCredentials() { |
| | | return StsCredentialsDTO.builder() |
| | | .endpoint(configuration.getEndpoint()) |
| | | .bucket(configuration.getBucket()) |
| | | .endpoint(OssConfiguration.endpoint) |
| | | .bucket(OssConfiguration.bucket) |
| | | .credentials(ossService.getCredentials()) |
| | | .provider(configuration.getProvider()) |
| | | .objectKeyPrefix(configuration.getObjectDirPrefix()) |
| | | .region(configuration.getRegion()) |
| | | .provider(OssConfiguration.provider) |
| | | .objectKeyPrefix(OssConfiguration.objectDirPrefix) |
| | | .region(OssConfiguration.region) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | try { |
| | | URL url = waylineFileService.getObjectUrl(workspaceId, waylineId); |
| | | response.sendRedirect(url.toString()); |
| | | |
| | | } catch (IOException | SQLException e) { |
| | | e.printStackTrace(); |
| | | } |
| | |
| | | waylineJobService.cancelFlightTask(workspaceId, jobIds); |
| | | return ResponseResult.success(); |
| | | } |
| | | |
| | | /** |
| | | * Set the media files for this job to upload immediately. |
| | | * @param workspaceId |
| | | * @param jobId |
| | | * @return |
| | | */ |
| | | @PostMapping("/{workspace_id}/jobs/{job_id}/media-highest") |
| | | public ResponseResult uploadMediaHighestPriority(@PathVariable(name = "workspace_id") String workspaceId, |
| | | @PathVariable(name = "job_id") String jobId) { |
| | | waylineJobService.uploadMediaHighestPriority(workspaceId, jobId); |
| | | return ResponseResult.success(); |
| | | } |
| | | } |
| | |
| | | private Integer outOfControlAction; |
| | | |
| | | private Integer mediaCount; |
| | | |
| | | private Integer uploadedCount; |
| | | |
| | | private Boolean uploading; |
| | | } |
| | |
| | | * @param headers |
| | | */ |
| | | void flightTaskResourceGet(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | |
| | | /** |
| | | * Set the media files for this job to upload immediately. |
| | | * @param workspaceId |
| | | * @param jobId |
| | | */ |
| | | void uploadMediaHighestPriority(String workspaceId, String jobId); |
| | | } |
| | |
| | | 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.enums.WaylineJobStatusEnum; |
| | |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private IWaylineJobService waylineJobService; |
| | | |
| | | @Override |
| | |
| | | .mediaCount(output.getExt().getMediaCount()) |
| | | .build(); |
| | | |
| | | // record the update of the media count. |
| | | if (Objects.nonNull(job.getMediaCount())) { |
| | | RedisOpsUtils.hashSet(RedisConst.MEDIA_FILE_PREFIX + receiver.getGateway(), job.getJobId(), |
| | | MediaFileCountDTO.builder().jobId(receiver.getBid()).mediaCount(job.getMediaCount()).uploadedCount(0).build()); |
| | | } |
| | | |
| | | if (EventsResultStatusEnum.OK != statusEnum) { |
| | | job.setCode(eventsReceiver.getResult()); |
| | | job.setStatus(WaylineJobStatusEnum.FAILED.getVal()); |
| | | } |
| | | |
| | | waylineJobService.updateJob(job); |
| | | redisOps.del(receiver.getBid()); |
| | | RedisOpsUtils.del(receiver.getBid()); |
| | | } |
| | | redisOps.setWithExpire(receiver.getBid(), eventsReceiver, RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); |
| | | RedisOpsUtils.setWithExpire(receiver.getBid(), eventsReceiver, RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); |
| | | DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); |
| | | websocketMessageService.sendBatch( |
| | | webSocketManageService.getValueWithWorkspaceAndUserType( |
| | | device.getWorkspaceId(), UserTypeEnum.WEB.getVal()), |
| | |
| | | |
| | | @Scheduled(initialDelay = 10, fixedRate = 5, timeUnit = TimeUnit.SECONDS) |
| | | private void checkScheduledJob() { |
| | | Object jobIdValue = redisOps.zGetMin(RedisConst.WAYLINE_JOB); |
| | | Object jobIdValue = RedisOpsUtils.zGetMin(RedisConst.WAYLINE_JOB); |
| | | log.info("Check the timed jobs of the wayline. {}", jobIdValue); |
| | | if (Objects.isNull(jobIdValue)) { |
| | | return; |
| | | } |
| | | String jobId = String.valueOf(jobIdValue); |
| | | double time = redisOps.zScore(RedisConst.WAYLINE_JOB, jobIdValue); |
| | | double time = RedisOpsUtils.zScore(RedisConst.WAYLINE_JOB, jobIdValue); |
| | | long now = System.currentTimeMillis(); |
| | | int offset = 30_000; |
| | | |
| | | // Expired tasks are deleted directly. |
| | | if (time < now - offset) { |
| | | redisOps.zRemove(RedisConst.WAYLINE_JOB, jobId); |
| | | RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB, jobId); |
| | | waylineJobService.updateJob(WaylineJobDTO.builder() |
| | | .jobId(jobId) |
| | | .status(WaylineJobStatusEnum.FAILED.getVal()) |
| | |
| | | .endTime(LocalDateTime.now()) |
| | | .code(HttpStatus.SC_INTERNAL_SERVER_ERROR).build()); |
| | | } finally { |
| | | redisOps.zRemove(RedisConst.WAYLINE_JOB, jobId); |
| | | RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB, jobId); |
| | | } |
| | | } |
| | | } |
| | |
| | | @Autowired |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public PaginationData<WaylineFileDTO> getWaylinesByParam(String workspaceId, WaylineQueryParam param) { |
| | | // Paging Query |
| | |
| | | if (waylineOpt.isEmpty()) { |
| | | throw new SQLException(waylineId + " does not exist."); |
| | | } |
| | | return ossService.getObjectUrl(configuration.getBucket(), waylineOpt.get().getObjectKey()); |
| | | return ossService.getObjectUrl(OssConfiguration.bucket, waylineOpt.get().getObjectKey()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | file.setWorkspaceId(workspaceId); |
| | | |
| | | if (!StringUtils.hasText(file.getSign())) { |
| | | try (InputStream object = ossService.getObject(configuration.getBucket(), metadata.getObjectKey())) { |
| | | try (InputStream object = ossService.getObject(OssConfiguration.bucket, metadata.getObjectKey())) { |
| | | if (object.available() == 0) { |
| | | throw new RuntimeException("The file " + metadata.getObjectKey() + |
| | | " does not exist in the bucket[" + configuration.getBucket() + "]."); |
| | | " does not exist in the bucket[" + OssConfiguration.bucket + "]."); |
| | | } |
| | | file.setSign(DigestUtils.md5DigestAsHex(object)); |
| | | } catch (IOException e) { |
| | |
| | | if (!isDel) { |
| | | return false; |
| | | } |
| | | return ossService.deleteObject(configuration.getBucket(), wayline.getObjectKey()); |
| | | return ossService.deleteObject(OssConfiguration.bucket, wayline.getObjectKey()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | waylineFile.setWaylineId(workspaceId); |
| | | waylineFile.setUsername(creator); |
| | | |
| | | ossService.putObject(configuration.getBucket(), waylineFile.getObjectKey(), file.getInputStream()); |
| | | ossService.putObject(OssConfiguration.bucket, waylineFile.getObjectKey(), file.getInputStream()); |
| | | this.saveWaylineFile(workspaceId, waylineFile); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | |
| | | return Optional.of(WaylineFileDTO.builder() |
| | | .droneModelKey(String.format("%s-%s-%s", DeviceDomainEnum.SUB_DEVICE.getVal(), type, subType)) |
| | | .payloadModelKeys(List.of(String.format("%s-%s-%s",DeviceDomainEnum.PAYLOAD.getVal(), payloadType, payloadSubType))) |
| | | .objectKey(configuration.getObjectDirPrefix() + File.separator + filename) |
| | | .objectKey(OssConfiguration.objectDirPrefix + File.separator + filename) |
| | | .name(filename.substring(0, filename.lastIndexOf(WAYLINE_FILE_SUFFIX))) |
| | | .sign(DigestUtils.md5DigestAsHex(file.getInputStream())) |
| | | .templateTypes(List.of(Integer.parseInt(templateId))) |
| | |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import com.dji.sample.media.model.MediaFileCountDTO; |
| | | import com.dji.sample.media.model.MediaMethodEnum; |
| | | import com.dji.sample.media.service.IFileService; |
| | | import com.dji.sample.wayline.dao.IWaylineJobMapper; |
| | | import com.dji.sample.wayline.model.dto.*; |
| | | import com.dji.sample.wayline.model.entity.WaylineJobEntity; |
| | |
| | | private IMessageSenderService messageSender; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private IFileService fileService; |
| | | |
| | | @Override |
| | | public Optional<WaylineJobDTO> createWaylineJob(CreateJobParam param, CustomClaim customClaim) { |
| | |
| | | .waylineType(param.getWaylineType()) |
| | | .outOfControlAction(param.getOutOfControlAction()) |
| | | .rthAltitude(param.getRthAltitude()) |
| | | .mediaCount(0) |
| | | .build(); |
| | | int id = mapper.insert(jobEntity); |
| | | if (id <= 0) { |
| | |
| | | } |
| | | |
| | | if (WaylineTaskTypeEnum.TIMED.getVal() == waylineJob.getTaskType()) { |
| | | boolean isAdd = redisOps.zAdd(RedisConst.WAYLINE_JOB, waylineJob.getJobId(), |
| | | boolean isAdd = RedisOpsUtils.zAdd(RedisConst.WAYLINE_JOB, waylineJob.getJobId(), |
| | | waylineJob.getExecuteTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); |
| | | if (!isAdd) { |
| | | return ResponseResult.error("Failed to create scheduled job."); |
| | |
| | | .jobId(jobId) |
| | | .status(WaylineJobStatusEnum.IN_PROGRESS.getVal()) |
| | | .build()); |
| | | redisOps.setWithExpire(jobId, |
| | | RedisOpsUtils.setWithExpire(jobId, |
| | | EventsReceiver.<FlightTaskProgressReceiver>builder().bid(jobId).sn(job.getDockSn()).build(), |
| | | RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND); |
| | | return true; |
| | |
| | | |
| | | private void publishCancelTask(String workspaceId, String dockSn, List<String> jobIds) { |
| | | boolean isOnline = deviceService.checkDeviceOnline(dockSn); |
| | | if (isOnline) { |
| | | if (!isOnline) { |
| | | throw new RuntimeException("Dock is offline."); |
| | | } |
| | | String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + dockSn + TopicConst.SERVICES_SUF; |
| | |
| | | .status(WaylineJobStatusEnum.CANCEL.getVal()) |
| | | .endTime(LocalDateTime.now()) |
| | | .build()); |
| | | redisOps.zRemove(RedisConst.WAYLINE_JOB, jobId); |
| | | RedisOpsUtils.zRemove(RedisConst.WAYLINE_JOB, jobId); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void uploadMediaHighestPriority(String workspaceId, String jobId) { |
| | | Optional<WaylineJobDTO> jobOpt = getJobByJobId(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())) { |
| | | return; |
| | | } |
| | | |
| | | ServiceReply reply = messageSender.publishWithReply(TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + dockSn + TopicConst.SERVICES_SUF, |
| | | CommonTopicResponse.builder() |
| | | .tid(UUID.randomUUID().toString()) |
| | | .bid(UUID.randomUUID().toString()) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .method(MediaMethodEnum.UPLOAD_FLIGHT_TASK_MEDIA_PRIORITIZE.getMethod()) |
| | | .data(Map.of(MapKeyConst.FLIGHT_ID, jobId)) |
| | | .build()); |
| | | 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) { |
| | | WaylineJobEntity.WaylineJobEntityBuilder builder = WaylineJobEntity.builder(); |
| | | if (dto == null) { |
| | |
| | | if (Objects.nonNull(entity.getEndTime())) { |
| | | builder.endTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getEndTime()), ZoneId.systemDefault())); |
| | | } |
| | | if (WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() && redisOps.getExpire(entity.getJobId()) > 0) { |
| | | EventsReceiver<FlightTaskProgressReceiver> taskProgress = (EventsReceiver<FlightTaskProgressReceiver>) redisOps.get(entity.getJobId()); |
| | | if (WaylineJobStatusEnum.IN_PROGRESS.getVal() == entity.getStatus() && RedisOpsUtils.getExpire(entity.getJobId()) > 0) { |
| | | EventsReceiver<FlightTaskProgressReceiver> taskProgress = (EventsReceiver<FlightTaskProgressReceiver>) RedisOpsUtils.get(entity.getJobId()); |
| | | if (Objects.nonNull(taskProgress.getOutput()) && Objects.nonNull(taskProgress.getOutput().getProgress())) { |
| | | builder.progress(taskProgress.getOutput().getProgress().getPercent()); |
| | | } |
| | | } |
| | | |
| | | if (entity.getMediaCount() == 0) { |
| | | return builder.build(); |
| | | } |
| | | |
| | | // sync the number of media files |
| | | String key = RedisConst.MEDIA_HIGHEST_PRIORITY_PREFIX + entity.getDockSn(); |
| | | String countKey = RedisConst.MEDIA_FILE_PREFIX + entity.getDockSn(); |
| | | 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))); |
| | | return builder.build(); |
| | | } |
| | | |
| | | int uploadedSize = fileService.getFilesByWorkspaceAndJobId(entity.getWorkspaceId(), entity.getJobId()).size(); |
| | | // All media for this job have been uploaded. |
| | | if (uploadedSize >= entity.getMediaCount()) { |
| | | return builder.uploadedCount(uploadedSize).build(); |
| | | } |
| | | RedisOpsUtils.hashSet(countKey, entity.getJobId(), |
| | | MediaFileCountDTO.builder() |
| | | .jobId(entity.getJobId()) |
| | | .mediaCount(entity.getMediaCount()) |
| | | .uploadedCount(uploadedSize).build()); |
| | | return builder.build(); |
| | | } |
| | | } |
| | |
| | | max-idle: 8 |
| | | min-idle: 0 |
| | | |
| | | servlet: |
| | | multipart: |
| | | max-file-size: 2GB |
| | | max-request-size: 2GB |
| | | |
| | | jwt: |
| | | issuer: DJI |