Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
GeoFlyApi
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
GeoFly
GeoFlyApi
Commits
7f6048a8
Commit
7f6048a8
authored
Aug 06, 2026
by
真的三个金的鑫
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/hk' into hk
parents
613dd868
1181476f
Show whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
543 additions
and
44 deletions
+543
-44
cloud-sdk/src/main/java/com/dji/sdk/cloudapi/livestream/LiveStartPushResponse.java
+27
-0
cloud-sdk/src/main/java/com/dji/sdk/cloudapi/livestream/api/AbstractLivestreamService.java
+2
-2
pom.xml
+16
-0
sample/src/main/java/com/dji/sample/ai/controller/AiInfoController.java
+58
-0
sample/src/main/java/com/dji/sample/ai/model/dto/TopicAiInfoDTO.java
+42
-0
sample/src/main/java/com/dji/sample/ai/service/IAiInfoService.java
+8
-0
sample/src/main/java/com/dji/sample/ai/service/impl/AiInfoServiceImpl.java
+89
-3
sample/src/main/java/com/dji/sample/common/util/JwtUtil.java
+1
-1
sample/src/main/java/com/dji/sample/component/websocket/config/AuthPrincipalHandler.java
+8
-3
sample/src/main/java/com/dji/sample/component/websocket/config/MyWebSocketHandler.java
+109
-11
sample/src/main/java/com/dji/sample/component/websocket/service/impl/WebSocketMessageServiceImpl.java
+5
-2
sample/src/main/java/com/dji/sample/configuration/mvc/GlobalMVCConfigurer.java
+17
-0
sample/src/main/java/com/dji/sample/manage/controller/DeviceController.java
+38
-2
sample/src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java
+24
-0
sample/src/main/java/com/dji/sample/manage/controller/UserController.java
+2
-1
sample/src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java
+8
-0
sample/src/main/java/com/dji/sample/manage/model/enums/OperateRecordTypeEnum.java
+7
-1
sample/src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java
+9
-0
sample/src/main/java/com/dji/sample/manage/service/IDeviceService.java
+11
-0
sample/src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java
+12
-0
sample/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
+41
-0
sample/src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java
+1
-12
sample/src/main/java/com/dji/sample/manage/service/impl/SDKDeviceService.java
+2
-0
sample/src/main/resources/application.yml
+6
-6
No files found.
cloud-sdk/src/main/java/com/dji/sdk/cloudapi/livestream/LiveStartPushResponse.java
0 → 100644
View file @
7f6048a8
package
com
.
dji
.
sdk
.
cloudapi
.
livestream
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
import
java.util.List
;
/**
* Response output for live_start_push services_reply.
* Newer DJI firmware returns {"origin_video_id": []} in the output field.
*/
public
class
LiveStartPushResponse
{
@JsonProperty
(
"origin_video_id"
)
private
List
<
String
>
originVideoId
;
public
LiveStartPushResponse
()
{
}
public
List
<
String
>
getOriginVideoId
()
{
return
originVideoId
;
}
public
LiveStartPushResponse
setOriginVideoId
(
List
<
String
>
originVideoId
)
{
this
.
originVideoId
=
originVideoId
;
return
this
;
}
}
cloud-sdk/src/main/java/com/dji/sdk/cloudapi/livestream/api/AbstractLivestreamService.java
View file @
7f6048a8
...
...
@@ -52,9 +52,9 @@ public abstract class AbstractLivestreamService {
* @param request data
* @return services_reply
*/
public
TopicServicesResponse
<
ServicesReplyData
<
String
>>
liveStartPush
(
GatewayManager
gateway
,
LiveStartPushRequest
request
)
{
public
TopicServicesResponse
<
ServicesReplyData
<
LiveStartPushResponse
>>
liveStartPush
(
GatewayManager
gateway
,
LiveStartPushRequest
request
)
{
return
servicesPublish
.
publish
(
new
TypeReference
<
String
>()
{},
new
TypeReference
<
LiveStartPushResponse
>()
{},
gateway
.
getGatewaySn
(),
LiveStreamMethodEnum
.
LIVE_START_PUSH
.
getMethod
(),
request
,
...
...
pom.xml
View file @
7f6048a8
...
...
@@ -105,6 +105,22 @@
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<version>
3.10.1
</version>
<!-- JDK 11 推荐用 3.8+ 版本 -->
<configuration>
<!-- 统一为 JDK 11,消除版本不匹配警告 -->
<release>
11
</release>
<encoding>
UTF-8
</encoding>
<!-- 可选:关闭严格泛型检查(避免额外报错) -->
<compilerArgs>
<arg>
-Xlint:-unchecked
</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
sample/src/main/java/com/dji/sample/ai/controller/AiInfoController.java
View file @
7f6048a8
...
...
@@ -18,6 +18,12 @@ import org.springframework.web.bind.annotation.*;
import
javax.servlet.http.HttpServletRequest
;
import
javax.validation.Valid
;
import
com.dji.sample.ai.model.dto.TopicAiInfoDTO
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
java.time.Instant
;
import
java.time.LocalDateTime
;
import
java.time.ZoneId
;
import
static
com
.
dji
.
sample
.
component
.
AuthInterceptor
.
TOKEN_CLAIM
;
...
...
@@ -35,6 +41,9 @@ public class AiInfoController {
@Autowired
private
IAiInfoService
aiInfoService
;
@Autowired
private
ObjectMapper
objectMapper
;
/**
* Paging to query all users in a workspace.
* @param param param
...
...
@@ -50,4 +59,53 @@ public class AiInfoController {
return
HttpResultResponse
.
success
(
paginationData
);
}
@PostMapping
(
"/add"
)
public
HttpResultResponse
<
AiInfoDTO
>
addAiInfo
(
@RequestBody
@Valid
AiInfoDTO
aiInfoDTO
)
{
AiInfoDTO
dto
=
aiInfoService
.
createAiInfo
(
aiInfoDTO
);
return
HttpResultResponse
.
success
(
dto
);
}
@PostMapping
(
"/addFromTopic"
)
public
HttpResultResponse
<
AiInfoDTO
>
addAiInfoFromTopic
(
@RequestBody
TopicAiInfoDTO
topicDto
)
throws
Exception
{
AiInfoDTO
dto
=
new
AiInfoDTO
();
dto
.
setDeviceSn
(
topicDto
.
getDeviceSn
());
dto
.
setPayloadSn
(
topicDto
.
getPayloadSn
());
dto
.
setWarnType
(
topicDto
.
getWarnType
());
dto
.
setWarnEvent
(
topicDto
.
getWarnEvent
());
dto
.
setImageUrl
(
topicDto
.
getImageUrl
());
dto
.
setWarnLocation
(
topicDto
.
getWarnLocation
());
dto
.
setAlgorithmType
(
topicDto
.
getAlgorithmType
());
if
(
topicDto
.
getWarnTime
()
!=
null
)
{
dto
.
setWarnTime
(
LocalDateTime
.
ofInstant
(
Instant
.
ofEpochMilli
(
topicDto
.
getWarnTime
()),
ZoneId
.
systemDefault
()));
}
dto
.
setCreateTime
(
LocalDateTime
.
now
());
if
(
topicDto
.
getObj
()
!=
null
)
{
dto
.
setJson
(
objectMapper
.
writeValueAsString
(
topicDto
.
getObj
()));
}
AiInfoDTO
result
=
aiInfoService
.
createAiInfo
(
dto
);
return
HttpResultResponse
.
success
(
result
);
}
@GetMapping
(
"/get"
)
public
HttpResultResponse
<
AiInfoDTO
>
getAiInfo
(
@RequestParam
Long
id
)
{
AiInfoDTO
dto
=
aiInfoService
.
getAiInfoById
(
id
);
return
HttpResultResponse
.
success
(
dto
);
}
@PostMapping
(
"/update"
)
public
HttpResultResponse
<
Boolean
>
updateAiInfo
(
@RequestBody
@Valid
AiInfoDTO
aiInfoDTO
)
{
boolean
ok
=
aiInfoService
.
updateAiInfo
(
aiInfoDTO
);
return
HttpResultResponse
.
success
(
ok
);
}
@PostMapping
(
"/delete"
)
public
HttpResultResponse
<
Boolean
>
deleteAiInfo
(
@RequestParam
Long
id
)
{
boolean
ok
=
aiInfoService
.
deleteAiInfoById
(
id
);
return
HttpResultResponse
.
success
(
ok
);
}
}
sample/src/main/java/com/dji/sample/ai/model/dto/TopicAiInfoDTO.java
0 → 100644
View file @
7f6048a8
package
com
.
dji
.
sample
.
ai
.
model
.
dto
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
import
lombok.Data
;
import
java.io.Serializable
;
/**
* @author guan
*/
@Data
public
class
TopicAiInfoDTO
implements
Serializable
{
@JsonProperty
(
"device_sn"
)
private
String
deviceSn
;
@JsonProperty
(
"payload_sn"
)
private
String
payloadSn
;
@JsonProperty
(
"warn_type"
)
private
String
warnType
;
@JsonProperty
(
"warn_event"
)
private
String
warnEvent
;
/** epoch milli */
@JsonProperty
(
"warn_time"
)
private
Long
warnTime
;
@JsonProperty
(
"image_url"
)
private
String
imageUrl
;
@JsonProperty
(
"warn_location"
)
private
String
warnLocation
;
@JsonProperty
(
"algorithm_type"
)
private
String
algorithmType
;
/** Raw object payload (may be JSON object) */
@JsonProperty
(
"obj"
)
private
Object
obj
;
}
sample/src/main/java/com/dji/sample/ai/service/IAiInfoService.java
View file @
7f6048a8
...
...
@@ -13,4 +13,12 @@ public interface IAiInfoService extends IService<AiInfoEntity> {
PaginationData
<
AiInfoDTO
>
getAiInfoPageByParam
(
AiInfoSearchParam
param
,
Long
page
,
Long
pageSize
);
AiInfoDTO
createAiInfo
(
AiInfoDTO
dto
);
AiInfoDTO
getAiInfoById
(
Long
id
);
boolean
updateAiInfo
(
AiInfoDTO
dto
);
boolean
deleteAiInfoById
(
Long
id
);
}
sample/src/main/java/com/dji/sample/ai/service/impl/AiInfoServiceImpl.java
View file @
7f6048a8
...
...
@@ -56,9 +56,71 @@ public class AiInfoServiceImpl extends ServiceImpl<IAiInfoMapper, AiInfoEntity>
String
[]
arr
=
param
.
getOrderBy
().
split
(
" "
);
String
column
=
arr
[
0
];
String
desc
=
arr
.
length
>
1
?
arr
[
1
]
:
"desc"
;
wrapper
.
last
(
Objects
.
nonNull
(
param
.
getOrderBy
()),
" order by "
+
column
+
" "
+
desc
);
String
direction
=
arr
.
length
>
1
?
arr
[
1
]
:
"desc"
;
// 避免SQL注入,不直接使用SQL语句,所以判断相应的列
switch
(
column
)
{
case
"id"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getId
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getId
);
}
break
;
case
"createTime"
:
case
"create_time"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getCreateTime
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getCreateTime
);
}
break
;
case
"warnTime"
:
case
"warn_time"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getWarnTime
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getWarnTime
);
}
break
;
case
"deviceSn"
:
case
"device_sn"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getDeviceSn
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getDeviceSn
);
}
break
;
case
"warnType"
:
case
"warn_type"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getWarnType
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getWarnType
);
}
break
;
case
"warnEvent"
:
case
"warn_event"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getWarnEvent
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getWarnEvent
);
}
break
;
case
"algorithmType"
:
case
"algorithm_type"
:
if
(
"asc"
.
equals
(
direction
))
{
wrapper
.
orderByAsc
(
AiInfoEntity:
:
getAlgorithmType
);
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getAlgorithmType
);
}
break
;
default
:
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getId
);
break
;
}
}
else
{
wrapper
.
orderByDesc
(
AiInfoEntity:
:
getId
);
}
Page
<
AiInfoEntity
>
pagination
=
this
.
page
(
new
Page
<>(
page
,
pageSize
),
wrapper
);
...
...
@@ -112,4 +174,28 @@ public class AiInfoServiceImpl extends ServiceImpl<IAiInfoMapper, AiInfoEntity>
return
aiInfoEntity
;
}
@Override
public
AiInfoDTO
createAiInfo
(
AiInfoDTO
dto
)
{
AiInfoEntity
entity
=
AiInfoDTOToEntity
(
dto
);
this
.
save
(
entity
);
return
AiInfoEntityToDTO
(
entity
);
}
@Override
public
AiInfoDTO
getAiInfoById
(
Long
id
)
{
AiInfoEntity
entity
=
this
.
getById
(
id
);
return
Objects
.
nonNull
(
entity
)
?
AiInfoEntityToDTO
(
entity
)
:
null
;
}
@Override
public
boolean
updateAiInfo
(
AiInfoDTO
dto
)
{
AiInfoEntity
entity
=
AiInfoDTOToEntity
(
dto
);
return
this
.
updateById
(
entity
);
}
@Override
public
boolean
deleteAiInfoById
(
Long
id
)
{
return
this
.
removeById
(
id
);
}
}
sample/src/main/java/com/dji/sample/common/util/JwtUtil.java
View file @
7f6048a8
...
...
@@ -39,7 +39,7 @@ public class JwtUtil {
@Value
(
"${jwt.age: 86400}"
)
private
void
setAge
(
long
age
)
{
JwtUtil
.
age
=
age
*
1000
;
JwtUtil
.
age
=
age
;
}
@Value
(
"${jwt.secret: CloudApiSample}"
)
...
...
sample/src/main/java/com/dji/sample/component/websocket/config/AuthPrincipalHandler.java
View file @
7f6048a8
...
...
@@ -32,19 +32,20 @@ public class AuthPrincipalHandler extends DefaultHandshakeHandler {
HttpServletRequest
servletRequest
=
((
ServletServerHttpRequest
)
request
).
getServletRequest
();
String
token
=
servletRequest
.
getParameter
(
AuthInterceptor
.
PARAM_TOKEN
);
// 默认让WebSocket的认证都通过
if
(!
StringUtils
.
hasText
(
token
))
{
return
fals
e
;
return
tru
e
;
}
log
.
debug
(
"token:"
+
token
);
Optional
<
CustomClaim
>
customClaim
=
JwtUtil
.
parseToken
(
token
);
if
(
customClaim
.
isEmpty
())
{
return
fals
e
;
return
tru
e
;
}
servletRequest
.
setAttribute
(
AuthInterceptor
.
TOKEN_CLAIM
,
customClaim
.
get
());
return
true
;
}
return
fals
e
;
return
tru
e
;
}
...
...
@@ -63,6 +64,10 @@ public class AuthPrincipalHandler extends DefaultHandshakeHandler {
CustomClaim
claim
=
(
CustomClaim
)
((
ServletServerHttpRequest
)
request
).
getServletRequest
()
.
getAttribute
(
AuthInterceptor
.
TOKEN_CLAIM
);
if
(
claim
==
null
)
{
return
()
->
null
;
}
return
()
->
claim
.
getWorkspaceId
()
+
"/"
+
claim
.
getUserType
()
+
"/"
+
claim
.
getId
();
}
return
()
->
null
;
...
...
sample/src/main/java/com/dji/sample/component/websocket/config/MyWebSocketHandler.java
View file @
7f6048a8
package
com
.
dji
.
sample
.
component
.
websocket
.
config
;
import
com.dji.sample.common.model.CustomClaim
;
import
com.dji.sample.common.util.JwtUtil
;
import
com.dji.sample.component.websocket.service.IWebSocketManageService
;
import
com.dji.sdk.websocket.WebSocketDefaultHandler
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.socket.CloseStatus
;
...
...
@@ -10,6 +14,9 @@ import org.springframework.web.socket.WebSocketMessage;
import
org.springframework.web.socket.WebSocketSession
;
import
java.security.Principal
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.concurrent.ConcurrentHashMap
;
/**
*
...
...
@@ -22,6 +29,11 @@ public class MyWebSocketHandler extends WebSocketDefaultHandler {
private
IWebSocketManageService
webSocketManageService
;
private
ObjectMapper
objectMapper
=
new
ObjectMapper
();
private
Map
<
String
,
Boolean
>
authenticatedSessions
=
new
ConcurrentHashMap
<>();
private
Map
<
String
,
CustomClaim
>
sessionClaims
=
new
ConcurrentHashMap
<>();
private
Map
<
String
,
String
>
sessionPrincipalNames
=
new
ConcurrentHashMap
<>();
MyWebSocketHandler
(
WebSocketHandler
delegate
,
IWebSocketManageService
webSocketManageService
)
{
super
(
delegate
);
this
.
webSocketManageService
=
webSocketManageService
;
...
...
@@ -30,29 +42,114 @@ public class MyWebSocketHandler extends WebSocketDefaultHandler {
@Override
public
void
afterConnectionEstablished
(
WebSocketSession
session
)
throws
Exception
{
Principal
principal
=
session
.
getPrincipal
();
if
(
StringUtils
.
hasText
(
principal
.
getName
()))
{
webSocketManageService
.
put
(
principal
.
getName
(),
new
MyConcurrentWebSocketSession
(
session
));
log
.
debug
(
"{} is connected. ID: {}. WebSocketSession[current count: {}]"
,
principal
.
getName
(),
session
.
getId
(),
webSocketManageService
.
getConnectedCount
());
return
;
String
principalName
=
principal
.
getName
();
if
(
StringUtils
.
hasText
(
principalName
)
&&
!
principalName
.
startsWith
(
"temp-"
))
{
webSocketManageService
.
put
(
principalName
,
new
MyConcurrentWebSocketSession
(
session
));
authenticatedSessions
.
put
(
session
.
getId
(),
true
);
// 记录 principalName 用于 afterConnectionClosed 时清理
sessionPrincipalNames
.
put
(
session
.
getId
(),
principalName
);
log
.
debug
(
"{} is connected (pre-authenticated). ID: {}. WebSocketSession[current count: {}]"
,
principalName
,
session
.
getId
(),
webSocketManageService
.
getConnectedCount
());
}
else
{
log
.
debug
(
"Unauthenticated connection established. ID: {}, temp principal: {}"
,
session
.
getId
(),
principalName
);
}
session
.
close
();
}
@Override
public
void
afterConnectionClosed
(
WebSocketSession
session
,
CloseStatus
closeStatus
)
throws
Exception
{
Principal
principal
=
session
.
getPrincipal
();
if
(
StringUtils
.
hasText
(
principal
.
getName
()))
{
webSocketManageService
.
remove
(
principal
.
getName
(),
session
.
getId
());
String
sessionId
=
session
.
getId
();
Boolean
isAuthenticated
=
authenticatedSessions
.
get
(
sessionId
);
if
(
Boolean
.
TRUE
.
equals
(
isAuthenticated
))
{
// 优先用 sessionClaims(消息认证方式),其次用 sessionPrincipalNames(URL token 认证方式)
CustomClaim
claim
=
sessionClaims
.
get
(
sessionId
);
if
(
claim
!=
null
)
{
String
key
=
claim
.
getWorkspaceId
()
+
"/"
+
claim
.
getUserType
()
+
"/"
+
claim
.
getId
();
webSocketManageService
.
remove
(
key
,
sessionId
);
log
.
debug
(
"{} is disconnected. ID: {}. WebSocketSession[current count: {}]"
,
principal
.
getName
(),
session
.
getId
(),
webSocketManageService
.
getConnectedCount
());
key
,
sessionId
,
webSocketManageService
.
getConnectedCount
());
}
else
{
String
principalName
=
sessionPrincipalNames
.
get
(
sessionId
);
if
(
principalName
!=
null
)
{
webSocketManageService
.
remove
(
principalName
,
sessionId
);
log
.
debug
(
"{} is disconnected (pre-auth). ID: {}. WebSocketSession[current count: {}]"
,
principalName
,
sessionId
,
webSocketManageService
.
getConnectedCount
());
}
}
}
authenticatedSessions
.
remove
(
sessionId
);
sessionClaims
.
remove
(
sessionId
);
sessionPrincipalNames
.
remove
(
sessionId
);
}
@Override
public
void
handleMessage
(
WebSocketSession
session
,
WebSocketMessage
<?>
message
)
throws
Exception
{
log
.
debug
(
"received message: {}"
,
message
.
getPayload
());
String
sessionId
=
session
.
getId
();
Boolean
isAuthenticated
=
authenticatedSessions
.
get
(
sessionId
);
String
payload
=
message
.
getPayload
().
toString
();
log
.
debug
(
"Received message from session {}: {}"
,
sessionId
,
payload
);
try
{
JsonNode
jsonNode
=
objectMapper
.
readTree
(
payload
);
String
type
=
jsonNode
.
has
(
"type"
)
?
jsonNode
.
get
(
"type"
).
asText
()
:
null
;
if
(
"auth"
.
equals
(
type
)
&&
!
Boolean
.
TRUE
.
equals
(
isAuthenticated
))
{
String
token
=
jsonNode
.
has
(
"token"
)
?
jsonNode
.
get
(
"token"
).
asText
()
:
null
;
if
(
StringUtils
.
hasText
(
token
))
{
Optional
<
CustomClaim
>
customClaimOpt
=
JwtUtil
.
parseToken
(
token
);
if
(
customClaimOpt
.
isPresent
())
{
CustomClaim
claim
=
customClaimOpt
.
get
();
String
key
=
claim
.
getWorkspaceId
()
+
"/"
+
claim
.
getUserType
()
+
"/"
+
claim
.
getId
();
authenticatedSessions
.
put
(
sessionId
,
true
);
sessionClaims
.
put
(
sessionId
,
claim
);
webSocketManageService
.
put
(
key
,
new
MyConcurrentWebSocketSession
(
session
));
log
.
debug
(
"Session {} authenticated successfully. User: {}"
,
sessionId
,
key
);
String
authResponse
=
objectMapper
.
writeValueAsString
(
Map
.
of
(
"type"
,
"auth_success"
,
"status"
,
"ok"
));
session
.
sendMessage
(
new
org
.
springframework
.
web
.
socket
.
TextMessage
(
authResponse
));
return
;
}
}
log
.
warn
(
"Authentication failed for session {}"
,
sessionId
);
String
authFail
=
objectMapper
.
writeValueAsString
(
Map
.
of
(
"type"
,
"auth_fail"
,
"status"
,
"error"
,
"message"
,
"Invalid token"
));
session
.
sendMessage
(
new
org
.
springframework
.
web
.
socket
.
TextMessage
(
authFail
));
session
.
close
(
CloseStatus
.
NOT_ACCEPTABLE
);
return
;
}
if
(!
Boolean
.
TRUE
.
equals
(
isAuthenticated
))
{
log
.
warn
(
"Unauthenticated session {} tried to send message. Closing."
,
sessionId
);
String
authRequired
=
objectMapper
.
writeValueAsString
(
Map
.
of
(
"type"
,
"auth_required"
,
"message"
,
"Please authenticate first"
));
session
.
sendMessage
(
new
org
.
springframework
.
web
.
socket
.
TextMessage
(
authRequired
));
// session.close(CloseStatus.NOT_ACCEPTABLE);
return
;
}
super
.
handleMessage
(
session
,
message
);
}
catch
(
Exception
e
)
{
log
.
error
(
"Error handling message from session {}"
,
sessionId
,
e
);
if
(!
Boolean
.
TRUE
.
equals
(
isAuthenticated
))
{
session
.
close
(
CloseStatus
.
BAD_DATA
);
}
}
}
}
\ No newline at end of file
sample/src/main/java/com/dji/sample/component/websocket/service/impl/WebSocketMessageServiceImpl.java
View file @
7f6048a8
...
...
@@ -63,9 +63,12 @@ public class WebSocketMessageServiceImpl implements IWebSocketMessageService {
for
(
MyConcurrentWebSocketSession
session
:
sessions
)
{
if
(!
session
.
isOpen
())
{
try
{
session
.
close
();
log
.
debug
(
"This session is closed."
);
return
;
}
catch
(
Exception
ignored
)
{
}
log
.
debug
(
"Skipping closed session: {}"
,
session
.
getId
());
continue
;
}
session
.
sendMessage
(
data
);
}
...
...
sample/src/main/java/com/dji/sample/configuration/mvc/GlobalMVCConfigurer.java
View file @
7f6048a8
...
...
@@ -24,6 +24,12 @@ public class GlobalMVCConfigurer implements WebMvcConfigurer {
@Value
(
"${url.manage.version}"
)
private
String
manageVersion
;
@Value
(
"${url.media.prefix}"
)
private
String
mediaPrefix
;
@Value
(
"${url.media.version}"
)
private
String
mediaVersion
;
@Override
public
void
addInterceptors
(
InterceptorRegistry
registry
)
{
...
...
@@ -36,10 +42,21 @@ public class GlobalMVCConfigurer implements WebMvcConfigurer {
excludePaths
.
add
(
"/swagger-ui/**"
);
excludePaths
.
add
(
"/v3/**"
);
excludePaths
.
add
(
"/ui/**"
);
excludePaths
.
add
(
"/actuator/health"
);
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/devices/**/deviceInfo"
);
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/live/streams/start2"
);
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/live/streams/stop2"
);
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/live/oneCapacity2"
);
// 放行 aiInfo 新增与修改接口
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/aiInfo/add"
);
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/aiInfo/update"
);
excludePaths
.
add
(
"/"
+
managePrefix
+
manageVersion
+
"/aiInfo/addFromTopic"
);
// 放行 OSS 文件浏览接口
excludePaths
.
add
(
"/"
+
mediaPrefix
+
mediaVersion
+
"/oss/**/files"
);
// 放行 OSS 文件下载接口
excludePaths
.
add
(
"/"
+
mediaPrefix
+
mediaVersion
+
"/oss/**/file/**/download"
);
// Intercept for all request interfaces.
registry
.
addInterceptor
(
authInterceptor
).
addPathPatterns
(
"/**"
).
excludePathPatterns
(
excludePaths
);
}
...
...
sample/src/main/java/com/dji/sample/manage/controller/DeviceController.java
View file @
7f6048a8
package
com
.
dji
.
sample
.
manage
.
controller
;
import
com.dji.sample.manage.model.dto.*
;
import
com.dji.sample.manage.model.enums.OperateRecordTypeEnum
;
import
com.dji.sample.manage.model.param.DeviceSearchParam
;
import
com.dji.sample.manage.service.IDeviceDictionaryService
;
import
com.dji.sample.manage.service.IOperateRecordService
;
import
com.dji.sample.manage.service.IDeviceService
;
import
com.dji.sdk.common.HttpResultResponse
;
import
com.dji.sdk.common.PaginationData
;
...
...
@@ -14,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.web.bind.annotation.*
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.List
;
import
java.util.Optional
;
...
...
@@ -33,6 +36,9 @@ public class DeviceController {
@Autowired
private
IDeviceDictionaryService
deviceDictionaryService
;
@Autowired
private
IOperateRecordService
operateRecordService
;
/**
* Get the topology list of all online devices in one workspace.
* @param workspaceId
...
...
@@ -136,9 +142,19 @@ public class DeviceController {
* @return
*/
@PostMapping
(
"/{workspace_id}/devices/ota"
)
public
HttpResultResponse
createOtaJob
(
@PathVariable
(
"workspace_id"
)
String
workspaceId
,
public
HttpResultResponse
createOtaJob
(
HttpServletRequest
request
,
@PathVariable
(
"workspace_id"
)
String
workspaceId
,
@RequestBody
List
<
DeviceFirmwareUpgradeDTO
>
upgradeDTOS
)
{
return
deviceService
.
createDeviceOtaJob
(
workspaceId
,
upgradeDTOS
);
HttpResultResponse
response
=
deviceService
.
createDeviceOtaJob
(
workspaceId
,
upgradeDTOS
);
// 下发成功后记录操作日志(operate_record)
if
(
response
!=
null
&&
response
.
getCode
()
==
0
&&
upgradeDTOS
!=
null
)
{
for
(
DeviceFirmwareUpgradeDTO
dto
:
upgradeDTOS
)
{
operateRecordService
.
record
(
request
,
OperateRecordTypeEnum
.
FIRMWARE_UPGRADE
,
dto
.
getSn
(),
dto
);
}
}
return
response
;
}
/**
...
...
@@ -346,4 +362,23 @@ public class DeviceController {
return
HttpResultResponse
.
success
(
deviceInfoTotal
);
}
/**
* Get the real-time OSD data of a device from Redis cache.
* Returns different OSD structures depending on device type:
* - Dock (domain=3): OsdDock (contains modeCode: Idle/Debugging/Working etc.)
* - Drone (domain=0): OsdDockDrone or OsdRcDrone (contains modeCode, lat/lng, altitude, speed, battery etc.)
* - Remote Controller (domain=2): OsdRemoteControl (contains lat/lng, height etc.)
* @param workspaceId
* @param deviceSn
* @return OSD data object
*/
@GetMapping
(
"/{workspace_id}/devices/{device_sn}/osd"
)
public
HttpResultResponse
getDeviceOsd
(
@PathVariable
(
"workspace_id"
)
String
workspaceId
,
@PathVariable
(
"device_sn"
)
String
deviceSn
)
{
Optional
<
Object
>
osdOpt
=
deviceService
.
getDeviceOsd
(
workspaceId
,
deviceSn
);
return
osdOpt
.
isEmpty
()
?
HttpResultResponse
.
error
(
"Device OSD data not found. The device may be offline, not reporting data, or not belong to this workspace."
)
:
HttpResultResponse
.
success
(
osdOpt
.
get
());
}
}
\ No newline at end of file
sample/src/main/java/com/dji/sample/manage/controller/DeviceFirmwareController.java
View file @
7f6048a8
...
...
@@ -4,10 +4,12 @@ import com.dji.sample.common.model.CustomClaim;
import
com.dji.sample.manage.model.dto.DeviceFirmwareDTO
;
import
com.dji.sample.manage.model.dto.DeviceFirmwareNoteDTO
;
import
com.dji.sample.manage.model.dto.FirmwareFileProperties
;
import
com.dji.sample.manage.model.enums.OperateRecordTypeEnum
;
import
com.dji.sample.manage.model.param.DeviceFirmwareQueryParam
;
import
com.dji.sample.manage.model.param.DeviceFirmwareUpdateParam
;
import
com.dji.sample.manage.model.param.DeviceFirmwareUploadParam
;
import
com.dji.sample.manage.service.IDeviceFirmwareService
;
import
com.dji.sample.manage.service.IOperateRecordService
;
import
com.dji.sdk.common.HttpResultResponse
;
import
com.dji.sdk.common.PaginationData
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
@@ -37,6 +39,9 @@ public class DeviceFirmwareController {
@Autowired
private
IDeviceFirmwareService
service
;
@Autowired
private
IOperateRecordService
operateRecordService
;
/**
* Get the latest firmware version information for this device model.
* @param deviceNames
...
...
@@ -89,10 +94,29 @@ public class DeviceFirmwareController {
String
creator
=
customClaim
.
getUsername
();
service
.
importFirmwareFile
(
workspaceId
,
creator
,
param
,
file
);
// 记录操作日志(operate_record)
operateRecordService
.
record
(
request
,
OperateRecordTypeEnum
.
FIRMWARE_UPLOAD
,
null
,
param
);
return
HttpResultResponse
.
success
();
}
/**
* Get firmware detail by firmwareId.
* @param workspaceId
* @param firmwareId
* @return
*/
@GetMapping
(
"/{workspace_id}/firmwares/{firmware_id}"
)
public
HttpResultResponse
<
DeviceFirmwareDTO
>
getFirmwareDetail
(
@PathVariable
(
"workspace_id"
)
String
workspaceId
,
@PathVariable
(
"firmware_id"
)
String
firmwareId
)
{
return
service
.
getFirmwareDetail
(
workspaceId
,
firmwareId
)
.
map
(
HttpResultResponse:
:
success
)
.
orElse
(
HttpResultResponse
.
error
(
"Firmware not found."
));
}
/**
* Change the firmware availability status.
* @param workspaceId
* @param firmwareId
...
...
sample/src/main/java/com/dji/sample/manage/controller/UserController.java
View file @
7f6048a8
...
...
@@ -152,7 +152,7 @@ public class UserController {
}
/**
*
Admin resets a user's
password.
*
User reset
password.
* The new password must comply with all password rules.
*
* @param request HTTP request
...
...
@@ -162,6 +162,7 @@ public class UserController {
@PostMapping
(
"/resetPassword"
)
public
HttpResultResponse
<
Object
>
resetPassword
(
HttpServletRequest
request
,
@RequestBody
ChangePasswordParam
param
)
{
CustomClaim
customClaim
=
(
CustomClaim
)
request
.
getAttribute
(
TOKEN_CLAIM
);
String
userId
=
customClaim
.
getId
();
return
userService
.
resetPassword
(
userId
,
param
);
...
...
sample/src/main/java/com/dji/sample/manage/model/dto/DeviceFirmwareDTO.java
View file @
7f6048a8
package
com
.
dji
.
sample
.
manage
.
model
.
dto
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.util.List
;
/**
...
...
@@ -42,4 +44,10 @@ public class DeviceFirmwareDTO {
private
String
workspaceId
;
private
String
username
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
)
private
LocalDateTime
createTime
;
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
)
private
LocalDateTime
updateTime
;
}
sample/src/main/java/com/dji/sample/manage/model/enums/OperateRecordTypeEnum.java
View file @
7f6048a8
...
...
@@ -29,7 +29,13 @@ public enum OperateRecordTypeEnum {
SEIZE_FLIGHT_AUTHORITY
(
"SEIZE_FLIGHT_AUTHORITY"
,
"夺取飞行控制权"
),
SEIZE_PAYLOAD_AUTHORITY
(
"SEIZE_PAYLOAD_AUTHORITY"
,
"夺取负载控制权"
),
PAYLOAD_COMMANDS
(
"PAYLOAD_COMMANDS"
,
"负载控制指令"
),
RTK_CALIBRATION
(
"RTK_CALIBRATION"
,
"RTK标定"
);
RTK_CALIBRATION
(
"RTK_CALIBRATION"
,
"RTK标定"
),
// -- FIRMWARE
FIRMWARE_UPLOAD
(
"FIRMWARE_UPLOAD"
,
"上传固件"
),
FIRMWARE_UPGRADE
(
"FIRMWARE_UPGRADE"
,
"下发固件升级"
),
;
private
final
String
type
;
private
final
String
description
;
...
...
sample/src/main/java/com/dji/sample/manage/service/IDeviceFirmwareService.java
View file @
7f6048a8
...
...
@@ -73,6 +73,15 @@ public interface IDeviceFirmwareService {
void
importFirmwareFile
(
String
workspaceId
,
String
creator
,
DeviceFirmwareUploadParam
param
,
MultipartFile
file
);
/**
* Get firmware detail by firmwareId.
*
* @param workspaceId
* @param firmwareId
* @return
*/
Optional
<
DeviceFirmwareDTO
>
getFirmwareDetail
(
String
workspaceId
,
String
firmwareId
);
/**
* Save the file information of the firmware.
* @param firmware
* @param deviceNames
...
...
sample/src/main/java/com/dji/sample/manage/service/IDeviceService.java
View file @
7f6048a8
...
...
@@ -294,4 +294,14 @@ public interface IDeviceService extends IService<DeviceEntity> {
DeviceDetailCountDTO
getDeviceInfoTotal
(
String
workspaceId
);
/**
* Get the OSD real-time data of the device from Redis.
* Automatically determines the device type (Dock, Drone, RC) and returns the corresponding OSD data.
* Validates that the device belongs to the specified workspace.
* @param workspaceId
* @param deviceSn
* @return OSD data object, or empty if device not found or no OSD data
*/
Optional
<
Object
>
getDeviceOsd
(
String
workspaceId
,
String
deviceSn
);
}
\ No newline at end of file
sample/src/main/java/com/dji/sample/manage/service/impl/DeviceFirmwareServiceImpl.java
View file @
7f6048a8
...
...
@@ -46,6 +46,7 @@ import java.io.InputStream;
import
java.nio.charset.StandardCharsets
;
import
java.time.Instant
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.ZoneId
;
import
java.time.format.DateTimeFormatter
;
import
java.util.*
;
...
...
@@ -167,6 +168,15 @@ public class DeviceFirmwareServiceImpl extends AbstractFirmwareService implement
}
@Override
public
Optional
<
DeviceFirmwareDTO
>
getFirmwareDetail
(
String
workspaceId
,
String
firmwareId
)
{
return
Optional
.
ofNullable
(
entity2Dto
(
mapper
.
selectOne
(
new
LambdaQueryWrapper
<
DeviceFirmwareEntity
>()
.
eq
(
DeviceFirmwareEntity:
:
getWorkspaceId
,
workspaceId
)
.
eq
(
DeviceFirmwareEntity:
:
getFirmwareId
,
firmwareId
),
null
)));
}
@Override
public
Boolean
checkFileExist
(
String
workspaceId
,
String
fileMd5
)
{
return
RedisOpsUtils
.
checkExist
(
RedisConst
.
FILE_UPLOADING_PREFIX
+
workspaceId
+
fileMd5
)
||
mapper
.
selectCount
(
new
LambdaQueryWrapper
<
DeviceFirmwareEntity
>()
...
...
@@ -337,6 +347,8 @@ public class DeviceFirmwareServiceImpl extends AbstractFirmwareService implement
.
firmwareStatus
(
entity
.
getStatus
())
.
workspaceId
(
entity
.
getWorkspaceId
())
.
username
(
entity
.
getUsername
())
.
createTime
(
entity
.
getCreateTime
()
!=
null
?
LocalDateTime
.
ofInstant
(
Instant
.
ofEpochMilli
(
entity
.
getCreateTime
()),
ZoneId
.
systemDefault
())
:
null
)
.
updateTime
(
entity
.
getUpdateTime
()
!=
null
?
LocalDateTime
.
ofInstant
(
Instant
.
ofEpochMilli
(
entity
.
getUpdateTime
()),
ZoneId
.
systemDefault
())
:
null
)
.
build
();
}
...
...
sample/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
View file @
7f6048a8
...
...
@@ -512,6 +512,14 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
public
Boolean
bindDevice
(
DeviceDTO
device
)
{
device
.
setBoundStatus
(
true
);
device
.
setBoundTime
(
LocalDateTime
.
now
());
// 绑定设备补充orgId
Optional
<
DeviceDTO
>
dbDeviceBySn
=
this
.
getDeviceBySn
(
device
.
getDeviceSn
());
if
(
dbDeviceBySn
.
isPresent
())
{
DeviceDTO
dbDeviceDTO
=
dbDeviceBySn
.
get
();
if
(!
StringUtils
.
hasText
(
dbDeviceDTO
.
getOrgId
()))
{
device
.
setOrgId
(
getOrgId
());
}
}
boolean
isUpd
=
this
.
updateDevice
(
device
);
if
(!
isUpd
)
{
...
...
@@ -1039,6 +1047,39 @@ public class DeviceServiceImpl extends ServiceImpl<IDeviceMapper, DeviceEntity>
}
@Override
public
Optional
<
Object
>
getDeviceOsd
(
String
workspaceId
,
String
deviceSn
)
{
Optional
<
DeviceDTO
>
deviceOpt
=
getDeviceBySn
(
deviceSn
);
if
(
deviceOpt
.
isEmpty
())
{
return
Optional
.
empty
();
}
DeviceDTO
device
=
deviceOpt
.
get
();
// Validate that the device belongs to the specified workspace
if
(!
workspaceId
.
equals
(
device
.
getWorkspaceId
()))
{
log
.
warn
(
"Device {} does not belong to workspace {}"
,
deviceSn
,
workspaceId
);
return
Optional
.
empty
();
}
DeviceDomainEnum
domain
=
device
.
getDomain
();
if
(
domain
==
null
)
{
return
Optional
.
empty
();
}
switch
(
domain
)
{
case
DOCK:
return
deviceRedisService
.
getDeviceOsd
(
deviceSn
,
OsdDock
.
class
).
map
(
osd
->
osd
);
case
DRONE:
// Try DockDrone first, then RcDrone
Optional
<
OsdDockDrone
>
dockDrone
=
deviceRedisService
.
getDeviceOsd
(
deviceSn
,
OsdDockDrone
.
class
);
if
(
dockDrone
.
isPresent
())
{
return
dockDrone
.
map
(
osd
->
osd
);
}
return
deviceRedisService
.
getDeviceOsd
(
deviceSn
,
OsdRcDrone
.
class
).
map
(
osd
->
osd
);
case
REMOTER_CONTROL:
return
deviceRedisService
.
getDeviceOsd
(
deviceSn
,
OsdRemoteControl
.
class
).
map
(
osd
->
osd
);
default
:
return
Optional
.
empty
();
}
}
@Override
public
Boolean
checkDockDrcMode
(
String
dockSn
)
{
if
(
CUSTOM_DOCK_LIST
.
contains
(
dockSn
)
||
dockSn
.
contains
(
"12345"
))
{
...
...
sample/src/main/java/com/dji/sample/manage/service/impl/LiveStreamServiceImpl.java
View file @
7f6048a8
...
...
@@ -153,7 +153,6 @@ public class LiveStreamServiceImpl implements ILiveStreamService {
Set
<
String
>
existingSessions
=
findSessionKeys
(
liveParam
.
getVideoId
());
boolean
streamAlreadyRunning
=
!
forceMqttPush
&&
existingSessions
!=
null
&&
!
existingSessions
.
isEmpty
();
String
rtspOutputUrl
=
null
;
// RTSP 特殊:播放地址来自设备响应
if
(
streamAlreadyRunning
)
{
log
.
info
(
"Stream already running with {} viewer(s), skip MQTT push and reuse. videoId={}"
,
...
...
@@ -166,7 +165,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService {
// videoQuality 为空时默认 AUTO(refresh 场景前端可能不传)
VideoQualityEnum
quality
=
liveParam
.
getVideoQuality
()
!=
null
?
liveParam
.
getVideoQuality
()
:
VideoQualityEnum
.
AUTO
;
TopicServicesResponse
<
ServicesReplyData
<
String
>>
response
=
abstractLivestreamService
.
liveStartPush
(
TopicServicesResponse
<
ServicesReplyData
<
LiveStartPushResponse
>>
response
=
abstractLivestreamService
.
liveStartPush
(
SDKManager
.
getDeviceSDK
(
responseResult
.
getData
().
getDeviceSn
()),
new
LiveStartPushRequest
()
.
setUrl
(
url
)
...
...
@@ -184,11 +183,6 @@ public class LiveStreamServiceImpl implements ILiveStreamService {
return
HttpResultResponse
.
error
(
response
.
getData
().
getResult
());
}
}
// 保存 RTSP 设备返回的 output(仅首次推流时设备会返回)
if
(
StringUtils
.
hasText
(
response
.
getData
().
getOutput
()))
{
rtspOutputUrl
=
response
.
getData
().
getOutput
();
}
}
// ========== 构造播放地址(无论首个还是复用,URL 构造逻辑一致) ==========
...
...
@@ -212,12 +206,7 @@ public class LiveStreamServiceImpl implements ILiveStreamService {
.
toString
());
break
;
case
RTSP:
// RTSP 优先用设备返回的 output 地址,复用时回退到配置 URL
if
(
StringUtils
.
hasText
(
rtspOutputUrl
))
{
live
.
setUrl
(
rtspOutputUrl
);
}
else
{
live
.
setUrl
(
url
.
toString
());
}
break
;
case
WHIP:
live
.
setUrl
(
url
.
toString
().
replace
(
"whip"
,
"whep"
));
...
...
sample/src/main/java/com/dji/sample/manage/service/impl/SDKDeviceService.java
View file @
7f6048a8
...
...
@@ -264,6 +264,7 @@ public class SDKDeviceService extends AbstractDeviceService {
}
OsdRemoteControl
data
=
request
.
getData
();
deviceRedisService
.
setDeviceOsd
(
from
,
data
);
deviceService
.
pushOsdDataToPilot
(
device
.
getWorkspaceId
(),
from
,
new
DeviceOsdHost
()
.
setLatitude
(
data
.
getLatitude
())
...
...
@@ -297,6 +298,7 @@ public class SDKDeviceService extends AbstractDeviceService {
}
OsdRcDrone
data
=
request
.
getData
();
deviceRedisService
.
setDeviceOsd
(
from
,
data
);
deviceService
.
pushOsdDataToPilot
(
device
.
getWorkspaceId
(),
from
,
new
DeviceOsdHost
()
.
setLatitude
(
data
.
getLatitude
())
...
...
sample/src/main/resources/application.yml
View file @
7f6048a8
...
...
@@ -84,10 +84,10 @@ mqtt:
# host: emqx-broker
# host: 192.168.32.90
# port: 44418
host
:
203.186.109.106
port
:
54941
#
host: emqx-broker
#
port: 1883
# host: geotwin.cc
#
port: 54941
host
:
emqx-broker
port
:
1883
username
:
JavaServer
password
:
123456
client-id
:
123456
...
...
@@ -216,7 +216,7 @@ livestream:
# RTMP Note: This IP is the address of the streaming server. If you want to see livestream on web page, you need to convert the RTMP stream to WebRTC stream.
rtmp
:
url
:
rtmp://
203.186.109.106
:44424/live/
# Example: 'rtmp://192.168.1.1/live/'
url
:
rtmp://
geotwin.cc
:44424/live/
# Example: 'rtmp://192.168.1.1/live/'
# 深圳
# url: rtmp://183.11.236.162:54424/live/ # Example: 'rtmp://192.168.1.1/live/'
rtsp
:
...
...
@@ -252,6 +252,6 @@ uom:
programVersion
:
"
version1.0"
# 上报平台 API 地址 https://uom.receive.caacic.cn/addFlightRoute
# url: https://218.189.32.212:8080/addFlightRoute
url
:
https://
220.232.168.7
:8080/addFlightRoute
url
:
https://
118.143.38.126
:8080/addFlightRoute
appID
:
GEOSYS
appKey
:
geosys_uas
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment