91 files modified
82 files added
| | |
| | | |
| | | ## Docker |
| | | |
| | | If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker_1.0.0.zip) |
| | | If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker.zip) |
| | | |
| | | ## Usage |
| | | |
| | | For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/cn/document/209883f1-f2ad-406e-b99c-be7498df7f10). |
| | | For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/doc/cloud-api-tutorial/cn/). |
| | | |
| | | ## Latest Release |
| | | |
| | | Cloud API 1.0.0 was released on 21 March 2022. For more information, please visit the [Release Note](https://developer.dji.com/cn/document/87026f9b-e906-4809-9aba-870f569061b5). |
| | | Cloud API 1.1.0 was released on 22 July 2022. For more information, please visit the [Release Note](https://developer.dji.com/doc/cloud-api-tutorial/cn/). |
| | | |
| | | ## License |
| | | |
| | |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"username\": \"adminPC\",\r\n \"password\": \"adminPC\"\r\n}", |
| | | "raw": "{\r\n \"username\": \"adminPC\",\r\n \"password\": \"adminPC\",\r\n \"flag\": 1\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | |
| | | "method": "GET", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/devices/devices", |
| | | "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "devices", |
| | | "{{workspace_id}}", |
| | | "devices" |
| | | ] |
| | | } |
| | |
| | | }, |
| | | { |
| | | "name": "Start Livestream", |
| | | "event": [ |
| | | { |
| | | "listen": "test", |
| | | "script": { |
| | | "exec": [ |
| | | "" |
| | | ], |
| | | "type": "text/javascript" |
| | | } |
| | | } |
| | | ], |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"url_type\": 0,\r\n \"url\": \"\",\r\n \"video_id\": \"\",\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\": \"1581F4BN/52-0-0/zoom-0\",\r\n \"video_quality\": 0\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"video_id\": \"\"\r\n}", |
| | | "raw": "{\r\n \"video_id\": \"1581F4BNDQ/39-0-7/normal-0\"\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Get All Users Info", |
| | | "request": { |
| | | "method": "GET", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/users/{{workspace_id}}/users?page=1&page_size=10", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "users", |
| | | "{{workspace_id}}", |
| | | "users" |
| | | ], |
| | | "query": [ |
| | | { |
| | | "key": "page", |
| | | "value": "1" |
| | | }, |
| | | { |
| | | "key": "page_size", |
| | | "value": "10" |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Update User Info", |
| | | "request": { |
| | | "method": "PUT", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"mqtt_username\": \"admin\",\r\n \"mqtt_password\": \"admin\"\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | | } |
| | | } |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/users/{{workspace_id}}/users/a1559e7c-8dd8-4780-b952-100cc4797da2", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "users", |
| | | "{{workspace_id}}", |
| | | "users", |
| | | "a1559e7c-8dd8-4780-b952-100cc4797da2" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Bind Device", |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"user_id\": \"be7c6c3d-afe9-4be4-b9eb-c55066c0914e\",\r\n \"workspace_id\": \"e3dea0f5-37f2-4d79-ae58-490af3228069\",\r\n \"device_sn\": \"1ZMDG009\",\r\n \"child_device_sn\": \"\"\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | | } |
| | | } |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/devices/binding", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "devices", |
| | | "binding" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Get Binding Devices", |
| | | "request": { |
| | | "method": "GET", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/bound?page=1&page_size=10&domain=sub-device", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "devices", |
| | | "{{workspace_id}}", |
| | | "devices", |
| | | "bound" |
| | | ], |
| | | "query": [ |
| | | { |
| | | "key": "page", |
| | | "value": "1" |
| | | }, |
| | | { |
| | | "key": "page_size", |
| | | "value": "10" |
| | | }, |
| | | { |
| | | "key": "domain", |
| | | "value": "sub-device" |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Get Device", |
| | | "request": { |
| | | "method": "GET", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/{{device_sn}}", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "devices", |
| | | "{{workspace_id}}", |
| | | "devices", |
| | | "{{device_sn}}" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Unbind Device", |
| | | "request": { |
| | | "method": "DELETE", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{manage_version}}/devices/{{device_sn}}/unbinding", |
| | | "host": [ |
| | | "{{base_url}}{{manage_version}}" |
| | | ], |
| | | "path": [ |
| | | "devices", |
| | | "{{device_sn}}", |
| | | "unbinding" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | } |
| | | ], |
| | | "auth": { |
| | | "type": "apikey", |
| | | "apikey": [ |
| | | { |
| | | "key": "key", |
| | | "value": "x-auth-token", |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTI2OTUxOTcsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTI3ODE1OTcsImlhdCI6MTY1MjY5NTE5NywidXNlcm5hbWUiOiJhZG1pblBDIn0.BHTwW8imw5ab0GUypRyJ2gkoz5av9q99NrxoFlL53dA", |
| | | "type": "string" |
| | | }, |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM", |
| | | "key": "key", |
| | | "value": "x-auth-token", |
| | | "type": "string" |
| | | } |
| | | ] |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTMzNzI3NDUsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTM0NTkxNDUsImlhdCI6MTY1MzM3Mjc0NSwidXNlcm5hbWUiOiJhZG1pblBDIn0.Zyb_f4umcGY2-WDaQKA1LHGOs9qYfJuPc3rQeIS-4hY", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | }, |
| | | { |
| | | "name": "Check Tiny Fingerprints", |
| | | "protocolProfileBehavior": { |
| | | "disableBodyPruning": true |
| | | }, |
| | | "request": { |
| | | "method": "GET", |
| | | "method": "POST", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"tiny_fingerprints\":[\r\n \r\n ]\r\n}", |
| | | "raw": "{\r\n \"tiny_fingerprints\":[\r\n \"4a3a67101ffb81d079338d4729315a8c_2022_3_3_11_38_58\",\r\n \"8e0fedb981be23dd034cf7927919da51_2022_3_3_11_45_26\"\r\n ]\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | |
| | | } |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{media_version}}/workspaces/{{workspace_id}}/files/tiny-fingerprints?tiny_fingerprint=045040860fb014916c81082407e9ff8b_2021_12_2_16_17_8,922aca3dee753f2f9ee1ad0565967334_2021_12_8_22_13_12", |
| | | "raw": "{{base_url}}{{media_version}}/workspaces/{{workspace_id}}/files/tiny-fingerprints", |
| | | "host": [ |
| | | "{{base_url}}{{media_version}}" |
| | | ], |
| | |
| | | "{{workspace_id}}", |
| | | "files", |
| | | "tiny-fingerprints" |
| | | ], |
| | | "query": [ |
| | | { |
| | | "key": "tiny_fingerprint", |
| | | "value": "045040860fb014916c81082407e9ff8b_2021_12_2_16_17_8,922aca3dee753f2f9ee1ad0565967334_2021_12_8_22_13_12" |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTgzOTIyNzksImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTg0Nzg2NzksImlhdCI6MTY1ODM5MjI3OSwidXNlcm5hbWUiOiJhZG1pblBDIn0.ErClyQS1YzoQVBcLYxpFEiyFTb1L-eg2-vsudlL9WJU", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTI2OTUxOTcsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTI3ODE1OTcsImlhdCI6MTY1MjY5NTE5NywidXNlcm5hbWUiOiJhZG1pblBDIn0.BHTwW8imw5ab0GUypRyJ2gkoz5av9q99NrxoFlL53dA", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTU0NDk2MDIsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTU1MzYwMDIsImlhdCI6MTY1NTQ0OTYwMiwidXNlcm5hbWUiOiJhZG1pblBDIn0.YZWHJ65Pl_DT2Ampxk0WC01KD_fNTm_rYVUBIHAZD-4", |
| | | "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": [ |
| | | "" |
| | | ] |
| | | } |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | "name": "job", |
| | | "item": [ |
| | | { |
| | | "name": "Create Flight Job", |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "body": { |
| | | "mode": "raw", |
| | | "raw": "{\r\n \"name\": \"\",\r\n \"fild_id\": \"\",\r\n \"dock_sn\": \"\",\r\n \"type\": \"\",\r\n \"immediate\": false\r\n}", |
| | | "options": { |
| | | "raw": { |
| | | "language": "json" |
| | | } |
| | | } |
| | | }, |
| | | "url": { |
| | | "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/flight-tasks", |
| | | "host": [ |
| | | "{{base_url}}{{wayline_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "flight-tasks" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Get Jobs", |
| | | "request": { |
| | | "method": "GET", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs?page=1&pageSize=10", |
| | | "host": [ |
| | | "{{base_url}}{{wayline_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "jobs" |
| | | ], |
| | | "query": [ |
| | | { |
| | | "key": "page", |
| | | "value": "1" |
| | | }, |
| | | { |
| | | "key": "pageSize", |
| | | "value": "10" |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | }, |
| | | { |
| | | "name": "Execute Job", |
| | | "request": { |
| | | "method": "POST", |
| | | "header": [], |
| | | "url": { |
| | | "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs/{{plan_id}}", |
| | | "host": [ |
| | | "{{base_url}}{{wayline_version}}" |
| | | ], |
| | | "path": [ |
| | | "workspaces", |
| | | "{{workspace_id}}", |
| | | "jobs", |
| | | "{{plan_id}}" |
| | | ] |
| | | } |
| | | }, |
| | | "response": [] |
| | | } |
| | | ], |
| | | "auth": { |
| | | "type": "apikey", |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTU4OTA5NTQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTU5NzczNTQsImlhdCI6MTY1NTg5MDk1NCwidXNlcm5hbWUiOiJhZG1pblBDIn0.fd0iIzCd71LDUE6ixexUJvo-YqtnSCqRx-790snCyBI", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | "apikey": [ |
| | | { |
| | | "key": "value", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Mzg5MzY2OTEsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2MzkwMjMwOTEsImlhdCI6MTYzODkzNjY5MSwidXNlcm5hbWUiOiJhZG1pblBDIn0.W_v88rbhVKivl61MnJ0Cz_0Eq6Gw0RotiHCdLj0UPSQ", |
| | | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTA0MjY3MzAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTA1MTMxMzAsImlhdCI6MTY1MDQyNjczMCwidXNlcm5hbWUiOiJhZG1pblBDIn0.-FBpi0ktuZ68jV6-HQ7mwm8iC07YH-Hw2aRiREzJ8hs", |
| | | "type": "string" |
| | | }, |
| | | { |
| | |
| | | "values": [ |
| | | { |
| | | "key": "ip", |
| | | "value": "192.168.1.1", |
| | | "value": "localhost", |
| | | "type": "default", |
| | | "enabled": true |
| | | }, |
| | |
| | | } |
| | | ], |
| | | "_postman_variable_scope": "environment", |
| | | "_postman_exported_at": "2022-03-29T03:52:14.600Z", |
| | | "_postman_exported_using": "Postman/9.7.1" |
| | | "_postman_exported_at": "2022-07-21T08:35:48.441Z", |
| | | "_postman_exported_using": "Postman/9.19.0" |
| | | } |
| | |
| | | |
| | | <groupId>com.dji</groupId> |
| | | <artifactId>cloud-api-sample</artifactId> |
| | | <version>1.0.0</version> |
| | | <version>1.1.0</version> |
| | | <name>cloud-api-sample</name> |
| | | |
| | | <properties> |
| | |
| | | <version>${glassfish-jaxb.version}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-data-redis</artifactId> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>org.apache.commons</groupId> |
| | | <artifactId>commons-pool2</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.amazonaws</groupId> |
| | | <artifactId>aws-java-sdk-s3</artifactId> |
| | | <version>1.12.200</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.amazonaws</groupId> |
| | | <artifactId>aws-java-sdk-sts</artifactId> |
| | | <version>1.12.200</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>com.fasterxml.jackson.datatype</groupId> |
| | | <artifactId>jackson-datatype-jsr310</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-aop</artifactId> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <build> |
| | |
| | | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; |
| | | |
| | | |
| | | # manage_camera_video |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_camera_video`; |
| | | |
| | | CREATE TABLE `manage_camera_video` ( |
| | | `id` int unsigned NOT NULL AUTO_INCREMENT, |
| | | `camera_id` int NOT NULL, |
| | | `video_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `video_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | PRIMARY KEY (`id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | |
| | | # manage_capacity_camera |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_capacity_camera`; |
| | | |
| | | CREATE TABLE `manage_capacity_camera` ( |
| | | `id` int unsigned NOT NULL AUTO_INCREMENT, |
| | | `device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
| | | `description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `camera_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `coexist_video_number_max` int NOT NULL, |
| | | `available_video_number` int NOT NULL, |
| | | PRIMARY KEY (`id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | |
| | | # manage_device |
| | | # manage_device |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_device`; |
| | |
| | | `id` int unsigned NOT NULL AUTO_INCREMENT, |
| | | `device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `device_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
| | | `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `device_type` smallint NOT NULL, |
| | | `sub_type` smallint NOT NULL, |
| | | `domain` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `version` smallint NOT NULL, |
| | | `device_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `child_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `nickname` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `device_type` smallint NOT NULL DEFAULT '-1', |
| | | `sub_type` smallint NOT NULL DEFAULT '-1', |
| | | `domain` smallint NOT NULL DEFAULT '-1', |
| | | `firmware_version` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `version` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `device_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `child_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL, |
| | | `device_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `url_normal` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `url_select` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `bound_time` bigint DEFAULT NULL, |
| | | `bound_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0:bund; 1:not bound', |
| | | `login_time` bigint DEFAULT NULL, |
| | | `device_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `url_normal` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `url_select` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `product_sn_UNIQUE` (`device_sn`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | |
| | | # manage_device_dictionary |
| | | # manage_device_dictionary |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_device_dictionary`; |
| | |
| | | (14,1,165,0,'DJI Dock Camera',NULL), |
| | | (15,1,90742,0,'L1',NULL), |
| | | (16,2,56,0,'DJI Smart Controller','Remote control for M300'), |
| | | (17,2,119,0,'Matrice 30 Smart Controller','Remote control for M30'), |
| | | (18,3,1,0,'DJI Dock','DJI Airport'); |
| | | |
| | | (17,2,119,0,'DJI RC Plus','Remote control for M30'), |
| | | (18,3,1,0,'DJI Dock',''); |
| | | |
| | | /*!40000 ALTER TABLE `manage_device_dictionary` ENABLE KEYS */; |
| | | UNLOCK TABLES; |
| | | |
| | | |
| | | # manage_device_payload |
| | | # manage_device_hms |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_device_hms`; |
| | | |
| | | CREATE TABLE `manage_device_hms` ( |
| | | `id` int unsigned NOT NULL AUTO_INCREMENT, |
| | | `hms_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `tid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `bid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `sn` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `level` smallint NOT NULL, |
| | | `module` tinyint NOT NULL, |
| | | `hms_key` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `message_zh` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `message_en` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL, |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `UNIQUE_hms_id` (`hms_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | # manage_device_payload |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_device_payload`; |
| | |
| | | `payload_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
| | | `payload_type` smallint NOT NULL, |
| | | `sub_type` smallint NOT NULL, |
| | | `version` smallint DEFAULT NULL, |
| | | `firmware_version` varchar(32) DEFAULT NULL, |
| | | `payload_index` smallint NOT NULL, |
| | | `device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `payload_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | |
| | | |
| | | |
| | | |
| | | # manage_user |
| | | # manage_user |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_user`; |
| | |
| | | `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `workspace_id` int NOT NULL, |
| | | `workspace_id` varchar(64) NOT NULL DEFAULT '', |
| | | `user_type` smallint NOT NULL, |
| | | `mqtt_username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `mqtt_password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | |
| | | |
| | | INSERT INTO `manage_user` (`id`, `user_id`, `username`, `password`, `workspace_id`, `user_type`, `mqtt_username`, `mqtt_password`, `create_time`, `update_time`) |
| | | VALUES |
| | | (1,'a1559e7c-8dd8-4780-b952-100cc4797da2','adminPC','adminPC',1,1,'admin','admin',1634898410751,1634898410751), |
| | | (2,'be7c6c3d-afe9-4be4-b9eb-c55066c0914e','pilot','pilot123',1,2,'pilot','pilot123',1634898410751,1634898410751); |
| | | (1,'a1559e7c-8dd8-4780-b952-100cc4797da2','adminPC','adminPC','e3dea0f5-37f2-4d79-ae58-490af3228069',1,'admin','admin',1634898410751,1650880112310), |
| | | (2,'be7c6c3d-afe9-4be4-b9eb-c55066c0914e','pilot','pilot123','e3dea0f5-37f2-4d79-ae58-490af3228069',2,'pilot','pilot123',1634898410751,1634898410751); |
| | | |
| | | /*!40000 ALTER TABLE `manage_user` ENABLE KEYS */; |
| | | UNLOCK TABLES; |
| | | |
| | | |
| | | # manage_workspace |
| | | # manage_workspace |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `manage_workspace`; |
| | |
| | | `platform_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL, |
| | | `bind_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `workspace_id_UNIQUE` (`workspace_id`) |
| | | UNIQUE KEY `workspace_id_UNIQUE` (`workspace_id`), |
| | | UNIQUE KEY `bind_code_UNIQUE` (`bind_code`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | LOCK TABLES `manage_workspace` WRITE; |
| | | /*!40000 ALTER TABLE `manage_workspace` DISABLE KEYS */; |
| | | |
| | | INSERT INTO `manage_workspace` (`id`, `workspace_id`, `workspace_name`, `workspace_desc`, `platform_name`, `create_time`, `update_time`) |
| | | INSERT INTO `manage_workspace` (`id`, `workspace_id`, `workspace_name`, `workspace_desc`, `platform_name`, `create_time`, `update_time`, `bind_code`) |
| | | VALUES |
| | | (1,'e3dea0f5-37f2-4d79-ae58-490af3228069','Test Group One','Cloud Sample Test Platform','Cloud Api Platform',1634898410751,1634898410751); |
| | | (1,'e3dea0f5-37f2-4d79-ae58-490af3228069','Test Group One','Cloud Sample Test Platform','Cloud Api Platform',1634898410751,1634898410751,'qwe'); |
| | | |
| | | /*!40000 ALTER TABLE `manage_workspace` ENABLE KEYS */; |
| | | UNLOCK TABLES; |
| | | |
| | | |
| | | # map_element_coordinate |
| | | # map_element_coordinate |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `map_element_coordinate`; |
| | |
| | | |
| | | |
| | | |
| | | # map_group |
| | | # map_group |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `map_group`; |
| | |
| | | UNLOCK TABLES; |
| | | |
| | | |
| | | # map_group_element |
| | | # map_group_element |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `map_group_element`; |
| | |
| | | |
| | | |
| | | |
| | | # media_file |
| | | # media_file |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `media_file`; |
| | |
| | | `file_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `file_path` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `fingerprint` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `fingerprint` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `tinny_fingerprint` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `object_key` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `sub_file_type` int NOT NULL, |
| | | `object_key` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `sub_file_type` int DEFAULT NULL, |
| | | `is_original` tinyint(1) NOT NULL, |
| | | `drone` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
| | | `payload` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
| | | `job_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '', |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL, |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `fingerprint_UNIQUE` (`fingerprint`) |
| | | PRIMARY KEY (`id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | |
| | | # wayline_file |
| | | # wayline_file |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `wayline_file`; |
| | |
| | | `drone_model_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `payload_model_keys` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
| | | `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `sign` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'MD5', |
| | | `favorited` tinyint(1) NOT NULL DEFAULT '0', |
| | | `template_types` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `object_key` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL COMMENT 'required, can not modify.', |
| | | `update_time` bigint NOT NULL COMMENT 'required, can''t modify.', |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `wayline_id_UNIQUE` (`wayline_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | |
| | | # wayline_job |
| | | # ------------------------------------------------------------ |
| | | |
| | | DROP TABLE IF EXISTS `wayline_job`; |
| | | |
| | | CREATE TABLE `wayline_job` ( |
| | | `id` int unsigned NOT NULL AUTO_INCREMENT, |
| | | `job_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
| | | `name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `file_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `dock_sn` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `workspace_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `bid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `type` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
| | | `create_time` bigint NOT NULL, |
| | | `update_time` bigint NOT NULL, |
| | | PRIMARY KEY (`id`), |
| | | UNIQUE KEY `job_id_UNIQUE` (`job_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
| | | |
| | | |
| | | |
| | | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; |
| | | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; |
| | |
| | | @MapperScan("com.dji.sample.*.dao") |
| | | @SpringBootApplication |
| | | @EnableScheduling |
| | | //@EnableConfigurationProperties(OssConfiguration.class) |
| | | public class CloudApiSampleApplication { |
| | | |
| | | public static void main(String[] args) { |
| | |
| | | */ |
| | | public enum CommonErrorEnum implements IErrorInfo { |
| | | |
| | | ILLEGAL_ARGUMENT(200001, "illegal argument"), |
| | | |
| | | GET_ORGANIZATION_FAILED(210230, "Failed to get organization."), |
| | | |
| | | DEVICE_BINDING_FAILED(210231, "Failed to bind device."), |
| | | |
| | | NON_REPEATABLE_BINDING(210232, "The device has been bound to another organization and can't be bound repeatedly."), |
| | | |
| | | GET_DEVICE_BINDING_STATUS_FAILED(210233, "Failed to get device binding status."), |
| | | |
| | | SYSTEM_ERROR(600500, "system error"), |
| | | |
| | | SECRET_INVALID(600100, "secret invalid"), |
| New file |
| | |
| | | package com.dji.sample.common.error; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/25 |
| | | */ |
| | | public enum StorageErrorEnum implements IErrorInfo { |
| | | |
| | | GENERATE_CREDENTIALS_ERROR(217001, "Failed to generate temporary credentials."), |
| | | |
| | | NO_BUCKET(217002, "The bucket does not exist."), |
| | | |
| | | ILLEGAL_PATH_FORMAT(217006, "Illegal path format."), |
| | | |
| | | FILE_CREATION_FAILED(217007, "File creation failed."), |
| | | |
| | | DIR_CREATION_FAILED(217008, "Directory creation failed"); |
| | | |
| | | private String msg; |
| | | |
| | | private int code; |
| | | |
| | | StorageErrorEnum(int code, String msg) { |
| | | this.msg = msg; |
| | | this.code = code; |
| | | } |
| | | |
| | | @Override |
| | | public String getErrorMsg() { |
| | | return msg; |
| | | } |
| | | |
| | | @Override |
| | | public Integer getErrorCode() { |
| | | return code; |
| | | } |
| | | } |
| | |
| | | JwtUtil.algorithm = Algorithm.HMAC256(secret); |
| | | } |
| | | |
| | | private JwtUtil() { |
| | | |
| | | } |
| | | |
| | | /** |
| | | * Create a token based on custom information. |
| | | * @param claims custom information |
| | |
| | | package com.dji.sample.component; |
| | | |
| | | import com.dji.sample.manage.model.DeviceStatusManager; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.param.DeviceQueryParam; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.CommandLineRunner; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | /** |
| | | * Subscribe to the devices that exist in the database when the program starts, |
| | | * Subscribe to the devices that exist in the redis when the program starts, |
| | | * to prevent the data from being different from the pilot side due to program interruptions. |
| | | * @param args |
| | | * @throws Exception |
| | | */ |
| | | @Override |
| | | public void run(String... args) throws Exception { |
| | | deviceService.getDevicesByParams(DeviceQueryParam.builder().build()) |
| | | .forEach(device -> { |
| | | deviceService.subscribeTopicOnline(device.getDeviceSn()); |
| | | DeviceStatusManager.STATUS_MANAGER.put( |
| | | DeviceDomainEnum.getVal(device.getDomain()) + "/" |
| | | + device.getDeviceSn(), LocalDateTime.now()); |
| | | }); |
| | | int start = RedisConst.DEVICE_ONLINE_PREFIX.length(); |
| | | |
| | | redisOps.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*") |
| | | .forEach(key -> deviceService.subscribeTopicOnline(key.substring(start))); |
| | | |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.component; |
| | | |
| | | import com.dji.sample.component.mqtt.service.IMqttTopicService; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Map; |
| | | import java.util.Arrays; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import static com.dji.sample.manage.model.DeviceStatusManager.DEFAULT_ALIVE_SECOND; |
| | | import static com.dji.sample.manage.model.DeviceStatusManager.STATUS_MANAGER; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private IMqttTopicService topicService; |
| | | |
| | | /** |
| | | * Check the status of the devices every 30 seconds. It is recommended to use cache. |
| | | */ |
| | | @Scheduled(fixedRate = 30, timeUnit = TimeUnit.SECONDS) |
| | | @Scheduled(initialDelay = 30, fixedRate = 30, timeUnit = TimeUnit.SECONDS) |
| | | private void deviceStatusListen() { |
| | | for (Map.Entry<String, LocalDateTime> entry : STATUS_MANAGER.entrySet()) { |
| | | if (entry.getValue().isAfter( |
| | | LocalDateTime.now().minusSeconds(DEFAULT_ALIVE_SECOND))) { |
| | | continue; |
| | | int start = RedisConst.DEVICE_ONLINE_PREFIX.length(); |
| | | |
| | | redisOps.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*").forEach(key -> { |
| | | long expire = redisOps.getExpire(key); |
| | | if (expire <= 30) { |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(key); |
| | | if (device.getDomain().equals(DeviceDomainEnum.SUB_DEVICE.getDesc())) { |
| | | deviceService.subDeviceOffline(key.substring(start)); |
| | | } else { |
| | | deviceService.unsubscribeTopicOffline(key.substring(start)); |
| | | deviceService.pushDeviceOfflineTopo(device.getWorkspaceId(), device.getDeviceSn()); |
| | | } |
| | | redisOps.del(key); |
| | | } |
| | | }); |
| | | |
| | | String device = entry.getKey(); |
| | | int index = device.indexOf("/"); |
| | | |
| | | STATUS_MANAGER.remove(device); |
| | | |
| | | int type = Integer.parseInt(device.substring(0, index)); |
| | | String sn = device.substring(index + 1); |
| | | // Determine whether it is a gateway device. |
| | | if (DeviceDomainEnum.GATEWAY.getVal() == type) { |
| | | deviceService.deviceOffline(sn); |
| | | deviceService.unsubscribeTopicOffline(sn); |
| | | continue; |
| | | } |
| | | |
| | | deviceService.subDeviceOffline(sn); |
| | | } |
| | | log.info("Subscriptions: {}", Arrays.toString(topicService.getSubscribedTopic())); |
| | | } |
| | | |
| | | } |
| | |
| | | import org.springframework.integration.mqtt.core.MqttPahoClientFactory; |
| | | import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; |
| | | import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.MessageChannel; |
| | | import org.springframework.messaging.MessageHandler; |
| | | |
| | |
| | | @ServiceActivator(inputChannel = ChannelName.DEFAULT) |
| | | public MessageHandler defaultInboundHandler() { |
| | | return message -> { |
| | | log.info("The default channel does not handle messages."); |
| | | log.info("The default channel does not handle messages." + |
| | | "\nTopic: " + message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC) + |
| | | "\nPayload: " + message.getPayload()); |
| | | }; |
| | | } |
| | | |
| | |
| | | |
| | | @Bean(name = ChannelName.INBOUND_OSD) |
| | | public MessageChannel osdChannel() { |
| | | return new DirectChannel(); |
| | | return new ExecutorChannel(threadPool); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.DEFAULT) |
| | |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_STATE_FIRMWARE_VERSION) |
| | | public MessageChannel stateFirmwareVersionChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_REQUESTS) |
| | | public MessageChannel requestsChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_REQUESTS_STORAGE_CONFIG_GET) |
| | | public MessageChannel requestsConfigGetChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_EVENTS) |
| | | public MessageChannel eventsChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS) |
| | | public MessageChannel eventsFlightTaskProgressChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK) |
| | | public MessageChannel eventsFileUploadCallbackChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_REQUESTS_AIRPORT_BIND_STATUS) |
| | | public MessageChannel requestsAirportBindStatusChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_GET) |
| | | public MessageChannel requestsAirportOrganizationGetChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND) |
| | | public MessageChannel requestsAirportOrganizationBindChannel() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | @Bean(name = ChannelName.INBOUND_EVENTS_HMS) |
| | | public MessageChannel eventsHms() { |
| | | return new DirectChannel(); |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2022/2/21 |
| | | */ |
| | | public abstract class AbstractStateTopicHandler { |
| | | |
| | | protected AbstractStateTopicHandler handler; |
| | | |
| | | @Autowired |
| | | protected ObjectMapper mapper; |
| | | |
| | | @Autowired |
| | | protected RedisOpsUtils redisOps; |
| | | |
| | | protected AbstractStateTopicHandler(AbstractStateTopicHandler handler) { |
| | | this.handler = handler; |
| | | } |
| | | |
| | | /** |
| | | * Passing dataNode data, using different processing methods depending on the data selection. |
| | | * @param dataNode |
| | | * @param stateReceiver |
| | | * @param sn |
| | | * @return |
| | | * @throws JsonProcessingException |
| | | */ |
| | | public abstract CommonTopicReceiver handleState(Map<String, Object> dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.EventsMethodEnum; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.integration.dsl.IntegrationFlow; |
| | | import org.springframework.integration.dsl.IntegrationFlows; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Configuration |
| | | public class EventsRouter { |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | @Bean |
| | | public IntegrationFlow eventsMethodRouterFlow() { |
| | | return IntegrationFlows |
| | | .from(ChannelName.INBOUND_EVENTS) |
| | | .<byte[], CommonTopicReceiver>transform(payload -> { |
| | | try { |
| | | return mapper.readValue(payload, CommonTopicReceiver.class); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return new CommonTopicReceiver(); |
| | | }) |
| | | .<CommonTopicReceiver, EventsMethodEnum>route( |
| | | receiver -> EventsMethodEnum.find(receiver.getMethod()), |
| | | mapping -> { |
| | | mapping.channelMapping(EventsMethodEnum.FILE_UPLOAD_CALLBACK, ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK); |
| | | 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(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.integration.annotation.Router; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.integration.router.AbstractMessageRouter; |
| | | import org.springframework.messaging.Message; |
| | | import org.springframework.messaging.MessageChannel; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import static com.dji.sample.component.mqtt.model.TopicConst.*; |
| | | |
| | | /** |
| | | * |
| | | * @author sean.zhou |
| | | * @date 2021/11/10 |
| | | * @version 0.1 |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class InboundMessageRouter extends AbstractMessageRouter { |
| | | |
| | | @Resource(name = ChannelName.INBOUND) |
| | | private MessageChannel inboundChannel; |
| | | |
| | | @Resource(name = ChannelName.INBOUND_STATUS) |
| | | private MessageChannel statusChannel; |
| | | |
| | | @Resource(name = ChannelName.INBOUND_STATE) |
| | | private MessageChannel stateChannel; |
| | | |
| | | @Resource(name = ChannelName.DEFAULT) |
| | | private MessageChannel defaultChannel; |
| | | |
| | | @Resource(name = ChannelName.INBOUND_SERVICE_REPLY) |
| | | private MessageChannel serviceReplyChannel; |
| | | |
| | | @Resource(name = ChannelName.INBOUND_OSD) |
| | | private MessageChannel osdChannel; |
| | | |
| | | @Resource(name = ChannelName.INBOUND_REQUESTS) |
| | | private MessageChannel requestsChannel; |
| | | |
| | | @Resource(name = ChannelName.INBOUND_EVENTS) |
| | | private MessageChannel eventsChannel; |
| | | |
| | | private static final Pattern PATTERN_TOPIC_STATUS = |
| | | Pattern.compile("^" + BASIC_PRE + PRODUCT + REGEX_SN + STATUS_SUF + "$"); |
| | | |
| | | private static final Pattern PATTERN_TOPIC_STATE = |
| | | Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + STATE_SUF + "$"); |
| | | |
| | | private static final Pattern PATTERN_TOPIC_SERVICE_REPLY = |
| | | Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + SERVICES_SUF + _REPLY_SUF + "$"); |
| | | |
| | | private static final Pattern PATTERN_TOPIC_OSD = |
| | | Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + OSD_SUF + "$"); |
| | | |
| | | private static final Pattern PATTERN_TOPIC_REQUESTS = |
| | | Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + REQUESTS_SUF + "$"); |
| | | |
| | | private static final Pattern PATTERN_TOPIC_EVENTS = |
| | | Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + EVENTS_SUF + "$"); |
| | | |
| | | /** |
| | | * All mqtt broker messages will arrive here before distributing them to different channels. |
| | | * @param message message from mqtt broker |
| | | * @return channel |
| | | */ |
| | | @Override |
| | | @Router(inputChannel = ChannelName.INBOUND) |
| | | protected Collection<MessageChannel> determineTargetChannels(Message<?> message) { |
| | | MessageHeaders headers = message.getHeaders(); |
| | | String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString(); |
| | | byte[] payload = (byte[])message.getPayload(); |
| | | |
| | | // osd |
| | | if (PATTERN_TOPIC_OSD.matcher(topic).matches()) { |
| | | return Collections.singleton(osdChannel); |
| | | } |
| | | |
| | | log.debug("received topic :{} \t payload :{}", topic, new String(payload)); |
| | | |
| | | // status |
| | | if (PATTERN_TOPIC_STATUS.matcher(topic).matches()) { |
| | | return Collections.singleton(statusChannel); |
| | | } |
| | | |
| | | // state |
| | | if (PATTERN_TOPIC_STATE.matcher(topic).matches()) { |
| | | return Collections.singleton(stateChannel); |
| | | } |
| | | |
| | | // services_reply |
| | | if (PATTERN_TOPIC_SERVICE_REPLY.matcher(topic).matches()) { |
| | | return Collections.singleton(serviceReplyChannel); |
| | | } |
| | | |
| | | // requests |
| | | if (PATTERN_TOPIC_REQUESTS.matcher(topic).matches()) { |
| | | return Collections.singleton(requestsChannel); |
| | | } |
| | | |
| | | // events |
| | | if (PATTERN_TOPIC_EVENTS.matcher(topic).matches()) { |
| | | return Collections.singleton(eventsChannel); |
| | | } |
| | | |
| | | return Collections.singleton(defaultChannel); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.RequestsMethodEnum; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.integration.dsl.IntegrationFlow; |
| | | import org.springframework.integration.dsl.IntegrationFlows; |
| | | |
| | | import java.io.IOException; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/25 |
| | | */ |
| | | @Configuration |
| | | public class RequestsRouter { |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | @Bean |
| | | public IntegrationFlow requestsMethodRouterFlow() { |
| | | return IntegrationFlows |
| | | .from(ChannelName.INBOUND_REQUESTS) |
| | | .<byte[], CommonTopicReceiver>transform(payload -> { |
| | | try { |
| | | return mapper.readValue(payload, CommonTopicReceiver.class); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return new CommonTopicReceiver(); |
| | | }) |
| | | .<CommonTopicReceiver, RequestsMethodEnum>route( |
| | | receiver -> RequestsMethodEnum.find(receiver.getMethod()), |
| | | mapping -> { |
| | | mapping.channelMapping(RequestsMethodEnum.STORAGE_CONFIG_GET, ChannelName.INBOUND_REQUESTS_STORAGE_CONFIG_GET); |
| | | mapping.channelMapping(RequestsMethodEnum.AIRPORT_BIND_STATUS, ChannelName.INBOUND_REQUESTS_AIRPORT_BIND_STATUS); |
| | | mapping.channelMapping(RequestsMethodEnum.AIRPORT_ORGANIZATION_GET, ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_GET); |
| | | mapping.channelMapping(RequestsMethodEnum.AIRPORT_ORGANIZATION_BIND, ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND); |
| | | mapping.channelMapping(RequestsMethodEnum.UNKNOWN, ChannelName.DEFAULT); |
| | | }) |
| | | .get(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2022/3/21 |
| | | */ |
| | | @Service |
| | | public class StateDefaultHandler extends AbstractStateTopicHandler { |
| | | |
| | | protected StateDefaultHandler() { |
| | | super(null); |
| | | } |
| | | |
| | | @Override |
| | | public CommonTopicReceiver handleState(Map<String, Object> dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException { |
| | | // If no suitable handler is found for the data, it is not processed. |
| | | return stateReceiver; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.StateDataEnum; |
| | | import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2022/2/21 |
| | | */ |
| | | @Service |
| | | public class StateDeviceBasicHandler extends AbstractStateTopicHandler { |
| | | |
| | | public StateDeviceBasicHandler(@Autowired @Qualifier("stateLiveCapacityHandler") AbstractStateTopicHandler handler) { |
| | | super(handler); |
| | | } |
| | | |
| | | @Override |
| | | public CommonTopicReceiver handleState(Map<String, Object> dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException { |
| | | // handle device basic data |
| | | if (dataNode.containsKey(StateDataEnum.PAYLOADS.getDesc())) { |
| | | DeviceBasicReceiver data = mapper.convertValue(stateReceiver.getData(), DeviceBasicReceiver.class); |
| | | data.setDeviceSn(sn); |
| | | data.getPayloads().forEach(payload -> payload.setDeviceSn(sn)); |
| | | |
| | | stateReceiver.setData(data); |
| | | return stateReceiver; |
| | | } |
| | | return handler.handleState(dataNode, stateReceiver, sn); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.StateDataEnum; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.enums.PayloadModelEnum; |
| | | import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2022/2/21 |
| | | */ |
| | | @Service |
| | | public class StateFirmwareVersionHandler extends AbstractStateTopicHandler { |
| | | |
| | | protected StateFirmwareVersionHandler(@Autowired @Qualifier("stateDefaultHandler") AbstractStateTopicHandler handler) { |
| | | super(handler); |
| | | } |
| | | |
| | | @Override |
| | | public CommonTopicReceiver handleState(Map<String, Object> dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException { |
| | | // Parse the firmware version of the device. |
| | | if (dataNode.containsKey(StateDataEnum.FIRMWARE_VERSION.getDesc())) { |
| | | FirmwareVersionReceiver firmware = mapper.convertValue(dataNode, FirmwareVersionReceiver.class); |
| | | firmware.setSn(sn); |
| | | firmware.setDomain(DeviceDomainEnum.SUB_DEVICE); |
| | | stateReceiver.setData(firmware); |
| | | return stateReceiver; |
| | | } |
| | | |
| | | // Parse the firmware version of the payload. |
| | | List<String> payloads = PayloadModelEnum.getAllModel(); |
| | | long count = dataNode.keySet() |
| | | .stream() |
| | | .map(key -> { |
| | | int end = key.indexOf("-"); |
| | | return end == -1 ? key : key.substring(0, end); |
| | | }) |
| | | .filter(payloads::contains) |
| | | .count(); |
| | | if (count > 0) { |
| | | FirmwareVersionReceiver firmware = FirmwareVersionReceiver.builder() |
| | | .firmwareVersion(((Map<String, String>)(dataNode.values().iterator().next())) |
| | | .get(StateDataEnum.FIRMWARE_VERSION.getDesc())) |
| | | .sn(sn) |
| | | .domain(DeviceDomainEnum.PAYLOAD) |
| | | .build(); |
| | | stateReceiver.setData(firmware); |
| | | return stateReceiver; |
| | | } |
| | | |
| | | return handler.handleState(dataNode, stateReceiver, sn); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.StateDataEnum; |
| | | import com.dji.sample.manage.model.receiver.LiveCapacityReceiver; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2022/2/21 |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class StateLiveCapacityHandler extends AbstractStateTopicHandler { |
| | | |
| | | protected StateLiveCapacityHandler(@Autowired @Qualifier("stateFirmwareVersionHandler") AbstractStateTopicHandler handler) { |
| | | super(handler); |
| | | } |
| | | |
| | | @Override |
| | | public CommonTopicReceiver handleState(Map<String, Object> dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException { |
| | | // Determine if it is live capacity data based on name. |
| | | if (dataNode.containsKey(StateDataEnum.LIVE_CAPACITY.getDesc())) { |
| | | stateReceiver.setData(mapper.convertValue( |
| | | dataNode.get(StateDataEnum.LIVE_CAPACITY.getDesc()), |
| | | LiveCapacityReceiver.class)); |
| | | log.info("Analyze live stream capabilities."); |
| | | return stateReceiver; |
| | | } |
| | | return handler.handleState(dataNode, stateReceiver, sn); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; |
| | | import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; |
| | | import com.dji.sample.manage.model.receiver.LiveCapacityReceiver; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.integration.annotation.MessageEndpoint; |
| | | import org.springframework.integration.annotation.Router; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.annotation.Splitter; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.integration.router.MessageRouter; |
| | | import org.springframework.integration.router.PayloadTypeRouter; |
| | | import org.springframework.messaging.Message; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Map; |
| | | |
| | | import static com.dji.sample.component.mqtt.model.TopicConst.*; |
| | | |
| | | /** |
| | | * |
| | | * @author sean.zhou |
| | | * @date 2021/11/17 |
| | | * @version 0.1 |
| | | */ |
| | | @MessageEndpoint |
| | | @Slf4j |
| | | @Configuration |
| | | public class StateRouter { |
| | | |
| | | @Resource(name = "stateDeviceBasicHandler") |
| | | private AbstractStateTopicHandler handler; |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | /** |
| | | * Handles the routing of state topic messages. Depending on the data, it is assigned to different channels for handling. |
| | | * @param message |
| | | * @return |
| | | * @throws IOException |
| | | */ |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE, outputChannel = ChannelName.INBOUND_STATE_SPLITTER) |
| | | public CommonTopicReceiver<?> resolveStateData(Message<?> message) throws IOException { |
| | | byte[] payload = (byte[])message.getPayload(); |
| | | String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); |
| | | |
| | | CommonTopicReceiver stateReceiver = mapper.readValue(payload, CommonTopicReceiver.class); |
| | | // Get the sn of the topic source. |
| | | String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(), |
| | | topic.indexOf(STATE_SUF)); |
| | | |
| | | try { |
| | | Map<String, Object> data = (Map<String, Object>) (stateReceiver.getData()); |
| | | |
| | | return handler.handleState(data, stateReceiver, from); |
| | | |
| | | } catch (UnrecognizedPropertyException e) { |
| | | log.info("The {} data is not processed.", e.getPropertyName()); |
| | | } |
| | | return stateReceiver; |
| | | } |
| | | |
| | | /** |
| | | * Split the state message data to different channels for handling according to their different types. |
| | | * @param receiver state message |
| | | * @return |
| | | */ |
| | | @Splitter(inputChannel = ChannelName.INBOUND_STATE_SPLITTER, outputChannel = ChannelName.INBOUND_STATE_ROUTER) |
| | | public Collection<Object> splitState(CommonTopicReceiver receiver) { |
| | | ArrayList<Object> type = new ArrayList<>(); |
| | | type.add(receiver.getData()); |
| | | return type; |
| | | } |
| | | |
| | | @Bean |
| | | @Router(inputChannel = ChannelName.INBOUND_STATE_ROUTER) |
| | | public MessageRouter resolveStateRouter() { |
| | | PayloadTypeRouter router = new PayloadTypeRouter(); |
| | | // Channel mapping for basic data. |
| | | router.setChannelMapping(DeviceBasicReceiver.class.getName(), |
| | | ChannelName.INBOUND_STATE_BASIC); |
| | | // Channel mapping for live streaming capabilities. |
| | | router.setChannelMapping(LiveCapacityReceiver.class.getName(), |
| | | ChannelName.INBOUND_STATE_CAPACITY); |
| | | router.setChannelMapping(FirmwareVersionReceiver.class.getName(), |
| | | ChannelName.INBOUND_STATE_FIRMWARE_VERSION); |
| | | router.setChannelMapping(Map.class.getName(), |
| | | ChannelName.DEFAULT); |
| | | return router; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.handler; |
| | | |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; |
| | | 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.MessageEndpoint; |
| | | import org.springframework.integration.annotation.Router; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.Message; |
| | | import org.springframework.util.CollectionUtils; |
| | | |
| | | import static com.dji.sample.component.mqtt.model.TopicConst.*; |
| | | |
| | | /** |
| | | * |
| | | * @author sean.zhou |
| | | * @date 2021/11/12 |
| | | * @version 0.1 |
| | | */ |
| | | @MessageEndpoint |
| | | public class StatusRouter { |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | /** |
| | | * Converts the status data sent by the gateway device into an object. |
| | | * @param message |
| | | * @return |
| | | */ |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATUS, outputChannel = ChannelName.INBOUND_STATUS_ROUTER) |
| | | public CommonTopicReceiver<StatusGatewayReceiver> resolveStatus(Message<?> message) { |
| | | CommonTopicReceiver<StatusGatewayReceiver> statusReceiver = new CommonTopicReceiver<>(); |
| | | try { |
| | | statusReceiver = mapper.readValue( |
| | | (byte[])message.getPayload(), |
| | | new TypeReference<CommonTopicReceiver<StatusGatewayReceiver>>() {}); |
| | | |
| | | String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); |
| | | |
| | | // set gateway's sn |
| | | statusReceiver.getData().setSn( |
| | | topic.substring((BASIC_PRE + PRODUCT).length(), |
| | | topic.indexOf(STATUS_SUF))); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return statusReceiver; |
| | | } |
| | | |
| | | /** |
| | | * Handles the routing of status topic messages. Depending on the data, it is assigned to different channels for handling. |
| | | * @param receiver |
| | | * @return |
| | | */ |
| | | @Router(inputChannel = ChannelName.INBOUND_STATUS_ROUTER) |
| | | public String resolveStatusRouter(CommonTopicReceiver<StatusGatewayReceiver> receiver) { |
| | | // Determine whether the drone is online or offline according to whether the data of the sub-device is empty. |
| | | return CollectionUtils.isEmpty(receiver.getData().getSubDevices()) ? |
| | | ChannelName.INBOUND_STATUS_OFFLINE : ChannelName.INBOUND_STATUS_ONLINE; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import java.util.concurrent.locks.LockSupport; |
| | | |
| | | /** |
| | | * The demo is only for functional closure, which is not recommended. |
| | | * @author sean.zhou |
| | | * @date 2021/11/22 |
| | | * @version 0.1 |
| | | */ |
| | | public class Chan<T> { |
| | | |
| | | private static final long THREAD_WAIT_TIME = 1000_000 * 2000; |
| | | |
| | | private volatile T data; |
| | | |
| | | private volatile Thread t; |
| | | |
| | | private Chan () { |
| | | |
| | | } |
| | | |
| | | public static Chan getInstance() { |
| | | return ChanSingleton.INSTANCE; |
| | | } |
| | | |
| | | public T get(Object blocker) { |
| | | this.t = Thread.currentThread(); |
| | | LockSupport.parkNanos(blocker, THREAD_WAIT_TIME); |
| | | this.t = null; |
| | | return data; |
| | | } |
| | | |
| | | public void put(T data) { |
| | | this.data = data; |
| | | if (t == null) { |
| | | return; |
| | | } |
| | | LockSupport.unpark(t); |
| | | } |
| | | |
| | | private static class ChanSingleton { |
| | | private static final Chan<?> INSTANCE = new Chan<>(); |
| | | } |
| | | } |
| | |
| | | |
| | | public static final String OUTBOUND = "outbound"; |
| | | |
| | | public static final String INBOUND_STATE_FIRMWARE_VERSION = "inboundStateFirmwareVersion"; |
| | | |
| | | public static final String INBOUND_REQUESTS = "inboundRequests"; |
| | | |
| | | public static final String INBOUND_REQUESTS_STORAGE_CONFIG_GET = "inboundRequestsConfigGet"; |
| | | |
| | | public static final String INBOUND_EVENTS = "inboundEvents"; |
| | | |
| | | public static final String INBOUND_EVENTS_FLIGHT_TASK_PROGRESS = "inboundEventsFlightTaskProgress"; |
| | | |
| | | public static final String INBOUND_EVENTS_FILE_UPLOAD_CALLBACK = "inboundEventsFileUploadCallback"; |
| | | |
| | | public static final String INBOUND_REQUESTS_AIRPORT_BIND_STATUS = "inboundRequestsAirportBindStatus"; |
| | | |
| | | public static final String INBOUND_REQUESTS_AIRPORT_ORGANIZATION_GET = "inboundRequestsAirportOrganizationGet"; |
| | | |
| | | public static final String INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND = "inboundRequestsAirportOrganizationBind"; |
| | | |
| | | public static final String INBOUND_EVENTS_HMS = "inboundEventsHms"; |
| | | } |
| | |
| | | private Long timestamp; |
| | | |
| | | private T data; |
| | | |
| | | private String gateway; |
| | | |
| | | private Integer needReply; |
| | | |
| | | private String from; |
| | | } |
| | |
| | | private String method; |
| | | |
| | | private T data; |
| | | |
| | | private Long timestamp; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/14 |
| | | */ |
| | | @Data |
| | | @AllArgsConstructor |
| | | public class ErrorInfoReply { |
| | | |
| | | private String sn; |
| | | |
| | | private Integer errCode; |
| | | |
| | | public static ErrorInfoReply success(String sn) { |
| | | return new ErrorInfoReply(sn, ResponseResult.CODE_SUCCESS); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | public enum EventsMethodEnum { |
| | | |
| | | FLIGHT_TASK_PROGRESS("flighttask_progress"), |
| | | |
| | | FILE_UPLOAD_CALLBACK("file_upload_callback"), |
| | | |
| | | HMS("hms"), |
| | | |
| | | UNKNOWN("Unknown"); |
| | | |
| | | private String method; |
| | | |
| | | EventsMethodEnum(String method) { |
| | | this.method = method; |
| | | } |
| | | |
| | | public String getMethod() { |
| | | return method; |
| | | } |
| | | |
| | | public static EventsMethodEnum find(String method) { |
| | | return Arrays.stream(EventsMethodEnum.values()) |
| | | .filter(methodEnum -> methodEnum.method.equals(method)) |
| | | .findAny() |
| | | .orElse(UNKNOWN); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | @Data |
| | | @JsonIgnoreProperties(ignoreUnknown = true) |
| | | public class EventsReceiver<T> { |
| | | |
| | | private Integer result; |
| | | |
| | | private T output; |
| | | |
| | | private String bid; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/14 |
| | | */ |
| | | public final class MapKeyConst { |
| | | |
| | | private MapKeyConst(){ |
| | | |
| | | } |
| | | |
| | | public static final String ORGANIZATION_NAME = "organization_name"; |
| | | |
| | | public static final String DEVICES = "devices"; |
| | | |
| | | public static final String SN = "sn"; |
| | | |
| | | public static final String BIND_DEVICES = "bind_devices"; |
| | | |
| | | public static final String ERR_INFOS = "err_infos"; |
| | | |
| | | public static final String TINY_FINGERPRINTS = "tiny_fingerprints"; |
| | | |
| | | public static final String BIND_STATUS = "bind_status"; |
| | | |
| | | public static final String LIST = "list"; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/25 |
| | | */ |
| | | public enum RequestsMethodEnum { |
| | | |
| | | STORAGE_CONFIG_GET("storage_config_get"), |
| | | |
| | | AIRPORT_BIND_STATUS("airport_bind_status"), |
| | | |
| | | AIRPORT_ORGANIZATION_BIND("airport_organization_bind"), |
| | | |
| | | AIRPORT_ORGANIZATION_GET("airport_organization_get"), |
| | | |
| | | UNKNOWN("Unknown"); |
| | | |
| | | private String method; |
| | | |
| | | RequestsMethodEnum(String method) { |
| | | this.method = method; |
| | | } |
| | | |
| | | public String getMethod() { |
| | | return method; |
| | | } |
| | | |
| | | public static RequestsMethodEnum find(String method) { |
| | | return Arrays.stream(RequestsMethodEnum.values()) |
| | | .filter(methodEnum -> methodEnum.method.equals(method)) |
| | | .findAny() |
| | | .orElse(UNKNOWN); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import com.dji.sample.common.error.IErrorInfo; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/13 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class RequestsReply<T> { |
| | | |
| | | private Integer result; |
| | | |
| | | private T output; |
| | | |
| | | |
| | | public static RequestsReply error(IErrorInfo errorInfo) { |
| | | return RequestsReply.builder() |
| | | .result(errorInfo.getErrorCode()) |
| | | .output(errorInfo.getErrorMsg()) |
| | | .build(); |
| | | } |
| | | |
| | | public static <T> RequestsReply success(T data) { |
| | | return RequestsReply.builder() |
| | | .result(ResponseResult.CODE_SUCCESS) |
| | | .output(data) |
| | | .build(); |
| | | } |
| | | public static RequestsReply success() { |
| | | return RequestsReply.builder() |
| | | .result(ResponseResult.CODE_SUCCESS) |
| | | .build(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | | * @version 0.1 |
| | | * @date 2021/11/22 |
| | | */ |
| | | @Data |
| | | @JsonIgnoreProperties(ignoreUnknown = true) |
| | | public class ServiceReply<T> { |
| | | |
| | | private Integer result; |
| | | |
| | | private T info; |
| | | |
| | | private T output; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | | * @date 2021/11/22 |
| | | * @version 0.1 |
| | | */ |
| | | public enum ServicesMethodEnum { |
| | | |
| | | LIVE_START_PUSH("live_start_push"), |
| | | |
| | | LIVE_STOP_PUSH("live_stop_push"), |
| | | |
| | | LIVE_SET_QUALITY("live_set_quality"), |
| | | |
| | | FLIGHTTASK_CREATE("flighttask_create"), |
| | | |
| | | UNKNOWN("unknown"); |
| | | |
| | | private String method; |
| | | |
| | | ServicesMethodEnum(String method) { |
| | | this.method = method; |
| | | } |
| | | |
| | | public String getMethod() { |
| | | return method; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.mqtt.model; |
| | | |
| | | /** |
| | | * |
| | | * @author sean.zhou |
| | | * @date 2021/11/18 |
| | | * @version 0.1 |
| | | */ |
| | | public enum StateDataEnum { |
| | | |
| | | FIRMWARE_VERSION("firmware_version"), |
| | | |
| | | LIVE_CAPACITY("live_capacity"), |
| | | |
| | | PAYLOADS("payloads"); |
| | | |
| | | private String desc; |
| | | |
| | | StateDataEnum(String desc) { |
| | | this.desc = desc; |
| | | } |
| | | |
| | | public String getDesc() { |
| | | return this.desc; |
| | | } |
| | | } |
| | |
| | | |
| | | public static final String OSD_SUF = "/osd"; |
| | | |
| | | public static final String REQUESTS_SUF = "/requests"; |
| | | |
| | | public static final String EVENTS_SUF = "/events"; |
| | | |
| | | public static final String REGEX_SN = "[A-Za-z0-9]+"; |
| | | |
| | | } |
| | |
| | | package com.dji.sample.component.mqtt.service; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.mqtt.model.ServiceReply; |
| | | |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | |
| | | */ |
| | | void publish(String topic, int qos, CommonTopicResponse response); |
| | | |
| | | /** |
| | | * Send live streaming start message and receive a response at the same time |
| | | * @param topic |
| | | * @param response notification of whether the start is successful. |
| | | * @return |
| | | */ |
| | | Optional<ServiceReply> publishWithReply(String topic, CommonTopicResponse response); |
| | | } |
| | |
| | | package com.dji.sample.component.mqtt.service.impl; |
| | | |
| | | import com.dji.sample.component.mqtt.model.Chan; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.mqtt.model.ServiceReply; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.component.mqtt.service.IMqttMessageGateway; |
| | | import com.fasterxml.jackson.annotation.JsonInclude; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Optional; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | |
| | | @Autowired |
| | | private IMqttMessageGateway messageGateway; |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | public void publish(String topic, CommonTopicResponse response) { |
| | | try { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | // Only parameters whose value is not null will be serialised. |
| | | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
| | | |
| | | messageGateway.publish(topic, mapper.writeValueAsBytes(response)); |
| | | } catch (JsonProcessingException e) { |
| | |
| | | |
| | | public void publish(String topic, int qos, CommonTopicResponse response) { |
| | | try { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | // Only parameters whose value is not null will be serialised. |
| | | mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
| | | |
| | | messageGateway.publish(topic, mapper.writeValueAsBytes(response), qos); |
| | | } catch (JsonProcessingException e) { |
| | | log.info("Failed to publish the message. {}", response.toString()); |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | public Optional<ServiceReply> publishWithReply(String topic, CommonTopicResponse response) { |
| | | AtomicInteger time = new AtomicInteger(0); |
| | | // Retry three times |
| | | while (time.getAndIncrement() < 3) { |
| | | this.publish(topic, response); |
| | | |
| | | Chan<CommonTopicReceiver<ServiceReply>> chan = Chan.getInstance(); |
| | | // If the message is not received in 0.5 seconds then resend it again. |
| | | CommonTopicReceiver<ServiceReply> receiver = chan.get(response.getMethod()); |
| | | if (receiver == null) { |
| | | continue; |
| | | } |
| | | // Need to match tid and bid. |
| | | if (receiver.getTid().equals(response.getTid()) && |
| | | receiver.getBid().equals(response.getBid())) { |
| | | return Optional.ofNullable(receiver.getData()); |
| | | } |
| | | } |
| | | return Optional.empty(); |
| | | } |
| | | } |
| | |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneOffset; |
| | | import java.time.ZoneId; |
| | | |
| | | /** |
| | | * Automatic filling for set values |
| | |
| | | @Override |
| | | public void insertFill(MetaObject metaObject) { |
| | | this.strictInsertFill(metaObject, "createTime", Long.class, |
| | | LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); |
| | | LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); |
| | | this.strictInsertFill(metaObject, "updateTime", Long.class, |
| | | LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); |
| | | LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); |
| | | } |
| | | |
| | | /** |
| | |
| | | @Override |
| | | public void updateFill(MetaObject metaObject) { |
| | | this.strictUpdateFill(metaObject, "updateTime", Long.class, |
| | | LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); |
| | | LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.oss.model; |
| | | |
| | | import lombok.Data; |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.2 |
| | | * @date 2021/12/9 |
| | | */ |
| | | @ConfigurationProperties(prefix = "oss") |
| | | @Component |
| | | @Data |
| | | public class OssConfiguration { |
| | | |
| | | /** |
| | | * @see com.dji.sample.component.oss.model.enums.OssTypeEnum |
| | | */ |
| | | private String provider; |
| | | |
| | | /** |
| | | * Whether to use the object storage service. |
| | | */ |
| | | private boolean enable; |
| | | |
| | | /** |
| | | * The protocol needs to be included at the beginning of the address. |
| | | */ |
| | | private String endpoint; |
| | | |
| | | private String accessKey; |
| | | |
| | | private String secretKey; |
| | | |
| | | private String region; |
| | | |
| | | private Long expire; |
| | | |
| | | private String roleSessionName; |
| | | |
| | | private String roleArn; |
| | | |
| | | private String bucket; |
| | | |
| | | private String objectDirPrefix; |
| | | |
| | | public void setProvider(String provider) { |
| | | this.provider = provider; |
| | | } |
| | | |
| | | public void setEnable(boolean enable) { |
| | | this.enable = enable; |
| | | } |
| | | |
| | | public void setEndpoint(String endpoint) { |
| | | this.endpoint = endpoint; |
| | | } |
| | | |
| | | public void setAccessKey(String accessKey) { |
| | | this.accessKey = accessKey; |
| | | } |
| | | |
| | | public void setSecretKey(String secretKey) { |
| | | this.secretKey = secretKey; |
| | | } |
| | | |
| | | public void setRegion(String region) { |
| | | this.region = region; |
| | | } |
| | | |
| | | public void setExpire(Long expire) { |
| | | this.expire = expire; |
| | | } |
| | | |
| | | public void setRoleSessionName(String roleSessionName) { |
| | | this.roleSessionName = roleSessionName; |
| | | } |
| | | |
| | | public void setRoleArn(String roleArn) { |
| | | this.roleArn = roleArn; |
| | | } |
| | | |
| | | public void setBucket(String bucket) { |
| | | this.bucket = bucket; |
| | | } |
| | | |
| | | public void setObjectDirPrefix(String objectDirPrefix) { |
| | | this.objectDirPrefix = objectDirPrefix; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| New file |
| | |
| | | package com.dji.sample.component.oss.model.enums; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/30 |
| | | */ |
| | | public enum OssTypeEnum { |
| | | |
| | | ALIYUN("ali"), |
| | | |
| | | AWS("aws"), |
| | | |
| | | /* |
| | | * MinIO is temporarily unavailable. |
| | | */ |
| | | MINIO("minio"); |
| | | |
| | | private String type; |
| | | |
| | | OssTypeEnum(String type) { |
| | | this.type = type; |
| | | } |
| | | |
| | | public String getType() { |
| | | return type; |
| | | } |
| | | } |
| | |
| | | */ |
| | | public interface IOssService { |
| | | |
| | | String getOssType(); |
| | | |
| | | /** |
| | | * Get temporary credentials. |
| | | * @return |
| | |
| | | * @return download link |
| | | */ |
| | | URL getObjectUrl(String bucket, String objectKey); |
| | | |
| | | /** |
| | | * Deletes the object in the storage bucket. |
| | | * @param bucket |
| | | * @param objectKey |
| | | * @return |
| | | */ |
| | | Boolean deleteObject(String bucket, String objectKey); |
| | | |
| | | /** |
| | | * Get the contents of an object. |
| | | * @param bucket |
| | | * @param objectKey |
| | | * @return |
| | | */ |
| | | byte[] getObject(String bucket, String objectKey); |
| | | } |
| | |
| | | package com.dji.sample.component.oss.service.impl; |
| | | |
| | | import com.aliyun.oss.OSS; |
| | | import com.aliyun.oss.OSSClientBuilder; |
| | | import com.aliyun.oss.model.OSSObject; |
| | | import com.aliyuncs.DefaultAcsClient; |
| | | import com.aliyuncs.IAcsClient; |
| | | import com.aliyuncs.exceptions.ClientException; |
| | | import com.aliyuncs.profile.DefaultProfile; |
| | | import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest; |
| | | import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse; |
| | | import com.dji.sample.component.oss.model.AliyunOSSConfiguration; |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.model.enums.OssTypeEnum; |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | | import java.util.Date; |
| | | |
| | |
| | | @Slf4j |
| | | public class AliyunOssServiceImpl implements IOssService { |
| | | |
| | | @Autowired(required = false) |
| | | private OSS ossClient; |
| | | @Autowired |
| | | public OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public String getOssType() { |
| | | return OssTypeEnum.ALIYUN.getType(); |
| | | } |
| | | |
| | | @Override |
| | | public CredentialsDTO getCredentials() { |
| | | |
| | | try { |
| | | DefaultProfile profile = DefaultProfile.getProfile( |
| | | AliyunOSSConfiguration.region, AliyunOSSConfiguration.accessKey, AliyunOSSConfiguration.secretKey); |
| | | configuration.getRegion(), configuration.getAccessKey(), configuration.getSecretKey()); |
| | | IAcsClient client = new DefaultAcsClient(profile); |
| | | |
| | | AssumeRoleRequest request = new AssumeRoleRequest(); |
| | | request.setDurationSeconds(AliyunOSSConfiguration.expire); |
| | | request.setRoleArn(AliyunOSSConfiguration.roleArn); |
| | | request.setRoleSessionName(AliyunOSSConfiguration.roleSessionName); |
| | | request.setDurationSeconds(configuration.getExpire()); |
| | | request.setRoleArn(configuration.getRoleArn()); |
| | | request.setRoleSessionName(configuration.getRoleSessionName()); |
| | | |
| | | AssumeRoleResponse response = client.getAcsResponse(request); |
| | | return new CredentialsDTO(response.getCredentials(), AliyunOSSConfiguration.expire); |
| | | return new CredentialsDTO(response.getCredentials(), configuration.getExpire()); |
| | | |
| | | } catch (ClientException e) { |
| | | log.debug("Failed to obtain sts."); |
| | |
| | | if (!StringUtils.hasText(bucket) || !StringUtils.hasText(objectKey)) { |
| | | return null; |
| | | } |
| | | try { |
| | | // First check if the object can be fetched. |
| | | ossClient.getObject(bucket, objectKey); |
| | | OSS ossClient = this.createClient(); |
| | | // First check if the object can be fetched. |
| | | ossClient.getObject(bucket, objectKey); |
| | | |
| | | return ossClient.generatePresignedUrl(bucket, objectKey, |
| | | new Date(System.currentTimeMillis() + AliyunOSSConfiguration.expire * 1000)); |
| | | } catch (NullPointerException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | return ossClient.generatePresignedUrl(bucket, objectKey, |
| | | new Date(System.currentTimeMillis() + configuration.getExpire() * 1000)); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | OSS ossClient = this.createClient(); |
| | | ossClient.deleteObject(bucket, objectKey); |
| | | ossClient.shutdown(); |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public byte[] getObject(String bucket, String objectKey) { |
| | | OSS ossClient = this.createClient(); |
| | | OSSObject object = ossClient.getObject(bucket, objectKey); |
| | | InputStream stream = object.getObjectContent(); |
| | | |
| | | try { |
| | | return stream.readAllBytes(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | stream.close(); |
| | | ossClient.shutdown(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return new byte[0]; |
| | | } |
| | | |
| | | private OSS createClient() { |
| | | return new OSSClientBuilder() |
| | | .build(configuration.getEndpoint(), configuration.getAccessKey(), configuration.getSecretKey()); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.oss.service.impl; |
| | | |
| | | import com.amazonaws.HttpMethod; |
| | | import com.amazonaws.auth.AWSStaticCredentialsProvider; |
| | | import com.amazonaws.auth.BasicAWSCredentials; |
| | | import com.amazonaws.services.s3.AmazonS3; |
| | | import com.amazonaws.services.s3.AmazonS3ClientBuilder; |
| | | import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration; |
| | | import com.amazonaws.services.s3.model.CORSRule; |
| | | import com.amazonaws.services.s3.model.S3Object; |
| | | import com.amazonaws.services.securitytoken.AWSSecurityTokenService; |
| | | import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; |
| | | import com.amazonaws.services.securitytoken.model.AssumeRoleRequest; |
| | | import com.amazonaws.services.securitytoken.model.AssumeRoleResult; |
| | | import com.amazonaws.services.securitytoken.model.Credentials; |
| | | import com.dji.sample.component.AuthInterceptor; |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.model.enums.OssTypeEnum; |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.net.URL; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/27 |
| | | */ |
| | | @Service |
| | | public class AmazonS3ServiceImpl implements IOssService { |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public String getOssType() { |
| | | return OssTypeEnum.AWS.getType(); |
| | | } |
| | | |
| | | @Override |
| | | public CredentialsDTO getCredentials() { |
| | | AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard() |
| | | .withCredentials(new AWSStaticCredentialsProvider( |
| | | new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey()))) |
| | | .withRegion(configuration.getRegion()).build(); |
| | | |
| | | AssumeRoleRequest request = new AssumeRoleRequest() |
| | | .withRoleArn(configuration.getRoleArn()) |
| | | .withRoleSessionName(configuration.getRoleSessionName()) |
| | | .withDurationSeconds(Math.toIntExact(configuration.getExpire())); |
| | | AssumeRoleResult result = stsClient.assumeRole(request); |
| | | Credentials credentials = result.getCredentials(); |
| | | stsClient.shutdown(); |
| | | return new CredentialsDTO(credentials); |
| | | } |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | AmazonS3 client = this.createClient(); |
| | | URL url = client.generatePresignedUrl(bucket, objectKey, |
| | | new Date(System.currentTimeMillis() + configuration.getExpire() * 1000), HttpMethod.GET); |
| | | client.shutdown(); |
| | | return url; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | AmazonS3 client = this.createClient(); |
| | | client.deleteObject(bucket, objectKey); |
| | | client.shutdown(); |
| | | return true; |
| | | } |
| | | |
| | | public byte[] getObject(String bucket, String objectKey) { |
| | | AmazonS3 client = this.createClient(); |
| | | S3Object object = client.getObject(bucket, objectKey); |
| | | InputStream stream = object.getObjectContent().getDelegateStream(); |
| | | try { |
| | | return stream.readAllBytes(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } finally { |
| | | try { |
| | | stream.close(); |
| | | client.shutdown(); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | return new byte[0]; |
| | | } |
| | | |
| | | private AmazonS3 createClient() { |
| | | return AmazonS3ClientBuilder.standard() |
| | | .withCredentials( |
| | | new AWSStaticCredentialsProvider( |
| | | new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey()))) |
| | | .withRegion(configuration.getRegion()) |
| | | .build(); |
| | | } |
| | | |
| | | /** |
| | | * Configuring cross-origin resource sharing |
| | | */ |
| | | @PostConstruct |
| | | private void configCORS() { |
| | | if (!configuration.isEnable() || !OssTypeEnum.AWS.getType().equals(configuration.getProvider())) { |
| | | return; |
| | | } |
| | | List<CORSRule.AllowedMethods> allowedMethods = new ArrayList<>(); |
| | | allowedMethods.add(CORSRule.AllowedMethods.GET); |
| | | allowedMethods.add(CORSRule.AllowedMethods.POST); |
| | | allowedMethods.add(CORSRule.AllowedMethods.DELETE); |
| | | |
| | | CORSRule rule = new CORSRule() |
| | | .withId("CORSAccessRule") |
| | | .withAllowedOrigins(List.of("*")) |
| | | .withAllowedHeaders(List.of(AuthInterceptor.PARAM_TOKEN)) |
| | | .withAllowedMethods(allowedMethods); |
| | | |
| | | AmazonS3 client = this.createClient(); |
| | | |
| | | client.setBucketCrossOriginConfiguration(this.configuration.getBucket(), |
| | | new BucketCrossOriginConfiguration().withRules(rule)); |
| | | client.shutdown(); |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.component.oss.service.impl; |
| | | |
| | | import com.dji.sample.component.oss.model.MinIOConfiguration; |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.model.enums.OssTypeEnum; |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import io.minio.GetPresignedObjectUrlArgs; |
| | |
| | | @Slf4j |
| | | public class MinIOServiceImpl implements IOssService { |
| | | |
| | | @Autowired(required = false) |
| | | private MinioClient client; |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public String getOssType() { |
| | | return OssTypeEnum.MINIO.getType(); |
| | | } |
| | | |
| | | @Override |
| | | public CredentialsDTO getCredentials() { |
| | | try { |
| | | AssumeRoleProvider provider = new AssumeRoleProvider(MinIOConfiguration.endpoint, MinIOConfiguration.accessKey, |
| | | MinIOConfiguration.secretKey, MinIOConfiguration.expire, |
| | | null, null, null, null, null, null); |
| | | return new CredentialsDTO(provider.fetch(), MinIOConfiguration.expire); |
| | | AssumeRoleProvider provider = new AssumeRoleProvider(configuration.getEndpoint(), configuration.getAccessKey(), |
| | | configuration.getSecretKey(), Math.toIntExact(configuration.getExpire()), |
| | | null, configuration.getRegion(), null, null, null, null); |
| | | return new CredentialsDTO(provider.fetch(), Math.toIntExact(configuration.getExpire())); |
| | | } catch (NoSuchAlgorithmException e) { |
| | | log.debug("Failed to obtain sts."); |
| | | e.printStackTrace(); |
| | |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | try { |
| | | return new URL( |
| | | client.getPresignedObjectUrl( |
| | | GetPresignedObjectUrlArgs.builder() |
| | | .method(Method.GET) |
| | | .bucket(bucket) |
| | | .object(objectKey) |
| | | .expiry(MinIOConfiguration.expire) |
| | | .build())); |
| | | this.createClient() |
| | | .getPresignedObjectUrl( |
| | | GetPresignedObjectUrlArgs.builder() |
| | | .method(Method.GET) |
| | | .bucket(bucket) |
| | | .object(objectKey) |
| | | .expiry(Math.toIntExact(configuration.getExpire())) |
| | | .build())); |
| | | } catch (ErrorResponseException | InsufficientDataException | InternalException | |
| | | InvalidKeyException | InvalidResponseException | IOException | |
| | | NoSuchAlgorithmException | XmlParserException | ServerException e) { |
| | | log.error("The file does not exist on the oss."); |
| | | log.error("The file does not exist on the OssConfiguration."); |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public byte[] getObject(String bucket, String objectKey) { |
| | | return new byte[0]; |
| | | } |
| | | |
| | | private MinioClient createClient() { |
| | | return MinioClient.builder() |
| | | .endpoint(configuration.getEndpoint()) |
| | | .credentials(configuration.getAccessKey(), configuration.getSecretKey()) |
| | | .region(configuration.getRegion()) |
| | | .build(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.oss.service.impl; |
| | | |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import org.aspectj.lang.annotation.Aspect; |
| | | import org.aspectj.lang.annotation.Before; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/20 |
| | | */ |
| | | @Component |
| | | @Aspect |
| | | public class OssAspectHandler { |
| | | |
| | | @Autowired |
| | | private OssServiceContext ossServiceContext; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Before("execution(public * com.dji.sample.component.oss.service.impl.OssServiceContext.*(..))") |
| | | public void before() { |
| | | if (!this.configuration.isEnable()) { |
| | | throw new IllegalArgumentException("Please enable OssConfiguration."); |
| | | } |
| | | if (this.ossServiceContext.getOssService() == null) { |
| | | throw new IllegalArgumentException("Please check the OssConfiguration configuration."); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.oss.service.impl; |
| | | |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.model.enums.OssTypeEnum; |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.media.model.CredentialsDTO; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.net.URL; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/30 |
| | | */ |
| | | @Service |
| | | public class OssServiceContext { |
| | | |
| | | private IOssService ossService; |
| | | |
| | | private OssConfiguration configuration; |
| | | |
| | | @Autowired |
| | | public OssServiceContext(List<IOssService> ossServices, OssConfiguration configuration) { |
| | | this.configuration = configuration; |
| | | if (!configuration.isEnable()) { |
| | | return; |
| | | } |
| | | this.ossService = ossServices.stream() |
| | | .filter(ossService -> ossService.getOssType().equals(configuration.getProvider())) |
| | | .findFirst() |
| | | .orElseThrow(() -> new IllegalArgumentException("Oss provider is illegal. Optional: " + |
| | | Arrays.toString(Arrays.stream(OssTypeEnum.values()).map(OssTypeEnum::getType).toArray()))); |
| | | } |
| | | |
| | | IOssService getOssService() { |
| | | return this.ossService; |
| | | } |
| | | |
| | | public CredentialsDTO getCredentials() { |
| | | return this.ossService.getCredentials(); |
| | | } |
| | | |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | return this.ossService.getObjectUrl(bucket, objectKey); |
| | | } |
| | | |
| | | public Boolean deleteObject(String bucket, String objectKey) { |
| | | return this.ossService.deleteObject(bucket, objectKey); |
| | | } |
| | | |
| | | public byte[] getObject(String bucket, String objectKey) { |
| | | return this.ossService.getObject(bucket, objectKey); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.redis; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonInclude; |
| | | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
| | | import com.fasterxml.jackson.databind.MapperFeature; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
| | | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| | | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; |
| | | import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.data.redis.connection.RedisConnectionFactory; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; |
| | | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; |
| | | import org.springframework.data.redis.serializer.StringRedisSerializer; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/19 |
| | | */ |
| | | @Configuration |
| | | @EnableRedisRepositories |
| | | public class RedisConfiguration { |
| | | |
| | | @Bean |
| | | public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { |
| | | RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); |
| | | redisTemplate.setConnectionFactory(factory); |
| | | |
| | | ObjectMapper objectMapper = new ObjectMapper(); |
| | | JavaTimeModule timeModule = new JavaTimeModule(); |
| | | timeModule.addDeserializer(LocalDateTime.class, |
| | | new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); |
| | | timeModule.addSerializer(LocalDateTime.class, |
| | | new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); |
| | | objectMapper.disable(MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS); |
| | | objectMapper.registerModules(timeModule); |
| | | objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), |
| | | ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); |
| | | |
| | | objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); |
| | | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); |
| | | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
| | | |
| | | |
| | | StringRedisSerializer serializer = new StringRedisSerializer(); |
| | | redisTemplate.setKeySerializer(serializer); |
| | | redisTemplate.setHashKeySerializer(serializer); |
| | | |
| | | GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(objectMapper); |
| | | redisTemplate.setValueSerializer(jsonRedisSerializer); |
| | | redisTemplate.setHashValueSerializer(jsonRedisSerializer); |
| | | redisTemplate.afterPropertiesSet(); |
| | | return redisTemplate; |
| | | |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.redis; |
| | | |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/21 |
| | | */ |
| | | public final class RedisConst { |
| | | |
| | | private RedisConst() { |
| | | |
| | | } |
| | | |
| | | public static final Integer DEVICE_ALIVE_SECOND = 60; |
| | | |
| | | public static final Integer WEBSOCKET_ALIVE_SECOND = 60 * 60 * 24; |
| | | |
| | | public static final String ONLINE_PREFIX = "online:"; |
| | | |
| | | public static final String DEVICE_ONLINE_PREFIX = ONLINE_PREFIX + DeviceDomainEnum.SUB_DEVICE + ":"; |
| | | |
| | | public static final String WEBSOCKET_PREFIX = "webSocket:"; |
| | | |
| | | public static final String WEBSOCKET_ALL = "webSocket:all"; |
| | | |
| | | public static final String HMS_PREFIX = "hms:"; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.component.redis; |
| | | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/19 |
| | | */ |
| | | @Component |
| | | public class RedisOpsUtils { |
| | | |
| | | @Autowired |
| | | private RedisTemplate<String, Object> redisTemplate; |
| | | |
| | | /** |
| | | * HSET |
| | | * @param key |
| | | * @param field |
| | | * @param value |
| | | */ |
| | | public void hashSet(String key, String field, Object value) { |
| | | redisTemplate.opsForHash().put(key, field, value); |
| | | } |
| | | |
| | | /** |
| | | * HGET |
| | | * @param key |
| | | * @param field |
| | | * @return |
| | | */ |
| | | public Object hashGet(String key, String field) { |
| | | return redisTemplate.opsForHash().get(key, field); |
| | | } |
| | | |
| | | /** |
| | | * HKEYS |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Set<Object> hashKeys(String key) { |
| | | return redisTemplate.opsForHash().keys(key); |
| | | } |
| | | |
| | | /** |
| | | * HEXISTS |
| | | * @param key |
| | | * @param field |
| | | * @return |
| | | */ |
| | | public boolean hashCheck(String key, String field) { |
| | | return redisTemplate.opsForHash().hasKey(key, field); |
| | | } |
| | | |
| | | /** |
| | | * HDEL |
| | | * @param key |
| | | * @param fields |
| | | * @return |
| | | */ |
| | | public boolean hashDel(String key, Object[] fields) { |
| | | return redisTemplate.opsForHash().delete(key, fields) > 0; |
| | | } |
| | | |
| | | /** |
| | | * EXPIRE |
| | | * @param key |
| | | * @param timeout |
| | | * @return |
| | | */ |
| | | public boolean expireKey(String key, long timeout) { |
| | | return redisTemplate.expire(key, timeout, TimeUnit.SECONDS); |
| | | } |
| | | |
| | | /** |
| | | * SET |
| | | * @param key |
| | | * @param value |
| | | */ |
| | | public void set(String key, Object value) { |
| | | redisTemplate.opsForValue().set(key, value); |
| | | } |
| | | |
| | | /** |
| | | * GET |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Object get(String key) { |
| | | return redisTemplate.opsForValue().get(key); |
| | | } |
| | | |
| | | /** |
| | | * SETEX |
| | | * @param key |
| | | * @param value |
| | | * @param expire |
| | | */ |
| | | public void setWithExpire(String key, Object value, long expire) { |
| | | redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); |
| | | } |
| | | |
| | | /** |
| | | * TTL |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public long getExpire(String key) { |
| | | return redisTemplate.getExpire(key, TimeUnit.SECONDS); |
| | | } |
| | | |
| | | /** |
| | | * EXISTS |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public boolean checkExist(String key) { |
| | | return redisTemplate.hasKey(key); |
| | | } |
| | | |
| | | /** |
| | | * DEL |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public boolean del(String key) { |
| | | return this.checkExist(key) && redisTemplate.delete(key); |
| | | } |
| | | |
| | | /** |
| | | * KEYS |
| | | * @param pattern |
| | | * @return |
| | | */ |
| | | public Set<String> getAllKeys(String pattern) { |
| | | return redisTemplate.keys(pattern); |
| | | } |
| | | |
| | | /** |
| | | * RPUSH |
| | | * @param key |
| | | * @param value |
| | | */ |
| | | public void listRPush(String key, Object... value) { |
| | | if (value.length == 0) { |
| | | return; |
| | | } |
| | | for (Object val : value) { |
| | | redisTemplate.opsForList().rightPush(key, val); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * LRANGE |
| | | * @param key |
| | | * @param start |
| | | * @param end |
| | | * @return |
| | | */ |
| | | public List<Object> listGet(String key, long start, long end) { |
| | | return redisTemplate.opsForList().range(key, start, end); |
| | | } |
| | | |
| | | /** |
| | | * LRANGE |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public List<Object> listGetAll(String key) { |
| | | return redisTemplate.opsForList().range(key, 0, -1); |
| | | } |
| | | |
| | | /** |
| | | * LLen |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public Long listLen(String key) { |
| | | return redisTemplate.opsForList().size(key); |
| | | } |
| | | } |
| | |
| | | if (!StringUtils.hasText(token)) { |
| | | return false; |
| | | } |
| | | |
| | | log.debug("token:" + token); |
| | | Optional<CustomClaim> customClaim = JwtUtil.parseToken(token); |
| | | if (customClaim.isEmpty()) { |
| | | return false; |
| | |
| | | package com.dji.sample.component.websocket.config; |
| | | |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.web.socket.WebSocketHandler; |
| | | import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory; |
| | |
| | | @Component |
| | | public class WebSocketDefaultFactory implements WebSocketHandlerDecoratorFactory { |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | @Override |
| | | public WebSocketHandler decorate(WebSocketHandler handler) { |
| | | return new WebSocketDefaultHandler(handler); |
| | | return new WebSocketDefaultHandler(handler, webSocketManageService); |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.component.websocket.config; |
| | | |
| | | import com.dji.sample.component.websocket.model.WebSocketManager; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.util.StringUtils; |
| | | import org.springframework.web.socket.CloseStatus; |
| | | import org.springframework.web.socket.WebSocketHandler; |
| | |
| | | @Slf4j |
| | | public class WebSocketDefaultHandler extends WebSocketHandlerDecorator { |
| | | |
| | | @Autowired |
| | | private ISendMessageService sendMessageService; |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | WebSocketDefaultHandler(WebSocketHandler delegate) { |
| | | WebSocketDefaultHandler(WebSocketHandler delegate, IWebSocketManageService webSocketManageService) { |
| | | super(delegate); |
| | | this.webSocketManageService = webSocketManageService; |
| | | } |
| | | |
| | | @Override |
| | | public void afterConnectionEstablished(WebSocketSession session) throws Exception { |
| | | Principal principal = session.getPrincipal(); |
| | | if (StringUtils.hasText(principal.getName())) { |
| | | WebSocketManager.put(principal.getName(), new ConcurrentWebSocketSession(session)); |
| | | webSocketManageService.put(principal.getName(), new ConcurrentWebSocketSession(session)); |
| | | log.debug("{} is connected. ID: {}. WebSocketSession[current count: {}]", |
| | | principal.getName(), session.getId(), WebSocketManager.getConnectedCount()); |
| | | principal.getName(), session.getId(), webSocketManageService.getConnectedCount()); |
| | | return; |
| | | } |
| | | session.close(); |
| | |
| | | public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { |
| | | Principal principal = session.getPrincipal(); |
| | | if (StringUtils.hasText(principal.getName())) { |
| | | WebSocketManager.remove(principal.getName(), session.getId()); |
| | | webSocketManageService.remove(principal.getName(), session.getId()); |
| | | log.debug("{} is disconnected. ID: {}. WebSocketSession[current count: {}]", |
| | | principal.getName(), session.getId(), WebSocketManager.getConnectedCount()); |
| | | principal.getName(), session.getId(), webSocketManageService.getConnectedCount()); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | GATEWAY_OSD("gateway_osd"), |
| | | |
| | | DOCK_OSD("dock_osd"), |
| | | |
| | | MAP_ELEMENT_CREATE("map_element_create"), |
| | | |
| | | MAP_ELEMENT_UPDATE("map_element_update"), |
| | | |
| | | MAP_ELEMENT_DELETE("map_element_delete"), |
| | | |
| | | MAP_GROUP_REFRESH("map_group_refresh"); |
| | | MAP_GROUP_REFRESH("map_group_refresh"), |
| | | |
| | | FLIGHT_TASK_PROGRESS("flighttask_progress"), |
| | | |
| | | DEVICE_HMS("device_hms"); |
| | | |
| | | private String code; |
| | | |
| New file |
| | |
| | | package com.dji.sample.component.websocket.service; |
| | | |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | |
| | | import java.util.Collection; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/25 |
| | | */ |
| | | public interface IWebSocketManageService { |
| | | |
| | | void put(String key, ConcurrentWebSocketSession val); |
| | | |
| | | void remove(String key, String sessionId); |
| | | |
| | | Collection<ConcurrentWebSocketSession> getValueWithWorkspace(String workspaceId); |
| | | |
| | | Collection<ConcurrentWebSocketSession> getValueWithWorkspaceAndUserType(String workspaceId, Integer userType); |
| | | |
| | | Long getConnectedCount(); |
| | | } |
| | |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.web.socket.TextMessage; |
| | | |
| | |
| | | @Slf4j |
| | | public class SendMessageServiceImpl implements ISendMessageService { |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | @Override |
| | | public void sendMessage(ConcurrentWebSocketSession session, CustomWebSocketMessage message) { |
| | | if (session == null) { |
| | |
| | | return; |
| | | } |
| | | |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | |
| | | session.sendMessage(new TextMessage(mapper.writeValueAsBytes(message))); |
| | | } catch (IOException e) { |
| | |
| | | |
| | | try { |
| | | |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | TextMessage data = new TextMessage(mapper.writeValueAsBytes(message)); |
| | | |
| | | for (ConcurrentWebSocketSession session : sessions) { |
| | |
| | | return; |
| | | } |
| | | session.sendMessage(data); |
| | | |
| | | } |
| | | |
| | | } catch (IOException e) { |
| New file |
| | |
| | | package com.dji.sample.component.websocket.service.impl; |
| | | |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.Objects; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/25 |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | public class WebSocketManageServiceImpl implements IWebSocketManageService { |
| | | |
| | | private static final ConcurrentHashMap<String, ConcurrentWebSocketSession> SESSIONS = new ConcurrentHashMap<>(16); |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public void put(String key, ConcurrentWebSocketSession val) { |
| | | String[] name = key.split("/"); |
| | | if (name.length != 3) { |
| | | log.debug("The key is out of format. [{workspaceId}/{userType}/{userId}]"); |
| | | return; |
| | | } |
| | | String sessionId = val.getId(); |
| | | String workspaceKey = RedisConst.WEBSOCKET_PREFIX + name[0]; |
| | | String userTypeKey = RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])).getDesc(); |
| | | redisOps.hashSet(workspaceKey, sessionId, name[2]); |
| | | redisOps.hashSet(userTypeKey, sessionId, name[2]); |
| | | SESSIONS.put(sessionId, val); |
| | | redisOps.expireKey(workspaceKey, RedisConst.WEBSOCKET_ALIVE_SECOND); |
| | | redisOps.expireKey(userTypeKey, RedisConst.WEBSOCKET_ALIVE_SECOND); |
| | | } |
| | | |
| | | @Override |
| | | public void remove(String key, String sessionId) { |
| | | String[] name = key.split("/"); |
| | | if (name.length != 3) { |
| | | log.debug("The key is out of format. [{workspaceId}/{userType}/{userId}]"); |
| | | return; |
| | | } |
| | | redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + name[0], new String[] {sessionId}); |
| | | redisOps.hashDel(RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(Integer.parseInt(name[1])), new String[] {sessionId}); |
| | | SESSIONS.remove(sessionId); |
| | | } |
| | | |
| | | @Override |
| | | public Collection<ConcurrentWebSocketSession> getValueWithWorkspace(String workspaceId) { |
| | | if (!StringUtils.hasText(workspaceId)) { |
| | | return Collections.emptySet(); |
| | | } |
| | | String key = RedisConst.WEBSOCKET_PREFIX + workspaceId; |
| | | |
| | | return redisOps.hashKeys(key) |
| | | .stream() |
| | | .map(SESSIONS::get) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | } |
| | | |
| | | @Override |
| | | public Collection<ConcurrentWebSocketSession> getValueWithWorkspaceAndUserType(String workspaceId, Integer userType) { |
| | | String key = RedisConst.WEBSOCKET_PREFIX + UserTypeEnum.find(userType).getDesc(); |
| | | return redisOps.hashKeys(key) |
| | | .stream() |
| | | .map(SESSIONS::get) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | } |
| | | |
| | | @Override |
| | | public Long getConnectedCount() { |
| | | return SESSIONS.mappingCount(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.configuration; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonInclude; |
| | | import com.fasterxml.jackson.core.JsonGenerator; |
| | | import com.fasterxml.jackson.core.JsonParser; |
| | | import com.fasterxml.jackson.databind.*; |
| | | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; |
| | | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; |
| | | 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.Configuration; |
| | | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; |
| | | |
| | | import java.io.IOException; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | |
| | | @Configuration |
| | | public class SpringBeanConfiguration { |
| | | |
| | | @Bean |
| | | @ConditionalOnMissingBean(ObjectMapper.class) |
| | | public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { |
| | | ObjectMapper objectMapper = builder.createXmlMapper(false).build(); |
| | | objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); |
| | | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); |
| | | objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
| | | |
| | | JavaTimeModule timeModule = new JavaTimeModule(); |
| | | timeModule.addDeserializer(LocalDateTime.class, |
| | | new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); |
| | | timeModule.addSerializer(LocalDateTime.class, |
| | | new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); |
| | | |
| | | objectMapper.disable(MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS); |
| | | objectMapper.registerModules(timeModule); |
| | | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| | | objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); |
| | | objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); |
| | | objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() { |
| | | @Override |
| | | public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { |
| | | gen.writeString(""); |
| | | } |
| | | }); |
| | | return objectMapper; |
| | | } |
| | | } |
| | |
| | | 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.component.AuthInterceptor; |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.model.WebSocketManager; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.WorkspaceDTO; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.model.param.DeviceQueryParam; |
| | | import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; |
| | | import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.Message; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .build()); |
| | | |
| | | // Publish the latest device topology information in the current workspace to the pilot. |
| | | deviceService.pushDeviceOnlineTopo(WorkspaceDTO.DEFAULT_WORKSPACE_ID, |
| | | receiver.getData().getSn(), receiver.getData().getSubDevices().get(0).getSn()); |
| | | } |
| | | } |
| | | |
| | |
| | | .bid(receiver.getBid()) |
| | | .build()); |
| | | |
| | | // Publish the latest device topology information in the current workspace to the pilot. |
| | | deviceService.pushDeviceOfflineTopo(WorkspaceDTO.DEFAULT_WORKSPACE_ID, receiver.getData().getSn()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Get the topology list of all devices in the current user workspace. |
| | | * @param request |
| | | * Get the topology list of all online devices in one workspace. |
| | | * @param workspaceId |
| | | * @return |
| | | */ |
| | | @GetMapping("/devices") |
| | | public ResponseResult<List<DeviceDTO>> getDevices(HttpServletRequest request) { |
| | | // Get information about the current user. |
| | | CustomClaim claim = (CustomClaim)request.getAttribute(AuthInterceptor.TOKEN_CLAIM); |
| | | String workspaceId = claim.getWorkspaceId(); |
| | | // Get information about the devices in the current user's workspace. |
| | | @GetMapping("/{workspace_id}/devices") |
| | | public ResponseResult<List<DeviceDTO>> getDevices(@PathVariable("workspace_id") String workspaceId) { |
| | | List<DeviceDTO> devicesList = deviceService.getDevicesTopoForWeb(workspaceId); |
| | | |
| | | return ResponseResult.success(devicesList); |
| | |
| | | deviceService.handleOSD(topic, payload); |
| | | } |
| | | |
| | | /** |
| | | * Handles the payloads data of the drone. |
| | | * @param deviceSn drone's sn |
| | | */ |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
| | | public void pushWebSocketDevices(String deviceSn) { |
| | | List<DeviceDTO> devicesList = deviceService.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .deviceSn(deviceSn) |
| | | .build()); |
| | | // Get drone information based on the sn of the drone. The sn of the drone is unique. |
| | | DeviceDTO device = devicesList.get(0); |
| | | // Set the remote controller and payloads information of the drone. |
| | | deviceService.spliceDeviceTopo(device); |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_FIRMWARE_VERSION) |
| | | public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { |
| | | deviceService.updateFirmwareVersion(receiver); |
| | | } |
| | | |
| | | CustomWebSocketMessage wsMessage = CustomWebSocketMessage.builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .bizCode(BizCodeEnum.DEVICE_UPDATE_TOPO.getCode()) |
| | | .data(device) |
| | | .build(); |
| | | // Update the topology of the drone via WebSocket notifications to the web side. |
| | | sendMessageService.sendBatch(WebSocketManager |
| | | .getValueWithWorkspaceAndUserType( |
| | | device.getWorkspaceId(), UserTypeEnum.WEB.getVal()), |
| | | wsMessage); |
| | | @PostMapping("/{device_sn}/binding") |
| | | public ResponseResult bindDevice(@RequestBody DeviceDTO device, @PathVariable("device_sn") String deviceSn) { |
| | | device.setDeviceSn(deviceSn); |
| | | boolean isUpd = deviceService.bindDevice(device); |
| | | return isUpd ? ResponseResult.success() : ResponseResult.error(); |
| | | } |
| | | |
| | | @GetMapping("/{workspace_id}/devices/{device_sn}") |
| | | public ResponseResult getDevice(@PathVariable("workspace_id") String workspaceId, |
| | | @PathVariable("device_sn") String deviceSn) { |
| | | Optional<DeviceDTO> deviceOpt = deviceService.getDeviceBySn(deviceSn); |
| | | return deviceOpt.isEmpty() ? ResponseResult.error("device not found.") : ResponseResult.success(deviceOpt.get()); |
| | | } |
| | | |
| | | /** |
| | | * Get the binding devices list in one workspace. |
| | | * @param workspaceId |
| | | * @param page |
| | | * @param pageSize |
| | | * @return |
| | | */ |
| | | @GetMapping("/{workspace_id}/devices/bound") |
| | | public ResponseResult<PaginationData<DeviceDTO>> getBoundDevicesWithDomain( |
| | | @PathVariable("workspace_id") String workspaceId, String domain, |
| | | @RequestParam(defaultValue = "1") Long page, |
| | | @RequestParam(value = "page_size", defaultValue = "50") Long pageSize) { |
| | | PaginationData<DeviceDTO> devices = deviceService.getBoundDevicesWithDomain(workspaceId, page, pageSize, domain); |
| | | |
| | | return ResponseResult.success(devices); |
| | | } |
| | | |
| | | @DeleteMapping("/{device_sn}/unbinding") |
| | | public ResponseResult unbindingDevice(@PathVariable("device_sn") String deviceSn) { |
| | | deviceService.unbindDevice(deviceSn); |
| | | return ResponseResult.success(); |
| | | } |
| | | |
| | | @PutMapping("/{workspace_id}/devices/{device_sn}") |
| | | public ResponseResult updateDevice(@RequestBody DeviceDTO device, |
| | | @PathVariable("workspace_id") String workspaceId, |
| | | @PathVariable("device_sn") String deviceSn) { |
| | | device.setDeviceSn(deviceSn); |
| | | boolean isUpd = deviceService.updateDevice(device); |
| | | return isUpd ? ResponseResult.success() : ResponseResult.error(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.controller; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.manage.model.dto.DeviceHmsDTO; |
| | | import com.dji.sample.manage.model.param.DeviceHmsQueryParam; |
| | | import com.dji.sample.manage.service.IDeviceHmsService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/7 |
| | | */ |
| | | |
| | | @RestController |
| | | @Slf4j |
| | | @RequestMapping("${url.manage.prefix}${url.manage.version}/devices") |
| | | public class DeviceHmsController { |
| | | |
| | | @Autowired |
| | | private IDeviceHmsService deviceHmsService; |
| | | |
| | | @GetMapping("/{workspace_id}/devices/hms") |
| | | public ResponseResult<PaginationData<DeviceHmsDTO>> getBoundDevicesWithDomain(DeviceHmsQueryParam param, |
| | | @PathVariable("workspace_id") String workspaceId) { |
| | | PaginationData<DeviceHmsDTO> devices = deviceHmsService.getDeviceHmsByParam(param); |
| | | |
| | | return ResponseResult.success(devices); |
| | | } |
| | | |
| | | @PutMapping("/{workspace_id}/devices/hms/{device_sn}") |
| | | public ResponseResult updateReadHmsByDeviceSn(@PathVariable("device_sn") String deviceSn) { |
| | | deviceHmsService.updateUnreadHms(deviceSn); |
| | | return ResponseResult.success(); |
| | | } |
| | | |
| | | @GetMapping("/{workspace_id}/devices/hms/{device_sn}") |
| | | public ResponseResult<List<DeviceHmsDTO>> getUnreadHmsByDeviceSn(@PathVariable("device_sn") String deviceSn) { |
| | | PaginationData<DeviceHmsDTO> paginationData = deviceHmsService.getDeviceHmsByParam( |
| | | DeviceHmsQueryParam.builder() |
| | | .deviceSn(new HashSet<>(Set.of(deviceSn))) |
| | | .updateTime(0L) |
| | | .build()); |
| | | return ResponseResult.success(paginationData.getList()); |
| | | } |
| | | } |
| | |
| | | |
| | | import com.dji.sample.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; |
| | | import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; |
| | | import com.dji.sample.manage.service.IDevicePayloadService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | private IDevicePayloadService devicePayloadService; |
| | | |
| | | /** |
| | | * Handles the data for the payload messages in the state topic. |
| | | * @param payloadsList List of payload information. |
| | | * @return drone's sn |
| | | */ |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_PAYLOAD, |
| | | outputChannel = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
| | | public String statePayload(List<DevicePayloadReceiver> payloadsList) { |
| | | // Delete all payload information for the drone based on the drone's sn. |
| | | devicePayloadService.deletePayloadsByDeviceSn(List.of(payloadsList.get(0).getDeviceSn())); |
| | | |
| | | // Save the new payload information. |
| | | devicePayloadService.savePayloadDTOs(payloadsList); |
| | | |
| | | log.debug("The result of saving the payload is successful."); |
| | | |
| | | return payloadsList.get(0).getDeviceSn(); |
| | | } |
| | | |
| | | /** |
| | | * Handles messages in the state topic about basic drone data. |
| | | * |
| | | * Note: Only the data of the drone payload is handled here. You can handle other data from the drone |
| | |
| | | * @param deviceBasic basic drone data |
| | | * @return drone's sn |
| | | */ |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_BASIC, |
| | | outputChannel = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
| | | public String stateBasic(DeviceBasicReceiver deviceBasic) { |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_BASIC) |
| | | public void stateBasic(DeviceBasicReceiver deviceBasic) { |
| | | // Delete all payload information for the drone based on the drone's sn. |
| | | devicePayloadService.deletePayloadsByDeviceSn(List.of(deviceBasic.getDeviceSn())); |
| | | |
| | |
| | | |
| | | log.debug("The result of saving the payloads is {}.", isSave); |
| | | |
| | | return deviceBasic.getDeviceSn(); |
| | | } |
| | | } |
| | |
| | | |
| | | import com.dji.sample.common.model.CustomClaim; |
| | | 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.CommonTopicReceiver; |
| | | import com.dji.sample.manage.model.Chan; |
| | | import com.dji.sample.component.mqtt.model.ServiceReply; |
| | | import com.dji.sample.manage.model.dto.CapacityDeviceDTO; |
| | | import com.dji.sample.manage.model.dto.LiveTypeDTO; |
| | | import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver; |
| | | import com.dji.sample.manage.model.receiver.ServiceReplyReceiver; |
| | | import com.dji.sample.manage.model.receiver.LiveCapacityReceiver; |
| | | import com.dji.sample.manage.service.ILiveStreamService; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | |
| | | @Autowired |
| | | private ILiveStreamService liveStreamService; |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | /** |
| | | * Analyze the live streaming capabilities of drones. |
| | | * This data is necessary if drones are required for live streaming. |
| | | * @param device the capacity of drone |
| | | * @param liveCapacity the capacity of drone and dock |
| | | */ |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_CAPACITY) |
| | | public void stateCapacity(CapacityDeviceReceiver device) { |
| | | boolean parseCapacity = liveStreamService.saveLiveCapacity(device); |
| | | log.debug("The result of parsing the live capacity is {}.", parseCapacity); |
| | | public void stateCapacity(LiveCapacityReceiver liveCapacity) { |
| | | liveStreamService.saveLiveCapacity(liveCapacity); |
| | | } |
| | | |
| | | /** |
| | |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_SERVICE_REPLY) |
| | | public void serviceReply(Message<?> message) throws IOException { |
| | | byte[] payload = (byte[])message.getPayload(); |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | CommonTopicReceiver<ServiceReplyReceiver> receiver = mapper.readValue(payload, |
| | | new TypeReference<CommonTopicReceiver<ServiceReplyReceiver>>() { |
| | | CommonTopicReceiver<ServiceReply> receiver = mapper.readValue(payload, |
| | | new TypeReference<CommonTopicReceiver<ServiceReply>>() { |
| | | }); |
| | | Chan<CommonTopicReceiver> chan = Chan.getInstance(); |
| | | // Put the message to the chan object. |
| | |
| | | |
| | | @PostMapping("/login") |
| | | public ResponseResult login(@RequestBody UserLoginDTO loginDTO) { |
| | | |
| | | String username = loginDTO.getUsername(); |
| | | String password = loginDTO.getPassword(); |
| | | return userService.userLogin(username, password); |
| | | return userService.userLogin(username, password, loginDTO.getFlag()); |
| | | } |
| | | |
| | | @PostMapping("/token/refresh") |
| | |
| | | return ResponseResult.error(CommonErrorEnum.NO_TOKEN.getErrorMsg()); |
| | | } |
| | | |
| | | return ResponseResult.success(user); |
| | | return ResponseResult.success(user.get()); |
| | | } |
| | | } |
| | |
| | | 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.UserListDTO; |
| | | import com.dji.sample.manage.service.IUserService; |
| | | 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.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | |
| | | @Autowired |
| | | private IUserService userService; |
| | | |
| | | /** |
| | | * Query the information of the current user. |
| | | * @param request |
| | | * @return |
| | | */ |
| | | @GetMapping("/current") |
| | | public ResponseResult getCurrentUserInfo(HttpServletRequest request) { |
| | | CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); |
| | | return userService.getUserByUsername(customClaim.getUsername(), customClaim.getWorkspaceId()); |
| | | } |
| | | |
| | | /** |
| | | * Paging to query all users in a workspace. |
| | | * @param page current page |
| | | * @param pageSize |
| | | * @param workspaceId |
| | | * @return |
| | | */ |
| | | @GetMapping("/{workspace_id}/users") |
| | | public ResponseResult<PaginationData<UserListDTO>> getUsers(@RequestParam(defaultValue = "1") Long page, |
| | | @RequestParam(value = "page_size", defaultValue = "50") Long pageSize, |
| | | @PathVariable("workspace_id") String workspaceId) { |
| | | PaginationData<UserListDTO> paginationData = userService.getUsersByWorkspaceId(page, pageSize, workspaceId); |
| | | return ResponseResult.success(paginationData); |
| | | } |
| | | |
| | | /** |
| | | * Modify user information. Only mqtt account information is included, nothing else can be modified. |
| | | * @param user |
| | | * @param workspaceId |
| | | * @param userId |
| | | * @return |
| | | */ |
| | | @PutMapping("/{workspace_id}/users/{user_id}") |
| | | public ResponseResult updateUser(@RequestBody UserListDTO user, |
| | | @PathVariable("workspace_id") String workspaceId, |
| | | @PathVariable("user_id") String userId) { |
| | | |
| | | userService.updateUser(workspaceId, userId, user); |
| | | return ResponseResult.success(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.dao; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.dji.sample.manage.model.entity.DeviceHmsEntity; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/6 |
| | | */ |
| | | public interface IDeviceHmsMapper extends BaseMapper<DeviceHmsEntity> { |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.common; |
| | | |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.core.io.ClassPathResource; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.PostConstruct; |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/7 |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | public class HmsJsonUtil { |
| | | |
| | | private static ObjectMapper mapper; |
| | | |
| | | @Autowired |
| | | public void setMapper(ObjectMapper mapper) { |
| | | HmsJsonUtil.mapper = mapper; |
| | | } |
| | | |
| | | private static JsonNode nodes; |
| | | |
| | | private HmsJsonUtil(){ |
| | | |
| | | } |
| | | |
| | | @PostConstruct |
| | | private void loadJsonFile() { |
| | | try (InputStream inputStream = new ClassPathResource("hms.json").getInputStream()){ |
| | | nodes = mapper.readTree(inputStream); |
| | | } catch (IOException e) { |
| | | log.error("hms.json failed to load."); |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | public static HmsMessage get(String key) { |
| | | return mapper.convertValue(nodes.get(key), HmsMessage.class); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.common; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/7 |
| | | */ |
| | | @Data |
| | | public class HmsMessage { |
| | | |
| | | private String zh; |
| | | |
| | | private String en; |
| | | } |
| | |
| | | @NoArgsConstructor |
| | | public class CapacityCameraDTO { |
| | | |
| | | private Integer id; |
| | | private String id; |
| | | |
| | | private String deviceSn; |
| | | |
| | | private String name; |
| | | |
| | | private String description; |
| | | |
| | | private String index; |
| | | |
| | |
| | | @NoArgsConstructor |
| | | public class CapacityVideoDTO { |
| | | |
| | | private Integer id; |
| | | private String id; |
| | | |
| | | private String index; |
| | | |
| | |
| | | package com.dji.sample.manage.model.dto; |
| | | |
| | | import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
| | | import com.fasterxml.jackson.databind.annotation.JsonNaming; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | @Builder |
| | | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
| | | public class DeviceDTO { |
| | | |
| | | private String deviceSn; |
| | |
| | | private List<DevicePayloadDTO> payloadsList; |
| | | |
| | | private IconUrlDTO iconUrl; |
| | | |
| | | private Boolean status; |
| | | |
| | | private Boolean boundStatus; |
| | | |
| | | private LocalDateTime loginTime; |
| | | |
| | | private LocalDateTime boundTime; |
| | | |
| | | private String nickname; |
| | | |
| | | private String userId; |
| | | |
| | | private String firmwareVersion; |
| | | |
| | | private String workspaceName; |
| | | |
| | | private DeviceDTO children; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.dto; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/8 |
| | | */ |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | @Builder |
| | | public class DeviceHmsDTO implements Cloneable { |
| | | |
| | | private String hmsId; |
| | | |
| | | private String tid; |
| | | |
| | | private String bid; |
| | | |
| | | private String sn; |
| | | |
| | | private Integer level; |
| | | |
| | | private Integer module; |
| | | |
| | | private String key; |
| | | |
| | | private String messageZh; |
| | | |
| | | private String messageEn; |
| | | |
| | | private LocalDateTime createTime; |
| | | |
| | | private LocalDateTime updateTime; |
| | | |
| | | @Override |
| | | public DeviceHmsDTO clone() { |
| | | try { |
| | | return (DeviceHmsDTO) super.clone(); |
| | | } catch (CloneNotSupportedException e) { |
| | | return DeviceHmsDTO.builder() |
| | | .sn(this.sn) |
| | | .bid(this.bid) |
| | | .tid(this.tid) |
| | | .createTime(this.createTime) |
| | | .updateTime(this.updateTime) |
| | | .build(); |
| | | } |
| | | } |
| | | } |
| | |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class TelemetryDTO { |
| | | public class TelemetryDTO<T> { |
| | | |
| | | private TelemetryDeviceDTO host; |
| | | private T host; |
| | | |
| | | private String sn; |
| | | } |
| | |
| | | |
| | | private DeviceModelDTO deviceModel; |
| | | |
| | | @Builder.Default |
| | | private Boolean onlineStatus = true; |
| | | private Boolean onlineStatus; |
| | | |
| | | private String deviceCallsign; |
| | | |
| | |
| | | private String userCallsign; |
| | | |
| | | private IconUrlDTO iconUrls; |
| | | |
| | | private String model; |
| | | |
| | | private Boolean boundStatus; |
| | | |
| | | private String gatewaySn; |
| | | |
| | | private String domain; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.dto; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/18 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class UserListDTO { |
| | | |
| | | private String userId; |
| | | |
| | | private String username; |
| | | |
| | | private String workspaceName; |
| | | |
| | | private String userType; |
| | | |
| | | private String mqttUsername; |
| | | |
| | | private String mqttPassword; |
| | | |
| | | private LocalDateTime createTime; |
| | | } |
| | |
| | | |
| | | @NonNull |
| | | private String password; |
| | | |
| | | @NonNull |
| | | private Integer flag; |
| | | } |
| | |
| | | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
| | | public class WorkspaceDTO { |
| | | |
| | | public static final String DEFAULT_WORKSPACE_ID = "e3dea0f5-37f2-4d79-ae58-490af3228069"; |
| | | |
| | | private Integer id; |
| | | |
| | | private String workspaceId; |
| | |
| | | private String workspaceDesc; |
| | | |
| | | private String platformName; |
| | | |
| | | private String bindCode; |
| | | } |
| | |
| | | |
| | | @TableField(value = "url_select") |
| | | private String urlSelect; |
| | | |
| | | @TableField(value = "user_id") |
| | | private String userId; |
| | | |
| | | @TableField(value = "nickname") |
| | | private String nickname; |
| | | |
| | | @TableField(value = "firmware_version") |
| | | private String firmwareVersion; |
| | | |
| | | @TableField(value = "bound_status") |
| | | private Boolean boundStatus; |
| | | |
| | | @TableField(value = "bound_time") |
| | | private Long boundTime; |
| | | |
| | | @TableField(value = "login_time") |
| | | private Long loginTime; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.entity; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/6 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @TableName(value = "manage_device_hms") |
| | | public class DeviceHmsEntity implements Serializable, Cloneable { |
| | | |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @TableField("hms_id") |
| | | private String hmsId; |
| | | |
| | | @TableField("tid") |
| | | private String tid; |
| | | |
| | | @TableField("bid") |
| | | private String bid; |
| | | |
| | | @TableField("sn") |
| | | private String sn; |
| | | |
| | | @TableField("level") |
| | | private Integer level; |
| | | |
| | | @TableField("module") |
| | | private Integer module; |
| | | |
| | | @TableField("hms_key") |
| | | private String hmsKey; |
| | | |
| | | @TableField("message_zh") |
| | | private String messageZh; |
| | | |
| | | @TableField("message_en") |
| | | private String messageEn; |
| | | |
| | | @TableField("create_time") |
| | | private Long createTime; |
| | | |
| | | @TableField("update_time") |
| | | private Long updateTime; |
| | | |
| | | @Override |
| | | public DeviceHmsEntity clone() { |
| | | try { |
| | | return (DeviceHmsEntity) super.clone(); |
| | | } catch (CloneNotSupportedException e) { |
| | | return DeviceHmsEntity.builder() |
| | | .bid(this.getBid()) |
| | | .tid(this.getTid()) |
| | | .createTime(this.getCreateTime()) |
| | | .updateTime(this.getUpdateTime()) |
| | | .sn(this.getSn()) |
| | | .build(); |
| | | } |
| | | } |
| | | } |
| | |
| | | @TableField(value = "sub_type") |
| | | private Integer subType; |
| | | |
| | | @TableField(value = "version") |
| | | private Integer version; |
| | | @TableField(value = "firmware_version") |
| | | private String firmwareVersion; |
| | | |
| | | @TableField(value = "payload_index") |
| | | private Integer payloadIndex; |
| | |
| | | private String password; |
| | | |
| | | @TableField(value = "workspace_id") |
| | | private Integer workspaceId; |
| | | private String workspaceId; |
| | | |
| | | @TableField(value = "user_type") |
| | | private Integer userType; |
| | |
| | | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateTime; |
| | | |
| | | @TableField(value = "bind_code") |
| | | private String bindCode; |
| | | } |
| | |
| | | |
| | | PAYLOAD(1, "payload"), |
| | | |
| | | DOCK (3, "dock"), |
| | | |
| | | UNKNOWN(-1, "unknown"); |
| | | |
| | | private int val; |
| | |
| | | return val; |
| | | } |
| | | |
| | | public String getDesc() { |
| | | return desc; |
| | | } |
| | | |
| | | public static String getDesc(int val) { |
| | | if (SUB_DEVICE.val == val) { |
| | | return SUB_DEVICE.desc; |
| | |
| | | |
| | | if (PAYLOAD.val == val) { |
| | | return PAYLOAD.desc; |
| | | } |
| | | |
| | | if (DOCK.val == val) { |
| | | return DOCK.desc; |
| | | } |
| | | return UNKNOWN.desc; |
| | | } |
| | |
| | | if (PAYLOAD.desc.equals(desc)) { |
| | | return PAYLOAD.val; |
| | | } |
| | | |
| | | if (DOCK.desc.equals(desc)) { |
| | | return DOCK.val; |
| | | } |
| | | return UNKNOWN.val; |
| | | } |
| | | |
| New file |
| | |
| | | package com.dji.sample.manage.model.enums; |
| | | |
| | | import lombok.Getter; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/7 |
| | | */ |
| | | @Getter |
| | | public enum HmsEnum { |
| | | |
| | | IN_THE_SKY("_in_the_sky", 1); |
| | | |
| | | private int val; |
| | | |
| | | private String text; |
| | | |
| | | HmsEnum(String text, int val) { |
| | | this.text = text; |
| | | this.val = val; |
| | | } |
| | | |
| | | @Getter |
| | | public enum MessageLanguage { |
| | | |
| | | EN("en"), |
| | | |
| | | ZH("zh"); |
| | | |
| | | String language; |
| | | |
| | | MessageLanguage(String language) { |
| | | this.language = language; |
| | | } |
| | | } |
| | | |
| | | @Getter |
| | | public enum DomainType { |
| | | DRONE_NEST("drone_nest"), |
| | | |
| | | DRONE("drone"); |
| | | |
| | | private String domain; |
| | | |
| | | DomainType(String domain) { |
| | | this.domain = domain; |
| | | } |
| | | |
| | | } |
| | | |
| | | @Getter |
| | | public enum HmsFaqIdEnum { |
| | | |
| | | FPV_TIP("fpv_tip_"); |
| | | |
| | | private String text; |
| | | |
| | | HmsFaqIdEnum(String text) { |
| | | this.text = text; |
| | | } |
| | | |
| | | } |
| | | |
| | | @Getter |
| | | public enum HmsBatteryIndexEnum { |
| | | LEFT(0, "left", "左"), |
| | | |
| | | RIGHT(1, "right", "右"), |
| | | |
| | | UNKNOWN(-1, "unknown", "未知"); |
| | | |
| | | private int val; |
| | | |
| | | private String en; |
| | | |
| | | private String zh; |
| | | |
| | | HmsBatteryIndexEnum(int val, String en, String zh) { |
| | | this.val = val; |
| | | this.en = en; |
| | | this.zh = zh; |
| | | } |
| | | |
| | | public static HmsBatteryIndexEnum find(int val) { |
| | | return Arrays.stream(HmsBatteryIndexEnum.values()) |
| | | .filter(battery -> battery.val == val) |
| | | .findAny() |
| | | .orElse(UNKNOWN); |
| | | } |
| | | } |
| | | |
| | | @Getter |
| | | public enum HmsDockCoverIndexEnum { |
| | | LEFT(0, "left", "左"), |
| | | |
| | | RIGHT(1, "right", "右"), |
| | | |
| | | UNKNOWN(-1, "unknown", "未知"); |
| | | |
| | | private int val; |
| | | |
| | | private String en; |
| | | |
| | | private String zh; |
| | | |
| | | HmsDockCoverIndexEnum(int val, String en, String zh) { |
| | | this.val = val; |
| | | this.en = en; |
| | | this.zh = zh; |
| | | } |
| | | |
| | | public static HmsDockCoverIndexEnum find(int val) { |
| | | return Arrays.stream(HmsDockCoverIndexEnum.values()) |
| | | .filter(dockCover -> dockCover.val == val) |
| | | .findAny() |
| | | .orElse(UNKNOWN); |
| | | } |
| | | } |
| | | |
| | | @Getter |
| | | public enum HmsChargingRodIndexEnum { |
| | | |
| | | FRONT(0, "front", "前"), |
| | | |
| | | BACK(1, "back", "后"), |
| | | |
| | | LEFT(2, "left", "左"), |
| | | |
| | | RIGHT(3, "right", "右"), |
| | | |
| | | UNKNOWN(-1, "unknown", "未知"); |
| | | |
| | | private int val; |
| | | |
| | | private String en; |
| | | |
| | | private String zh; |
| | | |
| | | HmsChargingRodIndexEnum(int val, String en, String zh) { |
| | | this.val = val; |
| | | this.en = en; |
| | | this.zh = zh; |
| | | } |
| | | |
| | | public static HmsChargingRodIndexEnum find(int val) { |
| | | return Arrays.stream(HmsChargingRodIndexEnum.values()) |
| | | .filter(rod -> rod.val == val) |
| | | .findAny() |
| | | .orElse(UNKNOWN); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.enums; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/29 |
| | | */ |
| | | public enum PayloadModelEnum { |
| | | |
| | | Z30("Z30", "20-0"), |
| | | |
| | | XT2("XT2", "26-0"), |
| | | |
| | | XTS("XTS", "41-0"), |
| | | |
| | | H20("H20", "42-0"), |
| | | |
| | | H20T("H20T", "43-0"), |
| | | |
| | | P1("P1", "50-65535"), |
| | | |
| | | M30("M30", "52-0"), |
| | | |
| | | M30T("M30T", "53-0"), |
| | | |
| | | H20N("H20N", "61-0"), |
| | | |
| | | DOCK("DOCK", "165-0"), |
| | | |
| | | L1("L1", "90742-0"); |
| | | |
| | | private String model; |
| | | |
| | | private String index; |
| | | |
| | | PayloadModelEnum(String model, String index) { |
| | | this.model = model; |
| | | this.index = index; |
| | | } |
| | | |
| | | public String getModel() { |
| | | return model; |
| | | } |
| | | |
| | | public String getIndex() { |
| | | return index; |
| | | } |
| | | |
| | | public static List<String> getAllModel() { |
| | | return Arrays.stream(PayloadModelEnum.values()).map(PayloadModelEnum::getModel).collect(Collectors.toList()); |
| | | } |
| | | |
| | | public static List<String> getAllIndex() { |
| | | return Arrays.stream(PayloadModelEnum.values()).map(PayloadModelEnum::getIndex).collect(Collectors.toList()); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | public enum UserTypeEnum { |
| | | |
| | | WEB(1), |
| | | WEB(1, "Web"), |
| | | |
| | | PILOT(2); |
| | | PILOT(2, "Pilot"), |
| | | |
| | | UNKNOWN(-1, "Unknown"); |
| | | |
| | | private int val; |
| | | |
| | | private String desc; |
| | | |
| | | UserTypeEnum(int val) { |
| | | UserTypeEnum(int val, String desc) { |
| | | this.val = val; |
| | | this.desc = desc; |
| | | } |
| | | |
| | | public int getVal() { |
| | | return val; |
| | | return this.val; |
| | | } |
| | | |
| | | public String getDesc() { |
| | | return this.desc; |
| | | } |
| | | |
| | | public static UserTypeEnum find(int val) { |
| | | if (val == WEB.val) { |
| | | return WEB; |
| | | } |
| | | if (val == PILOT.val) { |
| | | return PILOT; |
| | | } |
| | | return UNKNOWN; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.param; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonProperty; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/8 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class DeviceHmsQueryParam implements Serializable { |
| | | |
| | | @JsonProperty("device_sn") |
| | | private Set<String> deviceSn; |
| | | |
| | | @JsonProperty("begin_time") |
| | | private Long beginTime; |
| | | |
| | | @JsonProperty("end_time") |
| | | private Long endTime; |
| | | |
| | | private String language; |
| | | |
| | | private String message; |
| | | |
| | | private Long page; |
| | | |
| | | @JsonProperty("page_size") |
| | | private Long pageSize; |
| | | |
| | | private Integer level; |
| | | |
| | | @JsonProperty("update_time") |
| | | private Long updateTime; |
| | | } |
| | |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * The object of the device query field. |
| | | * |
| | |
| | | |
| | | private Integer subType; |
| | | |
| | | private Integer domain; |
| | | private List<Integer> domains; |
| | | |
| | | private String childSn; |
| | | |
| | | private Boolean boundStatus; |
| | | |
| | | private boolean orderBy; |
| | | |
| | | private boolean isAsc; |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Data |
| | | public class AlternateLandPointReceiver { |
| | | |
| | | private Double latitude; |
| | | |
| | | private Double longitude; |
| | | |
| | | private Double safeLandHeight; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/13 |
| | | */ |
| | | @Data |
| | | public class BindDeviceReceiver { |
| | | |
| | | private String deviceBindingCode; |
| | | |
| | | private String organizationId; |
| | | |
| | | private String deviceCallsign; |
| | | |
| | | private String sn; |
| | | |
| | | private String deviceModelKey; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import com.fasterxml.jackson.annotation.JsonInclude; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/14 |
| | | */ |
| | | @Builder |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | @JsonInclude |
| | | public class BindStatusReceiver { |
| | | |
| | | private String sn; |
| | | |
| | | private Boolean isDeviceBindOrganization; |
| | | |
| | | private String organizationId; |
| | | |
| | | private String organizationName; |
| | | |
| | | private String deviceCallsign; |
| | | } |
| | |
| | | |
| | | private String deviceSn; |
| | | |
| | | private Integer flightMode; |
| | | |
| | | private Integer flightStatus; |
| | | |
| | | private Double homeLatitude; |
| | | |
| | | private Double homeLongitude; |
| | | |
| | | private Integer lowBatteryWarningThreshold; |
| | | |
| | | private Integer positionMode; |
| | | |
| | | private Integer seriousLowBatteryWarningThreshold; |
| | | |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/6 |
| | | */ |
| | | @Data |
| | | public class DeviceHmsReceiver { |
| | | |
| | | private String code; |
| | | |
| | | private String deviceType; |
| | | |
| | | private String domainType; |
| | | |
| | | private Integer imminent; |
| | | |
| | | private Integer inTheSky; |
| | | |
| | | private Integer level; |
| | | |
| | | private Integer module; |
| | | |
| | | private HmsArgsReceiver args; |
| | | } |
| | |
| | | |
| | | private String sn; |
| | | |
| | | private Integer version; |
| | | |
| | | private Integer workMode; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/17 |
| | | */ |
| | | @Data |
| | | public class DockMediaFileDetailReceiver { |
| | | |
| | | private Integer remainUpload; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/17 |
| | | */ |
| | | @Data |
| | | public class DockSdrReceiver { |
| | | |
| | | private Integer downQuality; |
| | | |
| | | private Double frequencyBand; |
| | | |
| | | private Integer upQuality; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Data |
| | | public class DockSubDeviceReceiver { |
| | | |
| | | private String deviceSn; |
| | | |
| | | private Integer deviceOnlineStatus; |
| | | |
| | | private Integer devicePaired; |
| | | |
| | | private String deviceModelKey; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Data |
| | | public class DroneChargeStateReceiver { |
| | | |
| | | private Integer state; |
| | | |
| | | private Integer capacityPercent; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/4/28 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class FirmwareVersionReceiver { |
| | | |
| | | private String firmwareVersion; |
| | | |
| | | private Integer compatibleStatus; |
| | | |
| | | private Integer firmwareUpgradeStatus; |
| | | |
| | | private String sn; |
| | | |
| | | private DeviceDomainEnum domain; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/6 |
| | | */ |
| | | @Data |
| | | public class HmsArgsReceiver { |
| | | |
| | | private Long componentIndex; |
| | | |
| | | private Integer sensorIndex; |
| | | |
| | | private Integer alarmId; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/24 |
| | | */ |
| | | @Data |
| | | public class LiveCapacityReceiver { |
| | | |
| | | private Integer availableVideoNumber; |
| | | |
| | | private Integer coexistVideoNumberMax; |
| | | |
| | | private List<CapacityDeviceReceiver> deviceList; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Data |
| | | public class NetworkStateReceiver { |
| | | |
| | | private Integer type; |
| | | |
| | | private Integer quality; |
| | | |
| | | private float rate; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/13 |
| | | */ |
| | | @Data |
| | | public class OrganizationGetReceiver { |
| | | |
| | | private String deviceBindingCode; |
| | | |
| | | private String organizationId; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Data |
| | | public class OsdDockReceiver { |
| | | |
| | | private NetworkStateReceiver networkState; |
| | | |
| | | private Integer droneInDock; |
| | | |
| | | private DroneChargeStateReceiver droneChargeState; |
| | | |
| | | private Integer rainfall; |
| | | |
| | | private Float windSpeed; |
| | | |
| | | private Float environmentTemperature; |
| | | |
| | | private Integer environmentHumidity; |
| | | |
| | | private Float temperature; |
| | | |
| | | private Integer humidity; |
| | | |
| | | private Double latitude; |
| | | |
| | | private Double longitude; |
| | | |
| | | private Double height; |
| | | |
| | | private AlternateLandPointReceiver alternateLandPoint; |
| | | |
| | | private Integer jobNumber; |
| | | |
| | | private Integer accTime; |
| | | |
| | | private Long firstPowerOn; |
| | | |
| | | private PositionStateReceiver positionState; |
| | | |
| | | private StorageReceiver storage; |
| | | |
| | | private Integer electricSupplyVoltage; |
| | | |
| | | private Integer workingVoltage; |
| | | |
| | | private Integer workingCurrent; |
| | | |
| | | private Integer backupBatteryVoltage; |
| | | |
| | | private Integer modeCode; |
| | | |
| | | private Integer coverState; |
| | | |
| | | private Integer supplementLightState; |
| | | |
| | | private Integer putterState; |
| | | |
| | | private DockSubDeviceReceiver subDevice; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/17 |
| | | */ |
| | | @Data |
| | | public class OsdDockTransmissionReceiver { |
| | | |
| | | private Integer flighttaskStepCode; |
| | | |
| | | private DockMediaFileDetailReceiver mediaFileDetail; |
| | | |
| | | private DockSdrReceiver sdr; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/6 |
| | | */ |
| | | @Data |
| | | public class OsdPayloadReceiver { |
| | | |
| | | private String payloadIndex; |
| | | |
| | | private Double gimbalPitch; |
| | | |
| | | private Double gimbalRoll; |
| | | |
| | | private Double gimbalYaw; |
| | | |
| | | private Double measureTargetAltitude; |
| | | |
| | | private Double measureTargetDistance; |
| | | |
| | | private Double measureTargetLatitude; |
| | | |
| | | private Double measureTargetLongitude; |
| | | |
| | | private Integer measureTargetErrorState; |
| | | |
| | | private Integer version; |
| | | |
| | | } |
| | |
| | | import com.fasterxml.jackson.databind.annotation.JsonNaming; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | | * @version 0.1 |
| | |
| | | |
| | | private Double windDirection; |
| | | |
| | | private Double windSpeed; |
| | | private Float windSpeed; |
| | | |
| | | private PositionStateReceiver positionState; |
| | | |
| | | private List<OsdPayloadReceiver> payloads; |
| | | |
| | | private StorageReceiver storage; |
| | | } |
| | |
| | | @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
| | | public class PositionStateReceiver { |
| | | |
| | | private Integer isCalibration; |
| | | |
| | | private Integer gpsNumber; |
| | | |
| | | private Integer isFixed; |
| | |
| | | |
| | | private String sn; |
| | | |
| | | private Integer domain; |
| | | |
| | | private Integer type; |
| | | |
| | | @JsonProperty(value = "sub_type") |
| New file |
| | |
| | | package com.dji.sample.manage.model.receiver; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Data |
| | | public class StorageReceiver { |
| | | |
| | | private Long total; |
| | | |
| | | private Long used; |
| | | } |
| | |
| | | |
| | | private Integer downloadQuality; |
| | | |
| | | private Integer frequencyBand; |
| | | private Double frequencyBand; |
| | | |
| | | private Integer upwardQuality; |
| | | |
| | |
| | | import com.dji.sample.manage.model.dto.CapacityVideoDTO; |
| | | import com.dji.sample.manage.model.receiver.CapacityVideoReceiver; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | | * @date 2021/11/19 |
| | |
| | | public interface ICameraVideoService { |
| | | |
| | | /** |
| | | * Queries all lens data contained in the camera based on camera id. |
| | | * @param cameraId |
| | | * @return |
| | | * Convert the received lens capability object into lens data transfer object. |
| | | * @param receiver |
| | | * @return data transfer object |
| | | */ |
| | | List<CapacityVideoDTO> getCameraVideosByCameraId(Integer cameraId); |
| | | |
| | | /** |
| | | * Deletes all the data of this lens, according to the lens id. |
| | | * @param ids A collection of lens ids. |
| | | * @return true |
| | | */ |
| | | Boolean deleteCameraVideosById(List<Integer> ids); |
| | | |
| | | /** |
| | | * Save the live capability of all lenses of this camera. |
| | | * @param capacityVideoReceivers live capability of lens |
| | | * @param cameraId |
| | | * @return |
| | | */ |
| | | Boolean saveCameraVideoDTOList(List<CapacityVideoReceiver> capacityVideoReceivers, Integer cameraId); |
| | | |
| | | CapacityVideoDTO receiver2Dto(CapacityVideoReceiver receiver); |
| | | } |
| | |
| | | List<CapacityCameraDTO> getCapacityCameraByDeviceSn(String deviceSn); |
| | | |
| | | /** |
| | | * Query whether this camera data has been saved based on the device sn and camera location. |
| | | * @param deviceSn |
| | | * @param cameraIndex |
| | | * @return |
| | | */ |
| | | Boolean checkExist(String deviceSn, String cameraIndex); |
| | | |
| | | /** |
| | | * Delete all live capability data for this device based on the device sn. |
| | | * @param deviceSn |
| | | * @return |
| | |
| | | * Save the live capability data of the device. |
| | | * @param capacityCameraReceivers |
| | | * @param deviceSn |
| | | */ |
| | | void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn); |
| | | |
| | | /** |
| | | * Convert the received camera capability object into camera data transfer object. |
| | | * @param receiver |
| | | * @return |
| | | */ |
| | | Boolean saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn); |
| | | |
| | | CapacityCameraDTO receiver2Dto(CapacityCameraReceiver receiver); |
| | | } |
| | |
| | | |
| | | /** |
| | | * Query the type data of the device based on domain, device type and sub type. |
| | | * @param domain |
| | | * @param deviceType |
| | | * @param subType |
| | | * @return |
| | | */ |
| | | Optional<DeviceDictionaryDTO> getOneDictionaryInfoByDomainTypeSubType( |
| | | Integer domain, Integer deviceType, Integer subType); |
| | | Optional<DeviceDictionaryDTO> getOneDictionaryInfoByTypeSubType(Integer deviceType, Integer subType); |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.service; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.manage.model.dto.DeviceHmsDTO; |
| | | import com.dji.sample.manage.model.param.DeviceHmsQueryParam; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/6 |
| | | */ |
| | | public interface IDeviceHmsService { |
| | | |
| | | void handleHms(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | |
| | | PaginationData<DeviceHmsDTO> getDeviceHmsByParam(DeviceHmsQueryParam param); |
| | | |
| | | void updateUnreadHms(String deviceSn); |
| | | } |
| | |
| | | |
| | | import com.dji.sample.manage.model.dto.DevicePayloadDTO; |
| | | import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; |
| | | import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | * @param deviceSns |
| | | */ |
| | | void deletePayloadsByDeviceSn(List<String> deviceSns); |
| | | |
| | | /** |
| | | * Update the firmware version information of the payload. |
| | | * @param receiver |
| | | */ |
| | | void updateFirmwareVersion(FirmwareVersionReceiver receiver); |
| | | } |
| | |
| | | package com.dji.sample.manage.service; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.TopologyDeviceDTO; |
| | | import com.dji.sample.manage.model.param.DeviceQueryParam; |
| | | import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; |
| | | import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | |
| | | * @param sessions The collection of connection objects on the pilot side. |
| | | * @param sn |
| | | */ |
| | | void pushDeviceOnlineTopo(Collection<ConcurrentWebSocketSession> sessions, String sn); |
| | | void pushDeviceOnlineTopo(Collection<ConcurrentWebSocketSession> sessions, String sn, String gatewaySn); |
| | | |
| | | /** |
| | | * Query the information of the device according to the sn of the device. |
| | |
| | | * it also broadcasts a push of device online, offline and topology update to PILOT via websocket, |
| | | * and PILOT will get the device topology list again after receiving the push. |
| | | * @param workspaceId |
| | | * @param gatewaySn |
| | | * @param sn |
| | | */ |
| | | void pushDeviceOfflineTopo(String workspaceId, String gatewaySn); |
| | | void pushDeviceOfflineTopo(String workspaceId, String sn); |
| | | |
| | | /** |
| | | * When the server receives the request of any device online, offline and topology update in the same workspace, |
| | |
| | | * @param deviceSn |
| | | * @param gatewaySn |
| | | */ |
| | | void pushDeviceOnlineTopo(String workspaceId, String deviceSn, String gatewaySn); |
| | | void pushDeviceOnlineTopo(String workspaceId, String gatewaySn, String deviceSn); |
| | | |
| | | /** |
| | | * Handle messages from the osd topic. |
| | |
| | | */ |
| | | void handleOSD(String topic, byte[] payload); |
| | | |
| | | /** |
| | | * Update the device information. |
| | | * @param deviceDTO |
| | | * @return |
| | | */ |
| | | Boolean updateDevice(DeviceDTO deviceDTO); |
| | | |
| | | /** |
| | | * Bind devices to organizations and people. |
| | | * @param device |
| | | */ |
| | | Boolean bindDevice(DeviceDTO device); |
| | | |
| | | /** |
| | | * Handle dock binding status requests. |
| | | * Note: If your business does not need to bind the dock to the organization, |
| | | * you can directly reply to the successful message without implementing business logic. |
| | | * @param receiver |
| | | * @param headers |
| | | */ |
| | | void bindStatus(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | |
| | | /** |
| | | * Handle dock binding requests. |
| | | * Note: If your business does not need to bind the dock to the organization, |
| | | * you can directly reply to the successful message without implementing business logic. |
| | | * @param receiver |
| | | * @param headers |
| | | */ |
| | | void bindDevice(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | |
| | | /** |
| | | * Get the binding devices list in one workspace. |
| | | * @param workspaceId |
| | | * @param page |
| | | * @param pageSize |
| | | * @param domain |
| | | * @return |
| | | */ |
| | | PaginationData<DeviceDTO> getBoundDevicesWithDomain(String workspaceId, Long page, Long pageSize, String domain); |
| | | |
| | | /** |
| | | * Unbind device base on device's sn. |
| | | * @param deviceSn |
| | | */ |
| | | void unbindDevice(String deviceSn); |
| | | |
| | | /** |
| | | * Get device information based on device's sn. |
| | | * @param sn device's sn |
| | | * @return device |
| | | */ |
| | | Optional<DeviceDTO> getDeviceBySn(String sn); |
| | | |
| | | /** |
| | | * Update the firmware version information of the device or payload. |
| | | * @param receiver |
| | | */ |
| | | void updateFirmwareVersion(FirmwareVersionReceiver receiver); |
| | | } |
| | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.manage.model.dto.CapacityDeviceDTO; |
| | | import com.dji.sample.manage.model.dto.LiveTypeDTO; |
| | | import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver; |
| | | import com.dji.sample.manage.model.receiver.LiveCapacityReceiver; |
| | | |
| | | import java.util.List; |
| | | |
| | |
| | | List<CapacityDeviceDTO> getLiveCapacity(String workspaceId); |
| | | |
| | | /** |
| | | * Save live capability data from drone. |
| | | * @param capacityDeviceReceiver |
| | | * @return |
| | | * Save live capability data. |
| | | * @param liveCapacityReceiver |
| | | */ |
| | | Boolean saveLiveCapacity(CapacityDeviceReceiver capacityDeviceReceiver); |
| | | void saveLiveCapacity(LiveCapacityReceiver liveCapacityReceiver); |
| | | |
| | | /** |
| | | * Initiate a live streaming by publishing mqtt message. |
| | |
| | | package com.dji.sample.manage.service; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | |
| | | import java.util.Collection; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | |
| | | * @param sn |
| | | */ |
| | | void pushTelemetryData(String workspaceId, Object osdData, String sn); |
| | | |
| | | /** |
| | | * Handle device's osd data. |
| | | * @param receiver |
| | | * @param webSessions |
| | | * @param wsMessage |
| | | */ |
| | | void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, |
| | | Collection<ConcurrentWebSocketSession> webSessions, CustomWebSocketMessage<TelemetryDTO> wsMessage); |
| | | |
| | | } |
| | |
| | | package com.dji.sample.manage.service; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.manage.model.dto.UserDTO; |
| | | import com.dji.sample.manage.model.dto.UserListDTO; |
| | | |
| | | import java.util.Optional; |
| | | |
| | |
| | | * Verify the username and password to log in. |
| | | * @param username |
| | | * @param password |
| | | * @param flag |
| | | * @return |
| | | */ |
| | | ResponseResult userLogin(String username, String password); |
| | | ResponseResult userLogin(String username, String password, Integer flag); |
| | | |
| | | /** |
| | | * Create a user object containing a new token. |
| | |
| | | * @return |
| | | */ |
| | | Optional<UserDTO> refreshToken(String token); |
| | | |
| | | /** |
| | | * Query information about all users in a workspace. |
| | | * @param workspaceId uuid |
| | | * @return |
| | | */ |
| | | PaginationData<UserListDTO> getUsersByWorkspaceId(long page, long pageSize, String workspaceId); |
| | | |
| | | Boolean updateUser(String workspaceId, String userId, UserListDTO user); |
| | | } |
| | |
| | | package com.dji.sample.manage.service; |
| | | |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.manage.model.dto.WorkspaceDTO; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | |
| | | import java.util.Optional; |
| | | |
| | | public interface IWorkspaceService { |
| | | |
| | | /** |
| | | * Query the workspace information based on the primary key id of the database. |
| | | * @param id primary key id |
| | | * @return |
| | | */ |
| | | Optional<WorkspaceDTO> getWorkspaceById(int id); |
| | | |
| | | /** |
| | | * Query the information of a workspace based on its workspace id. |
| | |
| | | * @return |
| | | */ |
| | | Optional<WorkspaceDTO> getWorkspaceByWorkspaceId(String workspaceId); |
| | | |
| | | /** |
| | | * Query the workspace of a workspace based on bind code. |
| | | * @param bindCode |
| | | * @return |
| | | */ |
| | | Optional<WorkspaceDTO> getWorkspaceNameByBindCode(String bindCode); |
| | | |
| | | /** |
| | | * Handle the request for obtaining the organization information corresponding to the device binding. |
| | | * Note: If your business does not need to bind the dock to the organization, |
| | | * you can directly reply to the successful message without implementing business logic. |
| | | * @param receiver |
| | | */ |
| | | void replyOrganizationGet(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | } |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.model.WebSocketManager; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.service.ITSAService; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | |
| | | import java.util.Collection; |
| | |
| | | |
| | | protected AbstractTSAService tsaService; |
| | | |
| | | @Autowired |
| | | protected ObjectMapper mapper; |
| | | |
| | | @Autowired |
| | | protected RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | public AbstractTSAService(AbstractTSAService tsaService) { |
| | | this.tsaService = tsaService; |
| | | } |
| | |
| | | @Override |
| | | public void pushTelemetryData(String workspaceId, Object osdData, String sn) { |
| | | // All connected accounts on the pilot side of this workspace. |
| | | Collection<ConcurrentWebSocketSession> pilotSessions = WebSocketManager |
| | | .getValueWithWorkspaceAndUserType( |
| | | workspaceId, UserTypeEnum.PILOT.getVal()); |
| | | Collection<ConcurrentWebSocketSession> pilotSessions = webSocketManageService |
| | | .getValueWithWorkspaceAndUserType(workspaceId, UserTypeEnum.PILOT.getVal()); |
| | | |
| | | TelemetryDTO telemetry = TelemetryDTO.builder() |
| | | .sn(sn) |
| | |
| | | public abstract void pushTelemetryData(Collection<ConcurrentWebSocketSession> sessions, |
| | | CustomWebSocketMessage<TelemetryDTO> message, Object Object); |
| | | |
| | | protected abstract void handleOSD(TopicStateReceiver receiver, String sn, String workspaceId, JsonNode hostNode, |
| | | Collection<ConcurrentWebSocketSession> webSessions, CustomWebSocketMessage wsMessage) |
| | | throws JsonProcessingException; |
| | | public abstract void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, |
| | | Collection<ConcurrentWebSocketSession> webSessions, CustomWebSocketMessage<TelemetryDTO> wsMessage); |
| | | } |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.dji.sample.manage.dao.ICameraVideoMapper; |
| | | import com.dji.sample.manage.model.dto.CapacityVideoDTO; |
| | | import com.dji.sample.manage.model.entity.CameraVideoEntity; |
| | | import com.dji.sample.manage.model.receiver.CapacityVideoReceiver; |
| | | import com.dji.sample.manage.service.ICameraVideoService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | import java.util.UUID; |
| | | |
| | | /** |
| | | * @author sean.zhou |
| | |
| | | * @date 2021/11/19 |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | //@Transactional |
| | | public class CameraVideoServiceImpl implements ICameraVideoService { |
| | | |
| | | @Autowired |
| | | private ICameraVideoMapper mapper; |
| | | |
| | | @Override |
| | | public List<CapacityVideoDTO> getCameraVideosByCameraId(Integer cameraId) { |
| | | return mapper.selectList( |
| | | new LambdaQueryWrapper<CameraVideoEntity>() |
| | | .eq(CameraVideoEntity::getCameraId, cameraId)) |
| | | .stream() |
| | | .map(this::entityConvertToDto) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteCameraVideosById(List<Integer> ids) { |
| | | if (ids.isEmpty()) { |
| | | return true; |
| | | } |
| | | return mapper.deleteBatchIds(ids) > 0; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean saveCameraVideoDTOList(List<CapacityVideoReceiver> capacityVideoReceivers, Integer cameraId) { |
| | | for (CapacityVideoReceiver videoDTO : capacityVideoReceivers) { |
| | | CameraVideoEntity videoEntity = videoDTOConvertToEntity(videoDTO); |
| | | videoEntity.setCameraId(cameraId); |
| | | int saveId = this.saveOneCameraVideoEntity(videoEntity); |
| | | if (saveId <= 0) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Save the live capability of the lens of this camera. |
| | | * @param entity lens data |
| | | * @return |
| | | */ |
| | | private Integer saveOneCameraVideoEntity(CameraVideoEntity entity) { |
| | | return mapper.insert(entity) > 0 ? entity.getId() : 0; |
| | | } |
| | | |
| | | /** |
| | | * Convert the received lens capability object into a database entity object. |
| | | * @param dto received lens object |
| | | * @return entity |
| | | */ |
| | | private CameraVideoEntity videoDTOConvertToEntity(CapacityVideoReceiver dto) { |
| | | CameraVideoEntity.CameraVideoEntityBuilder builder = CameraVideoEntity.builder(); |
| | | if (dto != null) { |
| | | builder |
| | | .videoIndex(dto.getVideoIndex()) |
| | | .videoType(dto.getVideoType()); |
| | | } |
| | | return builder.build(); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into lens data transfer object. |
| | | * @param entity |
| | | * @return data transfer object |
| | | */ |
| | | private CapacityVideoDTO entityConvertToDto(CameraVideoEntity entity) { |
| | | public CapacityVideoDTO receiver2Dto(CapacityVideoReceiver receiver) { |
| | | CapacityVideoDTO.CapacityVideoDTOBuilder builder = CapacityVideoDTO.builder(); |
| | | |
| | | if (entity != null) { |
| | | builder |
| | | .id(entity.getId()) |
| | | .index(entity.getVideoIndex()) |
| | | .type(entity.getVideoType()); |
| | | if (receiver != null) { |
| | | builder.id(UUID.randomUUID().toString()) |
| | | .index(receiver.getVideoIndex()) |
| | | .type(receiver.getVideoType()); |
| | | } |
| | | return builder.build(); |
| | | } |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.dji.sample.manage.dao.ICapacityCameraMapper; |
| | | import com.dji.sample.component.mqtt.model.StateDataEnum; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.manage.model.dto.CapacityCameraDTO; |
| | | import com.dji.sample.manage.model.dto.CapacityVideoDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; |
| | | import com.dji.sample.manage.model.entity.CapacityCameraEntity; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.receiver.CapacityCameraReceiver; |
| | | import com.dji.sample.manage.service.ICameraVideoService; |
| | | import com.dji.sample.manage.service.ICapacityCameraService; |
| | | import com.dji.sample.manage.service.IDeviceDictionaryService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | * @version 0.1 |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | //@Transactional |
| | | public class CapacityCameraServiceImpl implements ICapacityCameraService { |
| | | |
| | | @Autowired |
| | | private ICapacityCameraMapper mapper; |
| | | |
| | | @Autowired |
| | | private ICameraVideoService cameraVideoService; |
| | |
| | | @Autowired |
| | | private IDeviceDictionaryService dictionaryService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public List<CapacityCameraDTO> getCapacityCameraByDeviceSn(String deviceSn) { |
| | | List<CapacityCameraDTO> capacityCamerasList = mapper.selectList( |
| | | new LambdaQueryWrapper<CapacityCameraEntity>() |
| | | .eq(CapacityCameraEntity::getDeviceSn, deviceSn)) |
| | | .stream() |
| | | .map(this::entityConvertToDto) |
| | | .collect(Collectors.toList()); |
| | | capacityCamerasList.forEach(capacityCamera -> { |
| | | // Set the lens data for this camera. |
| | | capacityCamera.setVideosList( |
| | | cameraVideoService.getCameraVideosByCameraId(capacityCamera.getId())); |
| | | }); |
| | | |
| | | return capacityCamerasList; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean checkExist(String deviceSn, String cameraIndex) { |
| | | return mapper.selectOne( |
| | | new LambdaQueryWrapper<CapacityCameraEntity>() |
| | | .eq(CapacityCameraEntity::getDeviceSn, deviceSn) |
| | | .eq(CapacityCameraEntity::getCameraIndex, cameraIndex) |
| | | .last(" limit 1")) != null; |
| | | return (List<CapacityCameraDTO>) redisOps.hashGet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteCapacityCameraByDeviceSn(String deviceSn) { |
| | | |
| | | List<CapacityCameraDTO> capacityCamerasList = this.getCapacityCameraByDeviceSn(deviceSn); |
| | | // Return directly if no data exists in the database. |
| | | if (capacityCamerasList.isEmpty()) { |
| | | return true; |
| | | } |
| | | |
| | | List<Integer> cameraIds = capacityCamerasList |
| | | .stream() |
| | | .map(CapacityCameraDTO::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | List<Integer> videoIds = capacityCamerasList |
| | | .stream() |
| | | .flatMap(camera -> camera.getVideosList().stream()) |
| | | .map(CapacityVideoDTO::getId) |
| | | .collect(Collectors.toList()); |
| | | |
| | | return mapper.deleteBatchIds(cameraIds) > 0 && cameraVideoService.deleteCameraVideosById(videoIds); |
| | | return redisOps.hashDel(StateDataEnum.LIVE_CAPACITY.getDesc(), new String[]{deviceSn}); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn) { |
| | | for (CapacityCameraReceiver cameraDTO : capacityCameraReceivers) { |
| | | CapacityCameraEntity cameraEntity = receiverConvertToEntity(cameraDTO); |
| | | cameraEntity.setDeviceSn(deviceSn); |
| | | int cameraId = this.saveOneCapacityCameraEntity(cameraEntity); |
| | | if (cameraId <= 0) { |
| | | continue; |
| | | } |
| | | boolean saveVideo = cameraVideoService.saveCameraVideoDTOList( |
| | | cameraDTO.getVideosList(), cameraId); |
| | | |
| | | if (!saveVideo) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | public void saveCapacityCameraReceiverList(List<CapacityCameraReceiver> capacityCameraReceivers, String deviceSn) { |
| | | List<CapacityCameraDTO> capacity = capacityCameraReceivers.stream() |
| | | .map(this::receiver2Dto).collect(Collectors.toList()); |
| | | redisOps.hashSet(StateDataEnum.LIVE_CAPACITY.getDesc(), deviceSn, capacity); |
| | | } |
| | | |
| | | /** |
| | | * Save the camera live capability data of the device. |
| | | * @param cameraEntity |
| | | * @return |
| | | */ |
| | | private Integer saveOneCapacityCameraEntity(CapacityCameraEntity cameraEntity) { |
| | | boolean exist = checkExist( |
| | | cameraEntity.getDeviceSn(), cameraEntity.getCameraIndex()); |
| | | if (exist) { |
| | | return -1; |
| | | } |
| | | return mapper.insert(cameraEntity) > 0 ? cameraEntity.getId() : 0; |
| | | } |
| | | |
| | | /** |
| | | * Convert the received camera capability object into a database entity object. |
| | | * @param receiver |
| | | * @return |
| | | */ |
| | | private CapacityCameraEntity receiverConvertToEntity(CapacityCameraReceiver receiver) { |
| | | CapacityCameraEntity.CapacityCameraEntityBuilder builder = CapacityCameraEntity.builder(); |
| | | @Override |
| | | public CapacityCameraDTO receiver2Dto(CapacityCameraReceiver receiver) { |
| | | CapacityCameraDTO.CapacityCameraDTOBuilder builder = CapacityCameraDTO.builder(); |
| | | if (receiver == null) { |
| | | return builder.build(); |
| | | } |
| | |
| | | // type-subType-index |
| | | if (indexArr.length == 3) { |
| | | Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService |
| | | .getOneDictionaryInfoByDomainTypeSubType( |
| | | DeviceDomainEnum.PAYLOAD.getVal(), indexArr[0], indexArr[1]); |
| | | .getOneDictionaryInfoByTypeSubType(indexArr[0], indexArr[1]); |
| | | dictionaryOpt.ifPresent(dictionary -> |
| | | builder.name(dictionary.getDeviceName())); |
| | | } |
| | | return builder |
| | | .availableVideoNumber(receiver.getAvailableVideoNumber()) |
| | | .coexistVideoNumberMax(receiver.getCoexistVideoNumberMax()) |
| | | .cameraIndex(receiver.getCameraIndex()) |
| | | .id(UUID.randomUUID().toString()) |
| | | .videosList(receiver.getVideosList() |
| | | .stream() |
| | | .map(cameraVideoService::receiver2Dto) |
| | | .collect(Collectors.toList())) |
| | | .index(receiver.getCameraIndex()) |
| | | .build(); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into camera data transfer object. |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private CapacityCameraDTO entityConvertToDto(CapacityCameraEntity entity) { |
| | | CapacityCameraDTO.CapacityCameraDTOBuilder builder = CapacityCameraDTO.builder(); |
| | | |
| | | if (entity != null) { |
| | | builder |
| | | .id(entity.getId()) |
| | | .name(entity.getName()) |
| | | .description(entity.getDescription()) |
| | | .deviceSn(entity.getDeviceSn()) |
| | | .index(entity.getCameraIndex()) |
| | | .build(); |
| | | } |
| | | return builder.build(); |
| | | } |
| | | } |
| | |
| | | private IDeviceDictionaryMapper mapper; |
| | | |
| | | @Override |
| | | public Optional<DeviceDictionaryDTO> getOneDictionaryInfoByDomainTypeSubType( |
| | | Integer domain, Integer deviceType, Integer subType) { |
| | | if (domain == null || deviceType == null || subType == null) { |
| | | public Optional<DeviceDictionaryDTO> getOneDictionaryInfoByTypeSubType(Integer deviceType, Integer subType) { |
| | | if (deviceType == null || subType == null) { |
| | | return Optional.empty(); |
| | | } |
| | | return Optional.ofNullable( |
| | | entityConvertToDTO( |
| | | mapper.selectOne( |
| | | new LambdaQueryWrapper<DeviceDictionaryEntity>() |
| | | .eq(DeviceDictionaryEntity::getDomain, domain) |
| | | .eq(DeviceDictionaryEntity::getDeviceType, deviceType) |
| | | .eq(DeviceDictionaryEntity::getSubType, subType)))); |
| | | } |
| New file |
| | |
| | | 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.component.mqtt.model.ChannelName; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.MapKeyConst; |
| | | import com.dji.sample.component.mqtt.model.TopicConst; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.service.impl.SendMessageServiceImpl; |
| | | import com.dji.sample.component.websocket.service.impl.WebSocketManageServiceImpl; |
| | | import com.dji.sample.manage.dao.IDeviceHmsMapper; |
| | | import com.dji.sample.manage.model.common.HmsJsonUtil; |
| | | import com.dji.sample.manage.model.common.HmsMessage; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceHmsDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | import com.dji.sample.manage.model.entity.DeviceHmsEntity; |
| | | import com.dji.sample.manage.model.enums.HmsEnum; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.model.param.DeviceHmsQueryParam; |
| | | import com.dji.sample.manage.model.receiver.DeviceHmsReceiver; |
| | | import com.dji.sample.manage.model.receiver.HmsArgsReceiver; |
| | | import com.dji.sample.manage.service.IDeviceHmsService; |
| | | 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.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.time.Instant; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/7/6 |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | public class DeviceHmsServiceImpl implements IDeviceHmsService { |
| | | |
| | | @Autowired |
| | | private IDeviceHmsMapper mapper; |
| | | |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private SendMessageServiceImpl sendMessageService; |
| | | |
| | | @Autowired |
| | | private WebSocketManageServiceImpl webSocketManageService; |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_HMS) |
| | | public void handleHms(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<DeviceHmsDTO> getDeviceHmsByParam(DeviceHmsQueryParam param) { |
| | | LambdaQueryWrapper<DeviceHmsEntity> queryWrapper = new LambdaQueryWrapper<DeviceHmsEntity>() |
| | | .and(wrapper -> param.getDeviceSn().forEach(sn -> wrapper.eq(DeviceHmsEntity::getSn, sn).or())) |
| | | .between(param.getBeginTime() != null && param.getEndTime() != null, |
| | | DeviceHmsEntity::getCreateTime, param.getBeginTime(), param.getEndTime()) |
| | | .eq(param.getUpdateTime() != null, DeviceHmsEntity::getUpdateTime, param.getUpdateTime()) |
| | | .eq(param.getLevel() != null, DeviceHmsEntity::getLevel, param.getLevel()) |
| | | .like(StringUtils.hasText(param.getMessage()) && |
| | | HmsEnum.MessageLanguage.ZH.getLanguage().equals(param.getLanguage()), |
| | | DeviceHmsEntity::getMessageZh, param.getMessage()) |
| | | .like(StringUtils.hasText(param.getMessage()) && |
| | | HmsEnum.MessageLanguage.EN.getLanguage().equals(param.getLanguage()), |
| | | DeviceHmsEntity::getMessageEn, param.getMessage()) |
| | | .orderByDesc(DeviceHmsEntity::getCreateTime); |
| | | if (param.getPage() == null || param.getPageSize() == null) { |
| | | param.setPage(1L); |
| | | param.setPageSize(Long.valueOf(mapper.selectCount(queryWrapper))); |
| | | } |
| | | |
| | | Page<DeviceHmsEntity> pagination = mapper.selectPage(new Page<>(param.getPage(), param.getPageSize()), queryWrapper); |
| | | |
| | | List<DeviceHmsDTO> deviceHmsList = pagination.getRecords().stream().map(this::entity2Dto).collect(Collectors.toList()); |
| | | |
| | | return new PaginationData<DeviceHmsDTO>(deviceHmsList, new Pagination(pagination)); |
| | | } |
| | | |
| | | @Override |
| | | public void updateUnreadHms(String deviceSn) { |
| | | mapper.update(DeviceHmsEntity.builder().updateTime(System.currentTimeMillis()).build(), |
| | | new LambdaUpdateWrapper<DeviceHmsEntity>() |
| | | .eq(DeviceHmsEntity::getSn, deviceSn) |
| | | .eq(DeviceHmsEntity::getUpdateTime, 0L)); |
| | | redisOps.del(RedisConst.HMS_PREFIX + deviceSn); |
| | | } |
| | | |
| | | private DeviceHmsDTO entity2Dto(DeviceHmsEntity entity) { |
| | | if (entity == null) { |
| | | return null; |
| | | } |
| | | return DeviceHmsDTO.builder() |
| | | .bid(entity.getBid()) |
| | | .tid(entity.getTid()) |
| | | .createTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getCreateTime()), ZoneId.systemDefault())) |
| | | .updateTime(entity.getUpdateTime().intValue() == 0 ? |
| | | null : LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getUpdateTime()), ZoneId.systemDefault())) |
| | | .sn(entity.getSn()) |
| | | .hmsId(entity.getHmsId()) |
| | | .key(entity.getHmsKey()) |
| | | .level(entity.getLevel()) |
| | | .module(entity.getModule()) |
| | | .messageEn(entity.getMessageEn()) |
| | | .messageZh(entity.getMessageZh()) |
| | | .build(); |
| | | } |
| | | |
| | | } |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.manage.model.DeviceStatusManager; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.DevicePayloadDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDeviceDTO; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.receiver.OsdPayloadReceiver; |
| | | import com.dji.sample.manage.model.receiver.OsdSubDeviceReceiver; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.DeserializationFeature; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | * @date 2022/2/21 |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class DeviceOSDServiceImpl extends AbstractTSAService { |
| | | |
| | | protected DeviceOSDServiceImpl() { |
| | | super(null); |
| | | protected DeviceOSDServiceImpl(@Autowired @Qualifier("dockOSDServiceImpl") AbstractTSAService tsaService) { |
| | | super(tsaService); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | } |
| | | @Override |
| | | protected void handleOSD(TopicStateReceiver receiver, String sn, String workspaceId, JsonNode hostNode, |
| | | Collection<ConcurrentWebSocketSession> webSessions, CustomWebSocketMessage wsMessage) throws JsonProcessingException { |
| | | // Real-time update of device status in memory |
| | | DeviceStatusManager.STATUS_MANAGER.put( |
| | | DeviceDomainEnum.SUB_DEVICE.getVal() + "/" + sn, LocalDateTime.now()); |
| | | wsMessage.setBizCode(BizCodeEnum.DEVICE_OSD.getCode()); |
| | | public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, |
| | | Collection<ConcurrentWebSocketSession> webSessions, |
| | | CustomWebSocketMessage<TelemetryDTO> wsMessage) { |
| | | if (DeviceDomainEnum.SUB_DEVICE.getDesc().equals(device.getDomain())) { |
| | | wsMessage.setBizCode(BizCodeEnum.DEVICE_OSD.getCode()); |
| | | |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| | | OsdSubDeviceReceiver data = mapper.treeToValue(hostNode, OsdSubDeviceReceiver.class); |
| | | OsdSubDeviceReceiver data = mapper.convertValue(receiver.getData(), OsdSubDeviceReceiver.class); |
| | | List<DevicePayloadDTO> payloadsList = device.getPayloadsList(); |
| | | try { |
| | | Map<String, Object> receiverData = (Map<String, Object>) receiver.getData(); |
| | | data.setPayloads(payloadsList.stream() |
| | | .map(payload -> mapper.convertValue( |
| | | receiverData.getOrDefault(payload.getPayloadName(), Map.of()), |
| | | OsdPayloadReceiver.class)) |
| | | .collect(Collectors.toList())); |
| | | |
| | | wsMessage.setData(data); |
| | | } catch (NullPointerException e) { |
| | | log.warn("Please remount the payload, or restart the drone. Otherwise the data of the payload will not be received."); |
| | | } |
| | | |
| | | sendMessageService.sendBatch(webSessions, wsMessage); |
| | | this.pushTelemetryData(workspaceId, data, sn); |
| | | |
| | | wsMessage.getData().setHost(data); |
| | | |
| | | sendMessageService.sendBatch(webSessions, wsMessage); |
| | | this.pushTelemetryData(device.getWorkspaceId(), data, device.getDeviceSn()); |
| | | } |
| | | tsaService.handleOSD(receiver, device, webSessions, wsMessage); |
| | | } |
| | | } |
| | |
| | | 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.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.manage.dao.IDevicePayloadMapper; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; |
| | | import com.dji.sample.manage.model.dto.DevicePayloadDTO; |
| | | import com.dji.sample.manage.model.entity.DevicePayloadEntity; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; |
| | | import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver; |
| | | import com.dji.sample.manage.service.ICapacityCameraService; |
| | | import com.dji.sample.manage.service.IDeviceDictionaryService; |
| | | import com.dji.sample.manage.service.IDevicePayloadService; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | |
| | | @Autowired |
| | | private ICapacityCameraService capacityCameraService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public Integer checkPayloadExist(String payloadSn) { |
| | | DevicePayloadEntity devicePayload = mapper.selectOne( |
| | |
| | | |
| | | @Override |
| | | public Boolean savePayloadDTOs(List<DevicePayloadReceiver> payloadReceiverList) { |
| | | if (payloadReceiverList.isEmpty()) { |
| | | return true; |
| | | } |
| | | |
| | | String deviceSn = payloadReceiverList.get(0).getDeviceSn(); |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(key); |
| | | List<DevicePayloadDTO> payloads = new ArrayList<>(); |
| | | |
| | | for (DevicePayloadReceiver payloadReceiver : payloadReceiverList) { |
| | | int payloadId = this.saveOnePayloadDTO(payloadReceiver); |
| | | if (payloadId <= 0) { |
| | | return false; |
| | | } |
| | | payloads.add(this.receiver2Dto(payloadReceiver)); |
| | | } |
| | | |
| | | if (payloads.isEmpty()) { |
| | | payloads = this.getDevicePayloadEntitiesByDeviceSn(deviceSn); |
| | | } |
| | | device.setPayloadsList(payloads); |
| | | redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(), device, RedisConst.DEVICE_ALIVE_SECOND); |
| | | return true; |
| | | } |
| | | |
| | |
| | | .eq(DevicePayloadEntity::getDeviceSn, deviceSn)); |
| | | capacityCameraService.deleteCapacityCameraByDeviceSn(deviceSn); |
| | | }); |
| | | } |
| | | |
| | | @Override |
| | | public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { |
| | | mapper.update(DevicePayloadEntity.builder() |
| | | .firmwareVersion(receiver.getFirmwareVersion()) |
| | | .build() |
| | | , new LambdaUpdateWrapper<DevicePayloadEntity>() |
| | | .eq(DevicePayloadEntity::getDeviceSn, receiver.getSn())); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | if (arr.length == 3) { |
| | | Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService |
| | | .getOneDictionaryInfoByDomainTypeSubType(DeviceDomainEnum.PAYLOAD.getVal(), |
| | | arr[0], arr[1]); |
| | | .getOneDictionaryInfoByTypeSubType(arr[0], arr[1]); |
| | | dictionaryOpt.ifPresent(dictionary -> |
| | | builder.payloadName(dictionary.getDeviceName()) |
| | | .payloadDesc(dictionary.getDeviceDesc())); |
| | |
| | | |
| | | return builder |
| | | .payloadSn(dto.getSn()) |
| | | .version(dto.getVersion()) |
| | | .deviceSn(dto.getSn() |
| | | .substring(0, |
| | | dto.getSn().indexOf("-"))) |
| | | .deviceSn(dto.getDeviceSn()) |
| | | .build(); |
| | | } |
| | | |
| | | private DevicePayloadDTO receiver2Dto(DevicePayloadReceiver receiver) { |
| | | DevicePayloadDTO.DevicePayloadDTOBuilder builder = DevicePayloadDTO.builder(); |
| | | if (receiver == null) { |
| | | return builder.build(); |
| | | } |
| | | return builder.payloadSn(receiver.getSn()) |
| | | .payloadName(receiver.getPayloadIndex()) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.dji.sample.common.error.CommonErrorEnum; |
| | | import com.dji.sample.common.model.Pagination; |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.component.mqtt.model.*; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.component.mqtt.service.IMqttTopicService; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.model.WebSocketManager; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.manage.dao.IDeviceMapper; |
| | | import com.dji.sample.manage.model.dto.*; |
| | | import com.dji.sample.manage.model.entity.DeviceEntity; |
| | |
| | | import com.dji.sample.manage.model.enums.IconUrlEnum; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.model.param.DeviceQueryParam; |
| | | import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; |
| | | import com.dji.sample.manage.model.receiver.StatusSubDeviceReceiver; |
| | | import com.dji.sample.manage.service.IDeviceDictionaryService; |
| | | import com.dji.sample.manage.service.IDevicePayloadService; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import com.dji.sample.manage.service.IWorkspaceService; |
| | | import com.fasterxml.jackson.databind.DeserializationFeature; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.dji.sample.manage.model.receiver.*; |
| | | import com.dji.sample.manage.service.*; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Optional; |
| | | import java.time.Instant; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.util.*; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | private ISendMessageService sendMessageService; |
| | | |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | @Autowired |
| | | @Qualifier("gatewayOSDServiceImpl") |
| | | private AbstractTSAService tsaService; |
| | | private ITSAService tsaService; |
| | | |
| | | @Override |
| | | public Boolean deviceOffline(String gatewaySn) { |
| | | List<DeviceDTO> gatewaysList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .deviceSn(gatewaySn) |
| | | .build()); |
| | | this.subscribeTopicOnline(gatewaySn); |
| | | |
| | | // If no information about this gateway device exists in the database, the drone is considered to be offline. |
| | | if (gatewaysList.isEmpty()) { |
| | | log.debug("The drone is already offline."); |
| | | // Only the remote controller is logged in and the aircraft is not connected. |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + gatewaySn; |
| | | |
| | | boolean exist = redisOps.checkExist(key); |
| | | if (!exist) { |
| | | Optional<DeviceDTO> gatewayOpt = this.getDeviceBySn(gatewaySn); |
| | | if (gatewayOpt.isPresent()) { |
| | | DeviceDTO value = gatewayOpt.get(); |
| | | value.setChildDeviceSn(value.getDeviceSn()); |
| | | value.setBoundTime(null); |
| | | value.setLoginTime(null); |
| | | redisOps.setWithExpire(key, value, RedisConst.DEVICE_ALIVE_SECOND); |
| | | this.pushDeviceOnlineTopo(value.getWorkspaceId(), gatewaySn, gatewaySn); |
| | | return true; |
| | | } |
| | | DeviceDTO gateway = DeviceDTO.builder() |
| | | .deviceSn(gatewaySn) |
| | | .childDeviceSn(gatewaySn) |
| | | .domain(DeviceDomainEnum.GATEWAY.getDesc()) |
| | | .build(); |
| | | gatewayOpt.map(DeviceDTO::getWorkspaceId).ifPresent(gateway::setWorkspaceId); |
| | | redisOps.setWithExpire(key, gateway, RedisConst.DEVICE_ALIVE_SECOND); |
| | | this.pushDeviceOnlineTopo(gateway.getWorkspaceId(), gatewaySn, gatewaySn); |
| | | return true; |
| | | } |
| | | // Handle the drone connected to the gateway device offline. |
| | | return this.subDeviceOffline(gatewaysList.get(0).getChildDeviceSn()); |
| | | |
| | | 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(); |
| | | if (deviceSn.equals(gatewaySn)) { |
| | | return true; |
| | | } |
| | | |
| | | return subDeviceOffline(deviceSn); |
| | | } |
| | | |
| | | @Override |
| | |
| | | // Cancel drone-related subscriptions. |
| | | this.unsubscribeTopicOffline(deviceSn); |
| | | |
| | | List<DeviceDTO> devicesList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .deviceSn(deviceSn) |
| | | .build()); |
| | | |
| | | // If no information about this drone exists in the database, the drone is considered to be offline. |
| | | if (devicesList.isEmpty()) { |
| | | log.debug("{} is already offline.", deviceSn); |
| | | payloadService.deletePayloadsByDeviceSn(new ArrayList<>(List.of(deviceSn))); |
| | | // If no information about this gateway device exists in the database, the drone is considered to be offline. |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | if (!redisOps.checkExist(key) || redisOps.getExpire(key) <= 0) { |
| | | log.debug("The drone is already offline."); |
| | | return true; |
| | | } |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(key); |
| | | // Publish the latest device topology information in the current workspace. |
| | | this.pushDeviceOfflineTopo(device.getWorkspaceId(), deviceSn); |
| | | |
| | | List<String> ids = devicesList.stream() |
| | | .map(DeviceDTO::getDeviceSn) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // Delete all data related to the drone. |
| | | boolean isDel = this.delDeviceByDeviceSns(ids); |
| | | payloadService.deletePayloadsByDeviceSn(ids); |
| | | |
| | | log.debug("{} offline status: {}.", deviceSn, isDel); |
| | | return isDel; |
| | | redisOps.del(key); |
| | | log.debug("{} offline.", deviceSn); |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deviceOnline(StatusGatewayReceiver deviceGateway) { |
| | | String deviceSn = deviceGateway.getSubDevices().get(0).getSn(); |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | // change log: Use redis instead of |
| | | long time = redisOps.getExpire(key); |
| | | long now = System.currentTimeMillis(); |
| | | |
| | | List<DeviceDTO> devicesList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .deviceSn(deviceSn) |
| | | .build()); |
| | | // If the information about this drone exists in the database, the drone is considered to be online. |
| | | if (!devicesList.isEmpty()) { |
| | | if (time > 0) { |
| | | redisOps.expireKey(RedisConst.DEVICE_ONLINE_PREFIX + deviceGateway.getSn(), RedisConst.DEVICE_ALIVE_SECOND); |
| | | redisOps.expireKey(key, RedisConst.DEVICE_ALIVE_SECOND); |
| | | DeviceDTO device = DeviceDTO.builder().loginTime(LocalDateTime.now()).deviceSn(deviceSn).build(); |
| | | DeviceDTO gateway = DeviceDTO.builder() |
| | | .loginTime(LocalDateTime.now()) |
| | | .deviceSn(deviceGateway.getSn()) |
| | | .childDeviceSn(deviceSn).build(); |
| | | this.updateDevice(gateway); |
| | | this.updateDevice(device); |
| | | String workspaceId = ((DeviceDTO)(redisOps.get(key))).getWorkspaceId(); |
| | | if (StringUtils.hasText(workspaceId)) { |
| | | this.subscribeTopicOnline(deviceSn); |
| | | this.subscribeTopicOnline(deviceGateway.getSn()); |
| | | } |
| | | log.warn("{} is already online.", deviceSn); |
| | | // Subscribe to topic related to drone and gateway devices. |
| | | this.subscribeTopicOnline(deviceGateway.getSn()); |
| | | this.subscribeTopicOnline(deviceSn); |
| | | return true; |
| | | } |
| | | |
| | | // Delete the gateway device information that was previously bound to the drone. |
| | | this.delDeviceByDeviceSns( |
| | | this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .childSn(deviceSn) |
| | | .build()) |
| | | .stream() |
| | | .map(DeviceDTO::getDeviceSn) |
| | | .collect(Collectors.toList())); |
| | | List<DeviceDTO> gatewaysList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .childSn(deviceSn) |
| | | .build()); |
| | | gatewaysList.stream().filter( |
| | | gateway -> !gateway.getDeviceSn().equals(deviceGateway.getSn())) |
| | | .findAny() |
| | | .ifPresent(gateway -> { |
| | | gateway.setChildDeviceSn(""); |
| | | this.updateDevice(gateway); |
| | | }); |
| | | |
| | | |
| | | DeviceEntity gateway = deviceGatewayConvertToDeviceEntity(deviceGateway); |
| | | gateway.setWorkspaceId(WorkspaceDTO.DEFAULT_WORKSPACE_ID); |
| | | gateway.setChildSn(deviceSn); |
| | | // Set the icon of the gateway device displayed in the pilot's map, required in the TSA module. |
| | | gateway.setUrlNormal(IconUrlEnum.NORMAL_PERSON.getUrl()); |
| | | // Set the icon of the gateway device displayed in the pilot's map when it is selected, required in the TSA module. |
| | | gateway.setUrlSelect(IconUrlEnum.SELECT_PERSON.getUrl()); |
| | | gateway.setLoginTime(now); |
| | | |
| | | DeviceEntity subDevice = subDeviceConvertToDeviceEntity(deviceGateway.getSubDevices().get(0)); |
| | | subDevice.setWorkspaceId(WorkspaceDTO.DEFAULT_WORKSPACE_ID); |
| | | // Set the icon of the drone device displayed in the pilot's map, required in the TSA module. |
| | | subDevice.setUrlSelect(IconUrlEnum.SELECT_EQUIPMENT.getUrl()); |
| | | // Set the icon of the drone device displayed in the pilot's map when it is selected, required in the TSA module. |
| | | subDevice.setUrlNormal(IconUrlEnum.NORMAL_EQUIPMENT.getUrl()); |
| | | // Set the icon of the drone device displayed in the pilot's map, required in the TSA module. |
| | | subDevice.setUrlSelect(IconUrlEnum.SELECT_EQUIPMENT.getUrl()); |
| | | subDevice.setLoginTime(now); |
| | | |
| | | gateway.setChildSn(subDevice.getDeviceSn()); |
| | | |
| | | boolean isSave = this.saveDevice(gateway) > 0 && this.saveDevice(subDevice) > 0; |
| | | |
| | | log.debug(subDevice.getDeviceSn() + " online status: {}", isSave); |
| | | if (isSave) { |
| | | // Subscribe to topic related to drone and gateway devices. |
| | | this.subscribeTopicOnline(subDevice.getDeviceSn()); |
| | | this.subscribeTopicOnline(gateway.getDeviceSn()); |
| | | |
| | | // dock go online |
| | | if (deviceGateway.getDomain() != null && DeviceDomainEnum.DOCK.getVal() == deviceGateway.getDomain()) { |
| | | Optional<DeviceDTO> deviceOpt = this.getDeviceBySn(deviceGateway.getSn()); |
| | | if (deviceOpt.isEmpty()) { |
| | | log.info("The dock is not bound and cannot go online."); |
| | | return false; |
| | | } |
| | | gateway.setNickname(null); |
| | | subDevice.setNickname(null); |
| | | } |
| | | return isSave; |
| | | |
| | | Optional<DeviceEntity> gatewayOpt = this.saveDevice(gateway); |
| | | String workspaceId = this.saveDevice(subDevice).orElse(subDevice).getWorkspaceId(); |
| | | |
| | | redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + deviceSn, |
| | | DeviceDTO.builder() |
| | | .deviceSn(deviceSn) |
| | | .domain(DeviceDomainEnum.SUB_DEVICE.getDesc()) |
| | | .workspaceId(workspaceId) |
| | | .build(), |
| | | RedisConst.DEVICE_ALIVE_SECOND); |
| | | redisOps.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + gateway.getDeviceSn(), |
| | | DeviceDTO.builder() |
| | | .deviceSn(gateway.getDeviceSn()) |
| | | .workspaceId(gatewayOpt.orElse(gateway).getWorkspaceId()) |
| | | .childDeviceSn(deviceSn) |
| | | .domain(deviceGateway.getDomain() != null ? |
| | | DeviceDomainEnum.getDesc(deviceGateway.getDomain()) : |
| | | DeviceDomainEnum.GATEWAY.getDesc()) |
| | | .build(), |
| | | RedisConst.DEVICE_ALIVE_SECOND); |
| | | log.debug("{} online.", subDevice.getDeviceSn()); |
| | | |
| | | if (StringUtils.hasText(workspaceId)) { |
| | | this.pushDeviceOnlineTopo(workspaceId, deviceGateway.getSn(), deviceSn); |
| | | } |
| | | // Subscribe to topic related to drone devices. |
| | | this.subscribeTopicOnline(deviceSn); |
| | | this.subscribeTopicOnline(deviceGateway.getSn()); |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | |
| | | topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + OSD_SUF); |
| | | topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + STATE_SUF); |
| | | topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + SERVICES_SUF + _REPLY_SUF); |
| | | topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + REQUESTS_SUF); |
| | | topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + EVENTS_SUF); |
| | | } |
| | | |
| | | @Override |
| | |
| | | topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + OSD_SUF); |
| | | topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + STATE_SUF); |
| | | topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + SERVICES_SUF + _REPLY_SUF); |
| | | topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + REQUESTS_SUF); |
| | | topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + EVENTS_SUF); |
| | | } |
| | | |
| | | @Override |
| | |
| | | return mapper.selectList( |
| | | new LambdaQueryWrapper<DeviceEntity>() |
| | | .eq(StringUtils.hasText(param.getDeviceSn()), |
| | | DeviceEntity::getDeviceSn, param.getDeviceSn()) |
| | | DeviceEntity::getDeviceSn, param.getDeviceSn()) |
| | | .eq(param.getDeviceType() != null, |
| | | DeviceEntity::getDeviceType, param.getDeviceType()) |
| | | .eq(param.getSubType() != null, |
| | | DeviceEntity::getSubType, param.getSubType()) |
| | | .eq(StringUtils.hasText(param.getChildSn()), |
| | | DeviceEntity::getChildSn, param.getChildSn()) |
| | | .eq(param.getDomain() != null, |
| | | DeviceEntity::getDomain, param.getDomain()) |
| | | .and(!CollectionUtils.isEmpty(param.getDomains()), wrapper -> { |
| | | for (Integer domain : param.getDomains()) { |
| | | wrapper.eq(DeviceEntity::getDomain, domain).or(); |
| | | } |
| | | }) |
| | | .eq(StringUtils.hasText(param.getWorkspaceId()), |
| | | DeviceEntity::getWorkspaceId, param.getWorkspaceId()) |
| | | .eq(param.getBoundStatus() != null, DeviceEntity::getBoundStatus, param.getBoundStatus()) |
| | | .orderBy(param.isOrderBy(), |
| | | param.isAsc(), DeviceEntity::getId)) |
| | | .stream() |
| | |
| | | List<DeviceDTO> devicesList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .workspaceId(workspaceId) |
| | | .domain(DeviceDomainEnum.SUB_DEVICE.getVal()) |
| | | .domains(List.of(DeviceDomainEnum.SUB_DEVICE.getVal())) |
| | | .build()); |
| | | |
| | | devicesList.forEach(device -> { |
| | | this.spliceDeviceTopo(device); |
| | | device.setWorkspaceId(workspaceId); |
| | | |
| | | device.setStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); |
| | | }); |
| | | return devicesList; |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void pushDeviceOnlineTopo(Collection<ConcurrentWebSocketSession> sessions, String sn) { |
| | | public void pushDeviceOnlineTopo(Collection<ConcurrentWebSocketSession> sessions, String sn, String gatewaySn) { |
| | | |
| | | CustomWebSocketMessage<TopologyDeviceDTO> pilotMessage = |
| | | CustomWebSocketMessage.<TopologyDeviceDTO>builder() |
| | |
| | | |
| | | this.getDeviceTopoForPilot(sn) |
| | | .ifPresent(pilotMessage::setData); |
| | | boolean exist = redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn); |
| | | pilotMessage.getData().setOnlineStatus(exist); |
| | | pilotMessage.getData().setGatewaySn(gatewaySn.equals(sn) ? "" : gatewaySn); |
| | | |
| | | sendMessageService.sendBatch(sessions, pilotMessage); |
| | | } |
| | |
| | | TopologyDeviceDTO.TopologyDeviceDTOBuilder builder = TopologyDeviceDTO.builder(); |
| | | |
| | | if (device != null) { |
| | | String domain = String.valueOf(DeviceDomainEnum.getVal(device.getDomain())); |
| | | int domain = DeviceDomainEnum.getVal(device.getDomain()); |
| | | String subType = String.valueOf(device.getSubType()); |
| | | String type = String.valueOf(device.getType()); |
| | | |
| | | builder.sn(device.getDeviceSn()) |
| | | .deviceCallsign(device.getDeviceName()) |
| | | .deviceCallsign(device.getNickname()) |
| | | .deviceModel(DeviceModelDTO.builder() |
| | | .domain(domain) |
| | | .domain(String.valueOf(domain)) |
| | | .subType(subType) |
| | | .type(type) |
| | | .key(domain + "-" + type + "-" + subType) |
| | | .build()) |
| | | .iconUrls(device.getIconUrl()) |
| | | .onlineStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) |
| | | .boundStatus(device.getBoundStatus()) |
| | | .model(device.getDeviceName()) |
| | | .userId(device.getUserId()) |
| | | .domain(DeviceDomainEnum.getDesc(domain)) |
| | | .build(); |
| | | } |
| | | return builder.build(); |
| | | } |
| | | |
| | | @Override |
| | | public void pushDeviceOnlineTopo(String workspaceId, String deviceSn, String gatewaySn) { |
| | | public void pushDeviceOnlineTopo(String workspaceId, String gatewaySn, String deviceSn) { |
| | | |
| | | // All connected accounts on the pilot side of this workspace. |
| | | Collection<ConcurrentWebSocketSession> pilotSessions = WebSocketManager |
| | | .getValueWithWorkspaceAndUserType( |
| | | workspaceId, UserTypeEnum.PILOT.getVal()); |
| | | // All connected accounts in this workspace. |
| | | Collection<ConcurrentWebSocketSession> allSessions = webSocketManageService.getValueWithWorkspace(workspaceId); |
| | | |
| | | this.pushDeviceOnlineTopo(pilotSessions, deviceSn); |
| | | this.pushDeviceOnlineTopo(pilotSessions, gatewaySn); |
| | | this.pushDeviceUpdateTopo(pilotSessions, deviceSn); |
| | | this.pushDeviceUpdateTopo(pilotSessions, gatewaySn); |
| | | if (!gatewaySn.equals(deviceSn)) { |
| | | this.pushDeviceOnlineTopo(allSessions, deviceSn, gatewaySn); |
| | | this.pushDeviceUpdateTopo(allSessions, deviceSn); |
| | | } |
| | | this.pushDeviceOnlineTopo(allSessions, gatewaySn, gatewaySn); |
| | | this.pushDeviceUpdateTopo(allSessions, gatewaySn); |
| | | } |
| | | |
| | | @Override |
| | | public void pushDeviceOfflineTopo(String workspaceId, String gatewaySn) { |
| | | // All connected accounts on the pilot side of this workspace. |
| | | Collection<ConcurrentWebSocketSession> pilotSessions = WebSocketManager |
| | | .getValueWithWorkspaceAndUserType( |
| | | workspaceId, UserTypeEnum.PILOT.getVal()); |
| | | public void pushDeviceOfflineTopo(String workspaceId, String sn) { |
| | | // All connected accounts of this workspace. |
| | | Collection<ConcurrentWebSocketSession> allSessions = webSocketManageService |
| | | .getValueWithWorkspace(workspaceId); |
| | | |
| | | |
| | | List<DeviceDTO> gatewaysList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .deviceSn(gatewaySn) |
| | | .build()); |
| | | |
| | | if (!gatewaysList.isEmpty()) { |
| | | String deviceSn = gatewaysList.get(0).getChildDeviceSn(); |
| | | this.pushDeviceOfflineTopo(pilotSessions, deviceSn); |
| | | this.pushDeviceUpdateTopo(pilotSessions, deviceSn); |
| | | } |
| | | |
| | | this.pushDeviceOfflineTopo(pilotSessions, gatewaySn); |
| | | this.pushDeviceUpdateTopo(pilotSessions, gatewaySn); |
| | | this.pushDeviceOfflineTopo(allSessions, sn); |
| | | this.pushDeviceUpdateTopo(allSessions, sn); |
| | | } |
| | | |
| | | @Override |
| | | public void handleOSD(String topic, byte[] payload) { |
| | | TopicStateReceiver receiver; |
| | | CommonTopicReceiver receiver; |
| | | try { |
| | | String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(), |
| | | topic.indexOf(OSD_SUF)); |
| | | |
| | | List<DeviceDTO> deviceList = this.getDevicesByParams( |
| | | DeviceQueryParam.builder().deviceSn(from).build()); |
| | | if (deviceList.isEmpty()) { |
| | | // Real-time update of device status in memory |
| | | redisOps.expireKey(RedisConst.DEVICE_ONLINE_PREFIX + from, RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + from); |
| | | |
| | | if (device == null || !StringUtils.hasText(device.getWorkspaceId())) { |
| | | return; |
| | | } |
| | | |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| | | receiver = objectMapper.readValue(payload, CommonTopicReceiver.class); |
| | | |
| | | receiver = mapper.readValue(payload, TopicStateReceiver.class); |
| | | CustomWebSocketMessage<TelemetryDTO> wsMessage = CustomWebSocketMessage.<TelemetryDTO>builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .data(TelemetryDTO.builder().sn(from).build()) |
| | | .build(); |
| | | |
| | | CustomWebSocketMessage wsMessage = CustomWebSocketMessage.builder() |
| | | .timestamp(System.currentTimeMillis()).build(); |
| | | |
| | | JsonNode hostNode = mapper.readTree(payload).findPath("data"); |
| | | |
| | | String workspaceId = deviceList.get(0).getWorkspaceId(); |
| | | Collection<ConcurrentWebSocketSession> webSessions = WebSocketManager |
| | | Collection<ConcurrentWebSocketSession> webSessions = webSocketManageService |
| | | .getValueWithWorkspaceAndUserType( |
| | | workspaceId, UserTypeEnum.WEB.getVal()); |
| | | device.getWorkspaceId(), UserTypeEnum.WEB.getVal()); |
| | | |
| | | |
| | | tsaService.handleOSD(receiver, from, workspaceId, hostNode, webSessions, wsMessage); |
| | | tsaService.handleOSD(receiver, device, webSessions, wsMessage); |
| | | |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private Integer saveDevice(DeviceEntity entity) { |
| | | private Optional<DeviceEntity> saveDevice(DeviceEntity entity) { |
| | | DeviceEntity deviceEntity = mapper.selectOne( |
| | | new LambdaQueryWrapper<DeviceEntity>() |
| | | .eq(DeviceEntity::getDeviceSn, entity.getDeviceSn())); |
| | |
| | | if (deviceEntity != null) { |
| | | entity.setId(deviceEntity.getId()); |
| | | mapper.updateById(entity); |
| | | return deviceEntity.getId(); |
| | | return Optional.of(deviceEntity); |
| | | } |
| | | return mapper.insert(entity) > 0 ? entity.getId() : 0; |
| | | return mapper.insert(entity) > 0 ? Optional.of(entity) : Optional.empty(); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | // Query the model information of this gateway device. |
| | | Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService |
| | | .getOneDictionaryInfoByDomainTypeSubType(gateway.getDomain(), |
| | | gateway.getType(), gateway.getSubType()); |
| | | .getOneDictionaryInfoByTypeSubType(gateway.getType(), gateway.getSubType()); |
| | | |
| | | dictionaryOpt.ifPresent(entity -> |
| | | builder.deviceName(entity.getDeviceName()) |
| | | .nickname(entity.getDeviceName()) |
| | | .deviceDesc(entity.getDeviceDesc())); |
| | | |
| | | return builder |
| | | .deviceSn(gateway.getSn()) |
| | | .domain(gateway.getDomain()) |
| | | .subType(gateway.getSubType()) |
| | | .deviceType(gateway.getType()) |
| | | .version(gateway.getVersion()) |
| | | .domain(gateway.getDomain() != null ? |
| | | gateway.getDomain() : DeviceDomainEnum.GATEWAY.getVal()) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | |
| | | // Query the model information of this drone device. |
| | | Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService |
| | | .getOneDictionaryInfoByDomainTypeSubType(DeviceDomainEnum.SUB_DEVICE.getVal(), |
| | | device.getType(), device.getSubType()); |
| | | .getOneDictionaryInfoByTypeSubType(device.getType(), device.getSubType()); |
| | | |
| | | dictionaryOpt.ifPresent(dictionary -> |
| | | builder.deviceName(dictionary.getDeviceName()) |
| | | .nickname(dictionary.getDeviceName()) |
| | | .deviceDesc(dictionary.getDeviceDesc())); |
| | | |
| | | return builder |
| | | .deviceSn(device.getSn()) |
| | | .deviceType(device.getType()) |
| | | .subType(device.getSubType()) |
| | | .domain(DeviceDomainEnum.SUB_DEVICE.getVal()) |
| | | .version(device.getVersion()) |
| | | .deviceIndex(device.getIndex()) |
| | | .domain(device.getDomain() != null ? |
| | | device.getDomain() : DeviceDomainEnum.SUB_DEVICE.getVal()) |
| | | .build(); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into device data transfer object. |
| | | * Convert database entity object into device data transfer object. |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private DeviceDTO deviceEntityConvertToDTO(DeviceEntity entity) { |
| | | DeviceDTO.DeviceDTOBuilder builder = DeviceDTO.builder(); |
| | | |
| | | if (entity != null) { |
| | | builder.deviceSn(entity.getDeviceSn()) |
| | | .childDeviceSn(entity.getChildSn()) |
| | | .deviceName(entity.getDeviceName()) |
| | | .deviceDesc(entity.getDeviceDesc()) |
| | | .deviceIndex(entity.getDeviceIndex()) |
| | | .workspaceId(entity.getWorkspaceId()) |
| | | .type(entity.getDeviceType()) |
| | | .subType(entity.getSubType()) |
| | | .domain(DeviceDomainEnum.getDesc(entity.getDomain())) |
| | | .iconUrl(IconUrlDTO.builder() |
| | | .normalUrl(entity.getUrlNormal()) |
| | | .selectUrl(entity.getUrlSelect()) |
| | | .build()) |
| | | .build(); |
| | | if (entity == null) { |
| | | return null; |
| | | } |
| | | return builder.build(); |
| | | return DeviceDTO.builder() |
| | | .deviceSn(entity.getDeviceSn()) |
| | | .childDeviceSn(entity.getChildSn()) |
| | | .deviceName(entity.getDeviceName()) |
| | | .deviceDesc(entity.getDeviceDesc()) |
| | | .deviceIndex(entity.getDeviceIndex()) |
| | | .workspaceId(entity.getWorkspaceId()) |
| | | .type(entity.getDeviceType()) |
| | | .subType(entity.getSubType()) |
| | | .domain(DeviceDomainEnum.getDesc(entity.getDomain())) |
| | | .iconUrl(IconUrlDTO.builder() |
| | | .normalUrl(entity.getUrlNormal()) |
| | | .selectUrl(entity.getUrlSelect()) |
| | | .build()) |
| | | .boundStatus(entity.getBoundStatus()) |
| | | .loginTime(entity.getLoginTime() != null ? |
| | | LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getLoginTime()), ZoneId.systemDefault()) |
| | | : null) |
| | | .boundTime(entity.getBoundTime() != null ? |
| | | LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getBoundTime()), ZoneId.systemDefault()) |
| | | : null) |
| | | .nickname(entity.getNickname()) |
| | | .firmwareVersion(entity.getFirmwareVersion()) |
| | | .workspaceName(entity.getWorkspaceId() != null ? |
| | | workspaceService.getWorkspaceByWorkspaceId(entity.getWorkspaceId()) |
| | | .map(WorkspaceDTO::getWorkspaceName).orElse("") : "") |
| | | .build(); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean updateDevice(DeviceDTO deviceDTO) { |
| | | int update = mapper.update(this.deviceDTO2Entity(deviceDTO), |
| | | new LambdaUpdateWrapper<DeviceEntity>().eq(DeviceEntity::getDeviceSn, deviceDTO.getDeviceSn())); |
| | | return update > 0; |
| | | } |
| | | |
| | | @Override |
| | | public Boolean bindDevice(DeviceDTO device) { |
| | | device.setBoundStatus(true); |
| | | device.setBoundTime(LocalDateTime.now()); |
| | | |
| | | boolean isUpd = this.saveDevice(this.deviceDTO2Entity(device)).isPresent(); |
| | | if (DeviceDomainEnum.DOCK.getDesc().equals(device.getDomain())) { |
| | | return isUpd; |
| | | } |
| | | if (!isUpd) { |
| | | return false; |
| | | } |
| | | |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(); |
| | | DeviceDTO redisDevice = (DeviceDTO)redisOps.get(key); |
| | | redisDevice.setWorkspaceId(device.getWorkspaceId()); |
| | | redisOps.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | if (DeviceDomainEnum.GATEWAY.getDesc().equals(redisDevice.getDomain())) { |
| | | this.pushDeviceOnlineTopo(webSocketManageService.getValueWithWorkspace(device.getWorkspaceId()), |
| | | device.getDeviceSn(), device.getDeviceSn()); |
| | | } |
| | | if (DeviceDomainEnum.SUB_DEVICE.getDesc().equals(redisDevice.getDomain())) { |
| | | DeviceDTO subDevice = this.getDevicesByParams(DeviceQueryParam.builder() |
| | | .childSn(device.getChildDeviceSn()) |
| | | .build()).get(0); |
| | | this.pushDeviceOnlineTopo(webSocketManageService.getValueWithWorkspace(device.getWorkspaceId()), |
| | | device.getDeviceSn(), subDevice.getDeviceSn()); |
| | | } |
| | | this.subscribeTopicOnline(device.getDeviceSn()); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_AIRPORT_BIND_STATUS, outputChannel = ChannelName.OUTBOUND) |
| | | public void bindStatus(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | List<Map<String, String>> data = ((Map<String, List<Map<String, String>>>) receiver.getData()).get(MapKeyConst.DEVICES); |
| | | String dockSn = data.get(0).get(MapKeyConst.SN); |
| | | String droneSn = data.size() > 1 ? data.get(1).get(MapKeyConst.SN) : "null"; |
| | | |
| | | Optional<DeviceDTO> dockOpt = this.getDeviceBySn(dockSn); |
| | | Optional<DeviceDTO> droneOpt = this.getDeviceBySn(droneSn); |
| | | |
| | | List<BindStatusReceiver> bindStatusResult = new ArrayList<>(); |
| | | bindStatusResult.add(dockOpt.isPresent() ? this.dto2BindStatus(dockOpt.get()) : |
| | | BindStatusReceiver.builder().sn(dockSn).isDeviceBindOrganization(false).build()); |
| | | if (data.size() > 1) { |
| | | bindStatusResult.add(droneOpt.isPresent() ? this.dto2BindStatus(droneOpt.get()) : |
| | | BindStatusReceiver.builder().sn(droneSn).isDeviceBindOrganization(false).build()); |
| | | } |
| | | |
| | | messageSender.publish(headers.get(MqttHeaders.RECEIVED_TOPIC) + _REPLY_SUF, |
| | | CommonTopicResponse.builder() |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .method(RequestsMethodEnum.AIRPORT_BIND_STATUS.getMethod()) |
| | | .data(RequestsReply.success(Map.of(MapKeyConst.BIND_STATUS, bindStatusResult))) |
| | | .build()); |
| | | |
| | | } |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND) |
| | | public void bindDevice(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | Map<String, List<BindDeviceReceiver>> data = objectMapper.convertValue(receiver.getData(), |
| | | new TypeReference<Map<String, List<BindDeviceReceiver>>>() {}); |
| | | List<BindDeviceReceiver> devices = data.get(MapKeyConst.BIND_DEVICES); |
| | | BindDeviceReceiver dock = null; |
| | | BindDeviceReceiver drone = null; |
| | | for (BindDeviceReceiver device : devices) { |
| | | int val = Integer.parseInt(device.getDeviceModelKey().split("-")[0]); |
| | | if (val == DeviceDomainEnum.DOCK.getVal()) { |
| | | dock = device; |
| | | } |
| | | if (val == DeviceDomainEnum.SUB_DEVICE.getVal()) { |
| | | drone = device; |
| | | } |
| | | } |
| | | |
| | | assert dock != null; |
| | | |
| | | Optional<DeviceEntity> dockEntityOpt = this.bindDevice2Entity(dock); |
| | | Optional<DeviceEntity> droneEntityOpt = this.bindDevice2Entity(drone); |
| | | |
| | | List<ErrorInfoReply> bindResult = new ArrayList<>(); |
| | | |
| | | droneEntityOpt.ifPresent(droneEntity -> { |
| | | dockEntityOpt.get().setChildSn(droneEntity.getDeviceSn()); |
| | | Optional<DeviceEntity> deviceEntityOpt = this.saveDevice(droneEntity); |
| | | bindResult.add( |
| | | deviceEntityOpt.isPresent() ? |
| | | ErrorInfoReply.success(droneEntity.getDeviceSn()) : |
| | | new ErrorInfoReply(droneEntity.getDeviceSn(), |
| | | CommonErrorEnum.DEVICE_BINDING_FAILED.getErrorCode()) |
| | | ); |
| | | }); |
| | | Optional<DeviceEntity> dockOpt = this.saveDevice(dockEntityOpt.get()); |
| | | |
| | | bindResult.add(dockOpt.isPresent() ? |
| | | ErrorInfoReply.success(dock.getSn()) : |
| | | new ErrorInfoReply(dock.getSn(), |
| | | CommonErrorEnum.DEVICE_BINDING_FAILED.getErrorCode())); |
| | | |
| | | String topic = headers.get(MqttHeaders.RECEIVED_TOPIC) + _REPLY_SUF; |
| | | messageSender.publish(topic, |
| | | CommonTopicResponse.builder() |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .method(RequestsMethodEnum.AIRPORT_ORGANIZATION_BIND.getMethod()) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .data(RequestsReply.success(Map.of(MapKeyConst.ERR_INFOS, bindResult))) |
| | | .build()); |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<DeviceDTO> getBoundDevicesWithDomain(String workspaceId, Long page, |
| | | Long pageSize, String domain) { |
| | | |
| | | Page<DeviceEntity> pagination = mapper.selectPage(new Page<>(page, pageSize), |
| | | new LambdaQueryWrapper<DeviceEntity>() |
| | | .eq(DeviceEntity::getDomain, DeviceDomainEnum.getVal(domain)) |
| | | .eq(DeviceEntity::getWorkspaceId, workspaceId) |
| | | .eq(DeviceEntity::getBoundStatus, true)); |
| | | List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO) |
| | | .peek(device -> { |
| | | device.setStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())); |
| | | if (StringUtils.hasText(device.getChildDeviceSn())) { |
| | | Optional<DeviceDTO> childOpt = this.getDeviceBySn(device.getChildDeviceSn()); |
| | | childOpt.ifPresent(child -> { |
| | | child.setStatus( |
| | | redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + child.getDeviceSn())); |
| | | child.setWorkspaceName(device.getWorkspaceName()); |
| | | device.setChildren(child); |
| | | }); |
| | | } |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | return new PaginationData<DeviceDTO>(devicesList, new Pagination(pagination)); |
| | | } |
| | | |
| | | @Override |
| | | public void unbindDevice(String deviceSn) { |
| | | String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn; |
| | | DeviceDTO redisDevice = (DeviceDTO) redisOps.get(key); |
| | | redisDevice.setWorkspaceId(""); |
| | | redisOps.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND); |
| | | |
| | | DeviceDTO device = DeviceDTO.builder() |
| | | .deviceSn(deviceSn) |
| | | .workspaceId("") |
| | | .userId("") |
| | | .boundStatus(false) |
| | | .build(); |
| | | this.updateDevice(device); |
| | | } |
| | | |
| | | @Override |
| | | public Optional<DeviceDTO> getDeviceBySn(String sn) { |
| | | List<DeviceDTO> devicesList = this.getDevicesByParams(DeviceQueryParam.builder().deviceSn(sn).build()); |
| | | if (devicesList.isEmpty()) { |
| | | return Optional.empty(); |
| | | } |
| | | DeviceDTO device = devicesList.get(0); |
| | | device.setStatus(redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn)); |
| | | return Optional.of(device); |
| | | } |
| | | |
| | | @Override |
| | | public void updateFirmwareVersion(FirmwareVersionReceiver receiver) { |
| | | if (receiver.getDomain() == DeviceDomainEnum.SUB_DEVICE) { |
| | | this.updateDevice(DeviceDTO.builder() |
| | | .deviceSn(receiver.getSn()) |
| | | .firmwareVersion(receiver.getFirmwareVersion()) |
| | | .build()); |
| | | return; |
| | | } |
| | | payloadService.updateFirmwareVersion(receiver); |
| | | } |
| | | |
| | | /** |
| | | * Convert device data transfer object into database entity object. |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | private DeviceEntity deviceDTO2Entity(DeviceDTO dto) { |
| | | DeviceEntity.DeviceEntityBuilder builder = DeviceEntity.builder(); |
| | | if (dto == null) { |
| | | return builder.build(); |
| | | } |
| | | |
| | | return builder.deviceSn(dto.getDeviceSn()) |
| | | .userId(dto.getUserId()) |
| | | .nickname(dto.getNickname()) |
| | | .workspaceId(dto.getWorkspaceId()) |
| | | .boundStatus(dto.getBoundStatus()) |
| | | .loginTime(dto.getLoginTime() != null ? |
| | | dto.getLoginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null) |
| | | .boundTime(dto.getBoundTime() != null ? |
| | | dto.getBoundTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null) |
| | | .childSn(dto.getChildDeviceSn()) |
| | | .domain(StringUtils.hasText(dto.getDomain()) ? DeviceDomainEnum.getVal(dto.getDomain()) : null) |
| | | .firmwareVersion(dto.getFirmwareVersion()) |
| | | .build(); |
| | | } |
| | | |
| | | /** |
| | | * Convert device binding data object into database entity object. |
| | | * @param receiver |
| | | * @return |
| | | */ |
| | | private Optional<DeviceEntity> bindDevice2Entity(BindDeviceReceiver receiver) { |
| | | if (receiver == null) { |
| | | return Optional.empty(); |
| | | } |
| | | int[] droneKey = Arrays.stream(receiver.getDeviceModelKey().split("-")).mapToInt(Integer::parseInt).toArray(); |
| | | Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService.getOneDictionaryInfoByTypeSubType(droneKey[1], droneKey[2]); |
| | | DeviceEntity.DeviceEntityBuilder builder = DeviceEntity.builder(); |
| | | |
| | | dictionaryOpt.ifPresent(entity -> |
| | | builder.deviceName(entity.getDeviceName()) |
| | | .nickname(entity.getDeviceName()) |
| | | .deviceDesc(entity.getDeviceDesc())); |
| | | |
| | | Optional<WorkspaceDTO> workspace = workspaceService.getWorkspaceNameByBindCode(receiver.getDeviceBindingCode()); |
| | | |
| | | DeviceEntity entity = builder |
| | | .workspaceId(workspace.isPresent() ? workspace.get().getWorkspaceId() : receiver.getOrganizationId()) |
| | | .domain(droneKey[0]) |
| | | .deviceType(droneKey[1]) |
| | | .subType(droneKey[2]) |
| | | .deviceSn(receiver.getSn()) |
| | | .boundStatus(true) |
| | | .loginTime(System.currentTimeMillis()) |
| | | .boundTime(System.currentTimeMillis()) |
| | | .urlSelect(IconUrlEnum.SELECT_EQUIPMENT.getUrl()) |
| | | .urlNormal(IconUrlEnum.NORMAL_EQUIPMENT.getUrl()) |
| | | .build(); |
| | | if (StringUtils.hasText(receiver.getDeviceCallsign())) { |
| | | entity.setNickname(receiver.getDeviceCallsign()); |
| | | } |
| | | return Optional.of(entity); |
| | | } |
| | | |
| | | /** |
| | | * Convert device data transfer object into device binding status data object. |
| | | * @param device |
| | | * @return |
| | | */ |
| | | private BindStatusReceiver dto2BindStatus(DeviceDTO device) { |
| | | if (device == null) { |
| | | return null; |
| | | } |
| | | return BindStatusReceiver.builder() |
| | | .sn(device.getDeviceSn()) |
| | | .deviceCallsign(device.getNickname()) |
| | | .isDeviceBindOrganization(device.getBoundStatus()) |
| | | .organizationId(device.getWorkspaceId()) |
| | | .organizationName(device.getWorkspaceName()) |
| | | .build(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.receiver.OsdDockReceiver; |
| | | import com.dji.sample.manage.model.receiver.OsdDockTransmissionReceiver; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.Collection; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.0 |
| | | * @date 2022/5/11 |
| | | */ |
| | | @Service |
| | | public class DockOSDServiceImpl extends AbstractTSAService { |
| | | |
| | | public DockOSDServiceImpl() { |
| | | super(null); |
| | | } |
| | | |
| | | @Override |
| | | public void pushTelemetryData(Collection<ConcurrentWebSocketSession> sessions, |
| | | CustomWebSocketMessage<TelemetryDTO> message, Object Object) { |
| | | |
| | | } |
| | | |
| | | @Override |
| | | public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, |
| | | Collection<ConcurrentWebSocketSession> webSessions, |
| | | CustomWebSocketMessage<TelemetryDTO> wsMessage) { |
| | | |
| | | if (DeviceDomainEnum.DOCK.getDesc().equals(device.getDomain())) { |
| | | wsMessage.setBizCode(BizCodeEnum.DOCK_OSD.getCode()); |
| | | OsdDockReceiver data = mapper.convertValue(receiver.getData(), OsdDockReceiver.class); |
| | | wsMessage.getData().setHost(data); |
| | | if (data.getSubDevice() == null) { |
| | | OsdDockTransmissionReceiver transmission = mapper.convertValue(receiver.getData(), OsdDockTransmissionReceiver.class); |
| | | wsMessage.getData().setHost(transmission); |
| | | } |
| | | sendMessageService.sendBatch(webSessions, wsMessage); |
| | | } |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.manage.model.DeviceStatusManager; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDTO; |
| | | import com.dji.sample.manage.model.dto.TelemetryDeviceDTO; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.receiver.OsdGatewayReceiver; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import com.fasterxml.jackson.databind.DeserializationFeature; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Qualifier; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.time.LocalDateTime; |
| | | import java.util.Collection; |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | @Override |
| | | protected void handleOSD(TopicStateReceiver receiver, String sn, String workspaceId, JsonNode hostNode, |
| | | Collection<ConcurrentWebSocketSession> webSessions, CustomWebSocketMessage wsMessage) throws JsonProcessingException { |
| | | if (sn.equals(receiver.getGateway())) { |
| | | // Real-time update of device status in memory |
| | | DeviceStatusManager.STATUS_MANAGER.put(DeviceDomainEnum.GATEWAY.getVal() + "/" + sn, |
| | | LocalDateTime.now()); |
| | | |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| | | public void handleOSD(CommonTopicReceiver receiver, DeviceDTO device, |
| | | Collection<ConcurrentWebSocketSession> webSessions, |
| | | CustomWebSocketMessage<TelemetryDTO> wsMessage) { |
| | | if (DeviceDomainEnum.GATEWAY.getDesc().equals(device.getDomain())) { |
| | | |
| | | wsMessage.setBizCode(BizCodeEnum.GATEWAY_OSD.getCode()); |
| | | OsdGatewayReceiver data = mapper.treeToValue(hostNode, OsdGatewayReceiver.class); |
| | | wsMessage.setData(data); |
| | | OsdGatewayReceiver data = mapper.convertValue(receiver.getData(), OsdGatewayReceiver.class); |
| | | wsMessage.getData().setHost(data); |
| | | |
| | | this.sendMessageService.sendBatch(webSessions, wsMessage); |
| | | |
| | | this.pushTelemetryData(workspaceId, data, sn); |
| | | this.pushTelemetryData(device.getWorkspaceId(), data, device.getDeviceSn()); |
| | | return; |
| | | } |
| | | |
| | | tsaService.handleOSD(receiver, sn, workspaceId, hostNode, webSessions, wsMessage); |
| | | tsaService.handleOSD(receiver, device, webSessions, wsMessage); |
| | | } |
| | | } |
| | |
| | | |
| | | import com.dji.sample.common.error.LiveErrorEnum; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.mqtt.model.ServiceReply; |
| | | import com.dji.sample.component.mqtt.model.ServicesMethodEnum; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.manage.model.Chan; |
| | | import com.dji.sample.component.redis.RedisConst; |
| | | import com.dji.sample.component.redis.RedisOpsUtils; |
| | | import com.dji.sample.manage.model.dto.*; |
| | | import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
| | | import com.dji.sample.manage.model.enums.LiveMethodEnum; |
| | | import com.dji.sample.manage.model.enums.LiveUrlTypeEnum; |
| | | import com.dji.sample.manage.model.enums.LiveVideoQualityEnum; |
| | | import com.dji.sample.manage.model.param.DeviceQueryParam; |
| | | import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver; |
| | | import com.dji.sample.manage.model.receiver.ServiceReplyReceiver; |
| | | import com.dji.sample.manage.model.receiver.LiveCapacityReceiver; |
| | | import com.dji.sample.manage.service.ICapacityCameraService; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import com.dji.sample.manage.service.ILiveStreamService; |
| | |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.lang.reflect.Field; |
| | | import java.util.*; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import static com.dji.sample.component.mqtt.model.TopicConst.*; |
| | | |
| | |
| | | @Autowired |
| | | private IMessageSenderService messageSender; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public List<CapacityDeviceDTO> getLiveCapacity(String workspaceId) { |
| | | |
| | | // Query all drone data in this workspace. |
| | | // Query all devices in this workspace. |
| | | List<DeviceDTO> devicesList = deviceService.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .workspaceId(workspaceId) |
| | | .domain(DeviceDomainEnum.SUB_DEVICE.getVal()) |
| | | .domains(List.of(DeviceDomainEnum.SUB_DEVICE.getVal(), DeviceDomainEnum.DOCK.getVal())) |
| | | .build()); |
| | | |
| | | List<CapacityDeviceDTO> capacityDevicesList = new ArrayList<>(); |
| | | // Query the live capability of each drone. |
| | | devicesList.forEach(device -> capacityDevicesList.add(CapacityDeviceDTO.builder() |
| | | .name(device.getDeviceName()) |
| | | .sn(device.getDeviceSn()) |
| | | .camerasList(capacityCameraService.getCapacityCameraByDeviceSn(device.getDeviceSn())) |
| | | .build())); |
| | | |
| | | return capacityDevicesList; |
| | | return devicesList.stream() |
| | | .filter(device -> redisOps.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn())) |
| | | .map(device -> CapacityDeviceDTO.builder() |
| | | .name(device.getDeviceName()) |
| | | .sn(device.getDeviceSn()) |
| | | .camerasList(capacityCameraService.getCapacityCameraByDeviceSn(device.getDeviceSn())) |
| | | .build()) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean saveLiveCapacity(CapacityDeviceReceiver capacityDeviceReceiver) { |
| | | return capacityCameraService.saveCapacityCameraReceiverList( |
| | | capacityDeviceReceiver.getCameraList(), |
| | | capacityDeviceReceiver.getSn()); |
| | | public void saveLiveCapacity(LiveCapacityReceiver liveCapacityReceiver) { |
| | | for (CapacityDeviceReceiver capacityDeviceReceiver : liveCapacityReceiver.getDeviceList()) { |
| | | capacityCameraService.saveCapacityCameraReceiverList( |
| | | capacityDeviceReceiver.getCameraList(), |
| | | capacityDeviceReceiver.getSn()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | return responseResult; |
| | | } |
| | | |
| | | List<DeviceDTO> data = (List<DeviceDTO>)responseResult.getData(); |
| | | DeviceDTO data = (DeviceDTO)responseResult.getData(); |
| | | // target topic |
| | | String respTopic = THING_MODEL_PRE + PRODUCT + |
| | | data.get(0).getDeviceSn() + SERVICES_SUF; |
| | | Optional<ServiceReplyReceiver> receiveReplyOpt = this.publishLiveStart(respTopic, liveParam); |
| | | data.getDeviceSn() + SERVICES_SUF; |
| | | Optional<ServiceReply> receiveReplyOpt = this.publishLiveStart(respTopic, liveParam); |
| | | |
| | | if (receiveReplyOpt.isEmpty()) { |
| | | return ResponseResult.error(LiveErrorEnum.NO_REPLY); |
| | |
| | | .toString()); |
| | | break; |
| | | case RTSP: |
| | | String url = receiveReplyOpt.get().getInfo(); |
| | | String url = receiveReplyOpt.get().getInfo().toString(); |
| | | this.resolveUrlUser(url, live); |
| | | break; |
| | | case UNKNOWN: |
| | |
| | | |
| | | @Override |
| | | public ResponseResult liveStop(String videoId) { |
| | | ResponseResult<List<DeviceDTO>> responseResult = this.checkBeforeLive(videoId); |
| | | ResponseResult<DeviceDTO> responseResult = this.checkBeforeLive(videoId); |
| | | if (responseResult.getCode() != 0) { |
| | | return responseResult; |
| | | } |
| | | |
| | | String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().get(0).getDeviceSn() + SERVICES_SUF; |
| | | String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF; |
| | | |
| | | Optional<ServiceReplyReceiver> receiveReplyOpt = this.publishLiveStop(respTopic, videoId); |
| | | Optional<ServiceReply> receiveReplyOpt = this.publishLiveStop(respTopic, videoId); |
| | | if (receiveReplyOpt.isEmpty()) { |
| | | return ResponseResult.error(LiveErrorEnum.NO_REPLY); |
| | | } |
| | |
| | | return ResponseResult.error(LiveErrorEnum.ERROR_PARAMETERS); |
| | | } |
| | | |
| | | ResponseResult<List<DeviceDTO>> responseResult = this.checkBeforeLive(liveParam.getVideoId()); |
| | | ResponseResult<DeviceDTO> responseResult = this.checkBeforeLive(liveParam.getVideoId()); |
| | | |
| | | if (responseResult.getCode() != 0) { |
| | | return responseResult; |
| | | } |
| | | |
| | | String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().get(0).getDeviceSn() + SERVICES_SUF; |
| | | String respTopic = THING_MODEL_PRE + PRODUCT + responseResult.getData().getDeviceSn() + SERVICES_SUF; |
| | | |
| | | Optional<ServiceReplyReceiver> receiveReplyOpt = this.publishLiveSetQuality(respTopic, liveParam); |
| | | Optional<ServiceReply> receiveReplyOpt = this.publishLiveSetQuality(respTopic, liveParam); |
| | | if (receiveReplyOpt.isEmpty()) { |
| | | return ResponseResult.error(LiveErrorEnum.NO_REPLY); |
| | | } |
| | |
| | | * @param videoId |
| | | * @return |
| | | */ |
| | | private ResponseResult checkBeforeLive(String videoId) { |
| | | private ResponseResult<DeviceDTO> checkBeforeLive(String videoId) { |
| | | String[] videoIdArr = videoId.split("/"); |
| | | // drone sn / enumeration value of the location where the payload is mounted / payload lens |
| | | if (videoIdArr.length != 3) { |
| | | return ResponseResult.error(LiveErrorEnum.ERROR_PARAMETERS); |
| | | } |
| | | |
| | | Optional<DeviceDTO> deviceOpt = deviceService.getDeviceBySn(videoIdArr[0]); |
| | | // Check if the gateway device connected to this drone exists |
| | | if (deviceOpt.isEmpty()) { |
| | | return ResponseResult.error(LiveErrorEnum.NO_AIRCRAFT); |
| | | } |
| | | |
| | | if (deviceOpt.get().getDomain().equals(DeviceDomainEnum.DOCK.getDesc())) { |
| | | return ResponseResult.success(deviceOpt.get()); |
| | | } |
| | | List<DeviceDTO> gatewayList = deviceService.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .childSn(videoIdArr[0]) |
| | | .build()); |
| | | // Check if the gateway device connected to this drone exists |
| | | if (gatewayList.isEmpty()) { |
| | | return ResponseResult.error(LiveErrorEnum.NO_FLIGHT_CONTROL); |
| | | } |
| | | return ResponseResult.success(gatewayList); |
| | | |
| | | return ResponseResult.success(gatewayList.get(0)); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param liveParam |
| | | * @return |
| | | */ |
| | | private Optional<ServiceReplyReceiver> publishLiveStart(String topic, LiveTypeDTO liveParam) { |
| | | private Optional<ServiceReply> publishLiveStart(String topic, LiveTypeDTO liveParam) { |
| | | CommonTopicResponse<LiveTypeDTO> response = new CommonTopicResponse<>(); |
| | | response.setTid(UUID.randomUUID().toString()); |
| | | response.setBid(UUID.randomUUID().toString()); |
| | | response.setData(liveParam); |
| | | response.setMethod(LiveMethodEnum.LIVE_START_PUSH.getMethod()); |
| | | response.setMethod(ServicesMethodEnum.LIVE_START_PUSH.getMethod()); |
| | | |
| | | return this.publishLive(topic, response); |
| | | return messageSender.publishWithReply(topic, response); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param liveParam |
| | | * @return |
| | | */ |
| | | private Optional<ServiceReplyReceiver> publishLiveSetQuality(String respTopic, LiveTypeDTO liveParam) { |
| | | private Optional<ServiceReply> publishLiveSetQuality(String respTopic, LiveTypeDTO liveParam) { |
| | | Map<String, Object> data = new ConcurrentHashMap<>(Map.of( |
| | | "video_id", liveParam.getVideoId(), |
| | | "video_quality", liveParam.getVideoQuality())); |
| | | CommonTopicResponse<Map<String, Object>> response = new CommonTopicResponse<>(); |
| | | response.setTid(UUID.randomUUID().toString()); |
| | | response.setBid(UUID.randomUUID().toString()); |
| | | response.setMethod(LiveMethodEnum.LIVE_SET_QUALITY.getMethod()); |
| | | response.setMethod(ServicesMethodEnum.LIVE_SET_QUALITY.getMethod()); |
| | | response.setData(data); |
| | | |
| | | return this.publishLive(respTopic, response); |
| | | return messageSender.publishWithReply(respTopic, response); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param videoId |
| | | * @return |
| | | */ |
| | | private Optional<ServiceReplyReceiver> publishLiveStop(String topic, String videoId) { |
| | | private Optional<ServiceReply> publishLiveStop(String topic, String videoId) { |
| | | Map<String, String> data = new ConcurrentHashMap<>(Map.of("video_id", videoId)); |
| | | CommonTopicResponse<Map<String, String>> response = new CommonTopicResponse<>(); |
| | | response.setTid(UUID.randomUUID().toString()); |
| | | response.setBid(UUID.randomUUID().toString()); |
| | | response.setData(data); |
| | | response.setMethod(LiveMethodEnum.LIVE_STOP_PUSH.getMethod()); |
| | | response.setMethod(ServicesMethodEnum.LIVE_STOP_PUSH.getMethod()); |
| | | |
| | | return this.publishLive(topic, response); |
| | | } |
| | | |
| | | /** |
| | | * Send live streaming start message and receive a response at the same time |
| | | * @param topic |
| | | * @param response notification of whether the start is successful. |
| | | * @return |
| | | */ |
| | | private Optional<ServiceReplyReceiver> publishLive(String topic, CommonTopicResponse response) { |
| | | AtomicInteger time = new AtomicInteger(0); |
| | | // Retry three times |
| | | while (time.getAndIncrement() < 3) { |
| | | messageSender.publish(topic, response); |
| | | |
| | | Chan<CommonTopicReceiver<ServiceReplyReceiver>> chan = Chan.getInstance(); |
| | | // If the message is not received in 0.5 seconds then resend it again. |
| | | CommonTopicReceiver<ServiceReplyReceiver> receiver = chan.get(response.getMethod()); |
| | | if (receiver == null) { |
| | | continue; |
| | | } |
| | | // Need to match tid and bid. |
| | | if (receiver.getTid().equals(response.getTid()) && |
| | | receiver.getBid().equals(response.getBid())) { |
| | | return Optional.ofNullable(receiver.getData()); |
| | | } |
| | | } |
| | | return Optional.empty(); |
| | | return messageSender.publishWithReply(topic, response); |
| | | } |
| | | |
| | | } |
| | |
| | | List<DeviceDTO> gatewayList = deviceService.getDevicesByParams( |
| | | DeviceQueryParam.builder() |
| | | .workspaceId(workspaceId) |
| | | .domain(DeviceDomainEnum.GATEWAY.getVal()) |
| | | .domains(List.of(DeviceDomainEnum.GATEWAY.getVal())) |
| | | .build()); |
| | | |
| | | List<TopologyDTO> topologyList = new ArrayList<>(); |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.auth0.jwt.JWT; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.dji.sample.common.model.CustomClaim; |
| | | 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.common.util.JwtUtil; |
| | | import com.dji.sample.component.mqtt.config.MqttConfiguration; |
| | | import com.dji.sample.manage.dao.IUserMapper; |
| | | import com.dji.sample.manage.model.dto.UserDTO; |
| | | import com.dji.sample.manage.model.dto.UserListDTO; |
| | | import com.dji.sample.manage.model.dto.WorkspaceDTO; |
| | | import com.dji.sample.manage.model.entity.UserEntity; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.manage.service.IUserService; |
| | | import com.dji.sample.manage.service.IWorkspaceService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.time.Instant; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Service |
| | | @Transactional |
| | |
| | | } |
| | | |
| | | @Override |
| | | public ResponseResult userLogin(String username, String password) { |
| | | public ResponseResult userLogin(String username, String password, Integer flag) { |
| | | // check user |
| | | UserEntity userEntity = this.getUserByUsername(username); |
| | | if (userEntity == null) { |
| | |
| | | .message("invalid username") |
| | | .build(); |
| | | } |
| | | if (flag.intValue() != userEntity.getUserType().intValue()) { |
| | | return ResponseResult.error("The account type does not match."); |
| | | } |
| | | if (!password.equals(userEntity.getPassword())) { |
| | | return ResponseResult.builder() |
| | | .code(HttpStatus.UNAUTHORIZED.value()) |
| | |
| | | .build(); |
| | | } |
| | | |
| | | Optional<WorkspaceDTO> workspaceOpt = workspaceService.getWorkspaceById(userEntity.getWorkspaceId()); |
| | | Optional<WorkspaceDTO> workspaceOpt = workspaceService.getWorkspaceByWorkspaceId(userEntity.getWorkspaceId()); |
| | | if (workspaceOpt.isEmpty()) { |
| | | return ResponseResult.builder() |
| | | .code(HttpStatus.UNAUTHORIZED.value()) |
| | |
| | | return Optional.of(user); |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<UserListDTO> getUsersByWorkspaceId(long page, long pageSize, String workspaceId) { |
| | | Page<UserEntity> userEntityPage = mapper.selectPage( |
| | | new Page<>(page, pageSize), |
| | | new LambdaQueryWrapper<UserEntity>().eq(UserEntity::getWorkspaceId, workspaceId)); |
| | | |
| | | List<UserListDTO> usersList = userEntityPage.getRecords() |
| | | .stream() |
| | | .map(this::entity2UserListDTO) |
| | | .collect(Collectors.toList()); |
| | | return new PaginationData<>(usersList, new Pagination(userEntityPage)); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean updateUser(String workspaceId, String userId, UserListDTO user) { |
| | | UserEntity userEntity = mapper.selectOne( |
| | | new LambdaQueryWrapper<UserEntity>() |
| | | .eq(UserEntity::getUserId, userId) |
| | | .eq(UserEntity::getWorkspaceId, workspaceId)); |
| | | if (userEntity == null) { |
| | | return false; |
| | | } |
| | | userEntity.setMqttUsername(user.getMqttUsername()); |
| | | userEntity.setMqttPassword(user.getMqttPassword()); |
| | | userEntity.setUpdateTime(System.currentTimeMillis()); |
| | | int id = mapper.update(userEntity, new LambdaUpdateWrapper<UserEntity>() |
| | | .eq(UserEntity::getUserId, userId) |
| | | .eq(UserEntity::getWorkspaceId, workspaceId)); |
| | | |
| | | return id > 0; |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into user data transfer object. |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private UserListDTO entity2UserListDTO(UserEntity entity) { |
| | | UserListDTO.UserListDTOBuilder builder = UserListDTO.builder(); |
| | | if (entity != null) { |
| | | builder.userId(entity.getUserId()) |
| | | .username(entity.getUsername()) |
| | | .mqttUsername(entity.getMqttUsername()) |
| | | .mqttPassword(entity.getMqttPassword()) |
| | | .userType(UserTypeEnum.find(entity.getUserType()).getDesc()) |
| | | .createTime(LocalDateTime.ofInstant( |
| | | Instant.ofEpochMilli(entity.getCreateTime()), ZoneId.systemDefault())); |
| | | Optional<WorkspaceDTO> workspaceOpt = workspaceService.getWorkspaceByWorkspaceId(entity.getWorkspaceId()); |
| | | workspaceOpt.ifPresent(workspace -> builder.workspaceName(workspace.getWorkspaceName())); |
| | | } |
| | | |
| | | return builder.build(); |
| | | } |
| | | |
| | | /** |
| | | * Query a user by username. |
| | | * @param username |
| | |
| | | .eq("username", username)); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into user data transfer object. |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private UserDTO entityConvertToDTO(UserEntity entity) { |
| | | if (entity == null) { |
| | | return new UserDTO(); |
| | |
| | | package com.dji.sample.manage.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.dji.sample.common.error.CommonErrorEnum; |
| | | import com.dji.sample.component.mqtt.model.*; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.manage.dao.IWorkspaceMapper; |
| | | import com.dji.sample.manage.model.dto.WorkspaceDTO; |
| | | import com.dji.sample.manage.model.entity.WorkspaceEntity; |
| | | import com.dji.sample.manage.model.receiver.OrganizationGetReceiver; |
| | | import com.dji.sample.manage.service.IWorkspaceService; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.integration.mqtt.support.MqttHeaders; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.util.Map; |
| | | import java.util.Optional; |
| | | |
| | | @Service |
| | |
| | | @Autowired |
| | | private IWorkspaceMapper mapper; |
| | | |
| | | @Override |
| | | public Optional<WorkspaceDTO> getWorkspaceById(int id) { |
| | | return Optional.ofNullable(entityConvertToDto(mapper.selectById(id))); |
| | | } |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private IMessageSenderService messageSenderService; |
| | | |
| | | @Override |
| | | public Optional<WorkspaceDTO> getWorkspaceByWorkspaceId(String workspaceId) { |
| | |
| | | .eq(WorkspaceEntity::getWorkspaceId, workspaceId)))); |
| | | } |
| | | |
| | | @Override |
| | | public Optional<WorkspaceDTO> getWorkspaceNameByBindCode(String bindCode) { |
| | | return Optional.ofNullable(entityConvertToDto( |
| | | mapper.selectOne(new LambdaQueryWrapper<WorkspaceEntity>().eq(WorkspaceEntity::getBindCode, bindCode)))); |
| | | } |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_GET, outputChannel = ChannelName.OUTBOUND) |
| | | public void replyOrganizationGet(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | OrganizationGetReceiver organizationGet = objectMapper.convertValue(receiver.getData(), OrganizationGetReceiver.class); |
| | | CommonTopicResponse.CommonTopicResponseBuilder<RequestsReply> builder = CommonTopicResponse.<RequestsReply>builder() |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .method(RequestsMethodEnum.AIRPORT_ORGANIZATION_GET.getMethod()) |
| | | .timestamp(System.currentTimeMillis()); |
| | | |
| | | String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString() + TopicConst._REPLY_SUF; |
| | | |
| | | if (!StringUtils.hasText(organizationGet.getDeviceBindingCode())) { |
| | | builder.data(RequestsReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT)); |
| | | messageSenderService.publish(topic, builder.build()); |
| | | return; |
| | | } |
| | | |
| | | Optional<WorkspaceDTO> workspace = this.getWorkspaceNameByBindCode(organizationGet.getDeviceBindingCode()); |
| | | if (workspace.isEmpty()) { |
| | | builder.data(RequestsReply.error(CommonErrorEnum.GET_ORGANIZATION_FAILED)); |
| | | messageSenderService.publish(topic, builder.build()); |
| | | return; |
| | | } |
| | | |
| | | builder.data(RequestsReply.success(Map.of(MapKeyConst.ORGANIZATION_NAME, workspace.get().getWorkspaceName()))); |
| | | messageSenderService.publish(topic, builder.build()); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into workspace data transfer object. |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private WorkspaceDTO entityConvertToDto(WorkspaceEntity entity) { |
| | | WorkspaceDTO.WorkspaceDTOBuilder builder = WorkspaceDTO.builder(); |
| | | if (entity == null) { |
| | | return builder.build(); |
| | | return null; |
| | | } |
| | | return builder |
| | | return WorkspaceDTO.builder() |
| | | .id(entity.getId()) |
| | | .workspaceId(entity.getWorkspaceId()) |
| | | .platformName(entity.getPlatformName()) |
| | | .workspaceDesc(entity.getWorkspaceDesc()) |
| | | .workspaceName(entity.getWorkspaceName()) |
| | | .bindCode(entity.getBindCode()) |
| | | .build(); |
| | | } |
| | | } |
| | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.websocket.model.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.model.WebSocketManager; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.map.model.dto.*; |
| | | import com.dji.sample.map.service.IWorkspaceElementService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | |
| | | @Autowired |
| | | private ISendMessageService sendMessageService; |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | /** |
| | | * In the first connection, pilot will send out this http request to obtain the group element list. |
| | |
| | | elementService.getElementByElementId(elementCreate.getId()) |
| | | .ifPresent(groupElement -> |
| | | sendMessageService.sendBatch( |
| | | WebSocketManager.getValueWithWorkspace(workspaceId), |
| | | webSocketManageService.getValueWithWorkspace(workspaceId), |
| | | CustomWebSocketMessage.<GroupElementDTO>builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .bizCode(BizCodeEnum.MAP_ELEMENT_CREATE.getCode()) |
| | |
| | | elementService.getElementByElementId(elementId) |
| | | .ifPresent(groupElement -> |
| | | sendMessageService.sendBatch( |
| | | WebSocketManager.getValueWithWorkspace(workspaceId), |
| | | webSocketManageService.getValueWithWorkspace(workspaceId), |
| | | CustomWebSocketMessage.<GroupElementDTO>builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .bizCode(BizCodeEnum.MAP_ELEMENT_UPDATE.getCode()) |
| | |
| | | if (ResponseResult.CODE_SUCCESS == response.getCode()) { |
| | | elementOpt.ifPresent(element -> |
| | | sendMessageService.sendBatch( |
| | | WebSocketManager.getValueWithWorkspace(workspaceId), |
| | | webSocketManageService.getValueWithWorkspace(workspaceId), |
| | | CustomWebSocketMessage.<WebSocketElementDelDTO>builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .bizCode(BizCodeEnum.MAP_ELEMENT_DELETE.getCode()) |
| | |
| | | if (ResponseResult.CODE_SUCCESS == response.getCode()) { |
| | | |
| | | sendMessageService.sendBatch( |
| | | WebSocketManager.getValueWithWorkspace(workspaceId), |
| | | webSocketManageService.getValueWithWorkspace(workspaceId), |
| | | CustomWebSocketMessage.builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .bizCode(BizCodeEnum.MAP_GROUP_REFRESH.getCode()) |
| | |
| | | package com.dji.sample.media.controller; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.media.model.MediaFileDTO; |
| | | import com.dji.sample.media.service.IFileService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.List; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.net.URL; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | * @return |
| | | */ |
| | | @GetMapping("/{workspace_id}/files") |
| | | public ResponseResult<List<MediaFileDTO>> getFilesList(@PathVariable(name = "workspace_id") String workspaceId) { |
| | | List<MediaFileDTO> filesList = fileService.getAllFilesByWorkspaceId(workspaceId); |
| | | public ResponseResult<PaginationData<MediaFileDTO>> getFilesList(@RequestParam(defaultValue = "1") Long page, |
| | | @RequestParam(name = "page_size", defaultValue = "10") Long pageSize, |
| | | @PathVariable(name = "workspace_id") String workspaceId) { |
| | | PaginationData<MediaFileDTO> filesList = fileService.getJobsPaginationByWorkspaceId(workspaceId, page, pageSize); |
| | | return ResponseResult.success(filesList); |
| | | } |
| | | |
| | | /** |
| | | * Query the download address of the file according to the media file fingerprint, |
| | | * and redirect to this address directly for download. |
| | | * @param workspaceId |
| | | * @param fingerprint |
| | | * @param response |
| | | */ |
| | | @GetMapping("/{workspace_id}/file/{fingerprint}/url") |
| | | public void getFileUrl(@PathVariable(name = "workspace_id") String workspaceId, |
| | | @PathVariable String fingerprint, HttpServletResponse response) { |
| | | |
| | | try { |
| | | URL url = fileService.getObjectUrl(workspaceId, fingerprint); |
| | | response.sendRedirect(url.toString()); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.media.controller; |
| | | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.mqtt.model.MapKeyConst; |
| | | import com.dji.sample.media.model.FileUploadDTO; |
| | | import com.dji.sample.media.service.IMediaService; |
| | | import com.fasterxml.jackson.core.JsonProcessingException; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | |
| | | boolean isExist = mediaService.fastUpload(workspaceId, file.getFingerprint()); |
| | | |
| | | return isExist ? ResponseResult.success() : ResponseResult.error(file.getFingerprint() + "already exists."); |
| | | return isExist ? ResponseResult.success() : ResponseResult.error(file.getFingerprint() + "don't exist."); |
| | | } |
| | | |
| | | /** |
| | |
| | | /** |
| | | * Query the files that already exist in this workspace based on the workspace id and the collection of tiny fingerprints. |
| | | * @param workspaceId |
| | | * @param tinyFingerprints |
| | | * @param tinyFingerprints There is only one tiny_fingerprint parameter in the body. |
| | | * But it is not recommended to use Map to receive the parameter. |
| | | * @return |
| | | */ |
| | | @GetMapping("/{workspace_id}/files/tiny-fingerprints") |
| | | public ResponseResult<Map<String, List<String>>> uploadCallback(@PathVariable(name = "workspace_id") String workspaceId, |
| | | @RequestParam(value = "tiny_fingerprint") List<String> tinyFingerprints) { |
| | | List<String> tinyFingerprintList = mediaService.getAllTinyFingerprintsByWorkspaceId(workspaceId); |
| | | List<String> existingList = tinyFingerprints |
| | | .stream() |
| | | .filter(tinyFingerprintList::contains) |
| | | .collect(Collectors.toList()); |
| | | return ResponseResult.success(new ConcurrentHashMap<>(Map.of("tiny_fingerprints", existingList))); |
| | | @PostMapping("/{workspace_id}/files/tiny-fingerprints") |
| | | public ResponseResult<Map<String, List<String>>> uploadCallback( |
| | | @PathVariable(name = "workspace_id") String workspaceId, |
| | | @RequestBody Map<String, List<String>> tinyFingerprints) throws JsonProcessingException { |
| | | |
| | | List<String> existingList = mediaService.getExistTinyFingerprints(workspaceId, tinyFingerprints.get(MapKeyConst.TINY_FINGERPRINTS)); |
| | | return ResponseResult.success(new ConcurrentHashMap<>(Map.of(MapKeyConst.TINY_FINGERPRINTS, existingList))); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse; |
| | | import io.minio.credentials.Credentials; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | |
| | | /** |
| | |
| | | * @date 2021/12/7 |
| | | */ |
| | | @Data |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class CredentialsDTO { |
| | | |
| | | private String accessKeyId; |
| | |
| | | this.expire = Math.toIntExact(expire); |
| | | } |
| | | |
| | | public CredentialsDTO() { |
| | | public CredentialsDTO(com.amazonaws.services.securitytoken.model.Credentials credentials) { |
| | | this.accessKeyId = credentials.getAccessKeyId(); |
| | | this.accessKeySecret = credentials.getSecretAccessKey(); |
| | | this.securityToken = credentials.getSessionToken(); |
| | | this.expire = Math.toIntExact((credentials.getExpiration().getTime() - System.currentTimeMillis()) / 1000); |
| | | } |
| | | } |
| | |
| | | |
| | | private String sn; |
| | | |
| | | private String flightId; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.media.model; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | @Data |
| | | public class FileUploadCallback { |
| | | |
| | | private Integer result; |
| | | |
| | | private Integer progress; |
| | | |
| | | private FileUploadDTO file; |
| | | } |
| | |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.2 |
| | |
| | | private String payload; |
| | | |
| | | private String tinnyFingerprint; |
| | | |
| | | private String fingerprint; |
| | | |
| | | private LocalDateTime createTime; |
| | | } |
| | |
| | | @TableField("payload") |
| | | private String payload; |
| | | |
| | | @TableField("job_id") |
| | | private String jobId; |
| | | |
| | | @TableField(value = "create_time", fill = FieldFill.INSERT) |
| | | private Long createTime; |
| | | |
| | |
| | | package com.dji.sample.media.service; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.media.model.FileUploadDTO; |
| | | import com.dji.sample.media.model.MediaFileDTO; |
| | | |
| | | import java.net.URL; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | * @return |
| | | */ |
| | | List<MediaFileDTO> getAllFilesByWorkspaceId(String workspaceId); |
| | | |
| | | /** |
| | | * Paginate through all media files in this workspace. |
| | | * @param workspaceId |
| | | * @param page |
| | | * @param pageSize |
| | | * @return |
| | | */ |
| | | PaginationData<MediaFileDTO> getJobsPaginationByWorkspaceId(String workspaceId, long page, long pageSize); |
| | | |
| | | /** |
| | | * Get the download address of the file. |
| | | * @param workspaceId |
| | | * @param fingerprint |
| | | * @return |
| | | */ |
| | | URL getObjectUrl(String workspaceId, String fingerprint); |
| | | } |
| | |
| | | package com.dji.sample.media.service; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.media.model.FileUploadDTO; |
| | | |
| | | import java.util.List; |
| | |
| | | * @return |
| | | */ |
| | | List<String> getAllTinyFingerprintsByWorkspaceId(String workspaceId); |
| | | |
| | | /** |
| | | * Query the fingerprints that already exist in it based on the incoming tiny fingerprints data. |
| | | * @param workspaceId |
| | | * @param tinyFingerprints |
| | | * @return |
| | | */ |
| | | List<String> getExistTinyFingerprints(String workspaceId, List<String> tinyFingerprints); |
| | | |
| | | /** |
| | | * Handle media files messages reported by dock. |
| | | * @param receiver |
| | | * @return |
| | | */ |
| | | void handleFileUploadCallBack(CommonTopicReceiver receiver); |
| | | } |
| | |
| | | package com.dji.sample.media.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | 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.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.service.impl.OssServiceContext; |
| | | import com.dji.sample.manage.model.dto.DeviceDictionaryDTO; |
| | | import com.dji.sample.manage.service.IDeviceDictionaryService; |
| | | import com.dji.sample.media.dao.IFileMapper; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.net.URL; |
| | | import java.time.Instant; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | |
| | | @Transactional |
| | | public class FileServiceImpl implements IFileService { |
| | | |
| | | |
| | | @Autowired |
| | | private IFileMapper mapper; |
| | | |
| | | @Autowired |
| | | private IDeviceDictionaryService deviceDictionaryService; |
| | | |
| | | @Override |
| | | public Boolean checkExist(String workspaceId, String fingerprint) { |
| | | @Autowired |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | private Optional<MediaFileEntity> getMediaByFingerprint(String workspaceId, String fingerprint) { |
| | | MediaFileEntity fileEntity = mapper.selectOne(new LambdaQueryWrapper<MediaFileEntity>() |
| | | .eq(MediaFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(MediaFileEntity::getFingerprint, fingerprint)); |
| | | return fileEntity != null; |
| | | return Optional.ofNullable(fileEntity); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean checkExist(String workspaceId, String fingerprint) { |
| | | return this.getMediaByFingerprint(workspaceId, fingerprint).isPresent(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<MediaFileDTO> getJobsPaginationByWorkspaceId(String workspaceId, long page, long pageSize) { |
| | | Page<MediaFileEntity> pageData = mapper.selectPage( |
| | | new Page<MediaFileEntity>(page, pageSize), |
| | | new LambdaQueryWrapper<MediaFileEntity>() |
| | | .eq(MediaFileEntity::getWorkspaceId, workspaceId)); |
| | | List<MediaFileDTO> records = pageData.getRecords() |
| | | .stream() |
| | | .map(this::entityConvertToDto) |
| | | .collect(Collectors.toList()); |
| | | |
| | | return new PaginationData<MediaFileDTO>(records, new Pagination(pageData)); |
| | | } |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String workspaceId, String fingerprint) { |
| | | Optional<MediaFileEntity> mediaFileOpt = getMediaByFingerprint(workspaceId, fingerprint); |
| | | if (mediaFileOpt.isEmpty()) { |
| | | throw new IllegalArgumentException("{} doesn't exist."); |
| | | } |
| | | |
| | | return ossService.getObjectUrl(configuration.getBucket(), mediaFileOpt.get().getObjectKey()); |
| | | } |
| | | |
| | | /** |
| | | * Convert the received file object into a database entity object. |
| | | * @param file |
| | |
| | | .objectKey(file.getObjectKey()) |
| | | .subFileType(file.getSubFileType()) |
| | | .isOriginal(file.getExt().getIsOriginal()) |
| | | .jobId(file.getExt().getFlightId()) |
| | | .drone(file.getExt().getSn()) |
| | | .tinnyFingerprint(file.getExt().getTinnyFingerprint()); |
| | | |
| | |
| | | .mapToInt(Integer::intValue) |
| | | .toArray(); |
| | | Optional<DeviceDictionaryDTO> payloadDict = deviceDictionaryService |
| | | .getOneDictionaryInfoByDomainTypeSubType(payloadModel[0], payloadModel[1], payloadModel[2]); |
| | | .getOneDictionaryInfoByTypeSubType(payloadModel[1], payloadModel[2]); |
| | | payloadDict.ifPresent(payload -> builder.payload(payload.getDeviceName())); |
| | | } |
| | | return builder.build(); |
| | |
| | | builder.fileName(entity.getFileName()) |
| | | .filePath(entity.getFilePath()) |
| | | .isOriginal(entity.getIsOriginal()) |
| | | .fingerprint(entity.getFingerprint()) |
| | | .objectKey(entity.getObjectKey()) |
| | | .tinnyFingerprint(entity.getTinnyFingerprint()) |
| | | .payload(entity.getPayload()) |
| | | .createTime(LocalDateTime.ofInstant( |
| | | Instant.ofEpochMilli(entity.getCreateTime()), ZoneId.systemDefault())) |
| | | .drone(entity.getDrone()); |
| | | |
| | | } |
| | |
| | | package com.dji.sample.media.service.impl; |
| | | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.mqtt.model.*; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.media.model.FileUploadCallback; |
| | | import com.dji.sample.media.model.FileUploadDTO; |
| | | import com.dji.sample.media.model.MediaFileDTO; |
| | | import com.dji.sample.media.service.IFileService; |
| | | import com.dji.sample.media.service.IMediaService; |
| | | import com.dji.sample.wayline.model.dto.WaylineJobDTO; |
| | | import com.dji.sample.wayline.service.IWaylineJobService; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.integration.annotation.ServiceActivator; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | |
| | | @Autowired |
| | | private IFileService fileService; |
| | | |
| | | @Autowired |
| | | private IWaylineJobService waylineJobService; |
| | | |
| | | @Autowired |
| | | private ObjectMapper objectMapper; |
| | | |
| | | @Autowired |
| | | private IMessageSenderService messageSenderService; |
| | | |
| | | @Override |
| | | public Boolean fastUpload(String workspaceId, String fingerprint) { |
| | |
| | | .map(MediaFileDTO::getTinnyFingerprint) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public List<String> getExistTinyFingerprints(String workspaceId, List<String> tinyFingerprints) { |
| | | List<String> tinyFingerprintList = this.getAllTinyFingerprintsByWorkspaceId(workspaceId); |
| | | return tinyFingerprints |
| | | .stream() |
| | | .filter(tinyFingerprintList::contains) |
| | | .collect(Collectors.toList()); |
| | | |
| | | } |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK, outputChannel = ChannelName.OUTBOUND) |
| | | public void handleFileUploadCallBack(CommonTopicReceiver receiver) { |
| | | FileUploadCallback callback = objectMapper.convertValue(receiver.getData(), FileUploadCallback.class); |
| | | |
| | | String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + receiver.getGateway() |
| | | + TopicConst.EVENTS_SUF + TopicConst._REPLY_SUF; |
| | | CommonTopicResponse<Object> data = CommonTopicResponse.builder() |
| | | .timestamp(System.currentTimeMillis()) |
| | | .method(EventsMethodEnum.FILE_UPLOAD_CALLBACK.getMethod()) |
| | | .data(ResponseResult.success()) |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .build(); |
| | | if (callback.getResult() == ResponseResult.CODE_SUCCESS) { |
| | | String jobId = callback.getFile().getExt().getFlightId(); |
| | | Optional<WaylineJobDTO> jobOpt = waylineJobService.getJobByJobId(jobId); |
| | | if (jobOpt.isPresent()) { |
| | | int id = fileService.saveFile(jobOpt.get().getWorkspaceId(), callback.getFile()); |
| | | if (id <= 0) { |
| | | data.setData(ResponseResult.error()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | messageSenderService.publish(topic, data); |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.storage.controller; |
| | | |
| | | import com.dji.sample.common.model.ResponseResult; |
| | | import com.dji.sample.component.oss.model.AliyunOSSConfiguration; |
| | | import com.dji.sample.component.oss.model.MinIOConfiguration; |
| | | import com.dji.sample.media.model.StsCredentialsDTO; |
| | | import com.dji.sample.storage.service.IStorageService; |
| | | import com.dji.sample.storage.service.impl.AliyunStorageServiceImpl; |
| | | import com.dji.sample.storage.service.impl.MinIOStorageServiceImpl; |
| | | 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; |
| | |
| | | */ |
| | | @RestController |
| | | @RequestMapping("${url.storage.prefix}${url.storage.version}/workspaces/") |
| | | @Slf4j |
| | | public class StorageController { |
| | | |
| | | @Autowired |
| | | private IStorageService storageService; |
| | | |
| | | @Autowired |
| | | private void setOssService(@Autowired(required = false) AliyunStorageServiceImpl aliyunStorageService, |
| | | @Autowired(required = false) MinIOStorageServiceImpl minIOStorageService) { |
| | | if (AliyunOSSConfiguration.enable) { |
| | | this.storageService = aliyunStorageService; |
| | | return; |
| | | } |
| | | if (MinIOConfiguration.enable) { |
| | | this.storageService = minIOStorageService; |
| | | return; |
| | | } |
| | | log.error("storageService is null."); |
| | | } |
| | | /** |
| | | * Get temporary credentials for uploading the media and wayline in DJI Pilot. |
| | | * @param workspaceId |
| | |
| | | StsCredentialsDTO stsCredentials = storageService.getSTSCredentials(); |
| | | return ResponseResult.success(stsCredentials); |
| | | } |
| | | |
| | | } |
| | |
| | | package com.dji.sample.storage.service; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import com.dji.sample.media.model.StsCredentialsDTO; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | * @return temporary credentials object |
| | | */ |
| | | StsCredentialsDTO getSTSCredentials(); |
| | | |
| | | /** |
| | | * Handles requests from the dock to obtain temporary credentials. |
| | | * @param receiver |
| | | * @param headers |
| | | */ |
| | | void replyConfigGet(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | } |
| New file |
| | |
| | | package com.dji.sample.storage.service.impl; |
| | | |
| | | import com.dji.sample.component.mqtt.model.*; |
| | | import com.dji.sample.component.mqtt.service.IMessageSenderService; |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.service.impl.OssServiceContext; |
| | | import com.dji.sample.media.model.StsCredentialsDTO; |
| | | import com.dji.sample.storage.service.IStorageService; |
| | | 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; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2022/3/9 |
| | | */ |
| | | @Service |
| | | public class StorageServiceImpl implements IStorageService { |
| | | |
| | | @Autowired |
| | | private IMessageSenderService messageSender; |
| | | |
| | | @Autowired |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public StsCredentialsDTO getSTSCredentials() { |
| | | return StsCredentialsDTO.builder() |
| | | .endpoint(configuration.getEndpoint()) |
| | | .bucket(configuration.getBucket()) |
| | | .credentials(ossService.getCredentials()) |
| | | .provider(configuration.getProvider()) |
| | | .objectKeyPrefix(configuration.getObjectDirPrefix()) |
| | | .region(configuration.getRegion()) |
| | | .build(); |
| | | } |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_STORAGE_CONFIG_GET, outputChannel = ChannelName.OUTBOUND) |
| | | public void replyConfigGet(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | CommonTopicResponse<RequestsReply> response = CommonTopicResponse.<RequestsReply>builder() |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .data(RequestsReply.success(this.getSTSCredentials())) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .method(receiver.getMethod()) |
| | | .build(); |
| | | messageSender.publish(headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF, response); |
| | | } |
| | | } |
| | |
| | | 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.component.oss.model.AliyunOSSConfiguration; |
| | | import com.dji.sample.wayline.model.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.WaylineFileUploadDTO; |
| | | import com.dji.sample.wayline.model.WaylineQueryParam; |
| | | import com.dji.sample.wayline.model.dto.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.dto.WaylineFileUploadDTO; |
| | | import com.dji.sample.wayline.model.param.WaylineQueryParam; |
| | | import com.dji.sample.wayline.service.IWaylineFileService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.net.URL; |
| | | import java.sql.SQLException; |
| | | import java.util.List; |
| | | |
| | | import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; |
| | |
| | | public void getFileUrl(@PathVariable(name = "workspace_id") String workspaceId, |
| | | @PathVariable(name = "wayline_id") String waylineId, HttpServletResponse response) { |
| | | |
| | | WaylineFileDTO wayline = waylineFileService.getWaylineByWaylineId(workspaceId, waylineId); |
| | | URL url = waylineFileService.getObjectUrl(AliyunOSSConfiguration.bucket, wayline.getObjectKey()); |
| | | |
| | | try { |
| | | URL url = waylineFileService.getObjectUrl(workspaceId, waylineId); |
| | | response.sendRedirect(url.toString()); |
| | | } catch (Exception e) { |
| | | } catch (IOException | SQLException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | |
| | | |
| | | return ResponseResult.success(existNamesList); |
| | | } |
| | | |
| | | /** |
| | | * Delete the wayline file in the workspace according to the wayline id. |
| | | * @param workspaceId |
| | | * @param waylineId |
| | | * @return |
| | | */ |
| | | @DeleteMapping("/{workspace_id}/waylines/{wayline_id}") |
| | | public ResponseResult deleteWayline(@PathVariable(name = "workspace_id") String workspaceId, |
| | | @PathVariable(name = "wayline_id") String waylineId) { |
| | | boolean isDel = waylineFileService.deleteByWaylineId(workspaceId, waylineId); |
| | | return isDel ? ResponseResult.success() : ResponseResult.error("Failed to delete wayline."); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.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.wayline.model.dto.WaylineJobDTO; |
| | | import com.dji.sample.wayline.model.param.CreateJobParam; |
| | | import com.dji.sample.wayline.service.IWaylineJobService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.sql.SQLException; |
| | | |
| | | import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @RequestMapping("${url.wayline.prefix}${url.wayline.version}/workspaces") |
| | | @RestController |
| | | public class WaylineJobController { |
| | | |
| | | @Autowired |
| | | private IWaylineJobService waylineJobService; |
| | | |
| | | /** |
| | | * Create a wayline task for the Dock. |
| | | * @param request |
| | | * @param param |
| | | * @param workspaceId |
| | | * @return |
| | | * @throws SQLException |
| | | */ |
| | | @PostMapping("/{workspace_id}/flight-tasks") |
| | | public ResponseResult createJob(HttpServletRequest request, @RequestBody CreateJobParam param, |
| | | @PathVariable(name = "workspace_id") String workspaceId) throws SQLException { |
| | | CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); |
| | | customClaim.setWorkspaceId(workspaceId); |
| | | boolean isCreate = waylineJobService.createJob(param, customClaim); |
| | | return isCreate ? ResponseResult.success() : ResponseResult.error(); |
| | | } |
| | | |
| | | /** |
| | | * Paginate through all jobs in this workspace. |
| | | * @param page |
| | | * @param pageSize |
| | | * @param workspaceId |
| | | * @return |
| | | */ |
| | | @GetMapping("/{workspace_id}/jobs") |
| | | public ResponseResult<PaginationData<WaylineJobDTO>> getJobs(@RequestParam(defaultValue = "1") Long page, |
| | | @RequestParam(name = "page_size", defaultValue = "10") Long pageSize, |
| | | @PathVariable(name = "workspace_id") String workspaceId) { |
| | | PaginationData<WaylineJobDTO> data = waylineJobService.getJobsByWorkspaceId(workspaceId, page, pageSize); |
| | | return ResponseResult.success(data); |
| | | } |
| | | |
| | | /** |
| | | * Issue wayline mission to the dock for execution. |
| | | * @param jobId |
| | | * @param workspaceId |
| | | * @return |
| | | * @throws SQLException |
| | | */ |
| | | @PostMapping("/{workspace_id}/jobs/{job_id}") |
| | | public ResponseResult publishJob(@PathVariable(name = "job_id") String jobId, |
| | | @PathVariable(name = "workspace_id") String workspaceId) throws SQLException { |
| | | waylineJobService.publishFlightTask(workspaceId, jobId); |
| | | return ResponseResult.success(); |
| | | } |
| | | } |
| | |
| | | package com.dji.sample.wayline.dao; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.dji.sample.wayline.model.WaylineFileEntity; |
| | | import com.dji.sample.wayline.model.entity.WaylineFileEntity; |
| | | |
| | | /** |
| | | * @author sean |
| New file |
| | |
| | | package com.dji.sample.wayline.dao; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.dji.sample.wayline.model.entity.WaylineJobEntity; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | public interface IWaylineJobMapper extends BaseMapper<WaylineJobEntity> { |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | @Data |
| | | public class FLightTaskProgress { |
| | | |
| | | private Integer currentStep; |
| | | |
| | | private Integer percent; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class FlightTaskCreateDTO { |
| | | |
| | | private String flightId; |
| | | |
| | | private String type; |
| | | |
| | | private FlightTaskFileDTO file; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class FlightTaskFileDTO { |
| | | |
| | | private String url; |
| | | |
| | | private String sign; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | @Data |
| | | public class FlightTaskProgressExt { |
| | | |
| | | private Integer currentWaypointIndex; |
| | | |
| | | private Integer mediaCount; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | @Data |
| | | public class FlightTaskProgressReceiver { |
| | | |
| | | private FlightTaskProgressExt ext; |
| | | |
| | | private FLightTaskProgress progress; |
| | | |
| | | private String status; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | 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 0.3 |
| | | * @date 2021/12/22 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class WaylineFileDTO { |
| | | |
| | | private String name; |
| | | |
| | | @JsonProperty("id") |
| | | private String waylineId; |
| | | |
| | | private String droneModelKey; |
| | | |
| | | private String sign; |
| | | |
| | | private List<String> payloadModelKeys; |
| | | |
| | | private Boolean favorited; |
| | | |
| | | private List<Integer> templateTypes; |
| | | |
| | | private String objectKey; |
| | | |
| | | @JsonProperty("user_name") |
| | | private String username; |
| | | |
| | | private Long updateTime; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2021/12/23 |
| | | */ |
| | | @Data |
| | | public class WaylineFileUploadDTO { |
| | | |
| | | private String objectKey; |
| | | |
| | | private String name; |
| | | |
| | | private WaylineFileDTO metadata; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.dto; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Data |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | @Builder |
| | | public class WaylineJobDTO { |
| | | |
| | | private String jobId; |
| | | |
| | | private String jobName; |
| | | |
| | | private String fileId; |
| | | |
| | | private String fileName; |
| | | |
| | | private String dockSn; |
| | | |
| | | private String dockName; |
| | | |
| | | private String workspaceId; |
| | | |
| | | private String bid; |
| | | |
| | | private String type; |
| | | |
| | | private String username; |
| | | |
| | | private LocalDateTime updateTime; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.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 0.3 |
| | | * @date 2021/12/22 |
| | | */ |
| | | @Data |
| | | @TableName("wayline_file") |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class WaylineFileEntity implements Serializable { |
| | | |
| | | @TableId(type = IdType.AUTO) |
| | | private Integer id; |
| | | |
| | | @TableField("name") |
| | | private String name; |
| | | |
| | | @TableField("wayline_id") |
| | | private String waylineId; |
| | | |
| | | @TableField("drone_model_key") |
| | | private String droneModelKey; |
| | | |
| | | @TableField("payload_model_keys") |
| | | private String payloadModelKeys; |
| | | |
| | | @TableField("sign") |
| | | private String sign; |
| | | |
| | | @TableField("workspace_id") |
| | | private String workspaceId; |
| | | |
| | | @TableField("favorited") |
| | | private Boolean favorited; |
| | | |
| | | @TableField("template_types") |
| | | private String templateTypes; |
| | | |
| | | @TableField("object_key") |
| | | private String objectKey; |
| | | |
| | | @TableField("user_name") |
| | | private String username; |
| | | |
| | | @TableField(value = "create_time", fill = FieldFill.INSERT) |
| | | private Long createTime; |
| | | |
| | | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateTime; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.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.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | @TableName("wayline_job") |
| | | public class WaylineJobEntity implements Serializable { |
| | | |
| | | @TableId(type = IdType.AUTO) |
| | | private Integer id; |
| | | |
| | | @TableField("job_id") |
| | | private String jobId; |
| | | |
| | | @TableField("name") |
| | | private String name; |
| | | |
| | | @TableField("file_id") |
| | | private String fileId; |
| | | |
| | | @TableField("dock_sn") |
| | | private String dockSn; |
| | | |
| | | @TableField("workspace_id") |
| | | private String workspaceId; |
| | | |
| | | @TableField("bid") |
| | | private String bid; |
| | | |
| | | @TableField("type") |
| | | private String type; |
| | | |
| | | @TableField("username") |
| | | private String username; |
| | | |
| | | @TableField(value = "create_time", fill = FieldFill.INSERT) |
| | | private Long createTime; |
| | | |
| | | @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) |
| | | private Long updateTime; |
| | | |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.param; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Data |
| | | public class CreateJobParam { |
| | | |
| | | private String name; |
| | | |
| | | private String fileId; |
| | | |
| | | private String dockSn; |
| | | |
| | | private String type; |
| | | |
| | | private boolean immediate; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.model.param; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 0.3 |
| | | * @date 2021/12/22 |
| | | */ |
| | | @Data |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class WaylineQueryParam { |
| | | |
| | | private boolean favorited; |
| | | |
| | | @Builder.Default |
| | | private int page = 1; |
| | | |
| | | @Builder.Default |
| | | private int pageSize = 10; |
| | | |
| | | private String orderBy; |
| | | |
| | | private Integer[] templateType; |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.service; |
| | | |
| | | import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
| | | import org.springframework.messaging.MessageHeaders; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | public interface IFlightTaskService { |
| | | |
| | | /** |
| | | * Handle the progress messages of the flight tasks reported by the dock. |
| | | * @param receiver |
| | | */ |
| | | void handleProgress(CommonTopicReceiver receiver, MessageHeaders headers); |
| | | } |
| | |
| | | package com.dji.sample.wayline.service; |
| | | |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.wayline.model.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.WaylineQueryParam; |
| | | import com.dji.sample.wayline.model.dto.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.param.WaylineQueryParam; |
| | | |
| | | import java.net.URL; |
| | | import java.sql.SQLException; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * @author sean |
| | |
| | | * @param waylineId |
| | | * @return |
| | | */ |
| | | WaylineFileDTO getWaylineByWaylineId(String workspaceId, String waylineId); |
| | | Optional<WaylineFileDTO> getWaylineByWaylineId(String workspaceId, String waylineId); |
| | | |
| | | /** |
| | | * Get the download address of the file object. |
| | | * @param bucket bucket name |
| | | * @param objectKey object name |
| | | * @param workspaceId |
| | | * @param waylineId |
| | | * @return |
| | | */ |
| | | URL getObjectUrl(String bucket, String objectKey); |
| | | URL getObjectUrl(String workspaceId, String waylineId) throws SQLException; |
| | | |
| | | /** |
| | | * Save the basic information of the wayline file. |
| | |
| | | * @return |
| | | */ |
| | | List<String> getDuplicateNames(String workspaceId, List<String> names); |
| | | |
| | | /** |
| | | * Delete the wayline file based on the wayline id. |
| | | * @param workspaceId |
| | | * @param waylineId |
| | | */ |
| | | Boolean deleteByWaylineId(String workspaceId, String waylineId); |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.service; |
| | | |
| | | import com.dji.sample.common.model.CustomClaim; |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.wayline.model.dto.WaylineJobDTO; |
| | | import com.dji.sample.wayline.model.param.CreateJobParam; |
| | | |
| | | import java.sql.SQLException; |
| | | import java.util.Optional; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | public interface IWaylineJobService { |
| | | |
| | | /** |
| | | * Create a wayline mission for the dock. |
| | | * @param param |
| | | * @param customClaim user info |
| | | * @return |
| | | */ |
| | | Boolean createJob(CreateJobParam param, CustomClaim customClaim) throws SQLException; |
| | | |
| | | /** |
| | | * Issue wayline mission to the dock for execution. |
| | | * @param workspaceId |
| | | * @param jobId |
| | | * @return |
| | | */ |
| | | void publishFlightTask(String workspaceId, String jobId) throws SQLException; |
| | | |
| | | /** |
| | | * Query job information based on job id. |
| | | * @param jobId |
| | | * @return job information |
| | | */ |
| | | Optional<WaylineJobDTO> getJobByJobId(String jobId); |
| | | |
| | | /** |
| | | * Update job data. |
| | | * @param dto |
| | | * @return |
| | | */ |
| | | Boolean updateJob(WaylineJobDTO dto); |
| | | |
| | | /** |
| | | * Paginate through all jobs in this workspace. |
| | | * @param workspaceId |
| | | * @param page |
| | | * @param pageSize |
| | | * @return |
| | | */ |
| | | PaginationData<WaylineJobDTO> getJobsByWorkspaceId(String workspaceId, long page, long pageSize); |
| | | } |
| New file |
| | |
| | | package com.dji.sample.wayline.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.BizCodeEnum; |
| | | import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
| | | import com.dji.sample.component.websocket.service.ISendMessageService; |
| | | import com.dji.sample.component.websocket.service.IWebSocketManageService; |
| | | import com.dji.sample.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.model.enums.UserTypeEnum; |
| | | import com.dji.sample.wayline.model.dto.FlightTaskProgressReceiver; |
| | | import com.dji.sample.wayline.service.IFlightTaskService; |
| | | 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; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/9 |
| | | */ |
| | | @Service |
| | | @Slf4j |
| | | public class FlightTaskServiceImpl implements IFlightTaskService { |
| | | |
| | | @Autowired |
| | | private IMessageSenderService messageSender; |
| | | |
| | | @Autowired |
| | | private ObjectMapper mapper; |
| | | |
| | | @Autowired |
| | | private ISendMessageService websocketMessageService; |
| | | |
| | | @Autowired |
| | | private IWebSocketManageService webSocketManageService; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS, outputChannel = ChannelName.OUTBOUND) |
| | | public void handleProgress(CommonTopicReceiver receiver, MessageHeaders headers) { |
| | | EventsReceiver<FlightTaskProgressReceiver> eventsReceiver = mapper.convertValue(receiver.getData(), |
| | | new TypeReference<EventsReceiver<FlightTaskProgressReceiver>>(){}); |
| | | eventsReceiver.setBid(receiver.getBid()); |
| | | |
| | | log.info("Task progress: " + eventsReceiver.getOutput().getProgress().toString()); |
| | | |
| | | if (eventsReceiver.getResult() != ResponseResult.CODE_SUCCESS) { |
| | | log.error("Error code: " + eventsReceiver.getResult()); |
| | | } |
| | | |
| | | DeviceDTO device = (DeviceDTO) redisOps.get(RedisConst.DEVICE_ONLINE_PREFIX + receiver.getGateway()); |
| | | websocketMessageService.sendBatch( |
| | | webSocketManageService.getValueWithWorkspaceAndUserType( |
| | | device.getWorkspaceId(), UserTypeEnum.WEB.getVal()), |
| | | CustomWebSocketMessage.builder() |
| | | .data(eventsReceiver) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .bizCode(BizCodeEnum.FLIGHT_TASK_PROGRESS.getCode()) |
| | | .build()); |
| | | |
| | | if (receiver.getNeedReply() == 1) { |
| | | String topic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF; |
| | | messageSender.publish(topic, |
| | | CommonTopicResponse.builder() |
| | | .tid(receiver.getTid()) |
| | | .bid(receiver.getBid()) |
| | | .method(EventsMethodEnum.FLIGHT_TASK_PROGRESS.getMethod()) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .data(ResponseResult.success()) |
| | | .build()); |
| | | } |
| | | } |
| | | } |
| | |
| | | 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.component.oss.model.AliyunOSSConfiguration; |
| | | import com.dji.sample.component.oss.model.MinIOConfiguration; |
| | | import com.dji.sample.component.oss.service.IOssService; |
| | | import com.dji.sample.component.oss.service.impl.AliyunOssServiceImpl; |
| | | import com.dji.sample.component.oss.service.impl.MinIOServiceImpl; |
| | | import com.dji.sample.component.oss.model.OssConfiguration; |
| | | import com.dji.sample.component.oss.service.impl.OssServiceContext; |
| | | import com.dji.sample.wayline.dao.IWaylineFileMapper; |
| | | import com.dji.sample.wayline.model.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.WaylineFileEntity; |
| | | import com.dji.sample.wayline.model.WaylineQueryParam; |
| | | import com.dji.sample.wayline.model.dto.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.entity.WaylineFileEntity; |
| | | import com.dji.sample.wayline.model.param.WaylineQueryParam; |
| | | import com.dji.sample.wayline.service.IWaylineFileService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.DigestUtils; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.net.URL; |
| | | import java.sql.SQLException; |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | @Slf4j |
| | | public class WaylineFileServiceImpl implements IWaylineFileService { |
| | | |
| | | @Autowired |
| | | private IWaylineFileMapper mapper; |
| | | |
| | | private IOssService ossService; |
| | | @Autowired |
| | | private OssServiceContext ossService; |
| | | |
| | | @Autowired |
| | | private void setOssService(@Autowired(required = false) AliyunOssServiceImpl aliyunOssService, |
| | | @Autowired(required = false) MinIOServiceImpl minIOService) { |
| | | if (AliyunOSSConfiguration.enable) { |
| | | this.ossService = aliyunOssService; |
| | | return; |
| | | } |
| | | if (MinIOConfiguration.enable) { |
| | | this.ossService = minIOService; |
| | | return; |
| | | } |
| | | log.error("ossService is null."); |
| | | } |
| | | private OssConfiguration configuration; |
| | | |
| | | @Override |
| | | public PaginationData<WaylineFileDTO> getWaylinesByParam(String workspaceId, WaylineQueryParam param) { |
| | |
| | | } |
| | | |
| | | @Override |
| | | public WaylineFileDTO getWaylineByWaylineId(String workspaceId, String waylineId) { |
| | | return this.entityConvertToDTO( |
| | | mapper.selectOne( |
| | | new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId))); |
| | | public Optional<WaylineFileDTO> getWaylineByWaylineId(String workspaceId, String waylineId) { |
| | | return Optional.ofNullable( |
| | | this.entityConvertToDTO( |
| | | mapper.selectOne( |
| | | new LambdaQueryWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId)))); |
| | | } |
| | | |
| | | @Override |
| | | public URL getObjectUrl(String bucket, String objectKey) { |
| | | return ossService.getObjectUrl(bucket, objectKey); |
| | | public URL getObjectUrl(String workspaceId, String waylineId) throws SQLException { |
| | | Optional<WaylineFileDTO> waylineOpt = this.getWaylineByWaylineId(workspaceId, waylineId); |
| | | if (waylineOpt.isEmpty()) { |
| | | throw new SQLException(waylineId + " does not exist."); |
| | | } |
| | | return ossService.getObjectUrl(configuration.getBucket(), waylineOpt.get().getObjectKey()); |
| | | } |
| | | |
| | | @Override |
| | |
| | | file.setWaylineId(UUID.randomUUID().toString()); |
| | | file.setWorkspaceId(workspaceId); |
| | | |
| | | byte[] object = ossService.getObject(configuration.getBucket(), metadata.getObjectKey()); |
| | | if (object.length == 0) { |
| | | throw new RuntimeException("The file " + metadata.getObjectKey() + |
| | | " does not exist in the bucket[" + configuration.getBucket() + "]."); |
| | | } |
| | | |
| | | file.setSign(DigestUtils.md5DigestAsHex(object)); |
| | | int insertId = mapper.insert(file); |
| | | return insertId > 0 ? file.getId() : insertId; |
| | | } |
| | |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean deleteByWaylineId(String workspaceId, String waylineId) { |
| | | Optional<WaylineFileDTO> waylineOpt = this.getWaylineByWaylineId(workspaceId, waylineId); |
| | | if (waylineOpt.isEmpty()) { |
| | | return true; |
| | | } |
| | | WaylineFileDTO wayline = waylineOpt.get(); |
| | | boolean isDel = mapper.delete(new LambdaUpdateWrapper<WaylineFileEntity>() |
| | | .eq(WaylineFileEntity::getWorkspaceId, workspaceId) |
| | | .eq(WaylineFileEntity::getWaylineId, waylineId)) |
| | | > 0; |
| | | if (!isDel) { |
| | | return false; |
| | | } |
| | | return ossService.deleteObject(configuration.getBucket(), wayline.getObjectKey()); |
| | | } |
| | | |
| | | /** |
| | | * Convert database entity objects into wayline data transfer object. |
| | | * @param entity |
| | | * @return |
| | | */ |
| | | private WaylineFileDTO entityConvertToDTO(WaylineFileEntity entity) { |
| | | WaylineFileDTO.WaylineFileDTOBuilder builder = WaylineFileDTO.builder(); |
| | | |
| | | if (entity != null) { |
| | | builder.droneModelKey(entity.getDroneModelKey()) |
| | | .favorited(entity.getFavorited()) |
| | | .name(entity.getName()) |
| | | .payloadModelKeys(entity.getPayloadModelKeys() != null ? |
| | | Arrays.asList(entity.getPayloadModelKeys().split(",")) : null) |
| | | .templateTypes(Arrays.stream(entity.getTemplateTypes().split(",")) |
| | | .map(Integer::parseInt) |
| | | .collect(Collectors.toList())) |
| | | .username(entity.getUsername()) |
| | | .objectKey(entity.getObjectKey()) |
| | | .updateTime(entity.getUpdateTime()) |
| | | .waylineId(entity.getWaylineId()); |
| | | if (entity == null) { |
| | | return null; |
| | | } |
| | | return WaylineFileDTO.builder() |
| | | .droneModelKey(entity.getDroneModelKey()) |
| | | .favorited(entity.getFavorited()) |
| | | .name(entity.getName()) |
| | | .payloadModelKeys(entity.getPayloadModelKeys() != null ? |
| | | Arrays.asList(entity.getPayloadModelKeys().split(",")) : null) |
| | | .templateTypes(Arrays.stream(entity.getTemplateTypes().split(",")) |
| | | .map(Integer::parseInt) |
| | | .collect(Collectors.toList())) |
| | | .username(entity.getUsername()) |
| | | .objectKey(entity.getObjectKey()) |
| | | .sign(entity.getSign()) |
| | | .updateTime(entity.getUpdateTime()) |
| | | .waylineId(entity.getWaylineId()) |
| | | .build(); |
| | | |
| | | return builder.build(); |
| | | } |
| | | |
| | | /** |
| New file |
| | |
| | | package com.dji.sample.wayline.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.CustomClaim; |
| | | import com.dji.sample.common.model.Pagination; |
| | | import com.dji.sample.common.model.PaginationData; |
| | | import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
| | | import com.dji.sample.component.mqtt.model.ServiceReply; |
| | | import com.dji.sample.component.mqtt.model.ServicesMethodEnum; |
| | | import com.dji.sample.component.mqtt.model.TopicConst; |
| | | 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.manage.model.dto.DeviceDTO; |
| | | import com.dji.sample.manage.service.IDeviceService; |
| | | import com.dji.sample.wayline.dao.IWaylineJobMapper; |
| | | import com.dji.sample.wayline.model.dto.FlightTaskCreateDTO; |
| | | import com.dji.sample.wayline.model.dto.FlightTaskFileDTO; |
| | | import com.dji.sample.wayline.model.dto.WaylineFileDTO; |
| | | import com.dji.sample.wayline.model.dto.WaylineJobDTO; |
| | | import com.dji.sample.wayline.model.entity.WaylineJobEntity; |
| | | import com.dji.sample.wayline.model.param.CreateJobParam; |
| | | import com.dji.sample.wayline.service.IWaylineFileService; |
| | | import com.dji.sample.wayline.service.IWaylineJobService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.net.URL; |
| | | import java.sql.SQLException; |
| | | import java.time.Instant; |
| | | import java.time.LocalDateTime; |
| | | import java.time.ZoneId; |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author sean |
| | | * @version 1.1 |
| | | * @date 2022/6/1 |
| | | */ |
| | | @Service |
| | | @Transactional |
| | | @Slf4j |
| | | public class WaylineJobServiceImpl implements IWaylineJobService { |
| | | |
| | | @Autowired |
| | | private IWaylineJobMapper mapper; |
| | | |
| | | @Autowired |
| | | private IWaylineFileService waylineFileService; |
| | | |
| | | @Autowired |
| | | private IDeviceService deviceService; |
| | | |
| | | @Autowired |
| | | private IMessageSenderService messageSender; |
| | | |
| | | @Autowired |
| | | private RedisOpsUtils redisOps; |
| | | |
| | | @Override |
| | | public Boolean createJob(CreateJobParam param, CustomClaim customClaim) throws SQLException { |
| | | if (param == null) { |
| | | return false; |
| | | } |
| | | WaylineJobEntity jobEntity = WaylineJobEntity.builder() |
| | | .name(param.getName()) |
| | | .dockSn(param.getDockSn()) |
| | | .fileId(param.getFileId()) |
| | | .username(customClaim.getUsername()) |
| | | .workspaceId(customClaim.getWorkspaceId()) |
| | | .jobId(UUID.randomUUID().toString()) |
| | | .type(param.getType()) |
| | | .build(); |
| | | int id = mapper.insert(jobEntity); |
| | | if (id <= 0) { |
| | | return false; |
| | | } |
| | | if (param.isImmediate()) { |
| | | publishFlightTask(jobEntity.getWorkspaceId(), jobEntity.getJobId()); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public void publishFlightTask(String workspaceId, String jobId) throws SQLException { |
| | | // get job |
| | | Optional<WaylineJobDTO> waylineJob = this.getJobByJobId(jobId); |
| | | if (waylineJob.isEmpty()) { |
| | | throw new IllegalArgumentException("Job doesn't exist."); |
| | | } |
| | | |
| | | long expire = redisOps.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + waylineJob.get().getDockSn()); |
| | | if (expire < 0) { |
| | | throw new RuntimeException("Dock is offline."); |
| | | } |
| | | |
| | | // get wayline file |
| | | Optional<WaylineFileDTO> waylineFile = waylineFileService.getWaylineByWaylineId(workspaceId, waylineJob.get().getFileId()); |
| | | if (waylineFile.isEmpty()) { |
| | | throw new IllegalArgumentException("Wayline file doesn't exist."); |
| | | } |
| | | |
| | | // get file url |
| | | URL url = waylineFileService.getObjectUrl(workspaceId, waylineFile.get().getWaylineId()); |
| | | |
| | | WaylineJobDTO job = waylineJob.get(); |
| | | FlightTaskCreateDTO flightTask = FlightTaskCreateDTO.builder() |
| | | .flightId(jobId) |
| | | .type(job.getType()) |
| | | .file(FlightTaskFileDTO.builder() |
| | | .url(url.toString()) |
| | | .sign(waylineFile.get().getSign()) |
| | | .build()) |
| | | .build(); |
| | | |
| | | String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + |
| | | job.getDockSn() + TopicConst.SERVICES_SUF; |
| | | CommonTopicResponse<Object> response = CommonTopicResponse.builder() |
| | | .tid(UUID.randomUUID().toString()) |
| | | .bid(UUID.randomUUID().toString()) |
| | | .timestamp(System.currentTimeMillis()) |
| | | .data(flightTask) |
| | | .method(ServicesMethodEnum.FLIGHTTASK_CREATE.getMethod()) |
| | | .build(); |
| | | |
| | | Optional<ServiceReply> serviceReplyOpt = messageSender.publishWithReply(topic, response); |
| | | if (serviceReplyOpt.isEmpty()) { |
| | | log.info("Timeout to receive reply."); |
| | | throw new RuntimeException("Timeout to receive reply."); |
| | | } |
| | | if (serviceReplyOpt.get().getResult() != 0) { |
| | | log.info("Error code: {}", serviceReplyOpt.get().getResult()); |
| | | throw new RuntimeException("Error code: " + serviceReplyOpt.get().getResult()); |
| | | } |
| | | |
| | | job.setBid(response.getBid()); |
| | | boolean isUpd = this.updateJob(job); |
| | | if (!isUpd) { |
| | | throw new SQLException("Failed to update data."); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Optional<WaylineJobDTO> getJobByJobId(String jobId) { |
| | | WaylineJobEntity jobEntity = mapper.selectOne( |
| | | new LambdaQueryWrapper<WaylineJobEntity>() |
| | | .eq(WaylineJobEntity::getJobId, jobId)); |
| | | return Optional.ofNullable(entity2Dto(jobEntity)); |
| | | } |
| | | |
| | | @Override |
| | | public Boolean updateJob(WaylineJobDTO dto) { |
| | | return mapper.update(this.dto2Entity(dto), |
| | | new LambdaUpdateWrapper<WaylineJobEntity>() |
| | | .eq(WaylineJobEntity::getWorkspaceId, dto.getWorkspaceId()) |
| | | .eq(WaylineJobEntity::getJobId, dto.getJobId())) |
| | | > 0; |
| | | } |
| | | |
| | | @Override |
| | | public PaginationData<WaylineJobDTO> getJobsByWorkspaceId(String workspaceId, long page, long pageSize) { |
| | | Page<WaylineJobEntity> pageData = mapper.selectPage( |
| | | new Page<WaylineJobEntity>(page, pageSize), |
| | | new LambdaQueryWrapper<WaylineJobEntity>() |
| | | .eq(WaylineJobEntity::getWorkspaceId, workspaceId)); |
| | | List<WaylineJobDTO> records = pageData.getRecords() |
| | | .stream() |
| | | .map(this::entity2Dto) |
| | | .collect(Collectors.toList()); |
| | | |
| | | return new PaginationData<WaylineJobDTO>(records, new Pagination(pageData)); |
| | | } |
| | | |
| | | private WaylineJobEntity dto2Entity(WaylineJobDTO dto) { |
| | | WaylineJobEntity.WaylineJobEntityBuilder builder = WaylineJobEntity.builder(); |
| | | if (dto == null) { |
| | | return builder.build(); |
| | | } |
| | | return builder.type(dto.getType()) |
| | | .bid(dto.getBid()) |
| | | .name(dto.getJobName()) |
| | | .build(); |
| | | } |
| | | |
| | | private WaylineJobDTO entity2Dto(WaylineJobEntity entity) { |
| | | if (entity == null) { |
| | | return null; |
| | | } |
| | | return WaylineJobDTO.builder() |
| | | .jobId(entity.getJobId()) |
| | | .bid(entity.getBid()) |
| | | .updateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getUpdateTime()), ZoneId.systemDefault())) |
| | | .jobName(entity.getName()) |
| | | .fileId(entity.getFileId()) |
| | | .fileName(waylineFileService.getWaylineByWaylineId(entity.getWorkspaceId(), entity.getFileId()) |
| | | .orElse(WaylineFileDTO.builder().build()).getName()) |
| | | .dockSn(entity.getDockSn()) |
| | | .dockName(deviceService.getDeviceBySn(entity.getDockSn()) |
| | | .orElse(DeviceDTO.builder().build()).getNickname()) |
| | | .username(entity.getUsername()) |
| | | .workspaceId(entity.getWorkspaceId()) |
| | | .type(entity.getType()) |
| | | .build(); |
| | | } |
| | | } |
| | |
| | | druid: |
| | | type: com.alibaba.druid.pool.DruidDataSource |
| | | driver-class-name: com.mysql.cj.jdbc.Driver |
| | | url: jdbc:mysql://localhost:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true |
| | | url: jdbc:mysql://cloud_api_sample_mysql:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true |
| | | username: root |
| | | password: root |
| | | initial-size: 10 |
| | |
| | | max-active: 20 |
| | | max-wait: 60000 |
| | | |
| | | jackson: |
| | | property-naming-strategy: SNAKE_CASE |
| | | date-format: yyyy-MM-dd HH:mm:ss |
| | | default-property-inclusion: NON_NULL |
| | | deserialization: |
| | | FAIL_ON_UNKNOWN_PROPERTIES: false |
| | | redis: |
| | | host: cloud_api_sample_redis |
| | | port: 6379 |
| | | database: 0 |
| | | username: # if you enable |
| | | password: |
| | | lettuce: |
| | | pool: |
| | | max-active: 8 |
| | | max-idle: 8 |
| | | min-idle: 0 |
| | | |
| | | |
| | | jwt: |
| | | issuer: DJI |
| | |
| | | |
| | | mqtt: |
| | | protocol: tcp |
| | | host: Please enter the address of the emqx server. # Example: 192.168.1.1 |
| | | host: Please enter your ip. # 192.168.1.1 |
| | | port: 1883 |
| | | username: JavaServer |
| | | password: 123456 |
| | | client-id: 123456 |
| | | # Topics that need to be subscribed when initially connecting to mqtt, multiple topics are divided by ",". |
| | | inbound-topic: sys/product/+/status |
| | | inbound-topic: sys/product/+/status,thing/product/+/requests |
| | | |
| | | url: |
| | | manage: |
| | |
| | | version: /api/v1 |
| | | |
| | | # Tutorial: https://help.aliyun.com/document_detail/100624.htm?spm=a2c4g.11186623.0.0.74075e34eIhK7T#concept-xzh-nzk-2gb |
| | | aliyun: |
| | | oss: |
| | | enable: false |
| | | endpoint: Please enter your endpoint. # Example: https://oss-cn-shenzhen.aliyuncs.com |
| | | access-key: Please enter your access key. |
| | | secret-key: Please enter your secret key. |
| | | expire: 3600 |
| | | region: Please enter oss region. # Example: cn-shenzhen |
| | | role-session-name: Please enter session name. # A custom role session name to distinguish the different tokens, for example it could be filled in as SessionTest. |
| | | role-arn: Please enter role ARN. # Example: acs:ram::123456789:role/oss |
| | | bucket: Please enter bucket name. |
| | | object-dir-prefix: Please enter object prefix. |
| | | oss: |
| | | enable: true |
| | | provider: ali # @see com.dji.sample.component.OssConfiguration.model.enums.OssTypeEnum |
| | | endpoint: https://oss-cn-hangzhou.aliyuncs.com |
| | | access-key: Please enter your access key. |
| | | secret-key: Please enter your secret key. |
| | | expire: 3600 |
| | | region: Please enter your oss region. # cn-hangzhou |
| | | role-session-name: cloudApi |
| | | role-arn: Please enter your role arn. # acs:ram::123456789:role/stsrole |
| | | bucket: Please enter your bucket name. |
| | | object-dir-prefix: Please enter a folder name. |
| | | |
| | | #oss: |
| | | # enable: true |
| | | # provider: aws |
| | | # endpoint: https://s3.us-east-1.amazonaws.com |
| | | # access-key: |
| | | # secret-key: |
| | | # expire: 3600 |
| | | # region: us-east-1 |
| | | # role-session-name: cloudApi |
| | | # role-arn: |
| | | # bucket: cloudapi-bucket |
| | | # object-dir-prefix: wayline |
| | | |
| | | # MinIO is temporarily unavailable. |
| | | minio: |
| | | enable: false |
| | | endpoint: Please enter your endpoint. #http://192.168.1.1:9000/ |
| | | access-key: minioadmin |
| | | secret-key: minioadmin |
| | | bucket: Please enter bucket name. |
| | | expire: 3600 |
| | | region: Please enter minio region. |
| | | object-dir-prefix: Please enter object prefix. |
| | | #oss: |
| | | # enable: false |
| | | # provider: minio |
| | | # endpoint: |
| | | # access-key: |
| | | # secret-key: |
| | | # bucket: |
| | | # expire: |
| | | # region: |
| | | # object-dir-prefix: |
| | | |
| | | logging: |
| | | level: |