diff --git a/src/modules/network_data/controller/n3iwf.go b/src/modules/network_data/controller/n3iwf.go new file mode 100644 index 00000000..0750b082 --- /dev/null +++ b/src/modules/network_data/controller/n3iwf.go @@ -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)) +} diff --git a/src/modules/network_data/controller/nssf.go b/src/modules/network_data/controller/nssf.go new file mode 100644 index 00000000..7bb0a5cd --- /dev/null +++ b/src/modules/network_data/controller/nssf.go @@ -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)) +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index d0a68959..2df1faab 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -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, diff --git a/src/modules/network_element/fetch_link/n3iwf.go b/src/modules/network_element/fetch_link/n3iwf.go new file mode 100644 index 00000000..598e4ef7 --- /dev/null +++ b/src/modules/network_element/fetch_link/n3iwf.go @@ -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 +} diff --git a/src/modules/network_element/fetch_link/nssf.go b/src/modules/network_element/fetch_link/nssf.go new file mode 100644 index 00000000..c73a35d6 --- /dev/null +++ b/src/modules/network_element/fetch_link/nssf.go @@ -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 +}