rts-sim-testing-service/api/simulation.go

525 lines
17 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package api
import (
"fmt"
"log/slog"
"net/http"
"sort"
"strconv"
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin"
"github.com/golang/protobuf/proto"
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/ats/verify/simulation"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/dto/request_proto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitSimulationRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
authed := api.Group("/v1/simulation").Use(authMiddleware.MiddlewareFunc(), middleware.PermissMiddleware)
authed.POST("/createByProject", createByProjectId)
authed.POST("/destroy/:id", destroy)
authed.GET("/list", findAllSimulations)
authed.POST("/check/data", checkSimMapData)
authed.POST("/train/add", addTrain)
authed.POST("/train/remove", removeTrain)
authed.POST("/switch/operation", switchOperation)
authed.GET("/getDataChannelName", getDataChannelName)
authed.POST("/relay/operation", relayOperation)
authed.POST("/signal/operation", signalOperation)
authed.POST("/axleSection/operation", axleSectionOperation)
authed.POST("/esbBtn/operation", esbBtnOperation)
authed.POST("/ibp/btn/operation", ibpBtnOperation)
authed.POST("/ibp/key/operation", ibpKeyOperation)
authed.GET("/:id/getMapKilometerRange", getMapKilometerRange)
authed.POST("/psl/operation", pslBtnOperation)
// 初始化地图信息
initPublishMapInfo()
// apiproto.Register(&apiproto.SimulationServer{})
// apiproto.Register(&apiproto.SimulationIBPServer{})
// apiproto.Register(&apiproto.SimulationPSLServer{})
// apiproto.Register(&apiproto.MemoryChangeServer{SimulationMap: make(map[string]*state.SimulationStatus)})
}
func initPublishMapInfo() {
mapArr, err := service.ListAllPublishedGi()
if err != nil {
panic("地图加载出错")
}
sort.SliceStable(mapArr, func(i, j int) bool { return mapArr[i].Type != 0 })
for _, v := range mapArr {
memory.PublishMapVerifyStructure(v)
}
}
// 创建ATS测试仿真通过项目ID
//
// @Summary 创建ATS测试仿真
//
// @Security JwtAuth
//
// @Description 创建ATS测试仿真通过项目ID
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param SimulationCreateReqDto body dto.SimulationCreateReqDto true "创建仿真请求"
// @Success 200 {object} dto.SimulationCreateRspDto
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/createByProject [post]
func createByProjectId(c *gin.Context) {
req := dto.SimulationCreateReqDto{}
if err := c.ShouldBind(&req); nil != err {
panic(sys_error.New("测试启动失败,请求参数异常", err))
}
// 地图信息
mapInfos := service.QueryProjectPublishedGi(req.ProjectId)
if len(mapInfos) == 0 {
panic(sys_error.New("测试启动失败,项目未关联发布图"))
}
mapIds := make([]int32, len(mapInfos))
for i, mapInfo := range mapInfos {
mapIds[i] = mapInfo.ID
}
// 运行环境配置
var runConfigStr string
runConfig := service.QueryRunConfig(req.ProjectRunConfigId)
if runConfig != nil {
runConfigStr = runConfig.ConfigContent
}
simulationId, err := simulation.CreateSimulation(req.ProjectId, mapIds, runConfigStr)
if err != nil {
panic(sys_error.New("测试启动失败", err))
}
rsp := dto.SimulationCreateRspDto{ProjectId: req.ProjectId, MapId: mapIds[0], MapIds: mapIds}
rsp.SimulationId = simulationId
c.JSON(http.StatusOK, &rsp)
}
// ATS仿真销毁
//
// @Summary ATS仿真销毁
//
// @Security JwtAuth
//
// @Description ATS测试仿真-添加列车
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param id path int true "仿真id"
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/destroy/{id} [post]
func destroy(c *gin.Context) {
simId := c.Param("id")
slog.Debug("ATS测试仿真-ATS仿真销毁 请求:", simId)
simulation.DestroySimulation(simId)
c.JSON(http.StatusOK, "ok")
}
// 获取ATS测试系统所有仿真实例的基本信息
//
// @Summary 获取ATS测试系统所有仿真实例的基本信息
//
// @Security JwtAuth
//
// @Description 获取ATS测试系统所有仿真实例的基本信息
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Success 200 {object} dto.SimulationInfoRspDtoArr
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/list [get]
func findAllSimulations(c *gin.Context) {
c.JSON(http.StatusOK, simulation.ListAllSimulations())
}
// ATS测试仿真地图数据校验
//
// @Summary ATS测试仿真地图数据校验
//
// @Security JwtAuth
//
// @Description 地图数据校验
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param RemoveTrainDto body dto.CheckMapDataReqDto true "ATS测试仿真-地图数据"
//
// @Success 200 {object} dto.CheckMapDataRspDto
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/check/data [post]
func checkSimMapData(c *gin.Context) {
rt := &dto.CheckMapDataReqDto{}
if err := c.ShouldBind(&rt); nil != err {
panic(sys_error.New("请求参数异常", err))
}
err := proto.Unmarshal(rt.Data, &graphicData.RtssGraphicStorage{})
if err != nil {
panic(sys_error.New("非平面布置图数据"))
}
c.JSON(http.StatusOK, &dto.CheckMapDataRspDto{Success: true})
}
// ATS测试仿真-添加列车
//
// @Summary ATS测试仿真-添加列车
//
// @Security JwtAuth
//
// @Description ATS测试仿真-添加列车
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param AddTrainReqDto body dto.AddTrainReqDto true "ATS测试仿真-添加列车"
// @Success 200 {object} dto.AddTrainRspDto
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/train/add [post]
func addTrain(c *gin.Context) {
req := dto.AddTrainReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("添加列车失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
id := getAddTrainPrimaryKey(simulation)
if id == -1 {
panic(sys_error.New("添加列车失败,已有列车在运行"))
}
rsp := &state.TrainState{
Id: strconv.Itoa(id),
HeadDeviceId: req.Id,
HeadOffset: req.HeadOffset,
DevicePort: req.DevicePort,
RunDirection: req.RunDirection,
TrainLength: req.TrainLength,
}
memory.AddTrainState(simulation, rsp, req.MapId)
c.JSON(http.StatusOK, &rsp)
}
// ATS测试仿真-移除列车
//
// @Summary ATS测试仿真-移除列车
//
// @Security JwtAuth
//
// @Description ATS测试仿真-移除列车
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param RemoveTrainDto body dto.RemoveTrainDto true "ATS测试仿真-移除列车"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/train/remove [post]
func removeTrain(c *gin.Context) {
rt := &dto.RemoveTrainDto{}
if err := c.ShouldBind(&rt); err != nil {
panic(sys_error.New("移除列车失败,请求参数异常", err))
}
slog.Debug("ATS测试仿真-移除列车,请求:", rt)
simulation := checkDeviceDataAndReturn(rt.SimulationId)
memory.RemoveTrainState(simulation, rt.TrainId)
//TODO 后续调用列车删除操作
c.JSON(http.StatusOK, "ok")
}
// 获取ATS测试-操作道岔
//
// @Summary 获取ATS测试-操作道岔
//
// @Security JwtAuth
//
// @Description ATS测试-操作道岔
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param TurnoutOperationReq body request_proto.TurnoutOperationReq true "ATS测试仿真-操作道岔"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/switch/operation [post]
func switchOperation(c *gin.Context) {
req := &request_proto.TurnoutOperationReq{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("道岔操作失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", "request", req)
memory.HandleTurnoutOperation(simulation, req)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-信号机操作
//
// @Summary ATS测试-信号机操作
//
// @Security JwtAuth
//
// @Description ATS测试-信号机操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param SignalOperationReqDto body dto.SignalOperationReqDto true "ATS测试仿真-操作信号机"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/signal/operation [post]
func signalOperation(c *gin.Context) {
req := &dto.SignalOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("输入参数格式错误", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeSignalState(simulation, req)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-计轴区段操作
//
// @Summary ATS测试-计轴区段操作
//
// @Security JwtAuth
//
// @Description ATS测试-计轴区段操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param AxleSectionOperationReqDto body dto.AxleSectionOperationReqDto true "ATS测试仿真-操作计轴区段"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/axleSection/operation [post]
func axleSectionOperation(c *gin.Context) {
req := &dto.AxleSectionOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("输入参数格式错误", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeAxleSectionState(simulation, req)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-ESB按钮操作
//
// @Summary ATS测试-ESB按钮操作
//
// @Security JwtAuth
//
// @Description ATS测试-ESB按钮操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param EsbButtonOperationReqDto body dto.EsbButtonOperationReqDto true "ATS测试仿真-ESB按钮操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/esbBtn/operation [post]
func esbBtnOperation(c *gin.Context) {
req := &dto.EsbButtonOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("紧急关闭按钮操作失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeEsbButtonState(simulation, req.MapId, req.Id, req.Down)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-IBP按钮操作
//
// @Summary ATS测试-IBP按钮操作
//
// @Security JwtAuth
//
// @Description ATS测试-IBP按钮操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param IBPButtonOperationReqDto body dto.IBPButtonOperationReqDto true "ATS测试仿真-IBP按钮操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/ibp/btn/operation [post]
func ibpBtnOperation(c *gin.Context) {
req := &dto.IBPButtonOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("IBP按钮操作失败请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeIBPButtonState(simulation, req.MapId, req.StationId, req.ButtonCode, req.Down)
c.JSON(http.StatusOK, "ok")
}
// ATS测试-IBP钥匙操作
//
// @Summary ATS测试-IBP钥匙操作
//
// @Security JwtAuth
//
// @Description ATS测试-IBP钥匙操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param KeyOperationReqDto body dto.KeyOperationReqDto true "ATS测试仿真-IBP钥匙操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/ibp/key/operation [post]
func ibpKeyOperation(c *gin.Context) {
req := &dto.KeyOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("IBP开关操作失败请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeIBPKeyState(simulation, req.MapId, req.StationId, req.KeyCode, req.Gear)
c.JSON(http.StatusOK, "ok")
}
// PSL操作
//
// @Summary PSL操作
//
// @Security JwtAuth
//
// @Description PSL操作
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param PslOperationReqDto body dto.PslOperationReqDto true "PSL操作"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/ibp/operation [post]
func pslBtnOperation(c *gin.Context) {
req := &dto.PslOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangePSLButtonState(simulation, req.MapId, req.GateBoxId, req.ButtonCode, req.Down)
c.JSON(http.StatusOK, "ok")
}
// 获取仿真信息更新通道名称
//
// @Summary 获取仿真信息更新通道名称
//
// @Security JwtAuth
//
// @Description 获取仿真信息更新通道名称
//
// Deprecated: 此接口废弃,使用轮询方式更新启动的测试列表
//
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/getDataChannelName [get]
func getDataChannelName(c *gin.Context) {
// c.JSON(http.StatusOK, config.SimulationId_prefix+apiproto.MemoryChangeServerSuffix)
panic(sys_error.New("接口已废弃", fmt.Errorf("此接口废弃,使用轮询方式更新启动的测试列表")))
}
// 获取仿真地图的公里标范围
//
// @Summary 获取仿真地图的公里标范围
//
// @Security JwtAuth
//
// @Description 获取仿真地图的公里标范围
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/:id/getMapKilometerRange [get]
func getMapKilometerRange(c *gin.Context) {
id, exist := c.Params.Get("id")
if !exist {
panic(sys_error.New("缺少仿真编号"))
}
simulation := checkDeviceDataAndReturn(id)
c.JSON(http.StatusOK, simulation.Repo.GetCoordinateInfo())
}
// 获取ATS测试-操作继电器
//
// @Summary 获取ATS测试-操作继电器
//
// @Security JwtAuth
//
// @Description ATS测试-操作继电器
// @Tags ATS测试仿真Api
// @Accept json
// @Produce json
// @Param Authorization header string true "JWT Token"
// @Param RelayOperationReqDto body dto.RelayOperationReqDto true "ATS测试仿真-操作继电器"
//
// @Success 200 {object} string
// @Failure 500 {object} dto.ErrorDto
// @Router /api/v1/simulation/relay/operation [post]
func relayOperation(c *gin.Context) {
req := &dto.RelayOperationReqDto{}
if err := c.ShouldBind(&req); err != nil {
panic(sys_error.New("继电器操作失败,请求参数异常", err))
}
simulation := checkDeviceDataAndReturn(req.SimulationId)
slog.Info("传入状态参数", req)
memory.ChangeRelayState(simulation, req.MapId, req.Id, req.Td)
c.JSON(http.StatusOK, "ok")
}
// 获取仿真设备数据并返回
func checkDeviceDataAndReturn(simId string) *memory.VerifySimulation {
deviceMemory := simulation.FindSimulation(simId)
if deviceMemory == nil {
panic(sys_error.New(fmt.Sprintf("仿真[%s]不存在", simId)))
}
return deviceMemory
}
// 获取列车主键
func getAddTrainPrimaryKey(simulation *memory.VerifySimulation) int {
trainMap := &simulation.Memory.Status.TrainStateMap
// 获取列车ID
i := 1
for {
_, ok := trainMap.Load(strconv.Itoa(i))
if !ok {
break
}
i++
}
return i
}