Refactor network element state management - Removed the NE state endpoint and related service logic from the network_data module. - Introduced a new NEStateController to handle network element state records. - Implemented NEState service and repository for managing state records in the database. - Updated NEInfo and NeLicense controllers to utilize the new NEState service for fetching and saving state information. - Enhanced state handling in the websocket processor to reflect the latest state of network elements. - Added caching logic for network element states using Redis. - Improved error handling and response formatting for state queries.
535 lines
16 KiB
Go
535 lines
16 KiB
Go
package controller
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"be.ems/src/framework/constants"
|
||
"be.ems/src/framework/database/redis"
|
||
"be.ems/src/framework/i18n"
|
||
"be.ems/src/framework/reqctx"
|
||
"be.ems/src/framework/resp"
|
||
"be.ems/src/framework/utils/parse"
|
||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||
"be.ems/src/modules/network_element/model"
|
||
neService "be.ems/src/modules/network_element/service"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// 实例化控制层 NeInfoController 结构体
|
||
var NewNeInfo = &NeInfoController{
|
||
neInfoService: neService.NewNeInfo,
|
||
neLicenseService: neService.NewNeLicense,
|
||
neVersionService: neService.NewNeVersion,
|
||
neStateService: neService.NewNEState,
|
||
}
|
||
|
||
// 网元信息请求
|
||
//
|
||
// PATH /info
|
||
type NeInfoController struct {
|
||
neInfoService *neService.NeInfo // 网元信息服务
|
||
neLicenseService *neService.NeLicense // 网元授权激活信息服务
|
||
neVersionService *neService.NeVersion // 网元版本信息服务
|
||
neStateService *neService.NEState // 网元状态服务
|
||
}
|
||
|
||
// 网元信息状态
|
||
//
|
||
// GET /state
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
|
||
// @Param neId query string true "NE ID" default(001)
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element information state
|
||
// @Description Network element information state
|
||
// @Router /ne/info/state [get]
|
||
func (s NeInfoController) State(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
var querys struct {
|
||
NeType string `form:"neType" binding:"required"`
|
||
NeId string `form:"neId" binding:"required"`
|
||
}
|
||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
|
||
neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeId)
|
||
if neInfo.NeId != querys.NeId || neInfo.IP == "" {
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||
return
|
||
}
|
||
state := s.neStateService.Last(neInfo.NeType, neInfo.NeId)
|
||
result := s.neStateService.ParseState(neInfo, state)
|
||
|
||
// 没状态标记,视为离线
|
||
key := fmt.Sprintf("%s:%s:%s_status", constants.CACHE_NE_INFO, neInfo.NeType, neInfo.NeId)
|
||
keyNum, err := redis.Has("", key)
|
||
if keyNum == 0 || err != nil {
|
||
result["online"] = false
|
||
} else {
|
||
result["online"] = true
|
||
}
|
||
c.JSON(200, resp.OkData(result))
|
||
}
|
||
|
||
// 网元neType和neID查询
|
||
//
|
||
// GET /byTypeAndID
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param neType query string true "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
|
||
// @Param neId query string true "NE ID" default(001)
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element neType and neID queries
|
||
// @Description Network element neType and neID queries
|
||
// @Router /ne/info/byTypeAndID [get]
|
||
func (s NeInfoController) NeTypeAndID(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
var querys struct {
|
||
NeType string `form:"neType" binding:"required"`
|
||
NeID string `form:"neId" binding:"required"`
|
||
}
|
||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
|
||
neInfo := s.neInfoService.FindByNeTypeAndNeID(querys.NeType, querys.NeID)
|
||
if neInfo.NeId != querys.NeID || neInfo.IP == "" {
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||
return
|
||
}
|
||
c.JSON(200, resp.OkData(neInfo))
|
||
}
|
||
|
||
// 网元信息列表全部无分页
|
||
//
|
||
// GET /listAll
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param neType query string true "NE Type"
|
||
// @Param neId query string true "NE ID" default(001)
|
||
// @Param bandStatus query boolean true "With status information"
|
||
// @Param bandHost query boolean true "With host information"
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary The list of network element information is all unpaginated
|
||
// @Description The list of network element information is all unpaginated
|
||
// @Router /ne/info/listAll [get]
|
||
func (s NeInfoController) ListAll(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
var querys struct {
|
||
NeType string `form:"neType"`
|
||
NeId string `form:"neId"`
|
||
BandStatus bool `form:"bandStatus"`
|
||
BandHost bool `form:"bandHost"`
|
||
}
|
||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
|
||
// 查询实体参数
|
||
ne := model.NeInfo{}
|
||
if querys.NeType != "" {
|
||
ne.NeType = querys.NeType
|
||
}
|
||
if querys.NeId != "" {
|
||
ne.NeId = querys.NeId
|
||
}
|
||
neList := s.neInfoService.Find(ne, querys.BandStatus, querys.BandHost)
|
||
if len(neList) == 0 {
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||
return
|
||
}
|
||
c.JSON(200, resp.OkData(neList))
|
||
}
|
||
|
||
// 网元端Para5G配置文件读取
|
||
//
|
||
// GET /para5GFile
|
||
func (s NeInfoController) Para5GFileRead(c *gin.Context) {
|
||
data, err := s.neInfoService.NeConfPara5GRead()
|
||
if err != nil {
|
||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||
return
|
||
}
|
||
c.JSON(200, resp.OkData(data))
|
||
}
|
||
|
||
// 网元端Para5G配置文件写入
|
||
//
|
||
// PUT /para5GFile
|
||
func (s NeInfoController) Para5GFileWrite(c *gin.Context) {
|
||
var body struct {
|
||
Content map[string]any `json:"content" binding:"required"` // 内容
|
||
SyncNE []string `json:"syncNe"` // 同步到网元
|
||
}
|
||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
|
||
err := s.neInfoService.NeConfPara5GWirte(body.Content, body.SyncNE)
|
||
if err != nil {
|
||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||
return
|
||
}
|
||
c.JSON(200, resp.Ok(nil))
|
||
}
|
||
|
||
// 网元端OAM配置文件读取
|
||
//
|
||
// GET /oamFile
|
||
func (s NeInfoController) OAMFileRead(c *gin.Context) {
|
||
var querys struct {
|
||
NeType string `form:"neType" binding:"required"`
|
||
NeID string `form:"neId" binding:"required"`
|
||
}
|
||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
|
||
data, err := s.neInfoService.NeConfOAMReadSync(querys.NeType, querys.NeID)
|
||
if err != nil {
|
||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||
return
|
||
}
|
||
c.JSON(200, resp.OkData(data))
|
||
}
|
||
|
||
// 网元端OAM配置文件写入
|
||
//
|
||
// PUT /oamFile
|
||
func (s NeInfoController) OAMFileWrite(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
var body struct {
|
||
NeType string `json:"neType" binding:"required"`
|
||
NeID string `json:"neId" binding:"required"`
|
||
Content map[string]any `json:"content" binding:"required"` // 内容
|
||
Sync bool `json:"sync"` // 同步到网元
|
||
}
|
||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
|
||
// 查询网元获取IP
|
||
neInfo := s.neInfoService.FindByNeTypeAndNeID(body.NeType, body.NeID)
|
||
if neInfo.NeId != body.NeID || neInfo.IP == "" {
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||
return
|
||
}
|
||
|
||
err := s.neInfoService.NeConfOAMWirteSync(neInfo, body.Content, body.Sync)
|
||
if err != nil {
|
||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||
return
|
||
}
|
||
c.JSON(200, resp.Ok(nil))
|
||
}
|
||
|
||
// 网元信息列表
|
||
//
|
||
// GET /list
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param bandStatus query boolean false "The result carries the state of the network element"
|
||
// @Param neId query string false "NE ID"
|
||
// @Param neType query string false "Ne Type"
|
||
// @Param pageNum query number true "pageNum" default(1)
|
||
// @Param pageSize query number true "pageSize" default(10)
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element information list
|
||
// @Description Network element information list
|
||
// @Router /ne/info/list [get]
|
||
func (s NeInfoController) List(c *gin.Context) {
|
||
query := reqctx.QueryMap(c)
|
||
bandStatus := false
|
||
if v, ok := query["bandStatus"]; ok {
|
||
bandStatus = parse.Boolean(v)
|
||
}
|
||
rows, total := s.neInfoService.FindByPage(query, bandStatus)
|
||
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
|
||
}
|
||
|
||
// 网元信息
|
||
//
|
||
// GET /:id
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param value path string true "Row ID"
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element information
|
||
// @Description Network element information
|
||
// @Router /ne/info/{value} [get]
|
||
func (s NeInfoController) Info(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
id := parse.Number(c.Param("id"))
|
||
if id <= 0 {
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
|
||
return
|
||
}
|
||
|
||
neHost := s.neInfoService.FindById(id, true)
|
||
if neHost.ID != id {
|
||
// 没有可访问网元信息数据!
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "neInfo.noData")))
|
||
return
|
||
}
|
||
|
||
c.JSON(200, resp.OkData(neHost))
|
||
}
|
||
|
||
// 网元信息新增
|
||
//
|
||
// POST /
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body object true "Request Param"
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element information addition
|
||
// @Description Network element information addition
|
||
// @Router /ne/info [post]
|
||
func (s NeInfoController) Add(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
var body model.NeInfo
|
||
err := c.ShouldBindBodyWithJSON(&body)
|
||
if err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
if body.ID != 0 {
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty"))
|
||
return
|
||
}
|
||
|
||
// 检查属性值唯一
|
||
uniqueInfo := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, 0)
|
||
if !uniqueInfo {
|
||
// 网元信息操作【%s】失败,同类型下标识已存在
|
||
msg := i18n.TTemplate(language, "neInfo.errKeyExists", map[string]any{"key": body.NeId})
|
||
c.JSON(200, resp.ErrMsg(msg))
|
||
return
|
||
}
|
||
|
||
loginUserName := reqctx.LoginUserToUserName(c)
|
||
// 新增Version信息
|
||
neVersion := model.NeVersion{
|
||
NeType: body.NeType,
|
||
NeId: body.NeId,
|
||
CreateBy: loginUserName,
|
||
}
|
||
// 新增License信息
|
||
neLicense := model.NeLicense{
|
||
NeType: body.NeType,
|
||
NeId: body.NeId,
|
||
CreateBy: loginUserName,
|
||
}
|
||
|
||
// 获取网元状态是否正常
|
||
key := fmt.Sprintf("%s:%s:%s_status", constants.CACHE_NE_INFO, body.NeType, body.NeId)
|
||
state, err := neFetchlink.NeState(body)
|
||
if err != nil {
|
||
redis.Del("", key)
|
||
body.Status = 0
|
||
} else {
|
||
redis.Set("", key, body.RmUID, 0)
|
||
// 网元状态设置为在线
|
||
body.Status = 1
|
||
if parse.Boolean(state["standby"]) {
|
||
body.Status = 3
|
||
}
|
||
// 下发网管配置信息给网元
|
||
if _, err = neFetchlink.NeConfigOMC(body); err != nil {
|
||
body.Status = 2
|
||
}
|
||
// 网元状态记录
|
||
neState := s.neStateService.SaveState(state)
|
||
body.ServerState = s.neStateService.ParseState(body, neState)
|
||
if neState.ID > 0 {
|
||
body.NeVersion = neState.NeVersion
|
||
neVersion.Version = neState.NeVersion
|
||
neLicense.SerialNum = neState.SerialNum
|
||
neLicense.ExpiryDate = neState.ExpiryDate
|
||
neLicense.Status = "1"
|
||
neLicense.UeNumber = neState.UENumber
|
||
neLicense.NbNumber = neState.NbNumber
|
||
}
|
||
}
|
||
|
||
s.neVersionService.Insert(neVersion)
|
||
s.neLicenseService.Insert(neLicense)
|
||
body.CreateBy = loginUserName
|
||
insertId := s.neInfoService.Insert(body)
|
||
if insertId > 0 {
|
||
c.JSON(200, resp.OkData(insertId))
|
||
return
|
||
}
|
||
c.JSON(200, resp.Err(nil))
|
||
}
|
||
|
||
// 网元信息修改
|
||
//
|
||
// PUT /
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param data body object true "Request Param"
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element information modification
|
||
// @Description Network element information modification
|
||
// @Router /ne/info [put]
|
||
func (s NeInfoController) Edit(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
var body model.NeInfo
|
||
err := c.ShouldBindBodyWithJSON(&body)
|
||
if err != nil {
|
||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||
return
|
||
}
|
||
if body.ID <= 0 {
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
|
||
return
|
||
}
|
||
|
||
// 检查属性值唯一
|
||
uniqueInfo := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, body.ID)
|
||
if !uniqueInfo {
|
||
// 网元信息操作【%s】失败,同类型下标识已存在
|
||
msg := i18n.TTemplate(language, "neInfo.errKeyExists", map[string]any{"key": body.NeId})
|
||
c.JSON(200, resp.ErrMsg(msg))
|
||
return
|
||
}
|
||
|
||
// 检查是否存在
|
||
neInfo := s.neInfoService.FindById(body.ID, false)
|
||
if neInfo.ID != body.ID {
|
||
// 没有可访问网元信息数据!
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "neInfo.noData")))
|
||
return
|
||
}
|
||
// 赋予主机ID
|
||
if neInfo.HostIDs != "" && len(body.Hosts) > 0 {
|
||
hostIDs := strings.Split(neInfo.HostIDs, ",")
|
||
for index, id := range hostIDs {
|
||
body.Hosts[index].ID = parse.Number(id)
|
||
}
|
||
}
|
||
|
||
loginUserName := reqctx.LoginUserToUserName(c)
|
||
neLicense := s.neLicenseService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||
neVersion := s.neVersionService.FindByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)
|
||
|
||
// 获取网元状态是否正常
|
||
key := fmt.Sprintf("%s:%s:%s_status", constants.CACHE_NE_INFO, body.NeType, body.NeId)
|
||
state, err := neFetchlink.NeState(body)
|
||
if err != nil {
|
||
redis.Del("", key)
|
||
body.Status = 0
|
||
} else {
|
||
redis.Set("", key, body.RmUID, 0)
|
||
// 网元状态设置为在线
|
||
body.Status = 1
|
||
if parse.Boolean(state["standby"]) {
|
||
body.Status = 3
|
||
}
|
||
// 下发网管配置信息给网元
|
||
if _, err = neFetchlink.NeConfigOMC(body); err != nil {
|
||
body.Status = 2
|
||
}
|
||
// 网元状态记录
|
||
neState := s.neStateService.SaveState(state)
|
||
body.ServerState = s.neStateService.ParseState(body, neState)
|
||
if neState.ID > 0 {
|
||
body.NeVersion = neState.NeVersion
|
||
neVersion.Version = neState.NeVersion
|
||
s.neVersionService.Update(neVersion)
|
||
neLicense.SerialNum = neState.SerialNum
|
||
neLicense.ExpiryDate = neState.ExpiryDate
|
||
neLicense.Status = "1"
|
||
neLicense.UeNumber = neState.UENumber
|
||
neLicense.NbNumber = neState.NbNumber
|
||
s.neLicenseService.Update(neLicense)
|
||
}
|
||
}
|
||
|
||
body.UpdateBy = loginUserName
|
||
rows := s.neInfoService.Update(body)
|
||
if rows > 0 {
|
||
c.JSON(200, resp.Ok(nil))
|
||
return
|
||
}
|
||
c.JSON(200, resp.Err(nil))
|
||
}
|
||
|
||
// 网元信息删除
|
||
//
|
||
// DELETE /:id
|
||
//
|
||
// @Tags network_element/info
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param value path string true "Row ID"
|
||
// @Success 200 {object} object "Response Results"
|
||
// @Security TokenAuth
|
||
// @Summary Network element information deletion
|
||
// @Description Network element information deletion
|
||
// @Router /ne/info [delete]
|
||
func (s NeInfoController) Remove(c *gin.Context) {
|
||
language := reqctx.AcceptLanguage(c)
|
||
id := c.Param("id")
|
||
if id == "" {
|
||
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
|
||
return
|
||
}
|
||
|
||
// 处理字符转id数组后去重
|
||
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
|
||
// 转换成int64数组类型
|
||
ids := make([]int64, 0)
|
||
for _, v := range uniqueIDs {
|
||
ids = append(ids, parse.Number(v))
|
||
}
|
||
|
||
rows, err := s.neInfoService.DeleteByIds(ids)
|
||
if err != nil {
|
||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
|
||
return
|
||
}
|
||
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
|
||
c.JSON(200, resp.OkMsg(msg))
|
||
}
|