ref: 网元数据将网元特有拆分直连模块

This commit is contained in:
TsMask
2025-06-11 16:32:50 +08:00
parent 1f3e07d5c7
commit f9648d1b26
56 changed files with 570 additions and 619 deletions

View File

@@ -0,0 +1,233 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
neFetchlink "be.ems/src/modules/network_link/fetch_link"
"github.com/gin-gonic/gin"
)
// 实例化控制层 AMFController 结构体
var NewAMF = &AMFController{
neInfoService: neService.NewNeInfo,
ueEventService: neDataService.NewUEEventAMF,
}
// 网元AMF
//
// PATH /amf
type AMFController struct {
neInfoService *neService.NeInfo // 网元信息服务
ueEventService *neDataService.UEEventAMF // UE会话事件服务
}
// UE会话列表
//
// GET /ue/list
//
// @Tags network_data/amf
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only AMF" Enums(AMF)
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List
// @Description UE Session List
// @Router /neData/amf/ue/list [get]
func (s *AMFController) UEList(c *gin.Context) {
var querys model.UEEventAMFQuery
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询数据
rows, total := s.ueEventService.FindByPage(querys)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UE会话删除
//
// DELETE /ue/:id
//
// @Tags network_data/amf
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session Deletion
// @Description UE Session Deletion
// @Router /neData/amf/ue/{id} [delete]
func (s *AMFController) UERemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.ueEventService.DeleteByIds(ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// UE会话列表导出
//
// POST /ue/export
//
// @Tags network_data/amf
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List Export
// @Description UE Session List Export
// @Router /neData/amf/ue/export [post]
func (s *AMFController) UEExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.UEEventAMFQuery
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
rows, total := s.ueEventService.FindByPage(querys)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.ueEventService.ExportXlsx(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 接入基站信息列表
//
// GET /nb/list
//
// @Tags network_data/amf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param id query string false "Base Station ID"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access Base Station Information List
// @Description Access Base Station Information List
// @Router /neData/amf/nb/list [get]
func (s *AMFController) NbInfoList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
NbId string `form:"id"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.AMFNbInfoList(neInfo, map[string]string{
"id": query.NbId,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 接入基站状态信息列表
//
// GET /nb/list-cfg
//
// @Tags network_data/amf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access to the base station status information list
// @Description Access to the base station status information list
// @Router /neData/amf/nb/list-cfg [get]
func (s *AMFController) NbStateList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.AMFGnbStateList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -0,0 +1,237 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
neFetchlink "be.ems/src/modules/network_link/fetch_link"
"github.com/gin-gonic/gin"
)
// 实例化控制层 IMSController 结构体
var NewIMS = &IMSController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREventIMS,
}
// 网元IMS
//
// PATH /ims
type IMSController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREventIMS // CDR会话事件服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags network_data/ims
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only IMS" Enums(IMS)
// @Param neId query string true "NE ID" default(001)
// @Param callerParty query string false "callerParty"
// @Param calledParty query string false "calledParty"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/ims/cdr/list [get]
func (s *IMSController) CDRList(c *gin.Context) {
var querys model.CDREventIMSQuery
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询数据
rows, total := s.cdrEventService.FindByPage(querys)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags network_data/ims
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/ims/cdr/{id} [delete]
func (s *IMSController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(442002, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds(ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
//
// @Tags network_data/ims
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/ims/cdr/export [post]
func (s *IMSController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.CDREventIMSQuery
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
rows, total := s.cdrEventService.FindByPage(querys)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 在线会话用户数量
//
// GET /session/num
//
// @Tags network_data/ims
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Number of online session users
// @Description Number of online session users
// @Router /neData/ims/session/num [get]
func (s *IMSController) UeSessionNum(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
num, err := neFetchlink.IMSUeSessionNum(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(num))
}
// 在线会话用户列表信息
//
// GET /session/list
//
// @Tags network_data/ims
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param msisdn query string false "msisdn"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/ims/session/list [get]
func (s *IMSController) UeSessionList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi"`
MSISDN string `form:"msisdn"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.IMSUeSessionList(neInfo, map[string]string{
"imsi": query.IMSI,
"msisdn": query.MSISDN,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -0,0 +1,233 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
neFetchlink "be.ems/src/modules/network_link/fetch_link"
"github.com/gin-gonic/gin"
)
// 实例化控制层 MMEController 结构体
var NewMME = &MMEController{
neInfoService: neService.NewNeInfo,
ueEventService: neDataService.NewUEEventMME,
}
// 网元MME
//
// PATH /mme
type MMEController struct {
neInfoService *neService.NeInfo // 网元信息服务
ueEventService *neDataService.UEEventMME // UE会话事件服务
}
// UE会话列表
//
// GET /ue/list
//
// @Tags network_data/mme
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only MME" Enums(MME)
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List
// @Description UE Session List
// @Router /neData/mme/ue/list [get]
func (s *MMEController) UEList(c *gin.Context) {
var querys model.UEEventMMEQuery
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询数据
rows, total := s.ueEventService.FindByPage(querys)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// UE会话删除
//
// DELETE /ue/:id
//
// @Tags network_data/mme
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session Deletion
// @Description UE Session Deletion
// @Router /neData/mme/ue/{id} [delete]
func (s *MMEController) UERemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.ueEventService.DeleteByIds(ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// UE会话列表导出
//
// POST /ue/export
//
// @Tags network_data/mme
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UE Session List Export
// @Description UE Session List Export
// @Router /neData/mme/ue/export [post]
func (s *MMEController) UEExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.UEEventMMEQuery
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
rows, total := s.ueEventService.FindByPage(querys)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("mme_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.ueEventService.ExportXlsx(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 接入基站信息列表
//
// GET /nb/list
//
// @Tags network_data/mme
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param id query string false "Base Station ID"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access Base Station Information List
// @Description Access Base Station Information List
// @Router /neData/mme/nb/list [get]
func (s *MMEController) NbInfoList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
NbId string `form:"id"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.MMENbInfoList(neInfo, map[string]string{
"id": query.NbId,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 接入基站状态信息列表
//
// GET /nb/list-cfg
//
// @Tags network_data/mme
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Access to the base station status information list
// @Description Access to the base station status information list
// @Router /neData/mme/nb/list-cfg [get]
func (s *MMEController) NbStateList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.MMEEnbStateList(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -0,0 +1,334 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neService "be.ems/src/modules/network_element/service"
neFetchlink "be.ems/src/modules/network_link/fetch_link"
"github.com/gin-gonic/gin"
)
// 实例化控制层 PCFController 结构体
var NewPCF = &PCFController{
neInfoService: neService.NewNeInfo,
}
// 网元PCF
//
// PATH /pcf
type PCFController struct {
neInfoService *neService.NeInfo // 网元信息服务
}
// 策略配置列表
//
// GET /rule/list
//
// @Tags network_data/pcf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "IMSI"
// @Param msisdn query string false "MSISDN"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Policy Configuration List
// @Description Policy Configuration List
// @Router /neData/pcf/rule/list [get]
func (s PCFController) RuleInfoList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi"`
MSISDN string `form:"msisdn"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.PCFRuleInfo(neInfo, map[string]string{
"imsi": query.IMSI,
"msisdn": query.MSISDN,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(data))
}
// 策略配置添加
//
// POST /rule
//
// @Tags network_data/pcf
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Policy Configuration Additions
// @Description Policy Configuration Additions
// @Router /neData/pcf/rule [post]
func (s PCFController) RuleInfoAdd(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
Num int64 `json:"num"` // 批量添加默认0单条大于1时imsi/msisdn会累加数值
ParamData map[string]any `json:"paramData" binding:"required"` // 参数数据
// Imsi string `json:"imsi" binding:"required"`
// Msisdn string `json:"msisdn" binding:"required"`
// Sar string `json:"sar"` // 根据PCF参数配置Service Area Restriction -> Name
// PccRules string `json:"pccRules"` // 根据PCF参数配置PCC Rules -> Rule ID
// QosAudio string `json:"qosAudio"` // 根据PCF参数配置QoS Template -> QoS ID
// QosVideo string `json:"qosVideo"` // 根据PCF参数配置QoS Template -> QoS ID
// SessRules string `json:"sessRules"` // 根据PCF参数配置Session Rules -> Rule ID
// HdrEnrich string `json:"hdrEnrich"` // 根据PCF参数配置Header Enrich Template -> Template Name
// UePolicy string `json:"uePolicy"` // UE策略模板(样例: uep_001)
// Rfsp int64 `json:"rfsp"` // 无线频率选择优先级
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
var err error
if body.Num > 0 { // 批量添加
err = neFetchlink.PCFRuleAddBatch(neInfo, body.ParamData, body.Num)
} else { // 单条添加
err = neFetchlink.PCFRuleAdd(neInfo, body.ParamData)
}
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// 策略配置更新
//
// PUT /rule
//
// @Tags network_data/pcf
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Policy Configuration Updates
// @Description Policy Configuration Updates
// @Router /neData/pcf/rule [put]
func (s PCFController) RuleInfoEdit(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
Num int64 `json:"num"` // 更新数量
ParamData map[string]any `json:"paramData" binding:"required"` // 参数数据
// Imsi string `json:"imsi" binding:"required"`
// Msisdn string `json:"msisdn" binding:"required"`
// Sar string `json:"sar"` // 根据PCF参数配置Service Area Restriction -> Name
// PccRules string `json:"pccRules"` // 根据PCF参数配置PCC Rules -> Rule ID
// QosAudio string `json:"qosAudio"` // 根据PCF参数配置QoS Template -> QoS ID
// QosVideo string `json:"qosVideo"` // 根据PCF参数配置QoS Template -> QoS ID
// SessRules string `json:"sessRules"` // 根据PCF参数配置Session Rules -> Rule ID
// HdrEnrich string `json:"hdrEnrich"` // 根据PCF参数配置Header Enrich Template -> Template Name
// UePolicy string `json:"uePolicy"` // UE策略模板(样例: uep_001)
// Rfsp int64 `json:"rfsp"` // 无线频率选择优先级
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
var err error
if body.Num > 0 { // 批量更新
err = neFetchlink.PCFRuleUpdateBatch(neInfo, body.ParamData, body.Num)
} else { // 单条更新
err = neFetchlink.PCFRuleUpdate(neInfo, body.ParamData)
}
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// 策略配置删除
//
// DELETE /rule
//
// @Tags network_data/pcf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string true "IMSi, batch deletion with quantity"
// @Param num query number false "Number of deletions"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Policy Configuration Deletion
// @Description Policy Configuration Deletion
// @Router /neData/pcf/rule [delete]
func (s PCFController) RuleInfoRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi, 带数量时为批量删除
Num int64 `form:"num"` // 删除数量
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
var err error
if query.Num > 0 { // 批量删除
err = neFetchlink.PCFRuleDeleteBatch(neInfo, query.IMSI, query.Num)
} else { // 单条删除
err = neFetchlink.PCFRuleDelete(neInfo, query.IMSI)
}
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.Ok(nil))
}
// 策略配置导出
//
// GET /rule/export
//
// @Tags network_data/pcf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param fileType query string true "File Type" default(txt)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Policy Configuration Export
// @Description Policy Configuration Export
// @Router /neData/pcf/rule/export [get]
func (s PCFController) RuleInfoExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
FileType string `form:"fileType" binding:"required,oneof=txt"` // 文件类型
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.PCFRuleExport(neInfo, map[string]string{
"fileType": query.FileType,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.Writer.Header().Set("Content-Disposition", `attachment; filename="pcf_rule_export.txt"`)
c.Data(200, "application/octet-stream", data)
}
// 策略配置导入
//
// PUT /rule/import
//
// @Tags network_data/pcf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param fileType query string true "File Type" default(txt)
// @Param filePath query string true "File Path" default(/tmp/pcfuser.txt)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Policy Configuration Import
// @Description Policy Configuration Import
// @Router /neData/pcf/rule/import [put]
func (s PCFController) RuleInfoImport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
FileType string `json:"fileType" binding:"required,oneof=txt"` // 文件类型
FilePath string `json:"filePath" binding:"required"` // 网元端文件所在绝对路径
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
output, err := neFetchlink.PCFRuleImport(neInfo, map[string]any{
"type": body.FileType,
"filePath": body.FilePath,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkMsg(output))
}

View File

@@ -0,0 +1,147 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 SGWCController 结构体
var NewSGWC = &SGWCController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREventSGWC,
UDMExtendService: service.NewUDMExtend,
}
// 网元SGWC
//
// PATH /sgwc
type SGWCController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREventSGWC // CDR会话事件服务
UDMExtendService *service.UDMExtend // UDM用户信息服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags network_data/sgwc
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only SGWC" Enums(SGWC)
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param msisdn query string false "msisdn"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/sgwc/cdr/list [get]
func (s *SGWCController) CDRList(c *gin.Context) {
var querys model.CDREventSGWCQuery
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询数据
rows, total := s.cdrEventService.FindByPage(querys)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags network_data/sgwc
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/sgwc/cdr/{id} [delete]
func (s *SGWCController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds(ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
//
// @Tags network_data/sgwc
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/sgwc/cdr/export [post]
func (s *SGWCController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.CDREventSGWCQuery
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
rows, total := s.cdrEventService.FindByPage(querys)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("sgwc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -0,0 +1,266 @@
package controller
import (
"fmt"
"strings"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
neFetchlink "be.ems/src/modules/network_link/fetch_link"
"be.ems/src/modules/network_link/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 SMFController 结构体
var NewSMF = &SMFController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREventSMF,
UDMExtendService: service.NewUDMExtend,
}
// 网元SMF
//
// PATH /smf
type SMFController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREventSMF // CDR会话事件服务
UDMExtendService *service.UDMExtend // UDM用户信息服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags network_data/smf
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only SMF" Enums(SMF)
// @Param neId query string true "NE ID" default(001)
// @Param subscriberID query string false "subscriberID is IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/smf/cdr/list [get]
func (s *SMFController) CDRList(c *gin.Context) {
var querys model.CDREventSMFQuery
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询数据
rows, total := s.cdrEventService.FindByPage(querys)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags network_data/smf
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/smf/cdr/{id} [delete]
func (s *SMFController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds(ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
//
// @Tags network_data/smf
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/smf/cdr/export [post]
func (s *SMFController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.CDREventSMFQuery
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
rows, total := s.cdrEventService.FindByPage(querys)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}
// 在线订阅用户数量
//
// GET /sub/num
//
// @Tags network_data/smf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Number of online session users
// @Description Number of online session users
// @Router /neData/smf/sub/num [get]
func (s *SMFController) SubUserNum(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
num, err := neFetchlink.SMFSubNum(neInfo)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, resp.OkData(num))
}
// 在线订阅用户列表信息
//
// GET /sub/list
//
// @Tags network_data/smf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "imsi"
// @Param msisdn query string false "msisdn"
// @Param upstate query string false "upstate"
// @Param pageNum query string true "pageNum" default(50)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Online session user list information
// @Description Online session user list information
// @Router /neData/smf/session/list [get]
func (s *SMFController) SubUserList(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi"`
MSISDN string `form:"msisdn"`
Upstate string `form:"upstate"`
PageNum string `form:"pageNum"`
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元直连
data, err := neFetchlink.SMFSubInfoList(neInfo, map[string]string{
"imsi": query.IMSI,
"msisdn": query.MSISDN,
"upstate": query.Upstate,
"pageNum": query.PageNum,
})
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 对数据进行处理去掉前缀并加入imsi拓展信息
rows := data["rows"].([]any)
if len(rows) > 0 {
arr := &rows
for i := range *arr {
item := (*arr)[i].(map[string]any)
if v, ok := item["imsi"]; ok && v != nil {
imsiStr := v.(string)
imsiStr = strings.TrimPrefix(imsiStr, "imsi-")
item["imsi"] = imsiStr
// 查UDM拓展信息
info := s.UDMExtendService.FindByIMSIAndNeID(query.CoreUID, query.NeUID, imsiStr)
item["remark"] = info.Remark
}
if v, ok := item["msisdn"]; ok && v != nil {
item["msisdn"] = strings.TrimPrefix(v.(string), "msisdn-")
}
}
}
c.JSON(200, resp.OkData(data))
}

View File

@@ -0,0 +1,145 @@
package controller
import (
"fmt"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"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"
)
// 实例化控制层 SMSCController 结构体
var NewSMSC = &SMSCController{
neInfoService: neService.NewNeInfo,
cdrEventService: neDataService.NewCDREventSMSC,
}
// 网元SMSC
//
// PATH /smsc
type SMSCController struct {
neInfoService *neService.NeInfo // 网元信息服务
cdrEventService *neDataService.CDREventSMSC // CDR会话事件服务
}
// CDR会话列表
//
// GET /cdr/list
//
// @Tags network_data/smsc
// @Accept json
// @Produce json
// @Param neType query string true "NE Type only SMSC" Enums(SMSC)
// @Param neId query string true "NE ID" default(001)
// @Param callerParty query string false "callerParty"
// @Param calledParty query string false "calledParty"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List
// @Description CDR Session List
// @Router /neData/smsc/cdr/list [get]
func (s *SMSCController) CDRList(c *gin.Context) {
var querys model.CDREventSMSCQuery
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询数据
rows, total := s.cdrEventService.FindByPage(querys)
c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total}))
}
// CDR会话删除
//
// DELETE /cdr/:id
//
// @Tags network_data/smsc
// @Accept json
// @Produce json
// @Param id path string true "list data id, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session Delete
// @Description CDR Session Delete
// @Router /neData/smsc/cdr/{id} [delete]
func (s *SMSCController) CDRRemove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
id := c.Param("id")
if id == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty"))
return
}
// 处理字符转id数组后去重
uniqueIDs := parse.RemoveDuplicatesToArray(id, ",")
// 转换成int64数组类型
ids := make([]int64, 0)
for _, v := range uniqueIDs {
ids = append(ids, parse.Number(v))
}
rows, err := s.cdrEventService.DeleteByIds(ids)
if err != nil {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, resp.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
//
// @Tags network_data/smsc
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary CDR Session List Export
// @Description CDR Session List Export
// @Router /neData/smsc/cdr/export [post]
func (s *SMSCController) CDRExport(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.CDREventSMSCQuery
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
rows, total := s.cdrEventService.FindByPage(querys)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 导出文件名称
fileName := fmt.Sprintf("smsc_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 导出数据表格
saveFilePath, err := s.cdrEventService.ExportXlsx(rows, fileName, language)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -0,0 +1,565 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/network_element/service"
neFetchlink "be.ems/src/modules/network_link/fetch_link"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMAuthController 结构体
var NewUDMAuth = &UDMAuthController{
udmAuthService: service.NewUDMAuthUser,
neInfoService: neService.NewNeInfo,
}
// UDM鉴权用户
//
// PATH /udm/auth
type UDMAuthController struct {
udmAuthService *service.UDMAuthUser // UDM鉴权信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDM鉴权用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User Data Refresh
// @Description UDM Authenticated User Data List Refresh Synchronization Latest
// @Router /neData/udm/auth/reset [put]
func (s *UDMAuthController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmAuthService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDM鉴权用户列表
//
// GET /list
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User List
// @Description UDM Authentication User List
// @Router /neData/udm/auth/list [get]
func (s *UDMAuthController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
total, rows := s.udmAuthService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows}))
}
// UDM鉴权用户信息
//
// GET /:neId/:imsi
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param coreUid query string true "NE ID" default(001)
// @Param neUid query string true "NE ID" default(001)
// @Param imsi query string true "IMSI"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User Information
// @Description UDM Authentication User Information
// @Router /neData/udm/auth [get]
func (s *UDMAuthController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp authdat:imsi=%s", query.IMSI)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No Auth Data"))
return
}
// 解析返回的数据
u := s.udmAuthService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, query.IMSI, data)
s.udmAuthService.Insert(neInfo.CoreUID, neInfo.NeUID, u)
c.JSON(200, resp.OkData(u))
}
// UDM鉴权用户新增
//
// POST /
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authentication User Added
// @Description UDM Authentication User Added
// @Router /neData/udm/auth [post]
func (s *UDMAuthController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 0 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is empty"))
return
}
var body model.UDMAuthUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.IMSI == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: imsi is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%d,", body.IMSI, num)
cmd += s.udmAuthService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.IMSI, num)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("add authdat:imsi=%s,", body.IMSI)
cmd += s.udmAuthService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM鉴权用户修改
//
// PUT /
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Modification
// @Description UDM Authenticated User Modification
// @Router /neData/udm/auth [put]
func (s *UDMAuthController) Edit(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body model.UDMAuthUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.IMSI == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: imsi is empty"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("mod authdata:imsi=%s,", body.IMSI)
cmd += s.udmAuthService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM鉴权用户删除
//
// DELETE /:neId/:imsi
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Deletion
// @Description UDM Authenticated User Deletion
// @Router /neData/udm/auth/{neId}/{value} [delete]
func (s *UDMAuthController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi
Num int64 `form:"num"` // 批量数量
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
if query.Num > 0 {
// 发送MML
cmd := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%d", query.IMSI, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmAuthService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.IMSI, query.Num)
}
c.JSON(200, resp.OkData(data))
return
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.IMSI, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
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") {
s.udmAuthService.Delete(neInfo.CoreUID, neInfo.NeUID, imsi)
}
resultData[imsi] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDM鉴权用户导出
//
// GET /export
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Export
// @Description UDM Authenticated User Export
// @Router /neData/udm/auth/export [get]
func (s *UDMAuthController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
return
}
query := reqctx.QueryMap(c)
total, rows := s.udmAuthService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_auth_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"})
for _, v := range rows {
opc := v.Opc
if opc == "-" {
opc = ""
}
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
opc := v.Opc
if opc == "-" {
opc = ""
}
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDM鉴权用户导入
//
// POST /import
//
// @Tags network_data/udm/auth
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Import
// @Description UDM Authenticated User Import
// @Router /neData/udm/auth/import [post]
func (s *UDMAuthController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
TypeVal string `json:"typeVal" binding:"required,oneof=default k4"` // default: 默认导入方式, k4: k4类型导入方式
TypeData any `json:"typeData"` // k4类型的数据密钥
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 结果信息
var resultMsg string
var resultErr error
// 默认的情况 发送MML
if body.TypeVal == "default" {
cmd := fmt.Sprintf("import authdat:path=%s", neFilePath)
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
}
// K4类型发特定请求
if body.TypeVal == "k4" {
resultMsg, resultErr = neFetchlink.UDMImportAuth(neInfo.IPAddr, map[string]any{
"path": neFilePath, "k4": body.TypeData,
})
}
if resultErr != nil {
c.JSON(200, resp.ErrMsg(resultErr.Error()))
return
}
// 命令ok时
if strings.Contains(resultMsg, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmAuthService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmAuthService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(resultMsg))
}

View File

@@ -0,0 +1,551 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMSubController 结构体
var NewUDMSub = &UDMSubController{
udmSubService: service.NewUDMSubUser,
neInfoService: neService.NewNeInfo,
}
// UDM签约用户
//
// PATH /udm/sub
type UDMSubController struct {
udmSubService *service.UDMSubUser // UDM签约信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDM签约用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Reload Data
// @Description UDM Subscriber User Reload Data
// @Router /neData/udm/sub/reset [put]
func (s *UDMSubController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmSubService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDM签约用户列表
//
// GET /list
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "IMSI"
// @Param msisdn query string false "Msisdn"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User List
// @Description UDM Subscriber User List
// @Router /neData/udm/sub/list [get]
func (s *UDMSubController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
total, rows := s.udmSubService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows}))
}
// UDM签约用户信息
//
// GET /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Information
// @Description UDM Subscriber User Information
// @Router /neData/udm/sub [get]
func (s *UDMSubController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp udmuser:imsi=%s", query.IMSI)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No Subs Data"))
return
}
// 解析返回的数据
u := s.udmSubService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, query.IMSI, data)
s.udmSubService.Insert(neInfo.CoreUID, neInfo.NeUID, u)
c.JSON(200, resp.OkData(u))
}
// UDM签约用户新增
//
// POST /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Added
// @Description UDM Subscriber User Added
// @Router /neData/udm/sub [post]
func (s *UDMSubController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 0 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is empty"))
return
}
var body model.UDMSubUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if len(body.IMSI) != 15 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: IMSI length is not 15 bits"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%d,", body.IMSI, body.MSISDN, num)
cmd += s.udmSubService.ParseCommandParams(body)
// 去除msisdn参数避免重复
omemsisdn := fmt.Sprintf(",msisdn=%s,", body.MSISDN)
cmd = strings.Replace(cmd, omemsisdn, ",", 1)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.IMSI, num, body.Remark)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("add udmuser:imsi=%s,", body.IMSI)
cmd += s.udmSubService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM签约用户修改
//
// PUT /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Modification
// @Description UDM Subscriber User Modification
// @Router /neData/udm/sub [put]
func (s *UDMSubController) Edit(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neId := c.Param("neId")
if neId == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: neId is empty"))
return
}
var body model.UDMSubUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if len(body.IMSI) != 15 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: IMSI length is not 15 bits"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("mod udmuser:imsi=%s,", body.IMSI)
cmd += s.udmSubService.ParseCommandParams(body)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.Insert(neInfo.CoreUID, neInfo.NeUID, body)
}
c.JSON(200, resp.OkData(data))
}
// UDM签约用户删除
//
// DELETE /
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Deletion
// @Description UDM Subscriber User Deletion
// @Router /neData/udm/sub [delete]
func (s *UDMSubController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi
Num int64 `form:"num"` // 批量数量
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
if query.Num > 0 {
// 发送MML
cmd := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%d", query.IMSI, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmSubService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.IMSI, query.Num, "-(Deleted)-")
}
c.JSON(200, resp.OkData(data))
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.IMSI, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
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") {
s.udmSubService.Delete(neInfo.CoreUID, neInfo.NeUID, imsi)
}
resultData[imsi] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDM签约用户导出
//
// GET /export
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param imsi query string false "IMSI"
// @Param msisdn query string false "Msisdn"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Export
// @Description UDM Subscriber User Export
// @Router /neData/udm/sub/export [post]
func (s *UDMSubController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
return
}
query := reqctx.QueryMap(c)
total, rows := s.udmSubService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_sub_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"IMSI", "MSISDN", "UeAmbrTpl", "NssaiTpl", "AreaForbiddenTpl", "ServiceAreaRestrictionTpl", "RatRestrictions", "CnTypeRestrictions", "SmfSel", "SmData", "EPSDat"})
for _, v := range rows {
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.UeAmbrTpl, v.NssaiTpl, v.AreaForbiddenTpl, v.ServiceAreaRestrictionTpl, v.RatRestrictions, v.CnTypeRestrictions, v.SmfSel, v.SmData, epsDat})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
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.UeAmbrTpl, v.NssaiTpl, v.AreaForbiddenTpl, v.ServiceAreaRestrictionTpl, v.RatRestrictions, v.CnTypeRestrictions, v.SmfSel, v.SmData, epsDat})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDM签约用户导入
//
// POST /import
//
// @Tags network_data/udm/sub
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Subscriber User Import
// @Description UDM Subscriber User Import
// @Router /neData/udm/sub/import [post]
func (s *UDMSubController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"`
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.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, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmSubService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmSubService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(data))
}

