Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
p x
wsmock
Commits
eb5a2d1c
Commit
eb5a2d1c
authored
Jan 09, 2026
by
p x
Browse files
添加4个接口
parent
16e196a6
Changes
12
Expand all
Show whitespace changes
Inline
Side-by-side
logs/wsmock.log
View file @
eb5a2d1c
This diff is collapsed.
Click to expand it.
src/main/kotlin/com/inzy/wsmock/AdasPushTask.kt
deleted
100644 → 0
View file @
16e196a6
package
com.inzy.wsmock
import
com.alibaba.fastjson2.JSONObject
import
com.inzy.wsmock.RequestParamHandler.Companion.PARAM_TYPE_KEY
import
com.inzy.wsmock.RequestParamHandler.Companion.PARAM_TYPE_VALUE_1
import
com.inzy.wsmock.RequestParamHandler.Companion.PARAM_TYPE_VALUE_2
import
com.inzy.wsmock.RequestParamHandler.Companion.REQUEST_PARAMS_KEY
import
com.inzy.wsmock.RequestParamHandler.Companion.REQUEST_PATH_KEY
import
com.inzy.wsmock.utils.FileIoUtil
import
io.netty.channel.Channel
import
io.netty.handler.codec.http.websocketx.TextWebSocketFrame
import
jakarta.annotation.PostConstruct
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.launch
import
org.slf4j.LoggerFactory
import
org.springframework.core.io.ResourceLoader
import
org.springframework.scheduling.annotation.Scheduled
import
org.springframework.stereotype.Component
import
java.time.LocalDateTime
@Component
class
AdasPushTask
(
// 注入Spring资源加载器(Spring自动装配)
private
val
resourceLoader
:
ResourceLoader
)
{
private
val
logger
=
LoggerFactory
.
getLogger
(
javaClass
)
// 注入ChannelManager单例
private
val
channelManager
=
ChannelManager
.
instance
//车辆位姿
private
var
carDst
=
mutableListOf
<
String
>()
//感知物
private
var
preDst
=
mutableListOf
<
String
>()
@PostConstruct
fun
readMockFile
()
{
var
classpathResource
=
resourceLoader
.
getResource
(
"classpath:adasm/CarVehicle_fz.txt"
)
// 读取文件内容(Kotlin简化写法)
CoroutineScope
(
Dispatchers
.
IO
).
launch
{
FileIoUtil
.
getMockToList
(
classpathResource
.
inputStream
,
carDst
)
// println("读取到文件内容:${dst.count()}")
classpathResource
=
resourceLoader
.
getResource
(
"classpath:adasm/PerTarget.txt"
)
FileIoUtil
.
getMockToList
(
classpathResource
.
inputStream
,
preDst
)
}
}
/**根据路径推送***/
fun
pushMsgFormPath
(
channel
:
Channel
){
var
path
:
String
=
""
if
(
channel
.
hasAttr
(
REQUEST_PATH_KEY
))
{
path
=
channel
.
attr
(
REQUEST_PATH_KEY
).
get
()
}
when
(
path
)
{
"/ws/adas"
->
{
pushMsgFromTypeAdas
(
channel
)
}
}
}
/**根据type推送**/
private
fun
pushMsgFromTypeAdas
(
channel
:
Channel
)
{
var
type
:
String
?
=
""
if
(
channel
.
hasAttr
(
REQUEST_PARAMS_KEY
))
{
val
params
=
channel
.
attr
(
REQUEST_PARAMS_KEY
).
get
()
type
=
params
.
get
(
PARAM_TYPE_KEY
)
}
when
(
type
)
{
PARAM_TYPE_VALUE_1
->
{
//车辆位姿
if
(
carDst
.
isNotEmpty
()){
CoroutineScope
(
Dispatchers
.
Default
).
launch
{
delay
(
1000
)
carDst
.
forEachIndexed
{
index
,
string
->
// println("index = ${index}")
sendMsg
(
channel
,
string
)
delay
(
200
)
}
}
}
}
PARAM_TYPE_VALUE_2
->
{
//感知物
if
(
preDst
.
isNotEmpty
()){
CoroutineScope
(
Dispatchers
.
Default
).
launch
{
delay
(
2000
)
preDst
.
forEachIndexed
{
index
,
string
->
// println("index = ${index}")
sendMsg
(
channel
,
string
)
delay
(
500
)
}
}
}
}
else
->
{
val
msg
=
JSONObject
()
msg
.
put
(
"type"
,
"adas"
)
msg
.
put
(
"data"
,
"adas"
)
sendMsg
(
channel
,
msg
.
toJSONString
())
}
}
}
private
fun
sendMsg
(
channel
:
Channel
,
msg
:
String
)
{
if
(!
channel
.
isActive
())
{
// println("无在线客户端,跳过推送")
channelManager
.
removeChannel
(
channel
)
return
}
val
clientId
=
channel
.
id
().
asShortText
()
val
frame
=
TextWebSocketFrame
(
msg
)
channel
.
writeAndFlush
(
frame
)
.
addListener
{
future
->
if
(!
future
.
isSuccess
)
{
println
(
"推送消息给客户端[$clientId]失败:${future.cause()?.message}"
)
channelManager
.
removeChannel
(
channel
)
// 推送失败移除失效Channel
}
}
}
}
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/NettyWebSocketServer.kt
View file @
eb5a2d1c
...
...
@@ -27,7 +27,9 @@ import java.net.ServerSocket
@Slf4j
@Component
class
NettyWebSocketServer
(
class
NettyWebSocketServer
(
@Value
(
"\${netty.websocket.port:8089}"
)
private
val
port
:
Int
,
private
val
webSocketHandler
:
WebSocketHandler
)
{
...
...
src/main/kotlin/com/inzy/wsmock/PushConfig.kt
View file @
eb5a2d1c
package
com.inzy.wsmock
import
jakarta.annotation.PreDestroy
import
org.springframework.stereotype.Component
import
java.util.concurrent.atomic.AtomicBoolean
import
java.util.concurrent.atomic.AtomicInteger
@Component
class
PushConfig
{
// 定时推送开关(默认关闭)
val
push
Enabled
=
Atomic
Boolean
(
true
)
val
push
Start
=
Atomic
Integer
(
0
)
// 推送间隔(毫秒,默认5秒)
var
pushInterval
:
Long
=
5000
@PreDestroy
fun
destroy
()
{
pushStart
.
set
(
0
)
}
}
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/PushConfigController.kt
0 → 100644
View file @
eb5a2d1c
package
com.inzy.wsmock
import
com.inzy.wsmock.bean.NaviMockBean
import
org.springframework.web.bind.annotation.GetMapping
import
org.springframework.web.bind.annotation.RequestParam
import
org.springframework.web.bind.annotation.RestController
/**
* 推送配置控制接口
*/
@RestController
//@RequestMapping("/api/push")
class
PushConfigController
(
// 注入PushConfig组件(Spring自动管理单例)
private
val
pushConfig
:
PushConfig
)
{
/**
* 设置推送开关状态
*/
@GetMapping
(
"mock/startnavi"
)
fun
setPushStatus
(
// 必传参数:是否启用推送
@RequestParam
(
"start"
)
start
:
Int
):
NaviMockBean
{
pushConfig
.
pushStart
.
set
(
start
)
val
message
=
if
(
start
==
1
)
"推送开关已启用"
else
"推送开关已禁用"
var
naviMockBean
=
NaviMockBean
().
apply
{
code
=
200
msg
=
message
}
return
naviMockBean
// return JSON.toJSONString(naviMockBean)
}
}
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/RequestParamHandler.kt
View file @
eb5a2d1c
...
...
@@ -16,6 +16,8 @@ class RequestParamHandler : SimpleChannelInboundHandler<TextWebSocketFrame?>() {
val
PARAM_TYPE_KEY
=
"type"
val
PARAM_TYPE_VALUE_1
=
"1"
val
PARAM_TYPE_VALUE_2
=
"2"
val
PARAM_TYPE_VALUE_3
=
"3"
val
PARAM_TYPE_VALUE_4
=
"4"
}
@Throws
(
Exception
::
class
)
...
...
src/main/kotlin/com/inzy/wsmock/WebSocketHandler.kt
View file @
eb5a2d1c
package
com.inzy.wsmock
import
com.inzy.wsmock.push.AdasPushTask
import
com.inzy.wsmock.push.PushFactory
import
io.netty.channel.ChannelHandler.Sharable
import
io.netty.channel.ChannelHandlerContext
import
io.netty.channel.SimpleChannelInboundHandler
...
...
@@ -14,7 +16,7 @@ import org.springframework.stereotype.Component
*/
@Sharable
@Component
class
WebSocketHandler
(
private
val
adasPushTask
:
AdasPushTask
)
:
SimpleChannelInboundHandler
<
WebSocketFrame
>()
{
class
WebSocketHandler
(
private
val
pushFactory
:
PushFactory
)
:
SimpleChannelInboundHandler
<
WebSocketFrame
>()
{
// private val logger = LoggerFactory.getLogger(javaClass)
...
...
@@ -28,7 +30,7 @@ class WebSocketHandler(private val adasPushTask: AdasPushTask) : SimpleChannelIn
// 交给ChannelManager管理
channelManager
.
addChannel
(
channel
)
//根据后缀路径推送
adasPushTask
.
pushMsgFormPath
(
channel
)
pushFactory
.
pushMsgFormPath
(
channel
)
// 握手成功后读取参数(此时参数已存储)
// val params = ctx.channel().attr(RequestParamHandler.REQUEST_PARAMS_KEY).get()
...
...
src/main/kotlin/com/inzy/wsmock/bean/DriveInOrOut.kt
0 → 100644
View file @
eb5a2d1c
package
com.inzy.wsmock.bean
/**
* 电子围栏驶入驶出状态
* {"fenceId":1938523150150586370,"vehicleId":"123456","name":"亦庄电子围栏","fenceChildList":[{"name":"bj_yizhuang","drFenceId":1938523150150586370,"type":"wms","smMapServiceId":3,"url":"https://172.29.128.52/browsemap/wms?service=WMS&version=1.1.0&request=GetMap&layers=workspace:bj_yizhuang"}],"finished":false,"timestamp":1753235649511}
* ***/
class
DriveInOrOut
{
var
fenceChildList
:
List
<
FenceChilds
>?
=
null
var
fenceId
:
Long
=
0L
var
finished
:
Boolean
=
false
//
var
name
:
String
=
""
var
timestamp
:
Long
=
0L
var
vehicleId
:
String
=
""
}
data class
FenceChilds
(
val
drFenceId
:
Long
,
val
name
:
String
,
val
smMapServiceId
:
Int
,
val
type
:
String
,
val
url
:
String
)
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/bean/NaviMockBean.kt
0 → 100644
View file @
eb5a2d1c
package
com.inzy.wsmock.bean
/***开启丰杰***/
class
NaviMockBean
{
var
code
:
Int
=
0
var
msg
:
String
=
""
val
result
:
FResult
=
FResult
(
"ok"
)
}
data class
FResult
(
val
status
:
String
)
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/push/AdasPushTask.kt
0 → 100644
View file @
eb5a2d1c
package
com.inzy.wsmock.push
import
com.alibaba.fastjson2.JSON
import
com.alibaba.fastjson2.JSONObject
import
com.inzy.wsmock.ChannelManager
import
com.inzy.wsmock.PushConfig
import
com.inzy.wsmock.RequestParamHandler
import
com.inzy.wsmock.bean.DriveInOrOut
import
com.inzy.wsmock.utils.FileIoUtil
import
io.netty.channel.Channel
import
io.netty.handler.codec.http.websocketx.TextWebSocketFrame
import
jakarta.annotation.PostConstruct
import
jakarta.annotation.PreDestroy
import
kotlinx.coroutines.*
import
org.slf4j.LoggerFactory
import
org.springframework.core.io.ResourceLoader
import
org.springframework.stereotype.Component
import
java.util.concurrent.atomic.AtomicBoolean
import
java.util.concurrent.atomic.AtomicInteger
@Component
class
AdasPushTask
(
// 注入Spring资源加载器(Spring自动装配)
private
val
resourceLoader
:
ResourceLoader
,
private
val
pushConfig
:
PushConfig
,
)
:
PushTask
{
private
val
logger
=
LoggerFactory
.
getLogger
(
javaClass
)
// 注入ChannelManager单例
private
val
channelManager
=
ChannelManager
.
instance
//车辆位姿
private
var
carDst
=
mutableListOf
<
String
>()
//车辆行驶的位置
private
var
carIndex
=
AtomicInteger
(
0
)
//感知物
private
var
preDst
=
mutableListOf
<
String
>()
//电子围栏只推一次开关
private
var
isFence
=
AtomicBoolean
(
false
)
//v2x只推一次开关
private
var
isV2x
=
AtomicBoolean
(
false
)
@PostConstruct
fun
readMockFile
()
{
var
classpathResource
=
resourceLoader
.
getResource
(
"classpath:adasm/CarVehicle_fz.txt"
)
// 读取文件内容(Kotlin简化写法)
CoroutineScope
(
Dispatchers
.
IO
).
launch
{
FileIoUtil
.
getMockToList
(
classpathResource
.
inputStream
,
carDst
)
// println("读取到文件内容:${dst.count()}")
classpathResource
=
resourceLoader
.
getResource
(
"classpath:adasm/PerTarget.txt"
)
FileIoUtil
.
getMockToList
(
classpathResource
.
inputStream
,
preDst
)
}
}
@PreDestroy
fun
destroy
()
{
carDst
.
clear
()
preDst
.
clear
()
}
override
fun
pushMsgFromType
(
type
:
String
,
channel
:
Channel
)
{
when
(
type
)
{
RequestParamHandler
.
PARAM_TYPE_VALUE_1
->
{
//车辆位姿
pushCarPos
(
channel
)
}
RequestParamHandler
.
PARAM_TYPE_VALUE_2
->
{
//感知物
pushPre
(
channel
)
}
RequestParamHandler
.
PARAM_TYPE_VALUE_3
->
{
//电子围栏驶入驶出
pushFence
(
channel
)
}
RequestParamHandler
.
PARAM_TYPE_VALUE_4
->
{
//v2x 预警
pushV2x
(
channel
)
}
else
->
{
val
msg
=
JSONObject
()
msg
.
put
(
"type"
,
"adas"
)
sendMsg
(
channel
,
msg
.
toJSONString
())
}
}
}
/**
* 推送车辆位姿
*/
private
fun
pushCarPos
(
channel
:
Channel
)
{
CoroutineScope
(
Dispatchers
.
Default
).
launch
{
while
(
isActive
)
{
if
(
pushConfig
.
pushStart
.
get
()
==
0
)
{
println
(
"------------没开始推"
)
// carIndex = 0
isFence
.
set
(
false
)
isV2x
.
set
(
false
)
// sendMsg(channel, carDst.first())
delay
(
1000
)
continue
}
if
(
carDst
.
isNotEmpty
())
{
carDst
.
forEachIndexed
{
index
,
string
->
// println("carIndex = ${carIndex}")
if
(
pushConfig
.
pushStart
.
get
()
==
0
){
return
@forEachIndexed
}
carIndex
.
set
(
index
)
sendMsg
(
channel
,
string
)
delay
(
200
)
}
println
(
"---- pushConfig.pushStart.set(0)"
)
carIndex
.
set
(
0
)
pushConfig
.
pushStart
.
set
(
0
)
}
}
}
}
/**感知物**/
private
fun
pushPre
(
channel
:
Channel
)
{
CoroutineScope
(
Dispatchers
.
Default
).
launch
{
if
(
preDst
.
isNotEmpty
())
{
delay
(
2000
)
preDst
.
forEachIndexed
{
index
,
string
->
// println("index = ${index}")
sendMsg
(
channel
,
string
)
delay
(
500
)
}
pushPre
(
channel
)
}
}
}
/**电子围栏**/
private
fun
pushFence
(
channel
:
Channel
)
{
CoroutineScope
(
Dispatchers
.
Default
).
launch
{
while
(
isActive
)
{
// println("---电子围栏carIndex = ${carIndex.get()}")
if
(
carIndex
.
get
()
==
0
)
continue
if
(
carIndex
.
get
()
==
130
)
{
//驶入 130
if
(
isFence
.
compareAndSet
(
false
,
true
))
{
val
driveInOrOut
=
DriveInOrOut
().
apply
{
finished
=
true
}
sendMsg
(
channel
,
JSON
.
toJSONString
(
driveInOrOut
))
isFence
.
set
(
false
)
}
}
else
if
(
carIndex
.
get
()
==
500
)
{
//驶出 200
if
(
isFence
.
compareAndSet
(
false
,
true
))
{
val
driveInOrOut
=
DriveInOrOut
().
apply
{
finished
=
false
}
sendMsg
(
channel
,
JSON
.
toJSONString
(
driveInOrOut
))
}
}
delay
(
150
)
}
}
}
/**施工**/
private
val
SHIGONG_V2X
=
"F2000004193C01000001980D93029B14323731323800000000000000000000011102004500030004000139373737353064302D616162662D346462312D623234622D303263653862343662623238000001980D9302993E0E8555123AFBF9FFFFFFFF0026050064000001000000000000000000000000000000000000000000000000000000000"
/****交叉路口***/
private
val
JIAOCHALUKOU_V2X
=
"F2000004193C01000001980D93029B14323731323800000000000000000000011102004500030004000139373737353064302D616162662D346462312D623234622D303263653862343662623238000001980D9302993E0E8555123AFBF9FFFFFFFF00840500640000010000000000000000000000000000000000000000000000000000000000"
/****人行横道***/
private
val
RENXINGHENGDAO_V2X
=
"F2000004193C01000001980D93029B14323731323800000000000000000000011102004500030004000139373737353064302D616162662D346462312D623234622D303263653862343662623238000001980D9302993E0E8555123AFBF9FFFFFFFF007205006400000100000000000000000000000000000000000000000000000000000000"
/****前向碰撞***/
private
val
QIANPENG_V2X
=
"F2000000745E01000001995C134B2914595A4D4E3030340000000000000023B8006266313137666466612D666566662D303130302D383564632D33353835303030306163623001000001995C134B294570A9A217BA61FFFFFFFFFF008B0031B92E4570A95117BA62B1FFFFFFFF0089000493E00100020000000000000000000000000000"
/****弱势交通***/
private
val
RUOSHI_V2X
=
"F2000004193C01000001995BD8FCB114595A4D4E3030340000000000000000011101004500030004000166623031303331332D663633662D343138312D623633322D333537623463383635646361000001995BD8FC544570F8E817BA370BFFFFFFFF159005000A000001FFFFFFFFFFFFFFFFFFFFFFFFFFFF00002435303333323435362D333033302D333033302D333533302D33303333333435333339353500000000000000000000000000000"
/****限速***/
private
val
XIANSU_V2X
=
"F2000004193C010000019B8793FAE914534D3030303030310000000000000001110207D000030004000137656266346363372D383133322D343530302D386262632D6132356539386138356433380000019B8793FAE94570A34217BA687AFFFFFFFF0055050064000001FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000"
private
fun
pushV2x
(
channel
:
Channel
)
{
CoroutineScope
(
Dispatchers
.
Default
).
launch
{
while
(
isActive
)
{
if
(
pushConfig
.
pushStart
.
get
()
==
0
)
{
delay
(
1000
)
continue
}
if
(
carIndex
.
get
()
<
100
)
continue
if
(
carIndex
.
get
()
==
200
)
{
//施工
pushV2xAtomic
(
channel
,
SHIGONG_V2X
)
}
else
if
(
carIndex
.
get
()
==
230
)
{
//交叉路口
pushV2xAtomic
(
channel
,
JIAOCHALUKOU_V2X
)
}
else
if
(
carIndex
.
get
()
==
260
)
{
//人行横道
pushV2xAtomic
(
channel
,
RENXINGHENGDAO_V2X
)
}
else
if
(
carIndex
.
get
()
==
320
)
{
//前向碰撞
pushV2xAtomic
(
channel
,
QIANPENG_V2X
)
}
else
if
(
carIndex
.
get
()
==
350
)
{
//弱势交通
pushV2xAtomic
(
channel
,
RUOSHI_V2X
)
}
else
if
(
carIndex
.
get
()
==
400
)
{
//车内限速标牌
pushV2xAtomic
(
channel
,
XIANSU_V2X
,
false
)
}
delay
(
150
)
}
}
}
private
fun
pushV2xAtomic
(
channel
:
Channel
,
str
:
String
,
change
:
Boolean
=
true
)
{
if
(
isV2x
.
compareAndSet
(
false
,
true
))
{
// val msgObj = JSONObject()
// msgObj["content"] = "定时推送消息 type=2 ${LocalDateTime.now()}"
sendMsg
(
channel
,
str
)
if
(
change
)
{
isV2x
.
set
(
false
)
}
}
}
private
fun
sendMsg
(
channel
:
Channel
,
msg
:
String
)
{
if
(!
channel
.
isActive
())
{
// println("无在线客户端,跳过推送")
channelManager
.
removeChannel
(
channel
)
return
}
val
clientId
=
channel
.
id
().
asShortText
()
val
frame
=
TextWebSocketFrame
(
msg
)
channel
.
writeAndFlush
(
frame
)
.
addListener
{
future
->
if
(!
future
.
isSuccess
)
{
println
(
"推送消息给客户端[$clientId]失败:${future.cause()?.message}"
)
channelManager
.
removeChannel
(
channel
)
// 推送失败移除失效Channel
}
}
}
}
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/push/PushFactory.kt
0 → 100644
View file @
eb5a2d1c
package
com.inzy.wsmock.push
import
com.inzy.wsmock.RequestParamHandler
import
io.netty.channel.Channel
import
org.springframework.stereotype.Component
@Component
class
PushFactory
(
private
val
adasPushTask
:
AdasPushTask
)
{
/**根据路径推送***/
fun
pushMsgFormPath
(
channel
:
Channel
)
{
var
path
=
""
if
(
channel
.
hasAttr
(
RequestParamHandler
.
REQUEST_PATH_KEY
))
{
path
=
channel
.
attr
(
RequestParamHandler
.
REQUEST_PATH_KEY
).
get
()
}
val
pushTask
=
createPushProduct
(
path
)
var
type
:
String
?
=
""
if
(
channel
.
hasAttr
(
RequestParamHandler
.
REQUEST_PARAMS_KEY
))
{
val
params
=
channel
.
attr
(
RequestParamHandler
.
Companion
.
REQUEST_PARAMS_KEY
).
get
()
type
=
params
.
get
(
RequestParamHandler
.
PARAM_TYPE_KEY
)
}
type
?.
let
{
pushTask
.
pushMsgFromType
(
it
,
channel
)
}
}
private
fun
createPushProduct
(
path
:
String
):
PushTask
{
when
(
path
)
{
"/ws/adas"
->
{
return
adasPushTask
}
else
->
{
throw
IllegalArgumentException
(
"Unknown product type"
)
}
}
}
}
\ No newline at end of file
src/main/kotlin/com/inzy/wsmock/push/PushTask.kt
0 → 100644
View file @
eb5a2d1c
package
com.inzy.wsmock.push
import
io.netty.channel.Channel
interface
PushTask
{
/**
* 根据查询参数type 推送
* @param type
* */
fun
pushMsgFromType
(
type
:
String
,
channel
:
Channel
)
}
\ No newline at end of file
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