diff --git a/src/modules/network_element/controller/ne_info.go b/src/modules/network_element/controller/ne_info.go new file mode 100644 index 0000000..07ca0d1 --- /dev/null +++ b/src/modules/network_element/controller/ne_info.go @@ -0,0 +1,42 @@ +package controller + +import ( + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" + "ems.agt/src/framework/vo/result" + neService "ems.agt/src/modules/network_element/service" + "github.com/gin-gonic/gin" +) + +// 实例化控制层 NeInfoController 结构体 +var NewNeInfo = &NeInfoController{ + neInfoService: neService.NewNeInfoImpl, +} + +// 网元信息请求 +// +// PATH / +type NeInfoController struct { + // 网元信息服务 + neInfoService neService.INeInfo +} + +// 网元neType和neID查询 +// +// GET /info +func (s *NeInfoController) NeTypeAndID(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neType := c.Query("neType") + neId := c.Query("neId") + if neType == "" || neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + c.JSON(200, result.OkData(neInfo)) +} diff --git a/src/modules/network_element/controller/udm_auth.go b/src/modules/network_element/controller/udm_auth.go new file mode 100644 index 0000000..a3e5596 --- /dev/null +++ b/src/modules/network_element/controller/udm_auth.go @@ -0,0 +1,455 @@ +package controller + +import ( + "fmt" + "strings" + "time" + + mmlclient "ems.agt/lib/core/mml_client" + "ems.agt/src/framework/config" + "ems.agt/src/framework/constants/uploadsubpath" + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" + "ems.agt/src/framework/utils/file" + "ems.agt/src/framework/utils/ssh" + "ems.agt/src/framework/vo/result" + "ems.agt/src/modules/network_element/model" + neService "ems.agt/src/modules/network_element/service" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 UDMAuthController 结构体 +var NewUDMAuth = &UDMAuthController{ + udmAuthService: neService.NewUDMAuthImpl, + neInfoService: neService.NewNeInfoImpl, +} + +// UDM鉴权用户请求 +// +// PATH /udm/auth +type UDMAuthController struct { + // UDM鉴权信息服务 + udmAuthService neService.IUDMAuth + // 网元信息服务 + neInfoService neService.INeInfo +} + +// UDM鉴权用户-获取全部保存数据库 +// +// POST /resetData/:neId +func (s *UDMAuthController) ResetData(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neId = "" + data := s.udmAuthService.Save(neId) + c.JSON(200, result.OkData(data)) +} + +// UDM鉴权用户 +// +// GET /list +func (s *UDMAuthController) List(c *gin.Context) { + querys := ctx.QueryMap(c) + querys["neId"] = "" + data := s.udmAuthService.Page(querys) + c.JSON(200, result.Ok(data)) +} + +// UDM鉴权用户-信息 +// +// GET /:neId/:imsi +func (s *UDMAuthController) Info(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + imsi := c.Param("imsi") + if neId == "" || imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + + // 发送MML + data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 查询数据库是否存在并存入 + neId = "" + var userInfo model.UDMAuth + list := s.udmAuthService.List(model.UDMAuth{NeID: neId, Imsi: imsi}) + if len(list) > 0 { + userInfo = list[0] + // 返回查询的用户信息 + userInfo.Amf = data["amf"] + userInfo.AlgoIndex = data["algo"] + userInfo.Opc = data["opc"] + userInfo.Ki = data["ki"] + } else { + userInfo := model.UDMAuth{ + Imsi: imsi, + Amf: data["amf"], + AlgoIndex: data["algo"], + Opc: data["opc"], + Ki: data["ki"], + } + s.udmAuthService.Insert(neId, userInfo) + } + c.JSON(200, result.OkData(userInfo)) +} + +// UDM鉴权用户-增加 +// +// POST /:neId +func (s *UDMAuthController) Add(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + var body model.UDMAuth + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.Imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmAuthService.Insert(neId, body) + } + c.JSON(200, result.OkData(data)) +} + +// UDM鉴权用户-批量添加 +// +// POST /:neId/:num +func (s *UDMAuthController) Adds(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + num := c.Param("num") + if neId == "" || num == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + var body model.UDMAuth + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.Imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("bad authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmAuthService.Inserts(neId, body, num) + } + c.JSON(200, result.OkData(data)) +} + +// UDM鉴权用户-修改 +// +// PUT /:neId +func (s *UDMAuthController) Edit(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + var body model.UDMAuth + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.Imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("mod authdata:imsi=%s", body.Imsi) + // 修改的参数名称 + if body.Ki != "" { + msg += fmt.Sprintf(",ki=%s", body.Ki) + } + if body.Amf != "" { + msg += fmt.Sprintf(",amf=%s", body.Amf) + } + if body.AlgoIndex != "" { + msg += fmt.Sprintf(",algo=%s", body.AlgoIndex) + } + if body.Opc != "" { + msg += fmt.Sprintf(",opc=%s", body.Opc) + } + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmAuthService.Update(neId, body) + } + c.JSON(200, result.OkData(data)) +} + +// UDM鉴权用户-删除 +// +// DELETE /:neId/:imsi +func (s *UDMAuthController) Remove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + imsi := c.Param("imsi") + if neId == "" || imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("del authdat:imsi=%s", imsi) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmAuthService.Delete(neId, imsi) + } + c.JSON(200, result.OkData(data)) +} + +// UDM鉴权用户-批量删除 +// +// DELETE /:neId/:imsi/:num +func (s *UDMAuthController) Removes(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + imsi := c.Param("imsi") + num := c.Param("num") + if neId == "" || imsi == "" || num == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmAuthService.Deletes(neId, imsi, num) + } + c.JSON(200, result.OkData(data)) +} + +// UDM鉴权用户-导出 +// +// POST /export +func (s *UDMAuthController) Export(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body struct { + NeId string `json:"neId" binding:"required"` + Type string `json:"type" binding:"required"` + } + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + if !(body.Type == "csv" || body.Type == "txt") { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportFileFormat"))) + return + } + + neId := "" + list := s.udmAuthService.List(model.UDMAuth{NeID: neId}) + // 文件名 + fileName := fmt.Sprintf("OMC_AUTH_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) + filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName) + + if body.Type == "csv" { + // 转换数据 + data := [][]string{} + data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"}) + for _, v := range list { + data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + } + // 输出到文件 + err := file.WriterCSVFile(data, filePath) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + } + + if body.Type == "txt" { + // 转换数据 + data := [][]string{} + for _, v := range list { + data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + } + // 输出到文件 + err = file.WriterTxtFile(data, filePath) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + } + + c.FileAttachment(filePath, fileName) +} + +// UDM鉴权用户-导入 +// +// POST /import +func (s *UDMAuthController) Import(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.PostForm("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + formFile, err := c.FormFile("file") + if err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 获取文件名 + if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) + return + } + // 上传文件转存 + upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 本地文件 + localPath := file.ParseUploadFilePath(upFilePath) + nePath := config.Get("mml.upload").(string) + // 复制到远程 + err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + fileName := localPath[strings.LastIndex(localPath, "/")+1:] + msg := fmt.Sprintf("import authdat:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + if strings.HasSuffix(fileName, ".csv") { + data := file.ReadCSVFile(localPath) + neId = "" + go s.udmAuthService.InsertCSV(neId, data) + } + if strings.HasSuffix(fileName, ".txt") { + data := file.ReadTxtFile(localPath) + neId = "" + go s.udmAuthService.InsertTxt(neId, data) + } + } + c.JSON(200, result.OkMsg(data)) +} diff --git a/src/modules/network_element/controller/udm_sub.go b/src/modules/network_element/controller/udm_sub.go new file mode 100644 index 0000000..dce7063 --- /dev/null +++ b/src/modules/network_element/controller/udm_sub.go @@ -0,0 +1,533 @@ +package controller + +import ( + "fmt" + "strconv" + "strings" + "time" + + mmlclient "ems.agt/lib/core/mml_client" + "ems.agt/src/framework/config" + "ems.agt/src/framework/constants/uploadsubpath" + "ems.agt/src/framework/i18n" + "ems.agt/src/framework/utils/ctx" + "ems.agt/src/framework/utils/file" + "ems.agt/src/framework/utils/ssh" + "ems.agt/src/framework/vo/result" + "ems.agt/src/modules/network_element/model" + neService "ems.agt/src/modules/network_element/service" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 UDMSubController 结构体 +var NewUDMSub = &UDMSubController{ + udmSubService: neService.NewUDMSubImpl, + neInfoService: neService.NewNeInfoImpl, +} + +// UDM签约用户请求 +// +// PATH /udm/sub +type UDMSubController struct { + // UDM鉴权信息服务 + udmSubService neService.IUDMSub + // 网元信息服务 + neInfoService neService.INeInfo +} + +// UDM签约用户-获取全部保存数据库 +// +// POST /resetData/:neId +func (s *UDMSubController) ResetData(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neId = "" + data := s.udmSubService.Save(neId) + c.JSON(200, result.OkData(data)) +} + +// UDM签约用户 +// +// GET /list +func (s *UDMSubController) List(c *gin.Context) { + querys := ctx.QueryMap(c) + querys["neId"] = "" + data := s.udmSubService.Page(querys) + c.JSON(200, result.Ok(data)) +} + +// UDM签约用户-信息 +// +// GET /:neId/:imsi +func (s *UDMSubController) Info(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + imsi := c.Param("imsi") + if neId == "" || imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + + // 发送MML + data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 解析返回的数据 + cnType, _ := strconv.ParseInt(data["CNType"][:4], 0, 64) + rat, _ := strconv.ParseInt(data["RAT"][:4], 0, 64) + msisdn := data["MSISDN"] + imsMsisdnLen := strings.Index(msisdn, ",") + if imsMsisdnLen != -1 { + msisdn = msisdn[:imsMsisdnLen] + } + userInfo := model.UDMSub{ + Imsi: imsi, + Msisdn: msisdn, + Ambr: data["AMBR"], + Arfb: data["AreaForbidden"], + Cn: fmt.Sprint(cnType), + SmData: data["SM-Data(snssai+dnn[1..n])"], + Sar: data["ServiceAreaRestriction"], + Nssai: data["NSSAI"], + SmfSel: data["Smf-Selection"], + Rat: fmt.Sprint(rat), + } + // 1,64,24,65,def_eps,1,2,010200000000,- + if v, ok := data["EPS-Data"]; ok { + userInfo.EpsDat = v + arr := strings.Split(v, ",") + userInfo.EpsFlag = arr[0] + userInfo.EpsOdb = arr[1] + userInfo.HplmnOdb = arr[2] + userInfo.Ard = arr[3] + userInfo.Epstpl = arr[4] + userInfo.ContextId = arr[5] + userInfo.ApnContext = arr[7] + userInfo.StaticIp = arr[8] + } + + // 查询数据库是否存在并存入更新 + neId = "" + list := s.udmSubService.List(model.UDMSub{NeID: neId, Imsi: imsi}) + if len(list) > 0 { + listItme := list[0] + userInfo.ID = listItme.ID + s.udmSubService.Update(neId, userInfo) + } else { + s.udmSubService.Insert(neId, userInfo) + } + c.JSON(200, result.OkData(userInfo)) +} + +// UDM签约用户-增加 +// +// POST /:neId +func (s *UDMSubController) Add(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + var body model.UDMSub + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.Imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", + body.Imsi, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) + // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 + if body.StaticIp != "" { + msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmSubService.Insert(neId, body) + } + c.JSON(200, result.OkData(data)) +} + +// UDM签约用户-批量添加 +// +// POST /:neId/:num +func (s *UDMSubController) Adds(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + num := c.Param("num") + if neId == "" || num == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + var body model.UDMSub + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.Imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("bad udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", + body.Imsi, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) + // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 + if body.StaticIp != "" { + msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmSubService.Inserts(neId, body, num) + } + c.JSON(200, result.OkData(data)) +} + +// UDM签约用户-修改 +// +// PUT /:neId +func (s *UDMSubController) Edit(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + var body model.UDMSub + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.Imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("mod udmuser:imsi=%s", body.Imsi) + // 修改的参数名称 + if body.Msisdn != "" { + msg += fmt.Sprintf(",msisdn=%s", body.Msisdn) + } + if body.Ambr != "" { + msg += fmt.Sprintf(",ambr=%s", body.Ambr) + } + if body.Nssai != "" { + msg += fmt.Sprintf(",nssai=%s", body.Nssai) + } + if body.Arfb != "" { + msg += fmt.Sprintf(",arfb=%s", body.Arfb) + } + if body.Sar != "" { + msg += fmt.Sprintf(",sar=%s", body.Sar) + } + if body.Rat != "" { + msg += fmt.Sprintf(",rat=%s", body.Rat) + } + if body.Cn != "" { + msg += fmt.Sprintf(",cn=%s", body.Cn) + } + if body.SmfSel != "" { + msg += fmt.Sprintf(",smf_sel=%s", body.SmfSel) + } + if body.SmData != "" { + msg += fmt.Sprintf(",sm_data=%s", body.SmData) + } + if body.EpsDat != "" { + msg += fmt.Sprintf(",eps_dat=%s", body.EpsDat) + } + if body.EpsFlag != "" { + msg += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) + } + if body.EpsOdb != "" { + msg += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) + } + if body.HplmnOdb != "" { + msg += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) + } + if body.Epstpl != "" { + msg += fmt.Sprintf(",epstpl=%s", body.Epstpl) + } + if body.Ard != "" { + msg += fmt.Sprintf(",ard=%s", body.Ard) + } + if body.ContextId != "" { + msg += fmt.Sprintf(",context_id=%s", body.ContextId) + } + if body.ApnContext != "" { + msg += fmt.Sprintf(",apn_context=%s", body.ApnContext) + } + if body.StaticIp != "" { + msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmSubService.Update(neId, body) + } + c.JSON(200, result.OkData(data)) +} + +// UDM签约用户-删除 +// +// DELETE /:neId/:imsi +func (s *UDMSubController) Remove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + imsi := c.Param("imsi") + if neId == "" || imsi == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("del udmuser:imsi=%s", imsi) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmSubService.Delete(neId, imsi) + } + c.JSON(200, result.OkData(data)) +} + +// UDM签约用户-批量删除 +// +// DELETE /:neId/:imsi/:num +func (s *UDMSubController) Removes(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.Param("neId") + imsi := c.Param("imsi") + num := c.Param("num") + if neId == "" || imsi == "" || num == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + msg := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + s.udmSubService.Deletes(neId, imsi, num) + } + c.JSON(200, result.OkData(data)) +} + +// UDM签约用户-导出 +// +// POST /export +func (s *UDMSubController) Export(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body struct { + NeId string `json:"neId" binding:"required"` + Type string `json:"type" binding:"required"` + } + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + if !(body.Type == "csv" || body.Type == "txt") { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportFileFormat"))) + return + } + + neId := "" + list := s.udmSubService.List(model.UDMSub{NeID: neId}) + // 文件名 + fileName := fmt.Sprintf("OMC_SUB_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) + filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName) + + if body.Type == "csv" { + // 转换数据 + data := [][]string{} + data = append(data, []string{"imsi", "msisdn", "ambr", "nssai", "arfb", "sar", "rat", "cn", "smf_sel", "sm_dat", "eps_dat"}) + for _, v := range list { + epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) + data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) + } + // 输出到文件 + err = file.WriterCSVFile(data, filePath) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + } + + if body.Type == "txt" { + // 转换数据 + data := [][]string{} + for _, v := range list { + epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) + data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) + } + // 输出到文件 + err = file.WriterTxtFile(data, filePath) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + } + + c.FileAttachment(filePath, fileName) +} + +// UDM签约用户-导入 +// +// POST /import +func (s *UDMSubController) Import(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neId := c.PostForm("neId") + if neId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + formFile, err := c.FormFile("file") + if err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 获取文件名 + if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat"))) + return + } + // 上传文件转存 + upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.OkData(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 本地文件 + localPath := file.ParseUploadFilePath(upFilePath) + nePath := config.Get("mml.upload").(string) + // 复制到远程 + err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + fileName := localPath[strings.LastIndex(localPath, "/")+1:] + msg := fmt.Sprintf("import udmuser:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) + + // 发送MML + data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + if strings.HasSuffix(fileName, ".csv") { + data := file.ReadCSVFile(localPath) + neId = "" + go s.udmSubService.InsertCSV(neId, data) + } + if strings.HasSuffix(fileName, ".txt") { + data := file.ReadTxtFile(localPath) + neId = "" + go s.udmSubService.InsertTxt(neId, data) + } + } + c.JSON(200, result.OkMsg(data)) +} diff --git a/src/modules/network_element/model/ne_info.go b/src/modules/network_element/model/ne_info.go new file mode 100644 index 0000000..941e7a0 --- /dev/null +++ b/src/modules/network_element/model/ne_info.go @@ -0,0 +1,19 @@ +package model + +// NeInfo 网元信息对象 ne_info +type NeInfo struct { + ID int64 `json:"id"` + NeType string `json:"neType"` + NeId string `json:"neId"` + RmUID string `json:"rmUid"` + NeName string `json:"neName"` + IP string `json:"ip"` + Port int64 `json:"port"` + PvFlag string `json:"pvFlag"` // enum('PNF','VNF') + Province string `json:"province"` + VendorName string `json:"vendorName"` + Dn string `json:"dn"` + NeAddress string `json:"neAddress"` + Status string `json:"status"` // 0: 在线 1: 下线 2: 备用 3: 工程 + UpdateTime string `json:"updateTime"` +} diff --git a/src/modules/network_element/model/udm_auth.go b/src/modules/network_element/model/udm_auth.go new file mode 100644 index 0000000..2fe70e2 --- /dev/null +++ b/src/modules/network_element/model/udm_auth.go @@ -0,0 +1,17 @@ +package model + +// UDMAuth UDM鉴权用户对象 u_auth_user +type UDMAuth struct { + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + Amf string `json:"amf" gorm:"column:amf"` // ANF + Status string `json:"status" gorm:"column:status"` // 状态 + Ki string `json:"ki" gorm:"column:ki"` // ki + AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex + Opc string `json:"opc" gorm:"column:opc"` + NeID string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 +} + +func (UDMAuth) TableName() string { + return "u_auth_user" +} diff --git a/src/modules/network_element/model/udm_sub.go b/src/modules/network_element/model/udm_sub.go new file mode 100644 index 0000000..1aa345c --- /dev/null +++ b/src/modules/network_element/model/udm_sub.go @@ -0,0 +1,33 @@ +package model + +// UDMSub UDM签约用户对象 u_sub_user +type UDMSub struct { + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + Msisdn string `json:"msisdn" gorm:"column:msisdn"` // 相当手机号 + Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + Ambr string `json:"ambr" gorm:"column:ambr"` + Nssai string `json:"nssai" gorm:"column:nssai"` + Rat string `json:"rat" gorm:"column:rat"` + Arfb string `json:"arfb" gorm:"column:arfb"` + Sar string `json:"sar" gorm:"column:sar"` + Cn string `json:"cn" gorm:"column:cn"` + SmData string `json:"smData" gorm:"column:sm_data"` + SmfSel string `json:"smfSel" gorm:"column:smf_sel"` + EpsDat string `json:"epsDat" gorm:"column:eps_dat"` + NeID string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 + + EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"` + EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"` + HplmnOdb string `json:"hplmnOdb" gorm:"column:hplmn_odb"` + Ard string `json:"ard" gorm:"column:ard"` + Epstpl string `json:"epstpl" gorm:"column:epstpl"` + ContextId string `json:"contextId" gorm:"column:context_id"` + ApnContext string `json:"apnContext" gorm:"column:apn_context"` + StaticIp string `json:"staticIp" gorm:"column:static_ip"` + + SubNum string `json:"subNum,omitempty" gorm:"-"` // 批量数 +} + +func (UDMSub) TableName() string { + return "u_sub_user" +} diff --git a/src/modules/network_element/network_element.go b/src/modules/network_element/network_element.go new file mode 100644 index 0000000..de36190 --- /dev/null +++ b/src/modules/network_element/network_element.go @@ -0,0 +1,133 @@ +package networkelement + +import ( + "ems.agt/src/framework/logger" + "ems.agt/src/framework/middleware" + "ems.agt/src/framework/middleware/collectlogs" + "ems.agt/src/framework/middleware/repeat" + "ems.agt/src/modules/network_element/controller" + + "github.com/gin-gonic/gin" +) + +// 模块路由注册 +func Setup(router *gin.Engine) { + logger.Infof("开始加载 ====> network_element 模块路由") + + neGroup := router.Group("/ne") + { + neGroup.GET("/info", + middleware.PreAuthorize(nil), + controller.NewNeInfo.NeTypeAndID, + ) + } + + // UDM鉴权用户信息 + udmAuthGroup := neGroup.Group("/udm/auth") + { + udmAuthGroup.PUT("/resetData/:neId", + repeat.RepeatSubmit(5), + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)), + controller.NewUDMAuth.ResetData, + ) + udmAuthGroup.GET("/list", + middleware.PreAuthorize(nil), + controller.NewUDMAuth.List, + ) + udmAuthGroup.GET("/:neId/:imsi", + middleware.PreAuthorize(nil), + controller.NewUDMAuth.Info, + ) + udmAuthGroup.POST("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMAuth.Add, + ) + udmAuthGroup.POST("/:neId/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMAuth.Adds, + ) + udmAuthGroup.PUT("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewUDMAuth.Edit, + ) + udmAuthGroup.DELETE("/:neId/:imsi", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMAuth.Remove, + ) + udmAuthGroup.DELETE("/:neId/:imsi/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMAuth.Removes, + ) + udmAuthGroup.POST("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewUDMAuth.Export, + ) + udmAuthGroup.POST("/import", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewUDMAuth.Import, + ) + } + + // UDM签约用户信息 + udmSubGroup := neGroup.Group("/udm/sub") + { + udmSubGroup.PUT("/resetData/:neId", + repeat.RepeatSubmit(5), + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)), + controller.NewUDMSub.ResetData, + ) + udmSubGroup.GET("/list", + middleware.PreAuthorize(nil), + controller.NewUDMSub.List, + ) + udmSubGroup.GET("/:neId/:imsi", + middleware.PreAuthorize(nil), + controller.NewUDMSub.Info, + ) + udmSubGroup.POST("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMSub.Add, + ) + udmSubGroup.POST("/:neId/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMSub.Adds, + ) + udmSubGroup.PUT("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewUDMSub.Edit, + ) + udmSubGroup.DELETE("/:neId/:imsi", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMSub.Remove, + ) + udmSubGroup.DELETE("/:neId/:imsi/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMSub.Removes, + ) + udmSubGroup.POST("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewUDMSub.Export, + ) + udmSubGroup.POST("/import", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewUDMSub.Import, + ) + } + +} diff --git a/src/modules/network_element/repository/ne_info.go b/src/modules/network_element/repository/ne_info.go new file mode 100644 index 0000000..1f4adcd --- /dev/null +++ b/src/modules/network_element/repository/ne_info.go @@ -0,0 +1,11 @@ +package repository + +import ( + "ems.agt/src/modules/network_element/model" +) + +// 网元信息 数据层接口 +type INeInfo interface { + // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 + SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo +} diff --git a/src/modules/network_element/repository/ne_info.impl.go b/src/modules/network_element/repository/ne_info.impl.go new file mode 100644 index 0000000..f3615bd --- /dev/null +++ b/src/modules/network_element/repository/ne_info.impl.go @@ -0,0 +1,69 @@ +package repository + +import ( + "ems.agt/src/framework/datasource" + "ems.agt/src/framework/logger" + "ems.agt/src/framework/utils/repo" + "ems.agt/src/modules/network_element/model" +) + +// 实例化数据层 NeInfoImpl 结构体 +var NewNeInfoImpl = &NeInfoImpl{ + selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time from ne_info`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_id": "NeId", + "rm_uid": "RmUID", + "ne_name": "NeName", + "ip": "IP", + "port": "Port", + "pv_flag": "PvFlag", + "province": "Province", + "vendor_name": "VendorName", + "dn": "Dn", + "ne_address": "NeAddress", + "status": "Status", + "update_time": "UpdateTime", + }, +} + +// NeInfoImpl 网元信息表 数据层处理 +type NeInfoImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *NeInfoImpl) convertResultRows(rows []map[string]any) []model.NeInfo { + arr := make([]model.NeInfo, 0) + for _, row := range rows { + item := model.NeInfo{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 +func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo { + querySql := r.selectSql + " where ne_type = ? and ne_id = ?" + results, err := datasource.RawDB("", querySql, []any{neType, neID}) + if err != nil { + logger.Errorf("query err => %v", err) + return model.NeInfo{} + } + // 转换实体 + rows := r.convertResultRows(results) + if len(rows) > 0 { + return rows[0] + } + return model.NeInfo{} +} diff --git a/src/modules/network_element/repository/udm_auth.go b/src/modules/network_element/repository/udm_auth.go new file mode 100644 index 0000000..d131964 --- /dev/null +++ b/src/modules/network_element/repository/udm_auth.go @@ -0,0 +1,26 @@ +package repository + +import ( + "ems.agt/src/modules/network_element/model" +) + +// UDM鉴权信息 数据层接口 +type IUDMAuth interface { + // ClearAndInsert 清空ne_id后新增实体 + ClearAndInsert(neID string, authArr []model.UDMAuth) int64 + + // SelectPage 根据条件分页查询 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(auth model.UDMAuth) []model.UDMAuth + + // Insert 批量添加 + Inserts(authUsers []model.UDMAuth) int64 + + // Delete 删除实体 + Delete(neID, imsi string) int64 + + // DeletePrefixImsi 删除前缀匹配的实体 + DeletePrefixImsi(neID, imsi string) int64 +} diff --git a/src/modules/network_element/repository/udm_auth.impl.go b/src/modules/network_element/repository/udm_auth.impl.go new file mode 100644 index 0000000..5971773 --- /dev/null +++ b/src/modules/network_element/repository/udm_auth.impl.go @@ -0,0 +1,191 @@ +package repository + +import ( + "strings" + + "ems.agt/src/framework/datasource" + "ems.agt/src/framework/logger" + "ems.agt/src/framework/utils/parse" + "ems.agt/src/framework/utils/repo" + "ems.agt/src/modules/network_element/model" +) + +// 实例化数据层 UDMAuthImpl 结构体 +var NewUDMAuthImpl = &UDMAuthImpl{ + selectSql: `select id, imsi, amf, status, ki, algo_index, opc, ne_id from u_auth_user`, + + resultMap: map[string]string{ + "id": "ID", + "imsi": "Imsi", + "amf": "Amf", + "status": "Status", + "ki": "Ki", + "algo_index": "AlgoIndex", + "opc": "Opc", + "ne_id": "NeID", + }, +} + +// UDMAuthImpl UDM鉴权信息表 数据层处理 +type UDMAuthImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *UDMAuthImpl) convertResultRows(rows []map[string]any) []model.UDMAuth { + arr := make([]model.UDMAuth, 0) + for _, row := range rows { + item := model.UDMAuth{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// ClearAndInsert 清空ne_id后新增实体 +func (r *UDMAuthImpl) ClearAndInsert(neID string, authArr []model.UDMAuth) int64 { + // 清空指定ne_id + _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) + if err != nil { + logger.Errorf("TRUNCATE err => %v", err) + } + + return r.Inserts(authArr) +} + +// SelectPage 根据条件分页查询 +func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if v, ok := query["imsi"]; ok && v != "" { + conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") + params = append(params, v) + } + if v, ok := query["neId"]; ok && v != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, v) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.UDMAuth{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from u_auth_user" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 排序 + sortSql := "" + if v, ok := query["sortField"]; ok && v != "" { + if v == "imsi" { + sortSql += " order by imsi " + } + if o, ok := query["sortOrder"]; ok && o != nil && v != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + } + + // 查询数据 + querySql := r.selectSql + whereSql + sortSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectList 根据实体查询 +func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth { + // 查询条件拼接 + var conditions []string + var params []any + if auth.Imsi != "" { + conditions = append(conditions, "imsi = ?") + params = append(params, auth.Imsi) + } + if auth.NeID != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, auth.NeID) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + " order by imsi asc " + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 批量添加 +func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 { + tx := datasource.DefaultDB().CreateInBatches(authUsers, 3000) + if err := tx.Error; err != nil { + logger.Errorf("CreateInBatches err => %v", err) + } + return tx.RowsAffected +} + +// Delete 删除实体 +func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) + if err := tx.Error; err != nil { + logger.Errorf("Delete err => %v", err) + } + return tx.RowsAffected +} + +// DeletePrefixImsi 删除前缀匹配的实体 +func (r *UDMAuthImpl) DeletePrefixImsi(neID, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) + if err := tx.Error; err != nil { + logger.Errorf("DeletePrefixImsi err => %v", err) + } + return tx.RowsAffected +} diff --git a/src/modules/network_element/repository/udm_sub.go b/src/modules/network_element/repository/udm_sub.go new file mode 100644 index 0000000..f2d202c --- /dev/null +++ b/src/modules/network_element/repository/udm_sub.go @@ -0,0 +1,35 @@ +package repository + +import ( + "ems.agt/src/modules/network_element/model" +) + +// UDM签约信息 数据层接口 +type IUDMSub interface { + // ClearAndInsert 清空ne_id后新增实体 + ClearAndInsert(neID string, subArr []model.UDMSub) int64 + + // SelectPage 根据条件分页查询字典类型 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(subUser model.UDMSub) []model.UDMSub + + // Insert 新增实体 + Insert(subUser model.UDMSub) string + + // Insert 批量添加 + Inserts(subUser []model.UDMSub) int64 + + // Update 修改更新 + Update(neID string, subUser model.UDMSub) int64 + + // Delete 删除实体 + Delete(neID, imsi string) int64 + + // DeletePrefixImsi 删除前缀匹配的实体 + DeletePrefixImsi(neID, imsi string) int64 + + // Delete 删除范围实体 + Deletes(neID, imsi, num string) int64 +} diff --git a/src/modules/network_element/repository/udm_sub.impl.go b/src/modules/network_element/repository/udm_sub.impl.go new file mode 100644 index 0000000..22f6011 --- /dev/null +++ b/src/modules/network_element/repository/udm_sub.impl.go @@ -0,0 +1,312 @@ +package repository + +import ( + "strconv" + "strings" + + "ems.agt/src/framework/datasource" + "ems.agt/src/framework/logger" + "ems.agt/src/framework/utils/parse" + "ems.agt/src/framework/utils/repo" + "ems.agt/src/modules/network_element/model" +) + +// 实例化数据层 UDMSubImpl 结构体 +var NewUDMSubImpl = &UDMSubImpl{ + selectSql: `select + id, msisdn, imsi, ambr, nssai, rat, arfb, sar, cn, sm_data, smf_sel, eps_dat, ne_id, eps_flag, eps_odb, hplmn_odb, ard, epstpl, context_id, apn_context, static_ip + from u_sub_user`, + + resultMap: map[string]string{ + "id": "ID", + "msisdn": "Msisdn", + "imsi": "Imsi", + "ambr": "Ambr", + "nssai": "Nssai", + "rat": "Rat", + "arfb": "Arfb", + "sar": "Sar", + "cn": "Cn", + "sm_data": "SmData", + "smf_sel": "SmfSel", + "eps_dat": "EpsDat", + "ne_id": "NeID", + "eps_flag": "EpsFlag", + "eps_odb": "EpsOdb", + "hplmn_odb": "HplmnOdb", + "ard": "Ard", + "epstpl": "Epstpl", + "context_id": "ContextId", + "apn_context": "ApnContext", + "static_ip": "StaticIp", + }, +} + +// UDMSubImpl UDM签约信息表 数据层处理 +type UDMSubImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *UDMSubImpl) convertResultRows(rows []map[string]any) []model.UDMSub { + arr := make([]model.UDMSub, 0) + for _, row := range rows { + item := model.UDMSub{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// ClearAndInsert 清空ne_id后新增实体 +func (r *UDMSubImpl) ClearAndInsert(neID string, subArr []model.UDMSub) int64 { + // 清空指定ne_id + _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) + if err != nil { + logger.Errorf("TRUNCATE err => %v", err) + } + + return r.Inserts(subArr) +} + +// SelectPage 根据条件分页查询字典类型 +func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if v, ok := query["msisdn"]; ok && v != "" { + conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')") + params = append(params, v) + } + if v, ok := query["imsi"]; ok && v != "" { + conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") + params = append(params, v) + } + if v, ok := query["neId"]; ok && v != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, v) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.UDMSub{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from u_sub_user" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 排序 + sortSql := "" + if v, ok := query["sortField"]; ok && v != "" { + if v == "imsi" { + sortSql += " order by imsi " + } + if v == "msisdn" { + sortSql += " order by msisdn " + } + if o, ok := query["sortOrder"]; ok && o != nil && v != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + } + + // 查询数据 + querySql := r.selectSql + whereSql + sortSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + return result + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectList 根据实体查询 +func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub { + // 查询条件拼接 + var conditions []string + var params []any + if subUser.Imsi != "" { + conditions = append(conditions, "imsi = ?") + params = append(params, subUser.Imsi) + } + if subUser.NeID != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, subUser.NeID) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + " order by imsi asc " + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 新增实体 +func (r *UDMSubImpl) Insert(subUser model.UDMSub) string { + err := datasource.DefaultDB().Create(&subUser).Error + if err != nil { + logger.Errorf("Create err => %v", err) + } + return subUser.ID +} + +// Insert 批量添加 +func (r *UDMSubImpl) Inserts(subUser []model.UDMSub) int64 { + tx := datasource.DefaultDB().CreateInBatches(subUser, 2000) + if err := tx.Error; err != nil { + logger.Errorf("CreateInBatches err => %v", err) + } + return tx.RowsAffected +} + +// Update 修改更新 +func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 { + // 查询先 + var user model.UDMSub + err := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).First(&user).Error + if err != nil { + logger.Errorf("Update First err => %v", err) + } + + if user.Msisdn != subUser.Msisdn { + user.Msisdn = subUser.Msisdn + } + if user.Ambr != subUser.Ambr { + user.Ambr = subUser.Ambr + } + if user.Arfb != subUser.Arfb { + user.Arfb = subUser.Arfb + } + if user.Sar != subUser.Sar { + user.Sar = subUser.Sar + } + if user.Rat != subUser.Rat { + user.Rat = subUser.Rat + } + if user.Cn != subUser.Cn { + user.Cn = subUser.Cn + } + if user.SmfSel != subUser.SmfSel { + user.SmfSel = subUser.SmfSel + } + if user.SmData != subUser.SmData { + user.SmData = subUser.SmData + } + if user.EpsDat != subUser.EpsDat { + user.EpsDat = subUser.EpsDat + } + if user.EpsFlag != subUser.EpsFlag { + user.EpsFlag = subUser.EpsFlag + } + if user.EpsDat != subUser.EpsDat { + user.EpsOdb = subUser.EpsOdb + } + if user.HplmnOdb != subUser.HplmnOdb { + user.HplmnOdb = subUser.HplmnOdb + } + if user.Epstpl != subUser.Epstpl { + user.Epstpl = subUser.Epstpl + } + if user.Ard != subUser.Ard { + user.Ard = subUser.Ard + } + if user.ContextId != subUser.ContextId { + user.ContextId = subUser.ContextId + } + if user.ApnContext != subUser.ApnContext { + user.ApnContext = subUser.ApnContext + } + if user.StaticIp != subUser.StaticIp { + user.StaticIp = subUser.StaticIp + } + + tx := datasource.DefaultDB().Save(user) + if err := tx.Error; err != nil { + logger.Errorf("Update Save err => %v", err) + return 0 + } + return tx.RowsAffected +} + +// Delete 删除实体 +func (r *UDMSubImpl) Delete(neID, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) + if err := tx.Error; err != nil { + logger.Errorf("Delete err => %v", err) + } + return tx.RowsAffected +} + +// DeletePrefixImsi 删除前缀匹配的实体 +func (r *UDMSubImpl) DeletePrefixImsi(neID, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) + if err := tx.Error; err != nil { + logger.Errorf("DeletePrefixImsi err => %v", err) + } + return tx.RowsAffected +} + +// Delete 删除范围实体 +func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 { + imsiV, err := strconv.Atoi(imsi) + if err != nil { + return 0 + } + + numV, err := strconv.Atoi(num) + if err != nil { + return 0 + } + + tx := datasource.DefaultDB().Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete(&model.UDMSub{}) + if err := tx.Error; err != nil { + logger.Errorf("Deletes err => %v", err) + } + return tx.RowsAffected +} diff --git a/src/modules/network_element/service/ne_info.go b/src/modules/network_element/service/ne_info.go new file mode 100644 index 0000000..715892b --- /dev/null +++ b/src/modules/network_element/service/ne_info.go @@ -0,0 +1,9 @@ +package service + +import "ems.agt/src/modules/network_element/model" + +// 网元信息 服务层接口 +type INeInfo interface { + // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 + SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo +} diff --git a/src/modules/network_element/service/ne_info.impl.go b/src/modules/network_element/service/ne_info.impl.go new file mode 100644 index 0000000..bd5d41a --- /dev/null +++ b/src/modules/network_element/service/ne_info.impl.go @@ -0,0 +1,22 @@ +package service + +import ( + "ems.agt/src/modules/network_element/model" + "ems.agt/src/modules/network_element/repository" +) + +// 实例化服务层 NeInfoImpl 结构体 +var NewNeInfoImpl = &NeInfoImpl{ + NeInfoRepository: repository.NewNeInfoImpl, +} + +// 网元信息 服务层处理 +type NeInfoImpl struct { + // 网元信息数据信息 + NeInfoRepository repository.INeInfo +} + +// SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 +func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo { + return r.NeInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID) +} diff --git a/src/modules/network_element/service/udm_auth.go b/src/modules/network_element/service/udm_auth.go new file mode 100644 index 0000000..d2d3270 --- /dev/null +++ b/src/modules/network_element/service/udm_auth.go @@ -0,0 +1,37 @@ +package service + +import "ems.agt/src/modules/network_element/model" + +// UDM鉴权信息 服务层接口 +type IUDMAuth interface { + // Save UDM鉴权用户-获取redis全部保存数据库 + Save(neID string) int64 + + // Page UDM鉴权用户-分页查询数据库 + Page(query map[string]any) map[string]any + + // List UDM鉴权用户-查询数据库 + List(authUser model.UDMAuth) []model.UDMAuth + + // Insert UDM鉴权用户-新增单个 + // imsi长度15,ki长度32,opc长度0或者32 + Insert(neID string, authUser model.UDMAuth) int64 + + // Insert UDM鉴权用户-批量添加 + Inserts(neID string, authUser model.UDMAuth, num string) int64 + + // InsertCSV UDM鉴权用户-批量添加 + InsertCSV(neID string, data []map[string]string) int64 + + // InsertTxt UDM鉴权用户-批量添加 + InsertTxt(neID string, data [][]string) int64 + + // Insert UDM鉴权用户-修改更新 + Update(neID string, authUser model.UDMAuth) int64 + + // Insert UDM鉴权用户-删除单个 + Delete(neID, imsi string) int64 + + // Insert UDM鉴权用户-删除范围 + Deletes(neID, imsi, num string) int64 +} diff --git a/src/modules/network_element/service/udm_auth.impl.go b/src/modules/network_element/service/udm_auth.impl.go new file mode 100644 index 0000000..378200a --- /dev/null +++ b/src/modules/network_element/service/udm_auth.impl.go @@ -0,0 +1,177 @@ +package service + +import ( + "fmt" + "strings" + + "ems.agt/src/framework/redis" + "ems.agt/src/modules/network_element/model" + "ems.agt/src/modules/network_element/repository" +) + +// 实例化服务层 UDMAuthImpl 结构体 +var NewUDMAuthImpl = &UDMAuthImpl{ + udmAuthRepository: repository.NewUDMAuthImpl, +} + +// UDM鉴权信息 服务层处理 +type UDMAuthImpl struct { + // UDM鉴权信息数据信息 + udmAuthRepository repository.IUDMAuth +} + +// authDataByRedis UDM鉴权用户 +func (r *UDMAuthImpl) authDataByRedis(imsi, neID string) []model.UDMAuth { + arr := []model.UDMAuth{} + ausfArr, err := redis.GetKeys("udmuser", fmt.Sprintf("ausf:%s", imsi)) + if err != nil { + return arr + } + for _, key := range ausfArr { + m, err := redis.GetHash("udmuser", key) + if err != nil { + continue + } + + // 跳过-号数据 + imsi := key[5:] + if strings.Contains(imsi, "-") { + continue + } + + status := "0" + if _, ok := m["auth_success"]; ok { + status = "1" + } + amf := "" + if v, ok := m["amf"]; ok { + amf = strings.Replace(v, "\r\n", "", 1) + } + a := model.UDMAuth{ + Imsi: imsi, + Amf: amf, + Status: status, + Ki: m["ki"], + AlgoIndex: m["algo"], + Opc: m["opc"], + NeID: neID, + } + arr = append(arr, a) + } + return arr +} + +// Save UDM鉴权用户-获取redis全部保存数据库 +func (r *UDMAuthImpl) Save(neID string) int64 { + var num int64 = 0 + authArr := r.authDataByRedis("*", neID) + // 有数据才清空 + if len(authArr) == 0 { + return num + } + go r.udmAuthRepository.ClearAndInsert(neID, authArr) + return int64(len(authArr)) +} + +// Page UDM鉴权用户-分页查询数据库 +func (r *UDMAuthImpl) Page(query map[string]any) map[string]any { + return r.udmAuthRepository.SelectPage(query) +} + +// List UDM鉴权用户-查询数据库 +func (r *UDMAuthImpl) List(authUser model.UDMAuth) []model.UDMAuth { + return r.udmAuthRepository.SelectList(authUser) +} + +// Insert UDM鉴权用户-新增单个 +// imsi长度15,ki长度32,opc长度0或者32 +func (r *UDMAuthImpl) Insert(neID string, authUser model.UDMAuth) int64 { + authArr := r.authDataByRedis(authUser.Imsi, neID) + if len(authArr) > 0 { + r.udmAuthRepository.Delete(neID, authUser.Imsi) + r.udmAuthRepository.Inserts(authArr) + } + return 0 +} + +// Insert UDM鉴权用户-批量添加 +func (r *UDMAuthImpl) Inserts(neID string, authUser model.UDMAuth, num string) int64 { + startIMSI := authUser.Imsi + startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*" + // keys udm-sd:4600001000004* + authArr := r.authDataByRedis(startIMSI, neID) + if len(authArr) > 0 { + for _, v := range authArr { + r.udmAuthRepository.Delete(neID, v.Imsi) + } + return r.udmAuthRepository.Inserts(authArr) + } + return 0 +} + +// InsertCSV UDM鉴权用户-批量添加 +func (r *UDMAuthImpl) InsertCSV(neID string, data []map[string]string) int64 { + prefixes := make(map[string]struct{}) + for _, v := range data { + imsi := v["imsi"] + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + // 分组插入 + var num int64 = 0 + for prefix := range prefixes { + r.udmAuthRepository.DeletePrefixImsi(neID, prefix) + subArr := r.authDataByRedis(prefix+"*", neID) + if len(subArr) > 0 { + num += r.udmAuthRepository.Inserts(subArr) + } + } + return num +} + +// InsertTxt UDM鉴权用户-批量添加 +func (r *UDMAuthImpl) InsertTxt(neID string, data [][]string) int64 { + prefixes := make(map[string]struct{}) + for _, v := range data { + imsi := v[0] + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + // 分组插入 + var num int64 = 0 + for prefix := range prefixes { + r.udmAuthRepository.DeletePrefixImsi(neID, prefix) + subArr := r.authDataByRedis(prefix+"*", neID) + if len(subArr) > 0 { + num += r.udmAuthRepository.Inserts(subArr) + } + } + return num +} + +// Insert UDM鉴权用户-修改更新 +func (r *UDMAuthImpl) Update(neID string, authUser model.UDMAuth) int64 { + authArr := r.authDataByRedis(authUser.Imsi, neID) + if len(authArr) > 0 { + r.udmAuthRepository.Delete(neID, authUser.Imsi) + return r.udmAuthRepository.Inserts(authArr) + } + return 0 +} + +// Insert UDM鉴权用户-删除单个 +func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { + return r.udmAuthRepository.Delete(neID, imsi) +} + +// Insert UDM鉴权用户-删除范围 +func (r *UDMAuthImpl) Deletes(neID, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)] + // keys udm-sd:4600001000004* + authArr := r.authDataByRedis(prefix+"*", neID) + if len(authArr) > 0 { + r.udmAuthRepository.DeletePrefixImsi(neID, prefix) + return r.udmAuthRepository.Inserts(authArr) + } + return 0 +} diff --git a/src/modules/network_element/service/udm_sub.go b/src/modules/network_element/service/udm_sub.go new file mode 100644 index 0000000..7da470a --- /dev/null +++ b/src/modules/network_element/service/udm_sub.go @@ -0,0 +1,37 @@ +package service + +import "ems.agt/src/modules/network_element/model" + +// UDM签约用户信息 服务层接口 +type IUDMSub interface { + // Save UDM签约用户-获取redis全部保存数据库 + Save(neID string) int64 + + // Page UDM签约用户-分页查询数据库 + Page(query map[string]any) map[string]any + + // List UDM签约用户-查询数据库 + List(subUser model.UDMSub) []model.UDMSub + + // Insert UDM签约用户-新增单个 + // imsi长度15,ki长度32,opc长度0或者32 + Insert(neID string, subUser model.UDMSub) int64 + + // Insert UDM签约用户-批量添加 + Inserts(neID string, subUser model.UDMSub, num string) int64 + + // InsertCSV UDM签约用户-批量添加 + InsertCSV(neID string, data []map[string]string) int64 + + // InsertTxt UDM签约用户-批量添加 + InsertTxt(neID string, data [][]string) int64 + + // Insert UDM签约用户-修改更新 + Update(neID string, subUser model.UDMSub) int64 + + // Insert UDM签约用户-删除单个 + Delete(neID, imsi string) int64 + + // Insert UDM签约用户-删除范围 + Deletes(neID, imsi, num string) int64 +} diff --git a/src/modules/network_element/service/udm_sub.impl.go b/src/modules/network_element/service/udm_sub.impl.go new file mode 100644 index 0000000..e730e01 --- /dev/null +++ b/src/modules/network_element/service/udm_sub.impl.go @@ -0,0 +1,191 @@ +package service + +import ( + "fmt" + "strings" + + "ems.agt/src/framework/redis" + "ems.agt/src/modules/network_element/model" + "ems.agt/src/modules/network_element/repository" +) + +// 实例化服务层 UDMSubImpl 结构体 +var NewUDMSubImpl = &UDMSubImpl{ + udmSubRepository: repository.NewUDMSubImpl, +} + +// UDM签约信息 服务层处理 +type UDMSubImpl struct { + // UDM签约信息数据信息 + udmSubRepository repository.IUDMSub +} + +// subDataByRedis UDM签约用户 +func (r *UDMSubImpl) subDataByRedis(imsi, neID string) []model.UDMSub { + arr := []model.UDMSub{} + udmsdArr, err := redis.GetKeys("udmuser", fmt.Sprintf("udm-sd:%s", imsi)) + if err != nil { + return arr + } + for _, key := range udmsdArr { + m, err := redis.GetHash("udmuser", key) + if err != nil { + continue + } + + a := model.UDMSub{ + Imsi: key[7:], + Msisdn: m["gpsi"], // 46003550072 strings.TrimPrefix(m["gpsi"], "86"), + SmfSel: m["smf-sel"], + SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet + NeID: neID, + } + + // def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,- + if v, ok := m["am-dat"]; ok { + arr := strings.Split(v, ",") + a.Ambr = arr[0] + a.Nssai = arr[1] + a.Rat = arr[2] + a.Arfb = arr[3] + a.Sar = arr[4] + a.Cn = arr[5] + } + // 1,64,24,65,def_eps,1,2,010200000000,- + if v, ok := m["eps-dat"]; ok { + arr := strings.Split(v, ",") + // 跳过非常规数据 + if len(arr) > 9 { + continue + } + a.EpsDat = v + a.EpsFlag = arr[0] + a.EpsOdb = arr[1] + a.HplmnOdb = arr[2] + a.Ard = arr[3] + a.Epstpl = arr[4] + a.ContextId = arr[5] + a.ApnContext = arr[7] + // [6] 是不要的,导入和导出不用 + a.StaticIp = arr[8] + } + + arr = append(arr, a) + } + return arr +} + +// Save UDM签约用户-获取redis全部保存数据库 +func (r *UDMSubImpl) Save(neID string) int64 { + var num int64 = 0 + subArr := r.subDataByRedis("*", neID) + // 有数据才清空 + if len(subArr) == 0 { + return num + } + go r.udmSubRepository.ClearAndInsert(neID, subArr) + return int64(len(subArr)) +} + +// Page UDM签约用户-分页查询数据库 +func (r *UDMSubImpl) Page(query map[string]any) map[string]any { + return r.udmSubRepository.SelectPage(query) +} + +// List UDM签约用户-查询数据库 +func (r *UDMSubImpl) List(subUser model.UDMSub) []model.UDMSub { + return r.udmSubRepository.SelectList(subUser) +} + +// Insert UDM签约用户-新增单个 +// imsi长度15,ki长度32,opc长度0或者32 +func (r *UDMSubImpl) Insert(neID string, subUser model.UDMSub) int64 { + authArr := r.subDataByRedis(subUser.Imsi, neID) + if len(authArr) > 0 { + r.udmSubRepository.Delete(neID, subUser.Imsi) + r.udmSubRepository.Inserts(authArr) + } + return 0 +} + +// Insert UDM签约用户-批量添加 +func (r *UDMSubImpl) Inserts(neID string, subUser model.UDMSub, num string) int64 { + startIMSI := subUser.Imsi + startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*" + // keys udm-sd:4600001000004* + subArr := r.subDataByRedis(startIMSI, neID) + if len(subArr) > 0 { + for _, v := range subArr { + r.udmSubRepository.Delete(neID, v.Imsi) + } + return r.udmSubRepository.Inserts(subArr) + } + return 0 +} + +// InsertCSV UDM签约用户-批量添加 +func (r *UDMSubImpl) InsertCSV(neID string, data []map[string]string) int64 { + prefixes := make(map[string]struct{}) + for _, v := range data { + imsi := v["imsi"] + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + // 分组插入 + var num int64 = 0 + for prefix := range prefixes { + r.udmSubRepository.DeletePrefixImsi(neID, prefix) + subArr := r.subDataByRedis(prefix+"*", neID) + if len(subArr) > 0 { + num += r.udmSubRepository.Inserts(subArr) + } + } + return num +} + +// InsertTxt UDM签约用户-批量添加 +func (r *UDMSubImpl) InsertTxt(neID string, data [][]string) int64 { + prefixes := make(map[string]struct{}) + for _, v := range data { + imsi := v[0] + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + // 分组插入 + var num int64 = 0 + for prefix := range prefixes { + r.udmSubRepository.DeletePrefixImsi(neID, prefix) + subArr := r.subDataByRedis(prefix+"*", neID) + if len(subArr) > 0 { + num += r.udmSubRepository.Inserts(subArr) + } + } + return num +} + +// Insert UDM签约用户-修改更新 +func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 { + authArr := r.subDataByRedis(subUser.Imsi, neID) + if len(authArr) > 0 { + r.udmSubRepository.Delete(neID, subUser.Imsi) + return r.udmSubRepository.Inserts(authArr) + } + return 0 +} + +// Insert UDM签约用户-删除单个 +func (r *UDMSubImpl) Delete(neID, imsi string) int64 { + return r.udmSubRepository.Delete(neID, imsi) +} + +// Insert UDM签约用户-删除范围 +func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)] + // keys udm-sd:4600001000004* + authArr := r.subDataByRedis(prefix+"*", neID) + if len(authArr) > 0 { + r.udmSubRepository.DeletePrefixImsi(neID, prefix) + return r.udmSubRepository.Inserts(authArr) + } + return 0 +}