View File

@@ -0,0 +1,493 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMVOIPController 结构体
var NewUDMVOIP = &UDMVOIPController{
udmVOIPService: service.NewUDMVOIPUser,
neInfoService: neService.NewNeInfo,
}
// UDMVOIP用户
//
// PATH /udm/voip
type UDMVOIPController struct {
udmVOIPService *service.UDMVOIPUser // UDMVOIP信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDMVOIP用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Data Refresh
// @Description UDM VOIP User Data List Refresh Synchronization Latest
// @Router /neData/udm/voip/reset [put]
func (s *UDMVOIPController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmVOIPService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDMVOIP用户列表
//
// GET /list
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Param username query string false "User Name"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User List
// @Description UDM VOIP User List
// @Router /neData/udm/voip/list [get]
func (s *UDMVOIPController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
total, rows := s.udmVOIPService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows}))
}
// UDMVOIP用户信息
//
// GET /
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "User Name"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Information
// @Description UDM VOIP User Information
// @Router /neData/udm/voip [get]
func (s *UDMVOIPController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
UserName string `form:"username" binding:"required"` // 用户名
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp voip:username=%s", query.UserName)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No VOIP Data"))
return
}
// 解析返回的数据
u := s.udmVOIPService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, data)
if u.ID != "" {
s.udmVOIPService.Insert(neInfo.CoreUID, neInfo.NeUID, u.UserName)
c.JSON(200, resp.OkData(u))
return
}
c.JSON(200, resp.ErrMsg("No VOIP Data"))
}
// UDMVOIP用户新增
//
// POST /
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Added
// @Description UDM VOIP User Added
// @Router /neData/udm/voip [post]
func (s *UDMVOIPController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 1 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: num is empty"))
return
}
var body model.UDMVOIPUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.UserName == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: username is empty"))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa voip:sub_num=%d,start_username=%s,password=%s", num, body.UserName, body.Password)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.UserName, num)
}
c.JSON(200, resp.OkData(data))
return
}
// 发送MML
cmd := fmt.Sprintf("add voip:username=%s,password=%s", body.UserName, body.Password)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.Insert(neInfo.CoreUID, neInfo.NeUID, body.UserName)
}
c.JSON(200, resp.OkData(data))
}
// UDMVOIP用户删除
//
// DELETE /
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "User Name, multiple separated by a , sign"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Deletion
// @Description UDM VOIP User Deletion
// @Router /neData/udm/voip [delete]
func (s *UDMVOIPController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
UserName string `form:"username" binding:"required"` // 用户名
Num int64 `form:"num"` // 批量数量
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
if query.Num > 1 {
// 发送MML
cmd := fmt.Sprintf("bde voip:start_username=%s,sub_num=%d", query.UserName, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.UserName, query.Num)
}
c.JSON(200, resp.OkData(data))
return
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.UserName, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
resultData := map[string]string{}
for _, v := range uniqueIDs {
// 发送MML
cmd := fmt.Sprintf("del voip:username=%s", v)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[v] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVOIPService.Delete(neInfo.CoreUID, neInfo.NeUID, v)
}
resultData[v] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDMVOIP用户导出
//
// GET /export
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param username query string false "User Name"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Export
// @Description UDM VOIP User Export
// @Router /neData/udm/voip/export [get]
func (s *UDMVOIPController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
neId := c.Query("neId")
fileType := c.Query("type")
if neId == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: neId is empty"))
return
}
if !(fileType == "csv" || fileType == "txt") {
c.JSON(200, resp.ErrMsg("file type error, only support csv,txt"))
return
}
query := reqctx.QueryMap(c)
total, rows := s.udmVOIPService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// rows := s.udmVOIPService.SelectList(model.UDMVOIPUser{NeId: neId})
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_voip_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"username", "password"})
for _, v := range rows {
data = append(data, []string{v.UserName, v.Password})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
data = append(data, []string{v.UserName, v.Password})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDMVOIP用户导入
//
// POST /import
//
// @Tags network_data/udm/voip
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VOIP User Import
// @Description UDM VOIP User Import
// @Router /neData/udm/voip/import [post]
func (s *UDMVOIPController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 结果信息
var resultMsg string
var resultErr error
// 发送MML
cmd := fmt.Sprintf("import voip:path=%s", neFilePath)
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
if resultErr != nil {
c.JSON(200, resp.ErrMsg(resultErr.Error()))
return
}
// 命令ok时
if strings.Contains(resultMsg, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmVOIPService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmVOIPService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(resultMsg))
}

View File

@@ -0,0 +1,520 @@
package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/telnet"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UDMVolteIMSController 结构体
var NewUDMVolteIMS = &UDMVolteIMSController{
udmVolteIMSService: service.NewUDMVolteIMSUser,
neInfoService: neService.NewNeInfo,
}
// UDMVolteIMS用户
//
// PATH /udm/volte-ims
type UDMVolteIMSController struct {
udmVolteIMSService *service.UDMVolteIMSUser // UDMVolteIMS信息服务
neInfoService *neService.NeInfo // 网元信息服务
}
// UDMVolteIMS用户重载数据
//
// PUT /reset
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Data Refresh
// @Description UDM Authenticated User Data List Refresh Synchronization Latest
// @Router /neData/udm/volte-ims/reset [put]
func (s *UDMVolteIMSController) ResetData(c *gin.Context) {
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
data := s.udmVolteIMSService.ResetData(query.CoreUID, query.NeUID)
c.JSON(200, resp.OkData(data))
}
// UDMVolteIMS用户列表
//
// GET /list
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User List
// @Description UDM VolteIMS User List
// @Router /neData/udm/volte-ims/list [get]
func (s *UDMVolteIMSController) List(c *gin.Context) {
query := reqctx.QueryMap(c)
total, rows := s.udmVolteIMSService.FindByPage(query)
c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows}))
}
// UDMVolteIMS用户信息
//
// GET /
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param value path string true "IMSI"
// @Param msisdn query string true "MSISDN"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Information
// @Description UDM VolteIMS User Information
// @Router /neData/udm/volte-ims [get]
func (s *UDMVolteIMSController) Info(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi
MSISDN string `form:"msisdn" binding:"required"` // MSISDN
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
cmd := fmt.Sprintf("dsp imsuser:imsi=%s,msisdn=%s", query.IMSI, query.MSISDN)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
if len(data) == 0 {
c.JSON(200, resp.ErrMsg("No Volte IMS Data"))
return
}
// 解析返回的数据
u := s.udmVolteIMSService.ParseInfo(neInfo.CoreUID, neInfo.NeUID, data)
if u.ID != "" {
s.udmVolteIMSService.InsertByIMSI(neInfo.CoreUID, neInfo.NeUID, query.IMSI)
c.JSON(200, resp.OkData(u))
return
}
c.JSON(200, resp.ErrMsg("No Volte IMS Data"))
}
// UDMVolteIMS用户新增
//
// POST /
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param neId path string true "NE ID" default(001)
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Added
// @Description UDM VolteIMS User Added If VoIP tag=0, then MSISDN and IMSI need to be the same.
// @Router /neData/udm/volte-ims [post]
func (s *UDMVolteIMSController) Add(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
// 传入数量大于0时为批量新增
num := parse.Number(c.Query("num"))
if num < 0 {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
var body model.UDMVolteIMSUser
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if body.IMSI == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: imsi is empty"))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 批量新增
if num > 1 {
// 发送MML
cmd := fmt.Sprintf("baa imsuser:sub_num=%d,start_imsi=%s,start_msisdn=%s,volte=%s,vni=%s", num, body.IMSI, body.MSISDN, body.Tag, body.VNI)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.LoadData(neInfo.CoreUID, neInfo.NeUID, body.IMSI, num)
}
c.JSON(200, resp.OkData(data))
return
}
// 检查同IMSI下msisdn是否存在
hasMsisdns := s.udmVolteIMSService.Find(model.UDMVolteIMSUser{IMSI: body.IMSI, MSISDN: body.MSISDN, NeUID: neInfo.NeUID})
if len(hasMsisdns) > 0 {
c.JSON(200, resp.ErrMsg("IMSI and MSISDN already exist"))
return
}
// 发送MML
cmd := fmt.Sprintf("add imsuser:imsi=%s,msisdn=%s,volte=%s,vni=%s", body.IMSI, body.MSISDN, body.Tag, body.VNI)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.InsertByIMSI(neInfo.CoreUID, neInfo.NeUID, body.IMSI)
}
c.JSON(200, resp.OkData(data))
}
// UDMVolteIMS用户删除
//
// DELETE /
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Param imsi query string true "IMSI"
// @Param num query number true "Number of releases, value includes start imsi"
// @Param msisdn query string false "MSISDN"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM VolteIMS User Batch Deletion
// @Description UDM VolteIMS User Batch Deletion
// @Router /neData/udm/volte-ims [delete]
func (s *UDMVolteIMSController) Remove(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var query struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
IMSI string `form:"imsi" binding:"required"` // IMSi, 带数量时为批量
MSISDN string `form:"msisdn"` // MSISDN, 精确msisdn删除
Num int64 `form:"num"` // 批量数量
}
if err := c.ShouldBindQuery(&query); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(query.CoreUID, query.NeUID)
if neInfo.CoreUID != query.CoreUID || neInfo.NeUID != query.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 精确msisdn删除
if query.MSISDN != "" {
// 发送MML
cmd := fmt.Sprintf("del imsuser:imsi=%s,msisdn=%s", query.IMSI, query.MSISDN)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.Delete(neInfo.CoreUID, neInfo.NeUID, query.IMSI)
}
c.JSON(200, resp.OkData(data))
return
}
// 批量更新
if query.Num > 0 {
// 发送MML
cmd := fmt.Sprintf("bde imsuser:start_imsi=%s,sub_num=%d", query.IMSI, query.Num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.LoadData(neInfo.CoreUID, neInfo.NeUID, query.IMSI, query.Num)
}
c.JSON(200, resp.OkData(data))
return
}
// 处理字符转id数组后去重
imsiArr := strings.Split(query.IMSI, ",")
uniqueIDs := parse.RemoveDuplicates(imsiArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, resp.Err(nil))
return
}
resultData := map[string]string{}
for _, imsi := range uniqueIDs {
// 发送MML
cmd := fmt.Sprintf("del imsuser:imsi=%s", imsi)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[imsi] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
s.udmVolteIMSService.Delete(neInfo.CoreUID, neInfo.NeUID, imsi)
}
resultData[imsi] = data
}
c.JSON(200, resp.OkData(resultData))
}
// UDMVolteIMS用户导出
//
// GET /export
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param coreUid query string true "CoreUID" default(001)
// @Param neUid query string true "NeUID" default(001)
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
// @Param imsi query string false "IMSI"
// @Param pageNum query number true "pageNum" default(1)
// @Param pageSize query number true "pageSize" default(10)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Export
// @Description UDM Authenticated User Export
// @Router /neData/udm/volte-ims/export [get]
func (s *UDMVolteIMSController) Export(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
neUid := c.Query("neUid")
if c.Query("coreUid") == "" || neUid == "" {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: coreUid or neUid is empty"))
return
}
fileType := c.Query("type")
if !(fileType == "csv" || fileType == "txt") {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
return
}
query := reqctx.QueryMap(c)
total, rows := s.udmVolteIMSService.FindByPage(query)
if total == 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
if len(rows) <= 0 {
// 导出数据记录为空
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
// 文件名
fileName := fmt.Sprintf("udm_volte_user_export_%s_%d.%s", neUid, time.Now().UnixMilli(), fileType)
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
if fileType == "csv" {
// 转换数据
data := [][]string{}
data = append(data, []string{"IMSI", "MSISDN", "TAG", "VNI"})
for _, v := range rows {
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
}
// 输出到文件
if err := file.WriterFileCSV(data, filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
if fileType == "txt" {
// 转换数据
data := [][]string{}
for _, v := range rows {
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
}
// 输出到文件
if err := file.WriterFileTXTLine(data, ",", filePath); err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
}
c.FileAttachment(filePath, fileName)
}
// UDMVolteIMS用户导入
//
// POST /import
//
// @Tags network_data/udm/volte-ims
// @Accept json
// @Produce json
// @Param data body object true "Request Param"
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary UDM Authenticated User Import
// @Description UDM Authenticated User Import
// @Router /neData/udm/volte-ims/import [post]
func (s *UDMVolteIMSController) Import(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body struct {
CoreUID string `json:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `json:"neUid" binding:"required"` // 网元唯一标识
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
}
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 查询网元信息
neInfo := s.neInfoService.FindByCoreUidAndNeUid(body.CoreUID, body.NeUID)
if neInfo.CoreUID != body.CoreUID || neInfo.NeUID != body.NeUID || neInfo.NeType != "UDM" {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.CoreUID, neInfo.NeUID)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, resp.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.CoreUID, neInfo.NeUID, 1)
if err != nil {
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 结果信息
var resultMsg string
var resultErr error
// 发送MML
cmd := fmt.Sprintf("import imsuser:path=%s", neFilePath)
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
if resultErr != nil {
c.JSON(200, resp.ErrMsg(resultErr.Error()))
return
}
// 命令ok时
if strings.Contains(resultMsg, "ok") {
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
go s.udmVolteIMSService.InsertData(neInfo.CoreUID, neInfo.NeUID, "csv", data)
}
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXTLine(",", localFilePath)
go s.udmVolteIMSService.InsertData(neInfo.CoreUID, neInfo.NeUID, "txt", data)
}
}
c.JSON(200, resp.OkMsg(resultMsg))
}

View File

@@ -0,0 +1,71 @@
package controller
import (
"fmt"
"be.ems/src/framework/i18n"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 UPFController 结构体
var NewUPF = &UPFController{
neInfoService: neService.NewNeInfo,
kpiReportService: neDataService.NewKpiReport,
}
// 网元UPF
//
// PATH /upf
type UPFController struct {
neInfoService *neService.NeInfo // 网元信息服务
kpiReportService *neDataService.KpiReport // 统计信息服务
}
// 总流量数 N3上行 N6下行
// 单位 比特(bit)
//
// GET /flow-total
//
// @Tags network_data/upf
// @Accept json
// @Produce json
// @Param neId query string true "NE ID" default(001)
// @Param day query number true "Statistical time a few days before" Enums(0, 7, 30)
// @Success 200 {object} object "Response Results"
// @Security TokenAuth
// @Summary Total number of flows N3 upstream N6 downstream
// @Description Total number of flows N3 upstream N6 downstream
// @Router /neData/upf/flow-total [get]
func (s UPFController) FlowTotal(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var querys struct {
CoreUID string `form:"coreUid" binding:"required"` // 核心网唯一标识
NeUID string `form:"neUid" binding:"required"` // 网元唯一标识
Day int `form:"day"`
}
if err := c.ShouldBindQuery(&querys); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
return
}
if querys.Day < 0 || querys.Day > 30 {
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "day must be between 0 and 30"))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.FindByCoreUidAndNeUid(querys.CoreUID, querys.NeUID)
if neInfo.CoreUID != querys.CoreUID || neInfo.NeUID != querys.NeUID {
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
up, down := s.kpiReportService.UPFTodayFlowFind(neInfo.NeUID, querys.Day)
c.JSON(200, resp.OkData(map[string]int64{"up": up, "down": down}))
}

View File

@@ -0,0 +1,39 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// AlarmHistory 告警历史记录
func AlarmHistory(neInfo model.NeInfo) ([]map[string]any, error) {
// 网元参数配置信息
neUrl := fmt.Sprintf("http://%s:%d/api/rest/faultManagement/v1/elementType/%s/objectType/alarms", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType))
resBytes, err := fetch.Get(neUrl, nil, 60_000)
var resData []map[string]any
if err != nil {
errStr := err.Error()
logger.Warnf("AlarmHistory Get \"%s\"", neUrl)
if !(strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "202") || strings.HasPrefix(errStr, "204")) {
logger.Errorf("AlarmHistory %s", err.Error())
return nil, fmt.Errorf("NeService Alarm History Info API Error")
}
}
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("AlarmHistory Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}

View File

@@ -0,0 +1,105 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// AMFNbInfoList AMF基站信息
//
// 查询参数 {"id":"7"}
//
// 返回结果 []
func AMFNbInfoList(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/amf/objectType/nbInfo", neInfo.IPAddr, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["id"]; ok && v != "" {
query = append(query, fmt.Sprintf("nbId=%s", v))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
var resData map[string]any
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("AMFNbInfoList Get \"%s\"", neUrl)
logger.Errorf("AMFNbInfoList %s", errStr)
return nil, fmt.Errorf("NeService AMF API Error")
}
// 序列化结果 {"data":[{"id":"7","name":"NR-SA-GNB","address":"192.168.5.100:60110","ueNum":0}]}
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("AMFNbInfoList Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
if arr := v.([]any); len(arr) > 0 {
result := make([]map[string]any, len(arr))
for i, item := range arr {
result[i] = item.(map[string]any)
}
return result, nil
}
}
return []map[string]any{}, nil
}
// AMFGnbStateList AMF基站状态信息对比配置项gnbList
//
// 返回结果 []
func AMFGnbStateList(neInfo model.NeInfo) ([]map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/amf/objectType/nbState", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("AMFGnbStateList Get \"%s\"", neUrl)
logger.Errorf("AMFGnbStateList %s", errStr)
return nil, fmt.Errorf("NeService AMF API Error")
}
// 序列化结果
// {
// "data": [
// {
// "index": 1,
// "name": "Gnb",
// "address": "192.168.8.1",
// "position": "Area-B",
// "offTime": "2024-12-30T16:31:57+08:00",
// "onTime": "2024-12-30T15:41:59+08:00",
// "state": "OFF",
// "nbName": "SA",
// "ueNum": 1
// },
// ]
// }
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("AMFGnbStateList Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
if arr := v.([]any); len(arr) > 0 {
result := make([]map[string]any, len(arr))
for i, item := range arr {
result[i] = item.(map[string]any)
}
return result, nil
}
}
return []map[string]any{}, nil
}

View File

@@ -0,0 +1,68 @@
// 网元HLR服务8080端口。
// 融合到UDM网元也许是UDM的HLR服务。
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// HLRTraceStart HLR跟踪任务开始
//
// data参数 {traceID:"跟踪任务ID", imsi:"IMSI和MSISDN必填一个都带的话以IMSI为准", msisdn:""}
func HLRTraceStart(neInfo model.NeInfo, data map[string]any) (string, error) {
// 网元参数配置新增array
neUrl := fmt.Sprintf("http://%s:%d/trace-manage/v1/add-task", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
var resData map[string]string
if err != nil {
errStr := err.Error()
logger.Warnf("HLRTraceStart Post \"%s\"", neUrl)
logger.Errorf("HLRTraceStart %s", errStr)
return "", fmt.Errorf("NeService HLR API Error")
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("HLRTraceStart Unmarshal %s", err.Error())
return "", err
}
if v, ok := resData["code"]; ok && v == "0" {
return strings.TrimSpace(strings.ToLower(resData["message"])), nil
}
return "", fmt.Errorf("%s", resData["message"])
}
// HLRTraceStop HLR跟踪任务停止
//
// data参数 {traceIDArray: ["跟踪任务ID数组"]}
func HLRTraceStop(neInfo model.NeInfo, data map[string]any) (string, error) {
// 网元参数配置新增array
neUrl := fmt.Sprintf("http://%s:%d/trace-manage/v1/delete-task", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
var resData map[string]string
if err != nil {
errStr := err.Error()
logger.Warnf("HLRTraceStop Post \"%s\"", neUrl)
logger.Errorf("HLRTraceStop %s", errStr)
return "", fmt.Errorf("NeService HLR API Error")
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("HLRTraceStop Unmarshal %s", err.Error())
return "", err
}
if v, ok := resData["code"]; ok && v == "0" {
return strings.TrimSpace(strings.ToLower(resData["message"])), nil
}
return "", fmt.Errorf("%s", resData["message"])
}

View File

@@ -0,0 +1,100 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_element/model"
)
// IMSUeSessionNum IMS会话数量
//
// 返回结果 0
func IMSUeSessionNum(neInfo model.NeInfo) (int64, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/ims/objectType/ueNum", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("IMSUeSessionNum Get \"%s\"", neUrl)
logger.Errorf("IMSUeSessionNum %s", errStr)
return 0, fmt.Errorf("NeService IMS API Error")
}
// 序列化结果 {"data":{"ueNum":0}}
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("IMSUeSessionNum Unmarshal %s", err.Error())
return 0, err
}
// 固定返回字段,方便前端解析
var ueNum int64 = 0
if v, ok := resData["data"]; ok && v != nil {
if num := v.(map[string]any)["ueNum"]; num != nil {
ueNum = parse.Number(num)
}
}
return ueNum, nil
}
// IMSUeSessionList IMS会话列表
//
// 查询参数 {"imsi":"460001230000002","msisdn":"12307551232"}
//
// 返回结果 []
func IMSUeSessionList(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/ims/objectType/ueInfo", neInfo.IPAddr, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["imsi"]; ok && v != "" {
query = append(query, fmt.Sprintf("imsi=%s", v))
}
if v, ok := data["msisdn"]; ok && v != "" {
query = append(query, fmt.Sprintf("msisdn=%s", v))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("IMSUeSessionList Get \"%s\"", neUrl)
logger.Errorf("IMSUeSessionList %s", errStr)
return nil, fmt.Errorf("NeService IMS API Error")
}
// 序列化结果
// { "data":[
// {
// "activeTime": "2023-11-29 17:04:54",
// "barring": 0,
// "impu": "sip:12307551232@ims.mnc000.mcc460.3gppnetwork.org",
// "imsi": "460001230000002",
// "msisdn": "12307551232",
// "regState": 1
// }
// ] }
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("IMSUeSessionList Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
if arr := v.([]any); len(arr) > 0 {
result := make([]map[string]any, len(arr))
for i, item := range arr {
result[i] = item.(map[string]any)
}
return result, nil
}
}
return []map[string]any{}, nil
}

View File

@@ -0,0 +1,105 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// MMENbInfoList MME基站信息
//
// 查询参数 {"id":"7"}
//
// 返回结果 []
func MMENbInfoList(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/mme/objectType/nbInfo", neInfo.IPAddr, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["id"]; ok && v != "" {
query = append(query, fmt.Sprintf("nbId=%s", v))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
var resData map[string]any
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("MMENbInfoList Get \"%s\"", neUrl)
logger.Errorf("MMENbInfoList %s", errStr)
return nil, fmt.Errorf("NeService MME API Error")
}
// 序列化结果 {"data":[{"id":"7","name":"NR-SA-GNB","address":"192.168.5.100:60110","ueNum":0}]}
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("MMENbInfoList Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
if arr := v.([]any); len(arr) > 0 {
result := make([]map[string]any, len(arr))
for i, item := range arr {
result[i] = item.(map[string]any)
}
return result, nil
}
}
return []map[string]any{}, nil
}
// MMEEnbStateList MME基站状态信息对比配置项enbList
//
// 返回结果 []
func MMEEnbStateList(neInfo model.NeInfo) ([]map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/mme/objectType/nbState", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("MMEEnbStateList Get \"%s\"", neUrl)
logger.Errorf("MMEEnbStateList %s", errStr)
return nil, fmt.Errorf("NeService MME API Error")
}
// 序列化结果
// {
// "data": [
// {
// "index": 1,
// "name": "Enb",
// "address": "192.168.8.1",
// "position": "Area-B",
// "offTime": "2024-12-30T16:31:57+08:00",
// "onTime": "2024-12-30T15:41:59+08:00",
// "state": "OFF",
// "nbName": "SA",
// "ueNum": 1
// },
// ]
// }
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("MMEEnbStateList Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
if arr := v.([]any); len(arr) > 0 {
result := make([]map[string]any, len(arr))
for i, item := range arr {
result[i] = item.(map[string]any)
}
return result, nil
}
}
return []map[string]any{}, nil
}

View File

@@ -0,0 +1,170 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// NeConfigOMC 网元配置对端网管信息
func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) {
// 网元配置对端网管信息
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType))
resBytes, err := fetch.PutJSON(neUrl, map[string]any{
"neId": neInfo.ID,
"neName": neInfo.NeName,
"port": neInfo.Port,
"province": neInfo.Province,
"pvFlag": neInfo.PvFlag,
"rmUID": neInfo.NeUID,
"vendorName": neInfo.VendorName,
"dn": neInfo.Dn,
}, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
return resData, nil
}
logger.Warnf("NeConfigOMC Put \"%s\"", neUrl)
logger.Errorf("NeConfigOMC %s", errStr)
return nil, fmt.Errorf("NeService Config OMC Update API Error")
}
// 200 成功无数据时
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeConfigOMC Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}
// NeConfigInfo 网元配置信息
func NeConfigInfo(neInfo model.NeInfo, paramName string) (map[string]any, error) {
// 网元参数配置信息
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType), paramName)
resBytes, err := fetch.Get(neUrl, nil, 30_000)
if err != nil {
logger.Warnf("NeConfigInfo Get \"%s\"", neUrl)
logger.Errorf("NeConfigInfo %s", err.Error())
return nil, fmt.Errorf("NeService Config Info API Error")
}
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeConfigInfo Unmarshal %s", err.Error())
return nil, err
}
// 网元参数配置信息为空时是{}需要补充data属性
if _, ok := resData["data"]; !ok {
resData["data"] = []map[string]any{}
}
return resData, nil
}
// NeConfigUpdate 网元配置更新
func NeConfigUpdate(neInfo model.NeInfo, paramName, loc string, data map[string]any) (map[string]any, error) {
// array需要层级
if loc != "" {
loc = fmt.Sprintf("?loc=%v", loc)
}
// 网元参数配置新增array
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s%s", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType), paramName, loc)
resBytes, err := fetch.PutJSON(neUrl, data, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
logger.Warnf("NeConfigUpdate Put \"%s\"", neUrl)
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
return resData, nil
}
logger.Errorf("NeConfigUpdate %s", errStr)
return nil, fmt.Errorf("NeService Config Update API Error")
}
// 200 成功无数据时
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeConfigUpdate Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}
// NeConfigAdd 网元配置新增 array
func NeConfigAdd(neInfo model.NeInfo, paramName, loc string, data map[string]any) (map[string]any, error) {
// 网元参数配置新增array
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s?loc=%v", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType), paramName, loc)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
logger.Warnf("NeConfigAdd Post \"%s\"", neUrl)
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
return resData, nil
}
logger.Errorf("NeConfigAdd %s", errStr)
return nil, fmt.Errorf("NeService Config Add API Error")
}
// 200 成功无数据时
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeConfigAdd Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}
// NeConfigDelete 网元配置删除 array
func NeConfigDelete(neInfo model.NeInfo, paramName, loc string) (map[string]any, error) {
// 网元参数配置删除array
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s?loc=%v", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType), paramName, loc)
resBytes, err := fetch.Delete(neUrl, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
logger.Warnf("NeConfigDelete Delete \"%s\"", neUrl)
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
return resData, nil
}
logger.Errorf("NeConfigDelete %s", errStr)
return nil, fmt.Errorf("NeService Config Update API Error")
}
// 200 成功无数据时
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeConfigInfoDel Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}

View File

@@ -0,0 +1,60 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"time"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// NeState 获取网元端服务状态
func NeState(neInfo model.NeInfo) (map[string]any, error) {
// 网元状态
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IPAddr, neInfo.Port, strings.ToLower(neInfo.NeType))
resBytes, err := fetch.Get(neUrl, nil, 1000)
if err != nil {
logger.Errorf("NeState %s", err.Error())
return nil, fmt.Errorf("NeService System State API Error")
}
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeState Unmarshal %s", err.Error())
return nil, err
}
// 检查是否有许可时间
if v, ok := resData["expiryDate"]; ok && v != nil {
expiryDate := v.(string)
// UPF存在2000的许可时间MME会有空字符
if strings.HasPrefix(expiryDate, "2000") || expiryDate == "" {
logger.Warnf("NeState %s License Expiration Aanomaly. Get \"%s\"", neInfo.NeType, neUrl)
return nil, fmt.Errorf("%s License Expiration Aanomaly", neInfo.NeType)
}
}
return map[string]any{
"coreUid": neInfo.CoreUID,
"neUid": neInfo.NeUID,
"neType": neInfo.NeType,
"neName": neInfo.NeName,
"neIP": neInfo.IPAddr,
"refreshTime": time.Now().UnixMilli(), // 获取时间
"standby": resData["standby"], // 是否备用服务
"version": resData["version"],
"capability": resData["capability"],
"sn": resData["serialNum"],
"expire": resData["expiryDate"],
"hostname": resData["hostName"],
"os": resData["osInfo"],
"cpu": resData["cpuUsage"],
"mem": resData["memUsage"],
"disk": resData["diskSpace"],
}, nil
}

View File

@@ -0,0 +1,69 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// NeTraceAdd 网元跟踪任务新增
func NeTraceAdd(neInfo model.NeInfo, data any) (map[string]any, error) {
// 跟踪任务创建
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v2/%s/subscriptions", neInfo.IPAddr, neInfo.Port, neInfo.NeType)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
if !(strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "400")) {
logger.Warnf("NeTraceAdd POST \"%s\"", neUrl)
logger.Errorf("NeTraceAdd %s", errStr)
return nil, fmt.Errorf("NeService Trace Add API Error")
}
}
// 200 成功无数据时
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeTraceAdd Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}
// NeTraceDelete 网元跟踪任务删除
func NeTraceDelete(neInfo model.NeInfo, traceId string) (map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v2/%s/subscriptions?id=%s", neInfo.IPAddr, neInfo.Port, neInfo.NeType, traceId)
resBytes, err := fetch.Delete(neUrl, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
return resData, nil
}
logger.Warnf("NeTraceDelete Delete \"%s\"", neUrl)
logger.Errorf("NeTraceDelete %s", errStr)
return nil, fmt.Errorf("NeService Trace Delete API Error")
}
// 200 成功无数据时
if len(resBytes) == 0 {
return resData, nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("NeTraceDelete Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}

View File

@@ -0,0 +1,280 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// PCFRuleInfo PCF策略配置查询信息
func PCFRuleInfo(neInfo model.NeInfo, data map[string]string) ([]map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo", neInfo.IPAddr, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["imsi"]; ok && v != "" {
query = append(query, fmt.Sprintf("imsi=%s", v))
}
if v, ok := data["msisdn"]; ok && v != "" {
query = append(query, fmt.Sprintf("msisdn=%s", v))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
var resData map[string]any
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("PCFRuleInfo Get \"%s\"", neUrl)
logger.Errorf("PCFRuleInfo %s", errStr)
return nil, fmt.Errorf("NeService PCF API Error")
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleInfo Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
if arr := v.([]any); len(arr) > 0 {
result := make([]map[string]any, len(arr))
for i, item := range arr {
result[i] = item.(map[string]any)
}
return result, nil
}
}
return []map[string]any{}, nil
}
// PCFRuleAdd PCF策略配置添加
func PCFRuleAdd(neInfo model.NeInfo, data any) error {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
if err != nil {
errStr := err.Error()
// 正常
if strings.HasPrefix(errStr, "201") {
return nil
}
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleAdd Unmarshal %s", err.Error())
return err
}
return fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleAdd Put \"%s\"", neUrl)
logger.Errorf("PCFRuleAdd %s", errStr)
return fmt.Errorf("NeService PCF API Error")
}
return nil
}
// PCFRuleAddBatch PCF策略配置批量添加
func PCFRuleAddBatch(neInfo model.NeInfo, data map[string]any, num int64) error {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/%d", neInfo.IPAddr, neInfo.Port, num)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
if err != nil {
errStr := err.Error()
// 正常
if strings.HasPrefix(errStr, "201") {
return nil
}
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleAddBatch Unmarshal %s", err.Error())
return err
}
return fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleAddBatch Put \"%s\"", neUrl)
logger.Errorf("PCFRuleAddBatch %s", errStr)
return fmt.Errorf("NeService PCF API Error")
}
return nil
}
// PCFRuleUpdate PCF策略配置修改
func PCFRuleUpdate(neInfo model.NeInfo, data map[string]any) error {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.PutJSON(neUrl, data, nil)
if err != nil {
errStr := err.Error()
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleUpdate Unmarshal %s", err.Error())
return err
}
return fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleUpdate Put \"%s\"", neUrl)
logger.Errorf("PCFRuleUpdate %s", errStr)
return fmt.Errorf("NeService PCF API Error")
}
return nil
}
// PCFRuleUpdateBatch PCF策略配置批量修改
func PCFRuleUpdateBatch(neInfo model.NeInfo, data map[string]any, num int64) error {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/%d", neInfo.IPAddr, neInfo.Port, num)
resBytes, err := fetch.PutJSON(neUrl, data, nil)
if err != nil {
errStr := err.Error()
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleUpdateBatch Unmarshal %s", err.Error())
return err
}
return fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleUpdateBatch Put \"%s\"", neUrl)
logger.Errorf("PCFRuleUpdateBatch %s", errStr)
return fmt.Errorf("NeService PCF API Error")
}
return nil
}
// PCFRuleDelete PCF策略配置删除
func PCFRuleDelete(neInfo model.NeInfo, imsi string) error {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo?imsi=%s", neInfo.IPAddr, neInfo.Port, imsi)
resBytes, err := fetch.Delete(neUrl, nil)
if err != nil {
errStr := err.Error()
// 正常
if strings.HasPrefix(errStr, "204") {
return nil
}
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleDelete Unmarshal %s", err.Error())
return err
}
return fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleDelete Delete \"%s\"", neUrl)
logger.Errorf("PCFRuleDelete %s", errStr)
return fmt.Errorf("NeService PCF API Error")
}
return nil
}
// PCFRuleDeleteBatch PCF策略配置批量删除
func PCFRuleDeleteBatch(neInfo model.NeInfo, imsi string, num int64) error {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/batch/%d?imsi=%s", neInfo.IPAddr, neInfo.Port, num, imsi)
resBytes, err := fetch.Delete(neUrl, nil)
if err != nil {
errStr := err.Error()
// 正常
if strings.HasPrefix(errStr, "204") {
return nil
}
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleDeleteBatch Unmarshal %s", err.Error())
return err
}
return fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleDeleteBatch Delete \"%s\"", neUrl)
logger.Errorf("PCFRuleDeleteBatch %s", errStr)
return fmt.Errorf("NeService PCF API Error")
}
return nil
}
// PCFRuleExport PCF策略配置导出
func PCFRuleExport(neInfo model.NeInfo, data map[string]string) ([]byte, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/file/export", neInfo.IPAddr, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["fileType"]; ok && v != "" {
query = append(query, fmt.Sprintf("fileType=%s", v))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
resBytes, err := fetch.Get(neUrl, nil, 30_000)
if err != nil {
logger.Warnf("PCFRuleExport Get \"%s\"", neUrl)
logger.Errorf("PCFRuleExport %s", err.Error())
return nil, fmt.Errorf("NeService PCF API Error")
}
return resBytes, nil
}
// PCFRuleImport PCF策略配置导入
func PCFRuleImport(neInfo model.NeInfo, data map[string]any) (string, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/pcf/objectType/ueInfo/file/import", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.PutJSON(neUrl, data, nil)
var resData map[string]any
if err != nil {
errStr := err.Error()
// 错误结果
if strings.HasPrefix(errStr, "400") {
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleDeleteBatch Unmarshal %s", err.Error())
return "", err
}
return "", fmt.Errorf("%s", resData["cause"])
}
logger.Warnf("PCFRuleImport Put \"%s\"", neUrl)
logger.Errorf("PCFRuleImport %s", errStr)
return "", fmt.Errorf("NeService PCF API Error")
}
// 200 成功无数据时
if len(resBytes) == 0 {
return "", nil
}
// 序列化结果
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("PCFRuleImport Unmarshal %s", err.Error())
return "", err
}
return fmt.Sprint(resData["data"]), nil
}

View File

@@ -0,0 +1,98 @@
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/network_element/model"
)
// SMFSubNum SMF在线订阅用户数量 只含5G用户数据
//
// 返回结果 0
func SMFSubNum(neInfo model.NeInfo) (int64, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/smf/objectType/ueNum", neInfo.IPAddr, neInfo.Port)
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
errStr := err.Error()
logger.Warnf("SMFSubNum Get \"%s\"", neUrl)
logger.Errorf("SMFSubNum %s", errStr)
return 0, fmt.Errorf("NeService SMF API Error")
}
// 序列化结果 {"data":{"ueNum":0}}
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("IMSUeSession Unmarshal %s", err.Error())
return 0, err
}
// 固定返回字段,方便前端解析
var ueNum int64 = 0
if v, ok := resData["data"]; ok && v != nil {
if num := v.(map[string]any)["ueNum"]; num != nil {
ueNum = parse.Number(num)
}
}
return ueNum, nil
}
// SMFSubInfoList SMF在线订阅用户列表信息
//
// 查询参数 {"imsi":"360000100000130","msisdn":"8612300000130","upstate":"Inactive","pageNum":"1"}
//
// 返回结果 {"rows":[],"total":0}
func SMFSubInfoList(neInfo model.NeInfo, data map[string]string) (map[string]any, error) {
neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo", neInfo.IPAddr, neInfo.Port)
// 查询参数拼接
query := []string{}
if v, ok := data["imsi"]; ok && v != "" {
query = append(query, fmt.Sprintf("imsi=%s", v))
}
if v, ok := data["msisdn"]; ok && v != "" {
query = append(query, fmt.Sprintf("msisdn=%s", v))
}
if v, ok := data["upstate"]; ok && v != "" {
query = append(query, fmt.Sprintf("upstate=%s", v))
}
// 固定页数量50条
if v, ok := data["pageNum"]; ok && v != "" {
pageNum := parse.Number(v)
query = append(query, fmt.Sprintf("pageNum=%d", pageNum))
}
if len(query) > 0 {
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
}
resBytes, err := fetch.Get(neUrl, nil, 60_000)
if err != nil {
logger.Warnf("SMFSubInfo Get \"%s\"", neUrl)
logger.Errorf("SMFSubInfo %s", err.Error())
return nil, fmt.Errorf("NeService SMF API Error")
}
// 序列化结果 {"data":[],"total":0}
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Errorf("SMFSubInfo Unmarshal %s", err.Error())
return nil, err
}
// 固定返回字段,方便前端解析
if v, ok := resData["data"]; ok && v != nil {
resData["rows"] = v.([]any)
delete(resData, "data")
} else {
resData["rows"] = []any{}
}
if v, ok := resData["total"]; !ok || v == nil {
resData["total"] = 0
}
return resData, nil
}

View File

@@ -0,0 +1,39 @@
// 网元UDM服务可能是8080、33030端口服务
// 融合的UDM网元视情况调整。
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
)
// UDMImportAuth UDM导入鉴权数据
//
// data参数 {path:"服务器文件路径", k4:"可选k4为空时Ki不加密。"}
func UDMImportAuth(udmIP string, data map[string]any) (string, error) {
// 网元参数配置新增array
neUrl := fmt.Sprintf("http://%s:8080/ue-manage/v1/import-auth", udmIP)
resBytes, err := fetch.PostJSON(neUrl, data, nil)
var resData map[string]string
if err != nil {
errStr := err.Error()
logger.Warnf("UDMImportAuth Post \"%s\"", neUrl)
logger.Errorf("UDMImportAuth %s", errStr)
return "", fmt.Errorf("NeService UDM API Error")
}
// 序列化结果
if err = json.Unmarshal(resBytes, &resData); err != nil {
logger.Errorf("UDMImportAuth Unmarshal %s", err.Error())
return "", err
}
if v, ok := resData["code"]; ok && v == "00000" {
return strings.TrimSpace(strings.ToLower(resData["message"])), nil
}
return "", fmt.Errorf("%s", resData["message"])
}

View File

@@ -0,0 +1,19 @@
package model
// UDMAuthUser UDM鉴权用户 udm_auth
type UDMAuthUser struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
Amf string `json:"amf" gorm:"column:amf"` // AMF
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
}
// TableName 表名称
func (*UDMAuthUser) TableName() string {
return "udm_auth"
}

View File

@@ -0,0 +1,17 @@
package model
// UDMExtend UDM用户IMSI扩展信息 udm_extend
type UDMExtend struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
Remark string `json:"remark" gorm:"column:remark"` // 备注
}
// TableName 表名称
func (*UDMExtend) TableName() string {
return "udm_extend"
}

View File

@@ -0,0 +1,50 @@
package model
// UDMSubUser UDM签约用户 udm_sub
type UDMSubUser struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
AmDat string `json:"amDat" gorm:"column:am_dat"` // AmData
UeAmbrTpl string `json:"ambr" gorm:"column:ambr"` // AmData SubUeAMBRTemp
NssaiTpl string `json:"nssai" gorm:"column:nssai"` // AmData SubSNSSAITemp
RatRestrictions string `json:"rat" gorm:"column:rat"` // AmData RAT 0x00:VIRTUAL 0x01:WLAN 0x02:EUTRA 0x03:NR
AreaForbiddenTpl string `json:"arfb" gorm:"column:arfb"` // AmData AreaForbidden
ServiceAreaRestrictionTpl string `json:"sar" gorm:"column:sar"` // AmData serviceAreaRestrictTemp
CnTypeRestrictions string `json:"cnType" gorm:"column:cn_type"` // AmData CNType 0x00:EPC和5GC 0x01:5GC 0x02:EPC 0x03:EPC+5GC
RfspIndex string `json:"rfspIndex" gorm:"column:rfsp_index"` // AmData RfspIndex
SubsRegTime string `json:"regTimer" gorm:"column:reg_timer"` // AmData RegTimer
UeUsageType string `json:"ueUsageType" gorm:"column:ue_usage_type"` // AmData UEUsageType
ActiveTime string `json:"activeTime" gorm:"column:active_time"` // AmData ActiveTime
MicoAllowed string `json:"mico" gorm:"column:mico"` // AmData MICO
OdbPs string `json:"odbPs" gorm:"column:odb_ps"` // AmData ODB_PS 0-all,1-hplmn,2-vplmn
GroupId string `json:"groupId" gorm:"column:group_id"` // AmData GroupId
EpsDat string `json:"epsDat" gorm:"column:eps_dat"` // EpsDat
EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"` // EpsDat epsFlag
EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"` // EpsDat epsOdb
HplmnOdb string `json:"hplmnOdb" gorm:"column:hplmn_odb"` // EpsDat hplmnOdb
Ard string `json:"ard" gorm:"column:ard"` // EpsDat Ard
Epstpl string `json:"epstpl" gorm:"column:epstpl"` // EpsDat Epstpl
ContextId string `json:"contextId" gorm:"column:context_id"` // EpsDat ContextId
ApnNum string `json:"apnNum" gorm:"column:apn_mum"` // EpsDat apnNum
ApnContext string `json:"apnContext" gorm:"column:apn_context"` // EpsDat apnContext
StaticIp string `json:"staticIp" gorm:"column:static_ip"` // EpsDat staticIp 指给4G UE分配的静态IP没有可不带此字段名
SmData string `json:"smData" gorm:"column:sm_data"` // smData
SmfSel string `json:"smfSel" gorm:"column:smf_sel"` // smfSel
Cag string `json:"cag" gorm:"column:cag"` // CAG
// ====== 非数据库字段属性 ======
Remark string `json:"remark,omitempty" gorm:"-"` // 备注
}
// TableName 表名称
func (*UDMSubUser) TableName() string {
return "udm_sub"
}

View File

@@ -0,0 +1,17 @@
package model
// UDMVOIPUser UDMVOIP用户 udm_voip
type UDMVOIPUser struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
UserName string `json:"username" gorm:"column:username"` // 用户名
Password string `json:"password" gorm:"column:password"` // 密码
}
// TableName 表名称
func (*UDMVOIPUser) TableName() string {
return "udm_voip"
}

View File

@@ -0,0 +1,19 @@
package model
// UDMVolteIMSUser UDMVolteIMS用户 udm_volte_ims
type UDMVolteIMSUser struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
CoreUID string `json:"coreUid" gorm:"column:core_uid"` // 核心网唯一标识
NeUID string `json:"neUid" gorm:"column:ne_uid"` // 网元唯一标识
NeType string `json:"neType" gorm:"column:ne_type"` // 网元类型
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
Tag string `json:"tag" gorm:"column:tag"` // 0=VoIP, 1=VoLTE
VNI string `json:"vni" gorm:"column:vni"` // VNI
}
// TableName 表名称
func (*UDMVolteIMSUser) TableName() string {
return "udm_volte_ims"
}

View File

@@ -0,0 +1,373 @@
package networklink
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_link/controller"
"github.com/gin-gonic/gin"
)
// 模块路由注册
func Setup(router *gin.Engine) {
logger.Infof("开始加载 ====> network_link 模块路由")
neDataGroup := router.Group("/ne/link")
// 网元IMS
imsGroup := neDataGroup.Group("/ims")
{
imsGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewIMS.CDRList,
)
imsGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewIMS.CDRRemove,
)
imsGroup.POST("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewIMS.CDRExport,
)
imsGroup.GET("/session/num",
middleware.AuthorizeUser(nil),
controller.NewIMS.UeSessionNum,
)
imsGroup.GET("/session/list",
middleware.AuthorizeUser(nil),
controller.NewIMS.UeSessionList,
)
}
// 网元SMSC
smscGroup := neDataGroup.Group("/smsc")
{
smscGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewSMSC.CDRList,
)
smscGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMSC.CDRRemove,
)
smscGroup.POST("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMSC.CDRExport,
)
}
// 网元SMF
smfGroup := neDataGroup.Group("/smf")
{
smfGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewSMF.CDRList,
)
smfGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMF.CDRRemove,
)
smfGroup.POST("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMF.CDRExport,
)
smfGroup.GET("/sub/num",
middleware.AuthorizeUser(nil),
controller.NewSMF.SubUserNum,
)
smfGroup.GET("/sub/list",
middleware.AuthorizeUser(nil),
controller.NewSMF.SubUserList,
)
}
// 网元AMF
amfGroup := neDataGroup.Group("/amf")
{
amfGroup.GET("/ue/list",
middleware.AuthorizeUser(nil),
controller.NewAMF.UEList,
)
amfGroup.DELETE("/ue/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewAMF.UERemove,
)
amfGroup.POST("/ue/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewAMF.UEExport,
)
amfGroup.GET("/nb/list",
middleware.AuthorizeUser(nil),
controller.NewAMF.NbInfoList,
)
amfGroup.GET("/nb/list-cfg",
middleware.AuthorizeUser(nil),
controller.NewAMF.NbStateList,
)
}
// 网元UPF
upfGroup := neDataGroup.Group("/upf")
{
upfGroup.GET("/flow-total",
middleware.AuthorizeUser(nil),
controller.NewUPF.FlowTotal,
)
}
// 网元UDM 鉴权用户信息
udmAuthGroup := neDataGroup.Group("/udm/auth")
{
udmAuthGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMAuth.ResetData,
)
udmAuthGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMAuth.List,
)
udmAuthGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMAuth.Info,
)
udmAuthGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMAuth.Add,
)
udmAuthGroup.PUT("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMAuth.Edit,
)
udmAuthGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMAuth.Remove,
)
udmAuthGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMAuth.Export,
)
udmAuthGroup.POST("/import",
middleware.AuthorizeUser(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.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMSub.ResetData,
)
udmSubGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMSub.List,
)
udmSubGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMSub.Info,
)
udmSubGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMSub.Add,
)
udmSubGroup.PUT("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMSub.Edit,
)
udmSubGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMSub.Remove,
)
udmSubGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMSub.Export,
)
udmSubGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMSub.Import,
)
}
// 网元UDM VOIP用户信息
udmVOIPGroup := neDataGroup.Group("/udm/voip")
{
udmVOIPGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMVOIP.ResetData,
)
udmVOIPGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMVOIP.List,
)
udmVOIPGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMVOIP.Info,
)
udmVOIPGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMVOIP.Add,
)
udmVOIPGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMVOIP.Remove,
)
udmVOIPGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMVOIP.Export,
)
udmVOIPGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMVOIP.Import,
)
}
// 网元UDM VolteIMS用户信息
udmVolteIMSGroup := neDataGroup.Group("/udm/volte-ims")
{
udmVolteIMSGroup.PUT("/reset",
repeat.RepeatSubmit(5),
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMVolteIMS.ResetData,
)
udmVolteIMSGroup.GET("/list",
middleware.AuthorizeUser(nil),
controller.NewUDMVolteIMS.List,
)
udmVolteIMSGroup.GET("",
middleware.AuthorizeUser(nil),
controller.NewUDMVolteIMS.Info,
)
udmVolteIMSGroup.POST("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMVolteIMS.Add,
)
udmVolteIMSGroup.DELETE("",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMVolteIMS.Remove,
)
udmVolteIMSGroup.GET("/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMVolteIMS.Export,
)
udmVolteIMSGroup.POST("/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMVolteIMS.Import,
)
}
// 网元MME
mmeGroup := neDataGroup.Group("/mme")
{
mmeGroup.GET("/ue/list",
middleware.AuthorizeUser(nil),
controller.NewMME.UEList,
)
mmeGroup.DELETE("/ue/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewMME.UERemove,
)
mmeGroup.POST("/ue/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewMME.UEExport,
)
mmeGroup.GET("/nb/list",
middleware.AuthorizeUser(nil),
controller.NewMME.NbInfoList,
)
mmeGroup.GET("/nb/list-cfg",
middleware.AuthorizeUser(nil),
controller.NewMME.NbStateList,
)
}
// 网元SGWC
sgwcGroup := neDataGroup.Group("/sgwc")
{
sgwcGroup.GET("/cdr/list",
middleware.AuthorizeUser(nil),
controller.NewSGWC.CDRList,
)
sgwcGroup.DELETE("/cdr/:id",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSGWC.CDRRemove,
)
sgwcGroup.POST("/cdr/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSGWC.CDRExport,
)
}
// 网元PCF
pcfGroup := neDataGroup.Group("/pcf")
{
pcfGroup.GET("/rule/list",
middleware.AuthorizeUser(nil),
controller.NewPCF.RuleInfoList,
)
pcfGroup.POST("/rule",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewPCF.RuleInfoAdd,
)
pcfGroup.PUT("/rule",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewPCF.RuleInfoEdit,
)
pcfGroup.DELETE("/rule",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewPCF.RuleInfoRemove,
)
pcfGroup.GET("/rule/export",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewPCF.RuleInfoExport,
)
pcfGroup.PUT("/rule/import",
middleware.AuthorizeUser(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.pcfRule", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewPCF.RuleInfoImport,
)
}
}

