Browse Source

V1.2.0

v1.2.0
sean.zhou 2 years ago
parent
commit
a336087883
  1. 392
      api/Cloud API Demo.postman_collection.json
  2. 16
      api/Cloud API Demo.postman_environment.json
  3. 15
      src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java
  4. 9
      src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java
  5. 46
      src/main/java/com/dji/sample/component/mqtt/handler/ServicesReplyHandler.java
  6. 2
      src/main/java/com/dji/sample/component/mqtt/model/Chan.java
  7. 6
      src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java
  8. 45
      src/main/java/com/dji/sample/component/mqtt/model/EventsMethodEnum.java
  9. 16
      src/main/java/com/dji/sample/component/mqtt/model/EventsOutputReceiver.java
  10. 2
      src/main/java/com/dji/sample/component/mqtt/model/EventsReceiver.java
  11. 47
      src/main/java/com/dji/sample/component/mqtt/model/EventsResultStatusEnum.java
  12. 2
      src/main/java/com/dji/sample/component/mqtt/model/MapKeyConst.java
  13. 18
      src/main/java/com/dji/sample/component/mqtt/model/OutputProgressReceiver.java
  14. 72
      src/main/java/com/dji/sample/component/mqtt/model/ServicesMethodEnum.java
  15. 13
      src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java
  16. 10
      src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java
  17. 3
      src/main/java/com/dji/sample/component/oss/model/enums/OssTypeEnum.java
  18. 18
      src/main/java/com/dji/sample/component/oss/service/impl/AliyunOssServiceImpl.java
  19. 13
      src/main/java/com/dji/sample/component/oss/service/impl/AmazonS3ServiceImpl.java
  20. 21
      src/main/java/com/dji/sample/component/oss/service/impl/MinIOServiceImpl.java
  21. 18
      src/main/java/com/dji/sample/component/redis/RedisConst.java
  22. 26
      src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java
  23. 2
      src/main/java/com/dji/sample/component/websocket/service/impl/WebSocketManageServiceImpl.java
  24. 4
      src/main/java/com/dji/sample/configuration/SpringBeanConfiguration.java
  25. 33
      src/main/java/com/dji/sample/configuration/mvc/GetSnakeArgumentProcessor.java
  26. 53
      src/main/java/com/dji/sample/configuration/mvc/GetSnakeDataBinder.java
  27. 9
      src/main/java/com/dji/sample/configuration/mvc/GlobalMVCConfigurer.java
  28. 30
      src/main/java/com/dji/sample/control/controller/DockController.java
  29. 18
      src/main/java/com/dji/sample/control/service/IControlService.java
  30. 133
      src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java
  31. 45
      src/main/java/com/dji/sample/manage/controller/DeviceController.java
  32. 43
      src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java
  33. 18
      src/main/java/com/dji/sample/manage/controller/DeviceHmsController.java
  34. 122
      src/main/java/com/dji/sample/manage/controller/DeviceLogsController.java
  35. 17
      src/main/java/com/dji/sample/manage/controller/DevicePayloadController.java
  36. 26
      src/main/java/com/dji/sample/manage/controller/LiveStreamController.java
  37. 12
      src/main/java/com/dji/sample/manage/dao/IDeviceFirmwareMapper.java
  38. 12
      src/main/java/com/dji/sample/manage/dao/IDeviceLogsMapper.java
  39. 12
      src/main/java/com/dji/sample/manage/dao/ILogsFileIndexMapper.java
  40. 12
      src/main/java/com/dji/sample/manage/dao/ILogsFileMapper.java
  41. 3
      src/main/java/com/dji/sample/manage/model/common/HmsJsonUtil.java
  42. 4
      src/main/java/com/dji/sample/manage/model/dto/DeviceDTO.java
  43. 40
      src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java
  44. 28
      src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareNoteDTO.java
  45. 20
      src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareUpgradeDTO.java
  46. 41
      src/main/java/com/dji/sample/manage/model/dto/DeviceLogsDTO.java
  47. 35
      src/main/java/com/dji/sample/manage/model/dto/LogsFileDTO.java
  48. 26
      src/main/java/com/dji/sample/manage/model/dto/LogsOutputProgressDTO.java
  49. 31
      src/main/java/com/dji/sample/manage/model/dto/LogsProgressDTO.java
  50. 47
      src/main/java/com/dji/sample/manage/model/dto/LogsUploadCredentialsDTO.java
  51. 3
      src/main/java/com/dji/sample/manage/model/entity/DeviceEntity.java
  52. 64
      src/main/java/com/dji/sample/manage/model/entity/DeviceFirmwareEntity.java
  53. 2
      src/main/java/com/dji/sample/manage/model/entity/DeviceHmsEntity.java
  54. 52
      src/main/java/com/dji/sample/manage/model/entity/DeviceLogsEntity.java
  55. 58
      src/main/java/com/dji/sample/manage/model/entity/LogsFileEntity.java
  56. 54
      src/main/java/com/dji/sample/manage/model/entity/LogsFileIndexEntity.java
  57. 62
      src/main/java/com/dji/sample/manage/model/enums/DeviceFirmwareStatusEnum.java
  58. 41
      src/main/java/com/dji/sample/manage/model/enums/DeviceLogsStatusEnum.java
  59. 36
      src/main/java/com/dji/sample/manage/model/enums/HmsEnum.java
  60. 28
      src/main/java/com/dji/sample/manage/model/enums/LogsFileUpdateMethodEnum.java
  61. 9
      src/main/java/com/dji/sample/manage/model/param/DeviceHmsQueryParam.java
  62. 21
      src/main/java/com/dji/sample/manage/model/param/DeviceLogsCreateParam.java
  63. 24
      src/main/java/com/dji/sample/manage/model/param/DeviceLogsQueryParam.java
  64. 32
      src/main/java/com/dji/sample/manage/model/param/DeviceOtaCreateParam.java
  65. 21
      src/main/java/com/dji/sample/manage/model/param/LogsFileUpdateParam.java
  66. 27
      src/main/java/com/dji/sample/manage/model/receiver/LogsExtFileReceiver.java
  67. 26
      src/main/java/com/dji/sample/manage/model/receiver/LogsFile.java
  68. 34
      src/main/java/com/dji/sample/manage/model/receiver/LogsFileUpload.java
  69. 24
      src/main/java/com/dji/sample/manage/model/receiver/LogsFileUploadList.java
  70. 26
      src/main/java/com/dji/sample/manage/model/receiver/LogsProgressReceiver.java
  71. 16
      src/main/java/com/dji/sample/manage/model/receiver/OutputLogsExtReceiver.java
  72. 16
      src/main/java/com/dji/sample/manage/model/receiver/OutputLogsProgressReceiver.java
  73. 3
      src/main/java/com/dji/sample/manage/service/ICapacityCameraService.java
  74. 48
      src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java
  75. 14
      src/main/java/com/dji/sample/manage/service/IDeviceHmsService.java
  76. 94
      src/main/java/com/dji/sample/manage/service/IDeviceLogsService.java
  77. 14
      src/main/java/com/dji/sample/manage/service/IDevicePayloadService.java
  78. 10
      src/main/java/com/dji/sample/manage/service/IDeviceService.java
  79. 3
      src/main/java/com/dji/sample/manage/service/ILiveStreamService.java
  80. 46
      src/main/java/com/dji/sample/manage/service/ILogsFileIndexService.java
  81. 66
      src/main/java/com/dji/sample/manage/service/ILogsFileService.java
  82. 8
      src/main/java/com/dji/sample/manage/service/ITopologyService.java
  83. 4
      src/main/java/com/dji/sample/manage/service/impl/CapacityCameraServiceImpl.java
  84. 218
      src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java
  85. 172
      src/main/java/com/dji/sample/manage/service/impl/DeviceHmsServiceImpl.java
  86. 376
      src/main/java/com/dji/sample/manage/service/impl/DeviceLogsServiceImpl.java
  87. 50
      src/main/java/com/dji/sample/manage/service/impl/DevicePayloadServiceImpl.java
  88. 111
      src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
  89. 16
      src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java
  90. 108
      src/main/java/com/dji/sample/manage/service/impl/LogsFileIndexServiceImpl.java
  91. 163
      src/main/java/com/dji/sample/manage/service/impl/LogsFileServiceImpl.java
  92. 19
      src/main/java/com/dji/sample/manage/service/impl/TopologyServiceImpl.java
  93. 2
      src/main/java/com/dji/sample/map/service/impl/GroupElementServiceImpl.java
  94. 10
      src/main/java/com/dji/sample/media/controller/FileController.java
  95. 8
      src/main/java/com/dji/sample/media/model/CredentialsDTO.java
  96. 2
      src/main/java/com/dji/sample/media/model/MediaFileDTO.java
  97. 3
      src/main/java/com/dji/sample/media/model/MediaFileEntity.java
  98. 4
      src/main/java/com/dji/sample/media/service/IFileService.java
  99. 14
      src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java
  100. 17
      src/main/resources/application.yml
  101. Some files were not shown because too many files have changed in this diff Show More

392
api/Cloud API Demo.postman_collection.json

