Merge remote-tracking branch 'origin/main' into multi-tenant
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# 项目信息
|
||||
framework:
|
||||
name: "OMC"
|
||||
version: "2.2408.1"
|
||||
version: "2.2409.3"
|
||||
|
||||
# 应用服务配置
|
||||
server:
|
||||
|
||||
96
src/framework/socket/tcp_client.go
Normal file
96
src/framework/socket/tcp_client.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ConnTCP 连接TCP客户端
|
||||
type ConnTCP struct {
|
||||
Addr string `json:"addr"` // 主机地址
|
||||
Port int64 `json:"port"` // 端口
|
||||
|
||||
DialTimeOut time.Duration `json:"dialTimeOut"` // 连接超时断开
|
||||
|
||||
Client *net.Conn `json:"client"`
|
||||
LastResult string `json:"lastResult"` // 记最后一次发送消息的结果
|
||||
}
|
||||
|
||||
// New 创建TCP客户端
|
||||
func (c *ConnTCP) New() (*ConnTCP, error) {
|
||||
// IPV6地址协议
|
||||
proto := "tcp"
|
||||
if strings.Contains(c.Addr, ":") {
|
||||
proto = "tcp6"
|
||||
c.Addr = fmt.Sprintf("[%s]", c.Addr)
|
||||
}
|
||||
address := fmt.Sprintf("%s:%d", c.Addr, c.Port)
|
||||
|
||||
// 默认等待5s
|
||||
if c.DialTimeOut == 0 {
|
||||
c.DialTimeOut = 5 * time.Second
|
||||
}
|
||||
|
||||
// 连接到服务端
|
||||
client, err := net.DialTimeout(proto, address, c.DialTimeOut)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Client = &client
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Close 关闭当前TCP客户端
|
||||
func (c *ConnTCP) Close() {
|
||||
if c.Client != nil {
|
||||
(*c.Client).Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Send 发送消息
|
||||
func (c *ConnTCP) Send(msg []byte, timer time.Duration) (string, error) {
|
||||
if c.Client == nil {
|
||||
return "", fmt.Errorf("tcp client not connected")
|
||||
}
|
||||
conn := *c.Client
|
||||
|
||||
// 写入信息
|
||||
if len(msg) > 0 {
|
||||
if _, err := conn.Write(msg); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
defer buf.Reset()
|
||||
|
||||
tmp := make([]byte, 1024)
|
||||
for {
|
||||
select {
|
||||
case <-time.After(timer):
|
||||
c.LastResult = buf.String()
|
||||
return c.LastResult, fmt.Errorf("timeout")
|
||||
default:
|
||||
// 读取命令消息
|
||||
n, err := conn.Read(tmp)
|
||||
if n == 0 || err != nil {
|
||||
tmp = nil
|
||||
break
|
||||
}
|
||||
|
||||
tmpStr := string(tmp[:n])
|
||||
buf.WriteString(tmpStr)
|
||||
|
||||
// 是否有终止符
|
||||
if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") {
|
||||
tmp = nil
|
||||
c.LastResult = buf.String()
|
||||
return c.LastResult, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
83
src/framework/socket/tcp_server.go
Normal file
83
src/framework/socket/tcp_server.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
)
|
||||
|
||||
// SocketTCP TCP服务端
|
||||
type SocketTCP struct {
|
||||
Addr string `json:"addr"` // 主机地址
|
||||
Port int64 `json:"port"` // 端口
|
||||
Listen *net.Listener `json:"listen"`
|
||||
StopChan chan struct{} `json:"stop"` // 停止信号
|
||||
}
|
||||
|
||||
// New 创建TCP服务端
|
||||
func (s *SocketTCP) New() (*SocketTCP, error) {
|
||||
// IPV6地址协议
|
||||
proto := "tcp"
|
||||
if strings.Contains(s.Addr, ":") {
|
||||
proto = "tcp6"
|
||||
s.Addr = fmt.Sprintf("[%s]", s.Addr)
|
||||
}
|
||||
address := fmt.Sprintf("%s:%d", s.Addr, s.Port)
|
||||
|
||||
ln, err := net.Listen(proto, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Listen = &ln
|
||||
s.StopChan = make(chan struct{}, 1)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Close 关闭当前TCP服务端
|
||||
func (s *SocketTCP) Close() {
|
||||
if s.Listen != nil {
|
||||
s.StopChan <- struct{}{}
|
||||
(*s.Listen).Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve 处理消息
|
||||
func (s *SocketTCP) Resolve(bufferSize int, callback func([]byte, int)) error {
|
||||
if s.Listen == nil {
|
||||
return fmt.Errorf("tcp service not created")
|
||||
}
|
||||
|
||||
ln := *s.Listen
|
||||
buffer := make([]byte, bufferSize)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.StopChan:
|
||||
return fmt.Errorf("udp service stop")
|
||||
default:
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
logger.Errorf("Error accepting connection: %v ", err)
|
||||
continue
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 读取数据
|
||||
n, err := conn.Read(buffer)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading from TCP connection:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
callback(buffer, n)
|
||||
|
||||
// 发送响应
|
||||
if _, err = conn.Write([]byte("tcp>")); err != nil {
|
||||
fmt.Println("Error sending response:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
96
src/framework/socket/udp_client.go
Normal file
96
src/framework/socket/udp_client.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ConnUDP 连接UDP客户端
|
||||
type ConnUDP struct {
|
||||
Addr string `json:"addr"` // 主机地址
|
||||
Port int64 `json:"port"` // 端口
|
||||
|
||||
DialTimeOut time.Duration `json:"dialTimeOut"` // 连接超时断开
|
||||
|
||||
Client *net.Conn `json:"client"`
|
||||
LastResult string `json:"lastResult"` // 记最后一次发送消息的结果
|
||||
}
|
||||
|
||||
// New 创建UDP客户端
|
||||
func (c *ConnUDP) New() (*ConnUDP, error) {
|
||||
// IPV6地址协议
|
||||
proto := "udp"
|
||||
if strings.Contains(c.Addr, ":") {
|
||||
proto = "udp6"
|
||||
c.Addr = fmt.Sprintf("[%s]", c.Addr)
|
||||
}
|
||||
address := fmt.Sprintf("%s:%d", c.Addr, c.Port)
|
||||
|
||||
// 默认等待5s
|
||||
if c.DialTimeOut == 0 {
|
||||
c.DialTimeOut = 5 * time.Second
|
||||
}
|
||||
|
||||
// 连接到服务端
|
||||
client, err := net.DialTimeout(proto, address, c.DialTimeOut)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Client = &client
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Close 关闭当前UDP客户端
|
||||
func (c *ConnUDP) Close() {
|
||||
if c.Client != nil {
|
||||
(*c.Client).Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Send 发送消息
|
||||
func (c *ConnUDP) Send(msg []byte, ms int) (string, error) {
|
||||
if c.Client == nil {
|
||||
return "", fmt.Errorf("udp client not connected")
|
||||
}
|
||||
conn := *c.Client
|
||||
|
||||
// 写入信息
|
||||
if len(msg) > 0 {
|
||||
if _, err := conn.Write(msg); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
defer buf.Reset()
|
||||
|
||||
tmp := make([]byte, 1024)
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Duration(time.Duration(ms).Milliseconds())):
|
||||
c.LastResult = buf.String()
|
||||
return c.LastResult, fmt.Errorf("timeout")
|
||||
default:
|
||||
// 读取命令消息
|
||||
n, err := conn.Read(tmp)
|
||||
if n == 0 || err != nil {
|
||||
tmp = nil
|
||||
break
|
||||
}
|
||||
|
||||
tmpStr := string(tmp[:n])
|
||||
buf.WriteString(tmpStr)
|
||||
|
||||
// 是否有终止符
|
||||
if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") {
|
||||
tmp = nil
|
||||
c.LastResult = buf.String()
|
||||
return c.LastResult, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/framework/socket/udp_server.go
Normal file
80
src/framework/socket/udp_server.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package socket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SocketUDP UDP服务端
|
||||
type SocketUDP struct {
|
||||
Addr string `json:"addr"` // 主机地址
|
||||
Port int64 `json:"port"` // 端口
|
||||
Conn *net.UDPConn `json:"conn"`
|
||||
StopChan chan struct{} `json:"stop"` // 停止信号
|
||||
}
|
||||
|
||||
// New 创建UDP服务端
|
||||
func (s *SocketUDP) New() (*SocketUDP, error) {
|
||||
// IPV6地址协议
|
||||
proto := "udp"
|
||||
if strings.Contains(s.Addr, ":") {
|
||||
proto = "udp6"
|
||||
s.Addr = fmt.Sprintf("[%s]", s.Addr)
|
||||
}
|
||||
address := fmt.Sprintf("%s:%d", s.Addr, s.Port)
|
||||
|
||||
// 解析 UDP 地址
|
||||
udpAddr, err := net.ResolveUDPAddr(proto, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 监听 UDP 地址
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Conn = conn
|
||||
s.StopChan = make(chan struct{}, 1)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// CloseService 关闭当前UDP服务端
|
||||
func (s *SocketUDP) Close() {
|
||||
if s.Conn != nil {
|
||||
s.StopChan <- struct{}{}
|
||||
(*s.Conn).Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve 处理消息
|
||||
func (s *SocketUDP) Resolve(bufferSize int, callback func([]byte, int)) error {
|
||||
if s.Conn == nil {
|
||||
return fmt.Errorf("udp service not created")
|
||||
}
|
||||
|
||||
buffer := make([]byte, bufferSize)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.StopChan:
|
||||
return fmt.Errorf("udp service stop")
|
||||
default:
|
||||
// 读取数据
|
||||
n, addr, err := s.Conn.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading from UDP connection:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
callback(buffer, n)
|
||||
|
||||
// 发送响应
|
||||
if _, err = s.Conn.WriteToUDP([]byte("udp>"), addr); err != nil {
|
||||
fmt.Println("Error sending response:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,11 +50,6 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) {
|
||||
// fmt.Fprintln(client, c.User)
|
||||
// fmt.Fprintln(client, c.Password)
|
||||
|
||||
// 调整窗口大小 (120 列 x 128 行)
|
||||
// 需要确保接收方理解并正确处理发送窗口大小设置命令
|
||||
client.Write([]byte{255, 251, 31})
|
||||
client.Write([]byte{255, 250, 31, byte(120 >> 8), byte(120 & 0xFF), byte(128 >> 8), byte(128 & 0xFF), 255, 240})
|
||||
|
||||
c.Client = &client
|
||||
|
||||
// 排空连接登录的信息
|
||||
@@ -116,6 +111,6 @@ func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, err
|
||||
s := &TelnetClientSession{
|
||||
Client: *c.Client,
|
||||
}
|
||||
s.WindowChange(cols, rows)
|
||||
// s.WindowChange(cols, rows)
|
||||
return s, nil
|
||||
}
|
||||
@@ -47,11 +47,11 @@ func (s *TelnetClientSession) Read() []byte {
|
||||
buf := make([]byte, 1024)
|
||||
// 设置读取超时时间为100毫秒
|
||||
s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
_, err := s.Client.Read(buf)
|
||||
n, err := s.Client.Read(buf)
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return buf
|
||||
return buf[:n]
|
||||
}
|
||||
|
||||
// CombinedOutput 发送命令带结果返回
|
||||
@@ -87,7 +87,7 @@ func Post(url string, data url.Values, headers map[string]string) ([]byte, error
|
||||
// PostJSON 发送 POST 请求,并将请求体序列化为 JSON 格式
|
||||
func PostJSON(url string, data any, headers map[string]string) ([]byte, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second, // 超时时间
|
||||
Timeout: 10 * time.Second, // 超时时间
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
@@ -180,7 +180,7 @@ func PostUploadFile(url string, params map[string]string, file *os.File) ([]byte
|
||||
// PutJSON 发送 PUT 请求,并将请求体序列化为 JSON 格式
|
||||
func PutJSON(url string, data any, headers map[string]string) ([]byte, error) {
|
||||
client := &http.Client{
|
||||
Timeout: 3 * time.Second, // 超时时间
|
||||
Timeout: 10 * time.Second, // 超时时间
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
|
||||
@@ -17,46 +17,53 @@ import (
|
||||
)
|
||||
|
||||
// Number 解析数值型
|
||||
func Number(str any) int64 {
|
||||
switch str := str.(type) {
|
||||
func Number(value any) int64 {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
if str == "" {
|
||||
if v == "" {
|
||||
return 0
|
||||
}
|
||||
num, err := strconv.ParseInt(str, 10, 64)
|
||||
num, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return num
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
return reflect.ValueOf(str).Int()
|
||||
case int, int8, int16, int32, int64:
|
||||
return reflect.ValueOf(v).Int()
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
return int64(reflect.ValueOf(v).Uint())
|
||||
case float32, float64:
|
||||
return int64(reflect.ValueOf(str).Float())
|
||||
return int64(reflect.ValueOf(v).Float())
|
||||
case bool:
|
||||
if v {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean 解析布尔型
|
||||
func Boolean(str any) bool {
|
||||
switch str := str.(type) {
|
||||
func Boolean(value any) bool {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
if str == "" || str == "false" || str == "0" {
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// 尝试将字符串解析为数字
|
||||
if num, err := strconv.ParseFloat(str, 64); err == nil {
|
||||
return num != 0
|
||||
}
|
||||
return true
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
num := reflect.ValueOf(str).Int()
|
||||
return b
|
||||
case int, int8, int16, int32, int64:
|
||||
num := reflect.ValueOf(v).Int()
|
||||
return num != 0
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
num := int64(reflect.ValueOf(v).Uint())
|
||||
return num != 0
|
||||
case float32, float64:
|
||||
num := reflect.ValueOf(str).Float()
|
||||
num := reflect.ValueOf(v).Float()
|
||||
return num != 0
|
||||
case bool:
|
||||
return str
|
||||
return v
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"be.ems/lib/core/datasource"
|
||||
"be.ems/lib/dborm"
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/cron"
|
||||
)
|
||||
@@ -103,7 +103,7 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
}
|
||||
|
||||
func (s *BarProcessor) exportData(query, filePath string) (int64, error) {
|
||||
rows, err := datasource.DefaultDB().DB().Query(query)
|
||||
rows, err := dborm.XCoreDB().Query(query)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -141,10 +141,8 @@ func (s *SysCacheController) ClearCacheKey(c *gin.Context) {
|
||||
func (s *SysCacheController) ClearCacheSafe(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
caches := []model.SysCache{
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.user"), cachekey.LOGIN_TOKEN_KEY),
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.sys_config"), cachekey.SYS_CONFIG_KEY),
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.sys_dict"), cachekey.SYS_DICT_KEY),
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.captcha_codes"), cachekey.CAPTCHA_CODE_KEY),
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.repeat_submit"), cachekey.REPEAT_SUBMIT_KEY),
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.rate_limit"), cachekey.RATE_LIMIT_KEY),
|
||||
model.NewSysCacheNames(i18n.TKey(language, "cache.name.pwd_err_cnt"), cachekey.PWD_ERR_CNT_KEY),
|
||||
|
||||
@@ -152,11 +152,11 @@ func (s *SystemInfoImpl) NetworkInfo() map[string]string {
|
||||
func (s *SystemInfoImpl) DiskInfo() []map[string]string {
|
||||
disks := make([]map[string]string, 0)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
partitions, err := disk.PartitionsWithContext(ctx, false)
|
||||
if err != context.DeadlineExceeded {
|
||||
if err != nil && err != context.DeadlineExceeded {
|
||||
return disks
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
@@ -22,8 +23,9 @@ import (
|
||||
|
||||
// 实例化控制层 SMFController 结构体
|
||||
var NewSMFController = &SMFController{
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
cdrEventService: neDataService.NewCDREventSMFImpl,
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
cdrEventService: neDataService.NewCDREventSMFImpl,
|
||||
udmUserInfoService: *neDataService.NewUDMUserInfo,
|
||||
}
|
||||
|
||||
// 网元SMF
|
||||
@@ -34,6 +36,8 @@ type SMFController struct {
|
||||
neInfoService neService.INeInfo
|
||||
// CDR会话事件服务
|
||||
cdrEventService neDataService.ICDREventSMF
|
||||
// UDM用户信息服务
|
||||
udmUserInfoService neDataService.UDMUserInfo
|
||||
}
|
||||
|
||||
// CDR会话列表
|
||||
@@ -263,3 +267,63 @@ PDU IPv6 Addres Swith Prefix: %s`, User_Identifier, SSC_Mode, RAT_Type, DNN_ID,
|
||||
|
||||
c.FileAttachment(saveFilePath, fileName)
|
||||
}
|
||||
|
||||
// 在线订阅用户列表信息
|
||||
//
|
||||
// GET /subscribers
|
||||
func (s *SMFController) SubUserList(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var query struct {
|
||||
NeId string `form:"neId" binding:"required"`
|
||||
IMSI string `form:"imsi"`
|
||||
MSISDN string `form:"msisdn"`
|
||||
Upstate string `form:"upstate"`
|
||||
PageNum string `form:"pageNum"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元信息 rmUID
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("SMF", query.NeId)
|
||||
if neInfo.NeId != query.NeId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元直连
|
||||
data, err := neFetchlink.SMFSubInfo(neInfo, map[string]string{
|
||||
"imsi": query.IMSI,
|
||||
"msisdn": query.MSISDN,
|
||||
"upstate": query.Upstate,
|
||||
"pageNum": query.PageNum,
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 对数据进行处理,去掉前缀,并加入imsi拓展信息
|
||||
rows := data["rows"].([]any)
|
||||
arr := &rows
|
||||
for i := range *arr {
|
||||
item := (*arr)[i].(map[string]any)
|
||||
if v, ok := item["imsi"]; ok && v != nil {
|
||||
imsiStr := v.(string)
|
||||
imsiStr = strings.TrimPrefix(imsiStr, "imsi-")
|
||||
item["imsi"] = imsiStr
|
||||
// 查UDM拓展信息
|
||||
info := s.udmUserInfoService.SelectByIMSIAndNeID(imsiStr, "")
|
||||
item["remark"] = info.Remark
|
||||
}
|
||||
if v, ok := item["msisdn"]; ok && v != nil {
|
||||
item["msisdn"] = strings.TrimPrefix(v.(string), "msisdn-")
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, result.Ok(map[string]any{
|
||||
"total": data["total"],
|
||||
"rows": data["rows"],
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
|
||||
"be.ems/src/framework/constants/uploadsubpath"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
// 实例化控制层 UDMAuthController 结构体
|
||||
var NewUDMAuth = &UDMAuthController{
|
||||
udmAuthService: neDataService.NewUDMAuthImpl,
|
||||
udmAuthService: neDataService.NewUDMAuthUser,
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ var NewUDMAuth = &UDMAuthController{
|
||||
// PATH /udm/auth
|
||||
type UDMAuthController struct {
|
||||
// UDM鉴权信息服务
|
||||
udmAuthService neDataService.IUDMAuth
|
||||
udmAuthService *neDataService.UDMAuthUser
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
@@ -103,26 +103,9 @@ func (s *UDMAuthController) Info(c *gin.Context) {
|
||||
}
|
||||
|
||||
neId = ""
|
||||
u := model.UDMAuth{
|
||||
IMSI: imsi,
|
||||
Amf: data["amf"],
|
||||
Status: "1",
|
||||
Ki: data["ki"],
|
||||
AlgoIndex: data["algo"],
|
||||
Opc: data["opc"],
|
||||
NeId: neId,
|
||||
}
|
||||
|
||||
// 查询imsi存在赋予id用于更新
|
||||
list := s.udmAuthService.SelectList(u)
|
||||
if len(list) > 0 {
|
||||
item := list[0]
|
||||
if item.ID != "" {
|
||||
u.ID = item.ID
|
||||
}
|
||||
}
|
||||
go s.udmAuthService.Insert(neId, u)
|
||||
|
||||
// 解析返回的数据
|
||||
u := s.udmAuthService.ParseInfo(imsi, neId, data)
|
||||
s.udmAuthService.Insert(neId, u)
|
||||
c.JSON(200, result.OkData(u))
|
||||
}
|
||||
|
||||
@@ -137,7 +120,7 @@ func (s *UDMAuthController) Add(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMAuth
|
||||
var body model.UDMAuthUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.IMSI == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
@@ -169,7 +152,7 @@ func (s *UDMAuthController) Add(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmAuthService.Insert(neId, body)
|
||||
s.udmAuthService.Insert(neId, body)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
@@ -186,7 +169,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMAuth
|
||||
var body model.UDMAuthUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.IMSI == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
@@ -234,7 +217,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMAuth
|
||||
var body model.UDMAuthUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.IMSI == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
@@ -279,7 +262,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmAuthService.Insert(neId, body)
|
||||
s.udmAuthService.Insert(neId, body)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
@@ -330,7 +313,7 @@ func (s *UDMAuthController) Remove(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmAuthService.Delete(neId, imsi)
|
||||
s.udmAuthService.Delete(imsi, neId)
|
||||
}
|
||||
resultData[imsi] = data
|
||||
}
|
||||
@@ -402,7 +385,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
|
||||
}
|
||||
|
||||
neId := ""
|
||||
list := s.udmAuthService.SelectList(model.UDMAuth{NeId: neId})
|
||||
list := s.udmAuthService.SelectList(model.UDMAuthUser{NeId: neId})
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("udm_auth_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type)
|
||||
filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName)
|
||||
|
||||
@@ -3,16 +3,15 @@ package controller
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/constants/uploadsubpath"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
@@ -23,7 +22,7 @@ import (
|
||||
|
||||
// 实例化控制层 UDMSubController 结构体
|
||||
var NewUDMSub = &UDMSubController{
|
||||
udmSubService: neDataService.NewUDMSubImpl,
|
||||
udmSubService: neDataService.NewUDMSub,
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
}
|
||||
|
||||
@@ -32,7 +31,7 @@ var NewUDMSub = &UDMSubController{
|
||||
// PATH /udm/sub
|
||||
type UDMSubController struct {
|
||||
// UDM签约信息服务
|
||||
udmSubService neDataService.IUDMSub
|
||||
udmSubService *neDataService.UDMSubUser
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
@@ -103,53 +102,10 @@ func (s *UDMSubController) Info(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 解析返回的数据
|
||||
cnType, _ := strconv.ParseInt(data["CNType"][:4], 0, 64)
|
||||
rat, _ := strconv.ParseInt(data["RAT"][:4], 0, 64)
|
||||
msisdn := data["MSISDN"]
|
||||
imsMsisdnLen := strings.Index(msisdn, ",")
|
||||
if imsMsisdnLen != -1 {
|
||||
msisdn = msisdn[:imsMsisdnLen]
|
||||
}
|
||||
neId = ""
|
||||
u := model.UDMSub{
|
||||
IMSI: imsi,
|
||||
Msisdn: msisdn,
|
||||
Ambr: data["AMBR"],
|
||||
Arfb: data["AreaForbidden"],
|
||||
Cn: fmt.Sprint(cnType),
|
||||
SmData: data["SM-Data(snssai+dnn[1..n])"],
|
||||
Sar: data["ServiceAreaRestriction"],
|
||||
Nssai: data["NSSAI"],
|
||||
SmfSel: data["Smf-Selection"],
|
||||
Rat: fmt.Sprint(rat),
|
||||
NeId: neId,
|
||||
}
|
||||
// 1,64,24,65,def_eps,1,2,010200000000,-
|
||||
if v, ok := data["EPS-Data"]; ok {
|
||||
u.EpsDat = v
|
||||
arr := strings.Split(v, ",")
|
||||
u.EpsFlag = arr[0]
|
||||
u.EpsOdb = arr[1]
|
||||
u.HplmnOdb = arr[2]
|
||||
u.Ard = arr[3]
|
||||
u.Epstpl = arr[4]
|
||||
u.ContextId = arr[5]
|
||||
u.ApnContext = arr[7]
|
||||
// [6] 是不要的,导入和导出不用
|
||||
u.StaticIp = arr[8]
|
||||
}
|
||||
|
||||
// 查询imsi存在赋予id用于更新
|
||||
list := s.udmSubService.SelectList(u)
|
||||
if len(list) > 0 {
|
||||
item := list[0]
|
||||
if item.ID != "" {
|
||||
u.ID = item.ID
|
||||
}
|
||||
}
|
||||
go s.udmSubService.Insert(neId, u)
|
||||
|
||||
// 解析返回的数据
|
||||
u := s.udmSubService.ParseInfo(imsi, neId, data)
|
||||
s.udmSubService.Insert(neId, u)
|
||||
c.JSON(200, result.OkData(u))
|
||||
}
|
||||
|
||||
@@ -164,9 +120,9 @@ func (s *UDMSubController) Add(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMSub
|
||||
var body model.UDMSubUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.IMSI == "" {
|
||||
if err != nil || len(body.IMSI) < 15 {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
@@ -186,8 +142,8 @@ func (s *UDMSubController) Add(c *gin.Context) {
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
|
||||
body.IMSI, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
|
||||
cmd := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s,cag=%s",
|
||||
body.IMSI, body.MSISDN, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext, body.Cag)
|
||||
// static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增
|
||||
if body.StaticIp != "" {
|
||||
cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp)
|
||||
@@ -201,7 +157,8 @@ func (s *UDMSubController) Add(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmSubService.Insert(neId, body)
|
||||
body.NeId = neId
|
||||
s.udmSubService.Insert(neId, body)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
@@ -218,9 +175,9 @@ func (s *UDMSubController) Adds(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMSub
|
||||
var body model.UDMSubUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.IMSI == "" {
|
||||
if err != nil || len(body.IMSI) < 15 {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
@@ -240,8 +197,8 @@ func (s *UDMSubController) Adds(c *gin.Context) {
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
|
||||
body.IMSI, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
|
||||
cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s,cag=%s",
|
||||
body.IMSI, body.MSISDN, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext, body.Cag)
|
||||
// static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增
|
||||
if body.StaticIp != "" {
|
||||
cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp)
|
||||
@@ -255,7 +212,7 @@ func (s *UDMSubController) Adds(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmSubService.LoadData(neId, body.IMSI, num)
|
||||
go s.udmSubService.LoadData(neId, body.IMSI, num, body.Remark)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
@@ -271,9 +228,9 @@ func (s *UDMSubController) Edit(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMSub
|
||||
var body model.UDMSubUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.IMSI == "" {
|
||||
if err != nil || len(body.IMSI) < 15 {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
@@ -295,8 +252,8 @@ func (s *UDMSubController) Edit(c *gin.Context) {
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("mod udmuser:imsi=%s", body.IMSI)
|
||||
// 修改的参数名称
|
||||
if body.Msisdn != "" {
|
||||
cmd += fmt.Sprintf(",msisdn=%s", body.Msisdn)
|
||||
if body.MSISDN != "" {
|
||||
cmd += fmt.Sprintf(",msisdn=%s", body.MSISDN)
|
||||
}
|
||||
if body.Ambr != "" {
|
||||
cmd += fmt.Sprintf(",ambr=%s", body.Ambr)
|
||||
@@ -346,6 +303,9 @@ func (s *UDMSubController) Edit(c *gin.Context) {
|
||||
if body.ApnContext != "" {
|
||||
cmd += fmt.Sprintf(",apn_context=%s", body.ApnContext)
|
||||
}
|
||||
if body.Cag != "" {
|
||||
cmd += fmt.Sprintf(",cag=%s", body.Cag)
|
||||
}
|
||||
if body.StaticIp != "" {
|
||||
cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp)
|
||||
}
|
||||
@@ -358,7 +318,8 @@ func (s *UDMSubController) Edit(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmSubService.Insert(neId, body)
|
||||
body.NeId = neId
|
||||
s.udmSubService.Insert(neId, body)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
@@ -370,7 +331,7 @@ func (s *UDMSubController) Remove(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || imsi == "" {
|
||||
if neId == "" || len(imsi) < 15 {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
@@ -409,7 +370,7 @@ func (s *UDMSubController) Remove(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmSubService.Delete(neId, imsi)
|
||||
s.udmSubService.Delete(neId, imsi)
|
||||
}
|
||||
resultData[imsi] = data
|
||||
}
|
||||
@@ -425,7 +386,7 @@ func (s *UDMSubController) Removes(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
num := c.Param("num")
|
||||
if neId == "" || imsi == "" || num == "" {
|
||||
if neId == "" || len(imsi) < 15 || num == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
@@ -455,7 +416,8 @@ func (s *UDMSubController) Removes(c *gin.Context) {
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
neId = ""
|
||||
go s.udmSubService.LoadData(neId, imsi, num)
|
||||
go s.udmSubService.LoadData(neId, imsi, num, "-(Deleted)-")
|
||||
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
@@ -481,7 +443,7 @@ func (s *UDMSubController) Export(c *gin.Context) {
|
||||
}
|
||||
|
||||
neId := ""
|
||||
list := s.udmSubService.SelectList(model.UDMSub{NeId: neId})
|
||||
list := s.udmSubService.SelectList(model.UDMSubUser{NeId: neId})
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("udm_sub_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type)
|
||||
filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName)
|
||||
@@ -492,7 +454,7 @@ func (s *UDMSubController) Export(c *gin.Context) {
|
||||
data = append(data, []string{"imsi", "msisdn", "ambr", "nssai", "arfb", "sar", "rat", "cn", "smf_sel", "sm_dat", "eps_dat"})
|
||||
for _, v := range list {
|
||||
epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp)
|
||||
data = append(data, []string{v.IMSI, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat})
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat})
|
||||
}
|
||||
// 输出到文件
|
||||
err = file.WriterFileCSV(data, filePath)
|
||||
@@ -507,7 +469,7 @@ func (s *UDMSubController) Export(c *gin.Context) {
|
||||
data := [][]string{}
|
||||
for _, v := range list {
|
||||
epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp)
|
||||
data = append(data, []string{v.IMSI, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat})
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat})
|
||||
}
|
||||
// 输出到文件
|
||||
err = file.WriterFileTXT(data, ",", filePath)
|
||||
|
||||
@@ -32,9 +32,8 @@ type UPFController struct {
|
||||
func (s *UPFController) TotalFlow(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var querys struct {
|
||||
NeType string `json:"neType" form:"neType" binding:"required"`
|
||||
NeID string `form:"neId" binding:"required"`
|
||||
Day int `form:"day" binding:"required"`
|
||||
NeID string `form:"neId" binding:"required"`
|
||||
Day int `form:"day" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); querys.Day < 0 || err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
@@ -42,7 +41,7 @@ func (s *UPFController) TotalFlow(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UPF", querys.NeID)
|
||||
if neInfo.NeId != querys.NeID || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package model
|
||||
|
||||
// UDMAuth UDM鉴权用户对象 u_auth_user
|
||||
type UDMAuth struct {
|
||||
// UDMAuthUser UDM鉴权用户 u_auth_user
|
||||
type UDMAuthUser struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID
|
||||
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号
|
||||
Amf string `json:"amf" gorm:"column:amf"` // ANF
|
||||
Status string `json:"status" gorm:"column:status"` // 状态 默认给1
|
||||
Ki string `json:"ki" gorm:"column:ki"` // ki
|
||||
AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex
|
||||
Opc string `json:"opc" gorm:"column:opc"` // opc
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统
|
||||
IMSI string `json:"imsi" gorm:"imsi"` // SIM卡/USIM卡ID
|
||||
NeId string `json:"neId" gorm:"ne_id"` // UDM网元标识
|
||||
Amf string `json:"amf" gorm:"amf"` // AMF
|
||||
Status string `json:"status" gorm:"status"` // 状态
|
||||
Ki string `json:"ki" gorm:"ki"` // ki
|
||||
AlgoIndex string `json:"algoIndex" gorm:"algo_index"` // algoIndex
|
||||
Opc string `json:"opc" gorm:"opc"` // OPC
|
||||
}
|
||||
|
||||
func (UDMAuth) TableName() string {
|
||||
// TableName 表名称
|
||||
func (*UDMAuthUser) TableName() string {
|
||||
return "u_auth_user"
|
||||
}
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
package model
|
||||
|
||||
// UDMSub UDM签约用户对象 u_sub_user
|
||||
type UDMSub struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
Msisdn string `json:"msisdn" gorm:"column:msisdn"` // 相当手机号
|
||||
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号
|
||||
Ambr string `json:"ambr" gorm:"column:ambr"`
|
||||
Nssai string `json:"nssai" gorm:"column:nssai"`
|
||||
Rat string `json:"rat" gorm:"column:rat"`
|
||||
Arfb string `json:"arfb" gorm:"column:arfb"`
|
||||
Sar string `json:"sar" gorm:"column:sar"`
|
||||
Cn string `json:"cn" gorm:"column:cn"`
|
||||
SmData string `json:"smData" gorm:"column:sm_data"`
|
||||
SmfSel string `json:"smfSel" gorm:"column:smf_sel"`
|
||||
EpsDat string `json:"epsDat" gorm:"column:eps_dat"`
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统
|
||||
// UDMSubUser UDM签约用户 u_sub_user
|
||||
type UDMSubUser struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
|
||||
IMSI string `json:"imsi" gorm:"imsi"` // SIM卡/USIM卡ID
|
||||
MSISDN string `json:"msisdn" gorm:"msisdn"` // 用户电话号码
|
||||
NeId string `json:"neId" gorm:"ne_id"` // UDM网元标识
|
||||
Ambr string `json:"ambr" gorm:"ambr"` // SubUeAMBRTemp
|
||||
Nssai string `json:"nssai" gorm:"nssai"` // SubSNSSAITemp
|
||||
Rat string `json:"rat" gorm:"rat"` // rat VIRTUAL|WLAN|EUTRA|NR
|
||||
Arfb string `json:"arfb" gorm:"arfb"` // forbiddenAreasTemp
|
||||
Sar string `json:"sar" gorm:"sar"` // serviceAreaRestrictTemp
|
||||
Cn string `json:"cn" gorm:"cn"` // cnType EPC|5GC
|
||||
SmData string `json:"smData" gorm:"sm_data"` // smData
|
||||
SmfSel string `json:"smfSel" gorm:"smf_sel"` // smfSel
|
||||
EpsDat string `json:"epsDat" gorm:"eps_dat"` // Eps
|
||||
EpsFlag string `json:"epsFlag" gorm:"eps_flag"` // epsFlag
|
||||
EpsOdb string `json:"epsOdb" gorm:"eps_odb"` // epsOdb
|
||||
HplmnOdb string `json:"hplmnOdb" gorm:"hplmn_odb"` // hplmnOdb
|
||||
Ard string `json:"ard" gorm:"ard"` // Ard
|
||||
Epstpl string `json:"epstpl" gorm:"epstpl"` // Epstpl
|
||||
ContextId string `json:"contextId" gorm:"context_id"` // ContextId
|
||||
ApnContext string `json:"apnContext" gorm:"apn_context"` // apnContext
|
||||
StaticIp string `json:"staticIp" gorm:"static_ip"` // staticIpstatic_ip指给4G UE分配的静态IP,没有可不带此字段名
|
||||
Cag string `json:"cag" gorm:"cag"` // CAG
|
||||
|
||||
EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"`
|
||||
EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"`
|
||||
HplmnOdb string `json:"hplmnOdb" gorm:"column:hplmn_odb"`
|
||||
Ard string `json:"ard" gorm:"column:ard"`
|
||||
Epstpl string `json:"epstpl" gorm:"column:epstpl"`
|
||||
ContextId string `json:"contextId" gorm:"column:context_id"`
|
||||
ApnContext string `json:"apnContext" gorm:"column:apn_context"`
|
||||
StaticIp string `json:"staticIp" gorm:"column:static_ip"`
|
||||
TenantID string `json:"tenantID" gorm:"column:tenant_id"`
|
||||
TenantName string `json:"tenantName" gorm:"-"`
|
||||
|
||||
// ====== 非数据库字段属性 ======
|
||||
|
||||
Remark string `json:"remark,omitempty" gorm:"-"` // 备注
|
||||
}
|
||||
|
||||
func (UDMSub) TableName() string {
|
||||
// TableName 表名称
|
||||
func (*UDMSubUser) TableName() string {
|
||||
return "u_sub_user"
|
||||
}
|
||||
|
||||
15
src/modules/network_data/model/udm_user_info.go
Normal file
15
src/modules/network_data/model/udm_user_info.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
// UDMUserInfo UDM用户IMSI扩展信息 u_user_info
|
||||
type UDMUserInfo struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID
|
||||
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
|
||||
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统
|
||||
Remark string `json:"remark" gorm:"remark"` // 备注
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*UDMUserInfo) TableName() string {
|
||||
return "u_user_info"
|
||||
}
|
||||
@@ -97,6 +97,10 @@ func Setup(router *gin.Engine) {
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewSMFController.CDRExport,
|
||||
)
|
||||
smfGroup.GET("/subscribers",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewSMFController.SubUserList,
|
||||
)
|
||||
}
|
||||
|
||||
// 网元AMF
|
||||
|
||||
@@ -1,26 +1,206 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// UDM鉴权信息 数据层接口
|
||||
type IUDMAuth interface {
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
ClearAndInsert(neId string, uArr []model.UDMAuth) int64
|
||||
// 实例化数据层 UDMAuthUser 结构体
|
||||
var NewUDMAuthUser = &UDMAuthUser{
|
||||
selectSql: `select id, imsi, ne_id, amf, status, ki, algo_index, opc from u_auth_user`,
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
SelectPage(query map[string]any) map[string]any
|
||||
|
||||
// SelectList 根据实体查询
|
||||
SelectList(u model.UDMAuth) []model.UDMAuth
|
||||
|
||||
// Insert 批量添加
|
||||
Inserts(uArr []model.UDMAuth) int64
|
||||
|
||||
// Delete 删除实体
|
||||
Delete(neId, imsi string) int64
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
DeletePrefixByIMSI(neId, imsi string) int64
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"imsi": "IMSI",
|
||||
"ne_id": "NeId",
|
||||
"amf": "Amf",
|
||||
"status": "Status",
|
||||
"ki": "Ki",
|
||||
"algo_index": "AlgoIndex",
|
||||
"opc": "Opc",
|
||||
},
|
||||
}
|
||||
|
||||
// UDMAuthUser UDM鉴权信息表 数据层处理
|
||||
type UDMAuthUser struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *UDMAuthUser) convertResultRows(rows []map[string]any) []model.UDMAuthUser {
|
||||
arr := make([]model.UDMAuthUser, 0)
|
||||
for _, row := range rows {
|
||||
item := model.UDMAuthUser{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *UDMAuthUser) ClearAndInsert(neId string, uArr []model.UDMAuthUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil)
|
||||
if err != nil {
|
||||
logger.Errorf("TRUNCATE err => %v", err)
|
||||
}
|
||||
return r.Inserts(uArr)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *UDMAuthUser) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
if v, ok := query["neId"]; ok && v != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.UDMAuthUser{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from u_auth_user"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 排序
|
||||
orderSql := ""
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v.(string)
|
||||
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
|
||||
if o == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
orderSql = fmt.Sprintf(" order by %s ", sortSql)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + orderSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *UDMAuthUser) SelectList(u model.UDMAuthUser) []model.UDMAuthUser {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if u.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, u.IMSI)
|
||||
}
|
||||
if u.NeId != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, u.NeId)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by imsi asc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIMSIAndNeID 通过imsi和ne_id查询
|
||||
func (r *UDMAuthUser) SelectByIMSIAndNeID(imsi, neId string) model.UDMAuthUser {
|
||||
querySql := r.selectSql + " where imsi = ? and ne_id = ?"
|
||||
results, err := datasource.RawDB("", querySql, []any{imsi, neId})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return model.UDMAuthUser{}
|
||||
}
|
||||
// 转换实体
|
||||
rows := r.convertResultRows(results)
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return model.UDMAuthUser{}
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r *UDMAuthUser) Inserts(uArr []model.UDMAuthUser) int64 {
|
||||
tx := datasource.DefaultDB().CreateInBatches(uArr, 3000)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r *UDMAuthUser) Delete(imsi, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMAuthUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r *UDMAuthUser) DeletePrefixByIMSI(neId, imsi string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMAuthUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
@@ -1,26 +1,288 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
dborm "be.ems/lib/core/datasource"
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// UDM签约信息 数据层接口
|
||||
type IUDMSub interface {
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
ClearAndInsert(neId string, uArr []model.UDMSub) int64
|
||||
// 实例化数据层 UDMSubUser 结构体
|
||||
var NewUDMSub = &UDMSubUser{
|
||||
selectSql: `select
|
||||
s.id, s.msisdn, s.imsi, s.ambr, s.nssai, s.rat, s.arfb, s.sar, s.cn, s.sm_data, s.smf_sel, s.eps_dat,
|
||||
s.ne_id, s.eps_flag, s.eps_odb, s.hplmn_odb, s.ard, s.epstpl, s.context_id, s.apn_context, s.static_ip,
|
||||
s.cag,
|
||||
t.tenant_id, t.tenant_name
|
||||
from u_sub_user s
|
||||
left join sys_tenant t on t.tenant_id = s.tenant_id`,
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
SelectPage(query map[string]any) map[string]any
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"imsi": "IMSI",
|
||||
"msisdn": "MSISDN",
|
||||
"ne_id": "NeId",
|
||||
"ambr": "Ambr",
|
||||
"nssai": "Nssai",
|
||||
"rat": "Rat",
|
||||
"arfb": "Arfb",
|
||||
"sar": "Sar",
|
||||
"cn": "Cn",
|
||||
"sm_data": "SmData",
|
||||
"smf_sel": "SmfSel",
|
||||
"eps_dat": "EpsDat",
|
||||
"eps_flag": "EpsFlag",
|
||||
"eps_odb": "EpsOdb",
|
||||
"hplmn_odb": "HplmnOdb",
|
||||
"ard": "Ard",
|
||||
"epstpl": "Epstpl",
|
||||
"context_id": "ContextId",
|
||||
"apn_context": "ApnContext",
|
||||
"static_ip": "StaticIp",
|
||||
"cag": "Cag",
|
||||
|
||||
// SelectList 根据实体查询
|
||||
SelectList(u model.UDMSub) []model.UDMSub
|
||||
|
||||
// Insert 批量添加
|
||||
Inserts(uArr []model.UDMSub) int64
|
||||
|
||||
// Delete 删除实体
|
||||
Delete(neId, imsi string) int64
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
DeletePrefixByIMSI(neId, imsi string) int64
|
||||
"tenant_id": "TenantID",
|
||||
"tenant_name": "TenantName", // Tenant name for multi-tenancy
|
||||
},
|
||||
}
|
||||
|
||||
// UDMSubUser UDM签约信息表 数据层处理
|
||||
type UDMSubUser struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *UDMSubUser) convertResultRows(rows []map[string]any) []model.UDMSubUser {
|
||||
arr := make([]model.UDMSubUser, 0)
|
||||
for _, row := range rows {
|
||||
item := model.UDMSubUser{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *UDMSubUser) ClearAndInsert(neID string, u []model.UDMSubUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil)
|
||||
if err != nil {
|
||||
logger.Errorf("TRUNCATE err => %v", err)
|
||||
}
|
||||
|
||||
return r.Inserts(u)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询字典类型
|
||||
func (r *UDMSubUser) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
//conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
|
||||
//params = append(params, strings.Trim(v.(string), " "))
|
||||
conditions = append(conditions, "imsi like ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["neId"]; ok && v != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
// for multi-tenancy solution
|
||||
if v, ok := query["tenantName"]; ok && v != "" {
|
||||
var tenantID []string
|
||||
err := dborm.DefaultDB().Table("sys_tenant").
|
||||
Where("tenant_name=?", v).Cols("tenant_id").Distinct().Find(&tenantID)
|
||||
if err != nil {
|
||||
log.Errorf("Find tenant_id from sys_user err => %v", err)
|
||||
}
|
||||
log.Tracef("userName=%v, tenantID=%v", v, tenantID)
|
||||
if len(tenantID) > 0 {
|
||||
conditions = append(conditions, "s.tenant_id = ?")
|
||||
params = append(params, tenantID[0])
|
||||
}
|
||||
} else if v, ok := query["userName"]; ok && v != "" {
|
||||
var tenantID string
|
||||
_, err := dborm.DefaultDB().Table("sys_user").
|
||||
Where("user_name=?", v).Cols("tenant_id").Distinct().Get(&tenantID)
|
||||
if err != nil {
|
||||
log.Errorf("Find tenant_id from sys_user err => %v", err)
|
||||
}
|
||||
log.Tracef("userName=%v, tenantID=%v", v, tenantID)
|
||||
if tenantID != "" {
|
||||
conditions = append(conditions, "s.tenant_id = ?")
|
||||
params = append(params, tenantID)
|
||||
}
|
||||
// if len(tenantID) > 0 {
|
||||
// conditions = append(conditions, "s.tenant_id = ?")
|
||||
// params = append(params, tenantID[0])
|
||||
// }
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.UDMSubUser{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from u_sub_user s"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 排序
|
||||
orderSql := ""
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v.(string)
|
||||
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
|
||||
if o == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
orderSql = fmt.Sprintf(" order by %s ", sortSql)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + orderSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return result
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *UDMSubUser) SelectList(u model.UDMSubUser) []model.UDMSubUser {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if u.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, u.IMSI)
|
||||
}
|
||||
if u.NeId != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, u.NeId)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by imsi asc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIMSIAndNeID 通过imsi和ne_id查询
|
||||
func (r *UDMSubUser) SelectByIMSIAndNeID(imsi, neId string) model.UDMSubUser {
|
||||
querySql := r.selectSql + " where imsi = ? and ne_id = ?"
|
||||
results, err := datasource.RawDB("", querySql, []any{imsi, neId})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return model.UDMSubUser{}
|
||||
}
|
||||
// 转换实体
|
||||
rows := r.convertResultRows(results)
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return model.UDMSubUser{}
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r *UDMSubUser) Inserts(uArr []model.UDMSubUser) int64 {
|
||||
// multi-tenancy
|
||||
r.SetTenantID(&uArr)
|
||||
|
||||
tx := datasource.DefaultDB().CreateInBatches(uArr, 2000)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r *UDMSubUser) Delete(imsi, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMSubUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r *UDMSubUser) DeletePrefixByIMSI(imsiPrefix, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsiPrefix, neId).Delete(&model.UDMSubUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
func (r *UDMSubUser) SetTenantID(subArr *[]model.UDMSubUser) {
|
||||
for s := 0; s < len(*subArr); s++ {
|
||||
var tenantID []string
|
||||
err := dborm.DefaultDB().Table("sys_tenant").
|
||||
Where("status='1' and tenancy_type='IMSI' and ? like tenancy_key", (*subArr)[s].IMSI).
|
||||
Cols("parent_id").Distinct().Find(&tenantID)
|
||||
if err != nil {
|
||||
logger.Errorf("Find tenant_id err => %v", err)
|
||||
continue
|
||||
}
|
||||
if len(tenantID) > 0 {
|
||||
(*subArr)[s].TenantID = tenantID[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
dborm "be.ems/lib/core/datasource"
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 UDMSubImpl 结构体
|
||||
var NewUDMSubImpl = &UDMSubImpl{
|
||||
selectSql: `select
|
||||
s.id, s.msisdn, s.imsi, s.ambr, s.nssai, s.rat, s.arfb, s.sar, s.cn, s.sm_data, s.smf_sel, s.eps_dat,
|
||||
s.ne_id, s.eps_flag, s.eps_odb, s.hplmn_odb, s.ard, s.epstpl, s.context_id, s.apn_context, s.static_ip,
|
||||
t.tenant_id, t.tenant_name
|
||||
from u_sub_user s
|
||||
left join sys_tenant t on t.tenant_id = s.tenant_id`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"msisdn": "Msisdn",
|
||||
"imsi": "IMSI",
|
||||
"ambr": "Ambr",
|
||||
"nssai": "Nssai",
|
||||
"rat": "Rat",
|
||||
"arfb": "Arfb",
|
||||
"sar": "Sar",
|
||||
"cn": "Cn",
|
||||
"sm_data": "SmData",
|
||||
"smf_sel": "SmfSel",
|
||||
"eps_dat": "EpsDat",
|
||||
"ne_id": "NeId",
|
||||
"eps_flag": "EpsFlag",
|
||||
"eps_odb": "EpsOdb",
|
||||
"hplmn_odb": "HplmnOdb",
|
||||
"ard": "Ard",
|
||||
"epstpl": "Epstpl",
|
||||
"context_id": "ContextId",
|
||||
"apn_context": "ApnContext",
|
||||
"static_ip": "StaticIp",
|
||||
"tenant_id": "TenantID",
|
||||
"tenant_name": "TenantName", // Tenant name for multi-tenancy
|
||||
},
|
||||
}
|
||||
|
||||
// UDMSubImpl UDM签约信息表 数据层处理
|
||||
type UDMSubImpl struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *UDMSubImpl) convertResultRows(rows []map[string]any) []model.UDMSub {
|
||||
arr := make([]model.UDMSub, 0)
|
||||
for _, row := range rows {
|
||||
item := model.UDMSub{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *UDMSubImpl) ClearAndInsert(neID string, u []model.UDMSub) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil)
|
||||
if err != nil {
|
||||
logger.Errorf("TRUNCATE err => %v", err)
|
||||
}
|
||||
return r.Inserts(u)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询字典类型
|
||||
func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
//conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
|
||||
//params = append(params, strings.Trim(v.(string), " "))
|
||||
conditions = append(conditions, "imsi like ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["neId"]; ok && v != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
// for multi-tenancy solution
|
||||
if v, ok := query["tenantName"]; ok && v != "" {
|
||||
var tenantID []string
|
||||
err := dborm.DefaultDB().Table("sys_tenant").
|
||||
Where("tenant_name=?", v).Cols("tenant_id").Distinct().Find(&tenantID)
|
||||
if err != nil {
|
||||
log.Errorf("Find tenant_id from sys_user err => %v", err)
|
||||
}
|
||||
log.Tracef("userName=%v, tenantID=%v", v, tenantID)
|
||||
if len(tenantID) > 0 {
|
||||
conditions = append(conditions, "s.tenant_id = ?")
|
||||
params = append(params, tenantID[0])
|
||||
}
|
||||
} else if v, ok := query["userName"]; ok && v != "" {
|
||||
var tenantID string
|
||||
_, err := dborm.DefaultDB().Table("sys_user").
|
||||
Where("user_name=?", v).Cols("tenant_id").Distinct().Get(&tenantID)
|
||||
if err != nil {
|
||||
log.Errorf("Find tenant_id from sys_user err => %v", err)
|
||||
}
|
||||
log.Tracef("userName=%v, tenantID=%v", v, tenantID)
|
||||
if tenantID != "" {
|
||||
conditions = append(conditions, "s.tenant_id = ?")
|
||||
params = append(params, tenantID)
|
||||
}
|
||||
// if len(tenantID) > 0 {
|
||||
// conditions = append(conditions, "s.tenant_id = ?")
|
||||
// params = append(params, tenantID[0])
|
||||
// }
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.UDMSub{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from u_sub_user s"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 排序
|
||||
orderSql := ""
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v.(string)
|
||||
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
|
||||
if o == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
orderSql = fmt.Sprintf(" order by %s ", sortSql)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + orderSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return result
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if u.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, u.IMSI)
|
||||
}
|
||||
if u.NeId != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, u.NeId)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by imsi asc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r *UDMSubImpl) Inserts(uArr []model.UDMSub) int64 {
|
||||
// multi-tenancy
|
||||
r.SetTenantID(&uArr)
|
||||
|
||||
tx := datasource.DefaultDB().CreateInBatches(uArr, 2000)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r *UDMSubImpl) Delete(neId, imsi string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMSub{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r *UDMSubImpl) DeletePrefixByIMSI(neId, imsi string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMSub{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
func (r *UDMSubImpl) SetTenantID(subArr *[]model.UDMSub) {
|
||||
for s := 0; s < len(*subArr); s++ {
|
||||
var tenantID []string
|
||||
err := dborm.DefaultDB().Table("sys_tenant").
|
||||
Where("status='1' and tenancy_type='IMSI' and ? like tenancy_key", (*subArr)[s].IMSI).
|
||||
Cols("parent_id").Distinct().Find(&tenantID)
|
||||
if err != nil {
|
||||
logger.Errorf("Find tenant_id err => %v", err)
|
||||
continue
|
||||
}
|
||||
if len(tenantID) > 0 {
|
||||
(*subArr)[s].TenantID = tenantID[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,24 +11,21 @@ import (
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 UDMAuthImpl 结构体
|
||||
var NewUDMAuthImpl = &UDMAuthImpl{
|
||||
selectSql: `select id, imsi, amf, status, ki, algo_index, opc, ne_id from u_auth_user`,
|
||||
// 实例化数据层 UDMUserInfo 结构体
|
||||
var NewUDMUserInfo = &UDMUserInfo{
|
||||
selectSql: `select id, imsi, msisdn, ne_id, remark from u_user_info`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"imsi": "IMSI",
|
||||
"amf": "Amf",
|
||||
"status": "Status",
|
||||
"ki": "Ki",
|
||||
"algo_index": "AlgoIndex",
|
||||
"opc": "Opc",
|
||||
"ne_id": "NeId",
|
||||
"id": "ID",
|
||||
"imsi": "IMSI",
|
||||
"msisdn": "MSISDN",
|
||||
"ne_id": "NeId",
|
||||
"remark": "Remark",
|
||||
},
|
||||
}
|
||||
|
||||
// UDMAuthImpl UDM鉴权信息表 数据层处理
|
||||
type UDMAuthImpl struct {
|
||||
// UDMUserInfo UDM鉴权信息表 数据层处理
|
||||
type UDMUserInfo struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
@@ -36,10 +33,10 @@ type UDMAuthImpl struct {
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *UDMAuthImpl) convertResultRows(rows []map[string]any) []model.UDMAuth {
|
||||
arr := make([]model.UDMAuth, 0)
|
||||
func (r *UDMUserInfo) convertResultRows(rows []map[string]any) []model.UDMUserInfo {
|
||||
arr := make([]model.UDMUserInfo, 0)
|
||||
for _, row := range rows {
|
||||
item := model.UDMAuth{}
|
||||
item := model.UDMUserInfo{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
@@ -50,18 +47,8 @@ func (r *UDMAuthImpl) convertResultRows(rows []map[string]any) []model.UDMAuth {
|
||||
return arr
|
||||
}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *UDMAuthImpl) ClearAndInsert(neId string, uArr []model.UDMAuth) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil)
|
||||
if err != nil {
|
||||
logger.Errorf("TRUNCATE err => %v", err)
|
||||
}
|
||||
return r.Inserts(uArr)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
|
||||
func (r *UDMUserInfo) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
@@ -82,11 +69,11 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.UDMAuth{},
|
||||
"rows": []model.UDMUserInfo{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from u_auth_user"
|
||||
totalSql := "select count(1) as 'total' from u_user_info"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
@@ -132,7 +119,7 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth {
|
||||
func (r *UDMUserInfo) SelectList(u model.UDMUserInfo) []model.UDMUserInfo {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
@@ -162,8 +149,24 @@ func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth {
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIMSIAndNeID 通过imsi和ne_id查询
|
||||
func (r *UDMUserInfo) SelectByIMSIAndNeID(imsi, neId string) model.UDMUserInfo {
|
||||
querySql := r.selectSql + " where imsi = ? and ne_id = ?"
|
||||
results, err := datasource.RawDB("", querySql, []any{imsi, neId})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return model.UDMUserInfo{}
|
||||
}
|
||||
// 转换实体
|
||||
rows := r.convertResultRows(results)
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return model.UDMUserInfo{}
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r *UDMAuthImpl) Inserts(uArr []model.UDMAuth) int64 {
|
||||
func (r *UDMUserInfo) Inserts(uArr []model.UDMUserInfo) int64 {
|
||||
tx := datasource.DefaultDB().CreateInBatches(uArr, 3000)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
@@ -172,8 +175,8 @@ func (r *UDMAuthImpl) Inserts(uArr []model.UDMAuth) int64 {
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r *UDMAuthImpl) Delete(neId, imsi string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{})
|
||||
func (r *UDMUserInfo) Delete(imsi, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMUserInfo{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
@@ -181,8 +184,8 @@ func (r *UDMAuthImpl) Delete(neId, imsi string) int64 {
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r *UDMAuthImpl) DeletePrefixByIMSI(neId, imsi string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{})
|
||||
func (r *UDMUserInfo) DeletePrefixByIMSI(imsiPrefix, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsiPrefix, neId).Delete(&model.UDMUserInfo{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
}
|
||||
@@ -1,28 +1,172 @@
|
||||
package service
|
||||
|
||||
import "be.ems/src/modules/network_data/model"
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
// UDM鉴权信息 服务层接口
|
||||
type IUDMAuth interface {
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
ResetData(neId string) int64
|
||||
"be.ems/src/framework/redis"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
SelectPage(query map[string]any) map[string]any
|
||||
|
||||
// SelectList 查询数据库
|
||||
SelectList(u model.UDMAuth) []model.UDMAuth
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
Insert(neId string, u model.UDMAuth) int64
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
InsertData(neId, dataType string, data any) int64
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
Delete(neID, imsi string) int64
|
||||
|
||||
// LoadData 删除范围后重新加载 num表示imsi后几位
|
||||
LoadData(neID, imsi, num string) int64
|
||||
// 实例化服务层 UDMAuthUser 结构体
|
||||
var NewUDMAuthUser = &UDMAuthUser{
|
||||
udmAuthRepository: repository.NewUDMAuthUser,
|
||||
}
|
||||
|
||||
// UDM鉴权信息 服务层处理
|
||||
type UDMAuthUser struct {
|
||||
// UDM鉴权信息数据信息
|
||||
udmAuthRepository *repository.UDMAuthUser
|
||||
}
|
||||
|
||||
// dataByRedis UDM鉴权用户 db:0 中 ausf:*
|
||||
func (r *UDMAuthUser) dataByRedis(imsi, neId string) []model.UDMAuthUser {
|
||||
arr := []model.UDMAuthUser{}
|
||||
key := fmt.Sprintf("ausf:%s", imsi)
|
||||
ausfArr, err := redis.GetKeys("udmuser", key)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
for _, key := range ausfArr {
|
||||
m, err := redis.GetHash("udmuser", key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过-号数据 ausf:360000100000130
|
||||
imsi := key[5:]
|
||||
if strings.Contains(imsi, "-") {
|
||||
continue
|
||||
}
|
||||
|
||||
amf := ""
|
||||
if v, ok := m["amf"]; ok {
|
||||
amf = strings.Replace(v, "\r\n", "", 1)
|
||||
}
|
||||
a := model.UDMAuthUser{
|
||||
IMSI: imsi,
|
||||
Amf: amf,
|
||||
Status: "1", // 默认给1
|
||||
Ki: m["ki"],
|
||||
AlgoIndex: m["algo"],
|
||||
Opc: m["opc"],
|
||||
NeId: neId,
|
||||
}
|
||||
arr = append(arr, a)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
func (r *UDMAuthUser) ResetData(neId string) int64 {
|
||||
authArr := r.dataByRedis("*", neId)
|
||||
// 数据清空后添加
|
||||
go r.udmAuthRepository.ClearAndInsert(neId, authArr)
|
||||
return int64(len(authArr))
|
||||
}
|
||||
|
||||
// ParseInfo 解析单个用户imsi鉴权信息 data从命令MML得到的结果
|
||||
func (r *UDMAuthUser) ParseInfo(imsi, neId string, data map[string]string) model.UDMAuthUser {
|
||||
u := model.UDMAuthUser{
|
||||
IMSI: imsi,
|
||||
NeId: neId,
|
||||
Amf: data["amf"],
|
||||
Status: "1",
|
||||
Ki: data["ki"],
|
||||
AlgoIndex: data["algo"],
|
||||
Opc: data["opc"],
|
||||
}
|
||||
|
||||
// 补充用户ID用于更新
|
||||
auth := r.udmAuthRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||
if auth.IMSI == imsi {
|
||||
u.ID = auth.ID
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
func (r *UDMAuthUser) SelectPage(query map[string]any) map[string]any {
|
||||
return r.udmAuthRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectList 查询数据库
|
||||
func (r *UDMAuthUser) SelectList(u model.UDMAuthUser) []model.UDMAuthUser {
|
||||
return r.udmAuthRepository.SelectList(u)
|
||||
}
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
func (r *UDMAuthUser) Insert(neId string, u model.UDMAuthUser) int64 {
|
||||
uArr := r.dataByRedis(u.IMSI, neId)
|
||||
if len(uArr) > 0 {
|
||||
r.udmAuthRepository.Delete(u.IMSI, neId)
|
||||
return r.udmAuthRepository.Inserts(uArr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
func (r *UDMAuthUser) InsertData(neId, dataType string, data any) int64 {
|
||||
// imsi截取前缀,重新获取部分数据
|
||||
prefixes := make(map[string]struct{})
|
||||
|
||||
if dataType == "csv" {
|
||||
for _, v := range data.([]map[string]string) {
|
||||
imsi := v["imsi"]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
if dataType == "txt" {
|
||||
for _, v := range data.([][]string) {
|
||||
imsi := v[0]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据前缀重新加载插入
|
||||
var num int64 = 0
|
||||
for prefix := range prefixes {
|
||||
// 直接删除前缀的记录
|
||||
r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix)
|
||||
// keys ausf:4600001000004*
|
||||
arr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(arr) > 0 {
|
||||
num += r.udmAuthRepository.Inserts(arr)
|
||||
}
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
func (r *UDMAuthUser) Delete(imsi, neId string) int64 {
|
||||
return r.udmAuthRepository.Delete(imsi, neId)
|
||||
}
|
||||
|
||||
// LoadData 重新加载从imsi开始num的数据
|
||||
func (r *UDMAuthUser) LoadData(neId, imsi, num string) {
|
||||
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
|
||||
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||||
var i int64
|
||||
for i = 0; i < subNum; i++ {
|
||||
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
|
||||
// 删除原数据
|
||||
r.udmAuthRepository.Delete(keyIMSI, neId)
|
||||
// 加载数据
|
||||
arr := r.dataByRedis(keyIMSI, neId)
|
||||
if len(arr) < 1 {
|
||||
continue
|
||||
}
|
||||
r.udmAuthRepository.Inserts(arr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/redis"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// 实例化服务层 UDMAuthImpl 结构体
|
||||
var NewUDMAuthImpl = &UDMAuthImpl{
|
||||
udmAuthRepository: repository.NewUDMAuthImpl,
|
||||
}
|
||||
|
||||
// UDM鉴权信息 服务层处理
|
||||
type UDMAuthImpl struct {
|
||||
// UDM鉴权信息数据信息
|
||||
udmAuthRepository repository.IUDMAuth
|
||||
}
|
||||
|
||||
// dataByRedis UDM鉴权用户 db:0 中 ausf:*
|
||||
func (r *UDMAuthImpl) dataByRedis(imsi, neId string) []model.UDMAuth {
|
||||
arr := []model.UDMAuth{}
|
||||
key := fmt.Sprintf("ausf:%s", imsi)
|
||||
ausfArr, err := redis.GetKeys("udmuser", key)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
for _, key := range ausfArr {
|
||||
m, err := redis.GetHash("udmuser", key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过-号数据
|
||||
imsi := key[5:]
|
||||
if strings.Contains(imsi, "-") {
|
||||
continue
|
||||
}
|
||||
|
||||
amf := ""
|
||||
if v, ok := m["amf"]; ok {
|
||||
amf = strings.Replace(v, "\r\n", "", 1)
|
||||
}
|
||||
a := model.UDMAuth{
|
||||
IMSI: imsi,
|
||||
Amf: amf,
|
||||
Status: "1", // 默认给1
|
||||
Ki: m["ki"],
|
||||
AlgoIndex: m["algo"],
|
||||
Opc: m["opc"],
|
||||
NeId: neId,
|
||||
}
|
||||
arr = append(arr, a)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
func (r *UDMAuthImpl) ResetData(neId string) int64 {
|
||||
authArr := r.dataByRedis("*", neId)
|
||||
// 数据清空后添加
|
||||
go r.udmAuthRepository.ClearAndInsert(neId, authArr)
|
||||
return int64(len(authArr))
|
||||
}
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
|
||||
return r.udmAuthRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectList 查询数据库
|
||||
func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth {
|
||||
return r.udmAuthRepository.SelectList(u)
|
||||
}
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
func (r *UDMAuthImpl) Insert(neId string, u model.UDMAuth) int64 {
|
||||
uArr := r.dataByRedis(u.IMSI, neId)
|
||||
if len(uArr) > 0 {
|
||||
r.udmAuthRepository.Delete(neId, u.IMSI)
|
||||
return r.udmAuthRepository.Inserts(uArr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
func (r *UDMAuthImpl) InsertData(neId, dataType string, data any) int64 {
|
||||
// imsi截取前缀,重新获取部分数据
|
||||
prefixes := make(map[string]struct{})
|
||||
|
||||
if dataType == "csv" {
|
||||
for _, v := range data.([]map[string]string) {
|
||||
imsi := v["imsi"]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
if dataType == "txt" {
|
||||
for _, v := range data.([][]string) {
|
||||
imsi := v[0]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据前缀重新加载插入
|
||||
var num int64 = 0
|
||||
for prefix := range prefixes {
|
||||
// 直接删除前缀的记录
|
||||
r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix)
|
||||
// keys ausf:4600001000004*
|
||||
authArr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(authArr) > 0 {
|
||||
num += r.udmAuthRepository.Inserts(authArr)
|
||||
}
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
func (r *UDMAuthImpl) Delete(neId, imsi string) int64 {
|
||||
return r.udmAuthRepository.Delete(neId, imsi)
|
||||
}
|
||||
|
||||
// LoadData 删除范围后重新加载 num表示imsi后几位
|
||||
func (r *UDMAuthImpl) LoadData(neId, imsi, num string) int64 {
|
||||
prefix := imsi[:len(imsi)-len(num)-1]
|
||||
// 直接删除前缀的记录
|
||||
delNum := r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix)
|
||||
// keys ausf:4600001000004*
|
||||
authArr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(authArr) > 0 {
|
||||
return r.udmAuthRepository.Inserts(authArr)
|
||||
}
|
||||
return delNum
|
||||
}
|
||||
@@ -1,28 +1,254 @@
|
||||
package service
|
||||
|
||||
import "be.ems/src/modules/network_data/model"
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
// UDM签约用户信息 服务层接口
|
||||
type IUDMSub interface {
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
ResetData(neId string) int64
|
||||
"be.ems/src/framework/redis"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
SelectPage(query map[string]any) map[string]any
|
||||
|
||||
// SelectList 查询数据库
|
||||
SelectList(u model.UDMSub) []model.UDMSub
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
Insert(neId string, u model.UDMSub) int64
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
InsertData(neId, dataType string, data any) int64
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
Delete(neId, imsi string) int64
|
||||
|
||||
// LoadData 删除范围后重新加载 num表示imsi后几位
|
||||
LoadData(neId, imsi, num string) int64
|
||||
// 实例化服务层 UDMSubUser 结构体
|
||||
var NewUDMSub = &UDMSubUser{
|
||||
udmSubRepository: repository.NewUDMSub,
|
||||
udmUserInfoRepository: repository.NewUDMUserInfo,
|
||||
}
|
||||
|
||||
// UDM签约信息 服务层处理
|
||||
type UDMSubUser struct {
|
||||
// UDM签约信息数据信息
|
||||
udmSubRepository *repository.UDMSubUser
|
||||
// UDM用户IMSI信息数据信息
|
||||
udmUserInfoRepository *repository.UDMUserInfo
|
||||
}
|
||||
|
||||
// dataByRedis UDM签约用户 db:0 中 udm-sd:*
|
||||
func (r *UDMSubUser) dataByRedis(imsi, neId string) []model.UDMSubUser {
|
||||
arr := []model.UDMSubUser{}
|
||||
key := fmt.Sprintf("udm-sd:%s", imsi)
|
||||
udmsdArr, err := redis.GetKeys("udmuser", key)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
for _, key := range udmsdArr {
|
||||
m, err := redis.GetHash("udmuser", key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
a := model.UDMSubUser{
|
||||
IMSI: key[7:], // udm-sd:360000100000130
|
||||
MSISDN: m["gpsi"], // 8612300000130
|
||||
NeId: neId,
|
||||
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.Ambr = arr[0]
|
||||
a.Nssai = arr[1]
|
||||
a.Rat = arr[2]
|
||||
a.Arfb = arr[3]
|
||||
a.Sar = arr[4]
|
||||
a.Cn = arr[5]
|
||||
}
|
||||
// 1,64,24,65,def_eps,1,2,010200000000,-
|
||||
if v, ok := m["eps-dat"]; ok {
|
||||
arr := strings.Split(v, ",")
|
||||
// 跳过非常规数据
|
||||
if len(arr) > 9 {
|
||||
continue
|
||||
}
|
||||
a.EpsDat = v
|
||||
a.EpsFlag = arr[0]
|
||||
a.EpsOdb = arr[1]
|
||||
a.HplmnOdb = arr[2]
|
||||
a.Ard = arr[3]
|
||||
a.Epstpl = arr[4]
|
||||
a.ContextId = arr[5]
|
||||
a.ApnContext = arr[7]
|
||||
// [6] 是不要的,导入和导出不用
|
||||
a.StaticIp = arr[8]
|
||||
}
|
||||
|
||||
arr = append(arr, a)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
func (r *UDMSubUser) ResetData(neId string) int64 {
|
||||
subArr := r.dataByRedis("*", neId)
|
||||
// 数据清空后添加
|
||||
go r.udmSubRepository.ClearAndInsert(neId, subArr)
|
||||
return int64(len(subArr))
|
||||
}
|
||||
|
||||
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
|
||||
func (r *UDMSubUser) ParseInfo(imsi, neId string, data map[string]string) model.UDMSubUser {
|
||||
cnType, _ := strconv.ParseInt(data["CNType"][:4], 0, 64)
|
||||
rat, _ := strconv.ParseInt(data["RAT"][:4], 0, 64)
|
||||
msisdn := data["MSISDN"]
|
||||
if imsMsisdnLen := strings.Index(msisdn, ","); imsMsisdnLen != -1 {
|
||||
msisdn = msisdn[:imsMsisdnLen]
|
||||
}
|
||||
|
||||
u := model.UDMSubUser{
|
||||
IMSI: imsi,
|
||||
MSISDN: msisdn,
|
||||
NeId: neId,
|
||||
Ambr: data["AMBR"],
|
||||
Arfb: data["AreaForbidden"],
|
||||
Cn: fmt.Sprint(cnType),
|
||||
SmData: data["SM-Data(snssai+dnn[1..n])"],
|
||||
Sar: data["ServiceAreaRestriction"],
|
||||
Nssai: data["NSSAI"],
|
||||
SmfSel: data["Smf-Selection"],
|
||||
Cag: data["cag"],
|
||||
Rat: fmt.Sprint(rat),
|
||||
}
|
||||
// 1,64,24,65,def_eps,1,2,010200000000,-
|
||||
if v, ok := data["EPS-Data"]; ok {
|
||||
u.EpsDat = v
|
||||
arr := strings.Split(v, ",")
|
||||
u.EpsFlag = arr[0]
|
||||
u.EpsOdb = arr[1]
|
||||
u.HplmnOdb = arr[2]
|
||||
u.Ard = arr[3]
|
||||
u.Epstpl = arr[4]
|
||||
u.ContextId = arr[5]
|
||||
u.ApnContext = arr[7]
|
||||
// [6] 是不要的,导入和导出不用
|
||||
u.StaticIp = arr[8]
|
||||
}
|
||||
|
||||
// 补充用户ID用于更新
|
||||
sub := r.udmSubRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||
if sub.IMSI == imsi {
|
||||
u.ID = sub.ID
|
||||
}
|
||||
// 补充用户拓展信息
|
||||
info := r.udmUserInfoRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||
if info.IMSI == imsi {
|
||||
u.Remark = info.Remark
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
func (r *UDMSubUser) SelectPage(query map[string]any) map[string]any {
|
||||
return r.udmSubRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectList 查询数据库
|
||||
func (r *UDMSubUser) SelectList(u model.UDMSubUser) []model.UDMSubUser {
|
||||
return r.udmSubRepository.SelectList(u)
|
||||
}
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
func (r *UDMSubUser) Insert(neId string, u model.UDMSubUser) int64 {
|
||||
uArr := r.dataByRedis(u.IMSI, neId)
|
||||
if len(uArr) > 0 {
|
||||
r.udmSubRepository.Delete(u.IMSI, neId)
|
||||
// 新增到拓展信息
|
||||
if u.Remark != "" {
|
||||
r.udmUserInfoRepository.Delete(u.IMSI, neId)
|
||||
r.udmUserInfoRepository.Inserts([]model.UDMUserInfo{{
|
||||
IMSI: u.IMSI,
|
||||
MSISDN: u.MSISDN,
|
||||
NeId: u.NeId,
|
||||
Remark: u.Remark,
|
||||
}})
|
||||
}
|
||||
return r.udmSubRepository.Inserts(uArr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
func (r *UDMSubUser) InsertData(neId, dataType string, data any) int64 {
|
||||
// imsi截取前缀,重新获取部分数据
|
||||
prefixes := make(map[string]struct{})
|
||||
|
||||
if dataType == "csv" {
|
||||
for _, v := range data.([]map[string]string) {
|
||||
imsi := v["imsi"]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
if dataType == "txt" {
|
||||
for _, v := range data.([][]string) {
|
||||
imsi := v[0]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据前缀重新加载插入
|
||||
var num int64 = 0
|
||||
for prefix := range prefixes {
|
||||
// keys udm-sd:4600001000004*
|
||||
arr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(arr) > 0 {
|
||||
r.udmSubRepository.DeletePrefixByIMSI(prefix, neId)
|
||||
num += r.udmSubRepository.Inserts(arr)
|
||||
}
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
func (r *UDMSubUser) Delete(neId, imsi string) int64 {
|
||||
// 删除拓展信息
|
||||
r.udmUserInfoRepository.Delete(imsi, neId)
|
||||
return r.udmSubRepository.Delete(imsi, neId)
|
||||
}
|
||||
|
||||
// LoadData 重新加载从imsi开始num的数据
|
||||
// remark不为空,则新增到拓展信息,删除标记为-(Deleted)-
|
||||
func (r *UDMSubUser) LoadData(neId, imsi, num, remark string) {
|
||||
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
|
||||
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||||
var i int64
|
||||
for i = 0; i < subNum; i++ {
|
||||
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
|
||||
// 删除原数据
|
||||
r.udmSubRepository.Delete(keyIMSI, neId)
|
||||
if remark == "-(Deleted)-" {
|
||||
r.udmUserInfoRepository.Delete(keyIMSI, neId)
|
||||
}
|
||||
// 加载数据
|
||||
arr := r.dataByRedis(keyIMSI, neId)
|
||||
if len(arr) < 1 {
|
||||
continue
|
||||
}
|
||||
r.udmSubRepository.Inserts(arr)
|
||||
// 拓展信息
|
||||
if remark != "" {
|
||||
uarr := make([]model.UDMUserInfo, 0, len(arr))
|
||||
for _, v := range arr {
|
||||
uarr = append(uarr, model.UDMUserInfo{
|
||||
IMSI: v.IMSI,
|
||||
MSISDN: v.MSISDN,
|
||||
NeId: v.NeId,
|
||||
Remark: remark,
|
||||
})
|
||||
}
|
||||
r.udmUserInfoRepository.Delete(keyIMSI, neId)
|
||||
r.udmUserInfoRepository.Inserts(uarr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/redis"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// 实例化服务层 UDMSubImpl 结构体
|
||||
var NewUDMSubImpl = &UDMSubImpl{
|
||||
udmSubRepository: repository.NewUDMSubImpl,
|
||||
}
|
||||
|
||||
// UDM签约信息 服务层处理
|
||||
type UDMSubImpl struct {
|
||||
// UDM签约信息数据信息
|
||||
udmSubRepository repository.IUDMSub
|
||||
}
|
||||
|
||||
// dataByRedis UDM签约用户 db:0 中 udm-sd:*
|
||||
func (r *UDMSubImpl) dataByRedis(imsi, neId string) []model.UDMSub {
|
||||
arr := []model.UDMSub{}
|
||||
key := fmt.Sprintf("udm-sd:%s", imsi)
|
||||
udmsdArr, err := redis.GetKeys("udmuser", key)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
for _, key := range udmsdArr {
|
||||
m, err := redis.GetHash("udmuser", key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
a := model.UDMSub{
|
||||
IMSI: key[7:],
|
||||
Msisdn: m["gpsi"], // 46003550072
|
||||
SmfSel: m["smf-sel"],
|
||||
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
|
||||
NeId: neId,
|
||||
}
|
||||
|
||||
// def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,-
|
||||
if v, ok := m["am-dat"]; ok {
|
||||
arr := strings.Split(v, ",")
|
||||
a.Ambr = arr[0]
|
||||
a.Nssai = arr[1]
|
||||
a.Rat = arr[2]
|
||||
a.Arfb = arr[3]
|
||||
a.Sar = arr[4]
|
||||
a.Cn = arr[5]
|
||||
}
|
||||
// 1,64,24,65,def_eps,1,2,010200000000,-
|
||||
if v, ok := m["eps-dat"]; ok {
|
||||
arr := strings.Split(v, ",")
|
||||
// 跳过非常规数据
|
||||
if len(arr) > 9 {
|
||||
continue
|
||||
}
|
||||
a.EpsDat = v
|
||||
a.EpsFlag = arr[0]
|
||||
a.EpsOdb = arr[1]
|
||||
a.HplmnOdb = arr[2]
|
||||
a.Ard = arr[3]
|
||||
a.Epstpl = arr[4]
|
||||
a.ContextId = arr[5]
|
||||
a.ApnContext = arr[7]
|
||||
// [6] 是不要的,导入和导出不用
|
||||
a.StaticIp = arr[8]
|
||||
}
|
||||
|
||||
arr = append(arr, a)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
func (r *UDMSubImpl) ResetData(neId string) int64 {
|
||||
subArr := r.dataByRedis("*", neId)
|
||||
// 数据清空后添加
|
||||
go r.udmSubRepository.ClearAndInsert(neId, subArr)
|
||||
return int64(len(subArr))
|
||||
}
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
|
||||
return r.udmSubRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectList 查询数据库
|
||||
func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub {
|
||||
return r.udmSubRepository.SelectList(u)
|
||||
}
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
func (r *UDMSubImpl) Insert(neId string, u model.UDMSub) int64 {
|
||||
uArr := r.dataByRedis(u.IMSI, neId)
|
||||
if len(uArr) > 0 {
|
||||
r.udmSubRepository.Delete(neId, u.IMSI)
|
||||
return r.udmSubRepository.Inserts(uArr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
func (r *UDMSubImpl) InsertData(neId, dataType string, data any) int64 {
|
||||
// imsi截取前缀,重新获取部分数据
|
||||
prefixes := make(map[string]struct{})
|
||||
|
||||
if dataType == "csv" {
|
||||
for _, v := range data.([]map[string]string) {
|
||||
imsi := v["imsi"]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
if dataType == "txt" {
|
||||
for _, v := range data.([][]string) {
|
||||
imsi := v[0]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据前缀重新加载插入
|
||||
var num int64 = 0
|
||||
for prefix := range prefixes {
|
||||
// 直接删除前缀的记录
|
||||
r.udmSubRepository.DeletePrefixByIMSI(neId, prefix)
|
||||
// keys udm-sd:4600001000004*
|
||||
subArr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(subArr) > 0 {
|
||||
num += r.udmSubRepository.Inserts(subArr)
|
||||
}
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
func (r *UDMSubImpl) Delete(neId, imsi string) int64 {
|
||||
return r.udmSubRepository.Delete(neId, imsi)
|
||||
}
|
||||
|
||||
// LoadData 删除范围后重新加载 num表示imsi后几位
|
||||
func (r *UDMSubImpl) LoadData(neId, imsi, num string) int64 {
|
||||
prefix := imsi[:len(imsi)-len(num)-1]
|
||||
// 直接删除前缀的记录
|
||||
delNum := r.udmSubRepository.DeletePrefixByIMSI(neId, prefix)
|
||||
// keys udm-sd:4600001000004*
|
||||
authArr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(authArr) > 0 {
|
||||
return r.udmSubRepository.Inserts(authArr)
|
||||
}
|
||||
return delNum
|
||||
}
|
||||
33
src/modules/network_data/service/udm_user_info.go
Normal file
33
src/modules/network_data/service/udm_user_info.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
)
|
||||
|
||||
// 实例化服务层 UDMUserInfo 结构体
|
||||
var NewUDMUserInfo = &UDMUserInfo{
|
||||
udmUserInfoRepository: repository.NewUDMUserInfo,
|
||||
}
|
||||
|
||||
// UDM用户IMSI拓展信息 服务层处理
|
||||
type UDMUserInfo struct {
|
||||
// UDM用户IMSI信息数据信息
|
||||
udmUserInfoRepository *repository.UDMUserInfo
|
||||
}
|
||||
|
||||
// SelectByIMSIAndNeID 通过IMSI和网元标识查询信息
|
||||
func (r *UDMUserInfo) SelectByIMSIAndNeID(imsi, neId string) model.UDMUserInfo {
|
||||
return r.udmUserInfoRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||
}
|
||||
|
||||
// Save 新增或修改信息
|
||||
func (r *UDMUserInfo) Save(u model.UDMUserInfo) bool {
|
||||
r.udmUserInfoRepository.Delete(u.IMSI, u.NeId)
|
||||
return r.udmUserInfoRepository.Inserts([]model.UDMUserInfo{u}) > 0
|
||||
}
|
||||
|
||||
// Delete 删除信息
|
||||
func (r *UDMUserInfo) Delete(imsi, neId string) int64 {
|
||||
return r.udmUserInfoRepository.Delete(imsi, neId)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
cm_omc "be.ems/features/cm/omc"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
@@ -191,14 +192,25 @@ func (s *NeConfigController) DataInfo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 网元直连
|
||||
resData, err := neFetchlink.NeConfigInfo(neInfo, query.ParamName)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
if query.NeType == "OMC" {
|
||||
var o *cm_omc.ConfigOMC
|
||||
resData, err := o.Query(query.ParamName)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.OkData(resData))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 网元直连
|
||||
resData, err := neFetchlink.NeConfigInfo(neInfo, query.ParamName)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, result.Ok(resData))
|
||||
c.JSON(200, result.Ok(resData))
|
||||
}
|
||||
}
|
||||
|
||||
// 网元参数配置数据修改
|
||||
@@ -223,14 +235,24 @@ func (s *NeConfigController) DataEdit(c *gin.Context) {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元直连
|
||||
resData, err := neFetchlink.NeConfigUpdate(neInfo, body.ParamName, body.Loc, body.ParamData)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
if body.NeType == "OMC" {
|
||||
var o *cm_omc.ConfigOMC
|
||||
resData, err := o.Modify(body.ParamName, body.ParamData)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.OkData(resData))
|
||||
return
|
||||
} else {
|
||||
// 网元直连
|
||||
resData, err := neFetchlink.NeConfigUpdate(neInfo, body.ParamName, body.Loc, body.ParamData)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.OkData(resData))
|
||||
}
|
||||
c.JSON(200, result.OkData(resData))
|
||||
}
|
||||
|
||||
// 网元参数配置数据新增(array)
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/ssh"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/network_element/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
|
||||
@@ -193,7 +193,7 @@ func (s *NeInfoController) OAMFileRead(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
data, err := s.neInfoService.NeConfOAMRead(querys.NeType, querys.NeID)
|
||||
data, err := s.neInfoService.NeConfOAMReadSync(querys.NeType, querys.NeID)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
@@ -224,7 +224,7 @@ func (s *NeInfoController) OAMFileWrite(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err := s.neInfoService.NeConfOAMSync(neInfo, body.Content, body.Sync)
|
||||
err := s.neInfoService.NeConfOAMWirteSync(neInfo, body.Content, body.Sync)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
|
||||
68
src/modules/network_element/fetch_link/hlr.go
Normal file
68
src/modules/network_element/fetch_link/hlr.go
Normal 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.IP, 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(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.IP, 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(resData["message"])
|
||||
}
|
||||
@@ -52,9 +52,9 @@ func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) {
|
||||
|
||||
// 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.IP, neInfo.Port, strings.ToLower(neInfo.NeType), paramName)
|
||||
resBytes, err := fetch.Get(neUrl, nil, 60_000)
|
||||
resBytes, err := fetch.Get(neUrl, nil, 30_000)
|
||||
if err != nil {
|
||||
logger.Warnf("NeConfigInfo Get \"%s\"", neUrl)
|
||||
logger.Errorf("NeConfigInfo %s", err.Error())
|
||||
|
||||
121
src/modules/network_element/fetch_link/ne_trace.go
Normal file
121
src/modules/network_element/fetch_link/ne_trace.go
Normal file
@@ -0,0 +1,121 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// NeTraceInfo 网元跟踪任务信息
|
||||
func NeTraceInfo(neInfo model.NeInfo, traceId string) (map[string]any, error) {
|
||||
// 跟踪任务信息
|
||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions?id=%s", neInfo.IP, neInfo.Port, traceId)
|
||||
resBytes, err := fetch.Get(neUrl, nil, 30_000)
|
||||
if err != nil {
|
||||
logger.Warnf("NeTraceInfo Get \"%s\"", neUrl)
|
||||
logger.Errorf("NeTraceInfo %s", err.Error())
|
||||
return nil, fmt.Errorf("NeService Trace Info API Error")
|
||||
}
|
||||
|
||||
// 序列化结果
|
||||
var resData map[string]any
|
||||
err = json.Unmarshal(resBytes, &resData)
|
||||
if err != nil {
|
||||
logger.Errorf("NeTraceInfo Unmarshal %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return resData, nil
|
||||
}
|
||||
|
||||
// NeTraceAdd 网元跟踪任务新增
|
||||
func NeTraceAdd(neInfo model.NeInfo, data map[string]any) (map[string]any, error) {
|
||||
// 跟踪任务创建
|
||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions", neInfo.IP, neInfo.Port)
|
||||
resBytes, err := fetch.PostJSON(neUrl, data, nil)
|
||||
var resData map[string]any
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
logger.Warnf("NeTraceAdd POST \"%s\"", neUrl)
|
||||
if !(strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "400")) {
|
||||
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
|
||||
}
|
||||
|
||||
// NeTraceEdit 网元跟踪任务编辑
|
||||
func NeTraceEdit(neInfo model.NeInfo, data map[string]any) (map[string]any, error) {
|
||||
// 网元参数配置新增(array)
|
||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions", neInfo.IP, neInfo.Port)
|
||||
resBytes, err := fetch.PutJSON(neUrl, data, nil)
|
||||
var resData map[string]any
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
logger.Warnf("NeTraceEdit PUT \"%s\"", neUrl)
|
||||
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
|
||||
return resData, nil
|
||||
}
|
||||
logger.Errorf("NeTraceEdit %s", errStr)
|
||||
return nil, fmt.Errorf("NeService Trace Edit API Error")
|
||||
}
|
||||
|
||||
// 200 成功无数据时
|
||||
if len(resBytes) == 0 {
|
||||
return resData, nil
|
||||
}
|
||||
|
||||
// 序列化结果
|
||||
err = json.Unmarshal(resBytes, &resData)
|
||||
if err != nil {
|
||||
logger.Errorf("NeTraceEdit Unmarshal %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return resData, nil
|
||||
}
|
||||
|
||||
// NeTraceDelete 网元跟踪任务删除
|
||||
func NeTraceDelete(neInfo model.NeInfo, traceId string) (map[string]any, error) {
|
||||
// 网元参数配置删除(array)
|
||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions?id=%s", neInfo.IP, neInfo.Port, traceId)
|
||||
resBytes, err := fetch.Delete(neUrl, nil)
|
||||
var resData map[string]any
|
||||
if err != nil {
|
||||
errStr := err.Error()
|
||||
logger.Warnf("NeTraceDelete Delete \"%s\"", neUrl)
|
||||
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
|
||||
return resData, nil
|
||||
}
|
||||
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
|
||||
}
|
||||
68
src/modules/network_element/fetch_link/smf.go
Normal file
68
src/modules/network_element/fetch_link/smf.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package fetchlink
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/fetch"
|
||||
"be.ems/src/modules/network_element/model"
|
||||
)
|
||||
|
||||
// SMFSubInfo SMF在线订阅用户列表信息
|
||||
//
|
||||
// 查询参数 {"imsi":"360000100000130","msisdn":"8612300000130","upstate":"Inactive","pageNum":"1"}
|
||||
//
|
||||
// 返回结果 {"rows":[],"total":0}
|
||||
func SMFSubInfo(neInfo model.NeInfo, data map[string]string) (map[string]any, error) {
|
||||
// neUrl := "http://127.0.0.1:4523/m1/3157310-1528434-82b449ee/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo?apifoxApiId=150640017"
|
||||
neUrl := fmt.Sprintf("http://%s:%s/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo", "172.16.20.150", "33030")
|
||||
// neUrl := fmt.Sprintf("http://%s:%d/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo", neInfo.IP, neInfo.Port)
|
||||
// 查询参数拼接
|
||||
query := []string{}
|
||||
if v, ok := data["imsi"]; ok && v != "" {
|
||||
query = append(query, fmt.Sprintf("imsi=%s", v))
|
||||
}
|
||||
if v, ok := data["msisdn"]; ok && v != "" {
|
||||
query = append(query, fmt.Sprintf("msisdn=%s", v))
|
||||
}
|
||||
if v, ok := data["upstate"]; ok && v != "" {
|
||||
query = append(query, fmt.Sprintf("upstate=%s", v))
|
||||
}
|
||||
// 固定页数量50条
|
||||
if v, ok := data["pageNum"]; ok && v != "" {
|
||||
query = append(query, fmt.Sprintf("pageNum=%s", v))
|
||||
}
|
||||
|
||||
if len(query) > 0 {
|
||||
neUrl = fmt.Sprintf("%s?%s", neUrl, strings.Join(query, "&"))
|
||||
}
|
||||
|
||||
resBytes, err := fetch.Get(neUrl, nil, 60_000)
|
||||
if err != nil {
|
||||
logger.Warnf("SMFSubInfo Get \"%s\"", neUrl)
|
||||
logger.Errorf("SMFSubInfo %s", err.Error())
|
||||
return nil, fmt.Errorf("NeService SMF API Error")
|
||||
}
|
||||
|
||||
// 序列化结果 {"data":[],"total":0}
|
||||
var resData map[string]any
|
||||
err = json.Unmarshal(resBytes, &resData)
|
||||
if err != nil {
|
||||
logger.Errorf("SMFSubInfo Unmarshal %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 固定返回字段,方便前端解析
|
||||
if v, ok := resData["data"]; ok && v != nil {
|
||||
resData["rows"] = v.([]any)
|
||||
delete(resData, "data")
|
||||
} else {
|
||||
resData["rows"] = []any{}
|
||||
}
|
||||
if v, ok := resData["total"]; !ok || v == nil {
|
||||
resData["total"] = 0
|
||||
}
|
||||
return resData, nil
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
// 网元UDM服务,可能是8080、33030端口服务
|
||||
// 融合的UDM网元视情况调整。
|
||||
|
||||
package fetchlink
|
||||
|
||||
import (
|
||||
@@ -25,8 +28,7 @@ func UDMImportAuth(udmIP string, data map[string]any) (string, error) {
|
||||
}
|
||||
|
||||
// 序列化结果
|
||||
err = json.Unmarshal(resBytes, &resData)
|
||||
if err != nil {
|
||||
if err = json.Unmarshal(resBytes, &resData); err != nil {
|
||||
logger.Errorf("UDMImportAuth Unmarshal %s", err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
const (
|
||||
// 数据库
|
||||
DbHost = "192.168.8.58"
|
||||
DbHost = "127.0.0.1"
|
||||
DbPort = 33066
|
||||
DbUser = "root"
|
||||
DbPassswd = "1000omc@kp!"
|
||||
@@ -29,10 +29,10 @@ const (
|
||||
// 配置文件路径
|
||||
configParamDir = "../../../config/param"
|
||||
// configParamFile = "*" // 目录下全部更新
|
||||
configParamFile = "cbc_param_config.yaml" // 单文件更新
|
||||
configParamFile = "omc_param_config.yaml" // 单文件更新
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
func TestConfig(t *testing.T) {
|
||||
fileNameList, err := getDirFileNameList(configParamDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
@@ -2,7 +2,6 @@ package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -82,29 +81,21 @@ func (r *NeInfoImpl) convertResultRows(rows []map[string]any) []model.NeInfo {
|
||||
arr = append(arr, item)
|
||||
}
|
||||
|
||||
// 排序
|
||||
sort.Slice(arr, func(i, j int) bool {
|
||||
// 前一个
|
||||
after := arr[i]
|
||||
afterIndex := 0
|
||||
for i, v := range neListSort {
|
||||
if after.NeType == v {
|
||||
afterIndex = i
|
||||
break
|
||||
// 创建优先级映射
|
||||
priority := make(map[string]int)
|
||||
for i, v := range neListSort {
|
||||
priority[v] = i
|
||||
}
|
||||
// 冒泡排序
|
||||
n := len(arr)
|
||||
for i := 0; i < n-1; i++ {
|
||||
for j := 0; j < n-i-1; j++ {
|
||||
if priority[arr[j].NeType] > priority[arr[j+1].NeType] {
|
||||
// 交换元素
|
||||
arr[j], arr[j+1] = arr[j+1], arr[j]
|
||||
}
|
||||
}
|
||||
// 后一个
|
||||
befter := arr[j]
|
||||
befterIndex := 0
|
||||
for i, v := range neListSort {
|
||||
if befter.NeType == v {
|
||||
befterIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
// 升序
|
||||
return afterIndex < befterIndex
|
||||
})
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
@@ -188,7 +179,7 @@ func (r *NeInfoImpl) SelectPage(query map[string]any) map[string]any {
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by ne_type asc, ne_id desc " + pageSql
|
||||
querySql := r.selectSql + whereSql + " order by ne_type asc, ne_id asc " + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
@@ -221,7 +212,7 @@ func (r *NeInfoImpl) SelectList(neInfo model.NeInfo) []model.NeInfo {
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by ne_type asc, ne_id desc "
|
||||
querySql := r.selectSql + whereSql + " order by ne_type asc, ne_id asc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
|
||||
@@ -10,7 +10,7 @@ type INeHost interface {
|
||||
// SelectList 根据实体查询
|
||||
SelectList(neHost model.NeHost) []model.NeHost
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
// SelectById 通过ID查询
|
||||
SelectById(hostId string) model.NeHost
|
||||
|
||||
// CheckUniqueHostTitle 校验分组组和主机名称是否唯一
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ssh"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
"be.ems/src/modules/network_element/model"
|
||||
)
|
||||
|
||||
@@ -58,11 +58,11 @@ type INeInfo interface {
|
||||
// num 是网元主机telnet 1:4100 2:5200
|
||||
NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error)
|
||||
|
||||
// neConfOAMRead 网元OAM配置文件读取
|
||||
NeConfOAMRead(neType, neId string) (map[string]any, error)
|
||||
// NeConfOAMReadSync 网元OAM配置文件读取
|
||||
NeConfOAMReadSync(neType, neId string) (map[string]any, error)
|
||||
|
||||
// NeConfOAMSync 网元OAM配置文件生成并同步
|
||||
NeConfOAMSync(neInfo model.NeInfo, content map[string]any, sync bool) error
|
||||
// NeConfOAMWirteSync 网元OAM配置文件生成并同步
|
||||
NeConfOAMWirteSync(neInfo model.NeInfo, content map[string]any, sync bool) error
|
||||
|
||||
// NeConfPara5GRead 网元公共配置文件读取
|
||||
NeConfPara5GRead() (map[string]any, error)
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"be.ems/src/framework/constants/cachekey"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/redis"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/ssh"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||||
"be.ems/src/modules/network_element/model"
|
||||
"be.ems/src/modules/network_element/repository"
|
||||
@@ -429,13 +429,74 @@ func (r *NeInfoImpl) NeRunTelnetClient(neType, neId string, num int) (*telnet.Co
|
||||
return telnetClient, nil
|
||||
}
|
||||
|
||||
// NeConfOAMReadSync 网元OAM配置文件读取
|
||||
func (r *NeInfoImpl) NeConfOAMReadSync(neType, neId string) (map[string]any, error) {
|
||||
oamData, err := r.neConfOAMRead(neType, neId, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// UPF和SMF 全小写的key
|
||||
if _, ok := oamData["httpmanagecfg"]; ok {
|
||||
content := map[string]any{}
|
||||
// 网元HTTP服务
|
||||
// if v, ok := oamData["httpmanagecfg"]; ok {
|
||||
// item := v.(map[string]any)
|
||||
// }
|
||||
// 对网管HTTP配置
|
||||
if v, ok := oamData["oamconfig"]; ok {
|
||||
item := v.(map[string]any)
|
||||
if v, ok := item["iptype"]; ok && v != "" && v != nil {
|
||||
ipType := v.(string)
|
||||
if ipType == "ipv6" {
|
||||
content["omcIP"] = item["ipv6"]
|
||||
}
|
||||
if ipType == "ipv4" {
|
||||
content["omcIP"] = item["ipv4"]
|
||||
}
|
||||
}
|
||||
content["oamEnable"] = item["enable"]
|
||||
content["oamPort"] = item["port"]
|
||||
}
|
||||
// 对网管SNMP配置
|
||||
if v, ok := oamData["snmpconfig"]; ok {
|
||||
item := v.(map[string]any)
|
||||
content["snmpEnable"] = item["enable"]
|
||||
content["snmpPort"] = item["port"]
|
||||
}
|
||||
// 对网管KPI上报配置
|
||||
if v, ok := oamData["kpiconfig"]; ok {
|
||||
item := v.(map[string]any)
|
||||
content["kpiEnable"] = item["enable"]
|
||||
content["kpiTimer"] = item["timer"]
|
||||
}
|
||||
|
||||
oamData := r.neConfOAMData()
|
||||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||||
r.NeConfOAMWirteSync(model.NeInfo{
|
||||
NeType: neType,
|
||||
NeId: neId,
|
||||
}, content, false)
|
||||
return r.neConfOAMRead(neType, neId, false)
|
||||
}
|
||||
|
||||
// NSSF和MME 配置KPIconfig名不一致时
|
||||
if v, ok := oamData["KPIconfig"]; ok && v != nil {
|
||||
item := v.(map[string]any)
|
||||
oamData["kpiConfig"] = item
|
||||
delete(oamData, "KPIconfig")
|
||||
r.neConfOAMWirte(neType, neId, oamData, false)
|
||||
}
|
||||
|
||||
return oamData, nil
|
||||
}
|
||||
|
||||
// neConfOAMData 网元OAM配置文件默认格式数据
|
||||
func (r *NeInfoImpl) neConfOAMData() map[string]any {
|
||||
return map[string]any{
|
||||
"httpManageCfg": map[string]any{
|
||||
"ipType": "ipv4",
|
||||
// 必改
|
||||
"ipv4": "172.60.5.2",
|
||||
"ipv4": "172.16.5.1", // 必改
|
||||
"ipv6": "",
|
||||
"port": 33030,
|
||||
"scheme": "http",
|
||||
@@ -443,11 +504,12 @@ func (r *NeInfoImpl) neConfOAMData() map[string]any {
|
||||
"oamConfig": map[string]any{
|
||||
"enable": true,
|
||||
"ipType": "ipv4",
|
||||
"ipv4": "172.60.5.1", // 必改
|
||||
"ipv4": "172.16.5.100", // 必改
|
||||
"ipv6": "",
|
||||
"port": 33030,
|
||||
"scheme": "http",
|
||||
"neConfig": map[string]any{ // 必改
|
||||
// 必改
|
||||
"neConfig": map[string]any{
|
||||
"neId": "001",
|
||||
"rmUid": "4400HX1XXX001",
|
||||
"neName": "XXX_001",
|
||||
@@ -460,7 +522,7 @@ func (r *NeInfoImpl) neConfOAMData() map[string]any {
|
||||
"snmpConfig": map[string]any{
|
||||
"enable": false,
|
||||
"ipType": "ipv4",
|
||||
"ipv4": "172.60.5.2", // 必改
|
||||
"ipv4": "172.16.5.1", // 必改
|
||||
"ipv6": "",
|
||||
"port": 4957,
|
||||
},
|
||||
@@ -472,15 +534,39 @@ func (r *NeInfoImpl) neConfOAMData() map[string]any {
|
||||
}
|
||||
}
|
||||
|
||||
// neConfOAMRead 网元OAM配置文件读取
|
||||
func (r *NeInfoImpl) NeConfOAMRead(neType, neId string) (map[string]any, error) {
|
||||
// neConfOAMRead 网元OAM配置文件读取 sync从网元端同步到本地
|
||||
func (r *NeInfoImpl) neConfOAMRead(neType, neId string, sync bool) (map[string]any, error) {
|
||||
neTypeLower := strings.ToLower(neType)
|
||||
fileName := "oam_manager.yaml"
|
||||
// 网管本地路径
|
||||
omcPath := "/usr/local/etc/omc/ne_config"
|
||||
localFilePath := fmt.Sprintf("/usr/local/etc/omc/ne_config/%s/%s/%s", neTypeLower, neId, fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
omcPath = fmt.Sprintf("C:%s", omcPath)
|
||||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||||
}
|
||||
|
||||
// 从网元端同步到本地
|
||||
if sync {
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := NewNeInfoImpl.NeRunSSHClient(neType, neId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ne info ssh client err")
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ne info sftp client err")
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
// 网元端文件路径
|
||||
neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, fileName)
|
||||
// 修改网元文件权限
|
||||
sshClient.RunCMD(fmt.Sprintf("sudo touch %s && sudo chmod o+rw %s", neFilePath, neFilePath))
|
||||
// 网元端复制到本地
|
||||
if err = sftpClient.CopyFileRemoteToLocal(neFilePath, localFilePath); err != nil {
|
||||
return nil, fmt.Errorf("copy oam config err")
|
||||
}
|
||||
}
|
||||
localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neId, "oam_manager.yaml")
|
||||
|
||||
// 读取文件内容
|
||||
bytes, err := os.ReadFile(localFilePath)
|
||||
@@ -538,7 +624,7 @@ func (r *NeInfoImpl) neConfOAMWirte(neType, neId string, content any, sync bool)
|
||||
neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, fileName)
|
||||
neFileDir := filepath.ToSlash(filepath.Dir(neFilePath))
|
||||
// 修改网元文件权限
|
||||
sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+w %s", neFileDir, neFileDir, neFilePath, neFilePath))
|
||||
sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+rw %s", neFileDir, neFileDir, neFilePath, neFilePath))
|
||||
// 复制到网元进行覆盖
|
||||
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
|
||||
return fmt.Errorf("please check if scp remote copy is allowed")
|
||||
@@ -548,9 +634,9 @@ func (r *NeInfoImpl) neConfOAMWirte(neType, neId string, content any, sync bool)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NeConfOAMSync 网元OAM配置文件生成并同步
|
||||
func (r *NeInfoImpl) NeConfOAMSync(neInfo model.NeInfo, content map[string]any, sync bool) error {
|
||||
oamData, err := r.NeConfOAMRead(neInfo.NeType, neInfo.NeId)
|
||||
// NeConfOAMWirteSync 网元OAM配置文件生成并同步
|
||||
func (r *NeInfoImpl) NeConfOAMWirteSync(neInfo model.NeInfo, content map[string]any, sync bool) error {
|
||||
oamData, err := r.neConfOAMRead(neInfo.NeType, neInfo.NeId, false)
|
||||
if oamData == nil || err != nil {
|
||||
return fmt.Errorf("error read OAM file info")
|
||||
}
|
||||
@@ -638,6 +724,8 @@ func (r *NeInfoImpl) NeConfOAMSync(neInfo model.NeInfo, content map[string]any,
|
||||
item := v.(map[string]any)
|
||||
if neInfo.NeType == "UPF" {
|
||||
item["timer"] = 5
|
||||
} else {
|
||||
item["timer"] = 60
|
||||
}
|
||||
|
||||
if kpiEnable, ok := content["kpiEnable"]; ok && kpiEnable != nil {
|
||||
|
||||
@@ -200,18 +200,26 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri
|
||||
cmdStrArr := []string{}
|
||||
if neType == "OMC" {
|
||||
omcStrArr := []string{}
|
||||
omcStrArr = append(omcStrArr, pkgCmdStr)
|
||||
if action == "install" {
|
||||
omcStrArr = append(omcStrArr, "/usr/local/omc/bin/setomc.sh -m install") // 初始化数据库
|
||||
// 安装软件包
|
||||
pkgCmdStr = fmt.Sprintf("sudo M_PARAM=install dpkg -i %s", strings.Join(neFilePaths, " "))
|
||||
if strings.HasSuffix(fileExt, "rpm") {
|
||||
pkgCmdStr = fmt.Sprintf("sudo M_PARAM=install rpm -Uvh %s", strings.Join(neFilePaths, " "))
|
||||
}
|
||||
omcStrArr = append(omcStrArr, pkgCmdStr)
|
||||
} else {
|
||||
omcStrArr = append(omcStrArr, "/usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库
|
||||
// 升级软件包
|
||||
pkgCmdStr = fmt.Sprintf("sudo M_PARAM=upgrade dpkg -i %s", strings.Join(neFilePaths, " "))
|
||||
if strings.HasSuffix(fileExt, "rpm") {
|
||||
pkgCmdStr = fmt.Sprintf("sudo M_PARAM=upgrade rpm -Uvh %s", strings.Join(neFilePaths, " "))
|
||||
}
|
||||
omcStrArr = append(omcStrArr, pkgCmdStr)
|
||||
}
|
||||
omcStrArr = append(omcStrArr, "sudo systemctl restart restagent") // 重启服务
|
||||
omcStrArr = append(omcStrArr, fmt.Sprintf("sudo rm %s", strings.Join(neFilePaths, " "))) // 删除软件包
|
||||
// 删除软件包
|
||||
omcStrArr = append(omcStrArr, fmt.Sprintf("sudo rm %s", strings.Join(neFilePaths, " ")))
|
||||
|
||||
// 2s后安装
|
||||
// 2s后执行omc相关命令
|
||||
cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 2s && %s\" > /tmp/omc_%s.out 2>&1 & \n", strings.Join(omcStrArr, " && "), action))
|
||||
// 结束
|
||||
cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr))
|
||||
return okFlagStr, cmdStrArr, nil
|
||||
} else if neType == "IMS" {
|
||||
@@ -473,14 +481,14 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri
|
||||
if strings.Contains(pkgCmdStr, "adb") {
|
||||
para5GData := NewNeInfoImpl.Para5GData
|
||||
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n")
|
||||
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["DB_IP"]))
|
||||
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind 127.0.0.1 %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["DB_IP"]))
|
||||
cmdStrArr = append(cmdStrArr, "sudo service adb restart \n")
|
||||
}
|
||||
// kvdb
|
||||
if strings.Contains(pkgCmdStr, "kvdb") {
|
||||
para5GData := NewNeInfoImpl.Para5GData
|
||||
cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/kvdb/default/kvdb.conf /usr/local/etc/kvdb/kvdb.conf \n")
|
||||
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/kvdb/kvdb.conf \n", para5GData["DB_IP"]))
|
||||
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind 127.0.0.1 %s/g\" /usr/local/etc/kvdb/kvdb.conf \n", para5GData["DB_IP"]))
|
||||
cmdStrArr = append(cmdStrArr, "sudo service kvdb restart \n")
|
||||
}
|
||||
}
|
||||
@@ -592,7 +600,7 @@ func (r *NeVersionImpl) operateDome(action string, neVersion model.NeVersion) er
|
||||
return fmt.Errorf("error found neinfo")
|
||||
}
|
||||
// ========= 网元OAM配置文件 start ==========
|
||||
if err := NewNeInfoImpl.NeConfOAMSync(neInfo, nil, true); err != nil {
|
||||
if err := NewNeInfoImpl.NeConfOAMWirteSync(neInfo, nil, true); err != nil {
|
||||
return fmt.Errorf("error wirte OAM file info")
|
||||
}
|
||||
// ========= 网元OAM配置文件 end ===========
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
// 实例化控制层 TcpdumpController 结构体
|
||||
var NewTcpdump = &TcpdumpController{
|
||||
TcpdumpService: traceService.NewTcpdumpImpl,
|
||||
TcpdumpService: traceService.NewTCPdump,
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ var NewTcpdump = &TcpdumpController{
|
||||
// PATH /tcpdump
|
||||
type TcpdumpController struct {
|
||||
// 信令抓包服务
|
||||
TcpdumpService traceService.ITcpdump
|
||||
TcpdumpService *traceService.TCPdump
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
|
||||
62
src/modules/trace/controller/trace_data.go
Normal file
62
src/modules/trace/controller/trace_data.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo/result"
|
||||
traceService "be.ems/src/modules/trace/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 TraceDataController 结构体
|
||||
var NewTraceData = &TraceDataController{
|
||||
traceDataService: traceService.NewTraceData,
|
||||
}
|
||||
|
||||
// 跟踪任务数据
|
||||
//
|
||||
// PATH /data
|
||||
type TraceDataController struct {
|
||||
// 跟踪_数据信息服务
|
||||
traceDataService *traceService.TraceData
|
||||
}
|
||||
|
||||
// 跟踪任务数据列表
|
||||
//
|
||||
// GET /list
|
||||
func (s *TraceDataController) List(c *gin.Context) {
|
||||
query := ctx.QueryMap(c)
|
||||
|
||||
// 查询数据
|
||||
data := s.traceDataService.SelectPage(query)
|
||||
c.JSON(200, result.Ok(data))
|
||||
}
|
||||
|
||||
// 跟踪任务数据删除
|
||||
//
|
||||
// DELETE /:ids
|
||||
func (s *TraceDataController) Remove(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
rowIds := c.Param("ids")
|
||||
if rowIds == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
// 处理字符转id数组后去重
|
||||
ids := strings.Split(rowIds, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
}
|
||||
rows, err := s.traceDataService.DeleteByIds(uniqueIDs)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
|
||||
c.JSON(200, result.OkMsg(msg))
|
||||
}
|
||||
131
src/modules/trace/controller/trace_task.go
Normal file
131
src/modules/trace/controller/trace_task.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/trace/model"
|
||||
traceService "be.ems/src/modules/trace/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 实例化控制层 TraceTaskController 结构体
|
||||
var NewTraceTask = &TraceTaskController{
|
||||
traceTaskService: traceService.NewTraceTask,
|
||||
}
|
||||
|
||||
// 跟踪任务
|
||||
//
|
||||
// PATH /task
|
||||
type TraceTaskController struct {
|
||||
// 跟踪_任务信息服务
|
||||
traceTaskService *traceService.TraceTask
|
||||
}
|
||||
|
||||
// 跟踪任务列表
|
||||
//
|
||||
// GET /list
|
||||
func (s *TraceTaskController) List(c *gin.Context) {
|
||||
query := ctx.QueryMap(c)
|
||||
|
||||
// 查询数据
|
||||
data := s.traceTaskService.SelectPage(query)
|
||||
c.JSON(200, result.Ok(data))
|
||||
}
|
||||
|
||||
// 跟踪任务信息
|
||||
//
|
||||
// GET /:id
|
||||
func (s *TraceTaskController) Info(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
data := s.traceTaskService.SelectById(id)
|
||||
if data.ID == id {
|
||||
c.JSON(200, result.OkData(data))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.Err(nil))
|
||||
}
|
||||
|
||||
// 跟踪任务新增
|
||||
//
|
||||
// POST /
|
||||
func (s *TraceTaskController) Add(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body model.TraceTask
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.ID != "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
body.CreateBy = ctx.LoginUserToUserName(c)
|
||||
if err = s.traceTaskService.Insert(body); err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.Ok(nil))
|
||||
}
|
||||
|
||||
// 跟踪任务修改
|
||||
//
|
||||
// PUT /
|
||||
func (s *TraceTaskController) Edit(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body model.TraceTask
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || body.ID == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否存在
|
||||
taskInfo := s.traceTaskService.SelectById(body.ID)
|
||||
if taskInfo.ID != body.ID {
|
||||
// 没有可访问任务信息数据!
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "task.noData")))
|
||||
return
|
||||
}
|
||||
|
||||
body.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
if err = s.traceTaskService.Update(body); err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.Ok(nil))
|
||||
}
|
||||
|
||||
// 跟踪任务删除
|
||||
//
|
||||
// DELETE /:ids
|
||||
func (s *TraceTaskController) Remove(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
rowIds := c.Param("ids")
|
||||
if rowIds == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
// 处理字符转id数组后去重
|
||||
ids := strings.Split(rowIds, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
}
|
||||
rows, err := s.traceTaskService.DeleteByIds(uniqueIDs)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
|
||||
c.JSON(200, result.OkMsg(msg))
|
||||
}
|
||||
242
src/modules/trace/controller/trace_task_hlr.go
Normal file
242
src/modules/trace/controller/trace_task_hlr.go
Normal file
@@ -0,0 +1,242 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/generate"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo/result"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
"be.ems/src/modules/trace/model"
|
||||
traceService "be.ems/src/modules/trace/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 实例化控制层 TraceTaskHlrController 结构体
|
||||
var NewTraceTaskHlr = &TraceTaskHlrController{
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
traceTaskHlrService: traceService.NewTraceTaskHlr,
|
||||
}
|
||||
|
||||
// 跟踪任务网元HLR
|
||||
//
|
||||
// PATH /task/hlr
|
||||
type TraceTaskHlrController struct {
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
// 跟踪_任务给HRL网元信息服务
|
||||
traceTaskHlrService *traceService.TraceTaskHlr
|
||||
}
|
||||
|
||||
// 跟踪任务列表
|
||||
//
|
||||
// GET /list
|
||||
func (s *TraceTaskHlrController) List(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var querys model.TraceTaskHlrQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
data := s.traceTaskHlrService.SelectPage(querys)
|
||||
c.JSON(200, result.Ok(data))
|
||||
}
|
||||
|
||||
// 跟踪任务删除
|
||||
//
|
||||
// DELETE /:ids
|
||||
func (s *TraceTaskHlrController) Remove(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
rowIds := c.Param("ids")
|
||||
if rowIds == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
// 处理字符转id数组后去重
|
||||
ids := strings.Split(rowIds, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
}
|
||||
rows, err := s.traceTaskHlrService.DeleteByIds(uniqueIDs)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
|
||||
c.JSON(200, result.OkMsg(msg))
|
||||
}
|
||||
|
||||
// 跟踪任务创建
|
||||
//
|
||||
// POST /start
|
||||
func (s *TraceTaskHlrController) Start(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
IMSI string `json:"imsi"` // IMSI
|
||||
MSISDN string `json:"msisdn"` // MSISDN
|
||||
StartTime int64 `json:"startTime"` // 开始时间
|
||||
EndTime int64 `json:"endTime"` // 结束时间
|
||||
Remark string `json:"remark"` // 备注说明
|
||||
}
|
||||
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
if body.IMSI == "" && body.MSISDN == "" {
|
||||
c.JSON(400, result.CodeMsg(400, "imsi amd msisdn is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
task := model.TraceTaskHlr{
|
||||
IMSI: body.IMSI,
|
||||
MSISDN: body.MSISDN,
|
||||
StartTime: body.StartTime,
|
||||
EndTime: body.EndTime,
|
||||
Remark: body.Remark,
|
||||
CreateBy: ctx.LoginUserToUserName(c),
|
||||
}
|
||||
id, err := s.traceTaskHlrService.Start(task)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.OkData(id))
|
||||
}
|
||||
|
||||
// 跟踪任务停止
|
||||
//
|
||||
// POST /stop
|
||||
func (s *TraceTaskHlrController) Stop(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
ID string `json:"id" binding:"required"` // 任务ID
|
||||
}
|
||||
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 处理字符转id数组后去重
|
||||
ids := strings.Split(body.ID, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
}
|
||||
|
||||
errArr := []map[string]any{}
|
||||
for _, id := range uniqueIDs {
|
||||
task := s.traceTaskHlrService.SelectById(id)
|
||||
if task.ID != id || task.ID == "" {
|
||||
errArr = append(errArr, map[string]any{"id": id, "err": "task not found"})
|
||||
continue
|
||||
}
|
||||
|
||||
task.UpdateBy = ctx.LoginUserToUserName(c)
|
||||
err := s.traceTaskHlrService.Stop(task)
|
||||
if err != nil {
|
||||
errArr = append(errArr, map[string]any{"id": id, "err": err.Error()})
|
||||
continue
|
||||
}
|
||||
}
|
||||
c.JSON(200, result.OkData(errArr))
|
||||
}
|
||||
|
||||
// 跟踪任务文件
|
||||
//
|
||||
// POST /file
|
||||
func (s *TraceTaskHlrController) File(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
ID string `json:"id" binding:"required"` // 任务ID
|
||||
Dir string `json:"dir" binding:"required"` // 网元文件目录
|
||||
}
|
||||
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
task := s.traceTaskHlrService.SelectById(body.ID)
|
||||
if task.ID != body.ID || task.ID == "" {
|
||||
c.JSON(200, result.CodeMsg(400, "task not found"))
|
||||
return
|
||||
}
|
||||
|
||||
list, err := s.traceTaskHlrService.File(task.TraceId, body.Dir)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, result.OkData(list))
|
||||
}
|
||||
|
||||
// 跟踪任务文件从网元到本地
|
||||
//
|
||||
// GET /filePull
|
||||
func (s *TraceTaskHlrController) FilePull(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var querys struct {
|
||||
NeType string `form:"neType" binding:"required"`
|
||||
NeID string `form:"neId" binding:"required"`
|
||||
Path string `form:"path" binding:"required"`
|
||||
FileName string `form:"fileName" binding:"required"`
|
||||
DelTemp bool `form:"delTemp"` // 删除本地临时文件
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
|
||||
if neInfo.NeId != querys.NeID || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
nePath := filepath.ToSlash(filepath.Join(querys.Path, querys.FileName))
|
||||
fileName := generate.Code(6) + "_" + querys.FileName
|
||||
localFilePath := filepath.Join("/tmp/omc/pull", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||||
}
|
||||
// 复制到本地
|
||||
if err = sftpClient.CopyFileRemoteToLocal(nePath, localFilePath); err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if querys.DelTemp {
|
||||
_ = os.Remove(localFilePath)
|
||||
}
|
||||
}()
|
||||
c.FileAttachment(localFilePath, fileName)
|
||||
}
|
||||
23
src/modules/trace/model/trace_data.go
Normal file
23
src/modules/trace/model/trace_data.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package model
|
||||
|
||||
// TraceData 跟踪_数据 trace_data
|
||||
type TraceData struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
TaskId int64 `json:"taskId" gorm:"task_id"` // 任务ID
|
||||
IMSI string `json:"imsi" gorm:"imsi"`
|
||||
MSISDN string `json:"msisdn" gorm:"msisdn"` // 可能存在
|
||||
SrcAddr string `json:"srcAddr" gorm:"src_addr"` // 源地址带端口
|
||||
DstAddr string `json:"dstAddr" gorm:"dst_addr"` // 目标地址带端口
|
||||
IfType int64 `json:"ifType" gorm:"if_type"` // 接口类型,未分类
|
||||
MsgType int64 `json:"msgType" gorm:"msg_type"`
|
||||
MsgDirect int64 `json:"msgDirect" gorm:"msg_direct"`
|
||||
Length int64 `json:"length" gorm:"length"` // 去除头后的原始数据byte长度
|
||||
Timestamp int64 `json:"timestamp" gorm:"timestamp"` // 毫秒
|
||||
RawMsg string `json:"rawMsg" gorm:"raw_msg"` // 去除头后的原始数据byteBase64
|
||||
DecMsg string `json:"decMsg" gorm:"dec_msg"` // TCP内容消息
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*TraceData) TableName() string {
|
||||
return "trace_data"
|
||||
}
|
||||
31
src/modules/trace/model/trace_task.go
Normal file
31
src/modules/trace/model/trace_task.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package model
|
||||
|
||||
// TraceTask 跟踪_任务
|
||||
type TraceTask struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 跟踪任务ID
|
||||
TraceId string `json:"traceId" gorm:"trace_id"` // 任务编号
|
||||
TraceType string `json:"traceType" gorm:"trace_type"` // 1-Interface,2-Device,3-User
|
||||
StartTime int64 `json:"startTime" gorm:"start_time"` // 开始时间 毫秒
|
||||
EndTime int64 `json:"endTime" gorm:"end_time"` // 结束时间 毫秒
|
||||
Interfaces string `json:"interfaces" gorm:"interfaces"` // 接口跟踪必须 例如 N8,N10
|
||||
IMSI string `json:"imsi" gorm:"imsi"` // 用户跟踪必须
|
||||
MSISDN string `json:"msisdn" gorm:"msisdn"` // 用户跟踪可选
|
||||
UeIp string `json:"ueIp" gorm:"ue_ip"` // 设备跟踪必须 IP
|
||||
SrcIp string `json:"srcIp" gorm:"src_ip"` // 源地址IP
|
||||
DstIp string `json:"dstIp" gorm:"dst_ip"` // 目标地址IP
|
||||
SignalPort int64 `json:"signalPort" gorm:"signal_port"` // 地址IP端口
|
||||
CreateBy string `json:"createBy" gorm:"create_by"` // 创建者
|
||||
CreateTime int64 `json:"createTime" gorm:"create_time"` // 创建时间
|
||||
UpdateBy string `json:"updateBy" gorm:"update_by"` // 更新者
|
||||
UpdateTime int64 `json:"updateTime" gorm:"update_time"` // 更新时间
|
||||
Remark string `json:"remark" gorm:"remark"` // 备注
|
||||
NeType string `json:"neType" gorm:"ne_type"` // 网元类型
|
||||
NeId string `json:"neId" gorm:"ne_id"` // 网元ID
|
||||
NotifyUrl string `json:"notifyUrl" gorm:"notify_url"` // 信息数据通知回调地址UDP 例如udp:192.168.5.58:29500
|
||||
FetchMsg string `json:"fetchMsg" gorm:"fetch_msg"` // 任务下发请求响应消息
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*TraceTask) TableName() string {
|
||||
return "trace_task"
|
||||
}
|
||||
35
src/modules/trace/model/trace_task_hlr.go
Normal file
35
src/modules/trace/model/trace_task_hlr.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package model
|
||||
|
||||
// TraceTaskHlr 跟踪_任务给HRL网元 trace_task_hlr
|
||||
type TraceTaskHlr struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
|
||||
TraceId string `json:"traceId" gorm:"trace_id"` // 任务编号
|
||||
IMSI string `json:"imsi" gorm:"imsi"` // IMSI
|
||||
MSISDN string `json:"msisdn" gorm:"msisdn"` // MSISDN
|
||||
StartTime int64 `json:"startTime" gorm:"start_time"` // 开始时间
|
||||
EndTime int64 `json:"endTime" gorm:"end_time"` // 结束时间
|
||||
Status string `json:"status" gorm:"status"` // 任务状态(0停止 1进行)
|
||||
Msg string `json:"msg" gorm:"msg"` // 任务信息
|
||||
Remark string `json:"remark" gorm:"remark"` // 备注说明
|
||||
CreateBy string `json:"createBy" gorm:"create_by"` // 创建者
|
||||
CreateTime int64 `json:"createTime" gorm:"create_time"` // 创建时间
|
||||
UpdateBy string `json:"updateBy" gorm:"update_by"` // 更新者
|
||||
UpdateTime int64 `json:"updateTime" gorm:"update_time"` // 更新时间
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*TraceTaskHlr) TableName() string {
|
||||
return "trace_task_hlr"
|
||||
}
|
||||
|
||||
// TraceTaskHlrQuery 查询参数结构体
|
||||
type TraceTaskHlrQuery struct {
|
||||
IMSI string `json:"imsi" form:"imsi"` // imsi
|
||||
MSISDN string `json:"msisdn" form:"msisdn"` // msisdn
|
||||
StartTime string `json:"startTime" form:"startTime"`
|
||||
EndTime string `json:"endTime" form:"endTime"`
|
||||
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=imsi msisdn"` // 排序字段,填写结果字段
|
||||
SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc
|
||||
PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"`
|
||||
PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"`
|
||||
}
|
||||
246
src/modules/trace/repository/trace_data.go
Normal file
246
src/modules/trace/repository/trace_data.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
"be.ems/src/modules/trace/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 TraceData 结构体
|
||||
var NewTraceData = &TraceData{
|
||||
selectSql: `select id, task_id, imsi, msisdn, src_addr, dst_addr, if_type, msg_type, msg_direct, length, timestamp, raw_msg, dec_msg from trace_data`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"task_id": "TaskId",
|
||||
"imsi": "IMSI",
|
||||
"msisdn": "MSISDN",
|
||||
"src_addr": "SrcAddr",
|
||||
"dst_addr": "DstAddr",
|
||||
"if_type": "IfType",
|
||||
"msg_type": "MsgType",
|
||||
"msg_direct": "MsgDirect",
|
||||
"length": "Length",
|
||||
"timestamp": "Timestamp",
|
||||
"raw_msg": "RawMsg",
|
||||
"dec_msg": "DecMsg",
|
||||
},
|
||||
}
|
||||
|
||||
// CDREventIMSImpl 跟踪_任务给HRL网元 数据层处理
|
||||
type TraceData struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *TraceData) convertResultRows(rows []map[string]any) []model.TraceData {
|
||||
arr := make([]model.TraceData, 0)
|
||||
for _, row := range rows {
|
||||
item := model.TraceData{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *TraceData) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
conditions = append(conditions, "imsi like concat(?, '%')")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
conditions = append(conditions, "msisdn like concat(?, '%')")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["startTime"]; ok && v != "" {
|
||||
conditions = append(conditions, "timestamp >= ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
conditions = append(conditions, "timestamp <= ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.TraceData{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from trace_data"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *TraceData) SelectList(data model.TraceData) []model.TraceData {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if data.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, data.IMSI)
|
||||
}
|
||||
if data.MSISDN != "" {
|
||||
conditions = append(conditions, "msisdn = ?")
|
||||
params = append(params, data.MSISDN)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by id desc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r *TraceData) SelectByIds(ids []string) []model.TraceData {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(ids))
|
||||
querySql := r.selectSql + " where id in (" + placeholder + ")"
|
||||
parameters := repo.ConvertIdsSlice(ids)
|
||||
results, err := datasource.RawDB("", querySql, parameters)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return []model.TraceData{}
|
||||
}
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r *TraceData) Insert(data model.TraceData) string {
|
||||
// 参数拼接
|
||||
params := make(map[string]any)
|
||||
if data.TaskId > 0 {
|
||||
params["task_id"] = data.TaskId
|
||||
}
|
||||
if data.IMSI != "" {
|
||||
params["imsi"] = data.IMSI
|
||||
}
|
||||
if data.MSISDN != "" {
|
||||
params["msisdn"] = data.MSISDN
|
||||
}
|
||||
if data.SrcAddr != "" {
|
||||
params["src_addr"] = data.SrcAddr
|
||||
}
|
||||
if data.DstAddr != "" {
|
||||
params["dst_addr"] = data.DstAddr
|
||||
}
|
||||
if data.IfType > -1 {
|
||||
params["if_type"] = data.IfType
|
||||
}
|
||||
if data.MsgType > -1 {
|
||||
params["msg_type"] = data.MsgType
|
||||
}
|
||||
if data.MsgDirect > -1 {
|
||||
params["msg_direct"] = data.MsgDirect
|
||||
}
|
||||
if data.Length > 0 {
|
||||
params["length"] = data.Length
|
||||
}
|
||||
if data.Timestamp > 0 {
|
||||
params["timestamp"] = data.Timestamp
|
||||
}
|
||||
if data.RawMsg != "" {
|
||||
params["raw_msg"] = data.RawMsg
|
||||
}
|
||||
if data.DecMsg != "" {
|
||||
params["dec_msg"] = data.DecMsg
|
||||
}
|
||||
|
||||
// 构建执行语句
|
||||
keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params)
|
||||
sql := "insert into trace_data (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||
|
||||
db := datasource.DefaultDB()
|
||||
// 开启事务
|
||||
tx := db.Begin()
|
||||
// 执行插入
|
||||
err := tx.Exec(sql, values...).Error
|
||||
if err != nil {
|
||||
logger.Errorf("insert row : %v", err.Error())
|
||||
tx.Rollback()
|
||||
return ""
|
||||
}
|
||||
// 获取生成的自增 ID
|
||||
var insertedID string
|
||||
err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID)
|
||||
if err != nil {
|
||||
logger.Errorf("insert last id : %v", err.Error())
|
||||
tx.Rollback()
|
||||
return ""
|
||||
}
|
||||
// 提交事务
|
||||
tx.Commit()
|
||||
return insertedID
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r *TraceData) DeleteByIds(ids []string) int64 {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(ids))
|
||||
sql := "delete from trace_data where id in (" + placeholder + ")"
|
||||
parameters := repo.ConvertIdsSlice(ids)
|
||||
results, err := datasource.ExecDB("", sql, parameters)
|
||||
if err != nil {
|
||||
logger.Errorf("delete err => %v", err)
|
||||
return 0
|
||||
}
|
||||
return results
|
||||
}
|
||||
358
src/modules/trace/repository/trace_task.go
Normal file
358
src/modules/trace/repository/trace_task.go
Normal file
@@ -0,0 +1,358 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
"be.ems/src/modules/trace/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 TraceTask 结构体
|
||||
var NewTraceTask = &TraceTask{
|
||||
selectSql: `select id, trace_id, trace_type, start_time, end_time,
|
||||
interfaces, imsi, msisdn,
|
||||
ue_ip, src_ip, dst_ip, signal_port,
|
||||
create_by, create_time, update_by, update_time, remark,
|
||||
ne_type, ne_id, notify_url, fetch_msg
|
||||
from trace_task`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"trace_id": "TraceId",
|
||||
"trace_type": "TraceType",
|
||||
"start_time": "StartTime",
|
||||
"end_time": "EndTime",
|
||||
"interfaces": "Interfaces",
|
||||
"imsi": "IMSI",
|
||||
"msisdn": "MSISDN",
|
||||
"ue_ip": "UeIp",
|
||||
"src_ip": "SrcIp",
|
||||
"dst_ip": "DstIp",
|
||||
"signal_port": "SignalPort",
|
||||
"create_by": "CreateBy",
|
||||
"create_time": "CreateTime",
|
||||
"update_by": "UpdateBy",
|
||||
"update_time": "UpdateTime",
|
||||
"remark": "Remark",
|
||||
"ne_type": "NeType",
|
||||
"ne_id": "NeId",
|
||||
"notify_url": "NotifyUrl",
|
||||
"fetch_msg": "FetchMsg",
|
||||
},
|
||||
}
|
||||
|
||||
// TraceTask 跟踪_任务 数据层处理
|
||||
type TraceTask struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *TraceTask) convertResultRows(rows []map[string]any) []model.TraceTask {
|
||||
arr := make([]model.TraceTask, 0)
|
||||
for _, row := range rows {
|
||||
item := model.TraceTask{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *TraceTask) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["neType"]; ok && v != "" {
|
||||
conditions = append(conditions, "ne_type = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
conditions = append(conditions, "imsi like concat(?, '%')")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
conditions = append(conditions, "msisdn like concat(?, '%')")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["startTime"]; ok && v != "" {
|
||||
conditions = append(conditions, "start_time >= ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
if v, ok := query["endTime"]; ok && v != "" {
|
||||
conditions = append(conditions, "end_time <= ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.TraceTask{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from trace_task"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 排序
|
||||
orderSql := ""
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v.(string)
|
||||
if v, ok := query["sortOrder"]; ok && v != "" {
|
||||
if v.(string) == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
orderSql = fmt.Sprintf(" order by %s ", sortSql)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + orderSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *TraceTask) SelectList(task model.TraceTask) []model.TraceTask {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if task.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, task.IMSI)
|
||||
}
|
||||
if task.SrcIp != "" {
|
||||
conditions = append(conditions, "src_ip = ?")
|
||||
params = append(params, task.SrcIp)
|
||||
}
|
||||
if task.DstIp != "" {
|
||||
conditions = append(conditions, "dst_ip = ?")
|
||||
params = append(params, task.DstIp)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by id desc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r *TraceTask) SelectByIds(ids []string) []model.TraceTask {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(ids))
|
||||
querySql := r.selectSql + " where id in (" + placeholder + ")"
|
||||
parameters := repo.ConvertIdsSlice(ids)
|
||||
results, err := datasource.RawDB("", querySql, parameters)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return []model.TraceTask{}
|
||||
}
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r *TraceTask) Insert(task model.TraceTask) string {
|
||||
// 参数拼接
|
||||
params := make(map[string]any)
|
||||
if task.TraceId != "" {
|
||||
params["trace_id"] = task.TraceId
|
||||
}
|
||||
if task.TraceType != "" {
|
||||
params["trace_type"] = task.TraceType
|
||||
}
|
||||
if task.StartTime > 0 {
|
||||
params["start_time"] = task.StartTime
|
||||
}
|
||||
if task.EndTime > 0 {
|
||||
params["end_time"] = task.EndTime
|
||||
}
|
||||
if task.Interfaces != "" {
|
||||
params["interfaces"] = task.Interfaces
|
||||
}
|
||||
if task.IMSI != "" {
|
||||
params["imsi"] = task.IMSI
|
||||
}
|
||||
if task.MSISDN != "" {
|
||||
params["msisdn"] = task.MSISDN
|
||||
}
|
||||
if task.UeIp != "" {
|
||||
params["ue_ip"] = task.UeIp
|
||||
}
|
||||
if task.SrcIp != "" {
|
||||
params["src_ip"] = task.SrcIp
|
||||
}
|
||||
if task.DstIp != "" {
|
||||
params["dst_ip"] = task.DstIp
|
||||
}
|
||||
if task.SignalPort != 0 {
|
||||
params["signal_port"] = task.SignalPort
|
||||
}
|
||||
if task.NeType != "" {
|
||||
params["ne_type"] = task.NeType
|
||||
}
|
||||
if task.NeId != "" {
|
||||
params["ne_id"] = task.NeId
|
||||
}
|
||||
if task.NotifyUrl != "" {
|
||||
params["notify_url"] = task.NotifyUrl
|
||||
}
|
||||
if task.FetchMsg != "" {
|
||||
params["fetch_msg"] = task.FetchMsg
|
||||
}
|
||||
if task.Remark != "" {
|
||||
params["remark"] = task.Remark
|
||||
}
|
||||
if task.CreateBy != "" {
|
||||
params["create_by"] = task.CreateBy
|
||||
params["create_time"] = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
// 构建执行语句
|
||||
keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params)
|
||||
sql := "insert into trace_task (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||
|
||||
db := datasource.DefaultDB()
|
||||
// 开启事务
|
||||
tx := db.Begin()
|
||||
// 执行插入
|
||||
err := tx.Exec(sql, values...).Error
|
||||
if err != nil {
|
||||
logger.Errorf("insert row : %v", err.Error())
|
||||
tx.Rollback()
|
||||
return ""
|
||||
}
|
||||
// 获取生成的自增 ID
|
||||
var insertedID string
|
||||
err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID)
|
||||
if err != nil {
|
||||
logger.Errorf("insert last id : %v", err.Error())
|
||||
tx.Rollback()
|
||||
return ""
|
||||
}
|
||||
// 提交事务
|
||||
tx.Commit()
|
||||
return insertedID
|
||||
}
|
||||
|
||||
// Update 修改信息
|
||||
func (r *TraceTask) Update(task model.TraceTask) int64 {
|
||||
// 参数拼接
|
||||
params := make(map[string]any)
|
||||
params["trace_id"] = task.TraceId
|
||||
params["trace_type"] = task.TraceType
|
||||
params["ne_type"] = task.NeType
|
||||
params["ne_id"] = task.NeId
|
||||
params["notify_url"] = task.NotifyUrl
|
||||
|
||||
params["start_time"] = task.StartTime
|
||||
params["end_time"] = task.EndTime
|
||||
params["fetch_msg"] = task.FetchMsg
|
||||
params["remark"] = task.Remark
|
||||
|
||||
params["interfaces"] = task.Interfaces
|
||||
|
||||
params["imsi"] = task.IMSI
|
||||
params["msisdn"] = task.MSISDN
|
||||
|
||||
params["ue_ip"] = task.UeIp
|
||||
params["src_ip"] = task.SrcIp
|
||||
params["dst_ip"] = task.DstIp
|
||||
params["signal_port"] = task.SignalPort
|
||||
|
||||
if task.UpdateBy != "" {
|
||||
params["update_by"] = task.UpdateBy
|
||||
params["update_time"] = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
// 构建执行语句
|
||||
keys, values := repo.KeyValueByUpdate(params)
|
||||
sql := "update trace_task set " + strings.Join(keys, ",") + " where id = ?"
|
||||
|
||||
// 执行更新
|
||||
values = append(values, task.ID)
|
||||
rows, err := datasource.ExecDB("", sql, values)
|
||||
if err != nil {
|
||||
logger.Errorf("update row : %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r *TraceTask) DeleteByIds(ids []string) int64 {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(ids))
|
||||
sql := "delete from trace_task where id in (" + placeholder + ")"
|
||||
parameters := repo.ConvertIdsSlice(ids)
|
||||
results, err := datasource.ExecDB("", sql, parameters)
|
||||
if err != nil {
|
||||
logger.Errorf("delete err => %v", err)
|
||||
return 0
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// LastID 最后一条ID
|
||||
func (r *TraceTask) LastID() int64 {
|
||||
// 查询数据
|
||||
querySql := "SELECT id as 'str' FROM trace_task ORDER BY id DESC LIMIT 1"
|
||||
results, err := datasource.RawDB("", querySql, nil)
|
||||
if err != nil {
|
||||
logger.Errorf("query err %v", err)
|
||||
return 0
|
||||
}
|
||||
if len(results) > 0 {
|
||||
return parse.Number(results[0]["str"])
|
||||
}
|
||||
return 0
|
||||
}
|
||||
316
src/modules/trace/repository/trace_task_hlr.go
Normal file
316
src/modules/trace/repository/trace_task_hlr.go
Normal file
@@ -0,0 +1,316 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
"be.ems/src/modules/trace/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 TraceTaskHlr 结构体
|
||||
var NewTraceTaskHlr = &TraceTaskHlr{
|
||||
selectSql: `select id, trace_id, imsi, msisdn, start_time, end_time, status, msg, remark, create_by, create_time, update_by, update_time from trace_task_hlr`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"trace_id": "TraceId",
|
||||
"imsi": "IMSI",
|
||||
"msisdn": "MSISDN",
|
||||
"start_time": "StartTime",
|
||||
"end_time": "EndTime",
|
||||
"status": "Status",
|
||||
"msg": "Msg",
|
||||
"remark": "Remark",
|
||||
"create_by": "CreateBy",
|
||||
"create_time": "CreateTime",
|
||||
"update_by": "UpdateBy",
|
||||
"update_time": "UpdateTime",
|
||||
},
|
||||
}
|
||||
|
||||
// TraceTaskHlr 跟踪_任务给HRL网元 数据层处理
|
||||
type TraceTaskHlr struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *TraceTaskHlr) convertResultRows(rows []map[string]any) []model.TraceTaskHlr {
|
||||
arr := make([]model.TraceTaskHlr, 0)
|
||||
for _, row := range rows {
|
||||
item := model.TraceTaskHlr{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *TraceTaskHlr) SelectPage(querys model.TraceTaskHlrQuery) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if querys.IMSI != "" {
|
||||
conditions = append(conditions, "imsi like concat(?, '%')")
|
||||
params = append(params, querys.IMSI)
|
||||
}
|
||||
if querys.MSISDN != "" {
|
||||
conditions = append(conditions, "msisdn like concat(?, '%')")
|
||||
params = append(params, querys.MSISDN)
|
||||
}
|
||||
if querys.StartTime != "" && len(querys.StartTime) == 13 {
|
||||
conditions = append(conditions, "start_time >= ?")
|
||||
params = append(params, querys.StartTime)
|
||||
}
|
||||
if querys.EndTime != "" && len(querys.EndTime) == 13 {
|
||||
conditions = append(conditions, "end_time <= ?")
|
||||
params = append(params, querys.EndTime)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []model.TraceTaskHlr{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from trace_task_hlr"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize)
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 排序
|
||||
orderSql := ""
|
||||
if querys.SortField != "" {
|
||||
sortSql := querys.SortField
|
||||
if querys.SortOrder != "" {
|
||||
if querys.SortOrder == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + orderSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *TraceTaskHlr) SelectList(task model.TraceTaskHlr) []model.TraceTaskHlr {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if task.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, task.IMSI)
|
||||
}
|
||||
if task.MSISDN != "" {
|
||||
conditions = append(conditions, "msisdn = ?")
|
||||
params = append(params, task.MSISDN)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by id desc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIds 通过ID查询
|
||||
func (r *TraceTaskHlr) SelectByIds(ids []string) []model.TraceTaskHlr {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(ids))
|
||||
querySql := r.selectSql + " where id in (" + placeholder + ")"
|
||||
parameters := repo.ConvertIdsSlice(ids)
|
||||
results, err := datasource.RawDB("", querySql, parameters)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return []model.TraceTaskHlr{}
|
||||
}
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r *TraceTaskHlr) Insert(task model.TraceTaskHlr) string {
|
||||
// 参数拼接
|
||||
params := make(map[string]any)
|
||||
if task.TraceId != "" {
|
||||
params["trace_id"] = task.TraceId
|
||||
}
|
||||
if task.IMSI != "" {
|
||||
params["imsi"] = task.IMSI
|
||||
}
|
||||
if task.MSISDN != "" {
|
||||
params["msisdn"] = task.MSISDN
|
||||
}
|
||||
if task.StartTime != 0 {
|
||||
params["start_time"] = task.StartTime
|
||||
}
|
||||
if task.EndTime != 0 {
|
||||
params["end_time"] = task.EndTime
|
||||
}
|
||||
if task.Status != "" {
|
||||
params["status"] = task.Status
|
||||
}
|
||||
if task.Msg != "" {
|
||||
params["msg"] = task.Msg
|
||||
}
|
||||
if task.Remark != "" {
|
||||
params["remark"] = task.Remark
|
||||
}
|
||||
if task.CreateBy != "" {
|
||||
params["create_by"] = task.CreateBy
|
||||
params["create_time"] = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
// 构建执行语句
|
||||
keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params)
|
||||
sql := "insert into trace_task_hlr (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||
|
||||
db := datasource.DefaultDB()
|
||||
// 开启事务
|
||||
tx := db.Begin()
|
||||
// 执行插入
|
||||
err := tx.Exec(sql, values...).Error
|
||||
if err != nil {
|
||||
logger.Errorf("insert row : %v", err.Error())
|
||||
tx.Rollback()
|
||||
return ""
|
||||
}
|
||||
// 获取生成的自增 ID
|
||||
var insertedID string
|
||||
err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID)
|
||||
if err != nil {
|
||||
logger.Errorf("insert last id : %v", err.Error())
|
||||
tx.Rollback()
|
||||
return ""
|
||||
}
|
||||
// 提交事务
|
||||
tx.Commit()
|
||||
return insertedID
|
||||
}
|
||||
|
||||
// Update 修改信息
|
||||
func (r *TraceTaskHlr) Update(task model.TraceTaskHlr) int64 {
|
||||
// 参数拼接
|
||||
params := make(map[string]any)
|
||||
if task.TraceId != "" {
|
||||
params["trace_id"] = task.TraceId
|
||||
}
|
||||
if task.IMSI != "" {
|
||||
params["imsi"] = task.IMSI
|
||||
}
|
||||
if task.MSISDN != "" {
|
||||
params["msisdn"] = task.MSISDN
|
||||
}
|
||||
if task.StartTime != 0 {
|
||||
params["start_time"] = task.StartTime
|
||||
}
|
||||
if task.EndTime != 0 {
|
||||
params["end_time"] = task.EndTime
|
||||
}
|
||||
if task.Status != "" {
|
||||
params["status"] = task.Status
|
||||
}
|
||||
if task.Msg != "" {
|
||||
params["msg"] = task.Msg
|
||||
}
|
||||
if task.Remark != "" {
|
||||
params["remark"] = task.Remark
|
||||
}
|
||||
if task.UpdateBy != "" {
|
||||
params["update_by"] = task.UpdateBy
|
||||
params["update_time"] = time.Now().UnixMilli()
|
||||
}
|
||||
|
||||
// 构建执行语句
|
||||
keys, values := repo.KeyValueByUpdate(params)
|
||||
sql := "update trace_task_hlr set " + strings.Join(keys, ",") + " where id = ?"
|
||||
|
||||
// 执行更新
|
||||
values = append(values, task.ID)
|
||||
rows, err := datasource.ExecDB("", sql, values)
|
||||
if err != nil {
|
||||
logger.Errorf("update row : %v", err.Error())
|
||||
return 0
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r *TraceTaskHlr) DeleteByIds(ids []string) int64 {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(ids))
|
||||
sql := "delete from trace_task_hlr where id in (" + placeholder + ")"
|
||||
parameters := repo.ConvertIdsSlice(ids)
|
||||
results, err := datasource.ExecDB("", sql, parameters)
|
||||
if err != nil {
|
||||
logger.Errorf("delete err => %v", err)
|
||||
return 0
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// LastID 最后一条ID
|
||||
func (r *TraceTaskHlr) LastID() int64 {
|
||||
// 查询数据
|
||||
querySql := "SELECT id as 'str' FROM trace_task_hlr ORDER BY id DESC LIMIT 1"
|
||||
results, err := datasource.RawDB("", querySql, nil)
|
||||
if err != nil {
|
||||
logger.Errorf("query err %v", err)
|
||||
return 0
|
||||
}
|
||||
if len(results) > 0 {
|
||||
return parse.Number(results[0]["str"])
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -1,16 +1,248 @@
|
||||
package service
|
||||
|
||||
// 信令抓包 服务层接口
|
||||
type ITcpdump interface {
|
||||
// DumpStart 触发tcpdump开始抓包
|
||||
DumpStart(neType, neId, cmdStr string) (string, error)
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// DumpStop 停止已存在抓包句柄
|
||||
DumpStop(neType, neId, taskCode string) (string, error)
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/file"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
)
|
||||
|
||||
// DumpDownload 抓包文件网元端复制到本地输出zip文件
|
||||
DumpDownload(neType, neId, taskCode string) (string, error)
|
||||
|
||||
// UPFTrace UPF标准版内部抓包
|
||||
UPFTrace(neType, neId, cmdStr string) (string, error)
|
||||
// 实例化服务层 TCPdump 结构体
|
||||
var NewTCPdump = &TCPdump{
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
}
|
||||
|
||||
// 信令抓包 服务层处理
|
||||
type TCPdump struct {
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
|
||||
// 抓包进程PID
|
||||
var dumpPIDMap sync.Map
|
||||
|
||||
// DumpStart 触发tcpdump开始抓包
|
||||
func (s *TCPdump) DumpStart(neType, neId, cmdStr string) (string, error) {
|
||||
// 命令检查
|
||||
if strings.Contains(cmdStr, "w") {
|
||||
return "", fmt.Errorf("command cannot contain -w")
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
|
||||
// 检查是否安装tcpdump
|
||||
if msg, err := sshClient.RunCMD("sudo tcpdump --version"); err != nil {
|
||||
// bash: tcpdump: command not found
|
||||
msg = strings.TrimSpace(msg)
|
||||
logger.Errorf("DumpStart err: %s => %s", msg, err.Error())
|
||||
return "", fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
taskCode := time.Now().Format("20060102150405")
|
||||
// 存放文件目录 /tmp/omc/tcpdump/udm/001/20240817104241
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s/%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
sshClient.RunCMD(fmt.Sprintf("mkdir -p %s && sudo chmod 777 -R /tmp/omc", neDirTemp))
|
||||
|
||||
// 命令拼装
|
||||
logPath := fmt.Sprintf("%s/tcpdump.log", neDirTemp)
|
||||
filePath := fmt.Sprintf("%s/part_%s.pcap ", neDirTemp, taskCode)
|
||||
if strings.Contains(cmdStr, "-G") {
|
||||
filePath = fmt.Sprintf("%s/part_%%Y%%m%%d%%H%%M%%S.pcap ", neDirTemp)
|
||||
}
|
||||
sendCmd := fmt.Sprintf("sudo timeout 60m sudo tcpdump -i any %s -w %s > %s 2>&1 & echo $!", cmdStr, filePath, logPath)
|
||||
// sudo timeout 60m sudo tcpdump -i any -n -s 0 -v -G 60 -W 6 -w /tmp/omc/tcpdump/udm/001/20240817104241/part_%Y-%m-%d_%H:%M:%S.pcap > /tmp/omc/tcpdump/udm/001/20240817104241/tcpdump.log 2>&1 & echo $!
|
||||
// sudo timeout 60m sudo tcpdump -i any -n -s 0 -v -w /tmp/omc/tcpdump/udm/001/20240817105440/part_2024-08-17_10:54:40.pcap > /tmp/omc/tcpdump/udm/001/20240817105440/tcpdump.log 2>&1 & echo $!
|
||||
//
|
||||
// timeout 超时60分钟后发送kill命令,1分钟后强制终止命令。tcpdump -G 文件轮转间隔时间(秒) -W 文件轮转保留最近数量
|
||||
// sudo timeout --kill-after=1m 60m sudo tcpdump -i any -n -s 0 -v -G 10 -W 7 -w /tmp/part_%Y%m%d%H%M%S.pcap > /tmp/part.log 2>&1 & echo $!
|
||||
// sudo kill $(pgrep -P 722729)
|
||||
outputPID, err := sshClient.RunCMD(sendCmd)
|
||||
outputPID = strings.TrimSpace(outputPID)
|
||||
if err != nil || strings.HasPrefix(outputPID, "stderr:") {
|
||||
logger.Errorf("DumpStart err: %s => %s", outputPID, err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 检查进程 ps aux | grep tcpdump
|
||||
// 强杀 sudo pkill tcpdump
|
||||
pidKey := fmt.Sprintf("%s_%s_%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
dumpPIDMap.Store(pidKey, outputPID)
|
||||
return taskCode, err
|
||||
}
|
||||
|
||||
// DumpStop 停止已存在抓包句柄
|
||||
func (s *TCPdump) DumpStop(neType, neId, taskCode string) (string, error) {
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
|
||||
// 是否存在执行过的进程
|
||||
pidKey := fmt.Sprintf("%s_%s_%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
pid, ok := dumpPIDMap.Load(pidKey)
|
||||
if !ok || pid == "" {
|
||||
return "", fmt.Errorf("tcpdump is not running")
|
||||
}
|
||||
defer dumpPIDMap.Delete(pidKey)
|
||||
|
||||
// 存放文件目录 /tmp/omc/tcpdump/udm/001/20240817104241
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s/%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
// 命令拼装
|
||||
sendCmd := fmt.Sprintf("pids=$(pgrep -P %s) && [ -n \"$pids\" ] && sudo kill $pids;sudo timeout 2s cat %s/tcpdump.log", pid, neDirTemp)
|
||||
// pids=$(pgrep -P 1914341) && [ -n "$pids" ] && sudo kill $pids;sudo timeout 2s cat tcpdump.log
|
||||
output, err := sshClient.RunCMD(sendCmd)
|
||||
if err != nil || strings.HasPrefix(output, "stderr:") {
|
||||
logger.Warnf("DumpStop err: %s => %s", strings.TrimSpace(output), err.Error())
|
||||
return "", err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// DumpDownload 抓包文件网元端复制到本地输出zip文件
|
||||
func (s *TCPdump) DumpDownload(neType, neId, taskCode string) (string, error) {
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ne info sftp client err")
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
// 网管本地路径
|
||||
localDirPath := fmt.Sprintf("/tmp/omc/tcpdump/zip/%s/%s", neTypeLower, neInfo.NeId)
|
||||
if runtime.GOOS == "windows" {
|
||||
localDirPath = fmt.Sprintf("C:%s", localDirPath)
|
||||
}
|
||||
|
||||
// 网元pcap目录 /tmp/omc/tcpdump/udm/001/20240817104241
|
||||
sshClient.RunCMD("mkdir -p /tmp/omc && sudo chmod 777 -R /tmp/omc")
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s/%s", neTypeLower, neInfo.NeId, taskCode)
|
||||
// 网元端复制到本地
|
||||
localDirFilePath := filepath.Join(localDirPath, taskCode)
|
||||
if err = sftpClient.CopyDirRemoteToLocal(neDirTemp, localDirFilePath); err != nil {
|
||||
return "", fmt.Errorf("copy tcpdump file err")
|
||||
}
|
||||
|
||||
// 压缩zip文件名
|
||||
zipFileName := fmt.Sprintf("%s-%s-pcap-%s.zip", neTypeLower, neInfo.NeId, taskCode)
|
||||
zipFilePath := filepath.Join(localDirPath, zipFileName)
|
||||
if err := file.CompressZipByDir(zipFilePath, localDirFilePath); err != nil {
|
||||
return "", fmt.Errorf("compress zip err")
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(localDirFilePath) // 删除本地临时目录
|
||||
return zipFilePath, nil
|
||||
}
|
||||
|
||||
// UPFTrace UPF标准版内部抓包
|
||||
func (s *TCPdump) UPFTrace(neType, neId, cmdStr string) (string, error) {
|
||||
// 命令检查
|
||||
if strings.Contains(cmdStr, "file") {
|
||||
return "", fmt.Errorf("command cannot contain file")
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UPF", neInfo.NeId, 2)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 命令拼装
|
||||
fileName := fmt.Sprintf("%s_%s_part_%s.pcap ", neInfo.NeType, neInfo.NeId, time.Now().Format("20060102150405"))
|
||||
pcapCmd := fmt.Sprintf("%s\r\n", cmdStr)
|
||||
// 以off结尾是停止抓包,不需要写文件
|
||||
if !strings.Contains(cmdStr, "off") {
|
||||
// pcap trace rx tx max 100000 intfc any file UPF_001_part_20240817164516.pcap
|
||||
pcapCmd = fmt.Sprintf("%s file %s\r\n", cmdStr, fileName)
|
||||
}
|
||||
// 发送命令 UPF内部默认输出路径/tmp只能写文件名
|
||||
// pcap trace rx tx max 100000 intfc any file upf_test.pcap
|
||||
// pcap trace rx tx off
|
||||
output, err := telnetClient.RunCMD(pcapCmd)
|
||||
if err != nil {
|
||||
logger.Warnf("DumpUPF err: %s => %s", output, err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 结果截取
|
||||
arr := strings.Split(output, "\r\n")
|
||||
if len(arr) == 2 {
|
||||
return "", fmt.Errorf("trace pacp run failed")
|
||||
}
|
||||
if len(arr) > 3 {
|
||||
resMsg := arr[2]
|
||||
// pcap trace: unknown input `f file UPF_001_part_2024-08-19...'
|
||||
// pcap trace: dispatch trace already enabled...
|
||||
// pcap trace: dispatch trace already disabled...
|
||||
// pcap trace: No packets captured...
|
||||
// Write 100000 packets to /tmp/UPF_001_part_20240817164516.pcap, and stop capture...
|
||||
if strings.Contains(resMsg, "unknown input") {
|
||||
return "", fmt.Errorf("trace pacp unknown input")
|
||||
}
|
||||
if strings.Contains(resMsg, "already enabled") {
|
||||
return "", fmt.Errorf("trace pacp already running")
|
||||
}
|
||||
if strings.Contains(resMsg, "already disabled") {
|
||||
return "", fmt.Errorf("trace pacp not running")
|
||||
}
|
||||
if strings.Contains(resMsg, "No packets") {
|
||||
return "", fmt.Errorf("trace pacp not packets")
|
||||
}
|
||||
if strings.Contains(resMsg, "packets to") {
|
||||
matches := regexp.MustCompile(`(/tmp/[^,\s]+)`).FindStringSubmatch(resMsg)
|
||||
if len(matches) == 0 {
|
||||
return "", fmt.Errorf("file path not found")
|
||||
}
|
||||
return matches[0], nil
|
||||
}
|
||||
}
|
||||
return "trace pacp running", nil
|
||||
}
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/file"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 TcpdumpImpl 结构体
|
||||
var NewTcpdumpImpl = &TcpdumpImpl{
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
}
|
||||
|
||||
// 信令抓包 服务层处理
|
||||
type TcpdumpImpl struct {
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
|
||||
// 抓包进程PID
|
||||
var dumpPIDMap sync.Map
|
||||
|
||||
// DumpStart 触发tcpdump开始抓包
|
||||
func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) {
|
||||
// 命令检查
|
||||
if strings.Contains(cmdStr, "w") {
|
||||
return "", fmt.Errorf("command cannot contain -w")
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
|
||||
// 检查是否安装tcpdump
|
||||
if msg, err := sshClient.RunCMD("sudo tcpdump --version"); err != nil {
|
||||
// bash: tcpdump: command not found
|
||||
msg = strings.TrimSpace(msg)
|
||||
logger.Errorf("DumpStart err: %s => %s", msg, err.Error())
|
||||
return "", fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
taskCode := time.Now().Format("20060102150405")
|
||||
// 存放文件目录 /tmp/omc/tcpdump/udm/001/20240817104241
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s/%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
sshClient.RunCMD(fmt.Sprintf("mkdir -p %s && sudo chmod 777 -R /tmp/omc", neDirTemp))
|
||||
|
||||
// 命令拼装
|
||||
logPath := fmt.Sprintf("%s/tcpdump.log", neDirTemp)
|
||||
filePath := fmt.Sprintf("%s/part_%s.pcap ", neDirTemp, taskCode)
|
||||
if strings.Contains(cmdStr, "-G") {
|
||||
filePath = fmt.Sprintf("%s/part_%%Y%%m%%d%%H%%M%%S.pcap ", neDirTemp)
|
||||
}
|
||||
sendCmd := fmt.Sprintf("sudo timeout 60m sudo tcpdump -i any %s -w %s > %s 2>&1 & echo $!", cmdStr, filePath, logPath)
|
||||
// sudo timeout 60m sudo tcpdump -i any -n -s 0 -v -G 60 -W 6 -w /tmp/omc/tcpdump/udm/001/20240817104241/part_%Y-%m-%d_%H:%M:%S.pcap > /tmp/omc/tcpdump/udm/001/20240817104241/tcpdump.log 2>&1 & echo $!
|
||||
// sudo timeout 60m sudo tcpdump -i any -n -s 0 -v -w /tmp/omc/tcpdump/udm/001/20240817105440/part_2024-08-17_10:54:40.pcap > /tmp/omc/tcpdump/udm/001/20240817105440/tcpdump.log 2>&1 & echo $!
|
||||
//
|
||||
// timeout 超时60分钟后发送kill命令,1分钟后强制终止命令。tcpdump -G 文件轮转间隔时间(秒) -W 文件轮转保留最近数量
|
||||
// sudo timeout --kill-after=1m 60m sudo tcpdump -i any -n -s 0 -v -G 10 -W 7 -w /tmp/part_%Y%m%d%H%M%S.pcap > /tmp/part.log 2>&1 & echo $!
|
||||
// sudo kill $(pgrep -P 722729)
|
||||
outputPID, err := sshClient.RunCMD(sendCmd)
|
||||
outputPID = strings.TrimSpace(outputPID)
|
||||
if err != nil || strings.HasPrefix(outputPID, "stderr:") {
|
||||
logger.Errorf("DumpStart err: %s => %s", outputPID, err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 检查进程 ps aux | grep tcpdump
|
||||
// 强杀 sudo pkill tcpdump
|
||||
pidKey := fmt.Sprintf("%s_%s_%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
dumpPIDMap.Store(pidKey, outputPID)
|
||||
return taskCode, err
|
||||
}
|
||||
|
||||
// DumpStop 停止已存在抓包句柄
|
||||
func (s *TcpdumpImpl) DumpStop(neType, neId, taskCode string) (string, error) {
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
|
||||
// 是否存在执行过的进程
|
||||
pidKey := fmt.Sprintf("%s_%s_%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
pid, ok := dumpPIDMap.Load(pidKey)
|
||||
if !ok || pid == "" {
|
||||
return "", fmt.Errorf("tcpdump is not running")
|
||||
}
|
||||
defer dumpPIDMap.Delete(pidKey)
|
||||
|
||||
// 存放文件目录 /tmp/omc/tcpdump/udm/001/20240817104241
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s/%s", strings.ToLower(neInfo.NeType), neInfo.NeId, taskCode)
|
||||
// 命令拼装
|
||||
sendCmd := fmt.Sprintf("pids=$(pgrep -P %s) && [ -n \"$pids\" ] && sudo kill $pids;sudo timeout 2s cat %s/tcpdump.log", pid, neDirTemp)
|
||||
// pids=$(pgrep -P 1914341) && [ -n "$pids" ] && sudo kill $pids;sudo timeout 2s cat tcpdump.log
|
||||
output, err := sshClient.RunCMD(sendCmd)
|
||||
if err != nil || strings.HasPrefix(output, "stderr:") {
|
||||
logger.Warnf("DumpStop err: %s => %s", strings.TrimSpace(output), err.Error())
|
||||
return "", err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// DumpDownload 抓包文件网元端复制到本地输出zip文件
|
||||
func (s *TcpdumpImpl) DumpDownload(neType, neId, taskCode string) (string, error) {
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ne info sftp client err")
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
neTypeLower := strings.ToLower(neInfo.NeType)
|
||||
// 网管本地路径
|
||||
localDirPath := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s", neTypeLower, neInfo.NeId)
|
||||
if runtime.GOOS == "windows" {
|
||||
localDirPath = fmt.Sprintf("C:%s", localDirPath)
|
||||
}
|
||||
|
||||
// 网元pcap目录 /tmp/omc/tcpdump/udm/001/20240817104241
|
||||
sshClient.RunCMD("mkdir -p /tmp/omc && sudo chmod 777 -R /tmp/omc")
|
||||
neDirTemp := fmt.Sprintf("/tmp/omc/tcpdump/%s/%s/%s", neTypeLower, neInfo.NeId, taskCode)
|
||||
// 网元端复制到本地
|
||||
localDirFilePath := filepath.Join(localDirPath, taskCode)
|
||||
if err = sftpClient.CopyDirRemoteToLocal(neDirTemp, localDirFilePath); err != nil {
|
||||
return "", fmt.Errorf("copy tcpdump file err")
|
||||
}
|
||||
|
||||
// 压缩zip文件名
|
||||
zipFileName := fmt.Sprintf("%s-%s-pcap-%s.zip", neTypeLower, neInfo.NeId, taskCode)
|
||||
zipFilePath := filepath.Join(localDirPath, zipFileName)
|
||||
if err := file.CompressZipByDir(zipFilePath, localDirFilePath); err != nil {
|
||||
return "", fmt.Errorf("compress zip err")
|
||||
}
|
||||
|
||||
_ = os.RemoveAll(localDirFilePath) // 删除本地临时目录
|
||||
return zipFilePath, nil
|
||||
}
|
||||
|
||||
// UPFTrace UPF标准版内部抓包
|
||||
func (s *TcpdumpImpl) UPFTrace(neType, neId, cmdStr string) (string, error) {
|
||||
// 命令检查
|
||||
if strings.Contains(cmdStr, "file") {
|
||||
return "", fmt.Errorf("command cannot contain file")
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
return "", fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UPF", neInfo.NeId, 2)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 命令拼装
|
||||
fileName := fmt.Sprintf("%s_%s_part_%s.pcap ", neInfo.NeType, neInfo.NeId, time.Now().Format("20060102150405"))
|
||||
pcapCmd := fmt.Sprintf("%s\r\n", cmdStr)
|
||||
// 以off结尾是停止抓包,不需要写文件
|
||||
if !strings.Contains(cmdStr, "off") {
|
||||
// pcap trace rx tx max 100000 intfc any file UPF_001_part_20240817164516.pcap
|
||||
pcapCmd = fmt.Sprintf("%s file %s\r\n", cmdStr, fileName)
|
||||
}
|
||||
// 发送命令 UPF内部默认输出路径/tmp只能写文件名
|
||||
// pcap trace rx tx max 100000 intfc any file upf_test.pcap
|
||||
// pcap trace rx tx off
|
||||
output, err := telnetClient.RunCMD(pcapCmd)
|
||||
if err != nil {
|
||||
logger.Warnf("DumpUPF err: %s => %s", output, err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 结果截取
|
||||
arr := strings.Split(output, "\r\n")
|
||||
if len(arr) == 2 {
|
||||
return "", fmt.Errorf("trace pacp run failed")
|
||||
}
|
||||
if len(arr) > 3 {
|
||||
resMsg := arr[2]
|
||||
// pcap trace: unknown input `f file UPF_001_part_2024-08-19...'
|
||||
// pcap trace: dispatch trace already enabled...
|
||||
// pcap trace: dispatch trace already disabled...
|
||||
// pcap trace: No packets captured...
|
||||
// Write 100000 packets to /tmp/UPF_001_part_20240817164516.pcap, and stop capture...
|
||||
if strings.Contains(resMsg, "unknown input") {
|
||||
return "", fmt.Errorf("trace pacp unknown input")
|
||||
}
|
||||
if strings.Contains(resMsg, "already enabled") {
|
||||
return "", fmt.Errorf("trace pacp already running")
|
||||
}
|
||||
if strings.Contains(resMsg, "already disabled") {
|
||||
return "", fmt.Errorf("trace pacp not running")
|
||||
}
|
||||
if strings.Contains(resMsg, "No packets") {
|
||||
return "", fmt.Errorf("trace pacp not packets")
|
||||
}
|
||||
if strings.Contains(resMsg, "packets to") {
|
||||
matches := regexp.MustCompile(`(/tmp/[^,\s]+)`).FindStringSubmatch(resMsg)
|
||||
if len(matches) == 0 {
|
||||
return "", fmt.Errorf("file path not found")
|
||||
}
|
||||
return matches[0], nil
|
||||
}
|
||||
}
|
||||
return "trace pacp running", nil
|
||||
}
|
||||
54
src/modules/trace/service/trace_data.go
Normal file
54
src/modules/trace/service/trace_data.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"be.ems/src/modules/trace/model"
|
||||
"be.ems/src/modules/trace/repository"
|
||||
)
|
||||
|
||||
// 实例化数据层 TraceData 结构体
|
||||
var NewTraceData = &TraceData{
|
||||
traceDataRepository: repository.NewTraceData,
|
||||
}
|
||||
|
||||
// TraceData 跟踪_数据 服务层处理
|
||||
type TraceData struct {
|
||||
// 跟踪_数据信息
|
||||
traceDataRepository *repository.TraceData
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *TraceData) SelectPage(query map[string]any) map[string]any {
|
||||
return r.traceDataRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectById 通过ID查询
|
||||
func (r *TraceData) SelectById(id string) model.TraceData {
|
||||
tasks := r.traceDataRepository.SelectByIds([]string{id})
|
||||
if len(tasks) > 0 {
|
||||
return tasks[0]
|
||||
}
|
||||
return model.TraceData{}
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r *TraceData) Insert(task model.TraceData) string {
|
||||
return r.traceDataRepository.Insert(task)
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r *TraceData) DeleteByIds(ids []string) (int64, error) {
|
||||
// 检查是否存在
|
||||
rows := r.traceDataRepository.SelectByIds(ids)
|
||||
if len(rows) <= 0 {
|
||||
return 0, fmt.Errorf("not data")
|
||||
}
|
||||
|
||||
if len(rows) == len(ids) {
|
||||
rows := r.traceDataRepository.DeleteByIds(ids)
|
||||
return rows, nil
|
||||
}
|
||||
// 删除信息失败!
|
||||
return 0, fmt.Errorf("delete fail")
|
||||
}
|
||||
294
src/modules/trace/service/trace_task.go
Normal file
294
src/modules/trace/service/trace_task.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/socket"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
"be.ems/src/modules/trace/model"
|
||||
"be.ems/src/modules/trace/repository"
|
||||
)
|
||||
|
||||
// 实例化数据层 TraceTask 结构体
|
||||
var NewTraceTask = &TraceTask{
|
||||
udpService: socket.SocketUDP{},
|
||||
traceTaskRepository: repository.NewTraceTask,
|
||||
traceDataRepository: repository.NewTraceData,
|
||||
}
|
||||
|
||||
// TraceTask 跟踪任务 服务层处理
|
||||
type TraceTask struct {
|
||||
// UDP服务对象
|
||||
udpService socket.SocketUDP
|
||||
// 跟踪_任务数据信息
|
||||
traceTaskRepository *repository.TraceTask
|
||||
// 跟踪_数据信息
|
||||
traceDataRepository *repository.TraceData
|
||||
}
|
||||
|
||||
// CreateUDP 创建UDP数据通道
|
||||
func (r *TraceTask) CreateUDP() error {
|
||||
// 跟踪配置是否开启
|
||||
if v := config.Get("trace.enabled"); v != nil {
|
||||
if !v.(bool) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
host := "127.0.0.1"
|
||||
if v := config.Get("trace.host"); v != nil {
|
||||
host = v.(string)
|
||||
}
|
||||
var port int64 = 33033
|
||||
if v := config.Get("trace.port"); v != nil {
|
||||
port = parse.Number(v)
|
||||
}
|
||||
|
||||
// 初始化UDP服务
|
||||
r.udpService = socket.SocketUDP{Addr: host, Port: port}
|
||||
if _, err := r.udpService.New(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 接收处理UDP数据
|
||||
go r.udpService.Resolve(2048, func(data []byte, n int) {
|
||||
logger.Infof("socket UDP: %s", string(data))
|
||||
mData, err := UDPDataHandler(data, n)
|
||||
if err != nil {
|
||||
logger.Errorf("udp resolve data fail: %s", err.Error())
|
||||
return
|
||||
}
|
||||
// 插入数据库做记录
|
||||
r.traceDataRepository.Insert(model.TraceData{
|
||||
TaskId: parse.Number(mData["taskId"]),
|
||||
IMSI: mData["imsi"].(string),
|
||||
SrcAddr: mData["srcAddr"].(string),
|
||||
DstAddr: mData["dstAddr"].(string),
|
||||
IfType: parse.Number(mData["ifType"]),
|
||||
MsgType: parse.Number(mData["msgType"]),
|
||||
MsgDirect: parse.Number(mData["msgDirect"]),
|
||||
Length: parse.Number(mData["dataLen"]),
|
||||
RawMsg: mData["dataInfo"].(string),
|
||||
Timestamp: parse.Number(mData["timestamp"]),
|
||||
DecMsg: mData["decMsg"].(string),
|
||||
})
|
||||
|
||||
// 推送文件
|
||||
if v, ok := mData["pcapFile"]; ok && v != "" {
|
||||
logger.Infof("pcapFile: %s", v)
|
||||
}
|
||||
})
|
||||
|
||||
// ============ 测试接收网元UDP发过来的数据
|
||||
// 初始化TCP服务 后续调整TODO
|
||||
tcpService := socket.SocketTCP{Addr: host, Port: port + 1}
|
||||
if _, err := tcpService.New(); err != nil {
|
||||
return err
|
||||
}
|
||||
// 接收处理TCP数据
|
||||
go tcpService.Resolve(1024, func(data []byte, n int) {
|
||||
logger.Infof("socket TCP: %s", string(data))
|
||||
mData, err := UDPDataHandler(data, n)
|
||||
if err != nil {
|
||||
logger.Errorf("tcp resolve data fail: %s", err.Error())
|
||||
return
|
||||
}
|
||||
// 插入数据库做记录
|
||||
r.traceDataRepository.Insert(model.TraceData{
|
||||
TaskId: parse.Number(mData["taskId"]),
|
||||
IMSI: mData["imsi"].(string),
|
||||
SrcAddr: mData["srcAddr"].(string),
|
||||
DstAddr: mData["dstAddr"].(string),
|
||||
IfType: parse.Number(mData["ifType"]),
|
||||
MsgType: parse.Number(mData["msgType"]),
|
||||
MsgDirect: parse.Number(mData["msgDirect"]),
|
||||
Length: parse.Number(mData["dataLen"]),
|
||||
RawMsg: mData["dataInfo"].(string),
|
||||
Timestamp: parse.Number(mData["timestamp"]),
|
||||
DecMsg: mData["decMsg"].(string),
|
||||
})
|
||||
|
||||
// 推送文件
|
||||
if v, ok := mData["pcapFile"]; ok && v != "" {
|
||||
logger.Infof("pcapFile: %s", v)
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseUDP 关闭UDP数据通道
|
||||
func (r *TraceTask) CloseUDP() {
|
||||
r.udpService.Close()
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *TraceTask) SelectPage(query map[string]any) map[string]any {
|
||||
return r.traceTaskRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectById 通过ID查询
|
||||
func (r *TraceTask) SelectById(id string) model.TraceTask {
|
||||
tasks := r.traceTaskRepository.SelectByIds([]string{id})
|
||||
if len(tasks) > 0 {
|
||||
return tasks[0]
|
||||
}
|
||||
return model.TraceTask{}
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r *TraceTask) Insert(task model.TraceTask) error {
|
||||
// 跟踪配置是否开启
|
||||
if v := config.Get("trace.enabled"); v != nil {
|
||||
if !v.(bool) {
|
||||
return fmt.Errorf("tracking is not enabled")
|
||||
}
|
||||
}
|
||||
host := "127.0.0.1"
|
||||
if v := config.Get("trace.host"); v != nil {
|
||||
host = v.(string)
|
||||
}
|
||||
var port int64 = 33033
|
||||
if v := config.Get("trace.port"); v != nil {
|
||||
port = parse.Number(v)
|
||||
}
|
||||
task.NotifyUrl = fmt.Sprintf("udp:%s:%d", host, port)
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(task.NeType, task.NeId)
|
||||
if neInfo.NeId != task.NeId || neInfo.IP == "" {
|
||||
return fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
traceId := r.traceTaskRepository.LastID() + 1 // 生成任务ID < 65535
|
||||
task.TraceId = fmt.Sprint(traceId)
|
||||
|
||||
// 发送任务给网元
|
||||
data := map[string]any{
|
||||
"neType": neInfo.NeType,
|
||||
"neId": neInfo.NeId,
|
||||
"notifyUrl": task.NotifyUrl,
|
||||
"id": traceId,
|
||||
"startTime": date.ParseDateToStr(task.StartTime, date.YYYY_MM_DD_HH_MM_SS),
|
||||
"endTime": date.ParseDateToStr(task.EndTime, date.YYYY_MM_DD_HH_MM_SS),
|
||||
}
|
||||
switch task.TraceType {
|
||||
case "1": // Interface
|
||||
data["traceType"] = "Interface"
|
||||
data["interfaces"] = strings.Split(task.Interfaces, ",")
|
||||
case "2": // Device
|
||||
data["traceType"] = "Device"
|
||||
data["ueIp"] = task.UeIp
|
||||
data["srcIp"] = task.SrcIp
|
||||
data["dstIp"] = task.DstIp
|
||||
data["signalPort"] = task.SignalPort
|
||||
task.UeIp = neInfo.IP
|
||||
case "3": // UE
|
||||
data["traceType"] = "UE"
|
||||
data["imsi"] = task.IMSI
|
||||
data["msisdn"] = task.MSISDN
|
||||
default:
|
||||
return fmt.Errorf("trace type is not disabled")
|
||||
}
|
||||
msg, err := neFetchlink.NeTraceAdd(neInfo, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s, _ := json.Marshal(msg)
|
||||
task.FetchMsg = string(s)
|
||||
|
||||
// 插入数据库
|
||||
r.traceTaskRepository.Insert(task)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update 修改信息
|
||||
func (r *TraceTask) Update(task model.TraceTask) error {
|
||||
// 跟踪配置是否开启
|
||||
if v := config.Get("trace.enabled"); v != nil {
|
||||
if !v.(bool) {
|
||||
return fmt.Errorf("tracking is not enabled")
|
||||
}
|
||||
}
|
||||
host := "127.0.0.1"
|
||||
if v := config.Get("trace.host"); v != nil {
|
||||
host = v.(string)
|
||||
}
|
||||
var port int64 = 33033
|
||||
if v := config.Get("trace.port"); v != nil {
|
||||
port = parse.Number(v)
|
||||
}
|
||||
task.NotifyUrl = fmt.Sprintf("udp:%s:%d", host, port)
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(task.NeType, task.NeId)
|
||||
if neInfo.NeId != task.NeId || neInfo.IP == "" {
|
||||
return fmt.Errorf("app.common.noNEInfo")
|
||||
}
|
||||
|
||||
// 查询网元任务信息
|
||||
if msg, err := neFetchlink.NeTraceInfo(neInfo, task.TraceId); err == nil {
|
||||
s, _ := json.Marshal(msg)
|
||||
task.FetchMsg = string(s)
|
||||
// 修改任务信息
|
||||
data := map[string]any{
|
||||
"neType": neInfo.NeType,
|
||||
"neId": neInfo.NeId,
|
||||
"notifyUrl": task.NotifyUrl,
|
||||
"id": parse.Number(task.TraceId),
|
||||
"startTime": date.ParseDateToStr(task.StartTime, date.YYYY_MM_DD_HH_MM_SS),
|
||||
"endTime": date.ParseDateToStr(task.EndTime, date.YYYY_MM_DD_HH_MM_SS),
|
||||
}
|
||||
switch task.TraceType {
|
||||
case "1": // Interface
|
||||
data["traceType"] = "Interface"
|
||||
data["interfaces"] = strings.Split(task.Interfaces, ",")
|
||||
case "2": // Device
|
||||
task.UeIp = neInfo.IP
|
||||
data["traceType"] = "Device"
|
||||
data["ueIp"] = task.UeIp
|
||||
data["srcIp"] = task.SrcIp
|
||||
data["dstIp"] = task.DstIp
|
||||
data["signalPort"] = task.SignalPort
|
||||
case "3": // UE
|
||||
data["traceType"] = "UE"
|
||||
data["imsi"] = task.IMSI
|
||||
data["msisdn"] = task.MSISDN
|
||||
default:
|
||||
return fmt.Errorf("trace type is not disabled")
|
||||
}
|
||||
neFetchlink.NeTraceEdit(neInfo, data)
|
||||
}
|
||||
|
||||
// 更新数据库
|
||||
r.traceTaskRepository.Update(task)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r *TraceTask) DeleteByIds(ids []string) (int64, error) {
|
||||
// 检查是否存在
|
||||
rows := r.traceTaskRepository.SelectByIds(ids)
|
||||
if len(rows) <= 0 {
|
||||
return 0, fmt.Errorf("not data")
|
||||
}
|
||||
|
||||
if len(rows) == len(ids) {
|
||||
// 停止任务
|
||||
for _, v := range rows {
|
||||
neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(v.NeType, v.NeId)
|
||||
if neInfo.NeId != v.NeId || neInfo.IP == "" {
|
||||
continue
|
||||
}
|
||||
neFetchlink.NeTraceDelete(neInfo, v.TraceId)
|
||||
}
|
||||
num := r.traceTaskRepository.DeleteByIds(ids)
|
||||
return num, nil
|
||||
}
|
||||
// 删除信息失败!
|
||||
return 0, fmt.Errorf("delete fail")
|
||||
}
|
||||
208
src/modules/trace/service/trace_task_hlr.go
Normal file
208
src/modules/trace/service/trace_task_hlr.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/ssh"
|
||||
neFetchlink "be.ems/src/modules/network_element/fetch_link"
|
||||
neModel "be.ems/src/modules/network_element/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
"be.ems/src/modules/trace/model"
|
||||
"be.ems/src/modules/trace/repository"
|
||||
)
|
||||
|
||||
// 实例化数据层 TraceTaskHlr 结构体
|
||||
var NewTraceTaskHlr = &TraceTaskHlr{
|
||||
traceTaskHlrRepository: repository.NewTraceTaskHlr,
|
||||
neInfoService: neService.NewNeInfoImpl,
|
||||
}
|
||||
|
||||
// TraceTaskHlr 跟踪_任务给HRL网元 服务层处理
|
||||
type TraceTaskHlr struct {
|
||||
// 跟踪_任务给HRL网元数据信息
|
||||
traceTaskHlrRepository *repository.TraceTaskHlr
|
||||
// 网元信息服务
|
||||
neInfoService neService.INeInfo
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r *TraceTaskHlr) SelectPage(querys model.TraceTaskHlrQuery) map[string]any {
|
||||
return r.traceTaskHlrRepository.SelectPage(querys)
|
||||
}
|
||||
|
||||
// SelectById 通过ID查询
|
||||
func (r *TraceTaskHlr) SelectById(id string) model.TraceTaskHlr {
|
||||
tasks := r.traceTaskHlrRepository.SelectByIds([]string{id})
|
||||
if len(tasks) > 0 {
|
||||
return tasks[0]
|
||||
}
|
||||
return model.TraceTaskHlr{}
|
||||
}
|
||||
|
||||
// Insert 新增信息
|
||||
func (r *TraceTaskHlr) Insert(task model.TraceTaskHlr) string {
|
||||
return r.traceTaskHlrRepository.Insert(task)
|
||||
}
|
||||
|
||||
// Update 修改信息
|
||||
func (r *TraceTaskHlr) Update(task model.TraceTaskHlr) int64 {
|
||||
return r.traceTaskHlrRepository.Update(task)
|
||||
}
|
||||
|
||||
// DeleteByIds 批量删除信息
|
||||
func (r *TraceTaskHlr) DeleteByIds(ids []string) (int64, error) {
|
||||
// 检查是否存在
|
||||
rows := r.traceTaskHlrRepository.SelectByIds(ids)
|
||||
if len(rows) <= 0 {
|
||||
return 0, fmt.Errorf("not data")
|
||||
}
|
||||
|
||||
if len(rows) == len(ids) {
|
||||
// 停止任务
|
||||
neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false)
|
||||
for _, r := range rows {
|
||||
if r.Status == "0" {
|
||||
continue
|
||||
}
|
||||
for _, v := range neInfos {
|
||||
neFetchlink.HLRTraceStop(v, map[string]any{
|
||||
"traceIDArray": []string{r.TraceId},
|
||||
})
|
||||
}
|
||||
}
|
||||
num := r.traceTaskHlrRepository.DeleteByIds(ids)
|
||||
return num, nil
|
||||
}
|
||||
// 删除信息失败!
|
||||
return 0, fmt.Errorf("delete fail")
|
||||
}
|
||||
|
||||
// Start 创建任务
|
||||
func (r *TraceTaskHlr) Start(task model.TraceTaskHlr) (string, error) {
|
||||
hlrList := []map[string]any{}
|
||||
traceId := r.traceTaskHlrRepository.LastID() + 1 // 生成任务ID < 65535
|
||||
data := map[string]any{
|
||||
"traceID": traceId,
|
||||
"imsi": task.IMSI,
|
||||
"msisdn": task.MSISDN,
|
||||
}
|
||||
if task.StartTime > task.EndTime {
|
||||
return "", fmt.Errorf("startTime must less than endTime")
|
||||
}
|
||||
if task.StartTime > 0 {
|
||||
data["startTime"] = date.ParseDateToStr(task.StartTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
}
|
||||
if task.StartTime > 0 {
|
||||
data["endTime"] = date.ParseDateToStr(task.EndTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
}
|
||||
|
||||
// 发送创建任务
|
||||
neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false)
|
||||
for _, neInfo := range neInfos {
|
||||
hlrItem := map[string]any{
|
||||
"neType": neInfo.NeType,
|
||||
"neId": neInfo.NeId,
|
||||
"msg": "",
|
||||
}
|
||||
msg, err := neFetchlink.HLRTraceStart(neInfo, data)
|
||||
if err != nil {
|
||||
hlrItem["err"] = err.Error()
|
||||
} else {
|
||||
hlrItem["err"] = msg
|
||||
}
|
||||
hlrList = append(hlrList, hlrItem)
|
||||
}
|
||||
|
||||
msg, _ := json.Marshal(hlrList)
|
||||
task.Msg = string(msg)
|
||||
task.Status = "1"
|
||||
task.TraceId = fmt.Sprint(traceId)
|
||||
id := r.traceTaskHlrRepository.Insert(task)
|
||||
if id == "" {
|
||||
return "", fmt.Errorf("start task fail")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// Stop 停止任务
|
||||
func (r *TraceTaskHlr) Stop(task model.TraceTaskHlr) error {
|
||||
hlrList := []map[string]any{}
|
||||
// 发送停止任务
|
||||
neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false)
|
||||
for _, neInfo := range neInfos {
|
||||
hlrItem := map[string]any{
|
||||
"neType": neInfo.NeType,
|
||||
"neId": neInfo.NeId,
|
||||
"msg": "",
|
||||
}
|
||||
msg, err := neFetchlink.HLRTraceStop(neInfo, map[string]any{
|
||||
"traceIDArray": []string{task.TraceId},
|
||||
})
|
||||
if err != nil {
|
||||
hlrItem["err"] = err.Error()
|
||||
} else {
|
||||
hlrItem["err"] = msg
|
||||
}
|
||||
hlrList = append(hlrList, hlrItem)
|
||||
}
|
||||
|
||||
msg, _ := json.Marshal(hlrList)
|
||||
task.Msg = string(msg)
|
||||
task.Status = "0"
|
||||
rows := r.traceTaskHlrRepository.Update(task)
|
||||
if rows <= 0 {
|
||||
return fmt.Errorf("stop task fail")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// File 任务文件
|
||||
func (r *TraceTaskHlr) File(traceId, dirPath string) ([]map[string]any, error) {
|
||||
hlrList := []map[string]any{}
|
||||
// 查询所有匹配的网元类型
|
||||
neInfos := r.neInfoService.SelectList(neModel.NeInfo{NeType: "UDM"}, false, false)
|
||||
if len(neInfos) == 0 {
|
||||
return nil, fmt.Errorf("not found network element")
|
||||
}
|
||||
|
||||
// 遍历多个网元主机获取文件
|
||||
for _, neInfo := range neInfos {
|
||||
hlrItem := map[string]any{
|
||||
"neType": neInfo.NeType,
|
||||
"neId": neInfo.NeId,
|
||||
"neName": neInfo.NeName,
|
||||
"err": "",
|
||||
}
|
||||
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := r.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
hlrItem["err"] = "ssh link fail"
|
||||
hlrList = append(hlrList, hlrItem)
|
||||
continue
|
||||
}
|
||||
defer sshClient.Close()
|
||||
|
||||
// 获取文件列表
|
||||
fileName := fmt.Sprintf("%s_%s", neInfo.NeName, traceId)
|
||||
_, rows, err := ssh.FileList(sshClient, filepath.ToSlash(dirPath), fileName)
|
||||
if err != nil {
|
||||
hlrItem["err"] = "file not found"
|
||||
hlrList = append(hlrList, hlrItem)
|
||||
continue
|
||||
}
|
||||
|
||||
// 遍历组装
|
||||
for _, v := range rows {
|
||||
if v.FileType == "file" {
|
||||
hlrItem["fileName"] = v.FileName
|
||||
hlrItem["filePath"] = filepath.ToSlash(filepath.Join(dirPath, v.FileName))
|
||||
hlrList = append(hlrList, hlrItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
return hlrList, nil
|
||||
}
|
||||
330
src/modules/trace/service/trace_task_udp_data.go
Normal file
330
src/modules/trace/service/trace_task_udp_data.go
Normal file
@@ -0,0 +1,330 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
)
|
||||
|
||||
const (
|
||||
GTPU_V1_VERSION = 1 << 5
|
||||
GTPU_VER_MASK = 7 << 5
|
||||
GTPU_PT_GTP = 1 << 4
|
||||
GTPU_HEADER_LEN = 12
|
||||
GTPU_E_S_PB_BIT = 7
|
||||
GTPU_E_BI = 1 << 2
|
||||
)
|
||||
|
||||
const (
|
||||
GTPU_HEADER_VERSION_INDEX = 0
|
||||
GTPU_HEADER_MSG_TYPE_INDEX = 1
|
||||
GTPU_HEADER_LENGTH_INDEX = 2
|
||||
GTPU_HEADER_TEID_INDEX = 4
|
||||
)
|
||||
|
||||
type ExtHeader struct {
|
||||
TaskId uint32
|
||||
IMSI string
|
||||
IfType int
|
||||
MsgType int
|
||||
MsgDirect int // 0-recv,1-send
|
||||
TimeStamp int64
|
||||
SrcIP string
|
||||
DstIP string
|
||||
SrcPort uint16
|
||||
DstPort uint16
|
||||
Proto int // Protocol
|
||||
PPI int // only for SCTP
|
||||
DataLen uint16
|
||||
DataInfo []byte
|
||||
}
|
||||
|
||||
// parseUDPData 解析UDP数据
|
||||
func parseUDPData(rvMsg []byte, rvLen int) (ExtHeader, error) {
|
||||
var extHdr ExtHeader
|
||||
// var tr dborm.TraceData
|
||||
var off int
|
||||
msg := rvMsg
|
||||
|
||||
verFlags := msg[GTPU_HEADER_VERSION_INDEX]
|
||||
|
||||
gtpuHdrLen := GTPU_HEADER_LEN
|
||||
|
||||
localTeid := binary.BigEndian.Uint32(msg[GTPU_HEADER_TEID_INDEX:])
|
||||
|
||||
extHdr.TaskId = localTeid
|
||||
|
||||
if (verFlags & GTPU_E_S_PB_BIT) != 0 {
|
||||
if (verFlags & GTPU_E_BI) != 0 {
|
||||
extTypeIndex := GTPU_HEADER_LEN - 1
|
||||
|
||||
extType := msg[extTypeIndex]
|
||||
|
||||
if extType == 0xFE {
|
||||
extHdr.IMSI = string(msg[extTypeIndex+2 : extTypeIndex+17])
|
||||
extHdr.IfType = int(msg[extTypeIndex+17])
|
||||
extHdr.MsgType = int(msg[extTypeIndex+18])
|
||||
extHdr.MsgDirect = int(msg[extTypeIndex+19])
|
||||
|
||||
extHdr.TimeStamp = time.Now().UTC().UnixMilli()
|
||||
// extHdr.TimeStamp = int64(binary.BigEndian.Uint64(msg[extTypeIndex+19:]))
|
||||
// fmt.Printf("ext info %v %s %d %d %d \n", msg[(extTypeIndex+2):(extTypeIndex+20)], extHdr.IMSI, extHdr.IfType, extHdr.MsgType, extHdr.MsgDirect)
|
||||
// set offset of IP Packet
|
||||
off = 40 + 4
|
||||
//src ip: msg+40+12
|
||||
extHdr.SrcIP = fmt.Sprintf("%d.%d.%d.%d", msg[off+12], msg[off+13], msg[off+14], msg[off+15])
|
||||
//dst ip: msg+40+12+4
|
||||
extHdr.DstIP = fmt.Sprintf("%d.%d.%d.%d", msg[off+16], msg[off+17], msg[off+18], msg[off+19])
|
||||
extHdr.SrcPort = uint16(binary.BigEndian.Uint16(msg[off+20:]))
|
||||
extHdr.DstPort = uint16(binary.BigEndian.Uint16(msg[off+22:]))
|
||||
// fmt.Printf("info %s:%d %s:%d \n", extHdr.SrcIP, extHdr.SrcPort, extHdr.DstIP, extHdr.DstPort)
|
||||
// ip header start msg+40
|
||||
extHdr.DataLen = uint16(rvLen - off)
|
||||
extHdr.DataInfo = make([]byte, int(rvLen-off))
|
||||
copy(extHdr.DataInfo, []byte(msg[off:]))
|
||||
|
||||
// 132 SCTP
|
||||
// 6 TCP
|
||||
// 17 UDP
|
||||
extHdr.Proto = int(msg[off+9])
|
||||
if extHdr.Proto == 132 {
|
||||
extHdr.PPI = int(msg[off+47])
|
||||
extHdr.DataLen = uint16(binary.BigEndian.Uint16(msg[(off+34):]) - 16)
|
||||
// fmt.Printf("dat len %d %d \n", extHdr.DataLen, extHdr.PPI)
|
||||
}
|
||||
}
|
||||
|
||||
for extType != 0 && extTypeIndex < rvLen {
|
||||
extLen := msg[extTypeIndex+1] << 2
|
||||
if extLen == 0 {
|
||||
return extHdr, fmt.Errorf("error, extLen is zero")
|
||||
}
|
||||
|
||||
gtpuHdrLen += int(extLen)
|
||||
extTypeIndex += int(extLen)
|
||||
extType = msg[extTypeIndex]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gtpuHdrLen -= 4
|
||||
}
|
||||
return extHdr, nil
|
||||
}
|
||||
|
||||
// UDPDataHandler UDP数据处理
|
||||
func UDPDataHandler(data []byte, n int) (map[string]any, error) {
|
||||
extHdr, err := parseUDPData(data, n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if extHdr.TaskId == 0 || extHdr.DataLen < 1 {
|
||||
return nil, fmt.Errorf("data error")
|
||||
}
|
||||
|
||||
m := map[string]any{
|
||||
"taskId": extHdr.TaskId,
|
||||
"imsi": extHdr.IMSI,
|
||||
"ifType": extHdr.IfType,
|
||||
"srcAddr": fmt.Sprintf("%s:%d", extHdr.SrcIP, extHdr.SrcPort),
|
||||
"dstAddr": fmt.Sprintf("%s:%d", extHdr.DstIP, extHdr.DstPort),
|
||||
"msgType": extHdr.MsgType,
|
||||
"msgDirect": extHdr.MsgDirect,
|
||||
"timestamp": extHdr.TimeStamp,
|
||||
"dataLen": extHdr.DataLen,
|
||||
// "dataInfo": extHdr.DataInfo,
|
||||
"decMsg": "",
|
||||
}
|
||||
// Base64 编码
|
||||
m["dataInfo"] = base64.StdEncoding.EncodeToString(extHdr.DataInfo)
|
||||
|
||||
if extHdr.Proto == 6 { // TCP
|
||||
// 取响应数据
|
||||
iplen := uint16(binary.BigEndian.Uint16(extHdr.DataInfo[2:]))
|
||||
tcplen := uint16(iplen - 32 - 20)
|
||||
hdrlen := uint16(binary.BigEndian.Uint16(extHdr.DataInfo[20+32+1:]))
|
||||
offset := uint16(52)
|
||||
// fmt.Printf("HTTP %d %d %d \n", iplen, tcplen, hdrlen)
|
||||
if tcplen > (hdrlen + 9) { // has data
|
||||
doffset := uint16(offset + hdrlen + 9)
|
||||
datlen := uint16(binary.BigEndian.Uint16(extHdr.DataInfo[doffset+1:]))
|
||||
// fmt.Printf("HTTP datlen %d \n", datlen)
|
||||
m["decMsg"], _ = httpDataMsg(extHdr.DataInfo[offset+9:offset+9+hdrlen], extHdr.DataInfo[doffset+9:doffset+datlen+9])
|
||||
} else {
|
||||
m["decMsg"], _ = httpDataMsg(extHdr.DataInfo[offset+9:hdrlen], nil)
|
||||
}
|
||||
}
|
||||
|
||||
// pcap文件
|
||||
m["pcapFile"] = writePcap(extHdr)
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// =========== TCP协议Body ===========
|
||||
|
||||
// httpDataMsg Http数据信息处理
|
||||
func httpDataMsg(header []byte, data []byte) (string, error) {
|
||||
var remainSize = uint32(16 << 20)
|
||||
var sawRegular bool
|
||||
var invalid bool // pseudo header field errors
|
||||
var Fields []hpack.HeaderField
|
||||
|
||||
invalid = false
|
||||
hdec := hpack.NewDecoder(4096, nil)
|
||||
hdec.SetEmitEnabled(true)
|
||||
hdec.SetMaxStringLength(int(16 << 20))
|
||||
hdec.SetEmitFunc(func(hf hpack.HeaderField) {
|
||||
if !httpguts.ValidHeaderFieldValue(hf.Value) {
|
||||
// Don't include the value in the error, because it may be sensitive.
|
||||
invalid = true
|
||||
}
|
||||
isPseudo := strings.HasPrefix(hf.Name, ":")
|
||||
if isPseudo {
|
||||
if sawRegular {
|
||||
invalid = true
|
||||
}
|
||||
} else {
|
||||
sawRegular = true
|
||||
if !validWireHeaderFieldName(hf.Name) {
|
||||
invalid = true
|
||||
}
|
||||
}
|
||||
|
||||
if invalid {
|
||||
hdec.SetEmitEnabled(false)
|
||||
return
|
||||
}
|
||||
|
||||
size := hf.Size()
|
||||
if size > remainSize {
|
||||
hdec.SetEmitEnabled(false)
|
||||
//mh.Truncated = true
|
||||
return
|
||||
}
|
||||
remainSize -= size
|
||||
|
||||
Fields = append(Fields, hf)
|
||||
})
|
||||
|
||||
// defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
|
||||
|
||||
frag := header
|
||||
if _, err := hdec.Write(frag); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := hdec.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
|
||||
|
||||
var headers []byte
|
||||
var line string
|
||||
for i := range Fields {
|
||||
line = fmt.Sprintf("\"%s\":\"%s\",", Fields[i].Name, Fields[i].Value)
|
||||
headers = append(headers, []byte(line)...)
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
return fmt.Sprintf("{ %s \"content\":%s }", string(headers), string(data)), nil
|
||||
} else {
|
||||
return fmt.Sprintf("{ %s }", string(headers)), nil
|
||||
}
|
||||
}
|
||||
|
||||
// validWireHeaderFieldName 校验报文头字段名称
|
||||
func validWireHeaderFieldName(v string) bool {
|
||||
if len(v) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, r := range v {
|
||||
if !httpguts.IsTokenRune(r) {
|
||||
return false
|
||||
}
|
||||
if 'A' <= r && r <= 'Z' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// =========== writePcap 写Pcap文件 ===========
|
||||
|
||||
const magicMicroseconds = 0xA1B2C3D4
|
||||
const versionMajor = 2
|
||||
const versionMinor = 4
|
||||
|
||||
func writeEmptyPcap(filename string, timeStamp int64, length int, data []byte) error {
|
||||
var err error
|
||||
var file *os.File
|
||||
if _, err = os.Stat(filename); os.IsNotExist(err) {
|
||||
file, err = os.Create(filename)
|
||||
// File Header
|
||||
var fileHeaderBuf [24]byte
|
||||
binary.LittleEndian.PutUint32(fileHeaderBuf[0:4], magicMicroseconds)
|
||||
binary.LittleEndian.PutUint16(fileHeaderBuf[4:6], versionMajor)
|
||||
binary.LittleEndian.PutUint16(fileHeaderBuf[6:8], versionMinor)
|
||||
// bytes 8:12 stay 0 (timezone = UTC)
|
||||
// bytes 12:16 stay 0 (sigfigs is always set to zero, according to
|
||||
// http://wiki.wireshark.org/Development/LibpcapFileFormat
|
||||
binary.LittleEndian.PutUint32(fileHeaderBuf[16:20], 0x00040000)
|
||||
binary.LittleEndian.PutUint32(fileHeaderBuf[20:24], 0x00000071)
|
||||
if _, err := file.Write(fileHeaderBuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
file, err = os.OpenFile(filename, os.O_WRONLY|os.O_APPEND, 0666)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Packet Header
|
||||
var packetHeaderBuf [24]byte
|
||||
t := time.UnixMilli(timeStamp)
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
}
|
||||
secs := t.Unix()
|
||||
usecs := t.Nanosecond() / 1000
|
||||
binary.LittleEndian.PutUint32(packetHeaderBuf[0:4], uint32(secs))
|
||||
binary.LittleEndian.PutUint32(packetHeaderBuf[4:8], uint32(usecs))
|
||||
binary.LittleEndian.PutUint32(packetHeaderBuf[8:12], uint32(length+16))
|
||||
binary.LittleEndian.PutUint32(packetHeaderBuf[12:16], uint32(length+16))
|
||||
if _, err := file.Write(packetHeaderBuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 数据包内容的定义
|
||||
cooked := [...]byte{0x00, 0x00, 0x03, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00}
|
||||
if _, err := file.Write(cooked[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Packet Data
|
||||
if _, err := file.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writePcap 写Pcap文件并返回文件路径
|
||||
func writePcap(extHdr ExtHeader) string {
|
||||
filePath := fmt.Sprintf("/tmp/trace_%d .pcap", extHdr.TaskId)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
err := writeEmptyPcap(filePath, extHdr.TimeStamp, int(extHdr.DataLen), extHdr.DataInfo)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"be.ems/src/framework/middleware"
|
||||
"be.ems/src/framework/middleware/collectlogs"
|
||||
"be.ems/src/modules/trace/controller"
|
||||
"be.ems/src/modules/trace/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -13,6 +14,9 @@ import (
|
||||
func Setup(router *gin.Engine) {
|
||||
logger.Infof("开始加载 ====> trace 模块路由")
|
||||
|
||||
// 启动时需要的初始参数
|
||||
InitLoad()
|
||||
|
||||
traceGroup := router.Group("/trace")
|
||||
|
||||
// 信令抓包
|
||||
@@ -38,4 +42,77 @@ func Setup(router *gin.Engine) {
|
||||
controller.NewTcpdump.UPFTrace,
|
||||
)
|
||||
}
|
||||
|
||||
// 跟踪任务 网元HLR (免登录)
|
||||
taskHLRGroup := traceGroup.Group("/task/hlr")
|
||||
{
|
||||
taskHLRGroup.GET("/list",
|
||||
controller.NewTraceTaskHlr.List,
|
||||
)
|
||||
taskHLRGroup.DELETE("/:ids",
|
||||
controller.NewTraceTaskHlr.Remove,
|
||||
)
|
||||
taskHLRGroup.POST("/start",
|
||||
controller.NewTraceTaskHlr.Start,
|
||||
)
|
||||
taskHLRGroup.POST("/stop",
|
||||
controller.NewTraceTaskHlr.Stop,
|
||||
)
|
||||
taskHLRGroup.POST("/file",
|
||||
controller.NewTraceTaskHlr.File,
|
||||
)
|
||||
taskHLRGroup.GET("/filePull",
|
||||
controller.NewTraceTaskHlr.FilePull,
|
||||
)
|
||||
}
|
||||
|
||||
// 跟踪任务
|
||||
taskGroup := traceGroup.Group("/task")
|
||||
{
|
||||
taskGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewTraceTask.List,
|
||||
)
|
||||
taskGroup.GET("/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewTraceTask.Info,
|
||||
)
|
||||
taskGroup.POST("",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.task", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewTraceTask.Add,
|
||||
)
|
||||
taskGroup.PUT("",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.task", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewTraceTask.Edit,
|
||||
)
|
||||
taskGroup.DELETE("/:ids",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.task", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewTraceTask.Remove,
|
||||
)
|
||||
}
|
||||
|
||||
// 跟踪数据
|
||||
taskDataGroup := traceGroup.Group("/data")
|
||||
{
|
||||
taskDataGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewTraceData.List,
|
||||
)
|
||||
taskDataGroup.DELETE("/:ids",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.taskData", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewTraceData.Remove,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// InitLoad 初始参数
|
||||
func InitLoad() {
|
||||
// 创建跟踪任务信令数据通道UDP
|
||||
if err := service.NewTraceTask.CreateUDP(); err != nil {
|
||||
logger.Errorf("socket udp init fail: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/ssh"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/ws/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -286,10 +286,6 @@ func (s *WSController) Telnet(c *gin.Context) {
|
||||
go s.wsService.ClientWriteListen(wsClient)
|
||||
go s.wsService.ClientReadListen(wsClient, service.ReceiveTelnet)
|
||||
|
||||
// 等待1秒,排空首次消息
|
||||
time.Sleep(1 * time.Second)
|
||||
_ = clientSession.Read()
|
||||
|
||||
// 实时读取Telnet消息直接输出
|
||||
msTicker := time.NewTicker(100 * time.Millisecond)
|
||||
defer msTicker.Stop()
|
||||
@@ -298,7 +294,7 @@ func (s *WSController) Telnet(c *gin.Context) {
|
||||
case ms := <-msTicker.C:
|
||||
outputByte := clientSession.Read()
|
||||
if len(outputByte) > 0 {
|
||||
outputStr := strings.TrimRight(string(outputByte), "\x00")
|
||||
outputStr := string(outputByte)
|
||||
msgByte, _ := json.Marshal(result.Ok(map[string]any{
|
||||
"requestId": fmt.Sprintf("telnet_%s_%d", neHost.HostID, ms.UnixMilli()),
|
||||
"data": outputStr,
|
||||
|
||||
@@ -8,13 +8,13 @@ type NetConnectData struct {
|
||||
Status string `json:"status"`
|
||||
Laddr net.Addr `json:"localaddr"`
|
||||
Raddr net.Addr `json:"remoteaddr"`
|
||||
PID int32 `json:"PID"`
|
||||
PID int32 `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// NetConnectQuery 网络连接进程查询
|
||||
type NetConnectQuery struct {
|
||||
Port int32 `json:"port"`
|
||||
ProcessName string `json:"processName"`
|
||||
ProcessID int32 `json:"processID"`
|
||||
Port int32 `json:"port"`
|
||||
Name string `json:"name"`
|
||||
PID int32 `json:"pid"`
|
||||
}
|
||||
|
||||
@@ -2,37 +2,33 @@ package model
|
||||
|
||||
// PsProcessData 进程数据
|
||||
type PsProcessData struct {
|
||||
PID int32 `json:"PID"`
|
||||
PID int32 `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
PPID int32 `json:"PPID"`
|
||||
PPID int32 `json:"ppid"`
|
||||
Username string `json:"username"`
|
||||
Status string `json:"status"`
|
||||
StartTime string `json:"startTime"`
|
||||
StartTime int64 `json:"startTime"`
|
||||
NumThreads int32 `json:"numThreads"`
|
||||
NumConnections int `json:"numConnections"`
|
||||
CpuPercent string `json:"cpuPercent"`
|
||||
|
||||
DiskRead string `json:"diskRead"`
|
||||
DiskWrite string `json:"diskWrite"`
|
||||
CmdLine string `json:"cmdLine"`
|
||||
DiskRead uint64 `json:"diskRead"`
|
||||
DiskWrite uint64 `json:"diskWrite"`
|
||||
|
||||
Rss string `json:"rss"`
|
||||
VMS string `json:"vms"`
|
||||
HWM string `json:"hwm"`
|
||||
Data string `json:"data"`
|
||||
Stack string `json:"stack"`
|
||||
Locked string `json:"locked"`
|
||||
Swap string `json:"swap"`
|
||||
Rss uint64 `json:"rss"`
|
||||
VMS uint64 `json:"vms"`
|
||||
HWM uint64 `json:"hwm"`
|
||||
Data uint64 `json:"data"`
|
||||
Stack uint64 `json:"stack"`
|
||||
Locked uint64 `json:"locked"`
|
||||
Swap uint64 `json:"swap"`
|
||||
|
||||
CpuValue float64 `json:"cpuValue"`
|
||||
RssValue uint64 `json:"rssValue"`
|
||||
|
||||
Envs []string `json:"envs"`
|
||||
CmdLine string `json:"cmdLine"`
|
||||
}
|
||||
|
||||
// PsProcessQuery 进程查询
|
||||
type PsProcessQuery struct {
|
||||
Pid int32 `json:"pid"`
|
||||
PID int32 `json:"pid"`
|
||||
Name string `json:"name"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
@@ -29,13 +29,16 @@ func GetNetConnections(requestID string, data any) ([]byte, error) {
|
||||
continue
|
||||
}
|
||||
for _, conn := range connections {
|
||||
if query.ProcessID > 0 && query.ProcessID != conn.Pid {
|
||||
if query.PID > 0 && query.PID != conn.Pid {
|
||||
continue
|
||||
}
|
||||
proc, err := process.NewProcess(conn.Pid)
|
||||
if err == nil {
|
||||
name, _ := proc.Name()
|
||||
if name != "" && query.ProcessName != "" && !strings.Contains(name, query.ProcessName) {
|
||||
name, err := proc.Name()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if query.Name != "" && !strings.Contains(name, query.Name) {
|
||||
continue
|
||||
}
|
||||
if query.Port > 0 && query.Port != int32(conn.Laddr.Port) && query.Port != int32(conn.Raddr.Port) {
|
||||
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/ws/model"
|
||||
"github.com/shirou/gopsutil/v4/process"
|
||||
@@ -31,86 +29,68 @@ func GetProcessData(requestID string, data any) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
dataArr = []model.PsProcessData{}
|
||||
resultMutex sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
numWorkers = 4
|
||||
)
|
||||
|
||||
handleData := func(proc *process.Process) {
|
||||
// 解析数据
|
||||
handleData := func(proc *process.Process) (model.PsProcessData, bool) {
|
||||
procData := model.PsProcessData{
|
||||
PID: proc.Pid,
|
||||
}
|
||||
if query.Pid > 0 && query.Pid != proc.Pid {
|
||||
return
|
||||
}
|
||||
procName, err := proc.Name()
|
||||
if procName == "" || err != nil {
|
||||
return
|
||||
} else {
|
||||
if procName, err := proc.Name(); err == nil {
|
||||
procData.Name = procName
|
||||
}
|
||||
if query.Name != "" && !strings.Contains(procData.Name, query.Name) {
|
||||
return
|
||||
}
|
||||
if username, err := proc.Username(); err == nil {
|
||||
procData.Username = username
|
||||
}
|
||||
|
||||
// 查询过滤
|
||||
if query.PID > 0 && procData.PID != query.PID {
|
||||
return procData, false
|
||||
}
|
||||
if query.Name != "" && !strings.Contains(procData.Name, query.Name) {
|
||||
return procData, false
|
||||
}
|
||||
if query.Username != "" && !strings.Contains(procData.Username, query.Username) {
|
||||
return
|
||||
return procData, false
|
||||
}
|
||||
|
||||
procData.PPID, _ = proc.Ppid()
|
||||
statusArray, _ := proc.Status()
|
||||
if len(statusArray) > 0 {
|
||||
if statusArray, err := proc.Status(); err == nil && len(statusArray) > 0 {
|
||||
procData.Status = strings.Join(statusArray, ",")
|
||||
}
|
||||
createTime, procErr := proc.CreateTime()
|
||||
if procErr == nil {
|
||||
procData.StartTime = date.ParseDateToStr(createTime, date.YYYY_MM_DD_HH_MM_SS)
|
||||
if createTime, err := proc.CreateTime(); err == nil {
|
||||
procData.StartTime = createTime
|
||||
}
|
||||
procData.NumThreads, _ = proc.NumThreads()
|
||||
procData.CpuValue, _ = proc.CPUPercent()
|
||||
procData.CpuPercent = fmt.Sprintf("%.2f", procData.CpuValue) + "%"
|
||||
if connections, err := proc.Connections(); err == nil {
|
||||
procData.NumConnections = len(connections)
|
||||
}
|
||||
cpuPercent, _ := proc.CPUPercent()
|
||||
procData.CpuPercent = fmt.Sprintf("%.2f", cpuPercent)
|
||||
menInfo, procErr := proc.MemoryInfo()
|
||||
if procErr == nil {
|
||||
procData.Rss = parse.Bit(float64(menInfo.RSS))
|
||||
procData.Data = parse.Bit(float64(menInfo.Data))
|
||||
procData.VMS = parse.Bit(float64(menInfo.VMS))
|
||||
procData.HWM = parse.Bit(float64(menInfo.HWM))
|
||||
procData.Stack = parse.Bit(float64(menInfo.Stack))
|
||||
procData.Locked = parse.Bit(float64(menInfo.Locked))
|
||||
procData.Swap = parse.Bit(float64(menInfo.Swap))
|
||||
|
||||
procData.RssValue = menInfo.RSS
|
||||
} else {
|
||||
procData.Rss = "--"
|
||||
procData.Data = "--"
|
||||
procData.VMS = "--"
|
||||
procData.HWM = "--"
|
||||
procData.Stack = "--"
|
||||
procData.Locked = "--"
|
||||
procData.Swap = "--"
|
||||
|
||||
procData.RssValue = 0
|
||||
procData.Rss = menInfo.RSS
|
||||
procData.Data = menInfo.Data
|
||||
procData.VMS = menInfo.VMS
|
||||
procData.HWM = menInfo.HWM
|
||||
procData.Stack = menInfo.Stack
|
||||
procData.Locked = menInfo.Locked
|
||||
procData.Swap = menInfo.Swap
|
||||
}
|
||||
ioStat, procErr := proc.IOCounters()
|
||||
if procErr == nil {
|
||||
procData.DiskWrite = parse.Bit(float64(ioStat.WriteBytes))
|
||||
procData.DiskRead = parse.Bit(float64(ioStat.ReadBytes))
|
||||
} else {
|
||||
procData.DiskWrite = "--"
|
||||
procData.DiskRead = "--"
|
||||
if ioStat, err := proc.IOCounters(); err == nil {
|
||||
procData.DiskWrite = ioStat.WriteBytes
|
||||
procData.DiskRead = ioStat.ReadBytes
|
||||
}
|
||||
procData.CmdLine, _ = proc.Cmdline()
|
||||
procData.Envs, _ = proc.Environ()
|
||||
|
||||
resultMutex.Lock()
|
||||
dataArr = append(dataArr, procData)
|
||||
resultMutex.Unlock()
|
||||
return procData, true
|
||||
}
|
||||
|
||||
var (
|
||||
dataArr = []model.PsProcessData{}
|
||||
mu sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
numWorkers = 4
|
||||
)
|
||||
|
||||
chunkSize := (len(processes) + numWorkers - 1) / numWorkers
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
wg.Add(1)
|
||||
@@ -122,9 +102,15 @@ func GetProcessData(requestID string, data any) ([]byte, error) {
|
||||
|
||||
go func(start, end int) {
|
||||
defer wg.Done()
|
||||
localDataArr := make([]model.PsProcessData, 0, end-start) // 本地切片避免竞态
|
||||
for j := start; j < end; j++ {
|
||||
handleData(processes[j])
|
||||
if data, ok := handleData(processes[j]); ok {
|
||||
localDataArr = append(localDataArr, data)
|
||||
}
|
||||
}
|
||||
mu.Lock()
|
||||
dataArr = append(dataArr, localDataArr...)
|
||||
mu.Unlock()
|
||||
}(start, end)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ssh"
|
||||
"be.ems/src/framework/utils/telnet"
|
||||
"be.ems/src/framework/vo/result"
|
||||
"be.ems/src/modules/ws/model"
|
||||
"be.ems/src/modules/ws/processor"
|
||||
@@ -234,9 +234,8 @@ func (s *WSReceiveImpl) Telnet(client *model.WSClient, reqMsg model.WSRequest) {
|
||||
}
|
||||
err = json.Unmarshal(msgByte, &data)
|
||||
if err == nil {
|
||||
telnetClientSession := client.ChildConn.(*telnet.TelnetClientSession)
|
||||
err = telnetClientSession.WindowChange(data.Rows, data.Cols)
|
||||
_ = telnetClientSession.Read()
|
||||
// telnetClientSession := client.ChildConn.(*telnet.TelnetClientSession)
|
||||
// _ = telnetClientSession.WindowChange(data.Rows, data.Cols)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("message type %s not supported", reqMsg.Type)
|
||||
|
||||
Reference in New Issue
Block a user