添加业务错误结构

修改用户注册和启动测试仿真接口使用业务错误返回
调整一些接口返回error
This commit is contained in:
walker 2023-10-20 15:08:47 +08:00
parent 7542ee473c
commit c9eaef1d6f
12 changed files with 157 additions and 48 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) {
@ -75,18 +76,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

@ -2,7 +2,6 @@ package simulation
import (
"encoding/binary"
"fmt"
"strconv"
"sync"
"time"
@ -10,6 +9,7 @@ import (
"joylink.club/bj-rtsts-server/ats/verify/protos/state"
"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"
@ -69,16 +69,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 {
@ -86,7 +88,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)
}
@ -98,10 +101,13 @@ func CreateSimulation(projectId int32, mapIds []int32) string {
// if httpCode != http.StatusOK || err != nil {
// panic(dto.ErrorDto{Code: dto.DynamicsError, Message: fmt.Sprintf("动力学接口调用失败:[%d][%s]", httpCode, err)})
// }
simulationMap.Store(simulationId, verifySimulation)
// dynamicsRun(verifySimulation)
simulationMap.Store(simulationId, verifySimulation)
// 全部成功,启动仿真
verifySimulation.World.StartUp()
}
return simulationId
return simulationId, nil
}
// 删除仿真对象

View File

@ -174,7 +174,10 @@ func turnoutMapToEcsLink(repo *repository.Repository, id string, port string, of
}
// 岔心公里标
crossKm = turnout.GetTurnoutKm(proto2.Port_None)
portKm = repo.ConvertKilometer(portKm, crossKm.CoordinateSystem)
portKm, err := repo.ConvertKilometer(portKm, crossKm.CoordinateSystem)
if err != nil {
panic(err)
}
// 关联link
link := portPosition.Link()
isStart := link.ARelation().Device().Id() == id
@ -242,7 +245,10 @@ func ecsLinkMapToTurnout(repo *repository.Repository, isA bool, offset int64, up
deviceId = tp.Turnout().Id()
tpOffset := tp.Turnout().FindLinkPositionByPort(tp.Port()).Offset()
crossKmInfo, portKmInfo := tp.Turnout().GetTurnoutKm(proto2.Port_None), tp.Turnout().GetTurnoutKm(tp.Port())
portKmInfo = repo.ConvertKilometer(portKmInfo, crossKmInfo.CoordinateSystem)
portKmInfo, err := repo.ConvertKilometer(portKmInfo, crossKmInfo.CoordinateSystem)
if err != nil {
panic(err)
}
crossKm, portKm := crossKmInfo.Value, portKmInfo.Value
if isA {
deviceOffset = tpOffset - (tpOffset - offset)

View File

@ -4,6 +4,7 @@ import (
"fmt"
"log/slog"
"math"
"runtime"
"sort"
"strconv"
"strings"
@ -14,6 +15,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/deprecated/vobc"
"joylink.club/bj-rtsts-server/third_party/message"
"joylink.club/ecs"
@ -99,12 +101,12 @@ 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
}
@ -114,9 +116,10 @@ func CreateSimulation(projectId int32, mapIds []int32) (*VerifySimulation, error
// 构建所有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,
@ -126,6 +129,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
}

@ -1 +1 @@
Subproject commit 43345d1094b74b36e77d31ee3dc4b63557406604
Subproject commit 9b1c6d78012eff4f9d300412ad41c8175751767d

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("权限不足"))
}
}

@ -1 +1 @@
Subproject commit 30c4210a5d0411bb52d383bef7e77de7b9484800
Subproject commit 7fb253612ec7ecfb0836e8c9c89cd6a4fc58f949

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
}