package api import ( "fmt" "net/http" "strconv" jwt "github.com/appleboy/gin-jwt/v2" "github.com/gin-gonic/gin" "github.com/golang/protobuf/proto" "go.uber.org/zap" "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/config" "joylink.club/bj-rtsts-server/dto" apiproto "joylink.club/bj-rtsts-server/grpcproto" "joylink.club/bj-rtsts-server/middleware" "joylink.club/bj-rtsts-server/service" ) func InitSimulationRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { authed := api.Group("/v1/simulation").Use(authMiddleware.MiddlewareFunc(), middleware.PermissMiddleware) authed.POST("/create", create) authed.POST("/createByProject", createByProjectId) authed.GET("/state/:id", findSimulationState) 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) // 初始化地图信息 initPublishMapInfo() apiproto.RegisterMsgServer(&apiproto.SimulationServer{}) apiproto.RegisterMsgServer(&apiproto.MemoryChangeServer{SimulationMap: make(map[string]*state.SimulationStatus)}) } func initPublishMapInfo() { mapArr, err := service.ListAllPublishedGi() if err != nil { panic("地图加载出错") } for _, v := range mapArr { memory.PublishMapVerifyStructure(v) } } // 创建ATS测试仿真 // // @Summary 创建ATS测试仿真 // // @Security JwtAuth // // @Description 创建ATS测试仿真 // @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/create [post] func create(c *gin.Context) { if simulation.IsExistSimulation() { panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "已有仿真在运行"}) } req := dto.SimulationCreateReqDto{} if err := c.ShouldBind(&req); nil != err { panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) } zap.S().Debug("创建仿真请求:", req) rsp := dto.SimulationCreateRspDto{ MapId: req.MapId, } rsp.SimulationId = simulation.CreateSimulation(req.MapId, req.ProjectId) c.JSON(http.StatusOK, &rsp) } // 创建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) { if simulation.IsExistSimulation() { panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "已有仿真在运行"}) } req := dto.SimulationCreateReqDto{} if err := c.ShouldBind(&req); nil != err { panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) } zap.S().Debug("创建仿真请求:", req) rsp := dto.SimulationCreateRspDto{ ProjectId: req.ProjectId, } mapInfos := service.QueryPublishedGi(req.ProjectId) if len(mapInfos) == 0 { panic(dto.ErrorDto{Code: dto.DataNotExist, Message: "项目未关联地图"}) } mapInfo := mapInfos[0] rsp.MapId = mapInfo.ID rsp.SimulationId = simulation.CreateSimulation(mapInfo.ID, req.ProjectId) c.JSON(http.StatusOK, &rsp) } // 创建并进入仿真后获取仿真的设备信息 // // @Summary 创建并进入仿真后获取仿真的设备信息 // // @Security JwtAuth // // @Description 创建并进入仿真后获取仿真的设备信息 // @Tags ATS测试仿真Api // @Accept json // @Produce json // @Param Authorization header string true "JWT Token" // @Param id path int true "仿真id" // @Success 200 {object} dto.SimulationCreateRspDto // @Failure 500 {object} dto.ErrorDto // @Router /api/v1/simulation/state/:id [get] func findSimulationState(c *gin.Context) { simId := c.Param("id") simulation := checkDeviceDataAndReturn(simId) allState := simulation.GetAllState() c.JSON(http.StatusOK, allState) } // 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") zap.S().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(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) } err := proto.Unmarshal(rt.Data, &graphicData.RtssGraphicStorage{}) if err != nil { c.JSON(http.StatusInternalServerError, "参数错误") } else { 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(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) } simulation := checkDeviceDataAndReturn(req.SimulationId) id := getAddTrainPrimaryKey(simulation) if id == -1 { c.JSON(http.StatusBadRequest, "已存在在线列车") } else { 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) 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(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) } zap.S().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 RemoveTrainDto body dto.SwitchOperationReqDto true "ATS测试仿真-操作道岔" // // @Success 200 {object} string // @Failure 500 {object} dto.ErrorDto // @Router /api/v1/simulation/switch/operation [post] func switchOperation(c *gin.Context) { req := &dto.SwitchOperationReqDto{} if err := c.ShouldBind(&req); err != nil { panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()}) } simulation := checkDeviceDataAndReturn(req.SimulationId) zap.S().Info("传入状态参数", req) memory.ChangeTurnoutState(simulation, &state.SwitchState{ Id: req.SwitchIndex, Normal: req.TurnNormal, Reverse: req.TurnReverse, }) c.JSON(http.StatusOK, "ok") } // 获取仿真信息更新通道名称 // // @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/getDataChannelName [get] func getDataChannelName(c *gin.Context) { c.JSON(http.StatusOK, config.SimulationId_prefix+apiproto.MemoryChangeServerSuffix) } // 获取仿真设备数据并返回 func checkDeviceDataAndReturn(simId string) *memory.VerifySimulation { deviceMemory := simulation.FindSimulation(simId) if deviceMemory == nil { panic(&dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("仿真[%s]不存在", simId)}) } return deviceMemory } // 获取列车主键 func getAddTrainPrimaryKey(simulation *memory.VerifySimulation) int { trainMap := &simulation.Memory.Status.TrainStateMap // 获取列车ID i := 1 for { t, ok := trainMap.Load(strconv.Itoa(i)) if ok { ts := t.(*state.TrainState) if ts.Show { i = -1 break } i++ } else { break } } return i }