@ -149,7 +149,7 @@
"header": [], "header": [],
"body": { "body": {
"mode": "raw", "mode": "raw",
"raw": "{\r\n \"url\": \"rtmp://192.168.1.1/live/1651053434895\",\r\n \"url_type\": 1,\r\n \"video_id\": \"1581F4BN/52-0-0/zoom-0\",\r\n \"video_quality\": 0\r\n}", "raw": "{\r\n \"url\": \"rtmp://192.168.1.1/live/1651053434895\",\r\n \"url_type\": 1,\r\n \"video_id\": \"1581F5B0159/53-0-0/normal-0\",\r\n \"video_quality\": 0\r\n}",
"options": { "options": {
"raw": { "raw": {
"language": "json" "language": "json"
@ -383,6 +383,326 @@
} }
}, },
"response": [] "response": []
},
{
"name": "Firmware Upgrad",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "[\r\n {\r\n \"sn\": \"1581F5B9\",\r\n \"device_name\": \"Matrice 30\",\r\n \"product_version\": \"04.01.0020\",\r\n \"firmware_upgrade_type\": 3\r\n }\r\n]\r\n",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/ota",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"devices",
"{{workspace_id}}",
"devices",
"ota"
]
}
},
"response": []
},
{
"name": "Get Latest Release Note",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/workspaces/firmware-release-notes/latest?device_name=DJI Dock",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"workspaces",
"firmware-release-notes",
"latest"
],
"query": [
{
"key": "device_name",
"value": "DJI Dock"
}
]
}
},
"response": []
},
{
"name": "Get HMS Info",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/hms?device_sn=&language=en&page=1&page_size=2",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"devices",
"{{workspace_id}}",
"devices",
"hms"
],
"query": [
{
"key": "device_sn",
"value": "",
"description": "Type: List"
},
{
"key": "begin_time",
"value": null,
"disabled": true
},
{
"key": "end_time",
"value": null,
"disabled": true
},
{
"key": "language",
"value": "en",
"description": "zh or en"
},
{
"key": "message",
"value": null,
"disabled": true
},
{
"key": "page",
"value": "1"
},
{
"key": "page_size",
"value": "2"
},
{
"key": "level",
"value": null,
"disabled": true
},
{
"key": "update_time",
"value": null,
"description": "Type: Long",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "Update Unread HMS",
"request": {
"method": "PUT",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/hms/{{device_sn}}",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"devices",
"{{workspace_id}}",
"devices",
"hms",
"{{device_sn}}"
]
}
},
"response": []
},
{
"name": "Get Unread Hms",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/hms/{{device_sn}}",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"devices",
"{{workspace_id}}",
"devices",
"hms",
"{{device_sn}}"
]
}
},
"response": []
},
{
"name": "Get Uploaded Logs",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/devices/{{device_sn}}/logs-uploaded?page=1&page_size=12&begin_time=123123&end_time=123123",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"workspaces",
"{{workspace_id}}",
"devices",
"{{device_sn}}",
"logs-uploaded"
],
"query": [
{
"key": "page",
"value": "1"
},
{
"key": "page_size",
"value": "12"
},
{
"key": "status",
"value": null,
"disabled": true
},
{
"key": "begin_time",
"value": "123123"
},
{
"key": "end_time",
"value": "123123"
},
{
"key": "logs_information",
"value": "",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "Get Real Time Logs",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/devices/{{device_sn}}/logs?domain_list=0,3",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"workspaces",
"{{workspace_id}}",
"devices",
"{{device_sn}}",
"logs"
],
"query": [
{
"key": "domain_list",
"value": "0,3"
}
]
}
},
"response": []
},
{
"name": "Upload Logs",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"logs_information\":\"\",\r\n \"happen_time\":1659326597,\r\n \"files\":[\r\n {\r\n \"list\":[\r\n {\r\n \"boot_index\":1053,\r\n \"end_time\":1662070409,\r\n \"size\":1083590875,\r\n \"start_time\":1662066809\r\n }\r\n ],\r\n \"device_sn\":\"4TADK1D\",\r\n \"module\":\"3\"\r\n },\r\n {\r\n \"list\":[\r\n {\r\n \"boot_index\":222,\r\n \"end_time\":1661833032,\r\n \"size\":1782411613,\r\n \"start_time\":1661830103\r\n }\r\n ],\r\n \"device_sn\":\"1581259\",\r\n \"module\":\"0\"\r\n }\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/devices/{{device_sn}}/logs",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"workspaces",
"{{workspace_id}}",
"devices",
"{{device_sn}}",
"logs"
]
}
},
"response": []
},
{
"name": "Cancel File Upload",
"request": {
"method": "DELETE",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"status\":\"cancel\",\r\n \"module_list\":[\r\n \"0\",\r\n \"3\"\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/devices/{{device_sn}}/logs",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"workspaces",
"{{workspace_id}}",
"devices",
"{{device_sn}}",
"logs"
]
}
},
"response": []
},
{
"name": "Delete Upload History",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}{{manage_version}}/workspaces/{{workspace_id}}/devices/{{device_sn}}/logs/{{logs_id}}",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"workspaces",
"{{workspace_id}}",
"devices",
"{{device_sn}}",
"logs",
"{{logs_id}}"
]
}
},
"response": []
} }
], ],
"auth": { "auth": {
@ -390,7 +710,7 @@
"apikey": [ "apikey": [
{ {
"key": "value", "key": "value",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTI2OTUxOTcsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTI3ODE1OTcsImlhdCI6MTY1MjY5NTE5NywidXNlcm5hbWUiOiJhZG1pblBDIn0.BHTwW8imw5ab0GUypRyJ2gkoz5av9q99NrxoFlL53dA", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NjM1NTkxMTAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NjM2NDU1MTAsImlhdCI6MTY2MzU1OTExMCwidXNlcm5hbWUiOiJhZG1pblBDIn0.LG1JXZkuTdMaqnXn5WMJvnysNkHHbc4HLe_qZPWz_nM",
"type": "string" "type": "string"
}, },
{ {
@ -723,7 +1043,7 @@
"apikey": [ "apikey": [
{ {
"key": "value", "key": "value",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTgzOTIyNzksImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTg0Nzg2NzksImlhdCI6MTY1ODM5MjI3OSwidXNlcm5hbWUiOiJhZG1pblBDIn0.ErClyQS1YzoQVBcLYxpFEiyFTb1L-eg2-vsudlL9WJU", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NjI2OTYwNjMsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NjI3ODI0NjMsImlhdCI6MTY2MjY5NjA2MywidXNlcm5hbWUiOiJhZG1pblBDIn0.9XEd-Zspb_a-2WhtcHxbQ4GdHbBj9wfmUbHBkZgSS0c",
"type": "string" "type": "string"
}, },
{ {
@ -783,7 +1103,7 @@
"apikey": [ "apikey": [
{ {
"key": "value", "key": "value",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTI2OTUxOTcsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTI3ODE1OTcsImlhdCI6MTY1MjY5NTE5NywidXNlcm5hbWUiOiJhZG1pblBDIn0.BHTwW8imw5ab0GUypRyJ2gkoz5av9q99NrxoFlL53dA", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTg3MTgxNTMsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTg4MDQ1NTMsImlhdCI6MTY1ODcxODE1MywidXNlcm5hbWUiOiJhZG1pblBDIn0._Xw3rnnDhs32JW9pD_FBtRWDuwLZgX_ys3GNmZxuHsk",
"type": "string" "type": "string"
}, },
{ {
@ -1050,7 +1370,7 @@
"header": [], "header": [],
"body": { "body": {
"mode": "raw", "mode": "raw",
"raw": "{\r\n \"name\": \"\",\r\n \"fild_id\": \"\",\r\n \"dock_sn\": \"\",\r\n \"type\": \"\",\r\n \"immediate\": false\r\n}", "raw": "{\r\n \"name\": \"\",\r\n \"file_id\": \"\",\r\n \"dock_sn\": \"\",\r\n \"type\": \"\",\r\n \"immediate\": false\r\n}",
"options": { "options": {
"raw": { "raw": {
"language": "json" "language": "json"
@ -1156,6 +1476,66 @@
} }
} }
] ]
},
{
"name": "control",
"item": [
{
"name": "Create Control Job",
"request": {
"method": "POST",
"header": [],
"url": {
"raw": "{{base_url}}{{control_version}}/devices/4TADK7E000000H/jobs/debug_mode_close",
"host": [
"{{base_url}}{{control_version}}"
],
"path": [
"devices",
"4TADK7E000000H",
"jobs",
"debug_mode_close"
]
}
},
"response": []
}
],
"auth": {
"type": "apikey",
"apikey": [
{
"key": "value",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NjE5NTQwMTQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NjIwNDA0MTQsImlhdCI6MTY2MTk1NDAxNCwidXNlcm5hbWUiOiJhZG1pblBDIn0.GgCh575h2-HvYvdGZIKBW50r0F6CPACQn4ceAVzJfCU",
"type": "string"
},
{
"key": "key",
"value": "x-auth-token",
"type": "string"
}
]
},
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
]
} }
], ],
"auth": { "auth": {
@ -1163,7 +1543,7 @@
"apikey": [ "apikey": [
{ {
"key": "value", "key": "value",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTA0MjY3MzAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTA1MTMxMzAsImlhdCI6MTY1MDQyNjczMCwidXNlcm5hbWUiOiJhZG1pblBDIn0.-FBpi0ktuZ68jV6-HQ7mwm8iC07YH-Hw2aRiREzJ8hs", "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NjMyMjM1MTAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NjMzMDk5MTAsImlhdCI6MTY2MzIyMzUxMCwidXNlcm5hbWUiOiJhZG1pblBDIn0.6gzNuuX2f0YBoddoD61NFnwABQ_X4LFtQhEaLWSmTW8",
"type": "string" "type": "string"
}, },
{ {

16
api/Cloud API Demo.postman_environment.json

@ -52,9 +52,21 @@
"key": "storage_version", "key": "storage_version",
"value": "/storage/api/v1", "value": "/storage/api/v1",
"enabled": true "enabled": true
},
{
"key": "control_version",
"value": "/control/api/v1",
"type": "default",
"enabled": true
},
{
"key": "device_sn",
"value": "xxxxxxxxxx",
"type": "default",
"enabled": true
} }
], ],
"_postman_variable_scope": "environment", "_postman_variable_scope": "environment",
"_postman_exported_at": "2022-07-21T08:35:48.441Z", "_postman_exported_at": "2022-09-23T03:53:25.999Z",
"_postman_exported_using": "Postman/9.19.0" "_postman_exported_using": "Postman/9.31.0"
} }

15
src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java

@ -137,4 +137,19 @@ public class MqttMessageChannel {
return new DirectChannel(); return new DirectChannel();
} }
@Bean(name = ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS)
public MessageChannel eventsControlProgress() {
return new DirectChannel();
}
@Bean(name = ChannelName.INBOUND_EVENTS_OTA_PROGRESS)
public MessageChannel eventsOtaProgress() {
return new DirectChannel();
}
@Bean(name = ChannelName.INBOUND_EVENTS_FILE_UPLOAD_PROGRESS)
public MessageChannel eventsFileUploadProgress() {
return new DirectChannel();
}
} }

9
src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java

@ -11,6 +11,7 @@ import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows; import org.springframework.integration.dsl.IntegrationFlows;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
/** /**
* @author sean * @author sean
@ -37,12 +38,8 @@ public class EventsRouter {
}) })
.<CommonTopicReceiver, EventsMethodEnum>route( .<CommonTopicReceiver, EventsMethodEnum>route(
receiver -> EventsMethodEnum.find(receiver.getMethod()), receiver -> EventsMethodEnum.find(receiver.getMethod()),
mapping -> { mapping -> Arrays.stream(EventsMethodEnum.values()).forEach(
mapping.channelMapping(EventsMethodEnum.FILE_UPLOAD_CALLBACK, ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK); methodEnum -> mapping.channelMapping(methodEnum, methodEnum.getChannelName())))
mapping.channelMapping(EventsMethodEnum.FLIGHT_TASK_PROGRESS, ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS);
mapping.channelMapping(EventsMethodEnum.HMS, ChannelName.INBOUND_EVENTS_HMS);
mapping.channelMapping(EventsMethodEnum.UNKNOWN, ChannelName.DEFAULT);
})
.get(); .get();
} }
} }

46
src/main/java/com/dji/sample/component/mqtt/handler/ServicesReplyHandler.java

@ -0,0 +1,46 @@
package com.dji.sample.component.mqtt.handler;
import com.dji.sample.component.mqtt.model.*;
import com.dji.sample.manage.model.receiver.LogsFileUploadList;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Component
public class ServicesReplyHandler {
@Autowired
private ObjectMapper mapper;
/**
* Handle the reply message from the pilot side to the on-demand video.
* @param message reply message
* @throws IOException
*/
@ServiceActivator(inputChannel = ChannelName.INBOUND_SERVICE_REPLY)
public void serviceReply(Message<?> message) throws IOException {
byte[] payload = (byte[])message.getPayload();
CommonTopicReceiver receiver = mapper.readValue(payload, new TypeReference<CommonTopicReceiver>() {});
if (ServicesMethodEnum.FILE_UPLOAD_LIST.getMethod().equals(receiver.getMethod())) {
LogsFileUploadList list = mapper.convertValue(receiver.getData(), new TypeReference<LogsFileUploadList>() {});
receiver.setData(list);
} else {
ServiceReply reply = mapper.convertValue(receiver.getData(), new TypeReference<ServiceReply>() {});
receiver.setData(reply);
}
Chan<CommonTopicReceiver<?>> chan = Chan.getInstance();
// Put the message to the chan object.
chan.put(receiver);
}
}

2
src/main/java/com/dji/sample/component/mqtt/model/Chan.java

@ -10,7 +10,7 @@ import java.util.concurrent.locks.LockSupport;
*/ */
public class Chan<T> { public class Chan<T> {
private static final long THREAD_WAIT_TIME = 1000_000 * 2000; private static final long THREAD_WAIT_TIME = 1000_000L * 10_000;
private volatile T data; private volatile T data;

6
src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java

@ -62,4 +62,10 @@ public class ChannelName {
public static final String INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND = "inboundRequestsAirportOrganizationBind"; public static final String INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND = "inboundRequestsAirportOrganizationBind";
public static final String INBOUND_EVENTS_HMS = "inboundEventsHms"; public static final String INBOUND_EVENTS_HMS = "inboundEventsHms";
public static final String INBOUND_EVENTS_CONTROL_PROGRESS = "inboundEventsControlProgress";
public static final String INBOUND_EVENTS_OTA_PROGRESS = "inboundEventsOtaProgress";
public static final String INBOUND_EVENTS_FILE_UPLOAD_PROGRESS = "inboundEventsFileUploadProgress";
} }

45
src/main/java/com/dji/sample/component/mqtt/model/EventsMethodEnum.java

@ -9,24 +9,59 @@ import java.util.Arrays;
*/ */
public enum EventsMethodEnum { public enum EventsMethodEnum {
FLIGHT_TASK_PROGRESS("flighttask_progress"), FLIGHT_TASK_PROGRESS("flighttask_progress", ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS),
FILE_UPLOAD_CALLBACK("file_upload_callback"), FILE_UPLOAD_CALLBACK("file_upload_callback", ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK),
HMS("hms"), HMS("hms", ChannelName.INBOUND_EVENTS_HMS),
UNKNOWN("Unknown"); DEVICE_REBOOT("device_reboot", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
DRONE_OPEN("drone_open", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
DRONE_CLOSE("drone_close", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
DEVICE_CHECK("device_check", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
DRONE_FORMAT("drone_format", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
DEVICE_FORMAT("device_format", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
COVER_OPEN("cover_open", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
COVER_CLOSE("cover_close", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
PUTTER_OPEN("putter_open", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
PUTTER_CLOSE("putter_close", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
CHARGE_OPEN("charge_open", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
CHARGE_CLOSE("charge_close", ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS),
OTA_PROGRESS("ota_progress", ChannelName.INBOUND_EVENTS_OTA_PROGRESS),
FILE_UPLOAD_PROGRESS("fileupload_progress", ChannelName.INBOUND_EVENTS_FILE_UPLOAD_PROGRESS),
UNKNOWN("Unknown", ChannelName.DEFAULT);
private String method; private String method;
EventsMethodEnum(String method) { private String channelName;
EventsMethodEnum(String method, String channelName) {
this.method = method; this.method = method;
this.channelName = channelName;
} }
public String getMethod() { public String getMethod() {
return method; return method;
} }
public String getChannelName() {
return channelName;
}
public static EventsMethodEnum find(String method) { public static EventsMethodEnum find(String method) {
return Arrays.stream(EventsMethodEnum.values()) return Arrays.stream(EventsMethodEnum.values())
.filter(methodEnum -> methodEnum.method.equals(method)) .filter(methodEnum -> methodEnum.method.equals(method))

16
src/main/java/com/dji/sample/component/mqtt/model/EventsOutputReceiver.java

@ -0,0 +1,16 @@
package com.dji.sample.component.mqtt.model;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/7/29
*/
@Data
public class EventsOutputReceiver {
private String status;
private OutputProgressReceiver progress;
}

2
src/main/java/com/dji/sample/component/mqtt/model/EventsReceiver.java

@ -18,4 +18,6 @@ public class EventsReceiver<T> {
private String bid; private String bid;
private String sn;
} }

47
src/main/java/com/dji/sample/component/mqtt/model/EventsResultStatusEnum.java

@ -0,0 +1,47 @@
package com.dji.sample.component.mqtt.model;
import lombok.Getter;
import java.util.Arrays;
/**
* @author sean
* @version 1.2
* @date 2022/8/17
*/
@Getter
public enum EventsResultStatusEnum {
SENT("sent", false),
IN_PROGRESS("in_progress", false),
OK("ok", true),
PAUSED("paused", false),
REJECTED("rejected", true),
FAILED("failed", true),
CANCELED("canceled", true),
TIMEOUT("timeout", true),
UNKNOWN("unknown", false);
String desc;
Boolean end;
EventsResultStatusEnum(String desc, Boolean end) {
this.desc = desc;
this.end = end;
}
public static EventsResultStatusEnum find(String desc) {
return Arrays.stream(EventsResultStatusEnum.values())
.filter(status -> status.desc.equals(desc))
.findFirst().orElse(UNKNOWN);
}
}

2
src/main/java/com/dji/sample/component/mqtt/model/MapKeyConst.java

@ -26,4 +26,6 @@ public final class MapKeyConst {
public static final String BIND_STATUS = "bind_status"; public static final String BIND_STATUS = "bind_status";
public static final String LIST = "list"; public static final String LIST = "list";
public static final String MODULE_LIST = "module_list";
} }

18
src/main/java/com/dji/sample/component/mqtt/model/OutputProgressReceiver.java

@ -0,0 +1,18 @@
package com.dji.sample.component.mqtt.model;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/7/29
*/
@Data
public class OutputProgressReceiver {
private Integer percent;
private String stepKey;
private Integer stepResult;
}

72
src/main/java/com/dji/sample/component/mqtt/model/ServicesMethodEnum.java

@ -1,5 +1,7 @@
package com.dji.sample.component.mqtt.model; package com.dji.sample.component.mqtt.model;
import java.util.Arrays;
/** /**
* @author sean.zhou * @author sean.zhou
* @date 2021/11/22 * @date 2021/11/22
@ -7,23 +9,81 @@ package com.dji.sample.component.mqtt.model;
*/ */
public enum ServicesMethodEnum { public enum ServicesMethodEnum {
LIVE_START_PUSH("live_start_push"), LIVE_START_PUSH("live_start_push", false),
LIVE_STOP_PUSH("live_stop_push", false),
LIVE_SET_QUALITY("live_set_quality", false),
FLIGHTTASK_CREATE("flighttask_create", false),
DEBUG_MODE_OPEN("debug_mode_open", false),
DEBUG_MODE_CLOSE("debug_mode_close", false),
SUPPLEMENT_LIGHT_OPEN("supplement_light_open", false),
SUPPLEMENT_LIGHT_CLOSE("supplement_light_close", false),
RETURN_HOME("return_home", false),
SDR_WORKMODE_SWITCH("sdr_workmode_switch", false),
DEVICE_REBOOT("device_reboot", true),
DRONE_OPEN("drone_open", true),
DRONE_CLOSE("drone_close", true),
DEVICE_CHECK("device_check", true),
LIVE_STOP_PUSH("live_stop_push"), DRONE_FORMAT("drone_format", true),
LIVE_SET_QUALITY("live_set_quality"), DEVICE_FORMAT("device_format", true),
FLIGHTTASK_CREATE("flighttask_create"), COVER_OPEN("cover_open", true),
UNKNOWN("unknown"); COVER_CLOSE("cover_close", true),
PUTTER_OPEN("putter_open", true),
PUTTER_CLOSE("putter_close", true),
CHARGE_OPEN("charge_open", true),
CHARGE_CLOSE("charge_close", true),
OTA_CREATE("ota_create", true),
FILE_UPLOAD_LIST("fileupload_list", false),
FILE_UPLOAD_START("fileupload_start", true),
FILE_UPLOAD_UPDATE("fileupload_update", false),
UNKNOWN("unknown", false);
private String method; private String method;
ServicesMethodEnum(String method) { private Boolean progress;
ServicesMethodEnum(String method, Boolean progress) {
this.method = method; this.method = method;
this.progress = progress;
}
public static ServicesMethodEnum find(String method) {
return Arrays.stream(ServicesMethodEnum.values())
.filter(methodEnum -> methodEnum.method.equals(method))
.findAny()
.orElse(UNKNOWN);
} }
public String getMethod() { public String getMethod() {
return method; return method;
} }
public Boolean getProgress() {
return progress;
}
} }

13
src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java

@ -28,10 +28,21 @@ public interface IMessageSenderService {
void publish(String topic, int qos, CommonTopicResponse response); void publish(String topic, int qos, CommonTopicResponse response);
/** /**
* Send live streaming start message and receive a response at the same time * Send live streaming start message and receive a response at the same time.
* @param topic * @param topic
* @param response notification of whether the start is successful. * @param response notification of whether the start is successful.
* @return * @return
*/ */
Optional<ServiceReply> publishWithReply(String topic, CommonTopicResponse response); Optional<ServiceReply> publishWithReply(String topic, CommonTopicResponse response);
/**
* Send live streaming start message and receive a response at the same time.
* @param clazz
* @param topic
* @param response
* @param retryTime
* @param <T>
* @return
*/
<T> Optional<T> publishWithReply(Class<T> clazz, String topic, CommonTopicResponse response, int retryTime);
} }

10
src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java

@ -50,14 +50,18 @@ public class MessageSenderServiceImpl implements IMessageSenderService {
} }
public Optional<ServiceReply> publishWithReply(String topic, CommonTopicResponse response) { public Optional<ServiceReply> publishWithReply(String topic, CommonTopicResponse response) {
return this.publishWithReply(ServiceReply.class, topic, response, 2);
}
public <T> Optional<T> publishWithReply(Class<T> clazz, String topic, CommonTopicResponse response, int retryTime) {
AtomicInteger time = new AtomicInteger(0); AtomicInteger time = new AtomicInteger(0);
// Retry three times // Retry three times
while (time.getAndIncrement() < 3) { while (time.getAndIncrement() < retryTime) {
this.publish(topic, response); this.publish(topic, response);
Chan<CommonTopicReceiver<ServiceReply>> chan = Chan.getInstance(); Chan<CommonTopicReceiver<T>> chan = Chan.getInstance();
// If the message is not received in 0.5 seconds then resend it again. // If the message is not received in 0.5 seconds then resend it again.
CommonTopicReceiver<ServiceReply> receiver = chan.get(response.getMethod()); CommonTopicReceiver<T> receiver = chan.get(response.getMethod());
if (receiver == null) { if (receiver == null) {
continue; continue;
} }

3
src/main/java/com/dji/sample/component/oss/model/enums/OssTypeEnum.java

@ -11,9 +11,6 @@ public enum OssTypeEnum {
AWS("aws"), AWS("aws"),
/*
* MinIO is temporarily unavailable.
*/
MINIO("minio"); MINIO("minio");
private String type; private String type;

18
src/main/java/com/dji/sample/component/oss/service/impl/AliyunOssServiceImpl.java

@ -2,6 +2,7 @@ package com.dji.sample.component.oss.service.impl;
import com.aliyun.oss.OSS; import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.OSSObject; import com.aliyun.oss.model.OSSObject;
import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient; import com.aliyuncs.IAcsClient;
@ -70,7 +71,10 @@ public class AliyunOssServiceImpl implements IOssService {
} }
OSS ossClient = this.createClient(); OSS ossClient = this.createClient();
// First check if the object can be fetched. // First check if the object can be fetched.
ossClient.getObject(bucket, objectKey); boolean isExist = ossClient.doesObjectExist(bucket, objectKey);
if (!isExist) {
throw new OSSException("The object does not exist.");
}
return ossClient.generatePresignedUrl(bucket, objectKey, return ossClient.generatePresignedUrl(bucket, objectKey,
new Date(System.currentTimeMillis() + configuration.getExpire() * 1000)); new Date(System.currentTimeMillis() + configuration.getExpire() * 1000));
@ -79,6 +83,10 @@ public class AliyunOssServiceImpl implements IOssService {
@Override @Override
public Boolean deleteObject(String bucket, String objectKey) { public Boolean deleteObject(String bucket, String objectKey) {
OSS ossClient = this.createClient(); OSS ossClient = this.createClient();
if (!ossClient.doesObjectExist(bucket, objectKey)) {
ossClient.shutdown();
return true;
}
ossClient.deleteObject(bucket, objectKey); ossClient.deleteObject(bucket, objectKey);
ossClient.shutdown(); ossClient.shutdown();
return true; return true;
@ -88,19 +96,13 @@ public class AliyunOssServiceImpl implements IOssService {
public byte[] getObject(String bucket, String objectKey) { public byte[] getObject(String bucket, String objectKey) {
OSS ossClient = this.createClient(); OSS ossClient = this.createClient();
OSSObject object = ossClient.getObject(bucket, objectKey); OSSObject object = ossClient.getObject(bucket, objectKey);
InputStream stream = object.getObjectContent();
try { try (InputStream stream = object.getObjectContent()) {
return stream.readAllBytes(); return stream.readAllBytes();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try {
stream.close();
ossClient.shutdown(); ossClient.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
} }
return new byte[0]; return new byte[0];
} }

13
src/main/java/com/dji/sample/component/oss/service/impl/AmazonS3ServiceImpl.java

@ -74,6 +74,10 @@ public class AmazonS3ServiceImpl implements IOssService {
@Override @Override
public Boolean deleteObject(String bucket, String objectKey) { public Boolean deleteObject(String bucket, String objectKey) {
AmazonS3 client = this.createClient(); AmazonS3 client = this.createClient();
if (!client.doesObjectExist(bucket, objectKey)) {
client.shutdown();
return true;
}
client.deleteObject(bucket, objectKey); client.deleteObject(bucket, objectKey);
client.shutdown(); client.shutdown();
return true; return true;
@ -82,18 +86,13 @@ public class AmazonS3ServiceImpl implements IOssService {
public byte[] getObject(String bucket, String objectKey) { public byte[] getObject(String bucket, String objectKey) {
AmazonS3 client = this.createClient(); AmazonS3 client = this.createClient();
S3Object object = client.getObject(bucket, objectKey); S3Object object = client.getObject(bucket, objectKey);
InputStream stream = object.getObjectContent().getDelegateStream();
try { try (InputStream stream = object.getObjectContent().getDelegateStream()) {
return stream.readAllBytes(); return stream.readAllBytes();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try {
stream.close();
client.shutdown(); client.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
} }
return new byte[0]; return new byte[0];
} }

21
src/main/java/com/dji/sample/component/oss/service/impl/MinIOServiceImpl.java

@ -4,8 +4,10 @@ import com.dji.sample.component.oss.model.OssConfiguration;
import com.dji.sample.component.oss.model.enums.OssTypeEnum; import com.dji.sample.component.oss.model.enums.OssTypeEnum;
import com.dji.sample.component.oss.service.IOssService; import com.dji.sample.component.oss.service.IOssService;
import com.dji.sample.media.model.CredentialsDTO; import com.dji.sample.media.model.CredentialsDTO;
import io.minio.GetObjectArgs;
import io.minio.GetPresignedObjectUrlArgs; import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient; import io.minio.MinioClient;
import io.minio.RemoveObjectArgs;
import io.minio.credentials.AssumeRoleProvider; import io.minio.credentials.AssumeRoleProvider;
import io.minio.errors.*; import io.minio.errors.*;
import io.minio.http.Method; import io.minio.http.Method;
@ -14,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -41,7 +44,7 @@ public class MinIOServiceImpl implements IOssService {
AssumeRoleProvider provider = new AssumeRoleProvider(configuration.getEndpoint(), configuration.getAccessKey(), AssumeRoleProvider provider = new AssumeRoleProvider(configuration.getEndpoint(), configuration.getAccessKey(),
configuration.getSecretKey(), Math.toIntExact(configuration.getExpire()), configuration.getSecretKey(), Math.toIntExact(configuration.getExpire()),
null, configuration.getRegion(), null, null, null, null); null, configuration.getRegion(), null, null, null, null);
return new CredentialsDTO(provider.fetch(), Math.toIntExact(configuration.getExpire())); return new CredentialsDTO(provider.fetch(), configuration.getExpire());
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
log.debug("Failed to obtain sts."); log.debug("Failed to obtain sts.");
e.printStackTrace(); e.printStackTrace();
@ -72,11 +75,25 @@ public class MinIOServiceImpl implements IOssService {
@Override @Override
public Boolean deleteObject(String bucket, String objectKey) { public Boolean deleteObject(String bucket, String objectKey) {
return null; MinioClient client = this.createClient();
try {
client.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectKey).build());
} catch (MinioException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
log.error("Failed to delete file.");
e.printStackTrace();
return false;
}
return true;
} }
@Override @Override
public byte[] getObject(String bucket, String objectKey) { public byte[] getObject(String bucket, String objectKey) {
MinioClient client = this.createClient();
try (InputStream objectResponse = client.getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build())) {
return objectResponse.readAllBytes();
} catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return new byte[0]; return new byte[0];
} }

18
src/main/java/com/dji/sample/component/redis/RedisConst.java

@ -13,17 +13,25 @@ public final class RedisConst {
} }
public static final String DELIMITER = ":";
public static final Integer DEVICE_ALIVE_SECOND = 60; public static final Integer DEVICE_ALIVE_SECOND = 60;
public static final Integer WEBSOCKET_ALIVE_SECOND = 60 * 60 * 24; public static final Integer WEBSOCKET_ALIVE_SECOND = 60 * 60 * 24;
public static final String ONLINE_PREFIX = "online:"; public static final String ONLINE_PREFIX = "online" + DELIMITER;
public static final String DEVICE_ONLINE_PREFIX = ONLINE_PREFIX + DeviceDomainEnum.SUB_DEVICE + DELIMITER;
public static final String WEBSOCKET_PREFIX = "webSocket" + DELIMITER;
public static final String WEBSOCKET_ALL = WEBSOCKET_PREFIX + "all";
public static final String DEVICE_ONLINE_PREFIX = ONLINE_PREFIX + DeviceDomainEnum.SUB_DEVICE + ":"; public static final String HMS_PREFIX = "hms" + DELIMITER;
public static final String WEBSOCKET_PREFIX = "webSocket:"; public static final String FIRMWARE_UPGRADING_PREFIX = "upgrading" + DELIMITER;
public static final String WEBSOCKET_ALL = "webSocket:all"; public static final String STATE_PAYLOAD_PREFIX = "payload" + DELIMITER;
public static final String HMS_PREFIX = "hms:"; public static final String LOGS_FILE_PREFIX = "logs_file" + DELIMITER;
} }

26
src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java

@ -29,7 +29,31 @@ public enum BizCodeEnum {
FLIGHT_TASK_PROGRESS("flighttask_progress"), FLIGHT_TASK_PROGRESS("flighttask_progress"),
DEVICE_HMS("device_hms"); DEVICE_HMS("device_hms"),
DEVICE_REBOOT("device_reboot"),
DRONE_OPEN("drone_open"),
DRONE_CLOSE("drone_close"),
DEVICE_CHECK("device_check"),
DRONE_FORMAT("drone_format"),
DEVICE_FORMAT("device_format"),
COVER_OPEN("cover_open"),
COVER_CLOSE("cover_close"),
PUTTER_OPEN("putter_open"),
PUTTER_CLOSE("putter_close"),
CHARGE_OPEN("charge_open"),
CHARGE_CLOSE("charge_close");
private String code; private String code;

2
src/main/java/com/dji/sample/component/websocket/service/impl/WebSocketManageServiceImpl.java

@ -55,7 +55,7 @@ public class WebSocketManageServiceImpl implements IWebSocketManageService {
return; return;
} }
redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + name[0], new String[] {sessionId}); redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + name[0], new String[] {sessionId});
redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])), new String[] {sessionId}); redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])).getDesc(), new String[] {sessionId});
SESSIONS.remove(sessionId); SESSIONS.remove(sessionId);
} }

4
src/main/java/com/dji/sample/configuration/SpringBeanConfiguration.java

@ -7,7 +7,6 @@ import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@ -20,7 +19,7 @@ import java.time.format.DateTimeFormatter;
public class SpringBeanConfiguration { public class SpringBeanConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(ObjectMapper.class) // @ConditionalOnMissingBean(ObjectMapper.class)
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build(); ObjectMapper objectMapper = builder.createXmlMapper(false).build();
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
@ -38,6 +37,7 @@ public class SpringBeanConfiguration {
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() { objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
@Override @Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {

33
src/main/java/com/dji/sample/configuration/mvc/GetSnakeArgumentProcessor.java

@ -0,0 +1,33 @@
package com.dji.sample.configuration.mvc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;
/**
* @author sean
* @version 1.2
* @date 2022/9/16
*/
public class GetSnakeArgumentProcessor extends ServletModelAttributeMethodProcessor {
@Autowired
private GetSnakeDataBinder snakeDataBinder;
/**
* Class constructor.
*
* @param annotationNotRequired if "true", non-simple method arguments and
* return values are considered model attributes with or without a
* {@code @ModelAttribute} annotation
*/
public GetSnakeArgumentProcessor(boolean annotationNotRequired) {
super(annotationNotRequired);
}
@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
super.bindRequestParameters(new GetSnakeDataBinder(binder.getTarget(), binder.getObjectName()), request);
}
}

53
src/main/java/com/dji/sample/configuration/mvc/GetSnakeDataBinder.java

@ -0,0 +1,53 @@
package com.dji.sample.configuration.mvc;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder;
import javax.servlet.ServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
public class GetSnakeDataBinder extends ExtendedServletRequestDataBinder {
public GetSnakeDataBinder(Object target, String objectName) {
super(target, objectName);
}
@Override
protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
List<PropertyValue> propertyValueList = mpvs.getPropertyValueList();
List<PropertyValue> values = new ArrayList<>(propertyValueList);
for (PropertyValue property : values) {
String name = convertSnake(property.getName());
if (!property.getName().equals(name)) {
mpvs.addPropertyValue(new PropertyValue(name, property.getValue()));
propertyValueList.remove(property);
}
}
super.addBindValues(mpvs, request);
}
private String convertSnake(String key) {
StringBuilder sb = new StringBuilder();
boolean isChange = false;
for (char c : key.toCharArray()) {
if (c == '_') {
isChange = true;
continue;
}
if (isChange) {
sb.append((char) (c - 32));
isChange = false;
continue;
}
sb.append(c);
}
return sb.toString();
}
}

9
src/main/java/com/dji/sample/configuration/GlobalMVCConfigurer.java → src/main/java/com/dji/sample/configuration/mvc/GlobalMVCConfigurer.java

@ -1,9 +1,10 @@
package com.dji.sample.configuration; package com.dji.sample.configuration.mvc;
import com.dji.sample.component.AuthInterceptor; import com.dji.sample.component.AuthInterceptor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -24,6 +25,7 @@ public class GlobalMVCConfigurer implements WebMvcConfigurer {
@Value("${url.manage.version}") @Value("${url.manage.version}")
private String manageVersion; private String manageVersion;
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// Exclude the login interface. // Exclude the login interface.
@ -32,4 +34,9 @@ public class GlobalMVCConfigurer implements WebMvcConfigurer {
// Intercept for all request interfaces. // Intercept for all request interfaces.
registry.addInterceptor(authInterceptor).addPathPatterns("/**").excludePathPatterns(excludePaths); registry.addInterceptor(authInterceptor).addPathPatterns("/**").excludePathPatterns(excludePaths);
} }
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new GetSnakeArgumentProcessor(true));
}
} }

30
src/main/java/com/dji/sample/control/controller/DockController.java

@ -0,0 +1,30 @@
package com.dji.sample.control.controller;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.control.service.IControlService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author sean
* @version 1.2
* @date 2022/7/29
*/
@RestController
@Slf4j
@RequestMapping("${url.control.prefix}${url.control.version}/devices")
public class DockController {
@Autowired
private IControlService controlService;
@PostMapping("/{sn}/jobs/{service_identifier}")
public ResponseResult createControlJob(@PathVariable String sn,
@PathVariable("service_identifier") String serviceIdentifier) {
return controlService.controlDock(sn, serviceIdentifier);
}
}

18
src/main/java/com/dji/sample/control/service/IControlService.java

@ -0,0 +1,18 @@
package com.dji.sample.control.service;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
import org.springframework.messaging.MessageHeaders;
/**
* @author sean
* @version 1.2
* @date 2022/7/29
*/
public interface IControlService {
ResponseResult controlDock(String sn, String serviceIdentifier);
void handleControlProgress(CommonTopicReceiver receiver, MessageHeaders headers);
}

133
src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java

@ -0,0 +1,133 @@
package com.dji.sample.control.service.impl;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.*;
import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.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.ISendMessageService;
import com.dji.sample.component.websocket.service.IWebSocketManageService;
import com.dji.sample.control.service.IControlService;
import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.enums.UserTypeEnum;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import java.util.Optional;
import java.util.UUID;
/**
* @author sean
* @version 1.2
* @date 2022/7/29
*/
@Service
@Slf4j
public class ControlServiceImpl implements IControlService {
@Autowired
private RedisOpsUtils redisOps;
@Autowired
private IMessageSenderService messageSenderService;
@Autowired
private ISendMessageService webSocketMessageService;
@Autowired
private IWebSocketManageService webSocketManageService;
@Autowired
private ObjectMapper mapper;
@Override
public ResponseResult controlDock(String sn, String serviceIdentifier) {
ServicesMethodEnum servicesMethodEnum = ServicesMethodEnum.find(serviceIdentifier);
if (servicesMethodEnum == ServicesMethodEnum.UNKNOWN) {
return ResponseResult.error("The " + serviceIdentifier + " method does not exist.");
}
boolean isExist = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + sn) > 0;
if (!isExist) {
return ResponseResult.error("The dock is offline.");
}
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + sn + TopicConst.SERVICES_SUF;
String bid = UUID.randomUUID().toString();
Optional<ServiceReply> serviceReplyOpt = messageSenderService.publishWithReply(
topic, CommonTopicResponse.builder()
.tid(UUID.randomUUID().toString())
.bid(bid)
.method(serviceIdentifier)
.timestamp(System.currentTimeMillis())
.data("")
.build());
if (serviceReplyOpt.isEmpty()) {
return ResponseResult.error("No message reply received.");
}
ServiceReply<EventsOutputReceiver> serviceReply = mapper.convertValue(
serviceReplyOpt.get(), new TypeReference<ServiceReply<EventsOutputReceiver>>() {});
if (serviceReply.getResult() != ResponseResult.CODE_SUCCESS) {
return ResponseResult.error(serviceReply.getResult(), serviceReply.getOutput().getStatus());
}
if (servicesMethodEnum.getProgress()) {
redisOps.setWithExpire(serviceIdentifier + RedisConst.DELIMITER + bid, sn,
RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND);
}
return ResponseResult.success();
}
@Override
@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) {
return;
}
String sn = redisOps.get(key).toString();
EventsReceiver<EventsOutputReceiver> eventsReceiver = mapper.convertValue(receiver.getData(),
new TypeReference<EventsReceiver<EventsOutputReceiver>>(){});
eventsReceiver.setBid(receiver.getBid());
eventsReceiver.setSn(sn);
log.info("SN: {}, {} ===> Control progress: {}",
sn, receiver.getMethod(), eventsReceiver.getOutput().getProgress().toString());
if (eventsReceiver.getResult() != ResponseResult.CODE_SUCCESS) {
log.error("SN: {}, {} ===> Error code: {}", sn, receiver.getMethod(), eventsReceiver.getResult());
}
if (eventsReceiver.getOutput().getProgress().getPercent() == 100 ||
EventsResultStatusEnum.find(eventsReceiver.getOutput().getStatus()).getEnd()) {
redisOps.del(key);
}
DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + sn);
webSocketMessageService.sendBatch(
webSocketManageService.getValueWithWorkspaceAndUserType(
device.getWorkspaceId(), UserTypeEnum.WEB.getVal()),
CustomWebSocketMessage.builder()
.data(eventsReceiver)
.timestamp(System.currentTimeMillis())
.bizCode(receiver.getMethod())
.build());
if (receiver.getNeedReply() != null && receiver.getNeedReply() == 1) {
String topic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF;
messageSenderService.publish(topic,
CommonTopicResponse.builder()
.tid(receiver.getTid())
.bid(receiver.getBid())
.method(receiver.getMethod())
.timestamp(System.currentTimeMillis())
.data(ResponseResult.success())
.build());
}
}
}

45
src/main/java/com/dji/sample/manage/controller/DeviceController.java

@ -7,6 +7,7 @@ import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
import com.dji.sample.component.mqtt.model.CommonTopicResponse; import com.dji.sample.component.mqtt.model.CommonTopicResponse;
import com.dji.sample.component.websocket.service.ISendMessageService; import com.dji.sample.component.websocket.service.ISendMessageService;
import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO;
import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver;
import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; import com.dji.sample.manage.model.receiver.StatusGatewayReceiver;
import com.dji.sample.manage.service.IDeviceService; import com.dji.sample.manage.service.IDeviceService;
@ -84,6 +85,10 @@ public class DeviceController {
return ResponseResult.success(devicesList); return ResponseResult.success(devicesList);
} }
/**
* Handle osd topic messages.
* @param message
*/
@ServiceActivator(inputChannel = ChannelName.INBOUND_OSD) @ServiceActivator(inputChannel = ChannelName.INBOUND_OSD)
public void osdRealTime(Message<?> message) { public void osdRealTime(Message<?> message) {
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
@ -91,11 +96,21 @@ public class DeviceController {
deviceService.handleOSD(topic, payload); deviceService.handleOSD(topic, payload);
} }
/**
* Receive the reported firmware version data.
* @param receiver
*/
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_FIRMWARE_VERSION) @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_FIRMWARE_VERSION)
public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { public void updateFirmwareVersion(FirmwareVersionReceiver receiver) {
deviceService.updateFirmwareVersion(receiver); deviceService.updateFirmwareVersion(receiver);
} }
/**
* After binding the device to the workspace, the device data can only be seen on the web.
* @param device
* @param deviceSn
* @return
*/
@PostMapping("/{device_sn}/binding") @PostMapping("/{device_sn}/binding")
public ResponseResult bindDevice(@RequestBody DeviceDTO device, @PathVariable("device_sn") String deviceSn) { public ResponseResult bindDevice(@RequestBody DeviceDTO device, @PathVariable("device_sn") String deviceSn) {
device.setDeviceSn(deviceSn); device.setDeviceSn(deviceSn);
@ -103,6 +118,12 @@ public class DeviceController {
return isUpd ? ResponseResult.success() : ResponseResult.error(); return isUpd ? ResponseResult.success() : ResponseResult.error();
} }
/**
* Obtain device information according to device sn.
* @param workspaceId
* @param deviceSn
* @return
*/
@GetMapping("/{workspace_id}/devices/{device_sn}") @GetMapping("/{workspace_id}/devices/{device_sn}")
public ResponseResult getDevice(@PathVariable("workspace_id") String workspaceId, public ResponseResult getDevice(@PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String deviceSn) { @PathVariable("device_sn") String deviceSn) {
@ -127,12 +148,24 @@ public class DeviceController {
return ResponseResult.success(devices); return ResponseResult.success(devices);
} }
/**
* Removing the binding state of the device.
* @param deviceSn
* @return
*/
@DeleteMapping("/{device_sn}/unbinding") @DeleteMapping("/{device_sn}/unbinding")
public ResponseResult unbindingDevice(@PathVariable("device_sn") String deviceSn) { public ResponseResult unbindingDevice(@PathVariable("device_sn") String deviceSn) {
deviceService.unbindDevice(deviceSn); deviceService.unbindDevice(deviceSn);
return ResponseResult.success(); return ResponseResult.success();
} }
/**
* Update device information.
* @param device
* @param workspaceId
* @param deviceSn
* @return
*/
@PutMapping("/{workspace_id}/devices/{device_sn}") @PutMapping("/{workspace_id}/devices/{device_sn}")
public ResponseResult updateDevice(@RequestBody DeviceDTO device, public ResponseResult updateDevice(@RequestBody DeviceDTO device,
@PathVariable("workspace_id") String workspaceId, @PathVariable("workspace_id") String workspaceId,
@ -141,4 +174,16 @@ public class DeviceController {
boolean isUpd = deviceService.updateDevice(device); boolean isUpd = deviceService.updateDevice(device);
return isUpd ? ResponseResult.success() : ResponseResult.error(); return isUpd ? ResponseResult.success() : ResponseResult.error();
} }
/**
* Delivers offline firmware upgrade tasks.
* @param workspaceId
* @param upgradeDTOS
* @return
*/
@PostMapping("/{workspace_id}/devices/ota")
public ResponseResult createOtaJob(@PathVariable("workspace_id") String workspaceId,
@RequestBody List<DeviceFirmwareUpgradeDTO> upgradeDTOS) {
return deviceService.createDeviceOtaJob(workspaceId, upgradeDTOS);
}
} }

43
src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java

@ -0,0 +1,43 @@
package com.dji.sample.manage.controller;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.manage.model.dto.DeviceFirmwareNoteDTO;
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 java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@RestController
@RequestMapping("${url.manage.prefix}${url.manage.version}/workspaces")
public class DeviceFirmwareController {
@Autowired
private IDeviceFirmwareService service;
/**
* Get the latest firmware version information for this device model.
* @param deviceNames
* @return
*/
@GetMapping("/firmware-release-notes/latest")
public ResponseResult<List<DeviceFirmwareNoteDTO>> getLatestFirmwareNote(@RequestParam("device_name") List<String> deviceNames) {
List<DeviceFirmwareNoteDTO> releaseNotes = new ArrayList<>();
deviceNames.forEach(deviceName -> {
Optional<DeviceFirmwareNoteDTO> latestFirmware = service.getLatestFirmwareReleaseNote(deviceName);
latestFirmware.ifPresent(releaseNotes::add);
});
return ResponseResult.success(releaseNotes);
}
}

18
src/main/java/com/dji/sample/manage/controller/DeviceHmsController.java

@ -27,20 +27,36 @@ public class DeviceHmsController {
@Autowired @Autowired
private IDeviceHmsService deviceHmsService; private IDeviceHmsService deviceHmsService;
/**
* Page to query the hms information of the device.
* @param param
* @param workspaceId
* @return
*/
@GetMapping("/{workspace_id}/devices/hms") @GetMapping("/{workspace_id}/devices/hms")
public ResponseResult<PaginationData<DeviceHmsDTO>> getBoundDevicesWithDomain(DeviceHmsQueryParam param, public ResponseResult<PaginationData<DeviceHmsDTO>> getHmsInformation(DeviceHmsQueryParam param,
@PathVariable("workspace_id") String workspaceId) { @PathVariable("workspace_id") String workspaceId) {
PaginationData<DeviceHmsDTO> devices = deviceHmsService.getDeviceHmsByParam(param); PaginationData<DeviceHmsDTO> devices = deviceHmsService.getDeviceHmsByParam(param);
return ResponseResult.success(devices); return ResponseResult.success(devices);
} }
/**
* Update unread hms messages to read status.
* @param deviceSn
* @return
*/
@PutMapping("/{workspace_id}/devices/hms/{device_sn}") @PutMapping("/{workspace_id}/devices/hms/{device_sn}")
public ResponseResult updateReadHmsByDeviceSn(@PathVariable("device_sn") String deviceSn) { public ResponseResult updateReadHmsByDeviceSn(@PathVariable("device_sn") String deviceSn) {
deviceHmsService.updateUnreadHms(deviceSn); deviceHmsService.updateUnreadHms(deviceSn);
return ResponseResult.success(); return ResponseResult.success();
} }
/**
* Get hms messages for a single device.
* @param deviceSn
* @return
*/
@GetMapping("/{workspace_id}/devices/hms/{device_sn}") @GetMapping("/{workspace_id}/devices/hms/{device_sn}")
public ResponseResult<List<DeviceHmsDTO>> getUnreadHmsByDeviceSn(@PathVariable("device_sn") String deviceSn) { public ResponseResult<List<DeviceHmsDTO>> getUnreadHmsByDeviceSn(@PathVariable("device_sn") String deviceSn) {
PaginationData<DeviceHmsDTO> paginationData = deviceHmsService.getDeviceHmsByParam( PaginationData<DeviceHmsDTO> paginationData = deviceHmsService.getDeviceHmsByParam(

122
src/main/java/com/dji/sample/manage/controller/DeviceLogsController.java

@ -0,0 +1,122 @@
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.DeviceLogsDTO;
import com.dji.sample.manage.model.param.DeviceLogsCreateParam;
import com.dji.sample.manage.model.param.DeviceLogsQueryParam;
import com.dji.sample.manage.model.param.LogsFileUpdateParam;
import com.dji.sample.manage.service.IDeviceLogsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URL;
import java.util.List;
import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@RestController
@Slf4j
@RequestMapping("${url.manage.prefix}${url.manage.version}/workspaces")
public class DeviceLogsController {
@Autowired
private IDeviceLogsService deviceLogsService;
/**
* Obtain the device upload log list by paging according to the query parameters.
* @param workspaceId
* @param deviceSn
* @param param
* @return
*/
@GetMapping("/{workspace_id}/devices/{device_sn}/logs-uploaded")
public ResponseResult getUploadedLogs(DeviceLogsQueryParam param, @PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String deviceSn) {
PaginationData<DeviceLogsDTO> data = deviceLogsService.getUploadedLogs(deviceSn, param);
return ResponseResult.success(data);
}
/**
* Get a list of log files that can be uploaded in real time.
* @param workspaceId
* @param deviceSn
* @param domainList
* @return
*/
@GetMapping("/{workspace_id}/devices/{device_sn}/logs")
public ResponseResult getLogsBySn(@PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String deviceSn,
@RequestParam("domain_list") List<String> domainList) {
return deviceLogsService.getRealTimeLogs(deviceSn, domainList);
}
/**
* Initiate a log upload request to the gateway.
* @return
*/
@PostMapping("/{workspace_id}/devices/{device_sn}/logs")
public ResponseResult uploadLogs(@PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String deviceSn,
HttpServletRequest request, @RequestBody DeviceLogsCreateParam param) {
CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM);
return deviceLogsService.pushFileUpload(customClaim.getUsername(), deviceSn, param);
}
/**
* Cancel logs file upload.
* @return
*/
@DeleteMapping("/{workspace_id}/devices/{device_sn}/logs")
public ResponseResult cancelUploadedLogs(@PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String deviceSn,
@RequestBody LogsFileUpdateParam param) {
return deviceLogsService.pushUpdateFile(deviceSn, param);
}
/**
* Delete upload history.
* @return
*/
@DeleteMapping("/{workspace_id}/devices/{device_sn}/logs/{logs_id}")
public ResponseResult deleteUploadedLogs(@PathVariable("workspace_id") String workspaceId,
@PathVariable("device_sn") String deviceSn,
@PathVariable("logs_id") String logsId) {
deviceLogsService.deleteLogs(deviceSn, logsId);
return ResponseResult.success();
}
/**
* Query the download address of the file according to the wayline file id,
* and redirect to this address directly for download.
* @param workspaceId
* @param fileId
* @param logsId
* @param response
*/
@GetMapping("/{workspace_id}/logs/{logs_id}/url/{file_id}")
public ResponseResult getFileUrl(@PathVariable(name = "workspace_id") String workspaceId,
@PathVariable(name = "file_id") String fileId,
@PathVariable(name = "logs_id") String logsId, HttpServletResponse response) {
try {
URL url = deviceLogsService.getLogsFileUrl(logsId, fileId);
return ResponseResult.success(url.toString());
} catch (Exception e) {
log.error("Failed to get the logs file download address.");
e.printStackTrace();
}
return ResponseResult.error("Failed to get the logs file download address.");
}
}

17
src/main/java/com/dji/sample/manage/controller/DevicePayloadController.java

@ -3,20 +3,17 @@ package com.dji.sample.manage.controller;
import com.dji.sample.component.mqtt.model.ChannelName; import com.dji.sample.component.mqtt.model.ChannelName;
import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; import com.dji.sample.manage.model.receiver.DeviceBasicReceiver;
import com.dji.sample.manage.service.IDevicePayloadService; import com.dji.sample.manage.service.IDevicePayloadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.MessageHeaders;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* @author sean.zhou * @author sean.zhou
* @date 2021/11/19 * @date 2021/11/19
* @version 0.1 * @version 0.1
*/ */
@RestController @RestController
@Slf4j
public class DevicePayloadController { public class DevicePayloadController {
@Autowired @Autowired
@ -28,17 +25,11 @@ public class DevicePayloadController {
* Note: Only the data of the drone payload is handled here. You can handle other data from the drone * Note: Only the data of the drone payload is handled here. You can handle other data from the drone
* according to your business needs. * according to your business needs.
* @param deviceBasic basic drone data * @param deviceBasic basic drone data
* @return drone's sn * @param headers
*/ */
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_BASIC) @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_BASIC)
public void stateBasic(DeviceBasicReceiver deviceBasic) { public void stateBasic(DeviceBasicReceiver deviceBasic, MessageHeaders headers) {
// Delete all payload information for the drone based on the drone's sn.
devicePayloadService.deletePayloadsByDeviceSn(List.of(deviceBasic.getDeviceSn()));
// Save the new payload information.
boolean isSave = devicePayloadService.savePayloadDTOs(deviceBasic.getPayloads());
log.debug("The result of saving the payloads is {}.", isSave);
devicePayloadService.saveDeviceBasicPayload(deviceBasic.getPayloads(), headers.getTimestamp());
} }
} }

26
src/main/java/com/dji/sample/manage/controller/LiveStreamController.java

@ -2,24 +2,19 @@ package com.dji.sample.manage.controller;
import com.dji.sample.common.model.CustomClaim; import com.dji.sample.common.model.CustomClaim;
import com.dji.sample.common.model.ResponseResult; import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.Chan;
import com.dji.sample.component.mqtt.model.ChannelName; import com.dji.sample.component.mqtt.model.ChannelName;
import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
import com.dji.sample.component.mqtt.model.ServiceReply;
import com.dji.sample.manage.model.dto.CapacityDeviceDTO; import com.dji.sample.manage.model.dto.CapacityDeviceDTO;
import com.dji.sample.manage.model.dto.LiveTypeDTO; import com.dji.sample.manage.model.dto.LiveTypeDTO;
import com.dji.sample.manage.model.receiver.LiveCapacityReceiver; import com.dji.sample.manage.model.receiver.LiveCapacityReceiver;
import com.dji.sample.manage.service.ILiveStreamService; import com.dji.sample.manage.service.ILiveStreamService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List; import java.util.List;
import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM;
@ -47,8 +42,8 @@ public class LiveStreamController {
* @param liveCapacity the capacity of drone and dock * @param liveCapacity the capacity of drone and dock
*/ */
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_CAPACITY) @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_CAPACITY)
public void stateCapacity(LiveCapacityReceiver liveCapacity) { public void stateCapacity(LiveCapacityReceiver liveCapacity, MessageHeaders headers) {
liveStreamService.saveLiveCapacity(liveCapacity); liveStreamService.saveLiveCapacity(liveCapacity, headers.getTimestamp());
} }
/** /**
@ -96,19 +91,4 @@ public class LiveStreamController {
return liveStreamService.liveSetQuality(liveParam); return liveStreamService.liveSetQuality(liveParam);
} }
/**
* Handle the reply message from the pilot side to the on-demand video.
* @param message reply message
* @throws IOException
*/
@ServiceActivator(inputChannel = ChannelName.INBOUND_SERVICE_REPLY)
public void serviceReply(Message<?> message) throws IOException {
byte[] payload = (byte[])message.getPayload();
CommonTopicReceiver<ServiceReply> receiver = mapper.readValue(payload,
new TypeReference<CommonTopicReceiver<ServiceReply>>() {
});
Chan<CommonTopicReceiver> chan = Chan.getInstance();
// Put the message to the chan object.
chan.put(receiver);
}
} }

12
src/main/java/com/dji/sample/manage/dao/IDeviceFirmwareMapper.java

@ -0,0 +1,12 @@
package com.dji.sample.manage.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dji.sample.manage.model.entity.DeviceFirmwareEntity;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
public interface IDeviceFirmwareMapper extends BaseMapper<DeviceFirmwareEntity> {
}

12
src/main/java/com/dji/sample/manage/dao/IDeviceLogsMapper.java

@ -0,0 +1,12 @@
package com.dji.sample.manage.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dji.sample.manage.model.entity.DeviceLogsEntity;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
public interface IDeviceLogsMapper extends BaseMapper<DeviceLogsEntity> {
}

12
src/main/java/com/dji/sample/manage/dao/ILogsFileIndexMapper.java

@ -0,0 +1,12 @@
package com.dji.sample.manage.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dji.sample.manage.model.entity.LogsFileIndexEntity;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
public interface ILogsFileIndexMapper extends BaseMapper<LogsFileIndexEntity> {
}

12
src/main/java/com/dji/sample/manage/dao/ILogsFileMapper.java

@ -0,0 +1,12 @@
package com.dji.sample.manage.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.dji.sample.manage.model.entity.LogsFileEntity;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
public interface ILogsFileMapper extends BaseMapper<LogsFileEntity> {
}

3
src/main/java/com/dji/sample/manage/model/common/HmsJsonUtil.java

@ -44,6 +44,9 @@ public class HmsJsonUtil {
} }
public static HmsMessage get(String key) { public static HmsMessage get(String key) {
if (nodes.get(key) == null) {
return new HmsMessage();
}
return mapper.convertValue(nodes.get(key), HmsMessage.class); return mapper.convertValue(nodes.get(key), HmsMessage.class);
} }
} }

4
src/main/java/com/dji/sample/manage/model/dto/DeviceDTO.java

@ -60,4 +60,8 @@ public class DeviceDTO {
private String workspaceName; private String workspaceName;
private DeviceDTO children; private DeviceDTO children;
private Integer firmwareStatus;
private Integer firmwareProgress;
} }

40
src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java

@ -0,0 +1,40 @@
package com.dji.sample.manage.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeviceFirmwareDTO {
private String firmwareId;
private String fileName;
private String productVersion;
private String fileUrl;
private Long fileSize;
private String fileMd5;
private String deviceName;
private String releaseNote;
private LocalDate releasedTime;
private Boolean firmwareStatus;
}

28
src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareNoteDTO.java

@ -0,0 +1,28 @@
package com.dji.sample.manage.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeviceFirmwareNoteDTO {
private String deviceName;
private String productVersion;
private String releaseNote;
private LocalDate releasedTime;
}

20
src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareUpgradeDTO.java

@ -0,0 +1,20 @@
package com.dji.sample.manage.model.dto;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@Data
public class DeviceFirmwareUpgradeDTO {
private String deviceName;
private String sn;
private String productVersion;
private Integer firmwareUpgradeType;
}

41
src/main/java/com/dji/sample/manage/model/dto/DeviceLogsDTO.java

@ -0,0 +1,41 @@
package com.dji.sample.manage.model.dto;
import com.dji.sample.manage.model.receiver.LogsFileUploadList;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DeviceLogsDTO {
private String logsId;
private LocalDateTime happenTime;
private String userName;
private String logsInformation;
private LocalDateTime createTime;
private Integer status;
private TopologyDTO deviceTopo;
private List<LogsProgressDTO> logsProgress;
private LogsFileUploadList deviceLogs;
}

35
src/main/java/com/dji/sample/manage/model/dto/LogsFileDTO.java

@ -0,0 +1,35 @@
package com.dji.sample.manage.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LogsFileDTO {
private String fileId;
private String name;
private Long size;
private String logsId;
private String deviceSn;
private String fingerprint;
private String objectKey;
private Boolean status;
}

26
src/main/java/com/dji/sample/manage/model/dto/LogsOutputProgressDTO.java

@ -0,0 +1,26 @@
package com.dji.sample.manage.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class LogsOutputProgressDTO {
private String logsId;
private String status;
private List<LogsProgressDTO> files;
}

31
src/main/java/com/dji/sample/manage/model/dto/LogsProgressDTO.java

@ -0,0 +1,31 @@
package com.dji.sample.manage.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogsProgressDTO {
private String deviceSn;
private String deviceModelDomain;
private Integer progress;
private Integer result;
private Float uploadRate;
private String status;
}

47
src/main/java/com/dji/sample/manage/model/dto/LogsUploadCredentialsDTO.java

@ -0,0 +1,47 @@
package com.dji.sample.manage.model.dto;
import com.dji.sample.manage.model.receiver.LogsFileUploadList;
import com.dji.sample.media.model.CredentialsDTO;
import com.dji.sample.media.model.StsCredentialsDTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogsUploadCredentialsDTO {
private String bucket;
private CredentialsDTO credentials;
private String endpoint;
@JsonProperty("file_store_dir")
private String objectKeyPrefix;
private String provider;
private String fileType = "text_log";
private LogsFileUploadList params;
public LogsUploadCredentialsDTO(StsCredentialsDTO sts) {
this.bucket = sts.getBucket();
Long expire = sts.getCredentials().getExpire();
sts.getCredentials().setExpire(System.currentTimeMillis() + (expire - 60) * 1000);
this.credentials = sts.getCredentials();
this.endpoint = sts.getEndpoint();
this.objectKeyPrefix = sts.getObjectKeyPrefix();
this.provider = sts.getProvider();
}
}

3
src/main/java/com/dji/sample/manage/model/entity/DeviceEntity.java

@ -76,6 +76,9 @@ public class DeviceEntity implements Serializable {
@TableField(value = "firmware_version") @TableField(value = "firmware_version")
private String firmwareVersion; private String firmwareVersion;
@TableField(value = "compatible_status")
private Boolean compatibleStatus;
@TableField(value = "bound_status") @TableField(value = "bound_status")
private Boolean boundStatus; private Boolean boundStatus;

64
src/main/java/com/dji/sample/manage/model/entity/DeviceFirmwareEntity.java

@ -0,0 +1,64 @@
package com.dji.sample.manage.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("manage_device_firmware")
public class DeviceFirmwareEntity implements Serializable {
private static final long serialVersionUID = -12L;
@TableId(type = IdType.AUTO)
private Long id;
@TableField("firmware_id")
private String firmwareId;
@TableField("file_name")
private String fileName;
@TableField("firmware_version")
private String firmwareVersion;
@TableField("file_url")
private String fileUrl;
@TableField("file_size")
private Long fileSize;
@TableField("file_md5")
private String fileMd5;
@TableField("device_name")
private String deviceName;
@TableField("release_note")
private String releaseNote;
@TableField("release_date")
private Long releaseDate;
@TableField("status")
private Boolean status;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Long createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Long updateTime;
}

2
src/main/java/com/dji/sample/manage/model/entity/DeviceHmsEntity.java

@ -23,6 +23,8 @@ import java.io.Serializable;
@TableName(value = "manage_device_hms") @TableName(value = "manage_device_hms")
public class DeviceHmsEntity implements Serializable, Cloneable { public class DeviceHmsEntity implements Serializable, Cloneable {
private static final long serialVersionUID = -12L;
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Long id; private Long id;

52
src/main/java/com/dji/sample/manage/model/entity/DeviceLogsEntity.java

@ -0,0 +1,52 @@
package com.dji.sample.manage.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@TableName("manage_device_logs")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DeviceLogsEntity implements Serializable {
private static final long serialVersionUID = -12L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("logs_id")
private String logsId;
@TableField("username")
private String username;
@TableField("logs_info")
private String logsInfo;
@TableField("device_sn")
private String deviceSn;
@TableField("happen_time")
private Long happenTime;
@TableField("status")
private Integer status;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Long createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Long updateTime;
}

58
src/main/java/com/dji/sample/manage/model/entity/LogsFileEntity.java

@ -0,0 +1,58 @@
package com.dji.sample.manage.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@TableName("logs_file")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogsFileEntity implements Serializable {
private static final long serialVersionUID = -12L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("file_id")
private String fileId;
@TableField("name")
private String name;
@TableField("size")
private Long size;
@TableField("logs_id")
private String logsId;
@TableField("device_sn")
private String deviceSn;
@TableField("fingerprint")
private String fingerprint;
@TableField("object_key")
private String objectKey;
@TableField("status")
private Boolean status;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Long createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Long updateTime;
}

54
src/main/java/com/dji/sample/manage/model/entity/LogsFileIndexEntity.java

@ -0,0 +1,54 @@
package com.dji.sample.manage.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName("logs_file_index")
public class LogsFileIndexEntity implements Serializable {
private static final long serialVersionUID = -12L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField("boot_index")
private Integer bootIndex;
@TableField("file_id")
private String fileId;
@TableField("start_time")
private Long startTime;
@TableField("end_time")
private Long endTime;
@TableField("size")
private Long size;
@TableField("device_sn")
private String deviceSn;
@TableField("domain")
private Integer domain;
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Long createTime;
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
private Long updateTime;
}

62
src/main/java/com/dji/sample/manage/model/enums/DeviceFirmwareStatusEnum.java

@ -0,0 +1,62 @@
package com.dji.sample.manage.model.enums;
import lombok.Getter;
import java.util.Arrays;
/**
* @author sean
* @version 1.2
* @date 2022/8/15
*/
@Getter
public enum DeviceFirmwareStatusEnum {
/**
* no need to upgrade
*/
NOT_UPGRADE(1),
/**
* to upgraded
*/
NORMAL_UPGRADE(2),
/**
* A consistency upgrade is required.
*/
CONSISTENT_UPGRADE(3),
/**
* during upgrade
*/
UPGRADING(4),
UNKNOWN(-1);
int val;
DeviceFirmwareStatusEnum(int val) {
this.val = val;
}
public static DeviceFirmwareStatusEnum find(int val) {
return Arrays.stream(DeviceFirmwareStatusEnum.values())
.filter(firmwareStatus -> firmwareStatus.val == val)
.findFirst().orElse(UNKNOWN);
}
@Getter
public enum CompatibleStatusEnum {
INCONSISTENT(1),
CONSISTENT(0);
int val;
CompatibleStatusEnum(int val) {
this.val = val;
}
}
}

41
src/main/java/com/dji/sample/manage/model/enums/DeviceLogsStatusEnum.java

@ -0,0 +1,41 @@
package com.dji.sample.manage.model.enums;
import com.dji.sample.component.mqtt.model.EventsResultStatusEnum;
import lombok.Getter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
@Getter
public enum DeviceLogsStatusEnum {
UPLOADING(1, EventsResultStatusEnum.IN_PROGRESS),
DONE(2, EventsResultStatusEnum.OK),
CANCELED(3, EventsResultStatusEnum.CANCELED),
FAILED(4, EventsResultStatusEnum.FAILED, EventsResultStatusEnum.REJECTED, EventsResultStatusEnum.TIMEOUT),
UNKNOWN(-1);
int val;
HashSet<EventsResultStatusEnum> status;
DeviceLogsStatusEnum(int val, EventsResultStatusEnum... status) {
this.status = new HashSet<>();
Collections.addAll(this.status, status);
this.val = val;
}
public static DeviceLogsStatusEnum find(EventsResultStatusEnum status) {
return Arrays.stream(DeviceLogsStatusEnum.values()).filter(element -> element.status.contains(status)).findAny().orElse(UNKNOWN);
}
}

36
src/main/java/com/dji/sample/manage/model/enums/HmsEnum.java

@ -54,6 +54,8 @@ public enum HmsEnum {
@Getter @Getter
public enum HmsFaqIdEnum { public enum HmsFaqIdEnum {
DOCK_TIP("dock_tip_"),
FPV_TIP("fpv_tip_"); FPV_TIP("fpv_tip_");
private String text; private String text;
@ -152,4 +154,38 @@ public enum HmsEnum {
.orElse(UNKNOWN); .orElse(UNKNOWN);
} }
} }
@Getter
public enum FormatKeyEnum {
ALARM_ID("alarmid", 0),
COMPONENT_INDEX("component_index", 1),
INDEX("index", 2),
BATTERY_INDEX("battery_index", 3),
DOCK_COVER_INDEX("dock_cover_index", 4),
CHARGING_ROD_INDEX("charging_rod_index", 5),
UNKNOWN("unknown", -1);
public static final char KEY_START = '%';
String key;
int index;
FormatKeyEnum(String key, int index) {
this.key = key;
this.index = index;
}
public static FormatKeyEnum find(String key) {
return Arrays.stream(FormatKeyEnum.values())
.filter(format -> format.getKey().equals(key))
.findAny().orElse(UNKNOWN);
}
}
} }

28
src/main/java/com/dji/sample/manage/model/enums/LogsFileUpdateMethodEnum.java

@ -0,0 +1,28 @@
package com.dji.sample.manage.model.enums;
import lombok.Getter;
import java.util.Arrays;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Getter
public enum LogsFileUpdateMethodEnum {
CANCEL("cancel"),
UNKNOWN("unknown");
String method;
LogsFileUpdateMethodEnum(String method) {
this.method = method;
}
public static LogsFileUpdateMethodEnum find(String method) {
return Arrays.stream(LogsFileUpdateMethodEnum.values()).filter(e -> e.method.equals(method)).findAny().orElse(UNKNOWN);
}
}

9
src/main/java/com/dji/sample/manage/model/param/DeviceHmsQueryParam.java

@ -1,12 +1,10 @@
package com.dji.sample.manage.model.param; package com.dji.sample.manage.model.param;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Set; import java.util.Set;
/** /**
@ -18,15 +16,12 @@ import java.util.Set;
@Builder @Builder
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class DeviceHmsQueryParam implements Serializable { public class DeviceHmsQueryParam {
@JsonProperty("device_sn")
private Set<String> deviceSn; private Set<String> deviceSn;
@JsonProperty("begin_time")
private Long beginTime; private Long beginTime;
@JsonProperty("end_time")
private Long endTime; private Long endTime;
private String language; private String language;
@ -35,11 +30,9 @@ public class DeviceHmsQueryParam implements Serializable {
private Long page; private Long page;
@JsonProperty("page_size")
private Long pageSize; private Long pageSize;
private Integer level; private Integer level;
@JsonProperty("update_time")
private Long updateTime; private Long updateTime;
} }

21
src/main/java/com/dji/sample/manage/model/param/DeviceLogsCreateParam.java

@ -0,0 +1,21 @@
package com.dji.sample.manage.model.param;
import com.dji.sample.manage.model.receiver.LogsFileUpload;
import lombok.Data;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
@Data
public class DeviceLogsCreateParam {
private String logsInformation;
private Long happenTime;
private List<LogsFileUpload> files;
}

24
src/main/java/com/dji/sample/manage/model/param/DeviceLogsQueryParam.java

@ -0,0 +1,24 @@
package com.dji.sample.manage.model.param;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Data
public class DeviceLogsQueryParam {
private Long page;
private Long pageSize;
private Integer status;
private Long beginTime;
private Long endTime;
private String logsInformation;
}

32
src/main/java/com/dji/sample/manage/model/param/DeviceOtaCreateParam.java

@ -0,0 +1,32 @@
package com.dji.sample.manage.model.param;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DeviceOtaCreateParam {
private String sn;
private String productVersion;
private String fileUrl;
private String md5;
private Long fileSize;
private Integer firmwareUpgradeType;
private String fileName;
}

21
src/main/java/com/dji/sample/manage/model/param/LogsFileUpdateParam.java

@ -0,0 +1,21 @@
package com.dji.sample.manage.model.param;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Data
public class LogsFileUpdateParam {
private String status;
@JsonProperty("module_list")
private List<String> deviceModelDomainList;
}

27
src/main/java/com/dji/sample/manage/model/receiver/LogsExtFileReceiver.java

@ -0,0 +1,27 @@
package com.dji.sample.manage.model.receiver;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Data
public class LogsExtFileReceiver {
@JsonProperty("module")
private String deviceModelDomain;
private Long size;
private String deviceSn;
private String key;
private String fingerprint;
private LogsProgressReceiver progress;
}

26
src/main/java/com/dji/sample/manage/model/receiver/LogsFile.java

@ -0,0 +1,26 @@
package com.dji.sample.manage.model.receiver;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogsFile {
private Integer bootIndex;
private Long endTime;
private Long startTime;
private Long size;
}

34
src/main/java/com/dji/sample/manage/model/receiver/LogsFileUpload.java

@ -0,0 +1,34 @@
package com.dji.sample.manage.model.receiver;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LogsFileUpload {
private String deviceSn;
private List<LogsFile> list;
@JsonProperty("module")
private String deviceModelDomain;
private String objectKey;
private Integer result;
private String fileId;
}

24
src/main/java/com/dji/sample/manage/model/receiver/LogsFileUploadList.java

@ -0,0 +1,24 @@
package com.dji.sample.manage.model.receiver;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class LogsFileUploadList {
private List<LogsFileUpload> files;
private Integer result;
}

26
src/main/java/com/dji/sample/manage/model/receiver/LogsProgressReceiver.java

@ -0,0 +1,26 @@
package com.dji.sample.manage.model.receiver;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Data
public class LogsProgressReceiver {
private Integer currentStep;
private Integer totalStep;
private Integer progress;
private Long finishTime;
private Float uploadRate;
private String status;
private Integer result;
}

16
src/main/java/com/dji/sample/manage/model/receiver/OutputLogsExtReceiver.java

@ -0,0 +1,16 @@
package com.dji.sample.manage.model.receiver;
import lombok.Data;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Data
public class OutputLogsExtReceiver {
private List<LogsExtFileReceiver> files;
}

16
src/main/java/com/dji/sample/manage/model/receiver/OutputLogsProgressReceiver.java

@ -0,0 +1,16 @@
package com.dji.sample.manage.model.receiver;
import lombok.Data;
/**
* @author sean
* @version 1.2
* @date 2022/9/9
*/
@Data
public class OutputLogsProgressReceiver {
private OutputLogsExtReceiver ext;
private String status;
}

3
src/main/java/com/dji/sample/manage/service/ICapacityCameraService.java

@ -30,8 +30,9 @@ public interface ICapacityCameraService {
* Save the live capability data of the device. * Save the live capability data of the device.
* @param capacityCameraReceivers * @param capacityCameraReceivers
* @param deviceSn * @param deviceSn
* @param timestamp
*/ */
void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn); void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn, Long timestamp);
/** /**
* Convert the received camera capability object into camera data transfer object. * Convert the received camera capability object into camera data transfer object.

48
src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java

@ -0,0 +1,48 @@
package com.dji.sample.manage.service;
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.DeviceOtaCreateParam;
import org.springframework.messaging.MessageHeaders;
import java.util.List;
import java.util.Optional;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
public interface IDeviceFirmwareService {
/**
* Query specific firmware information based on the device model and firmware version.
* @param deviceName
* @param version
* @return
*/
Optional<DeviceFirmwareDTO> getFirmware(String deviceName, String version);
/**
* Get the latest firmware release note for this device model.
* @param deviceName
* @return
*/
Optional<DeviceFirmwareNoteDTO> getLatestFirmwareReleaseNote(String deviceName);
/**
* Get the firmware information that the device needs to update.
* @param upgradeDTOS
* @return
*/
List<DeviceOtaCreateParam> getDeviceOtaFirmware(List<DeviceFirmwareUpgradeDTO> upgradeDTOS);
/**
* Interface to handle device firmware update progress.
* @param receiver
* @param headers
*/
void handleOtaProgress(CommonTopicReceiver receiver, MessageHeaders headers);
}

14
src/main/java/com/dji/sample/manage/service/IDeviceHmsService.java

@ -13,9 +13,23 @@ import org.springframework.messaging.MessageHeaders;
*/ */
public interface IDeviceHmsService { public interface IDeviceHmsService {
/**
* Handle hms messages.
* @param receiver
* @param headers
*/
void handleHms(CommonTopicReceiver receiver, MessageHeaders headers); void handleHms(CommonTopicReceiver receiver, MessageHeaders headers);
/**
* Query hms data by paging according to query parameters.
* @param param
* @return
*/
PaginationData<DeviceHmsDTO> getDeviceHmsByParam(DeviceHmsQueryParam param); PaginationData<DeviceHmsDTO> getDeviceHmsByParam(DeviceHmsQueryParam param);
/**
* Read message handling.
* @param deviceSn
*/
void updateUnreadHms(String deviceSn); void updateUnreadHms(String deviceSn);
} }

94
src/main/java/com/dji/sample/manage/service/IDeviceLogsService.java

@ -0,0 +1,94 @@
package com.dji.sample.manage.service;
import com.dji.sample.common.model.PaginationData;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
import com.dji.sample.manage.model.dto.DeviceLogsDTO;
import com.dji.sample.manage.model.param.DeviceLogsCreateParam;
import com.dji.sample.manage.model.param.DeviceLogsQueryParam;
import com.dji.sample.manage.model.param.LogsFileUpdateParam;
import org.springframework.messaging.MessageHeaders;
import java.net.URL;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
public interface IDeviceLogsService {
/**
* Obtain the device upload log list by paging according to the query parameters.
* @param deviceSn
* @param param
* @return
*/
PaginationData<DeviceLogsDTO> getUploadedLogs(String deviceSn, DeviceLogsQueryParam param);
/**
* Get a list of log files that can be uploaded in real time.
* @param deviceSn
* @param domainList
* @return
*/
ResponseResult getRealTimeLogs(String deviceSn, List<String> domainList);
/**
* Add device logs.
*
* @param bid
* @param username
* @param deviceSn
* @param param
* @return logs id
*/
String insertDeviceLogs(String bid, String username, String deviceSn, DeviceLogsCreateParam param);
/**
* Initiate a log upload request to the gateway.
* @param username
* @param deviceSn
* @param param
* @return
*/
ResponseResult pushFileUpload(String username, String deviceSn, DeviceLogsCreateParam param);
/**
* Push a request to modify the status of the logs file.
* @param deviceSn
* @param param
* @return
*/
ResponseResult pushUpdateFile(String deviceSn, LogsFileUpdateParam param);
/**
* Delete log records.
* @param deviceSn
* @param logsId
*/
void deleteLogs(String deviceSn, String logsId);
/**
* Handle logs file upload progress.
* @param receiver
* @param headers
*/
void handleFileUploadProgress(CommonTopicReceiver receiver, MessageHeaders headers);
/**
* Update status, which is updated when the logs upload succeeds or fails.
* @param logsId
* @param value
*/
void updateLogsStatus(String logsId, Integer value);
/**
* Get the file address.
* @param logsId
* @param fileId
* @return
*/
URL getLogsFileUrl(String logsId, String fileId);
}

14
src/main/java/com/dji/sample/manage/service/IDevicePayloadService.java

@ -4,6 +4,7 @@ import com.dji.sample.manage.model.dto.DevicePayloadDTO;
import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; import com.dji.sample.manage.model.receiver.DevicePayloadReceiver;
import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -52,4 +53,17 @@ public interface IDevicePayloadService {
* @param receiver * @param receiver
*/ */
void updateFirmwareVersion(FirmwareVersionReceiver receiver); void updateFirmwareVersion(FirmwareVersionReceiver receiver);
/**
* Handle the topic that contains the payloads field in the state, and save the payloads data.
* @param payloadReceiverList
* @param timestamp
*/
void saveDeviceBasicPayload(List<DevicePayloadReceiver> payloadReceiverList, Long timestamp);
/**
* Delete payload data based on payload sn.
* @param payloadSns
*/
void deletePayloadsByPayloadsSn(Collection<String> payloadSns);
} }

10
src/main/java/com/dji/sample/manage/service/IDeviceService.java

@ -1,10 +1,12 @@
package com.dji.sample.manage.service; package com.dji.sample.manage.service;
import com.dji.sample.common.model.PaginationData; import com.dji.sample.common.model.PaginationData;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.CommonTopicReceiver; import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
import com.dji.sample.component.mqtt.model.CommonTopicResponse; import com.dji.sample.component.mqtt.model.CommonTopicResponse;
import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession;
import com.dji.sample.manage.model.dto.DeviceDTO; import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.dto.DeviceFirmwareUpgradeDTO;
import com.dji.sample.manage.model.dto.TopologyDeviceDTO; import com.dji.sample.manage.model.dto.TopologyDeviceDTO;
import com.dji.sample.manage.model.param.DeviceQueryParam; import com.dji.sample.manage.model.param.DeviceQueryParam;
import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver;
@ -195,4 +197,12 @@ public interface IDeviceService {
* @param receiver * @param receiver
*/ */
void updateFirmwareVersion(FirmwareVersionReceiver receiver); void updateFirmwareVersion(FirmwareVersionReceiver receiver);
/**
* Create job for device firmware updates.
* @param workspaceId
* @param upgradeDTOS
* @return
*/
ResponseResult createDeviceOtaJob(String workspaceId, List<DeviceFirmwareUpgradeDTO> upgradeDTOS);
} }

3
src/main/java/com/dji/sample/manage/service/ILiveStreamService.java

@ -24,8 +24,9 @@ public interface ILiveStreamService {
/** /**
* Save live capability data. * Save live capability data.
* @param liveCapacityReceiver * @param liveCapacityReceiver
* @param timestamp
*/ */
void saveLiveCapacity(LiveCapacityReceiver liveCapacityReceiver); void saveLiveCapacity(LiveCapacityReceiver liveCapacityReceiver, Long timestamp);
/** /**
* Initiate a live streaming by publishing mqtt message. * Initiate a live streaming by publishing mqtt message.

46
src/main/java/com/dji/sample/manage/service/ILogsFileIndexService.java

@ -0,0 +1,46 @@
package com.dji.sample.manage.service;
import com.dji.sample.manage.model.dto.LogsFileDTO;
import com.dji.sample.manage.model.receiver.LogsFile;
import com.dji.sample.manage.model.receiver.LogsFileUpload;
import java.util.List;
import java.util.Optional;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
public interface ILogsFileIndexService {
/**
* Insert the index of the device logs.
* @param file
* @param deviceSn
* @param domain
* @param fileId
* @return
*/
Boolean insertFileIndex(LogsFile file, String deviceSn, Integer domain, String fileId);
/**
* Query logs file upload information based on the file id.
* @param fileId
* @return
*/
Optional<LogsFileUpload> getFileIndexByFileId(String fileId);
/**
* Batch query logs file upload information.
* @param fileIds
* @return
*/
List<LogsFileUpload> getFileIndexByFileIds(List<LogsFileDTO> fileIds);
/**
* Delete log index data based on file id.
* @param fileIds
*/
void deleteFileIndexByFileIds(List<String> fileIds);
}

66
src/main/java/com/dji/sample/manage/service/ILogsFileService.java

@ -0,0 +1,66 @@
package com.dji.sample.manage.service;
import com.dji.sample.manage.model.dto.LogsFileDTO;
import com.dji.sample.manage.model.receiver.LogsExtFileReceiver;
import com.dji.sample.manage.model.receiver.LogsFileUpload;
import java.net.URL;
import java.util.List;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
public interface ILogsFileService {
/**
* Query the uploaded log file information based on the log id.
* @param logsId
* @return
*/
List<LogsFileDTO> getLogsFileInfoByLogsId(String logsId);
/**
* Query the uploaded log file structure information based on the log id.
* @param logsId
* @return
*/
List<LogsFileUpload> getLogsFileByLogsId(String logsId);
/**
* Added logs file.
* @param file
* @param logsId
* @return
*/
Boolean insertFile(LogsFileUpload file, String logsId);
/**
* Delete logs files.
* @param logsId
*/
void deleteFileByLogsId(String logsId);
/**
* Update file information.
* @param logsId
* @param fileReceiver
*/
void updateFile(String logsId, LogsExtFileReceiver fileReceiver);
/**
* Update file upload status.
* @param logsId
* @param isUploaded
*/
void updateFileUploadStatus(String logsId, Boolean isUploaded);
/**
* Get the file address.
* @param logsId
* @param fileId
* @return
*/
URL getLogsFileUrl(String logsId, String fileId);
}

8
src/main/java/com/dji/sample/manage/service/ITopologyService.java

@ -3,6 +3,7 @@ package com.dji.sample.manage.service;
import com.dji.sample.manage.model.dto.TopologyDTO; import com.dji.sample.manage.model.dto.TopologyDTO;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* @author sean * @author sean
@ -17,4 +18,11 @@ public interface ITopologyService {
* @return * @return
*/ */
List<TopologyDTO> getDeviceTopology(String workspaceId); List<TopologyDTO> getDeviceTopology(String workspaceId);
/**
* Query the topology according to the gateway sn.
* @param gatewaySn
* @return
*/
Optional<TopologyDTO> getDeviceTopologyByGatewaySn(String gatewaySn);
} }

