This commit is contained in:
weizhihong 2023-10-20 15:54:31 +08:00
commit a7b7caa9d1
11 changed files with 162 additions and 51 deletions

View File

@ -20,6 +20,7 @@ import (
apiproto "joylink.club/bj-rtsts-server/grpcproto"
"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) {
@ -78,18 +79,24 @@ func initPublishMapInfo() {
func createByProjectId(c *gin.Context) {
req := dto.SimulationCreateReqDto{}
if err := c.ShouldBind(&req); nil != err {
panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
// panic(dto.ErrorDto{Code: dto.ArgumentParseError, Message: err.Error()})
panic(sys_error.New("测试启动失败,请求参数异常", err))
}
mapInfos := service.QueryProjectPublishedGi(req.ProjectId)
if len(mapInfos) == 0 {
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: "项目未关联地图"})
// panic(dto.ErrorDto{Code: dto.DataNotExist, Message: "项目未关联地图"})
panic(sys_error.New("测试启动失败,项目未关联发布图"))
}
mapIds := make([]int32, len(mapInfos))
for i, mapInfo := range mapInfos {
mapIds[i] = mapInfo.ID
}
rsp := dto.SimulationCreateRspDto{ProjectId: req.ProjectId, MapId: mapIds[0], MapIds: mapIds}
rsp.SimulationId = simulation.CreateSimulation(req.ProjectId, mapIds)
simulationId, err := simulation.CreateSimulation(req.ProjectId, mapIds)
if err != nil {
panic(sys_error.New("测试启动失败", err))
}
rsp.SimulationId = simulationId
c.JSON(http.StatusOK, &rsp)
}

View File

