382 lines
10 KiB
Go
382 lines
10 KiB
Go
package service
|
||
|
||
import (
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"be.ems/src/framework/database/redis"
|
||
"be.ems/src/framework/utils/date"
|
||
neService "be.ems/src/modules/ne/service"
|
||
"be.ems/src/modules/ne_data/model"
|
||
"be.ems/src/modules/ne_data/repository"
|
||
)
|
||
|
||
// 实例化服务层 UDMSubUser 结构体
|
||
var NewUDMSubUser = &UDMSubUser{
|
||
udmSubRepository: repository.NewUDMSub,
|
||
UDMExtendRepository: repository.NewUDMExtend,
|
||
}
|
||
|
||
// UDM签约信息 服务层处理
|
||
type UDMSubUser struct {
|
||
udmSubRepository *repository.UDMSubUser // UDM签约信息数据信息
|
||
UDMExtendRepository *repository.UDMExtend // UDM用户IMSI信息数据信息
|
||
}
|
||
|
||
// dataByRedis UDM签约用户 db:0 中 udm-sd:*
|
||
func (r *UDMSubUser) dataByRedis(imsi, neId string) []model.UDMSubUser {
|
||
arr := []model.UDMSubUser{}
|
||
key := fmt.Sprintf("udm-sd:%s", imsi)
|
||
source := fmt.Sprintf("UDM_%s", neId)
|
||
|
||
// 网元主机的Redis客户端
|
||
redisClient, err := neService.NewNeInfo.NeRunRedisClient("UDM", neId)
|
||
if err != nil {
|
||
return arr
|
||
}
|
||
defer func() {
|
||
redisClient.Close()
|
||
redis.ConnectPush(source, nil)
|
||
}()
|
||
redis.ConnectPush(source, redisClient.Client)
|
||
|
||
udmsdArr, err := redis.GetKeys(source, key)
|
||
if err != nil {
|
||
return arr
|
||
}
|
||
mkv, err := redis.GetHashBatch(source, udmsdArr)
|
||
if err != nil {
|
||
return arr
|
||
}
|
||
|
||
for k, m := range mkv {
|
||
if len(k) != 22 {
|
||
continue
|
||
}
|
||
|
||
// 跳过-号数据 udm-sd:360000100000130
|
||
imsi, hasPrefix := strings.CutPrefix(k, "udm-sd:")
|
||
if strings.Contains(imsi, "-") || !hasPrefix {
|
||
continue
|
||
}
|
||
var createTime int64 = 0
|
||
if v, ok := m["create_time"]; ok {
|
||
t := date.ParseStrToDate(v, date.YYYY_MM_DDTHH_MM_SSZ)
|
||
createTime = t.UnixMilli()
|
||
} else {
|
||
createTime = time.Now().UnixMilli()
|
||
}
|
||
|
||
a := model.UDMSubUser{
|
||
CreateTime: createTime,
|
||
NeId: neId,
|
||
IMSI: imsi, // udm-sd:360000100000130
|
||
MSISDN: m["gpsi"], // 8612300000130
|
||
SmfSel: m["smf-sel"], // def_snssai
|
||
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
|
||
Cag: m["cag"], // def_cag
|
||
}
|
||
|
||
// 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.AmDat = v
|
||
a.UeAmbrTpl = arr[0]
|
||
a.NssaiTpl = arr[1]
|
||
a.RatRestrictions = arr[2]
|
||
a.AreaForbiddenTpl = arr[3]
|
||
a.ServiceAreaRestrictionTpl = arr[4]
|
||
a.CnTypeRestrictions = arr[5]
|
||
a.RfspIndex = arr[6]
|
||
a.SubsRegTime = arr[7]
|
||
a.UeUsageType = arr[8]
|
||
a.ActiveTime = arr[9]
|
||
a.MicoAllowed = "0" // arr[10]
|
||
a.OdbPs = "1" // arr[11]
|
||
a.GroupId = "-" // arr[12]
|
||
if len(arr) > 10 {
|
||
a.MicoAllowed = arr[10]
|
||
}
|
||
if len(arr) > 11 {
|
||
a.OdbPs = arr[11]
|
||
}
|
||
if len(arr) > 12 && arr[12] != "-" {
|
||
a.GroupId = arr[12]
|
||
}
|
||
}
|
||
// 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.ApnNum = arr[6] // 导入和导出不用
|
||
a.ApnContext = arr[7]
|
||
if len(arr) >= 9 {
|
||
a.StaticIp = arr[8]
|
||
}
|
||
}
|
||
|
||
arr = append(arr, a)
|
||
}
|
||
return arr
|
||
}
|
||
|
||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||
func (r *UDMSubUser) ResetData(neId string) int64 {
|
||
subArr := r.dataByRedis("*", neId)
|
||
// 数据清空后添加
|
||
go r.udmSubRepository.ClearAndInsert(neId, subArr)
|
||
return int64(len(subArr))
|
||
}
|
||
|
||
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
|
||
func (r *UDMSubUser) ParseInfo(imsi, neId string, data map[string]string) model.UDMSubUser {
|
||
u := r.udmSubRepository.SelectByIMSIAndNeID(imsi, neId)
|
||
|
||
cnType, _ := strconv.ParseInt(data["CNType"][:4], 0, 64) // 0x03(EPC|5GC)
|
||
rat, _ := strconv.ParseInt(data["RAT"][:4], 0, 64) // 0x00(VIRTUAL|WLAN|EUTRA|NR)
|
||
msisdn := data["MSISDN"]
|
||
if imsMsisdnLen := strings.Index(msisdn, ","); imsMsisdnLen != -1 {
|
||
msisdn = msisdn[:imsMsisdnLen]
|
||
}
|
||
|
||
// 用于更新
|
||
u.IMSI = imsi
|
||
u.MSISDN = msisdn
|
||
u.NeId = neId
|
||
u.UeAmbrTpl = data["AMBR"]
|
||
u.NssaiTpl = data["NSSAI"]
|
||
u.AreaForbiddenTpl = data["AreaForbidden"]
|
||
u.ServiceAreaRestrictionTpl = data["ServiceAreaRestriction"]
|
||
u.CnTypeRestrictions = fmt.Sprint(cnType)
|
||
u.RatRestrictions = fmt.Sprint(rat)
|
||
u.MicoAllowed = data["MICO"]
|
||
u.SmData = data["SM-Data(snssai+dnn[1..n])"]
|
||
u.SmfSel = data["Smf-Selection"]
|
||
u.Cag = data["cag"]
|
||
|
||
// 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.ApnNum = arr[6] // 导入和导出不用
|
||
u.ApnContext = arr[7]
|
||
u.StaticIp = arr[8]
|
||
}
|
||
|
||
// 补充用户拓展信息
|
||
info := r.UDMExtendRepository.SelectByIMSIAndNeID(imsi, neId)
|
||
if info.IMSI == imsi {
|
||
u.Remark = info.Remark
|
||
}
|
||
return u
|
||
}
|
||
|
||
// FindByPage 分页查询数据库
|
||
func (r *UDMSubUser) FindByPage(query map[string]string) ([]model.UDMSubUser, int64) {
|
||
return r.udmSubRepository.SelectPage(query)
|
||
}
|
||
|
||
// Find 查询数据库
|
||
func (r *UDMSubUser) Find(u model.UDMSubUser) []model.UDMSubUser {
|
||
return r.udmSubRepository.SelectList(u)
|
||
}
|
||
|
||
// Insert 从数据中读取后删除imsi再存入数据库
|
||
// imsi长度15,ki长度32,opc长度0或者32
|
||
func (r *UDMSubUser) Insert(neId string, u model.UDMSubUser) int64 {
|
||
uArr := r.dataByRedis(u.IMSI, neId)
|
||
if len(uArr) > 0 {
|
||
r.udmSubRepository.Delete(u.IMSI, neId)
|
||
// 新增到拓展信息
|
||
if u.Remark != "" {
|
||
r.UDMExtendRepository.Delete(u.IMSI, "%")
|
||
r.UDMExtendRepository.Inserts([]model.UDMExtend{{
|
||
IMSI: u.IMSI,
|
||
MSISDN: u.MSISDN,
|
||
NeId: u.NeId,
|
||
Remark: u.Remark,
|
||
}})
|
||
}
|
||
return r.udmSubRepository.Inserts(uArr)
|
||
}
|
||
return 0
|
||
}
|
||
|
||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||
func (r *UDMSubUser) 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 {
|
||
// keys udm-sd:4600001000004*
|
||
arr := r.dataByRedis(prefix+"*", neId)
|
||
if len(arr) > 0 {
|
||
r.udmSubRepository.DeletePrefixByIMSI(prefix, neId)
|
||
num += r.udmSubRepository.Inserts(arr)
|
||
}
|
||
}
|
||
return num
|
||
}
|
||
|
||
// Delete 删除单个不重新加载
|
||
func (r *UDMSubUser) Delete(neId, imsi string) int64 {
|
||
// 删除拓展信息
|
||
r.UDMExtendRepository.Delete(imsi, neId)
|
||
return r.udmSubRepository.Delete(imsi, neId)
|
||
}
|
||
|
||
// LoadData 重新加载从imsi开始num的数据
|
||
// remark不为空,则新增到拓展信息,删除标记为-(Deleted)-
|
||
func (r *UDMSubUser) LoadData(neId, imsi, num, remark string) {
|
||
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
|
||
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||
var i int64
|
||
for i = 0; i < subNum; i++ {
|
||
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
|
||
// 删除原数据
|
||
r.udmSubRepository.Delete(keyIMSI, neId)
|
||
if remark == "-(Deleted)-" {
|
||
r.UDMExtendRepository.Delete(keyIMSI, "%")
|
||
}
|
||
// 加载数据,删除标记为-(Deleted)-加载为空不插入
|
||
arr := r.dataByRedis(keyIMSI, neId)
|
||
if len(arr) < 1 {
|
||
continue
|
||
}
|
||
r.udmSubRepository.Inserts(arr)
|
||
// 拓展信息
|
||
if remark != "" {
|
||
uarr := make([]model.UDMExtend, 0, len(arr))
|
||
for _, v := range arr {
|
||
uarr = append(uarr, model.UDMExtend{
|
||
IMSI: v.IMSI,
|
||
MSISDN: v.MSISDN,
|
||
NeId: v.NeId,
|
||
Remark: remark,
|
||
})
|
||
}
|
||
r.UDMExtendRepository.Delete(keyIMSI, neId)
|
||
r.UDMExtendRepository.Inserts(uarr)
|
||
}
|
||
}
|
||
}
|
||
|
||
// ParseCommandParams 解析数据组成命令参数 msisdn=xx,xx=xx,...
|
||
func (r *UDMSubUser) ParseCommandParams(item model.UDMSubUser) string {
|
||
var conditions []string
|
||
if item.MSISDN != "" {
|
||
conditions = append(conditions, fmt.Sprintf("msisdn=%s", item.MSISDN))
|
||
}
|
||
|
||
// AmData
|
||
if item.UeAmbrTpl != "" {
|
||
conditions = append(conditions, fmt.Sprintf("ambr=%s", item.UeAmbrTpl))
|
||
}
|
||
if item.NssaiTpl != "" {
|
||
conditions = append(conditions, fmt.Sprintf("nssai=%s", item.NssaiTpl))
|
||
}
|
||
if item.AreaForbiddenTpl != "" {
|
||
conditions = append(conditions, fmt.Sprintf("arfb=%s", item.AreaForbiddenTpl))
|
||
}
|
||
if item.ServiceAreaRestrictionTpl != "" {
|
||
conditions = append(conditions, fmt.Sprintf("sar=%s", item.ServiceAreaRestrictionTpl))
|
||
}
|
||
if item.RatRestrictions != "" {
|
||
conditions = append(conditions, fmt.Sprintf("rat=%s", item.RatRestrictions))
|
||
}
|
||
if item.CnTypeRestrictions != "" {
|
||
conditions = append(conditions, fmt.Sprintf("cn=%s", item.CnTypeRestrictions))
|
||
}
|
||
if item.RfspIndex != "" {
|
||
conditions = append(conditions, fmt.Sprintf("rfsp=%s", item.RfspIndex))
|
||
}
|
||
if item.UeUsageType != "" {
|
||
conditions = append(conditions, fmt.Sprintf("usagetype=%s", item.UeUsageType))
|
||
}
|
||
if item.MicoAllowed != "" {
|
||
conditions = append(conditions, fmt.Sprintf("mico=%s", item.MicoAllowed))
|
||
}
|
||
|
||
// EpsDat
|
||
// if item.EpsDat != "" {
|
||
// conditions = append(conditions, fmt.Sprintf("eps_dat=%s", item.EpsDat))
|
||
// }
|
||
if item.EpsFlag != "" {
|
||
conditions = append(conditions, fmt.Sprintf("eps_flag=%s", item.EpsFlag))
|
||
}
|
||
if item.EpsOdb != "" {
|
||
conditions = append(conditions, fmt.Sprintf("eps_odb=%s", item.EpsOdb))
|
||
}
|
||
if item.HplmnOdb != "" {
|
||
conditions = append(conditions, fmt.Sprintf("hplmn_odb=%s", item.HplmnOdb))
|
||
}
|
||
if item.Epstpl != "" {
|
||
conditions = append(conditions, fmt.Sprintf("epstpl=%s", item.Epstpl))
|
||
}
|
||
if item.Ard != "" {
|
||
conditions = append(conditions, fmt.Sprintf("ard=%s", item.Ard))
|
||
}
|
||
if item.ContextId != "" {
|
||
conditions = append(conditions, fmt.Sprintf("context_id=%s", item.ContextId))
|
||
}
|
||
if item.ApnContext != "" {
|
||
conditions = append(conditions, fmt.Sprintf("apn_context=%s", item.ApnContext))
|
||
}
|
||
// static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增
|
||
if item.StaticIp != "" {
|
||
conditions = append(conditions, fmt.Sprintf("static_ip=%s", item.StaticIp))
|
||
}
|
||
|
||
// 其他
|
||
if item.SmfSel != "" {
|
||
conditions = append(conditions, fmt.Sprintf("smf_sel=%s", item.SmfSel))
|
||
}
|
||
if item.SmData != "" {
|
||
conditions = append(conditions, fmt.Sprintf("sm_data=%s", item.SmData))
|
||
}
|
||
conditions = append(conditions, fmt.Sprintf("cag=%s", item.Cag))
|
||
|
||
return strings.Join(conditions, ",")
|
||
}
|