4
src/main/java/com/dji/sample/manage/service/impl/CapacityCameraServiceImpl.java

@ -1,6 +1,7 @@
package com.dji.sample.manage.service.impl; package com.dji.sample.manage.service.impl;
import com.dji.sample.component.mqtt.model.StateDataEnum; import com.dji.sample.component.mqtt.model.StateDataEnum;
import com.dji.sample.component.redis.RedisConst;
import com.dji.sample.component.redis.RedisOpsUtils; import com.dji.sample.component.redis.RedisOpsUtils;
import com.dji.sample.manage.model.dto.CapacityCameraDTO; import com.dji.sample.manage.model.dto.CapacityCameraDTO;
import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; import com.dji.sample.manage.model.dto.DeviceDictionaryDTO;
@ -46,10 +47,11 @@ public class CapacityCameraServiceImpl implements ICapacityCameraService {
} }
@Override @Override
public void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn) { public void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn, Long timestamp) {
List<CapacityCameraDTO> capacity = capacityCameraReceivers.stream() List<CapacityCameraDTO> capacity = capacityCameraReceivers.stream()
.map(this::receiver2Dto).collect(Collectors.toList()); .map(this::receiver2Dto).collect(Collectors.toList());
redisOps.hashSet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn, capacity); redisOps.hashSet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn, capacity);
redisOps.setWithExpire(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + deviceSn, timestamp, RedisConst.DEVICE_ALIVE_SECOND);
} }
@Override @Override