@ -10,6 +10,7 @@ import (
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/middleware"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
func InitUserRouter(api *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
@ -37,9 +38,12 @@ func register(c *gin.Context) {
user := &dto.RegisterUser{}
err := c.BindJSON(user)
if err != nil {
slog.Warn("用户注册失败", err)
panic(sys_error.New("注册失败,参数错误", err))
}
err = service.Register(user)
if err != nil {
panic(sys_error.New("注册失败", err))
}
service.Register(user)
c.JSON(http.StatusOK, "ok")
}

View File

@ -1,12 +1,12 @@
package simulation
import (
"fmt"
"strconv"
"sync"
"joylink.club/bj-rtsts-server/ats/verify/simulation/wayside/memory"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
@ -27,16 +27,18 @@ func IsExistSimulation() bool {
}
// 创建仿真对象
func CreateSimulation(projectId int32, mapIds []int32) string {
func CreateSimulation(projectId int32, mapIds []int32) (string, error) {
simulationId := createSimulationId(projectId)
_, e := simulationMap.Load(simulationId)
if !e && IsExistSimulation() {
panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "已有仿真在运行"})
// panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "已有仿真在运行"})
return "", sys_error.New("一套环境同时只能运行一个仿真")
}
if !e {
verifySimulation, err := memory.CreateSimulation(projectId, mapIds)
if err != nil {
panic(fmt.Sprintf("创建仿真失败:%s", err.Error()))
return "", err
// panic(fmt.Sprintf("创建仿真失败:%s", err.Error()))
}
verifySimulation.SimulationId = simulationId
if config.Config.Dynamics.Open {
@ -44,7 +46,8 @@ func CreateSimulation(projectId int32, mapIds []int32) string {
lineBaseInfo := verifySimulation.BuildLineBaseInfo()
err := dynamics.Default().RequestStartSimulation(lineBaseInfo)
if err != nil {
panic(dto.ErrorDto{Code: dto.DynamicsError, Message: err.Error()})
return "", err
// panic(dto.ErrorDto{Code: dto.DynamicsError, Message: err.Error()})
}
dynamics.Default().Start(verifySimulation)
}
@ -53,8 +56,10 @@ func CreateSimulation(projectId int32, mapIds []int32) string {
semi_physical_train.Default().Start(verifySimulation)
}
simulationMap.Store(simulationId, verifySimulation)
// 全部成功,启动仿真
verifySimulation.World.StartUp()
}
return simulationId
return simulationId, nil
}
// 删除仿真对象

View File

@ -178,9 +178,12 @@ func turnoutMapToEcsLink(repo *repository.Repository, id string, port string, of
default:
panic(dto.ErrorDto{Code: dto.DataNotExist, Message: fmt.Sprintf("无效端口【%s】偏移量", port)})
}
// 统一坐标 岔心公里标
crossKm = convertRepoBaseKm(repo, turnout.GetTurnoutKm(proto2.Port_None))
portKm = convertRepoBaseKm(repo, portKm)
// 岔心公里标
crossKm = turnout.GetTurnoutKm(proto2.Port_None)
portKm, err := repo.ConvertKilometer(portKm, crossKm.CoordinateSystem)
if err != nil {
panic(err)
}
// 关联link
link := portPosition.Link()
isStart := link.ARelation().Device().Id() == id
@ -247,9 +250,11 @@ func ecsLinkMapToTurnout(repo *repository.Repository, isA bool, offset int64, up
}
deviceId = tp.Turnout().Id()
tpOffset := tp.Turnout().FindLinkPositionByPort(tp.Port()).Offset()
// 统一坐标
crossKmInfo := convertRepoBaseKm(repo, tp.Turnout().GetTurnoutKm(proto2.Port_None))
portKmInfo := convertRepoBaseKm(repo, tp.Turnout().GetTurnoutKm(tp.Port()))
crossKmInfo, portKmInfo := tp.Turnout().GetTurnoutKm(proto2.Port_None), tp.Turnout().GetTurnoutKm(tp.Port())
portKmInfo, err := repo.ConvertKilometer(portKmInfo, crossKmInfo.CoordinateSystem)
if err != nil {
panic(err)
}
crossKm, portKm := crossKmInfo.Value, portKmInfo.Value
if isA {
deviceOffset = tpOffset - (tpOffset - offset)
@ -344,5 +349,9 @@ func concertTrainKilometer(kilometer, offset int64, tendTo bool) int64 {
// 转换成统一坐标公里标
func convertRepoBaseKm(r *repository.Repository, km *proto2.Kilometer) *proto2.Kilometer {
return r.ConvertKilometer(km, r.GetCoordinateInfo().Coordinate)
k, err := r.ConvertKilometer(km, r.GetCoordinateInfo().Coordinate)
if err != nil {
panic(err)
}
return k
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"log/slog"
"math"
"runtime"
"sort"
"strconv"
"strings"
@ -18,6 +19,7 @@ import (
"joylink.club/bj-rtsts-server/ats/verify/protos/graphicData"
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/dynamics"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/semi_physical_train"
@ -104,21 +106,22 @@ func CreateSimulation(projectId int32, mapIds []int32) (*VerifySimulation, error
if repo == nil {
protoRepo, err := buildProtoRepository(mapIds)
if err != nil {
return nil, err
return nil, sys_error.New("数据错误", err)
}
protoRepo.Id, protoRepo.Version = repoId, repoVersion
newRepo, err := repository.BuildRepository(protoRepo)
if err != nil {
return nil, err
return nil, sys_error.New("数据错误", err)
}
repo = newRepo
}
// 构建所有UID映射关系
allUidMap := buildRepositoryAllUidsMap(mapIds, repo)
//创建仿真
// worldId := world.CreateSimulation(repo)
w := rtss_simulation.NewSimulation(repo)
w.StartUp()
w, err := rtss_simulation.NewSimulation(repo)
if err != nil {
return nil, sys_error.New("仿真创建失败", err)
}
verifySimulation := &VerifySimulation{
MapIds: mapIds,
ProjectId: projectId,
@ -128,6 +131,11 @@ func CreateSimulation(projectId int32, mapIds []int32) (*VerifySimulation, error
WorldId: w.Id(),
uidMap: allUidMap,
}
// 保证World关闭
runtime.SetFinalizer(verifySimulation, func(verifySimulation *VerifySimulation) {
slog.Info("---关闭仿真World---")
verifySimulation.World.Close()
})
return verifySimulation, nil
}

View File

@ -11,7 +11,7 @@ dynamics:
udpRemotePort: 3000
udpRemoteTrainPort: 3001
httpPort: 7800
open: true
open: false
# VOBC
vobc:
ip: 10.60.1.59

39
init.go
View File

@ -1,6 +1,7 @@
package main
import (
"fmt"
"log/slog"
"net"
"net/http"
@ -13,6 +14,7 @@ import (
"go.uber.org/zap"
"joylink.club/bj-rtsts-server/db/dbquery"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/sys_error"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
@ -45,19 +47,32 @@ func InitServer() *gin.Engine {
engine.Use(cors.New(conf))
// gin panic 异常处理,默认处理为
engine.Use(CustomRecoveryWithSlog(slog.Default(), true, func(c *gin.Context, e interface{}) {
switch e := e.(type) {
case error:
c.JSON(http.StatusInternalServerError, &dto.ErrorDto{
Code: dto.LogicError,
Tip: dto.ErrorTipMap[dto.LogicError],
Message: e.Error(),
})
case dto.ErrorDto:
e.Tip = dto.ErrorTipMap[e.Code]
c.JSON(http.StatusInternalServerError, e)
default:
c.JSON(http.StatusInternalServerError, e)
be, ok := e.(*sys_error.BusinessError)
if !ok {
e, ok := e.(error)
if ok {
be = sys_error.New("未知错误", e)
} else {
be = sys_error.New("未知错误", fmt.Errorf("%v", e))
}
}
c.JSON(http.StatusInternalServerError, &dto.ErrorDto{
Tip: be.UserMsg,
Message: be.Error(),
})
// switch e := e.(type) {
// case error:
// c.JSON(http.StatusInternalServerError, &dto.ErrorDto{
// Code: dto.LogicError,
// Tip: dto.ErrorTipMap[dto.LogicError],
// Message: e.Error(),
// })
// case dto.ErrorDto:
// e.Tip = dto.ErrorTipMap[e.Code]
// c.JSON(http.StatusInternalServerError, e)
// default:
// c.JSON(http.StatusInternalServerError, e)
// }
c.Writer.WriteHeaderNow()
c.Abort()
}))

View File

@ -9,6 +9,7 @@ import (
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/service"
"joylink.club/bj-rtsts-server/sys_error"
)
// 用户权限缓存
@ -40,7 +41,7 @@ func permissionMiddleware() gin.HandlerFunc {
return
}
slog.Error("无权限操作请求路径", "path", path, "method", method)
panic(dto.ErrorDto{Code: dto.NoAuthOperationError, Message: "无权限操作"})
panic(sys_error.New("权限不足"))
}
}

View File

@ -2,13 +2,13 @@ package service
import (
"fmt"
"log/slog"
"sort"
"time"
"joylink.club/bj-rtsts-server/db/dbquery"
"joylink.club/bj-rtsts-server/db/model"
"joylink.club/bj-rtsts-server/dto"
"joylink.club/bj-rtsts-server/sys_error"
)
// 分页查询用户列表
@ -28,23 +28,23 @@ func PagingQueryUser(query *dto.PageUserReqDto) (*dto.PageDto, error) {
return &dto.PageDto{Total: int(total), PageQueryDto: query.PageQueryDto, Records: linkUserRole(records)}, err
}
func Register(user *dto.RegisterUser) {
defer func() {
err := recover()
if err != nil {
slog.Warn("用户注册失败", err)
panic(err)
}
}()
func Register(user *dto.RegisterUser) error {
u := dbquery.User
uq := u.Where()
uq = uq.Where(u.Mobile.Eq(user.Mobile))
findCounter, _ := uq.Count()
findCounter, err := uq.Count()
if err != nil {
return sys_error.New("数据服务异常", err)
}
if findCounter > 0 {
panic(dto.ErrorDto{Code: dto.DataAlreadyExist, Message: "重复的手机号"})
return sys_error.New("手机号已存在")
}
user.RegisterTime = time.Now()
u.Save(user)
err = u.Save(user)
if err != nil {
return sys_error.New("数据服务异常", err)
}
return nil
}
func FindUserInfo(userId int32) *dto.UserRspDto {

61
sys_error/error.go Normal file
View File

@ -0,0 +1,61 @@
package sys_error
import (
"fmt"
"strings"
)
// 业务错误定义
type BusinessError struct {
// 用户提示信息
UserMsg string
// 错误信息传递(用于开发回溯定位,不给用户展示)
Errors []string
}
// 新建业务错误
// 如果errs为空,则返回一个只包含用户提示信息的业务错误
// 如果errs不为空,如果errs是一个业务错误,则附加错误信息,否则返回一个包含用户提示信息和错误信息的业务错误
func New(userMsg string, errs ...error) *BusinessError {
if len(errs) == 1 {
be, ok := errs[0].(*BusinessError)
if ok {
be.prependUserMsg(userMsg)
return be
} else {
return &BusinessError{
UserMsg: userMsg,
Errors: []string{errs[0].Error()},
}
}
}
return &BusinessError{
UserMsg: userMsg,
// Errors: convert(errs),
}
}
func IsBusinessError(err error) bool {
_, ok := err.(*BusinessError)
return ok
}
func (e *BusinessError) prependUserMsg(userMsg string) {
e.UserMsg = fmt.Sprintf("%s,%s", userMsg, e.UserMsg)
}
// func convert(err []error) []string {
// s := []string{}
// for _, e := range err {
// s = append(s, e.Error())
// }
// return s
// }
func (e *BusinessError) Append(err error) {
e.Errors = append(e.Errors, err.Error())
}
func (e *BusinessError) Error() string {
return strings.Join(e.Errors, ", ")
}

View File

@ -11,6 +11,7 @@ import (
"time"
"joylink.club/bj-rtsts-server/config"
"joylink.club/bj-rtsts-server/sys_error"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/bj-rtsts-server/third_party/udp"
)
@ -117,14 +118,14 @@ func (d *dynamics) RequestStartSimulation(base *message.LineBaseInfo) error {
data, _ := json.Marshal(base)
resp, err := d.httpClient.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("请求启动仿真异常: %v", err)
return sys_error.New("动力学开始仿真请求发送错误", err)
}
defer resp.Body.Close()
var buf []byte
_, err = resp.Body.Read(buf)
if err != nil {
return fmt.Errorf("请求启动仿真读取相应异常: %v", err)
return sys_error.New("动力学开始仿真请求响应错误", err)
}
return nil
}