View File

@@ -0,0 +1,149 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/network_link/model"
)
// 实例化数据层 UDMAuthUser 结构体
var NewUDMAuthUser = &UDMAuthUser{}
// UDMAuthUser UDM鉴权信息表 数据层处理
type UDMAuthUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r *UDMAuthUser) ClearAndInsert(coreUid, neUid string, uArr []model.UDMAuthUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_auth", nil)
result := db.DB("").Where("core_uid = ? and ne_id = ?", coreUid, neUid).Unscoped().Delete(&model.UDMAuthUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
func (r *UDMAuthUser) SelectPage(query map[string]string) (int64, []model.UDMAuthUser) {
tx := db.DB("").Model(&model.UDMAuthUser{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_id = ?", v)
}
if v, ok := query["imsis"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("imsi in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMAuthUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return total, rows
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return total, rows
}
// SelectList 根据实体查询
func (r *UDMAuthUser) SelectList(u model.UDMAuthUser) []model.UDMAuthUser {
tx := db.DB("").Model(&model.UDMAuthUser{})
// 查询条件拼接
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
// 查询数据
arr := []model.UDMAuthUser{}
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByIMSI 通过imsi和ne_id查询
func (r *UDMAuthUser) SelectByIMSI(coreUid, neUid, imsi string) model.UDMAuthUser {
tx := db.DB("").Model(&model.UDMAuthUser{})
item := model.UDMAuthUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
// 查询数据
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r *UDMAuthUser) Inserts(uArr []model.UDMAuthUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除实体
func (r *UDMAuthUser) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
tx.Delete(&model.UDMAuthUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMAuthUser) DeletePrefixByIMSI(coreUid, neUid, imsiPrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsiPrefix))
tx.Delete(&model.UDMAuthUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -0,0 +1,130 @@
package repository
import (
"fmt"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/network_link/model"
)
// 实例化数据层 UDMExtend 结构体
var NewUDMExtend = &UDMExtend{}
// UDMExtend UDM鉴权信息表 数据层处理
type UDMExtend struct{}
// SelectByPage 分页查询集合
func (r UDMExtend) SelectByPage(query map[string]string) ([]model.UDMExtend, int64) {
tx := db.DB("").Model(&model.UDMExtend{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
// 查询结果
var total int64 = 0
rows := []model.UDMExtend{}
// 查询数量为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return rows, total
}
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortField := v
if o, ok := query["sortOrder"]; ok && o != "" {
sortField = sortField + " desc"
}
tx = tx.Order(sortField)
}
// 查询数据分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Limit(pageSize).Offset(pageSize * pageNum)
err := tx.Find(&rows).Error
if err != nil {
logger.Errorf("query find err => %v", err.Error())
return rows, total
}
return rows, total
}
// SelectList 根据实体查询
func (r *UDMExtend) SelectList(u model.UDMExtend) []model.UDMExtend {
tx := db.DB("").Model(&model.UDMExtend{})
// 构建查询条件
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
tx = tx.Order("imsi asc")
// 查询数据
rows := []model.UDMExtend{}
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query find err => %v", err.Error())
return rows
}
return rows
}
// SelectByIMSI 通过imsi和ne_id查询 neUid为%时模糊imsi查询
func (r *UDMExtend) SelectByIMSI(coreUid, neUid, imsi string) model.UDMExtend {
tx := db.DB("").Model(&model.UDMExtend{})
// 查询条件拼接
if neUid == "%" {
tx = tx.Where("core_uid = ?", coreUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsi))
} else {
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
}
// 查询数据
rows := []model.UDMExtend{}
if err := tx.Limit(1).Find(&rows).Error; err != nil {
logger.Errorf("query find err => %v", err.Error())
}
if len(rows) > 0 {
return rows[0]
}
return model.UDMExtend{}
}
// Insert 批量添加
func (r *UDMExtend) Inserts(uArr []model.UDMExtend) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除实体 neUid为%时模糊imsi前缀
func (r *UDMExtend) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
// 查询条件拼接
if neUid == "%" {
tx = tx.Where("core_uid = ?", coreUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsi))
} else {
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
}
tx = tx.Delete(&model.UDMExtend{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -0,0 +1,151 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/network_link/model"
)
// 实例化数据层 UDMSubUser 结构体
var NewUDMSub = &UDMSubUser{}
// UDMSubUser UDM签约信息表 数据层处理
type UDMSubUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r *UDMSubUser) ClearAndInsert(coreUid, neUid string, u []model.UDMSubUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_sub", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", neUid).Unscoped().Delete(&model.UDMSubUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(u)
}
// SelectPage 根据条件分页查询字典类型
func (r *UDMSubUser) SelectPage(query map[string]string) (int64, []model.UDMSubUser) {
tx := db.DB("").Model(&model.UDMSubUser{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["msisdn"]; ok && v != "" {
tx = tx.Where("msisdn like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["imsis"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("imsi in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMSubUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return total, rows
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return total, rows
}
// SelectList 根据实体查询
func (r *UDMSubUser) SelectList(u model.UDMSubUser) []model.UDMSubUser {
tx := db.DB("").Model(&model.UDMSubUser{})
// 查询条件拼接
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
// 查询数据
arr := []model.UDMSubUser{}
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByIMSIAndNeID 通过imsi查询
func (r *UDMSubUser) SelectByIMSI(coreUid, neUid, imsi string) model.UDMSubUser {
tx := db.DB("").Model(&model.UDMSubUser{})
item := model.UDMSubUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
// 查询数据
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r *UDMSubUser) Inserts(uArr []model.UDMSubUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// DeleteByIMSI 删除实体
func (r *UDMSubUser) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
tx.Delete(&model.UDMSubUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMSubUser) DeletePrefixByIMSI(coreUid, neUid, imsiPrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsiPrefix))
tx.Delete(&model.UDMSubUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -0,0 +1,151 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/network_link/model"
)
// 实例化数据层 UDMVOIPUser 结构体
var NewUDMVOIPUser = &UDMVOIPUser{}
// UDMVOIPUser UDMVOIP用户信息表 数据层处理
type UDMVOIPUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r UDMVOIPUser) ClearAndInsert(coreUid, neUid string, uArr []model.UDMVOIPUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_voip", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", coreUid, neUid).Unscoped().Delete(&model.UDMVOIPUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
func (r UDMVOIPUser) SelectPage(query map[string]string) (int64, []model.UDMVOIPUser) {
tx := db.DB("").Model(&model.UDMVOIPUser{})
// 查询条件拼接
if v, ok := query["username"]; ok && v != "" {
tx = tx.Where("username like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["usernames"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("username in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMVOIPUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return total, rows
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
} else {
tx = tx.Order("username asc")
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return total, rows
}
// SelectList 根据实体查询
func (r UDMVOIPUser) SelectList(u model.UDMVOIPUser) []model.UDMVOIPUser {
tx := db.DB("").Model(&model.UDMVOIPUser{})
// 查询条件拼接
if u.UserName != "" {
tx = tx.Where("username = ?", u.UserName)
}
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
// 查询数据
arr := []model.UDMVOIPUser{}
if err := tx.Order("username asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByUserName 通过username查询
func (r UDMVOIPUser) SelectByUserName(coreUid, neUid, username string) model.UDMVOIPUser {
tx := db.DB("").Model(&model.UDMVOIPUser{})
item := model.UDMVOIPUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("username = ?", username)
// 查询数据
if err := tx.Order("username asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r UDMVOIPUser) Inserts(uArr []model.UDMVOIPUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// DeleteByUserName 删除实体
func (r UDMVOIPUser) DeleteByUserName(coreUid, neUid, username string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("username = ?", username)
tx.Delete(&model.UDMVOIPUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByUserName 删除前缀匹配的实体
func (r UDMVOIPUser) DeletePrefixByUserName(coreUid, neUid, usernamePrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("username like ?", fmt.Sprintf("%s%%", usernamePrefix))
tx.Delete(&model.UDMVOIPUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByUserName err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -0,0 +1,163 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/database/db"
"be.ems/src/framework/logger"
"be.ems/src/modules/network_link/model"
)
// 实例化数据层 UDMVolteIMSUser 结构体
var NewUDMVolteIMSUser = &UDMVolteIMSUser{}
// UDMVolteIMSUser UDMVOIP用户信息表 数据层处理
type UDMVolteIMSUser struct{}
// ClearAndInsert 清空ne_id后新增实体
func (r UDMVolteIMSUser) ClearAndInsert(coreUid, neUid string, uArr []model.UDMVolteIMSUser) int64 {
// 不指定neID时用 TRUNCATE 清空表快
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_volte_ims", nil)
result := db.DB("").Where("core_uid = ? and ne_uid = ?", coreUid, neUid).Unscoped().Delete(&model.UDMVolteIMSUser{})
if result.Error != nil {
logger.Errorf("Delete err => %v", result.Error)
}
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
func (r UDMVolteIMSUser) SelectPage(query map[string]string) (int64, []model.UDMVolteIMSUser) {
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
// 查询条件拼接
if v, ok := query["imsi"]; ok && v != "" {
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["msisdn"]; ok && v != "" {
tx = tx.Where("msisdn like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["coreUid"]; ok && v != "" {
tx = tx.Where("core_uid = ?", v)
}
if v, ok := query["neUid"]; ok && v != "" {
tx = tx.Where("ne_uid = ?", v)
}
if v, ok := query["tag"]; ok && v != "" {
tx = tx.Where("tag = ?", v)
}
if v, ok := query["vni"]; ok && v != "" {
tx = tx.Where("vni like ?", fmt.Sprintf("%%%s%%", v))
}
if v, ok := query["imsis"]; ok && v != "" {
arr := strings.Split(v, ",")
tx = tx.Where("imsi in ?", arr)
// 勾选时pageSize为勾选的数量
query["pageSize"] = fmt.Sprint(len(arr))
}
var total int64 = 0
rows := []model.UDMVolteIMSUser{}
// 查询数量 长度为0直接返回
if err := tx.Count(&total).Error; err != nil || total <= 0 {
return total, rows
}
// 分页
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
// 排序
if v, ok := query["sortField"]; ok && v != "" {
sortSql := v
if o, ok := query["sortOrder"]; ok && o != "" {
if o == "desc" {
sortSql += " desc "
} else {
sortSql += " asc "
}
}
tx = tx.Order(sortSql)
} else {
tx = tx.Order("imsi asc")
}
// 查询数据
if err := tx.Find(&rows).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return total, rows
}
// SelectList 根据实体查询
func (r UDMVolteIMSUser) SelectList(u model.UDMVolteIMSUser) []model.UDMVolteIMSUser {
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
// 查询条件拼接
if u.NeUID != "" {
tx = tx.Where("ne_uid = ?", u.NeUID)
}
if u.CoreUID != "" {
tx = tx.Where("core_uid = ?", u.CoreUID)
}
if u.IMSI != "" {
tx = tx.Where("imsi = ?", u.IMSI)
}
if u.Tag != "" {
tx = tx.Where("tag = ?", u.Tag)
}
// 查询数据
arr := []model.UDMVolteIMSUser{}
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return arr
}
// SelectByIMSIAndMSISDN 通过imsi,msisdn查询
func (r UDMVolteIMSUser) SelectByIMSIAndMSISDN(coreUid, neUid, imsi, msisdn string) model.UDMVolteIMSUser {
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
item := model.UDMVolteIMSUser{}
// 查询条件拼接
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ? and msisdn = ?", imsi, msisdn)
// 查询数据
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
logger.Errorf("query err => %v", err)
}
return item
}
// Insert 批量添加
func (r UDMVolteIMSUser) Inserts(uArr []model.UDMVolteIMSUser) int64 {
tx := db.DB("").CreateInBatches(uArr, 500)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除实体
func (r UDMVolteIMSUser) DeleteByIMSI(coreUid, neUid, imsi string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi = ?", imsi)
tx.Delete(&model.UDMVolteIMSUser{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r UDMVolteIMSUser) DeletePrefixByIMSI(coreUid, neUid, imsiPrefix string) int64 {
tx := db.DB("")
tx = tx.Where("core_uid = ? and ne_uid = ?", coreUid, neUid)
tx = tx.Where("imsi like ?", fmt.Sprintf("%s%%", imsiPrefix))
tx.Delete(&model.UDMVolteIMSUser{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -0,0 +1,203 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/repository"
)
// 实例化服务层 UDMAuthUser 结构体
var NewUDMAuthUser = &UDMAuthUser{
udmAuthRepository: repository.NewUDMAuthUser,
}
// UDM鉴权信息 服务层处理
type UDMAuthUser struct {
// UDM鉴权信息数据信息
udmAuthRepository *repository.UDMAuthUser
}
// dataByRedis UDM鉴权用户 db:0 中 ausf:*
func (r *UDMAuthUser) dataByRedis(coreUid, neUid, imsi string) []model.UDMAuthUser {
arr := []model.UDMAuthUser{}
key := fmt.Sprintf("ausf:%s", imsi)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
ausfArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, ausfArr)
if err != nil {
return arr
}
for k, m := range mkv {
if len(k) != 20 {
continue
}
// 跳过-号数据 ausf:360000100000130
imsi, hasPrefix := strings.CutPrefix(k, "ausf:")
if strings.Contains(imsi, "-") || !hasPrefix {
continue
}
amf := ""
if v, ok := m["amf"]; ok {
amf = strings.Replace(v, "\r\n", "", 1)
}
a := model.UDMAuthUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
IMSI: imsi,
Amf: amf,
Ki: m["ki"],
AlgoIndex: m["algo"],
Opc: m["opc"],
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
func (r *UDMAuthUser) ResetData(coreUid, neUid string) int64 {
authArr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmAuthRepository.ClearAndInsert(coreUid, neUid, authArr)
return int64(len(authArr))
}
// ParseInfo 解析单个用户imsi鉴权信息 data从命令MML得到的结果
func (r *UDMAuthUser) ParseInfo(coreUid, neUid, imsi string, data map[string]string) model.UDMAuthUser {
u := r.udmAuthRepository.SelectByIMSI(coreUid, neUid, imsi)
u.CoreUID = coreUid
u.NeUID = neUid
u.NeType = "UDM"
// 用于更新
u.Amf = data["amf"]
u.Ki = data["ki"]
u.AlgoIndex = data["algo"]
u.Opc = data["opc"]
return u
}
// FindByPage 分页查询数据库
func (r *UDMAuthUser) FindByPage(query map[string]string) (int64, []model.UDMAuthUser) {
return r.udmAuthRepository.SelectPage(query)
}
// Find 查询数据库
func (r *UDMAuthUser) Find(u model.UDMAuthUser) []model.UDMAuthUser {
return r.udmAuthRepository.SelectList(u)
}
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度0或者32
func (r *UDMAuthUser) Insert(coreUid, neUid string, u model.UDMAuthUser) int64 {
uArr := r.dataByRedis(coreUid, neUid, u.IMSI)
if len(uArr) > 0 {
r.udmAuthRepository.DeleteByIMSI(coreUid, neUid, u.IMSI)
return r.udmAuthRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r *UDMAuthUser) InsertData(coreUid, neUid, 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(coreUid, neUid, prefix)
// keys ausf:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
num += r.udmAuthRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r *UDMAuthUser) Delete(coreUid, neUid, imsi string) int64 {
return r.udmAuthRepository.DeleteByIMSI(coreUid, neUid, imsi)
}
// LoadData 重新加载从imsi开始num的数据
func (r *UDMAuthUser) LoadData(coreUid, neUid, imsi string, num int64) {
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
// 删除原数据
r.udmAuthRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
// 加载数据
arr := r.dataByRedis(coreUid, neUid, keyIMSI)
if len(arr) < 1 {
continue
}
r.udmAuthRepository.Inserts(arr)
}
}
// ParseCommandParams 解析数据组成命令参数 ki=xx,xx=xx,...
func (r *UDMAuthUser) ParseCommandParams(item model.UDMAuthUser) string {
var conditions []string
if item.Ki != "" {
conditions = append(conditions, fmt.Sprintf("ki=%s", item.Ki))
}
if item.Amf != "" {
conditions = append(conditions, fmt.Sprintf("amf=%s", item.Amf))
}
if item.AlgoIndex != "" {
conditions = append(conditions, fmt.Sprintf("algo=%s", item.AlgoIndex))
}
if item.Opc != "" {
conditions = append(conditions, fmt.Sprintf("opc=%s", item.Opc))
}
return strings.Join(conditions, ",")
}

View File

@@ -0,0 +1,33 @@
package service
import (
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/repository"
)
// 实例化服务层 UDMExtend 结构体
var NewUDMExtend = &UDMExtend{
UDMExtendRepository: repository.NewUDMExtend,
}
// UDM用户IMSI拓展信息 服务层处理
type UDMExtend struct {
// UDM用户IMSI信息数据信息
UDMExtendRepository *repository.UDMExtend
}
// FindByIMSIAndNeID 通过IMSI和网元标识查询信息 neId为%时模糊imsi查询
func (r UDMExtend) FindByIMSIAndNeID(coreUid, neUid, imsi string) model.UDMExtend {
return r.UDMExtendRepository.SelectByIMSI(coreUid, neUid, imsi)
}
// Save 新增或修改信息
func (r UDMExtend) Save(u model.UDMExtend) bool {
r.UDMExtendRepository.DeleteByIMSI(u.CoreUID, u.NeUID, u.IMSI)
return r.UDMExtendRepository.Inserts([]model.UDMExtend{u}) > 0
}
// Delete 删除信息 neId为%时模糊imsi查询
func (r UDMExtend) Delete(coreUid, neUid, imsi string) int64 {
return r.UDMExtendRepository.DeleteByIMSI(coreUid, neUid, imsi)
}

View File

@@ -0,0 +1,372 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/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(coreUid, neUid, imsi string) []model.UDMSubUser {
arr := []model.UDMSubUser{}
key := fmt.Sprintf("udm-sd:%s", imsi)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
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
}
a := model.UDMSubUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
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(coreUid, neUid string) int64 {
subArr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmSubRepository.ClearAndInsert(coreUid, neUid, subArr)
return int64(len(subArr))
}
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
func (r *UDMSubUser) ParseInfo(coreUid, neUid, imsi string, data map[string]string) model.UDMSubUser {
u := r.udmSubRepository.SelectByIMSI(coreUid, neUid, imsi)
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.CoreUID = coreUid
u.NeUID = neUid
u.NeType = "UDM"
u.IMSI = imsi
u.MSISDN = msisdn
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.SelectByIMSI(coreUid, neUid, imsi)
if info.IMSI == imsi {
u.Remark = info.Remark
}
return u
}
// FindByPage 分页查询数据库
func (r *UDMSubUser) FindByPage(query map[string]string) (int64, []model.UDMSubUser) {
return r.udmSubRepository.SelectPage(query)
}
// Find 查询数据库
func (r *UDMSubUser) Find(u model.UDMSubUser) []model.UDMSubUser {
return r.udmSubRepository.SelectList(u)
}
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度0或者32
func (r *UDMSubUser) Insert(coreUid, neUid string, u model.UDMSubUser) int64 {
uArr := r.dataByRedis(coreUid, neUid, u.IMSI)
if len(uArr) > 0 {
r.udmSubRepository.DeleteByIMSI(coreUid, neUid, u.IMSI)
// 新增到拓展信息
if u.Remark != "" {
r.UDMExtendRepository.DeleteByIMSI(coreUid, "%", u.IMSI)
r.UDMExtendRepository.Inserts([]model.UDMExtend{{
CoreUID: u.CoreUID,
NeUID: u.NeUID,
NeType: u.NeType,
IMSI: u.IMSI,
MSISDN: u.MSISDN,
Remark: u.Remark,
}})
}
return r.udmSubRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r *UDMSubUser) InsertData(coreUid, neUid, 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(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
r.udmSubRepository.DeletePrefixByIMSI(coreUid, neUid, prefix)
num += r.udmSubRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r *UDMSubUser) Delete(coreUid, neUid, imsi string) int64 {
// 删除拓展信息
r.UDMExtendRepository.DeleteByIMSI(coreUid, neUid, imsi)
return r.udmSubRepository.DeleteByIMSI(coreUid, neUid, imsi)
}
// LoadData 重新加载从imsi开始num的数据
// remark不为空则新增到拓展信息删除标记为-(Deleted)-
func (r *UDMSubUser) LoadData(coreUid, neUid, imsi string, num int64, remark string) {
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
// 删除原数据
r.udmSubRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
if remark == "-(Deleted)-" {
r.UDMExtendRepository.DeleteByIMSI(coreUid, "%", keyIMSI)
}
// 加载数据,删除标记为-(Deleted)-加载为空不插入
arr := r.dataByRedis(coreUid, neUid, keyIMSI)
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{
CoreUID: v.CoreUID,
NeUID: v.NeUID,
NeType: v.NeType,
IMSI: v.IMSI,
MSISDN: v.MSISDN,
Remark: remark,
})
}
r.UDMExtendRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
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.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, ",")
}

View File

@@ -0,0 +1,175 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/repository"
)
// 实例化服务层 UDMVOIPUser 结构体
var NewUDMVOIPUser = &UDMVOIPUser{
udmVOIPRepository: repository.NewUDMVOIPUser,
}
// UDMVOIP信息 服务层处理
type UDMVOIPUser struct {
// UDMVOIP信息数据信息
udmVOIPRepository *repository.UDMVOIPUser
}
// dataByRedis UDMVOIP用户 db:0 中 voip:*
func (r UDMVOIPUser) dataByRedis(coreUid, neUid, username string) []model.UDMVOIPUser {
arr := []model.UDMVOIPUser{}
key := fmt.Sprintf("voip:%s", username)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
voipArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, voipArr)
if err != nil {
return arr
}
for k, m := range mkv {
// 跳过-号数据 voip:360000100000130
username, hasPrefix := strings.CutPrefix(k, "voip:")
if strings.Contains(username, "-") || !hasPrefix {
continue
}
a := model.UDMVOIPUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
UserName: username,
Password: m["password"],
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置VOIP用户数据清空数据库重新同步Redis数据
func (r UDMVOIPUser) ResetData(coreUid, neUid string) int64 {
arr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmVOIPRepository.ClearAndInsert(coreUid, neUid, arr)
return int64(len(arr))
}
// ParseInfo 解析单个用户userName信息 data从命令MML得到的结果
func (r UDMVOIPUser) ParseInfo(coreUid, neUid string, data map[string]string) model.UDMVOIPUser {
u := model.UDMVOIPUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
UserName: data["username"],
Password: data["password"],
}
// 赋予ID
item := r.udmVOIPRepository.SelectByUserName(coreUid, neUid, u.UserName)
if item.ID != "" {
u.ID = item.ID
}
return u
}
// FindByPage 分页查询数据库
func (r UDMVOIPUser) FindByPage(query map[string]string) (int64, []model.UDMVOIPUser) {
return r.udmVOIPRepository.SelectPage(query)
}
// Find 查询数据库
func (r UDMVOIPUser) Find(u model.UDMVOIPUser) []model.UDMVOIPUser {
return r.udmVOIPRepository.SelectList(u)
}
// Insert 从数据中读取后删除username再存入数据库
func (r UDMVOIPUser) Insert(coreUid, neUid string, username string) int64 {
uArr := r.dataByRedis(coreUid, neUid, username)
if len(uArr) > 0 {
r.udmVOIPRepository.DeleteByUserName(coreUid, neUid, username)
return r.udmVOIPRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r UDMVOIPUser) InsertData(coreUid, neUid, dataType string, data any) int64 {
// imsi截取前缀,重新获取部分数据
prefixes := make(map[string]struct{})
if dataType == "csv" {
for _, v := range data.([]map[string]string) {
username := v["username"]
if len(username) < 4 {
continue
}
prefix := username[:len(username)-3]
prefixes[prefix] = struct{}{}
}
}
if dataType == "txt" {
for _, v := range data.([][]string) {
username := v[0]
if len(username) < 4 {
continue
}
prefix := username[:len(username)-3]
prefixes[prefix] = struct{}{}
}
}
// 根据前缀重新加载插入
var num int64 = 0
for prefix := range prefixes {
// 直接删除前缀的记录
r.udmVOIPRepository.DeletePrefixByUserName(coreUid, neUid, prefix)
// keys voip:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
num += r.udmVOIPRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r UDMVOIPUser) Delete(coreUid, neUid, username string) int64 {
return r.udmVOIPRepository.DeleteByUserName(coreUid, neUid, username)
}
// LoadData 重新加载从username开始num的数据
func (r UDMVOIPUser) LoadData(coreUid, neUid, username string, num int64) {
startUserName, _ := strconv.ParseInt(username, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyUserName := fmt.Sprintf("%d", startUserName+i)
// 删除原数据
r.udmVOIPRepository.DeleteByUserName(coreUid, neUid, keyUserName)
// 加载数据
arr := r.dataByRedis(coreUid, neUid, keyUserName)
if len(arr) < 1 {
continue
}
r.udmVOIPRepository.Inserts(arr)
}
}

View File

@@ -0,0 +1,196 @@
package service
import (
"fmt"
"strconv"
"strings"
"be.ems/src/framework/database/redis"
neService "be.ems/src/modules/network_element/service"
"be.ems/src/modules/network_link/model"
"be.ems/src/modules/network_link/repository"
)
// 实例化服务层 UDMVolteIMSUser 结构体
var NewUDMVolteIMSUser = &UDMVolteIMSUser{
udmVolteIMSRepository: repository.NewUDMVolteIMSUser,
}
// UDMVolteIMS信息 服务层处理
type UDMVolteIMSUser struct {
// UDMVolteIMS信息数据信息
udmVolteIMSRepository *repository.UDMVolteIMSUser
}
// dataByRedis UDMVolteIMS用户 db:0 中 volte:*
func (r UDMVolteIMSUser) dataByRedis(coreUid, neUid, imsi string) []model.UDMVolteIMSUser {
arr := []model.UDMVolteIMSUser{}
key := fmt.Sprintf("volte:%s", imsi)
source := fmt.Sprintf("UDM_%s", neUid)
// 网元主机的Redis客户端
redisClient, err := neService.NewNeInfo.NeRunRedisClient(coreUid, neUid)
if err != nil {
return arr
}
defer func() {
redisClient.Close()
redis.ConnectPush(source, nil)
}()
redis.ConnectPush(source, redisClient.Client)
volteArr, err := redis.GetKeys(source, key)
if err != nil {
return arr
}
mkv, err := redis.GetHashBatch(source, volteArr)
if err != nil {
return arr
}
for k, m := range mkv {
// volte:360000100000130:8612300000130
keys := strings.Split(k, ":")
if len(keys) != 3 {
continue
}
// "110011200004217@ims.mnc001.mcc110.3gppnetwork.org"
vni := ""
impiParts := strings.Split(m["impi"], "@")
if len(impiParts) > 1 {
vni = impiParts[1]
}
a := model.UDMVolteIMSUser{
CoreUID: coreUid,
NeUID: neUid,
NeType: "UDM",
IMSI: keys[1],
MSISDN: keys[2],
Tag: m["tag"], // volte = tag
VNI: vni,
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置VolteIMS用户数据清空数据库重新同步Redis数据
func (r UDMVolteIMSUser) ResetData(coreUid, neUid string) int64 {
authArr := r.dataByRedis(coreUid, neUid, "*")
// 数据清空后添加
go r.udmVolteIMSRepository.ClearAndInsert(coreUid, neUid, authArr)
return int64(len(authArr))
}
// ParseInfo 解析单个用户imsi信息 data从命令MML得到的结果
func (r UDMVolteIMSUser) ParseInfo(coreUid, neUid string, data map[string]string) model.UDMVolteIMSUser {
// "110011200004217@ims.mnc001.mcc110.3gppnetwork.org"
vni := ""
impiParts := strings.Split(data["impi"], "@")
if len(impiParts) > 1 {
vni = impiParts[1]
}
if vni == "" {
return model.UDMVolteIMSUser{}
}
u := model.UDMVolteIMSUser{
CoreUID: coreUid,
NeUID: neUid,
IMSI: data["imsi"],
MSISDN: data["msisdn"],
Tag: data["volte_tag"],
VNI: vni,
}
// 赋予ID
item := r.udmVolteIMSRepository.SelectByIMSIAndMSISDN(coreUid, neUid, u.IMSI, u.MSISDN)
if item.ID != "" {
u.ID = item.ID
}
return u
}
// FindByPage 分页查询数据库
func (r UDMVolteIMSUser) FindByPage(query map[string]string) (int64, []model.UDMVolteIMSUser) {
return r.udmVolteIMSRepository.SelectPage(query)
}
// Find 查询数据库
func (r UDMVolteIMSUser) Find(u model.UDMVolteIMSUser) []model.UDMVolteIMSUser {
return r.udmVolteIMSRepository.SelectList(u)
}
// InsertByIMSI 从数据中读取后删除imsi再存入数据库
// imsi长度15
func (r UDMVolteIMSUser) InsertByIMSI(coreUid, neUid, imsi string) int64 {
uArr := r.dataByRedis(coreUid, neUid, imsi+":*")
if len(uArr) > 0 {
r.udmVolteIMSRepository.DeleteByIMSI(coreUid, neUid, imsi)
return r.udmVolteIMSRepository.Inserts(uArr)
}
return 0
}
// InsertData 导入文件数据 dataType目前两种txt/csv
func (r UDMVolteIMSUser) InsertData(coreUid, neUid, 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.udmVolteIMSRepository.DeletePrefixByIMSI(coreUid, neUid, prefix)
// keys voip:4600001000004*
arr := r.dataByRedis(coreUid, neUid, prefix+"*")
if len(arr) > 0 {
num += r.udmVolteIMSRepository.Inserts(arr)
}
}
return num
}
// Delete 删除单个不重新加载
func (r UDMVolteIMSUser) Delete(coreUid, neUid, imsi string) int64 {
return r.udmVolteIMSRepository.DeleteByIMSI(coreUid, neUid, imsi)
}
// LoadData 重新加载从imsi开始num的数据
func (r UDMVolteIMSUser) LoadData(coreUid, neUid, imsiOrMsisdn string, num int64) {
startIMSIOrMsisdn, _ := strconv.ParseInt(imsiOrMsisdn, 10, 64)
var i int64
for i = 0; i < num; i++ {
keyIMSI := fmt.Sprintf("%d", startIMSIOrMsisdn+i)
// 删除原数据
r.udmVolteIMSRepository.DeleteByIMSI(coreUid, neUid, keyIMSI)
// 加载数据
arr := r.dataByRedis(coreUid, neUid, keyIMSI+":*")
if len(arr) < 1 {
continue
}
r.udmVolteIMSRepository.Inserts(arr)
}
}