218
src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java

@ -0,0 +1,218 @@
package com.dji.sample.manage.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.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.entity.DeviceFirmwareEntity;
import com.dji.sample.manage.model.enums.UserTypeEnum;
import com.dji.sample.manage.model.param.DeviceOtaCreateParam;
import com.dji.sample.manage.service.IDeviceFirmwareService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* @author sean
* @version 1.2
* @date 2022/8/16
*/
@Service
@Slf4j
public class DeviceFirmwareServiceImpl implements IDeviceFirmwareService {
@Autowired
private IDeviceFirmwareMapper mapper;
@Autowired
private RedisOpsUtils redisOps;
@Autowired
private MessageSenderServiceImpl messageSenderService;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SendMessageServiceImpl webSocketMessageService;
@Autowired
private IWebSocketManageService webSocketManageService;
@Override
public Optional<DeviceFirmwareDTO> getFirmware(String deviceName, String version) {
return Optional.ofNullable(entity2Dto(mapper.selectOne(
new LambdaQueryWrapper<DeviceFirmwareEntity>()
.eq(DeviceFirmwareEntity::getDeviceName, deviceName)
.eq(DeviceFirmwareEntity::getFirmwareVersion, version))));
}
@Override
public Optional<DeviceFirmwareNoteDTO> getLatestFirmwareReleaseNote(String deviceName) {
return Optional.ofNullable(entity2NoteDto(mapper.selectOne(
new LambdaQueryWrapper<DeviceFirmwareEntity>()
.eq(DeviceFirmwareEntity::getDeviceName, deviceName)
.eq(DeviceFirmwareEntity::getStatus, true)
.orderByDesc(DeviceFirmwareEntity::getReleaseDate)
.last(" limit 1 "))));
}
@Override
public List<DeviceOtaCreateParam> getDeviceOtaFirmware(List<DeviceFirmwareUpgradeDTO> upgradeDTOS) {
List<DeviceOtaCreateParam> deviceOtaList = new ArrayList<>();
upgradeDTOS.forEach(upgradeDevice -> {
boolean exist = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + upgradeDevice.getSn()) > 0;
if (!exist) {
throw new IllegalArgumentException("Device is offline.");
}
Optional<DeviceFirmwareDTO> firmwareOpt = this.getFirmware(
upgradeDevice.getDeviceName(), upgradeDevice.getProductVersion());
if (firmwareOpt.isEmpty()) {
throw new IllegalArgumentException("This firmware version does not exist.");
}
if (!firmwareOpt.get().getFirmwareStatus()) {
throw new IllegalArgumentException("This firmware version is not available.");
}
DeviceOtaCreateParam ota = dto2OtaCreateDto(firmwareOpt.get());
ota.setSn(upgradeDevice.getSn());
ota.setFirmwareUpgradeType(upgradeDevice.getFirmwareUpgradeType());
deviceOtaList.add(ota);
});
return deviceOtaList;
}
@Override
@ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_OTA_PROGRESS, outputChannel = ChannelName.OUTBOUND)
public void handleOtaProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString();
String sn = topic.substring((TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT).length(),
topic.indexOf(TopicConst.EVENTS_SUF));
EventsReceiver<EventsOutputReceiver> eventsReceiver = objectMapper.convertValue(receiver.getData(),
new TypeReference<EventsReceiver<EventsOutputReceiver>>(){});
eventsReceiver.setBid(receiver.getBid());
eventsReceiver.setSn(sn);
EventsOutputReceiver output = eventsReceiver.getOutput();
log.info("SN: {}, {} ===> Upgrading progress: {}",
sn, receiver.getMethod(), output.getProgress().toString());
if (eventsReceiver.getResult() != ResponseResult.CODE_SUCCESS) {
log.error("SN: {}, {} ===> Error code: {}", sn, receiver.getMethod(), eventsReceiver.getResult());
}
DeviceDTO device = (DeviceDTO) redisOps.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;
// 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);
} else {
// Update the update progress of the dock in redis.
redisOps.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);
} else {
// Update the update progress of the drone in redis.
redisOps.setWithExpire(
RedisConst.FIRMWARE_UPGRADING_PREFIX + childDeviceSn, output.getProgress().getPercent(),
RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND);
}
}
webSocketMessageService.sendBatch(
webSocketManageService.getValueWithWorkspaceAndUserType(
device.getWorkspaceId(), UserTypeEnum.WEB.getVal()),
CustomWebSocketMessage.builder()
.data(eventsReceiver)
.timestamp(System.currentTimeMillis())
.bizCode(receiver.getMethod())
.build());
if (receiver.getNeedReply() != null && receiver.getNeedReply() == 1) {
String replyTopic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF;
messageSenderService.publish(replyTopic,
CommonTopicResponse.builder()
.tid(receiver.getTid())
.bid(receiver.getBid())
.method(receiver.getMethod())
.timestamp(System.currentTimeMillis())
.data(ResponseResult.success())
.build());
}
}
private DeviceFirmwareNoteDTO entity2NoteDto (DeviceFirmwareEntity entity) {
if (entity == null) {
return null;
}
return DeviceFirmwareNoteDTO.builder()
.deviceName(entity.getDeviceName())
.productVersion(entity.getFirmwareVersion())
.releasedTime(LocalDate.ofInstant(Instant.ofEpochMilli(entity.getReleaseDate()), ZoneId.systemDefault()))
.releaseNote(entity.getReleaseNote())
.build();
}
private DeviceFirmwareDTO entity2Dto (DeviceFirmwareEntity entity) {
if (entity == null) {
return null;
}
return DeviceFirmwareDTO.builder()
.deviceName(entity.getDeviceName())
.fileMd5(entity.getFileMd5())
.fileSize(entity.getFileSize())
.fileUrl(entity.getFileUrl())
.firmwareId(entity.getFirmwareId())
.fileName(entity.getFileName())
.productVersion(entity.getFirmwareVersion())
.releasedTime(LocalDate.ofInstant(Instant.ofEpochMilli(entity.getReleaseDate()), ZoneId.systemDefault()))
.firmwareStatus(entity.getStatus())
.build();
}
private DeviceOtaCreateParam dto2OtaCreateDto(DeviceFirmwareDTO dto) {
if (dto == null) {
return null;
}
return DeviceOtaCreateParam.builder()
.fileSize(dto.getFileSize())
.fileUrl(dto.getFileUrl())
.fileName(dto.getFileName())
.md5(dto.getFileMd5())
.productVersion(dto.getProductVersion())
.build();
}
}

