Commit eb5a2d1c authored by p x's avatar p x
Browse files

添加4个接口

parent 16e196a6
This diff is collapsed.
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
...@@ -27,7 +27,9 @@ import java.net.ServerSocket ...@@ -27,7 +27,9 @@ import java.net.ServerSocket
@Slf4j @Slf4j
@Component @Component
class NettyWebSocketServer( class
NettyWebSocketServer(
@Value("\${netty.websocket.port:8089}") private val port: Int, @Value("\${netty.websocket.port:8089}") private val port: Int,
private val webSocketHandler: WebSocketHandler private val webSocketHandler: WebSocketHandler
) { ) {
......
package com.inzy.wsmock package com.inzy.wsmock
import jakarta.annotation.PreDestroy
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
@Component @Component
class PushConfig { class PushConfig {
// 定时推送开关(默认关闭) // 定时推送开关(默认关闭)
val pushEnabled = AtomicBoolean(true) val pushStart = AtomicInteger(0)
// 推送间隔(毫秒,默认5秒) // 推送间隔(毫秒,默认5秒)
var pushInterval: Long = 5000 var pushInterval: Long = 5000
@PreDestroy
fun destroy() {
pushStart.set(0)
}
} }
\ No newline at end of file
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
...@@ -16,6 +16,8 @@ class RequestParamHandler : SimpleChannelInboundHandler<TextWebSocketFrame?>() { ...@@ -16,6 +16,8 @@ class RequestParamHandler : SimpleChannelInboundHandler<TextWebSocketFrame?>() {
val PARAM_TYPE_KEY = "type" val PARAM_TYPE_KEY = "type"
val PARAM_TYPE_VALUE_1 = "1" val PARAM_TYPE_VALUE_1 = "1"
val PARAM_TYPE_VALUE_2 = "2" val PARAM_TYPE_VALUE_2 = "2"
val PARAM_TYPE_VALUE_3 = "3"
val PARAM_TYPE_VALUE_4 = "4"
} }
@Throws(Exception::class) @Throws(Exception::class)
......
package com.inzy.wsmock 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.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler import io.netty.channel.SimpleChannelInboundHandler
...@@ -14,7 +16,7 @@ import org.springframework.stereotype.Component ...@@ -14,7 +16,7 @@ import org.springframework.stereotype.Component
*/ */
@Sharable @Sharable
@Component @Component
class WebSocketHandler(private val adasPushTask: AdasPushTask) : SimpleChannelInboundHandler<WebSocketFrame>() { class WebSocketHandler(private val pushFactory: PushFactory) : SimpleChannelInboundHandler<WebSocketFrame>() {
// private val logger = LoggerFactory.getLogger(javaClass) // private val logger = LoggerFactory.getLogger(javaClass)
...@@ -28,7 +30,7 @@ class WebSocketHandler(private val adasPushTask: AdasPushTask) : SimpleChannelIn ...@@ -28,7 +30,7 @@ class WebSocketHandler(private val adasPushTask: AdasPushTask) : SimpleChannelIn
// 交给ChannelManager管理 // 交给ChannelManager管理
channelManager.addChannel(channel) channelManager.addChannel(channel)
//根据后缀路径推送 //根据后缀路径推送
adasPushTask.pushMsgFormPath(channel) pushFactory.pushMsgFormPath(channel)
// 握手成功后读取参数(此时参数已存储) // 握手成功后读取参数(此时参数已存储)
// val params = ctx.channel().attr(RequestParamHandler.REQUEST_PARAMS_KEY).get() // val params = ctx.channel().attr(RequestParamHandler.REQUEST_PARAMS_KEY).get()
......
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
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
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
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
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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment