From f5b6e122b371bd4b37f2abde6a395fc1f2257add Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Thu, 19 Sep 2024 11:43:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0SMF=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E7=94=A8=E6=88=B7=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/network_data/controller/smf.go | 68 ++++++++++++++++++- src/modules/network_data/network_data.go | 4 ++ src/modules/network_element/fetch_link/smf.go | 68 +++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/modules/network_element/fetch_link/smf.go diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index 640fac58..e0aaf0df 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -15,6 +15,7 @@ import ( "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" + neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" @@ -22,8 +23,9 @@ import ( // 实例化控制层 SMFController 结构体 var NewSMFController = &SMFController{ - neInfoService: neService.NewNeInfoImpl, - cdrEventService: neDataService.NewCDREventSMFImpl, + neInfoService: neService.NewNeInfoImpl, + cdrEventService: neDataService.NewCDREventSMFImpl, + udmUserInfoService: *neDataService.NewUDMUserInfo, } // 网元SMF @@ -34,6 +36,8 @@ type SMFController struct { neInfoService neService.INeInfo // CDR会话事件服务 cdrEventService neDataService.ICDREventSMF + // UDM用户信息服务 + udmUserInfoService neDataService.UDMUserInfo } // CDR会话列表 @@ -263,3 +267,63 @@ PDU IPv6 Addres Swith Prefix: %s`, User_Identifier, SSC_Mode, RAT_Type, DNN_ID, c.FileAttachment(saveFilePath, fileName) } + +// 在线订阅用户列表信息 +// +// GET /subscribers +func (s *SMFController) SubUserList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var query struct { + NeId string `form:"neId" binding:"required"` + IMSI string `form:"imsi"` + MSISDN string `form:"msisdn"` + Upstate string `form:"upstate"` + PageNum string `form:"pageNum"` + } + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元信息 rmUID + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("SMF", query.NeId) + if neInfo.NeId != query.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + data, err := neFetchlink.SMFSubInfo(neInfo, map[string]string{ + "imsi": query.IMSI, + "msisdn": query.MSISDN, + "upstate": query.Upstate, + "pageNum": query.PageNum, + }) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 对数据进行处理,去掉前缀,并加入imsi拓展信息 + rows := data["rows"].([]any) + arr := &rows + for i := range *arr { + item := (*arr)[i].(map[string]any) + if v, ok := item["imsi"]; ok && v != nil { + imsiStr := v.(string) + imsiStr = strings.TrimPrefix(imsiStr, "imsi-") + item["imsi"] = imsiStr + // 查UDM拓展信息 + info := s.udmUserInfoService.SelectByIMSIAndNeID(imsiStr, "") + item["remark"] = info.Remark + } + if v, ok := item["msisdn"]; ok && v != nil { + item["msisdn"] = strings.TrimPrefix(v.(string), "msisdn-") + } + } + + c.JSON(200, result.Ok(map[string]any{ + "total": data["total"], + "rows": data["rows"], + })) +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 69b513d8..e60cdd9f 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -97,6 +97,10 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)), controller.NewSMFController.CDRExport, ) + smfGroup.GET("/subscribers", + middleware.PreAuthorize(nil), + controller.NewSMFController.SubUserList, + ) } // 网元AMF diff --git a/src/modules/network_element/fetch_link/smf.go b/src/modules/network_element/fetch_link/smf.go new file mode 100644 index 00000000..09954625 --- /dev/null +++ b/src/modules/network_element/fetch_link/smf.go @@ -0,0 +1,68 @@ +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" +) + +// SMFSubInfo SMF在线订阅用户列表信息 +// +// 查询参数 {"imsi":"360000100000130","msisdn":"8612300000130","upstate":"Inactive","pageNum":"1"} +// +// 返回结果 {"rows":[],"total":0} +func SMFSubInfo(neInfo model.NeInfo, data map[string]string) (map[string]any, error) { + // neUrl := "http://127.0.0.1:4523/m1/3157310-1528434-82b449ee/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo?apifoxApiId=150640017" + neUrl := fmt.Sprintf("http://%s:%s/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo", "172.16.20.150", "33030") + // neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo", neInfo.IP, neInfo.Port) + // 查询参数拼接 + query := []string{} + if v, ok := data["imsi"]; ok && v != "" { + query = append(query, fmt.Sprintf("imsi=%s", v)) + } + if v, ok := data["msisdn"]; ok && v != "" { + query = append(query, fmt.Sprintf("msisdn=%s", v)) + } + if v, ok := data["upstate"]; ok && v != "" { + query = append(query, fmt.Sprintf("upstate=%s", v)) + } + // 固定页数量50条 + if v, ok := data["pageNum"]; ok && v != "" { + query = append(query, fmt.Sprintf("pageNum=%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("SMFSubInfo Get \"%s\"", neUrl) + logger.Errorf("SMFSubInfo %s", err.Error()) + return nil, fmt.Errorf("NeService SMF API Error") + } + + // 序列化结果 {"data":[],"total":0} + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Errorf("SMFSubInfo Unmarshal %s", err.Error()) + return nil, err + } + + // 固定返回字段,方便前端解析 + if v, ok := resData["data"]; ok && v != nil { + resData["rows"] = v.([]any) + delete(resData, "data") + } else { + resData["rows"] = []any{} + } + if v, ok := resData["total"]; !ok || v == nil { + resData["total"] = 0 + } + return resData, nil +}