172
src/main/java/com/dji/sample/manage/service/impl/DeviceHmsServiceImpl.java

@ -43,6 +43,8 @@ import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.*; import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -69,9 +71,61 @@ public class DeviceHmsServiceImpl implements IDeviceHmsService {
@Autowired @Autowired
private WebSocketManageServiceImpl webSocketManageService; private WebSocketManageServiceImpl webSocketManageService;
private static final Pattern PATTERN_KEY = Pattern.compile(
HmsEnum.FormatKeyEnum.KEY_START +
"(" +
Arrays.stream(HmsEnum.FormatKeyEnum.values())
.map(HmsEnum.FormatKeyEnum::getKey)
.collect(Collectors.joining("|")) +
")");
@Override @Override
@ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_HMS) @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_HMS)
public void handleHms(CommonTopicReceiver receiver, MessageHeaders headers) { public void handleHms(CommonTopicReceiver receiver, MessageHeaders headers) {
String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString();
String sn = topic.substring((TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT).length(),
topic.indexOf(TopicConst.EVENTS_SUF));
DeviceHmsEntity entity = DeviceHmsEntity.builder()
.bid(receiver.getBid())
.tid(receiver.getTid())
.createTime(receiver.getTimestamp())
.updateTime(0L)
.sn(sn)
.build();
String key = RedisConst.HMS_PREFIX + sn;
// Query all unread hms messages of the device in redis.
Set<String> hmsMap = redisOps.listGetAll(key).stream().map(String::valueOf).collect(Collectors.toSet());
DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + sn);
List<DeviceHmsDTO> unReadList = new ArrayList<>();
objectMapper.convertValue(((Map) (receiver.getData())).get(MapKeyConst.LIST),
new TypeReference<List<DeviceHmsReceiver>>() {})
.forEach(hmsReceiver -> {
final DeviceHmsEntity hms = entity.clone();
this.fillEntity(hms, hmsReceiver);
// The same unread hms are no longer incremented.
if (hmsMap.contains(hms.getHmsKey())) {
return;
}
this.fillMessage(hms, hmsReceiver.getArgs());
unReadList.add(entity2Dto(hms));
mapper.insert(hms);
});
if (unReadList.isEmpty()) {
return;
}
redisOps.listRPush(key, unReadList.stream().map(DeviceHmsDTO::getKey).toArray(String[]::new));
// push to the web
Collection<ConcurrentWebSocketSession> sessions = webSocketManageService.getValueWithWorkspaceAndUserType(
device.getWorkspaceId(), UserTypeEnum.WEB.getVal());
sendMessageService.sendBatch(sessions, CustomWebSocketMessage.builder()
.bizCode(BizCodeEnum.DEVICE_HMS.getCode())
.data(TelemetryDTO.<List<DeviceHmsDTO>>builder().sn(sn).host(unReadList).build())
.timestamp(System.currentTimeMillis())
.build());
} }
@Override @Override
@ -107,6 +161,7 @@ public class DeviceHmsServiceImpl implements IDeviceHmsService {
new LambdaUpdateWrapper<DeviceHmsEntity>() new LambdaUpdateWrapper<DeviceHmsEntity>()
.eq(DeviceHmsEntity::getSn, deviceSn) .eq(DeviceHmsEntity::getSn, deviceSn)
.eq(DeviceHmsEntity::getUpdateTime, 0L)); .eq(DeviceHmsEntity::getUpdateTime, 0L));
// Delete unread messages cached in redis.
redisOps.del(RedisConst.HMS_PREFIX + deviceSn); redisOps.del(RedisConst.HMS_PREFIX + deviceSn);
} }
@ -130,4 +185,121 @@ public class DeviceHmsServiceImpl implements IDeviceHmsService {
.build(); .build();
} }
/**
* Populate the received data into the entity. Please refer to the documentation for splicing rules.
* @param dto
* @param receiver
*/
private void fillEntity(DeviceHmsEntity dto, DeviceHmsReceiver receiver) {
dto.setLevel(receiver.getLevel());
dto.setModule(receiver.getModule());
dto.setHmsId(UUID.randomUUID().toString());
if (HmsEnum.DomainType.DRONE_NEST.getDomain().equals(receiver.getDomainType())) {
dto.setHmsKey(HmsEnum.HmsFaqIdEnum.DOCK_TIP.getText() + receiver.getCode());
return;
}
StringBuilder key = new StringBuilder(HmsEnum.HmsFaqIdEnum.FPV_TIP.getText()).append(receiver.getCode());
if (receiver.getInTheSky() == HmsEnum.IN_THE_SKY.getVal()) {
key.append(HmsEnum.IN_THE_SKY.getText());
}
dto.setHmsKey(key.toString());
}
/**
* Replace wildcards in messages according to the relevant rules.
* Please refer to the documentation for splicing rules.
* @param dto
* @param args
*/
private void fillMessage(DeviceHmsEntity dto, HmsArgsReceiver args) {
HmsMessage hmsMessage = HmsJsonUtil.get(dto.getHmsKey());
String zh = StringUtils.hasText(hmsMessage.getZh()) ? hmsMessage.getZh() : String.format("未知错误(%s)", dto.getHmsKey());
String en = StringUtils.hasText(hmsMessage.getEn()) ? hmsMessage.getEn() : String.format("Unknown(%s)", dto.getHmsKey());//
dto.setMessageZh(format(Locale.CHINESE.getLanguage(), zh, args));
dto.setMessageEn(format(Locale.ENGLISH.getLanguage(), en, args));
}
/**
* Set the matching parameters for key.
* @param l language: zh or en
* @param hmsArgs
* @return
*/
private List<String> fillKeyArgs(String l, HmsArgsReceiver hmsArgs) {
List<String> args = new ArrayList<>();
args.add(Objects.nonNull(hmsArgs.getAlarmId()) ? Long.toHexString(hmsArgs.getAlarmId()) : null);
args.add(Objects.nonNull(hmsArgs.getComponentIndex()) ? String.valueOf(hmsArgs.getComponentIndex() + 1) : null);
if (Objects.nonNull(hmsArgs.getSensorIndex())) {
args.add(String.valueOf(hmsArgs.getSensorIndex() + 1));
HmsEnum.HmsBatteryIndexEnum hmsBatteryIndexEnum = HmsEnum.HmsBatteryIndexEnum.find(hmsArgs.getSensorIndex());
HmsEnum.HmsDockCoverIndexEnum hmsDockCoverIndexEnum = HmsEnum.HmsDockCoverIndexEnum.find(hmsArgs.getSensorIndex());
HmsEnum.HmsChargingRodIndexEnum hmsChargingRodIndexEnum = HmsEnum.HmsChargingRodIndexEnum.find(hmsArgs.getSensorIndex());
switch (l) {
case "zh":
args.add(hmsBatteryIndexEnum.getZh());
args.add(hmsDockCoverIndexEnum.getZh());
args.add(hmsChargingRodIndexEnum.getZh());
break;
case "en":
args.add(hmsBatteryIndexEnum.getEn());
args.add(hmsDockCoverIndexEnum.getEn());
args.add(hmsChargingRodIndexEnum.getEn());
break;
default:
break;
}
}
return args;
}
/**
* Returns a formatted string using the specified locale, format string, and arguments.
* @param l language: zh or en
* @param format
* @param hmsArgs
* @return
*/
private String format(String l, String format, HmsArgsReceiver hmsArgs) {
List<String> args = fillKeyArgs(l, hmsArgs);
List<String> list = parse(format);
StringBuilder sb = new StringBuilder();
for (String word : list) {
if (!StringUtils.hasText(word)) {
continue;
}
HmsEnum.FormatKeyEnum keyEnum = HmsEnum.FormatKeyEnum.find(word.substring(1));
sb.append(HmsEnum.FormatKeyEnum.KEY_START != word.charAt(0) || HmsEnum.FormatKeyEnum.UNKNOWN == keyEnum ?
word : args.get(keyEnum.getIndex()));
}
return sb.toString();
}
/**
* Finds format specifiers in the format string.
* @param s
* @return
*/
private List<String> parse(String s) {
List<String> list = new ArrayList<>();
Matcher matcher = PATTERN_KEY.matcher(s);
for (int i = 0; i < s.length(); ) {
if (matcher.find(i)) {
if (matcher.start() != i) {
list.add(s.substring(i, matcher.start()));
}
list.add(matcher.group());
i = matcher.end();
} else {
list.add(s.substring(i));
break;
}
}
return list;
}
} }

