diff --git a/src/modules/network_data/controller/udm_auth.go b/src/modules/network_data/controller/udm_auth.go new file mode 100644 index 00000000..e19888a9 --- /dev/null +++ b/src/modules/network_data/controller/udm_auth.go @@ -0,0 +1,522 @@ +package controller + +import ( + "fmt" + "path/filepath" + "strings" + "time" + + "be.ems/src/framework/constants/uploadsubpath" + "be.ems/src/framework/i18n" + "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/file" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/utils/telnet" + "be.ems/src/framework/vo/result" + "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 UDMAuthController 结构体 +var NewUDMAuth = &UDMAuthController{ + udmAuthService: neDataService.NewUDMAuthImpl, + neInfoService: neService.NewNeInfoImpl, +} + +// UDM鉴权用户 +// +// PATH /udm/auth +type UDMAuthController struct { + // UDM鉴权信息服务 + udmAuthService neDataService.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.ResetData(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.SelectPage(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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + data, err := telnet.ConvertToMap(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + if len(data) == 0 { + c.JSON(200, result.ErrMsg("No Auth Data")) + return + } + + neId = "" + u := model.UDMAuth{ + IMSI: imsi, + Amf: data["amf"], + Status: "1", + Ki: data["ki"], + AlgoIndex: data["algo"], + Opc: data["opc"], + NeId: neId, + } + + // 查询imsi存在赋予id用于更新 + list := s.udmAuthService.SelectList(u) + if len(list) > 0 { + item := list[0] + if item.ID != "" { + u.ID = item.ID + } + } + go s.udmAuthService.Insert(neId, u) + + c.JSON(200, result.OkData(u)) +} + +// 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("baa 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) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmAuthService.LoadData(neId, body.IMSI, 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("mod authdata:imsi=%s", body.IMSI) + // 修改的参数名称 + if body.Ki != "" { + cmd += fmt.Sprintf(",ki=%s", body.Ki) + } + if body.Amf != "" { + cmd += fmt.Sprintf(",amf=%s", body.Amf) + } + if body.AlgoIndex != "" { + cmd += fmt.Sprintf(",algo=%s", body.AlgoIndex) + } + if body.Opc != "" { + cmd += fmt.Sprintf(",opc=%s", body.Opc) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmAuthService.Insert(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 + } + + // 处理字符转id数组后去重 + imsiArr := strings.Split(imsi, ",") + uniqueIDs := parse.RemoveDuplicates(imsiArr) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + resultData := map[string]string{} + for _, imsi := range uniqueIDs { + // 发送MML + cmd := fmt.Sprintf("del authdat:imsi=%s", imsi) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + resultData[imsi] = err.Error() + continue + } + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmAuthService.Delete(neId, imsi) + } + resultData[imsi] = data + } + + c.JSON(200, result.OkData(resultData)) +} + +// 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmAuthService.LoadData(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.errExportType"))) + return + } + + neId := "" + list := s.udmAuthService.SelectList(model.UDMAuth{NeId: neId}) + // 文件名 + fileName := fmt.Sprintf("udm_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.WriterFileCSV(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.WriterFileTXT(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) + var body struct { + NeId string `json:"neId" binding:"required"` + UploadPath string `json:"uploadPath" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 判断文件名 + if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() + + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg("error uploading file")) + return + } + + // 网元主机的Telnet客户端 + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("import authdat:path=%s", neFilePath) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + if strings.HasSuffix(body.UploadPath, ".csv") { + data := file.ReadFileCSV(localFilePath) + neId := "" + go s.udmAuthService.InsertData(neId, "csv", data) + } + if strings.HasSuffix(body.UploadPath, ".txt") { + data := file.ReadFileTXT(",", localFilePath) + neId := "" + go s.udmAuthService.InsertData(neId, "txt", data) + } + } + c.JSON(200, result.OkMsg(data)) +} diff --git a/src/modules/network_data/controller/udm_sub.go b/src/modules/network_data/controller/udm_sub.go new file mode 100644 index 00000000..62f57ac6 --- /dev/null +++ b/src/modules/network_data/controller/udm_sub.go @@ -0,0 +1,603 @@ +package controller + +import ( + "fmt" + "path/filepath" + "strconv" + "strings" + "time" + + "be.ems/src/framework/constants/uploadsubpath" + "be.ems/src/framework/i18n" + "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/file" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/utils/telnet" + "be.ems/src/framework/vo/result" + "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" + neService "be.ems/src/modules/network_element/service" + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 UDMSubController 结构体 +var NewUDMSub = &UDMSubController{ + udmSubService: neDataService.NewUDMSubImpl, + neInfoService: neService.NewNeInfoImpl, +} + +// UDM签约用户 +// +// PATH /udm/sub +type UDMSubController struct { + // UDM签约信息服务 + udmSubService neDataService.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.ResetData(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.SelectPage(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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + data, err := telnet.ConvertToMap(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + if len(data) == 0 { + c.JSON(200, result.ErrMsg("No Subs Data")) + 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] + } + neId = "" + u := 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), + NeId: neId, + } + // 1,64,24,65,def_eps,1,2,010200000000,- + if v, ok := data["EPS-Data"]; ok { + u.EpsDat = v + arr := strings.Split(v, ",") + u.EpsFlag = arr[0] + u.EpsOdb = arr[1] + u.HplmnOdb = arr[2] + u.Ard = arr[3] + u.Epstpl = arr[4] + u.ContextId = arr[5] + u.ApnContext = arr[7] + // [6] 是不要的,导入和导出不用 + u.StaticIp = arr[8] + } + + // 查询imsi存在赋予id用于更新 + list := s.udmSubService.SelectList(u) + if len(list) > 0 { + item := list[0] + if item.ID != "" { + u.ID = item.ID + } + } + go s.udmSubService.Insert(neId, u) + + c.JSON(200, result.OkData(u)) +} + +// 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := 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 != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("baa 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 != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmSubService.LoadData(neId, body.IMSI, 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("mod udmuser:imsi=%s", body.IMSI) + // 修改的参数名称 + if body.Msisdn != "" { + cmd += fmt.Sprintf(",msisdn=%s", body.Msisdn) + } + if body.Ambr != "" { + cmd += fmt.Sprintf(",ambr=%s", body.Ambr) + } + if body.Nssai != "" { + cmd += fmt.Sprintf(",nssai=%s", body.Nssai) + } + if body.Arfb != "" { + cmd += fmt.Sprintf(",arfb=%s", body.Arfb) + } + if body.Sar != "" { + cmd += fmt.Sprintf(",sar=%s", body.Sar) + } + if body.Rat != "" { + cmd += fmt.Sprintf(",rat=%s", body.Rat) + } + if body.Cn != "" { + cmd += fmt.Sprintf(",cn=%s", body.Cn) + } + if body.SmfSel != "" { + cmd += fmt.Sprintf(",smf_sel=%s", body.SmfSel) + } + if body.SmData != "" { + cmd += fmt.Sprintf(",sm_data=%s", body.SmData) + } + if body.EpsDat != "" { + cmd += fmt.Sprintf(",eps_dat=%s", body.EpsDat) + } + if body.EpsFlag != "" { + cmd += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) + } + if body.EpsOdb != "" { + cmd += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) + } + if body.HplmnOdb != "" { + cmd += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) + } + if body.Epstpl != "" { + cmd += fmt.Sprintf(",epstpl=%s", body.Epstpl) + } + if body.Ard != "" { + cmd += fmt.Sprintf(",ard=%s", body.Ard) + } + if body.ContextId != "" { + cmd += fmt.Sprintf(",context_id=%s", body.ContextId) + } + if body.ApnContext != "" { + cmd += fmt.Sprintf(",apn_context=%s", body.ApnContext) + } + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmSubService.Insert(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 + } + + // 处理字符转id数组后去重 + imsiArr := strings.Split(imsi, ",") + uniqueIDs := parse.RemoveDuplicates(imsiArr) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) + if neInfo.NeId != neId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + resultData := map[string]string{} + for _, imsi := range uniqueIDs { + // 发送MML + cmd := fmt.Sprintf("del udmuser:imsi=%s", imsi) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + resultData[imsi] = err.Error() + continue + } + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmSubService.Delete(neId, imsi) + } + resultData[imsi] = data + } + + c.JSON(200, result.OkData(resultData)) +} + +// 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.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + neId = "" + go s.udmSubService.LoadData(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.errImportUserSubFileFormat"))) + return + } + + neId := "" + list := s.udmSubService.SelectList(model.UDMSub{NeId: neId}) + // 文件名 + fileName := fmt.Sprintf("udm_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.WriterFileCSV(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.WriterFileTXT(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) + var body struct { + NeId string `json:"neId" binding:"required"` + UploadPath string `json:"uploadPath" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 判断文件名 + if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() + + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg("error uploading file")) + return + } + + // 网元主机的Telnet客户端 + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + + // 发送MML + cmd := fmt.Sprintf("import udmuser:path=%s", neFilePath) + data, err := telnet.ConvertToStr(telnetClient, cmd) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 命令ok时 + if strings.Contains(data, "ok") { + if strings.HasSuffix(body.UploadPath, ".csv") { + data := file.ReadFileCSV(localFilePath) + neId := "" + go s.udmSubService.InsertData(neId, "csv", data) + } + if strings.HasSuffix(body.UploadPath, ".txt") { + data := file.ReadFileTXT(",", localFilePath) + neId := "" + go s.udmSubService.InsertData(neId, "txt", data) + } + } + c.JSON(200, result.OkMsg(data)) +} diff --git a/src/modules/network_data/model/udm_auth.go b/src/modules/network_data/model/udm_auth.go new file mode 100644 index 00000000..6f7c1d17 --- /dev/null +++ b/src/modules/network_data/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"` // 默认ID + IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + Amf string `json:"amf" gorm:"column:amf"` // ANF + Status string `json:"status" gorm:"column:status"` // 状态 默认给1 + Ki string `json:"ki" gorm:"column:ki"` // ki + AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex + Opc string `json:"opc" gorm:"column:opc"` // opc + NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 +} + +func (UDMAuth) TableName() string { + return "u_auth_user" +} diff --git a/src/modules/network_data/model/udm_sub.go b/src/modules/network_data/model/udm_sub.go new file mode 100644 index 00000000..a4f3acd7 --- /dev/null +++ b/src/modules/network_data/model/udm_sub.go @@ -0,0 +1,34 @@ +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"` + + // ====== 非数据库字段属性 ====== + +} + +func (UDMSub) TableName() string { + return "u_sub_user" +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 47d7d6d0..2cd2bfc2 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -4,6 +4,7 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/middleware" "be.ems/src/framework/middleware/collectlogs" + "be.ems/src/framework/middleware/repeat" "be.ems/src/modules/network_data/controller" "github.com/gin-gonic/gin" @@ -107,4 +108,111 @@ func Setup(router *gin.Engine) { ) } + // 网元UDM 鉴权用户信息 + udmAuthGroup := neDataGroup.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 := neDataGroup.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_data/repository/udm_auth.go b/src/modules/network_data/repository/udm_auth.go new file mode 100644 index 00000000..90a3bea8 --- /dev/null +++ b/src/modules/network_data/repository/udm_auth.go @@ -0,0 +1,26 @@ +package repository + +import ( + "be.ems/src/modules/network_data/model" +) + +// UDM鉴权信息 数据层接口 +type IUDMAuth interface { + // ClearAndInsert 清空ne_id后新增实体 + ClearAndInsert(neId string, uArr []model.UDMAuth) int64 + + // SelectPage 根据条件分页查询 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(u model.UDMAuth) []model.UDMAuth + + // Insert 批量添加 + Inserts(uArr []model.UDMAuth) int64 + + // Delete 删除实体 + Delete(neId, imsi string) int64 + + // DeletePrefixByIMSI 删除前缀匹配的实体 + DeletePrefixByIMSI(neId, imsi string) int64 +} diff --git a/src/modules/network_data/repository/udm_auth.impl.go b/src/modules/network_data/repository/udm_auth.impl.go new file mode 100644 index 00000000..5fee2f0d --- /dev/null +++ b/src/modules/network_data/repository/udm_auth.impl.go @@ -0,0 +1,190 @@ +package repository + +import ( + "fmt" + "strings" + + "be.ems/src/framework/datasource" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/utils/repo" + "be.ems/src/modules/network_data/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, uArr []model.UDMAuth) int64 { + // 不指定neID时,用 TRUNCATE 清空表快 + _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) + if err != nil { + logger.Errorf("TRUNCATE err => %v", err) + } + return r.Inserts(uArr) +} + +// 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, strings.Trim(v.(string), " ")) + } + 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) + + // 排序 + orderSql := "" + if v, ok := query["sortField"]; ok && v != "" { + sortSql := v.(string) + if o, ok := query["sortOrder"]; ok && o != nil && v != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + orderSql = fmt.Sprintf(" order by %s ", sortSql) + } + + // 查询数据 + querySql := r.selectSql + whereSql + orderSql + 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(u model.UDMAuth) []model.UDMAuth { + // 查询条件拼接 + var conditions []string + var params []any + if u.IMSI != "" { + conditions = append(conditions, "imsi = ?") + params = append(params, u.IMSI) + } + if u.NeId != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, u.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(uArr []model.UDMAuth) int64 { + tx := datasource.DefaultDB().CreateInBatches(uArr, 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 +} + +// DeletePrefixByIMSI 删除前缀匹配的实体 +func (r *UDMAuthImpl) DeletePrefixByIMSI(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("DeletePrefixByIMSI err => %v", err) + } + return tx.RowsAffected +} diff --git a/src/modules/network_data/repository/udm_sub.go b/src/modules/network_data/repository/udm_sub.go new file mode 100644 index 00000000..db8db0f8 --- /dev/null +++ b/src/modules/network_data/repository/udm_sub.go @@ -0,0 +1,26 @@ +package repository + +import ( + "be.ems/src/modules/network_data/model" +) + +// UDM签约信息 数据层接口 +type IUDMSub interface { + // ClearAndInsert 清空ne_id后新增实体 + ClearAndInsert(neId string, uArr []model.UDMSub) int64 + + // SelectPage 根据条件分页查询 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(u model.UDMSub) []model.UDMSub + + // Insert 批量添加 + Inserts(uArr []model.UDMSub) int64 + + // Delete 删除实体 + Delete(neId, imsi string) int64 + + // DeletePrefixByIMSI 删除前缀匹配的实体 + DeletePrefixByIMSI(neId, imsi string) int64 +} diff --git a/src/modules/network_data/repository/udm_sub.impl.go b/src/modules/network_data/repository/udm_sub.impl.go new file mode 100644 index 00000000..c5ddda82 --- /dev/null +++ b/src/modules/network_data/repository/udm_sub.impl.go @@ -0,0 +1,211 @@ +package repository + +import ( + "fmt" + "strings" + + "be.ems/src/framework/datasource" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/utils/repo" + "be.ems/src/modules/network_data/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, u []model.UDMSub) int64 { + // 不指定neID时,用 TRUNCATE 清空表快 + _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) + if err != nil { + logger.Errorf("TRUNCATE err => %v", err) + } + + return r.Inserts(u) +} + +// 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, strings.Trim(v.(string), " ")) + } + if v, ok := query["imsi"]; ok && v != "" { + conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") + params = append(params, strings.Trim(v.(string), " ")) + } + 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) + + // 排序 + orderSql := "" + if v, ok := query["sortField"]; ok && v != "" { + sortSql := v.(string) + if o, ok := query["sortOrder"]; ok && o != nil && v != "" { + if o == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + orderSql = fmt.Sprintf(" order by %s ", sortSql) + } + + // 查询数据 + querySql := r.selectSql + whereSql + orderSql + 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(u model.UDMSub) []model.UDMSub { + // 查询条件拼接 + var conditions []string + var params []any + if u.IMSI != "" { + conditions = append(conditions, "imsi = ?") + params = append(params, u.IMSI) + } + if u.NeId != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, u.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) Inserts(uArr []model.UDMSub) int64 { + tx := datasource.DefaultDB().CreateInBatches(uArr, 2000) + if err := tx.Error; err != nil { + logger.Errorf("CreateInBatches err => %v", err) + } + 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 +} + +// DeletePrefixByIMSI 删除前缀匹配的实体 +func (r *UDMSubImpl) DeletePrefixByIMSI(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("DeletePrefixByIMSI err => %v", err) + } + return tx.RowsAffected +} diff --git a/src/modules/network_data/service/udm_auth.go b/src/modules/network_data/service/udm_auth.go new file mode 100644 index 00000000..6e2b14e1 --- /dev/null +++ b/src/modules/network_data/service/udm_auth.go @@ -0,0 +1,28 @@ +package service + +import "be.ems/src/modules/network_data/model" + +// UDM鉴权信息 服务层接口 +type IUDMAuth interface { + // ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 + ResetData(neId string) int64 + + // SelectPage 分页查询数据库 + SelectPage(query map[string]any) map[string]any + + // SelectList 查询数据库 + SelectList(u model.UDMAuth) []model.UDMAuth + + // Insert 从数据中读取后删除imsi再存入数据库 + // imsi长度15,ki长度32,opc长度0或者32 + Insert(neId string, u model.UDMAuth) int64 + + // InsertData 导入文件数据 dataType目前两种:txt/csv + InsertData(neId, dataType string, data any) int64 + + // Delete 删除单个不重新加载 + Delete(neID, imsi string) int64 + + // LoadData 删除范围后重新加载 num表示imsi后几位 + LoadData(neID, imsi, num string) int64 +} diff --git a/src/modules/network_data/service/udm_auth.impl.go b/src/modules/network_data/service/udm_auth.impl.go new file mode 100644 index 00000000..d7998a10 --- /dev/null +++ b/src/modules/network_data/service/udm_auth.impl.go @@ -0,0 +1,146 @@ +package service + +import ( + "fmt" + "strings" + + "be.ems/src/framework/redis" + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" +) + +// 实例化服务层 UDMAuthImpl 结构体 +var NewUDMAuthImpl = &UDMAuthImpl{ + udmAuthRepository: repository.NewUDMAuthImpl, +} + +// UDM鉴权信息 服务层处理 +type UDMAuthImpl struct { + // UDM鉴权信息数据信息 + udmAuthRepository repository.IUDMAuth +} + +// dataByRedis UDM鉴权用户 db:0 中 ausf:* +func (r *UDMAuthImpl) dataByRedis(imsi, neId string) []model.UDMAuth { + arr := []model.UDMAuth{} + key := fmt.Sprintf("ausf:%s", imsi) + ausfArr, err := redis.GetKeys("udmuser", key) + 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 + } + + amf := "" + if v, ok := m["amf"]; ok { + amf = strings.Replace(v, "\r\n", "", 1) + } + a := model.UDMAuth{ + IMSI: imsi, + Amf: amf, + Status: "1", // 默认给1 + Ki: m["ki"], + AlgoIndex: m["algo"], + Opc: m["opc"], + NeId: neId, + } + arr = append(arr, a) + } + return arr +} + +// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 +func (r *UDMAuthImpl) ResetData(neId string) int64 { + authArr := r.dataByRedis("*", neId) + // 数据清空后添加 + go r.udmAuthRepository.ClearAndInsert(neId, authArr) + return int64(len(authArr)) +} + +// SelectPage 分页查询数据库 +func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { + return r.udmAuthRepository.SelectPage(query) +} + +// SelectList 查询数据库 +func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth { + return r.udmAuthRepository.SelectList(u) +} + +// Insert 从数据中读取后删除imsi再存入数据库 +// imsi长度15,ki长度32,opc长度0或者32 +func (r *UDMAuthImpl) Insert(neId string, u model.UDMAuth) int64 { + uArr := r.dataByRedis(u.IMSI, neId) + if len(uArr) > 0 { + r.udmAuthRepository.Delete(neId, u.IMSI) + return r.udmAuthRepository.Inserts(uArr) + } + return 0 +} + +// InsertData 导入文件数据 dataType目前两种:txt/csv +func (r *UDMAuthImpl) InsertData(neId, dataType string, data any) int64 { + // imsi截取前缀,重新获取部分数据 + prefixes := make(map[string]struct{}) + + if dataType == "csv" { + for _, v := range data.([]map[string]string) { + imsi := v["imsi"] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + if dataType == "txt" { + for _, v := range data.([][]string) { + imsi := v[0] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + + // 根据前缀重新加载插入 + var num int64 = 0 + for prefix := range prefixes { + // 直接删除前缀的记录 + r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix) + // keys ausf:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + num += r.udmAuthRepository.Inserts(authArr) + } + } + return num +} + +// Delete 删除单个不重新加载 +func (r *UDMAuthImpl) Delete(neId, imsi string) int64 { + return r.udmAuthRepository.Delete(neId, imsi) +} + +// LoadData 删除范围后重新加载 num表示imsi后几位 +func (r *UDMAuthImpl) LoadData(neId, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)-1] + // 直接删除前缀的记录 + delNum := r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix) + // keys ausf:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + return r.udmAuthRepository.Inserts(authArr) + } + return delNum +} diff --git a/src/modules/network_data/service/udm_sub.go b/src/modules/network_data/service/udm_sub.go new file mode 100644 index 00000000..cb03afe7 --- /dev/null +++ b/src/modules/network_data/service/udm_sub.go @@ -0,0 +1,28 @@ +package service + +import "be.ems/src/modules/network_data/model" + +// UDM签约用户信息 服务层接口 +type IUDMSub interface { + // ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 + ResetData(neId string) int64 + + // SelectPage 分页查询数据库 + SelectPage(query map[string]any) map[string]any + + // SelectList 查询数据库 + SelectList(u model.UDMSub) []model.UDMSub + + // Insert 从数据中读取后删除imsi再存入数据库 + // imsi长度15,ki长度32,opc长度0或者32 + Insert(neId string, u model.UDMSub) int64 + + // InsertData 导入文件数据 dataType目前两种:txt/csv + InsertData(neId, dataType string, data any) int64 + + // Delete 删除单个不重新加载 + Delete(neId, imsi string) int64 + + // LoadData 删除范围后重新加载 num表示imsi后几位 + LoadData(neId, imsi, num string) int64 +} diff --git a/src/modules/network_data/service/udm_sub.impl.go b/src/modules/network_data/service/udm_sub.impl.go new file mode 100644 index 00000000..768e48a8 --- /dev/null +++ b/src/modules/network_data/service/udm_sub.impl.go @@ -0,0 +1,164 @@ +package service + +import ( + "fmt" + "strings" + + "be.ems/src/framework/redis" + "be.ems/src/modules/network_data/model" + "be.ems/src/modules/network_data/repository" +) + +// 实例化服务层 UDMSubImpl 结构体 +var NewUDMSubImpl = &UDMSubImpl{ + udmSubRepository: repository.NewUDMSubImpl, +} + +// UDM签约信息 服务层处理 +type UDMSubImpl struct { + // UDM签约信息数据信息 + udmSubRepository repository.IUDMSub +} + +// dataByRedis UDM签约用户 db:0 中 udm-sd:* +func (r *UDMSubImpl) dataByRedis(imsi, neId string) []model.UDMSub { + arr := []model.UDMSub{} + key := fmt.Sprintf("udm-sd:%s", imsi) + udmsdArr, err := redis.GetKeys("udmuser", key) + 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 + 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 +} + +// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 +func (r *UDMSubImpl) ResetData(neId string) int64 { + subArr := r.dataByRedis("*", neId) + // 数据清空后添加 + go r.udmSubRepository.ClearAndInsert(neId, subArr) + return int64(len(subArr)) +} + +// SelectPage 分页查询数据库 +func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { + return r.udmSubRepository.SelectPage(query) +} + +// SelectList 查询数据库 +func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub { + return r.udmSubRepository.SelectList(u) +} + +// Insert 从数据中读取后删除imsi再存入数据库 +// imsi长度15,ki长度32,opc长度0或者32 +func (r *UDMSubImpl) Insert(neId string, u model.UDMSub) int64 { + uArr := r.dataByRedis(u.IMSI, neId) + if len(uArr) > 0 { + r.udmSubRepository.Delete(neId, u.IMSI) + return r.udmSubRepository.Inserts(uArr) + } + return 0 +} + +// InsertData 导入文件数据 dataType目前两种:txt/csv +func (r *UDMSubImpl) InsertData(neId, dataType string, data any) int64 { + // imsi截取前缀,重新获取部分数据 + prefixes := make(map[string]struct{}) + + if dataType == "csv" { + for _, v := range data.([]map[string]string) { + imsi := v["imsi"] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + if dataType == "txt" { + for _, v := range data.([][]string) { + imsi := v[0] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + + // 根据前缀重新加载插入 + var num int64 = 0 + for prefix := range prefixes { + // 直接删除前缀的记录 + r.udmSubRepository.DeletePrefixByIMSI(neId, prefix) + // keys udm-sd:4600001000004* + subArr := r.dataByRedis(prefix+"*", neId) + if len(subArr) > 0 { + num += r.udmSubRepository.Inserts(subArr) + } + } + return num +} + +// Delete 删除单个不重新加载 +func (r *UDMSubImpl) Delete(neId, imsi string) int64 { + return r.udmSubRepository.Delete(neId, imsi) +} + +// LoadData 删除范围后重新加载 num表示imsi后几位 +func (r *UDMSubImpl) LoadData(neId, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)-1] + // 直接删除前缀的记录 + delNum := r.udmSubRepository.DeletePrefixByIMSI(neId, prefix) + // keys udm-sd:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + return r.udmSubRepository.Inserts(authArr) + } + return delNum +}