feat: 新增nssf/n3iwf直连接口

This commit is contained in:
TsMask
2025-07-15 15:01:10 +08:00
parent 6f48e0ae41
commit e67c0d6ba6
5 changed files with 365 additions and 6 deletions

View File

@@ -0,0 +1,70 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neFetchlink "be.ems/src/modules/network_element/fetch_link"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 N3IWFController 结构体
var NewN3IWF = &N3IWFController{
neInfoService: neService.NewNeInfo,
}
// 网元N3IWF
//
// PATH /n3iwf
type N3IWFController struct {
neInfoService *neService.NeInfo // 网元信息服务
}
// 在线订阅用户列表信息
//
// GET /sub/list
//
// @Tags network_data/n3iwf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/n3iwf/sub/list [get]
func (s N3IWFController) SubUserList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
NeId string `form:"neId" binding:"required"`
IMSI string `form:"imsi"`
}
if err := c.ShouldBindQuery(&query); 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("N3IWF", query.NeId)
if neInfo.NeId != query.NeId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.N3IWFSubInfoList(neInfo, map[string]string{
"imsi": query.IMSI,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -0,0 +1,107 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neFetchlink "be.ems/src/modules/network_element/fetch_link"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 NSSFController 结构体
var NewNSSF = &NSSFController{
neInfoService: neService.NewNeInfo,
}
// 网元NSSF
//
// PATH /NSSF
type NSSFController struct {
neInfoService *neService.NeInfo // 网元信息服务
}
// 在线订阅用户列表信息
//
// GET /sub/list
//
// @Tags network_data/nssf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/nssf/sub/list [get]
func (s NSSFController) SubUserList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
NeId string `form:"neId" binding:"required"`
}
if err := c.ShouldBindQuery(&query); 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("NSSF", query.NeId)
if neInfo.NeId != query.NeId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.NSSFSubInfoList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 可用AMF列表信息
//
// GET /amf/list
//
// @Tags network_data/nssf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/nssf/amf/list [get]
func (s NSSFController) AvailableList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
NeId string `form:"neId" binding:"required"`
}
if err := c.ShouldBindQuery(&query); 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("NSSF", query.NeId)
if neInfo.NeId != query.NeId || neInfo.IP == "" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.NSSFAvailableAMFList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -100,7 +100,7 @@ func Setup(router *gin.Engine) {
middleware.AuthorizeUser(nil),
controller.NewNBState.List,
)
nbStateGroup.POST("/export",
nbStateGroup.GET("/export",
middleware.AuthorizeUser(nil),
controller.NewNBState.Export,
)
@@ -118,7 +118,7 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewIMS.CDRRemove,
)
imsGroup.POST("/cdr/export",
imsGroup.GET("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewIMS.CDRExport,
@@ -145,7 +145,7 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMSC.CDRRemove,
)
smscGroup.POST("/cdr/export",
smscGroup.GET("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMSC.CDRExport,
@@ -164,7 +164,7 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMF.CDRRemove,
)
smfGroup.POST("/cdr/export",
smfGroup.GET("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMF.CDRExport,
@@ -191,7 +191,7 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewAMF.UERemove,
)
amfGroup.POST("/ue/export",
amfGroup.GET("/ue/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewAMF.UEExport,
@@ -215,6 +215,29 @@ func Setup(router *gin.Engine) {
)
}
// 网元N3IWF
n3iwfGroup := neDataGroup.Group("/n3iwf")
{
n3iwfGroup.GET("/sub/list",
middleware.AuthorizeUser(nil),
controller.NewN3IWF.SubUserList,
)
}
// 网元N3IWF
nssf := controller.NewNSSF
nssfGroup := neDataGroup.Group("/nssf")
{
nssfGroup.GET("/sub/list",
middleware.AuthorizeUser(nil),
nssf.SubUserList,
)
nssfGroup.GET("/amf/list",
middleware.AuthorizeUser(nil),
nssf.AvailableList,
)
}
// 备份数据
backupGroup := neDataGroup.Group("/backup")
{
@@ -452,7 +475,7 @@ func Setup(router *gin.Engine) {
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewMME.UERemove,
)
mmeGroup.POST("/ue/export",
mmeGroup.GET("/ue/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewMME.UEExport,

View File

@@ -0,0 +1,64 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// N3IWFSubInfoList N3IWF在线列表信息
//
// 查询参数 {"imsi":"460302072701181"}
//
// 返回结果 {"rows":[],"total":0}
func N3IWFSubInfoList(neInfo model.NeInfo, data map[string]string) (map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/n3iwf/objectType/ueInfo", neInfo.IP, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["imsi"]; ok && v != "" {
query = append(query, fmt.Sprintf("imsi=%s", v))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
logger.Warnf("N3IWFSubInfo Get \"%s\"", neUrl)
logger.Errorf("N3IWFSubInfo %s", err.Error())
return nil, fmt.Errorf("NeService N3IWF API Error")
}
// 序列化结果
// {
// "data": [
// {
// "activeTime": "2023-11-29 06:35:43",
// "imsi": "460302072701181",
// "nai": "0460302072701181@nai.epc.mnc030.mcc460.3gppnetwork.org",
// "regState": 1
// }
// ]
// }
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("N3IWFSubInfo Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
resData["rows"] = v.([]any)
resData["total"] = len(v.([]any))
delete(resData, "data")
} else {
resData["rows"] = []any{}
resData["total"] = 0
}
return resData, nil
}

View File

@@ -0,0 +1,95 @@
package fetchlink
import (
"encoding/json"
"fmt"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// NSSFSubInfoList NSSF在线列表信息
//
// 返回结果 {"rows":[],"total":0}
func NSSFSubInfoList(neInfo model.NeInfo) (map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/nssf/objectType/subscriptions", neInfo.IP, neInfo.Port)
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
logger.Warnf("NSSFSubInfo Get \"%s\"", neUrl)
logger.Errorf("NSSFSubInfo %s", err.Error())
return nil, fmt.Errorf("NeService NSSF API Error")
}
// 序列化结果
// {
// "data": [
// {
// "subscriptionId": "460302072701181",
// "event": "460302072701181",
// "nfNssaiAvailabilityUri": "0460302072701181@nai.epc.mnc030.mcc460.3gppnetwork.org"
// }
// ]
// }
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NSSFSubInfo Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
resData["rows"] = v.([]any)
resData["total"] = len(v.([]any))
delete(resData, "data")
} else {
resData["rows"] = []any{}
resData["total"] = 0
}
return resData, nil
}
// NSSFAvailableAMFList NSSF装载AMF信息
//
// 返回结果 {"rows":[],"total":0}
func NSSFAvailableAMFList(neInfo model.NeInfo) (map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/nssf/objectType/availableAMFs", neInfo.IP, neInfo.Port)
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
logger.Warnf("NSSFAvailableAMFList Get \"%s\"", neUrl)
logger.Errorf("NSSFAvailableAMFList %s", err.Error())
return nil, fmt.Errorf("NeService NSSF API Error")
}
// 序列化结果
// {
// "data": [
// {
// "nfId": "001",
// "amfSetId": "001"
// },
// {
// "nfId": "002",
// "amfSetId": "[001,002]"
// }
// ]
// }
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NSSFAvailableAMFList Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
resData["rows"] = v.([]any)
resData["total"] = len(v.([]any))
delete(resData, "data")
} else {
resData["rows"] = []any{}
resData["total"] = 0
}
return resData, nil
}