376
src/main/java/com/dji/sample/manage/service/impl/DeviceLogsServiceImpl.java

@ -0,0 +1,376 @@
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.IMessageSenderService;
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.ISendMessageService;
import com.dji.sample.component.websocket.service.IWebSocketManageService;
import com.dji.sample.manage.dao.IDeviceLogsMapper;
import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.entity.DeviceLogsEntity;
import com.dji.sample.manage.model.enums.DeviceDomainEnum;
import com.dji.sample.manage.model.enums.DeviceLogsStatusEnum;
import com.dji.sample.manage.model.enums.LogsFileUpdateMethodEnum;
import com.dji.sample.manage.model.enums.UserTypeEnum;
import com.dji.sample.manage.model.param.DeviceLogsCreateParam;
import com.dji.sample.manage.model.param.DeviceLogsQueryParam;
import com.dji.sample.manage.model.param.LogsFileUpdateParam;
import com.dji.sample.manage.model.receiver.*;
import com.dji.sample.manage.service.IDeviceLogsService;
import com.dji.sample.manage.service.ILogsFileService;
import com.dji.sample.manage.service.ITopologyService;
import com.dji.sample.media.model.StsCredentialsDTO;
import com.dji.sample.storage.service.IStorageService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Service
@Transactional
@Slf4j
public class DeviceLogsServiceImpl implements IDeviceLogsService {
private static final String LOGS_FILE_SUFFIX = ".tar";
@Autowired
private IDeviceLogsMapper mapper;
@Autowired
private ITopologyService topologyService;
@Autowired
private IMessageSenderService messageSenderService;
@Autowired
private ILogsFileService logsFileService;
@Autowired
private RedisOpsUtils redisOpsUtils;
@Autowired
private IStorageService storageService;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ISendMessageService webSocketMessageService;
@Autowired
private IWebSocketManageService webSocketManageService;
@Override
public PaginationData<DeviceLogsDTO> getUploadedLogs(String deviceSn, DeviceLogsQueryParam param) {
LambdaQueryWrapper<DeviceLogsEntity> queryWrapper = new LambdaQueryWrapper<DeviceLogsEntity>()
.eq(DeviceLogsEntity::getDeviceSn, deviceSn)
.between(Objects.nonNull(param.getBeginTime()) && Objects.nonNull(param.getEndTime()),
DeviceLogsEntity::getCreateTime, param.getBeginTime(), param.getEndTime())
.eq(Objects.nonNull(param.getStatus()), DeviceLogsEntity::getStatus, param.getStatus())
.like(StringUtils.hasText(param.getLogsInformation()),
DeviceLogsEntity::getLogsInfo, param.getLogsInformation())
.orderByDesc(DeviceLogsEntity::getCreateTime);
Page<DeviceLogsEntity> pagination = mapper.selectPage(new Page<>(param.getPage(), param.getPageSize()), queryWrapper);
List<DeviceLogsDTO> deviceLogsList = pagination.getRecords().stream().map(this::entity2Dto).collect(Collectors.toList());
return new PaginationData<DeviceLogsDTO>(deviceLogsList, new Pagination(pagination));
}
@Override
public ResponseResult getRealTimeLogs(String deviceSn, List<String> domainList) {
boolean exist = redisOpsUtils.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + deviceSn) > 0;
if (!exist) {
return ResponseResult.error("Device is offline.");
}
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + deviceSn + TopicConst.SERVICES_SUF;
Optional<LogsFileUploadList> serviceReplyOpt = messageSenderService.publishWithReply(
LogsFileUploadList.class,
topic,
CommonTopicResponse.builder()
.tid(UUID.randomUUID().toString())
.bid(UUID.randomUUID().toString())
.method(ServicesMethodEnum.FILE_UPLOAD_LIST.getMethod())
.timestamp(System.currentTimeMillis())
.data(Map.of(MapKeyConst.MODULE_LIST, domainList))
.build(), 1);
if (serviceReplyOpt.isEmpty()) {
return ResponseResult.error("No message reply received.");
}
LogsFileUploadList data = serviceReplyOpt.get();
for (LogsFileUpload file : data.getFiles()) {
if (file.getDeviceSn().isBlank()) {
file.setDeviceSn(deviceSn);
}
}
return ResponseResult.success(data);
}
@Override
public String insertDeviceLogs(String bid, String username, String deviceSn, DeviceLogsCreateParam param) {
DeviceLogsEntity entity = DeviceLogsEntity.builder()
.deviceSn(deviceSn)
.username(username)
.happenTime(param.getHappenTime())
.logsInfo(Objects.requireNonNullElse(param.getLogsInformation(), ""))
.logsId(bid)
.status(DeviceLogsStatusEnum.UPLOADING.getVal())
.build();
boolean insert = mapper.insert(entity) > 0;
if (!insert) {
return "";
}
for (LogsFileUpload file : param.getFiles()) {
insert = logsFileService.insertFile(file, entity.getLogsId());
if (!insert) {
return "";
}
}
return bid;
}
@Override
public ResponseResult pushFileUpload(String username, String deviceSn, DeviceLogsCreateParam param) {
StsCredentialsDTO stsCredentials = storageService.getSTSCredentials();
LogsUploadCredentialsDTO credentialsDTO = new LogsUploadCredentialsDTO(stsCredentials);
// Set the storage name of the file.
List<LogsFileUpload> files = param.getFiles();
files.forEach(file -> file.setObjectKey(credentialsDTO.getObjectKeyPrefix() + "/" + UUID.randomUUID().toString() + LOGS_FILE_SUFFIX));
credentialsDTO.setParams(LogsFileUploadList.builder().files(files).build());
String bid = UUID.randomUUID().toString();
Optional<ServiceReply> serviceReply = messageSenderService.publishWithReply(
TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + deviceSn + TopicConst.SERVICES_SUF,
CommonTopicResponse.<LogsUploadCredentialsDTO>builder()
.tid(UUID.randomUUID().toString())
.bid(bid)
.timestamp(System.currentTimeMillis())
.method(ServicesMethodEnum.FILE_UPLOAD_START.getMethod())
.data(credentialsDTO)
.build());
if (serviceReply.isEmpty()) {
return ResponseResult.error("No message reply received.");
}
ServiceReply reply = serviceReply.get();
if (ResponseResult.CODE_SUCCESS != reply.getResult()) {
return ResponseResult.error(String.valueOf(reply.getResult()));
}
String logsId = this.insertDeviceLogs(bid, username, deviceSn, param);
if (!bid.equals(logsId)) {
return ResponseResult.error("Database insert failed.");
}
// Save the status of the log upload.
redisOpsUtils.hashSet(RedisConst.LOGS_FILE_PREFIX + deviceSn, bid, LogsOutputProgressDTO.builder().logsId(logsId).build());
return ResponseResult.success();
}
@Override
public ResponseResult pushUpdateFile(String deviceSn, LogsFileUpdateParam param) {
LogsFileUpdateMethodEnum method = LogsFileUpdateMethodEnum.find(param.getStatus());
if (LogsFileUpdateMethodEnum.UNKNOWN == method) {
return ResponseResult.error("Illegal param");
}
String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + deviceSn + TopicConst.SERVICES_SUF;
String bid = UUID.randomUUID().toString();
Optional<ServiceReply> serviceReply = messageSenderService.publishWithReply(topic,
CommonTopicResponse.<LogsFileUpdateParam>builder()
.tid(UUID.randomUUID().toString())
.bid(bid)
.timestamp(System.currentTimeMillis())
.method(ServicesMethodEnum.FILE_UPLOAD_UPDATE.getMethod())
.data(param)
.build());
if (serviceReply.isEmpty()) {
return ResponseResult.error("No message reply received.");
}
ServiceReply reply = serviceReply.get();
if (ResponseResult.CODE_SUCCESS != reply.getResult()) {
return ResponseResult.error("Error Code : " + reply.getResult());
}
return ResponseResult.success();
}
@Override
public void deleteLogs(String deviceSn, String logsId) {
mapper.delete(new LambdaUpdateWrapper<DeviceLogsEntity>()
.eq(DeviceLogsEntity::getLogsId, logsId).eq(DeviceLogsEntity::getDeviceSn, deviceSn));
logsFileService.deleteFileByLogsId(logsId);
}
@ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_FILE_UPLOAD_PROGRESS, outputChannel = ChannelName.OUTBOUND)
@Override
public void handleFileUploadProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString();
String sn = topic.substring((TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT).length(),
topic.indexOf(TopicConst.EVENTS_SUF));
if (receiver.getNeedReply() != null && receiver.getNeedReply() == 1) {
String replyTopic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF;
messageSenderService.publish(replyTopic,
CommonTopicResponse.builder()
.tid(receiver.getTid())
.bid(receiver.getBid())
.method(receiver.getMethod())
.timestamp(System.currentTimeMillis())
.data(ResponseResult.success())
.build());
}
EventsReceiver<OutputLogsProgressReceiver> eventsReceiver = objectMapper.convertValue(receiver.getData(),
new TypeReference<EventsReceiver<OutputLogsProgressReceiver>>(){});
EventsReceiver<LogsOutputProgressDTO> webSocketData = new EventsReceiver<>();
webSocketData.setBid(receiver.getBid());
webSocketData.setSn(sn);
DeviceDTO device = (DeviceDTO) redisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + sn);
try {
OutputLogsProgressReceiver output = eventsReceiver.getOutput();
EventsResultStatusEnum statusEnum = EventsResultStatusEnum.find(output.getStatus());
log.info("Logs upload progress: {}", output.toString());
String key = RedisConst.LOGS_FILE_PREFIX + sn;
LogsOutputProgressDTO progress;
boolean exist = redisOpsUtils.checkExist(key);
if (!exist && !statusEnum.getEnd()) {
progress = LogsOutputProgressDTO.builder().logsId(receiver.getBid()).build();
redisOpsUtils.hashSet(key, receiver.getBid(), progress);
} else if (exist) {
progress = (LogsOutputProgressDTO) redisOpsUtils.hashGet(key, receiver.getBid());
} else {
progress = LogsOutputProgressDTO.builder().build();
}
progress.setStatus(output.getStatus());
// If the logs file is empty, delete the cache of this task.
List<LogsExtFileReceiver> fileReceivers = output.getExt().getFiles();
if (CollectionUtils.isEmpty(fileReceivers)) {
redisOpsUtils.del(RedisConst.LOGS_FILE_PREFIX + sn);
return;
}
// refresh cache.
List<LogsProgressDTO> fileProgressList = new ArrayList<>();
fileReceivers.forEach(file -> {
LogsProgressReceiver logsProgress = file.getProgress();
if (!StringUtils.hasText(file.getDeviceSn())) {
if (String.valueOf(DeviceDomainEnum.DOCK.getVal()).equals(file.getDeviceModelDomain())) {
file.setDeviceSn(sn);
} else if (String.valueOf(DeviceDomainEnum.SUB_DEVICE.getVal()).equals(file.getDeviceModelDomain())) {
file.setDeviceSn(device.getChildDeviceSn());
}
}
fileProgressList.add(LogsProgressDTO.builder()
.deviceSn(file.getDeviceSn())
.deviceModelDomain(file.getDeviceModelDomain())
.result(logsProgress.getResult())
.status(logsProgress.getStatus())
.uploadRate(logsProgress.getUploadRate())
.progress(((logsProgress.getCurrentStep() - 1) * 100 + logsProgress.getProgress()) / logsProgress.getTotalStep())
.build());
});
progress.setFiles(fileProgressList);
webSocketData.setOutput(progress);
redisOpsUtils.hashSet(RedisConst.LOGS_FILE_PREFIX + sn, receiver.getBid(), progress);
// Delete the cache at the end of the task.
if (statusEnum.getEnd()) {
redisOpsUtils.del(RedisConst.LOGS_FILE_PREFIX + sn);
this.updateLogsStatus(receiver.getBid(), DeviceLogsStatusEnum.find(statusEnum).getVal());
fileReceivers.forEach(file -> logsFileService.updateFile(receiver.getBid(), file));
}
} catch (NullPointerException e) {
this.updateLogsStatus(receiver.getBid(), DeviceLogsStatusEnum.FAILED.getVal());
redisOpsUtils.del(RedisConst.LOGS_FILE_PREFIX + sn);
}
webSocketMessageService.sendBatch(
webSocketManageService.getValueWithWorkspaceAndUserType(
device.getWorkspaceId(), UserTypeEnum.WEB.getVal()),
CustomWebSocketMessage.builder()
.data(webSocketData)
.timestamp(System.currentTimeMillis())
.bizCode(receiver.getMethod())
.build());
}
@Override
public void updateLogsStatus(String logsId, Integer value) {
mapper.update(DeviceLogsEntity.builder().status(value).build(),
new LambdaUpdateWrapper<DeviceLogsEntity>().eq(DeviceLogsEntity::getLogsId, logsId));
if (DeviceLogsStatusEnum.DONE.getVal() == value) {
logsFileService.updateFileUploadStatus(logsId, true);
}
}
@Override
public URL getLogsFileUrl(String logsId, String fileId) {
return logsFileService.getLogsFileUrl(logsId, fileId);
}
private DeviceLogsDTO entity2Dto(DeviceLogsEntity entity) {
if (Objects.isNull(entity)) {
return null;
}
String key = RedisConst.LOGS_FILE_PREFIX + entity.getDeviceSn();
LogsOutputProgressDTO progress = new LogsOutputProgressDTO();
if (redisOpsUtils.hashCheck(key, entity.getLogsId())) {
progress = (LogsOutputProgressDTO) redisOpsUtils.hashGet(key, entity.getLogsId());
}
return DeviceLogsDTO.builder()
.logsId(entity.getLogsId())
.createTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getCreateTime()), ZoneId.systemDefault()))
.happenTime(Objects.isNull(entity.getHappenTime()) ?
null : LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getHappenTime()), ZoneId.systemDefault()))
.status(entity.getStatus())
.logsInformation(entity.getLogsInfo())
.userName(entity.getUsername())
.deviceLogs(LogsFileUploadList.builder().files(logsFileService.getLogsFileByLogsId(entity.getLogsId())).build())
.logsProgress(progress.getFiles())
.deviceTopo(topologyService.getDeviceTopologyByGatewaySn(entity.getDeviceSn()).orElse(null))
.build();
}
}

50
src/main/java/com/dji/sample/manage/service/impl/DevicePayloadServiceImpl.java

@ -14,14 +14,13 @@ import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver;
import com.dji.sample.manage.service.ICapacityCameraService; import com.dji.sample.manage.service.ICapacityCameraService;
import com.dji.sample.manage.service.IDeviceDictionaryService; import com.dji.sample.manage.service.IDeviceDictionaryService;
import com.dji.sample.manage.service.IDevicePayloadService; import com.dji.sample.manage.service.IDevicePayloadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -29,6 +28,7 @@ import java.util.stream.Collectors;
* @version 0.1 * @version 0.1
* @date 2021/11/19 * @date 2021/11/19
*/ */
@Slf4j
@Service @Service
@Transactional @Transactional
public class DevicePayloadServiceImpl implements IDevicePayloadService { public class DevicePayloadServiceImpl implements IDevicePayloadService {
@ -124,6 +124,48 @@ public class DevicePayloadServiceImpl implements IDevicePayloadService {
.eq(DevicePayloadEntity::getDeviceSn, receiver.getSn())); .eq(DevicePayloadEntity::getDeviceSn, receiver.getSn()));
} }
@Override
public void saveDeviceBasicPayload(List<DevicePayloadReceiver> payloadReceiverList, Long timestamp) {
if (payloadReceiverList.isEmpty()) {
return;
}
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);
if (last > timestamp) {
return;
}
// Filter unsaved payload information.
Set<String> payloadSns = this.getDevicePayloadEntitiesByDeviceSn(payloadReceiverList.get(0).getDeviceSn())
.stream().map(DevicePayloadDTO::getPayloadSn).collect(Collectors.toSet());
Set<String> newPayloadSns = payloadReceiverList.stream().map(DevicePayloadReceiver::getSn).collect(Collectors.toSet());
Set<String> needToDel = payloadSns.stream().filter(sn -> !newPayloadSns.contains(sn)).collect(Collectors.toSet());
this.deletePayloadsByPayloadsSn(needToDel);
List<DevicePayloadReceiver> needToSave = payloadReceiverList.stream()
.filter(payload -> !payloadSns.contains(payload.getSn())).collect(Collectors.toList());
// Save the new payload information.
boolean isSave = this.savePayloadDTOs(needToSave);
if (isSave) {
redisOps.setWithExpire(key, timestamp, RedisConst.DEVICE_ALIVE_SECOND);
}
log.debug("The result of saving the payloads is {}.", isSave);
}
@Override
public void deletePayloadsByPayloadsSn(Collection<String> payloadSns) {
if (CollectionUtils.isEmpty(payloadSns)) {
return;
}
mapper.delete(new LambdaUpdateWrapper<DevicePayloadEntity>()
.or(wrapper -> payloadSns.forEach(sn -> wrapper.eq(DevicePayloadEntity::getPayloadSn, sn))));
}
/** /**
* Convert database entity objects into payload data transfer object. * Convert database entity objects into payload data transfer object.
* @param entity * @param entity

111
src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dji.sample.common.error.CommonErrorEnum; import com.dji.sample.common.error.CommonErrorEnum;
import com.dji.sample.common.model.Pagination; import com.dji.sample.common.model.Pagination;
import com.dji.sample.common.model.PaginationData; 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.model.*;
import com.dji.sample.component.mqtt.service.IMessageSenderService; import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.mqtt.service.IMqttTopicService; import com.dji.sample.component.mqtt.service.IMqttTopicService;
@ -20,8 +21,10 @@ import com.dji.sample.manage.dao.IDeviceMapper;
import com.dji.sample.manage.model.dto.*; import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.entity.DeviceEntity; import com.dji.sample.manage.model.entity.DeviceEntity;
import com.dji.sample.manage.model.enums.DeviceDomainEnum; import com.dji.sample.manage.model.enums.DeviceDomainEnum;
import com.dji.sample.manage.model.enums.DeviceFirmwareStatusEnum;
import com.dji.sample.manage.model.enums.IconUrlEnum; import com.dji.sample.manage.model.enums.IconUrlEnum;
import com.dji.sample.manage.model.enums.UserTypeEnum; import com.dji.sample.manage.model.enums.UserTypeEnum;
import com.dji.sample.manage.model.param.DeviceOtaCreateParam;
import com.dji.sample.manage.model.param.DeviceQueryParam; import com.dji.sample.manage.model.param.DeviceQueryParam;
import com.dji.sample.manage.model.receiver.*; import com.dji.sample.manage.model.receiver.*;
import com.dji.sample.manage.service.*; import com.dji.sample.manage.service.*;
@ -89,6 +92,9 @@ public class DeviceServiceImpl implements IDeviceService {
@Autowired @Autowired
private IWebSocketManageService webSocketManageService; private IWebSocketManageService webSocketManageService;
@Autowired
private IDeviceFirmwareService deviceFirmwareService;
@Autowired @Autowired
@Qualifier("gatewayOSDServiceImpl") @Qualifier("gatewayOSDServiceImpl")
private ITSAService tsaService; private ITSAService tsaService;
@ -123,13 +129,6 @@ public class DeviceServiceImpl implements IDeviceService {
return true; return true;
} }
long expire = redisOps.getExpire(key);
// If the key about the device in redis has expired, the remote control is considered to be offline.
if (expire <= 0) {
log.debug("The remote control is already offline.");
return true;
}
String deviceSn = ((DeviceDTO)(redisOps.get(key))).getChildDeviceSn(); String deviceSn = ((DeviceDTO)(redisOps.get(key))).getChildDeviceSn();
if (deviceSn.equals(gatewaySn)) { if (deviceSn.equals(gatewaySn)) {
return true; return true;
@ -165,10 +164,10 @@ public class DeviceServiceImpl implements IDeviceService {
String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn;
// change log: Use redis instead of // change log: Use redis instead of
long time = redisOps.getExpire(key); long time = redisOps.getExpire(key);
long gatewayTime = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + deviceGateway.getSn());
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (time > 0) { if (time > 0 && gatewayTime > 0) {
redisOps.expireKey(RedisConst.DEVICE_ONLINE_PREFIX + deviceGateway.getSn(), RedisConst.DEVICE_ALIVE_SECOND);
redisOps.expireKey(key, RedisConst.DEVICE_ALIVE_SECOND); redisOps.expireKey(key, RedisConst.DEVICE_ALIVE_SECOND);
DeviceDTO device = DeviceDTO.builder().loginTime(LocalDateTime.now()).deviceSn(deviceSn).build(); DeviceDTO device = DeviceDTO.builder().loginTime(LocalDateTime.now()).deviceSn(deviceSn).build();
DeviceDTO gateway = DeviceDTO.builder() DeviceDTO gateway = DeviceDTO.builder()
@ -372,6 +371,9 @@ public class DeviceServiceImpl implements IDeviceService {
@Override @Override
public Optional<TopologyDeviceDTO> getDeviceTopoForPilot(String sn) { public Optional<TopologyDeviceDTO> getDeviceTopoForPilot(String sn) {
if (sn.isBlank()) {
return Optional.empty();
}
List<TopologyDeviceDTO> topologyDeviceList = this.getDevicesByParams( List<TopologyDeviceDTO> topologyDeviceList = this.getDevicesByParams(
DeviceQueryParam.builder() DeviceQueryParam.builder()
.deviceSn(sn) .deviceSn(sn)
@ -468,9 +470,19 @@ public class DeviceServiceImpl implements IDeviceService {
DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + from); DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + from);
if (device == null || !StringUtils.hasText(device.getWorkspaceId())) { if (device == null) {
Optional<DeviceDTO> deviceOpt = this.getDeviceBySn(from);
if (deviceOpt.isEmpty()) {
return; return;
} }
device = deviceOpt.get();
if (!StringUtils.hasText(device.getWorkspaceId())) {
return;
}
redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + from, device,
RedisConst.DEVICE_ALIVE_SECOND);
this.subscribeTopicOnline(from);
}
receiver = objectMapper.readValue(payload, CommonTopicReceiver.class); receiver = objectMapper.readValue(payload, CommonTopicReceiver.class);
@ -613,7 +625,7 @@ public class DeviceServiceImpl implements IDeviceService {
if (entity == null) { if (entity == null) {
return null; return null;
} }
return DeviceDTO.builder() DeviceDTO.DeviceDTOBuilder deviceDTOBuilder = DeviceDTO.builder()
.deviceSn(entity.getDeviceSn()) .deviceSn(entity.getDeviceSn())
.childDeviceSn(entity.getChildSn()) .childDeviceSn(entity.getChildSn())
.deviceName(entity.getDeviceName()) .deviceName(entity.getDeviceName())
@ -638,8 +650,31 @@ public class DeviceServiceImpl implements IDeviceService {
.firmwareVersion(entity.getFirmwareVersion()) .firmwareVersion(entity.getFirmwareVersion())
.workspaceName(entity.getWorkspaceId() != null ? .workspaceName(entity.getWorkspaceId() != null ?
workspaceService.getWorkspaceByWorkspaceId(entity.getWorkspaceId()) workspaceService.getWorkspaceByWorkspaceId(entity.getWorkspaceId())
.map(WorkspaceDTO::getWorkspaceName).orElse("") : "") .map(WorkspaceDTO::getWorkspaceName).orElse("") : "");
.build();
if (!StringUtils.hasText(entity.getFirmwareVersion())) {
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());
if (Objects.nonNull(progress)) {
return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.UPGRADING.getVal()).firmwareProgress((int)progress).build();
}
// First query the latest firmware version of the device model and compare it with the current firmware version
// to see if it needs to be upgraded.
Optional<DeviceFirmwareNoteDTO> firmwareReleaseNoteOpt = deviceFirmwareService.getLatestFirmwareReleaseNote(entity.getDeviceName());
if (firmwareReleaseNoteOpt.isPresent()) {
DeviceFirmwareNoteDTO firmwareNoteDTO = firmwareReleaseNoteOpt.get();
if (firmwareNoteDTO.getProductVersion().equals(entity.getFirmwareVersion())) {
return deviceDTOBuilder.firmwareStatus(entity.getCompatibleStatus() ?
DeviceFirmwareStatusEnum.NOT_UPGRADE.getVal() :
DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE.getVal()).build();
}
return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.NORMAL_UPGRADE.getVal()).build();
}
return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.NOT_UPGRADE.getVal()).build();
} }
@Override @Override
@ -822,15 +857,59 @@ public class DeviceServiceImpl implements IDeviceService {
@Override @Override
public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { public void updateFirmwareVersion(FirmwareVersionReceiver receiver) {
if (receiver.getDomain() == DeviceDomainEnum.SUB_DEVICE) { if (receiver.getDomain() == DeviceDomainEnum.SUB_DEVICE) {
this.updateDevice(DeviceDTO.builder() final DeviceDTO device = DeviceDTO.builder()
.deviceSn(receiver.getSn()) .deviceSn(receiver.getSn())
.firmwareVersion(receiver.getFirmwareVersion()) .firmwareVersion(receiver.getFirmwareVersion())
.build()); .firmwareStatus(receiver.getCompatibleStatus() == null ?
null : DeviceFirmwareStatusEnum.CompatibleStatusEnum.INCONSISTENT.getVal() != receiver.getCompatibleStatus() ?
DeviceFirmwareStatusEnum.UNKNOWN.getVal() : DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE.getVal())
.build();
this.updateDevice(device);
return; return;
} }
payloadService.updateFirmwareVersion(receiver); payloadService.updateFirmwareVersion(receiver);
} }
@Override
public ResponseResult createDeviceOtaJob(String workspaceId, List<DeviceFirmwareUpgradeDTO> upgradeDTOS) {
List<DeviceOtaCreateParam> deviceOtaFirmwares = deviceFirmwareService.getDeviceOtaFirmware(upgradeDTOS);
if (deviceOtaFirmwares.isEmpty()) {
return ResponseResult.error();
}
DeviceOtaCreateParam deviceOtaFirmware = deviceOtaFirmwares.get(0);
List<DeviceDTO> devices = getDevicesByParams(DeviceQueryParam.builder().childSn(deviceOtaFirmware.getSn()).build());
String gatewaySn = devices.isEmpty() ? deviceOtaFirmware.getSn() : devices.get(0).getDeviceSn();
String topic = THING_MODEL_PRE + PRODUCT + gatewaySn + SERVICES_SUF;
// The bids in the progress messages reported subsequently are the same.
String bid = UUID.randomUUID().toString();
Optional<ServiceReply> serviceReplyOpt = messageSender.publishWithReply(
topic, CommonTopicResponse.<Map<String, List<DeviceOtaCreateParam>>>builder()
.tid(UUID.randomUUID().toString())
.bid(bid)
.timestamp(System.currentTimeMillis())
.method(ServicesMethodEnum.OTA_CREATE.getMethod())
.data(Map.of(MapKeyConst.DEVICES, deviceOtaFirmwares))
.build());
if (serviceReplyOpt.isEmpty()) {
return ResponseResult.error("No message reply received.");
}
ServiceReply serviceReply = serviceReplyOpt.get();
if (serviceReply.getResult() != ResponseResult.CODE_SUCCESS) {
return ResponseResult.error(serviceReply.getResult(), "Firmware Error Code: " + serviceReply.getResult());
}
if (ServicesMethodEnum.OTA_CREATE.getProgress()) {
// Record the device state that needs to be updated.
deviceOtaFirmwares.forEach(deviceOta -> redisOps.setWithExpire(
RedisConst.FIRMWARE_UPGRADING_PREFIX + deviceOta.getSn(),
bid,
RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND));
}
return ResponseResult.success();
}
/** /**
* Convert device data transfer object into database entity object. * Convert device data transfer object into database entity object.
* @param dto * @param dto
@ -854,6 +933,8 @@ public class DeviceServiceImpl implements IDeviceService {
.childSn(dto.getChildDeviceSn()) .childSn(dto.getChildDeviceSn())
.domain(StringUtils.hasText(dto.getDomain()) ? DeviceDomainEnum.getVal(dto.getDomain()) : null) .domain(StringUtils.hasText(dto.getDomain()) ? DeviceDomainEnum.getVal(dto.getDomain()) : null)
.firmwareVersion(dto.getFirmwareVersion()) .firmwareVersion(dto.getFirmwareVersion())
.compatibleStatus(dto.getFirmwareStatus() == null ? null :
DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE != DeviceFirmwareStatusEnum.find(dto.getFirmwareStatus()))
.build(); .build();
} }

16
src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java

@ -5,6 +5,7 @@ import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.CommonTopicResponse; import com.dji.sample.component.mqtt.model.CommonTopicResponse;
import com.dji.sample.component.mqtt.model.ServiceReply; import com.dji.sample.component.mqtt.model.ServiceReply;
import com.dji.sample.component.mqtt.model.ServicesMethodEnum; import com.dji.sample.component.mqtt.model.ServicesMethodEnum;
import com.dji.sample.component.mqtt.model.StateDataEnum;
import com.dji.sample.component.mqtt.service.IMessageSenderService; import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.redis.RedisConst; import com.dji.sample.component.redis.RedisConst;
import com.dji.sample.component.redis.RedisOpsUtils; import com.dji.sample.component.redis.RedisOpsUtils;
@ -25,10 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -80,11 +78,17 @@ public class LiveStreamServiceImpl implements ILiveStreamService {
} }
@Override @Override
public void saveLiveCapacity(LiveCapacityReceiver liveCapacityReceiver) { public void saveLiveCapacity(LiveCapacityReceiver liveCapacityReceiver, Long timestamp) {
// Solve timing problems
for (CapacityDeviceReceiver capacityDeviceReceiver : liveCapacityReceiver.getDeviceList()) { for (CapacityDeviceReceiver capacityDeviceReceiver : liveCapacityReceiver.getDeviceList()) {
long last = (long) Objects.requireNonNullElse(
redisOps.get(StateDataEnum.LIVE_CAPACITY + RedisConst.DELIMITER + capacityDeviceReceiver.getSn()), 0L);
if (last > timestamp) {
return;
}
capacityCameraService.saveCapacityCameraReceiverList( capacityCameraService.saveCapacityCameraReceiverList(
capacityDeviceReceiver.getCameraList(), capacityDeviceReceiver.getCameraList(),
capacityDeviceReceiver.getSn()); capacityDeviceReceiver.getSn(), timestamp);
} }
} }

108
src/main/java/com/dji/sample/manage/service/impl/LogsFileIndexServiceImpl.java

@ -0,0 +1,108 @@
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.dji.sample.manage.dao.ILogsFileIndexMapper;
import com.dji.sample.manage.model.dto.LogsFileDTO;
import com.dji.sample.manage.model.entity.LogsFileIndexEntity;
import com.dji.sample.manage.model.receiver.LogsFile;
import com.dji.sample.manage.model.receiver.LogsFileUpload;
import com.dji.sample.manage.service.ILogsFileIndexService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* @author sean
* @version 1.2
* @date 2022/9/8
*/
@Service
@Transactional
public class LogsFileIndexServiceImpl implements ILogsFileIndexService {
@Autowired
private ILogsFileIndexMapper mapper;
@Override
public Boolean insertFileIndex(LogsFile file, String deviceSn, Integer domain, String fileId) {
if (Objects.isNull(file)) {
return false;
}
LogsFileIndexEntity entity = this.logsFile2Entity(file);
entity.setDomain(domain);
entity.setDeviceSn(deviceSn);
entity.setFileId(fileId);
return mapper.insert(entity) > 0;
}
@Override
public List<LogsFileUpload> getFileIndexByFileIds(List<LogsFileDTO> files) {
List<LogsFileUpload> list = new ArrayList<>();
files.forEach(file -> {
Optional<LogsFileUpload> fileOpt = this.getFileIndexByFileId(file.getFileId());
fileOpt.ifPresent(fileUpload -> {
fileUpload.setObjectKey(file.getStatus() ? file.getObjectKey() : "");
list.add(fileUpload);
});
});
return list;
}
@Override
public void deleteFileIndexByFileIds(List<String> fileIds) {
mapper.delete(new LambdaUpdateWrapper<LogsFileIndexEntity>()
.or(wrapper -> fileIds.forEach(fileId -> wrapper.eq(LogsFileIndexEntity::getFileId, fileId))));
}
@Override
public Optional<LogsFileUpload> getFileIndexByFileId(String fileId) {
List<LogsFileIndexEntity> logsFileIndexList = mapper.selectList(
new LambdaQueryWrapper<LogsFileIndexEntity>().eq(LogsFileIndexEntity::getFileId, fileId));
if (CollectionUtils.isEmpty(logsFileIndexList)) {
return Optional.empty();
}
LogsFileIndexEntity entity = logsFileIndexList.get(0);
List<LogsFile> logsFileList = logsFileIndexList.stream().map(this::entity2LogsFile).collect(Collectors.toList());
return Optional.of(LogsFileUpload.builder()
.deviceSn(entity.getDeviceSn())
.deviceModelDomain(String.valueOf(entity.getDomain()))
.list(logsFileList)
.fileId(fileId)
.build());
}
private LogsFile entity2LogsFile(LogsFileIndexEntity entity) {
if (Objects.isNull(entity)) {
return null;
}
return LogsFile.builder()
.bootIndex(entity.getBootIndex())
.startTime(entity.getStartTime())
.endTime(entity.getEndTime())
.size(entity.getSize())
.build();
}
private LogsFileIndexEntity logsFile2Entity(LogsFile file) {
if (Objects.isNull(file)) {
return null;
}
return LogsFileIndexEntity.builder()
.bootIndex(file.getBootIndex())
.size(file.getSize())
.startTime(file.getStartTime())
.endTime(file.getEndTime())
.build();
}
}

163
src/main/java/com/dji/sample/manage/service/impl/LogsFileServiceImpl.java

@ -0,0 +1,163 @@
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.dji.sample.component.mqtt.model.EventsResultStatusEnum;
import com.dji.sample.component.oss.model.OssConfiguration;
import com.dji.sample.component.oss.service.impl.OssServiceContext;
import com.dji.sample.manage.dao.ILogsFileMapper;
import com.dji.sample.manage.model.dto.LogsFileDTO;
import com.dji.sample.manage.model.entity.LogsFileEntity;
import com.dji.sample.manage.model.receiver.LogsExtFileReceiver;
import com.dji.sample.manage.model.receiver.LogsFile;
import com.dji.sample.manage.model.receiver.LogsFileUpload;
import com.dji.sample.manage.service.ILogsFileIndexService;
import com.dji.sample.manage.service.ILogsFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author sean
* @version 1.2
* @date 2022/9/7
*/
@Service
@Transactional
public class LogsFileServiceImpl implements ILogsFileService {
@Autowired
private ILogsFileMapper mapper;
@Autowired
private ILogsFileIndexService logsFileIndexService;
@Autowired
private OssServiceContext ossService;
@Autowired
private OssConfiguration configuration;
@Autowired
private OssServiceContext ossServiceContext;
@Override
public List<LogsFileDTO> getLogsFileInfoByLogsId(String logsId) {
return mapper.selectList(
new LambdaQueryWrapper<LogsFileEntity>()
.eq(LogsFileEntity::getLogsId, logsId)).stream()
.map(this::entity2Dto).collect(Collectors.toList());
}
private LogsFileDTO entity2Dto(LogsFileEntity entity) {
if (Objects.isNull(entity)) {
return null;
}
return LogsFileDTO.builder()
.deviceSn(entity.getDeviceSn())
.fileId(entity.getFileId())
.fingerprint(entity.getFingerprint())
.logsId(entity.getLogsId())
.name(entity.getName())
.objectKey(entity.getObjectKey())
.size(entity.getSize())
.status(entity.getStatus())
.build();
}
@Override
public List<LogsFileUpload> getLogsFileByLogsId(String logsId) {
List<LogsFileDTO> logsFiles = this.getLogsFileInfoByLogsId(logsId);
if (CollectionUtils.isEmpty(logsFiles)) {
return new ArrayList<>();
}
return logsFileIndexService.getFileIndexByFileIds(logsFiles);
}
@Override
public Boolean insertFile(LogsFileUpload file, String logsId) {
LogsFileEntity entity = LogsFileEntity.builder()
.logsId(logsId)
.fileId(UUID.randomUUID().toString())
.objectKey(file.getObjectKey())
.status(false)
.deviceSn(file.getDeviceSn())
.build();
boolean insert = mapper.insert(entity) > 0;
if (!insert) {
return false;
}
for (LogsFile logsFile : file.getList()) {
insert = logsFileIndexService.insertFileIndex(logsFile, file.getDeviceSn(), Integer.valueOf(file.getDeviceModelDomain()), entity.getFileId());
if (!insert) {
return false;
}
}
return true;
}
@Override
public void deleteFileByLogsId(String logsId) {
List<LogsFileDTO> logsFiles = this.getLogsFileInfoByLogsId(logsId);
if (CollectionUtils.isEmpty(logsFiles)) {
return;
}
mapper.delete(new LambdaUpdateWrapper<LogsFileEntity>().eq(LogsFileEntity::getLogsId, logsId));
List<String> fileIds = new ArrayList<>();
logsFiles.forEach(file -> {
if (file.getStatus()) {
ossService.deleteObject(configuration.getBucket(), file.getObjectKey());
}
fileIds.add(file.getFileId());
});
logsFileIndexService.deleteFileIndexByFileIds(fileIds);
}
@Override
public void updateFile(String logsId, LogsExtFileReceiver fileReceiver) {
List<LogsFileDTO> logsFiles = this.getLogsFileInfoByLogsId(logsId);
if (CollectionUtils.isEmpty(logsFiles)) {
return;
}
mapper.update(receiver2Entity(fileReceiver),
new LambdaUpdateWrapper<LogsFileEntity>().eq(LogsFileEntity::getLogsId, logsId)
.eq(LogsFileEntity::getDeviceSn, fileReceiver.getDeviceSn()));
}
@Override
public void updateFileUploadStatus(String logsId, Boolean isUploaded) {
mapper.update(LogsFileEntity.builder().status(isUploaded).build(),
new LambdaUpdateWrapper<LogsFileEntity>().eq(LogsFileEntity::getLogsId, logsId));
}
@Override
public URL getLogsFileUrl(String logsId, String fileId) {
LogsFileEntity logsFile = mapper.selectOne(new LambdaQueryWrapper<LogsFileEntity>()
.eq(LogsFileEntity::getLogsId, logsId).eq(LogsFileEntity::getFileId, fileId));
if (Objects.isNull(logsFile)) {
return null;
}
return ossService.getObjectUrl(configuration.getBucket(), logsFile.getObjectKey());
}
private LogsFileEntity receiver2Entity(LogsExtFileReceiver receiver) {
if (Objects.isNull(receiver)) {
return null;
}
return LogsFileEntity.builder()
.fingerprint(receiver.getFingerprint())
.size(receiver.getSize())
.status(Objects.nonNull(receiver.getProgress()) &&
EventsResultStatusEnum.OK.getDesc().equals(receiver.getProgress().getStatus()))
.name(receiver.getKey().substring(receiver.getKey().lastIndexOf("/") + 1)).build();
}
}

19
src/main/java/com/dji/sample/manage/service/impl/TopologyServiceImpl.java

@ -36,8 +36,19 @@ public class TopologyServiceImpl implements ITopologyService {
List<TopologyDTO> topologyList = new ArrayList<>(); List<TopologyDTO> topologyList = new ArrayList<>();
gatewayList.forEach(device -> { gatewayList.forEach(device -> this.getDeviceTopologyByGatewaySn(device.getDeviceSn())
.ifPresent(topologyList::add));
return topologyList;
}
public Optional<TopologyDTO> getDeviceTopologyByGatewaySn(String gatewaySn) {
Optional<DeviceDTO> dtoOptional = deviceService.getDeviceBySn(gatewaySn);
if (dtoOptional.isEmpty()) {
return Optional.empty();
}
List<TopologyDeviceDTO> parents = new ArrayList<>(); List<TopologyDeviceDTO> parents = new ArrayList<>();
DeviceDTO device = dtoOptional.get();
TopologyDeviceDTO gateway = deviceService.deviceConvertToTopologyDTO(device); TopologyDeviceDTO gateway = deviceService.deviceConvertToTopologyDTO(device);
parents.add(gateway); parents.add(gateway);
@ -46,10 +57,6 @@ public class TopologyServiceImpl implements ITopologyService {
List<TopologyDeviceDTO> deviceTopoList = new ArrayList<>(); List<TopologyDeviceDTO> deviceTopoList = new ArrayList<>();
deviceTopo.ifPresent(deviceTopoList::add); deviceTopo.ifPresent(deviceTopoList::add);
topologyList.add(TopologyDTO.builder().parents(parents).hosts(deviceTopoList).build()); return Optional.ofNullable(TopologyDTO.builder().parents(parents).hosts(deviceTopoList).build());
});
return topologyList;
} }
} }

2
src/main/java/com/dji/sample/map/service/impl/GroupElementServiceImpl.java

@ -193,7 +193,7 @@ public class GroupElementServiceImpl implements IGroupElementService {
groupElement.setElementType(ElementTypeEnum.findVal(elementUpdate.getContent().getGeometry().getType())); groupElement.setElementType(ElementTypeEnum.findVal(elementUpdate.getContent().getGeometry().getType()));
groupElement.setColor(elementUpdate.getContent().getProperties().getColor()); groupElement.setColor(elementUpdate.getContent().getProperties().getColor());
boolean clampToGround = elementUpdate.getContent().getProperties().getClampToGround(); Boolean clampToGround = elementUpdate.getContent().getProperties().getClampToGround();
groupElement.setClampToGround(clampToGround); groupElement.setClampToGround(clampToGround);
} }
} }

10
src/main/java/com/dji/sample/media/controller/FileController.java

@ -37,18 +37,18 @@ public class FileController {
} }
/** /**
* Query the download address of the file according to the media file fingerprint, * Query the download address of the file according to the media file id,
* and redirect to this address directly for download. * and redirect to this address directly for download.
* @param workspaceId * @param workspaceId
* @param fingerprint * @param fileId
* @param response * @param response
*/ */
@GetMapping("/{workspace_id}/file/{fingerprint}/url") @GetMapping("/{workspace_id}/file/{file_id}/url")
public void getFileUrl(@PathVariable(name = "workspace_id") String workspaceId, public void getFileUrl(@PathVariable(name = "workspace_id") String workspaceId,
@PathVariable String fingerprint, HttpServletResponse response) { @PathVariable(name = "file_id") String fileId, HttpServletResponse response) {
try { try {
URL url = fileService.getObjectUrl(workspaceId, fingerprint); URL url = fileService.getObjectUrl(workspaceId, fileId);
response.sendRedirect(url.toString()); response.sendRedirect(url.toString());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

8
src/main/java/com/dji/sample/media/model/CredentialsDTO.java

@ -21,11 +21,11 @@ public class CredentialsDTO {
private String accessKeySecret; private String accessKeySecret;
private Integer expire; private Long expire;
private String securityToken; private String securityToken;
public CredentialsDTO(Credentials credentials, int expire) { public CredentialsDTO(Credentials credentials, long expire) {
this.accessKeyId = credentials.accessKey(); this.accessKeyId = credentials.accessKey();
this.accessKeySecret = credentials.secretKey(); this.accessKeySecret = credentials.secretKey();
this.securityToken = credentials.sessionToken(); this.securityToken = credentials.sessionToken();
@ -36,13 +36,13 @@ public class CredentialsDTO {
this.accessKeyId = credentials.getAccessKeyId(); this.accessKeyId = credentials.getAccessKeyId();
this.accessKeySecret = credentials.getAccessKeySecret(); this.accessKeySecret = credentials.getAccessKeySecret();
this.securityToken = credentials.getSecurityToken(); this.securityToken = credentials.getSecurityToken();
this.expire = Math.toIntExact(expire); this.expire = expire;
} }
public CredentialsDTO(com.amazonaws.services.securitytoken.model.Credentials credentials) { public CredentialsDTO(com.amazonaws.services.securitytoken.model.Credentials credentials) {
this.accessKeyId = credentials.getAccessKeyId(); this.accessKeyId = credentials.getAccessKeyId();
this.accessKeySecret = credentials.getSecretAccessKey(); this.accessKeySecret = credentials.getSecretAccessKey();
this.securityToken = credentials.getSessionToken(); this.securityToken = credentials.getSessionToken();
this.expire = Math.toIntExact((credentials.getExpiration().getTime() - System.currentTimeMillis()) / 1000); this.expire = (credentials.getExpiration().getTime() - System.currentTimeMillis()) / 1000;
} }
} }

2
src/main/java/com/dji/sample/media/model/MediaFileDTO.java

@ -18,6 +18,8 @@ import java.time.LocalDateTime;
@AllArgsConstructor @AllArgsConstructor
public class MediaFileDTO { public class MediaFileDTO {
private String fileId;
private String fileName; private String fileName;
private String filePath; private String filePath;

3
src/main/java/com/dji/sample/media/model/MediaFileEntity.java

@ -23,6 +23,9 @@ public class MediaFileEntity implements Serializable {
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Integer id; private Integer id;
@TableField("file_id")
private String fileId;
@TableField("file_name") @TableField("file_name")
private String fileName; private String fileName;

4
src/main/java/com/dji/sample/media/service/IFileService.java

@ -49,8 +49,8 @@ public interface IFileService {
/** /**
* Get the download address of the file. * Get the download address of the file.
* @param workspaceId * @param workspaceId
* @param fingerprint * @param fileId
* @return * @return
*/ */
URL getObjectUrl(String workspaceId, String fingerprint); URL getObjectUrl(String workspaceId, String fileId);
} }

14
src/main/java/com/dji/sample/media/service/impl/FileServiceImpl.java

@ -24,6 +24,7 @@ import java.time.ZoneId;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -54,6 +55,13 @@ public class FileServiceImpl implements IFileService {
return Optional.ofNullable(fileEntity); return Optional.ofNullable(fileEntity);
} }
private Optional<MediaFileEntity> getMediaByFileId(String workspaceId, String fileId) {
MediaFileEntity fileEntity = mapper.selectOne(new LambdaQueryWrapper<MediaFileEntity>()
.eq(MediaFileEntity::getWorkspaceId, workspaceId)
.eq(MediaFileEntity::getFileId, fileId));
return Optional.ofNullable(fileEntity);
}
@Override @Override
public Boolean checkExist(String workspaceId, String fingerprint) { public Boolean checkExist(String workspaceId, String fingerprint) {
return this.getMediaByFingerprint(workspaceId, fingerprint).isPresent(); return this.getMediaByFingerprint(workspaceId, fingerprint).isPresent();
@ -63,6 +71,7 @@ public class FileServiceImpl implements IFileService {
public Integer saveFile(String workspaceId, FileUploadDTO file) { public Integer saveFile(String workspaceId, FileUploadDTO file) {
MediaFileEntity fileEntity = this.fileUploadConvertToEntity(file); MediaFileEntity fileEntity = this.fileUploadConvertToEntity(file);
fileEntity.setWorkspaceId(workspaceId); fileEntity.setWorkspaceId(workspaceId);
fileEntity.setFileId(UUID.randomUUID().toString());
return mapper.insert(fileEntity); return mapper.insert(fileEntity);
} }
@ -90,8 +99,8 @@ public class FileServiceImpl implements IFileService {
} }
@Override @Override
public URL getObjectUrl(String workspaceId, String fingerprint) { public URL getObjectUrl(String workspaceId, String fileId) {
Optional<MediaFileEntity> mediaFileOpt = getMediaByFingerprint(workspaceId, fingerprint); Optional<MediaFileEntity> mediaFileOpt = getMediaByFileId(workspaceId, fileId);
if (mediaFileOpt.isEmpty()) { if (mediaFileOpt.isEmpty()) {
throw new IllegalArgumentException("{} doesn't exist."); throw new IllegalArgumentException("{} doesn't exist.");
} }
@ -140,6 +149,7 @@ public class FileServiceImpl implements IFileService {
if (entity != null) { if (entity != null) {
builder.fileName(entity.getFileName()) builder.fileName(entity.getFileName())
.fileId(entity.getFileId())
.filePath(entity.getFilePath()) .filePath(entity.getFilePath())
.isOriginal(entity.getIsOriginal()) .isOriginal(entity.getIsOriginal())
.fingerprint(entity.getFingerprint()) .fingerprint(entity.getFingerprint())

17
src/main/resources/application.yml

@ -88,17 +88,16 @@ oss:
# bucket: cloudapi-bucket # bucket: cloudapi-bucket
# object-dir-prefix: wayline # object-dir-prefix: wayline
# MinIO is temporarily unavailable.
#oss: #oss:
# enable: false # enable: true
# provider: minio # provider: minio
# endpoint: # endpoint: http://192.168.1.1:9000
# access-key: # access-key: minioadmin
# secret-key: # secret-key: minioadmin
# bucket: # bucket: cloud-bucket
# expire: # expire: 3600
# region: # region: us-east-1
# object-dir-prefix: # object-dir-prefix: wayline
logging: logging:
level: level:

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save