1
0

merge: 合并代码20240706

This commit is contained in:
TsMask
2024-07-06 18:27:00 +08:00
parent 3b50e2f3f8
commit 49860c2f28
145 changed files with 4366 additions and 4051 deletions

View File

@@ -1,7 +1,7 @@
# 项目信息
framework:
name: "CN EMS"
version: "2.2405.4"
version: "2.2407.1"
# 应用服务配置
server:

View File

@@ -1,12 +1,12 @@
package admin
// 管理员常量信息
// 系统管理员常量信息
// 管理员-系统指定角色ID
// 系统管理员-系统指定角色ID
const ROLE_ID = "1"
// 管理员-系统指定角色KEY
const ROLE_KEY = "admin"
// 系统管理员-系统指定角色KEY
const ROLE_KEY = "system"
// 管理员-系统指定权限
// 系统管理员-系统指定权限
const PERMISSION = "*:*:*"

View File

@@ -8,6 +8,7 @@ import (
"time"
"be.ems/src/framework/constants/common"
tokenConstants "be.ems/src/framework/constants/token"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/parse"
@@ -178,6 +179,8 @@ var maskProperties []string = []string{
"oldPassword",
"newPassword",
"confirmPassword",
tokenConstants.RESPONSE_FIELD,
tokenConstants.ACCESS_TOKEN,
}
// processSensitiveFields 处理敏感属性字段

View File

@@ -20,6 +20,7 @@ var URL_WHITE_LIST = []string{
"/systemState",
"/omcNeConfig",
"/cdrEvent",
"/ueEvent",
"/upload-ue",
"/oauth/token",
}

View File

@@ -84,8 +84,8 @@ func Authorization(c *gin.Context) string {
return ""
}
// 拆分 Authorization 请求头,提取 JWT 令牌部分
arr := strings.Split(authHeader, token.HEADER_PREFIX)
if len(arr) == 2 && arr[1] == "" {
arr := strings.SplitN(authHeader, token.HEADER_PREFIX, 2)
if len(arr) < 2 {
return ""
}
return arr[1]
@@ -212,6 +212,11 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string)
conditions = append(conditions, sql)
}
if roledatascope.DEPT == dataScope {
sql := fmt.Sprintf(`%s.dept_id = '%s'`, deptAlias, userInfo.DeptID)
conditions = append(conditions, sql)
}
if roledatascope.DEPT_AND_CHILD == dataScope {
sql := fmt.Sprintf(`%s.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = '%s' or find_in_set('%s' , ancestors ) )`, deptAlias, userInfo.DeptID, userInfo.DeptID)
conditions = append(conditions, sql)
@@ -220,7 +225,7 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string)
if roledatascope.SELF == dataScope {
// 数据权限为仅本人且没有userAlias别名不查询任何数据
if userAlias == "" {
sql := fmt.Sprintf(`%s.dept_id = '0'`, deptAlias)
sql := fmt.Sprintf(`%s.parent_id = '0'`, deptAlias)
conditions = append(conditions, sql)
} else {
sql := fmt.Sprintf(`%s.user_id = '%s'`, userAlias, userInfo.UserID)

View File

@@ -48,7 +48,14 @@ func ParseDateToStr(date any, formatStr string) string {
if v == 0 {
return ""
}
t = time.UnixMilli(v)
if v > 9999999999 {
t = time.UnixMilli(v)
} else if v > 999999999 {
t = time.Unix(v, 0)
} else {
logger.Infof("utils ParseDateToStr err %v", "Invalid timestamp")
return ""
}
case string:
parsedTime, err := time.Parse(formatStr, v)
if err != nil {

View File

@@ -172,10 +172,10 @@ func Color(colorStr string) *color.RGBA {
}
}
// ConvertIPMask 转换IP网络地址掩码 24 -> 255.255.255.0
// ConvertIPMask 转换IP网络地址掩码 24->"255.255.255.0" 20->"255.255.240.0"
func ConvertIPMask(bits int64) string {
if bits < 0 || bits > 32 {
return "Invalid Mask Bits"
return "255.255.255.255"
}
// 构建一个32位的uint32类型掩码指定前bits位为1其余为0

View File

@@ -66,12 +66,12 @@ func SetFieldValue(obj any, fieldName string, value any) {
}
fieldValue.SetFloat(floatValue)
case reflect.Struct:
fmt.Printf("%s 时间解析 %s %v \n", fieldName, fieldValue.Type(), value)
fmt.Printf("%s time resolution %s %v \n", fieldName, fieldValue.Type(), value)
if fieldValue.Type() == reflect.TypeOf(time.Time{}) && value != nil {
// 解析 value 并转换为 time.Time 类型
parsedTime, err := time.Parse("2006-01-02 15:04:05 +0800 CST", fmt.Sprintf("%v", value))
if err != nil {
fmt.Println("时间解析出错:", err)
fmt.Println("Time resolution error:", err)
} else {
// 设置字段的值
fieldValue.Set(reflect.ValueOf(parsedTime))

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"strings"
"be.ems/src/framework/config"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd"
"be.ems/src/framework/utils/parse"
@@ -23,35 +22,31 @@ type FileListRow struct {
}
// 文件列表
// neIp 网元IP空字符串为本地
// search 文件名后模糊*
//
// return 目录大小,行记录,异常
func FileList(path, neIp, search string) (string, []FileListRow, error) {
func FileList(sshClient *ConnSSH, path, search string) (string, []FileListRow, error) {
totalSize := ""
var rows []FileListRow
rowStr := ""
// 发送命令
searchStr := ""
searchStr := "*"
if search != "" {
searchStr = search + "*"
searchStr = search + searchStr
}
pathStr := fmt.Sprintf("cd %s \n", path)
cmdStr := fmt.Sprintf("ls -lht --time-style=+%%s %s \n", searchStr)
cmdStr := fmt.Sprintf("cd %s && ls -lthd --time-style=+%%s %s", path, searchStr)
// 是否远程读取
if neIp != "" {
usernameNe := config.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neIp)
resultStr, err := cmd.ExecWithCheck("ssh", sshHost, pathStr, cmdStr)
// 是否远程客户端读取
if sshClient == nil {
resultStr, err := cmd.Execf(cmdStr)
if err != nil {
logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error())
return totalSize, rows, err
}
rowStr = resultStr
} else {
resultStr, err := cmd.Execf(pathStr, cmdStr)
resultStr, err := sshClient.RunCMD(cmdStr)
if err != nil {
logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error())
return totalSize, rows, err

View File

@@ -1,55 +0,0 @@
package ssh
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"time"
"be.ems/src/framework/config"
"be.ems/src/framework/logger"
)
// 网元NE 文件复制到远程文件
func FileSCPLocalToNe(neIp, localPath, nePath string) error {
usernameNe := config.Get("ne.user").(string)
// scp /path/to/local/file.txt user@remote-server:/path/to/remote/directory/
neDir := fmt.Sprintf("%s@%s:%s", usernameNe, neIp, nePath)
cmd := exec.Command("scp", "-r", localPath, neDir)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("FileSCPLocalToNe %s => %s", output, err.Error())
return err
}
return nil
}
// 网元NE 远程文件复制到本地文件
func FileSCPNeToLocal(neIp, nePath, localPath string) error {
// 确保文件夹路径存在
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
logger.Errorf("FileSCPNeToLocal MkdirAll err %v", err)
return err
}
// 如果目标文件已经存在,先将目标文件重命名
if info, err := os.Stat(localPath); err == nil && !info.IsDir() {
ext := filepath.Ext(localPath)
name := localPath[0 : len(localPath)-len(ext)]
newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)
err := os.Rename(localPath, newName)
if err != nil {
return err
}
}
usernameNe := config.Get("ne.user").(string)
// scp user@remote-server:/path/to/remote/directory/ /path/to/local/file.txt
neDir := fmt.Sprintf("%s@%s:%s", usernameNe, neIp, nePath)
cmd := exec.Command("scp", "-r", neDir, localPath)
output, err := cmd.CombinedOutput()
if err != nil {
logger.Errorf("FileSCPNeToLocal %s => %s", output, err.Error())
return err
}
return nil
}

View File

@@ -0,0 +1,202 @@
package ssh
import (
"io"
"os"
"path/filepath"
"be.ems/src/framework/logger"
gosftp "github.com/pkg/sftp"
)
// SSHClientSFTP SSH客户端SFTP对象
type SSHClientSFTP struct {
Client *gosftp.Client
}
// Close 关闭会话
func (s *SSHClientSFTP) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// CopyDirRemoteToLocal 复制目录-远程到本地
func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error {
// 列出远程目录中的文件和子目录
remoteFiles, err := s.Client.ReadDir(remoteDir)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 创建本地目录
err = os.MkdirAll(localDir, 0775)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error())
return err
}
// 遍历远程文件和子目录并复制到本地
for _, remoteFile := range remoteFiles {
remotePath := filepath.Join(remoteDir, remoteFile.Name())
localPath := filepath.Join(localDir, remoteFile.Name())
if remoteFile.IsDir() {
// 如果是子目录,则递归复制子目录
err = s.CopyDirRemoteToLocal(remotePath, localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error())
continue
}
} else {
// 如果是文件,则复制文件内容
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error())
continue
}
defer remoteFile.Close()
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error())
continue
}
defer localFile.Close()
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error())
continue
}
}
}
return nil
}
// CopyDirRemoteToLocal 复制目录-本地到远程
func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error {
// 创建远程目录
err := s.Client.MkdirAll(remoteDir)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 遍历本地目录中的文件和子目录并复制到远程
err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 生成远程路径
remotePath := filepath.Join(remoteDir, localPath[len(localDir):])
if info.IsDir() {
// 如果是子目录,则创建远程目录
err := s.Client.MkdirAll(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error())
return nil
}
} else {
// 如果是文件,则复制文件内容
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error())
return nil
}
defer localFile.Close()
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error())
return nil
}
defer remoteFile.Close()
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error())
return nil
}
}
return nil
})
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-远程到本地
func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error {
// 打开远程文件
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
return err
}
// 如果目标文件已经存在,先将目标文件重命名
// if info, err := os.Stat(localPath); err == nil && !info.IsDir() {
// ext := filepath.Ext(localPath)
// name := localPath[0 : len(localPath)-len(ext)]
// newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)
// err := os.Rename(localPath, newName)
// if err != nil {
// return err
// }
// }
// 创建本地文件
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 复制文件内容
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-本地到远程
func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error {
// 打开本地文件
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 创建远程文件
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
// 复制文件内容
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error())
return err
}
return nil
}

View File

@@ -1,14 +1,10 @@
package ssh
import (
"bytes"
"fmt"
"io"
"os"
"os/user"
"path/filepath"
"strings"
"sync"
"time"
"be.ems/src/framework/logger"
@@ -89,24 +85,6 @@ func (c *ConnSSH) Close() {
}
}
// NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连
//
// ssh.ConnSSH{
// User: "user",
// Addr: "192.168.x.x",
// Port: body.Port,
// }
func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) {
c.Port = 22
c.AuthMode = "1"
privateKey, err := c.CurrentUserRsaKey(false)
if err != nil {
return nil, err
}
c.PrivateKey = privateKey
return c.NewClient()
}
// RunCMD 执行单次命令
func (c *ConnSSH) RunCMD(cmd string) (string, error) {
if c.Client == nil {
@@ -128,57 +106,6 @@ func (c *ConnSSH) RunCMD(cmd string) (string, error) {
return c.LastResult, err
}
// SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥
func (c *ConnSSH) SendToAuthorizedKeys() error {
publicKey, err := c.CurrentUserRsaKey(true)
if err != nil {
return err
}
authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey))
cmdStrArr := []string{
fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User),
}
_, err = c.RunCMD(strings.Join(cmdStrArr, " && "))
if err != nil {
logger.Errorf("SendAuthorizedKeys echo err %s", err.Error())
return err
}
return nil
}
// CurrentUserRsaKey 当前用户OMC使用的RSA私钥
// 默认读取私钥
// ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
// ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub
func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) {
usr, err := user.Current()
if err != nil {
logger.Errorf("CurrentUserRsaKey get => %s", err.Error())
return "", err
}
// 是否存在私钥并创建
keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir)
if _, err := os.Stat(keyPath); err != nil {
if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil {
logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error())
}
}
// 读取用户默认的文件
if publicKey {
keyPath = keyPath + ".pub"
}
key, err := os.ReadFile(keyPath)
if err != nil {
logger.Errorf("CurrentUserRsaKey [%s] read => %s", usr.Username, err.Error())
return "", fmt.Errorf("read file %s fail", keyPath)
}
return string(key), nil
}
// NewClientSession 创建SSH客户端会话对象
func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) {
sshSession, err := c.Client.NewSession()
@@ -216,69 +143,6 @@ func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) {
}, nil
}
// SSHClientSession SSH客户端会话对象
type SSHClientSession struct {
Stdin io.WriteCloser
Stdout *singleWriter
Session *gossh.Session
}
// Close 关闭会话
func (s *SSHClientSession) Close() {
if s.Stdin != nil {
s.Stdin.Close()
}
if s.Stdout != nil {
s.Stdout = nil
}
if s.Session != nil {
s.Session.Close()
}
}
// Write 写入命令 回车(\n)才会执行
func (s *SSHClientSession) Write(cmd string) (int, error) {
if s.Stdin == nil {
return 0, fmt.Errorf("ssh client session is nil to content write failed")
}
return s.Stdin.Write([]byte(cmd))
}
// Read 读取结果
func (s *SSHClientSession) Read() []byte {
if s.Stdout == nil {
return []byte{}
}
bs := s.Stdout.Bytes()
if len(bs) > 0 {
s.Stdout.Reset()
return bs
}
return []byte{}
}
// singleWriter SSH客户端会话消息
type singleWriter struct {
b bytes.Buffer
mu sync.Mutex
}
func (w *singleWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.b.Write(p)
}
func (w *singleWriter) Bytes() []byte {
w.mu.Lock()
defer w.mu.Unlock()
return w.b.Bytes()
}
func (w *singleWriter) Reset() {
w.mu.Lock()
defer w.mu.Unlock()
w.b.Reset()
}
// NewClientSFTP 创建SSH客户端SFTP对象
func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
sftpClient, err := gosftp.NewClient(c.Client)
@@ -292,193 +156,70 @@ func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
}, nil
}
// SSHClientSFTP SSH客户端SFTP对象
type SSHClientSFTP struct {
Client *gosftp.Client
// NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连
//
// ssh.ConnSSH{
// User: "user",
// Addr: "192.168.x.x",
// Port: body.Port,
// }
func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) {
c.Port = 22
c.AuthMode = "1"
privateKey, err := c.CurrentUserRsaKey(false)
if err != nil {
return nil, err
}
c.PrivateKey = privateKey
return c.NewClient()
}
// Close 关闭会话
func (s *SSHClientSFTP) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// CopyDirRemoteToLocal 复制目录-远程到本地
func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error {
// 列出远程目录中的文件和子目录
remoteFiles, err := s.Client.ReadDir(remoteDir)
// CurrentUserRsaKey 当前用户OMC使用的RSA私钥
// 默认读取私钥
// ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
// ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub
func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) {
usr, err := user.Current()
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error())
return err
logger.Errorf("CurrentUserRsaKey get => %s", err.Error())
return "", err
}
// 创建本地目录
err = os.MkdirAll(localDir, 0775)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error())
return err
}
// 遍历远程文件和子目录并复制到本地
for _, remoteFile := range remoteFiles {
remotePath := filepath.Join(remoteDir, remoteFile.Name())
localPath := filepath.Join(localDir, remoteFile.Name())
if remoteFile.IsDir() {
// 如果是子目录,则递归复制子目录
err = s.CopyDirRemoteToLocal(remotePath, localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error())
continue
}
} else {
// 如果是文件,则复制文件内容
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error())
continue
}
defer remoteFile.Close()
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error())
continue
}
defer localFile.Close()
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error())
continue
}
// 是否存在私钥并创建
keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir)
if _, err := os.Stat(keyPath); err != nil {
if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil {
logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error())
}
}
return nil
// 读取用户默认的文件
if publicKey {
keyPath = keyPath + ".pub"
}
key, err := os.ReadFile(keyPath)
if err != nil {
logger.Errorf("CurrentUserRsaKey [%s] read => %s", usr.Username, err.Error())
return "", fmt.Errorf("read file %s fail", keyPath)
}
return string(key), nil
}
// CopyDirRemoteToLocal 复制目录-本地到远程
func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error {
// 创建远程目录
err := s.Client.MkdirAll(remoteDir)
// SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥
func (c *ConnSSH) SendToAuthorizedKeys() error {
publicKey, err := c.CurrentUserRsaKey(true)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error())
return err
}
// 遍历本地目录中的文件和子目录并复制到远程
err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 生成远程路径
remotePath := filepath.Join(remoteDir, localPath[len(localDir):])
if info.IsDir() {
// 如果是子目录,则创建远程目录
err := s.Client.MkdirAll(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error())
return nil
}
} else {
// 如果是文件,则复制文件内容
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error())
return nil
}
defer localFile.Close()
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error())
return nil
}
defer remoteFile.Close()
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error())
return nil
}
}
return nil
})
authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey))
cmdStrArr := []string{
fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User),
fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User),
}
_, err = c.RunCMD(strings.Join(cmdStrArr, " && "))
if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-远程到本地
func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error {
// 打开远程文件
remoteFile, err := s.Client.Open(remotePath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil {
return err
}
// 如果目标文件已经存在,先将目标文件重命名
// if info, err := os.Stat(localPath); err == nil && !info.IsDir() {
// ext := filepath.Ext(localPath)
// name := localPath[0 : len(localPath)-len(ext)]
// newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext)
// err := os.Rename(localPath, newName)
// if err != nil {
// return err
// }
// }
// 创建本地文件
localFile, err := os.Create(localPath)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 复制文件内容
_, err = io.Copy(localFile, remoteFile)
if err != nil {
logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error())
return err
}
return nil
}
// CopyDirRemoteToLocal 复制文件-本地到远程
func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error {
// 打开本地文件
localFile, err := os.Open(localPath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error())
return err
}
defer localFile.Close()
// 创建远程文件
remoteFile, err := s.Client.Create(remotePath)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error())
return err
}
defer remoteFile.Close()
// 复制文件内容
_, err = io.Copy(remoteFile, localFile)
if err != nil {
logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error())
logger.Errorf("SendAuthorizedKeys echo err %s", err.Error())
return err
}
return nil

View File

@@ -0,0 +1,73 @@
package ssh
import (
"bytes"
"fmt"
"io"
"sync"
gossh "golang.org/x/crypto/ssh"
)
// SSHClientSession SSH客户端会话对象
type SSHClientSession struct {
Stdin io.WriteCloser
Stdout *singleWriter
Session *gossh.Session
}
// Close 关闭会话
func (s *SSHClientSession) Close() {
if s.Stdin != nil {
s.Stdin.Close()
}
if s.Stdout != nil {
s.Stdout = nil
}
if s.Session != nil {
s.Session.Close()
}
}
// Write 写入命令 回车(\n)才会执行
func (s *SSHClientSession) Write(cmd string) (int, error) {
if s.Stdin == nil {
return 0, fmt.Errorf("ssh client session is nil to content write failed")
}
return s.Stdin.Write([]byte(cmd))
}
// Read 读取结果
func (s *SSHClientSession) Read() []byte {
if s.Stdout == nil {
return []byte{}
}
bs := s.Stdout.Bytes()
if len(bs) > 0 {
s.Stdout.Reset()
return bs
}
return []byte{}
}
// singleWriter SSH客户端会话消息
type singleWriter struct {
b bytes.Buffer
mu sync.Mutex
}
func (w *singleWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.b.Write(p)
}
func (w *singleWriter) Bytes() []byte {
w.mu.Lock()
defer w.mu.Unlock()
return w.b.Bytes()
}
func (w *singleWriter) Reset() {
w.mu.Lock()
defer w.mu.Unlock()
w.b.Reset()
}

View File

@@ -0,0 +1,77 @@
package telnet
import (
"fmt"
"strings"
)
// ConvertToStr 转换为string
func ConvertToStr(telnetClient *ConnTelnet, cmd string) (string, error) {
output, err := telnetClient.RunCMD(cmd)
if err != nil {
return "", err
}
str := strings.ToLower(output)
// 截断
index := strings.Index(str, "\n")
if index != -1 {
str = str[:index]
}
// 命令成功
if strings.Contains(str, "ok") || strings.Contains(str, "success") {
return str, nil
}
return "", fmt.Errorf(str)
}
// ConvertToMap 转换为map
func ConvertToMap(telnetClient *ConnTelnet, cmd string) (map[string]string, error) {
output, err := telnetClient.RunCMD(cmd)
if err != nil {
return nil, err
}
// 无数据
if strings.HasPrefix(output, "No ") {
// 截断
index := strings.Index(output, "\n")
if index != -1 {
output = output[:index]
}
return nil, fmt.Errorf(output)
}
// 初始化一个map用于存储拆分后的键值对
m := make(map[string]string)
var items []string
if strings.Contains(output, "\r\n") {
// 按照分隔符"\r\n"进行拆分
items = strings.Split(output, "\r\n")
} else if strings.Contains(output, "\n") {
// 按照分隔符"\n"进行拆分
items = strings.Split(output, "\n")
}
// 遍历拆分后的结果
for _, item := range items {
var pair []string
if strings.Contains(item, "=") {
// 按照分隔符"="进行拆分键值对
pair = strings.SplitN(item, "=", 2)
} else if strings.Contains(item, ":") {
// 按照分隔符":"进行拆分键值对
pair = strings.SplitN(item, ":", 2)
}
if len(pair) == 2 {
// 将键值对存入map中
m[pair[0]] = pair[1]
}
}
return m, err
}

View File

@@ -50,11 +50,11 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) {
// fmt.Fprintln(client, c.User)
// fmt.Fprintln(client, c.Password)
// 需要确保接收方理解并正确处理发送窗口大小设置命令
client.Write([]byte{255, 251, 31}) // 发送窗口大小选项
client.Write([]byte{255, 250, 31, 0, 128, 0, 120, 255, 240}) // 发送窗口行和列的大小
c.Client = &client
// 调整窗口大小 (120 列 x 128 行)
requestPty(c.Client, 120, 128)
// 排空连接登录的信息
c.RunCMD("")
return c, nil
@@ -73,8 +73,6 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
return "", fmt.Errorf("telnet client not connected")
}
conn := *c.Client
var buf bytes.Buffer
tmp := make([]byte, 1024)
// 写入命令
if cmd != "" {
@@ -83,22 +81,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
}
}
// 读取命令消息
var buf bytes.Buffer
tmp := make([]byte, 1024)
for {
// 设置读取超时时间为1000毫秒
conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
// 读取命令消息
n, err := conn.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
if n == 0 || err != nil {
tmp = nil
break
}
if n == 0 {
tmpStr := string(tmp[:n])
buf.WriteString(tmpStr)
// 是否有终止符
if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") {
tmp = nil
break
}
buf.Write(tmp[:n])
}
defer buf.Reset()
@@ -107,77 +107,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
}
// NewClient 创建Telnet客户端会话对象
func (c *ConnTelnet) NewClientSession(cols, rows uint8) (*TelnetClientSession, error) {
func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) {
if c.Client == nil {
return nil, fmt.Errorf("telnet client not connected")
}
requestPty(c.Client, cols, rows)
return &TelnetClientSession{
Client: *c.Client,
}, nil
}
// TelnetClientSession Telnet客户端会话对象
type TelnetClientSession struct {
Client net.Conn
}
// Close 关闭会话
func (s *TelnetClientSession) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// Write 写入命令 不带回车(\n)也会执行根据客户端情况
func (s *TelnetClientSession) Write(cmd string) (int, error) {
if s.Client == nil {
return 0, fmt.Errorf("client is nil to content write failed")
}
return s.Client.Write([]byte(cmd))
}
// Read 读取结果 等待一会才有结果
func (s *TelnetClientSession) Read() []byte {
if s.Client == nil {
return []byte{}
}
buf := make([]byte, 1024)
// 设置读取超时时间为100毫秒
s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
_, err := s.Client.Read(buf)
if err != nil {
return []byte{}
}
return buf
}
// CombinedOutput 发送命令带结果返回
func (s *TelnetClientSession) CombinedOutput(cmd string) (string, error) {
n, err := s.Write(cmd)
if n == 0 || err != nil {
return "", err
}
var buf bytes.Buffer
tmp := make([]byte, 1024)
for {
// 设置读取超时时间为1000毫秒
s.Client.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
n, err := s.Client.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
defer buf.Reset()
return buf.String(), nil
// requestPty 调整终端窗口大小
func requestPty(client *net.Conn, cols, rows int) error {
if client == nil {
return fmt.Errorf("telnet client not connected")
}
conn := *client
// 需要确保接收方理解并正确处理发送窗口大小设置命令
conn.Write([]byte{255, 251, 31})
conn.Write([]byte{255, 250, 31, byte(cols >> 8), byte(cols & 0xFF), byte(rows >> 8), byte(rows & 0xFF), 255, 240})
return nil
}

View File

@@ -0,0 +1,74 @@
package telnet
import (
"bytes"
"fmt"
"net"
"time"
)
// TelnetClientSession Telnet客户端会话对象
type TelnetClientSession struct {
Client net.Conn
}
// Close 关闭会话
func (s *TelnetClientSession) Close() {
if s.Client != nil {
s.Client.Close()
}
}
// Write 写入命令 不带回车(\n)也会执行根据客户端情况
func (s *TelnetClientSession) Write(cmd string) (int, error) {
if s.Client == nil {
return 0, fmt.Errorf("client is nil to content write failed")
}
return s.Client.Write([]byte(cmd))
}
// Read 读取结果 等待一会才有结果
func (s *TelnetClientSession) Read() []byte {
if s.Client == nil {
return []byte{}
}
buf := make([]byte, 1024)
// 设置读取超时时间为100毫秒
s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
_, err := s.Client.Read(buf)
if err != nil {
return []byte{}
}
return buf
}
// CombinedOutput 发送命令带结果返回
func (s *TelnetClientSession) CombinedOutput(cmd string) (string, error) {
n, err := s.Write(cmd)
if n == 0 || err != nil {
return "", err
}
var buf bytes.Buffer
tmp := make([]byte, 1024)
for {
// 设置读取超时时间为1000毫秒
s.Client.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
n, err := s.Client.Read(tmp)
if err != nil {
// 判断是否是超时错误
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break
}
if n == 0 {
break
}
buf.Write(tmp[:n])
}
defer buf.Reset()
return buf.String(), nil
}

View File

@@ -1,9 +1,9 @@
package controller
import (
"be.ems/lib/core/utils/date"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"

View File

@@ -1,22 +1,30 @@
package controller
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
sysService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// 实例化控制层 AMFController 结构体
var NewAMFController = &AMFController{
neInfoService: neService.NewNeInfoImpl,
ueEventService: neDataService.NewUEEventImpl,
ueEventService: neDataService.NewUEEventAMFImpl,
}
// 网元AMF
@@ -25,8 +33,8 @@ var NewAMFController = &AMFController{
type AMFController struct {
// 网元信息服务
neInfoService neService.INeInfo
// CDR会话事件服务
ueEventService neDataService.IUEEvent
// UE会话事件服务
ueEventService neDataService.IUEEventAMF
}
// UE会话列表
@@ -34,19 +42,19 @@ type AMFController struct {
// GET /ue/list
func (s *AMFController) UEList(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys model.UEEventQuery
var querys model.UEEventAMFQuery
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
}
querys.RmUID = neInfo.RmUID
// 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
// }
// querys.RmUID = neInfo.RmUID
// 查询数据
data := s.ueEventService.SelectPage(querys)
@@ -78,3 +86,125 @@ func (s *AMFController) UERemove(c *gin.Context) {
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg))
}
// UE会话列表导出
//
// POST /ue/export
func (s *AMFController) UEExport(c *gin.Context) {
language := ctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.UEEventAMFQuery
if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
data := s.ueEventService.SelectPage(querys)
if parse.Number(data["total"]) == 0 {
// 导出数据记录为空
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
rows := data["rows"].([]model.UEEventAMF)
// 导出文件名称
fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "IMSI",
"C1": "Event Type",
"D1": "Result",
"E1": "Time",
}
// 读取字典数据 UE 事件类型
dictUEEventType := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_type")
// 读取字典数据 UE 事件认证代码类型
dictUEAauthCode := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_auth_code")
// 读取字典数据 UE 事件CM状态
dictUEEventCmState := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_cm_state")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var eventJSON map[string]interface{}
err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON)
if err != nil {
logger.Warnf("UEExport Error parsing JSON: %s", err.Error())
continue
}
// 取IMSI
imsi := ""
if v, ok := eventJSON["imsi"]; ok && v != nil {
imsi = v.(string)
}
// 取类型
eventType := ""
for _, v := range dictUEEventType {
if row.EventType == v.DictValue {
eventType = i18n.TKey(language, v.DictLabel)
break
}
}
// 取结果
eventResult := ""
// 取时间
timeStr := ""
if row.EventType == "auth-result" {
if v, ok := eventJSON["authTime"]; ok && v != nil {
timeStr = v.(string)
}
if v, ok := eventJSON["authCode"]; ok && v != nil {
eventResult = v.(string)
for _, v := range dictUEAauthCode {
if eventResult == v.DictValue {
eventResult = i18n.TKey(language, v.DictLabel)
break
}
}
}
}
if row.EventType == "detach" {
if v, ok := eventJSON["detachTime"]; ok && v != nil {
timeStr = v.(string)
}
eventResult = "Success"
}
if row.EventType == "cm-state" {
if v, ok := eventJSON["changeTime"]; ok && v != nil {
timeStr = v.(string)
}
if v, ok := eventJSON["status"]; ok && v != nil {
eventResult = v.(string)
for _, v := range dictUEEventCmState {
if eventResult == v.DictValue {
eventResult = i18n.TKey(language, v.DictLabel)
break
}
}
}
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: imsi,
"C" + idx: eventType,
"D" + idx: eventResult,
"E" + idx: timeStr,
})
}
// 导出数据表格
saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "")
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -1,22 +1,31 @@
package controller
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
sysService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// 实例化控制层 IMSController 结构体
var NewIMSController = &IMSController{
neInfoService: neService.NewNeInfoImpl,
cdrEventService: neDataService.NewCDREventImpl,
cdrEventService: neDataService.NewCDREventIMSImpl,
}
// 网元IMS
@@ -26,7 +35,7 @@ type IMSController struct {
// 网元信息服务
neInfoService neService.INeInfo
// CDR会话事件服务
cdrEventService neDataService.ICDREvent
cdrEventService neDataService.ICDREventIMS
}
// CDR会话列表
@@ -34,19 +43,19 @@ type IMSController struct {
// GET /cdr/list
func (s *IMSController) CDRList(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys model.CDREventQuery
var querys model.CDREventIMSQuery
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
}
querys.RmUID = neInfo.RmUID
// 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
// }
// querys.RmUID = neInfo.RmUID
// 查询数据
data := s.cdrEventService.SelectPage(querys)
@@ -78,3 +87,126 @@ func (s *IMSController) CDRRemove(c *gin.Context) {
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
func (s *IMSController) CDRExport(c *gin.Context) {
language := ctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.CDREventIMSQuery
if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
data := s.cdrEventService.SelectPage(querys)
if parse.Number(data["total"]) == 0 {
// 导出数据记录为空
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
rows := data["rows"].([]model.CDREventIMS)
// 导出文件名称
fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "Record Behavior",
"C1": "Type",
"D1": "Called",
"E1": "Caller",
"F1": "Duration",
"G1": "Result",
"H1": "Time",
}
// 读取字典数据 CDR SIP响应代码类别类型
dictCDRSipCode := sysService.NewSysDictDataImpl.SelectDictDataByType("cdr_sip_code")
// 读取字典数据 CDR 呼叫类型
dictCDRCallType := sysService.NewSysDictDataImpl.SelectDictDataByType("cdr_call_type")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 记录类型
recordType := ""
if v, ok := cdrJSON["recordType"]; ok && v != nil {
recordType = v.(string)
}
// 被叫
called := ""
if v, ok := cdrJSON["calledParty"]; ok && v != nil {
called = v.(string)
}
// 主叫
caller := ""
if v, ok := cdrJSON["callerParty"]; ok && v != nil {
caller = v.(string)
}
// 呼叫类型
callType := "sms"
callTypeLable := "SMS"
if v, ok := cdrJSON["callType"]; ok && v != nil {
callType = v.(string)
for _, v := range dictCDRCallType {
if callType == v.DictValue {
callTypeLable = i18n.TKey(language, v.DictLabel)
break
}
}
}
// 时长
duration := "-"
if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" {
duration = fmt.Sprint(parse.Number(v))
}
// 呼叫结果 非短信都有code作为结果 sms短信都ok
callResult := "Success"
if v, ok := cdrJSON["cause"]; ok && v != nil && callType != "sms" {
cause := fmt.Sprint(v)
for _, v := range dictCDRSipCode {
if cause == v.DictValue {
callResult = i18n.TKey(language, v.DictLabel)
break
}
}
}
// 取时间
timeStr := ""
if v, ok := cdrJSON["releaseTime"]; ok && v != nil {
releaseTime := parse.Number(v)
timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ)
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: recordType,
"C" + idx: callTypeLable,
"D" + idx: called,
"E" + idx: caller,
"F" + idx: duration,
"G" + idx: callResult,
"H" + idx: timeStr,
})
}
// 导出数据表格
saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "")
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -0,0 +1,200 @@
package controller
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
sysService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// 实例化控制层 MMEController 结构体
var NewMMEController = &MMEController{
neInfoService: neService.NewNeInfoImpl,
ueEventService: neDataService.NewUEEventMMEImpl,
}
// 网元MME
//
// PATH /mme
type MMEController struct {
// 网元信息服务
neInfoService neService.INeInfo
// UE会话事件服务
ueEventService neDataService.IUEEventMME
}
// UE会话列表
//
// GET /ue/list
func (s *MMEController) UEList(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys model.UEEventMMEQuery
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
// }
// querys.RmUID = neInfo.RmUID
// 查询数据
data := s.ueEventService.SelectPage(querys)
c.JSON(200, result.Ok(data))
}
// UE会话删除
//
// DELETE /ue/:ueIds
func (s *MMEController) UERemove(c *gin.Context) {
language := ctx.AcceptLanguage(c)
ueIds := c.Param("ueIds")
if ueIds == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 处理字符转id数组后去重
ids := strings.Split(ueIds, ",")
uniqueIDs := parse.RemoveDuplicates(ids)
if len(uniqueIDs) <= 0 {
c.JSON(200, result.Err(nil))
return
}
rows, err := s.ueEventService.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))
}
// UE会话列表导出
//
// POST /ue/export
func (s *MMEController) UEExport(c *gin.Context) {
language := ctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.UEEventMMEQuery
if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
data := s.ueEventService.SelectPage(querys)
if parse.Number(data["total"]) == 0 {
// 导出数据记录为空
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
rows := data["rows"].([]model.UEEventMME)
// 导出文件名称
fileName := fmt.Sprintf("mme_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "IMSI",
"C1": "Event Type",
"D1": "Result",
"E1": "Time",
}
// 读取字典数据 UE 事件类型
dictUEEventType := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_type")
// 读取字典数据 UE 事件认证代码类型
dictUEAauthCode := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_auth_code")
// 读取字典数据 UE 事件CM状态
dictUEEventCmState := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_cm_state")
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var eventJSON map[string]interface{}
err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON)
if err != nil {
logger.Warnf("UEExport Error parsing JSON: %s", err.Error())
continue
}
// 取IMSI
imsi := ""
if v, ok := eventJSON["imsi"]; ok && v != nil {
imsi = v.(string)
}
// 取类型
eventType := row.EventType
for _, v := range dictUEEventType {
if row.EventType == v.DictValue {
eventType = i18n.TKey(language, v.DictLabel)
break
}
}
// 取结果
eventResult := ""
if v, ok := eventJSON["result"]; ok && v != nil {
eventResult = v.(string)
if row.EventType == "auth-result" {
for _, v := range dictUEAauthCode {
if eventResult == v.DictValue {
eventResult = i18n.TKey(language, v.DictLabel)
break
}
}
}
if row.EventType == "cm-state" {
for _, v := range dictUEEventCmState {
if eventResult == v.DictValue {
eventResult = i18n.TKey(language, v.DictLabel)
break
}
}
}
}
// 取时间
timeStr := ""
if v, ok := eventJSON["timestamp"]; ok && v != nil {
rowTime := parse.Number(v)
timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ)
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: imsi,
"C" + idx: eventType,
"D" + idx: eventResult,
"E" + idx: timeStr,
})
}
// 导出数据表格
saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "")
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -1,32 +1,39 @@
package controller
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// 实例化控制层 IMSController 结构体
// 实例化控制层 SMFController 结构体
var NewSMFController = &SMFController{
neInfoService: neService.NewNeInfoImpl,
cdrEventService: neDataService.NewSMFCDREventImpl,
cdrEventService: neDataService.NewCDREventSMFImpl,
}
// 网元IMS
// 网元SMF
//
// PATH /ims
// PATH /smf
type SMFController struct {
// 网元信息服务
neInfoService neService.INeInfo
// SMF CDR会话事件服务
cdrEventService neDataService.SMFCDREvent
// CDR会话事件服务
cdrEventService neDataService.ICDREventSMF
}
// CDR会话列表
@@ -34,19 +41,19 @@ type SMFController struct {
// GET /cdr/list
func (s *SMFController) CDRList(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys model.SMFCDREventQuery
var querys model.CDREventSMFQuery
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
}
querys.RmUID = neInfo.RmUID
// 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
// }
// querys.RmUID = neInfo.RmUID
// 查询数据
data := s.cdrEventService.SelectPage(querys)
@@ -78,3 +85,174 @@ func (s *SMFController) CDRRemove(c *gin.Context) {
msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg))
}
// CDR会话列表导出
//
// POST /cdr/export
func (s *SMFController) CDRExport(c *gin.Context) {
language := ctx.AcceptLanguage(c)
// 查询结果,根据查询条件结果,单页最大值限制
var querys model.CDREventSMFQuery
if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 限制导出数据集
if querys.PageSize > 10000 {
querys.PageSize = 10000
}
data := s.cdrEventService.SelectPage(querys)
if parse.Number(data["total"]) == 0 {
// 导出数据记录为空
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
return
}
rows := data["rows"].([]model.CDREventSMF)
// 导出文件名称
fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli())
// 第一行表头标题
headerCells := map[string]string{
"A1": "ID",
"B1": "Charging ID",
"C1": "Subscriber ID Data",
"D1": "Subscriber ID Type",
"E1": "Data Volume Uplink",
"F1": "Data Volume Downlink",
"G1": "Data Total Volume",
"H1": "Duration",
"I1": "Invocation Time",
"J1": "PDU Session Charging Information",
}
// 从第二行开始的数据
dataCells := make([]map[string]any, 0)
for i, row := range rows {
idx := strconv.Itoa(i + 2)
// 解析 JSON 字符串为 map
var cdrJSON map[string]interface{}
err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON)
if err != nil {
logger.Warnf("CDRExport Error parsing JSON: %s", err.Error())
continue
}
// 计费ID
chargingID := ""
if v, ok := cdrJSON["chargingID"]; ok && v != nil {
chargingID = fmt.Sprint(parse.Number(v))
}
// 订阅 ID 类型
subscriptionIDType := "-"
// 订阅 ID 数据
subscriptionIDData := "-"
if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil {
if sub, subOk := v.(map[string]any); subOk && sub != nil {
subscriptionIDType = sub["subscriptionIDType"].(string)
subscriptionIDData = sub["subscriptionIDData"].(string)
}
}
// 数据量上行链路
dataVolumeUplink := []string{}
// 数据量下行链路
dataVolumeDownlink := []string{}
// 数据总量
dataTotalVolume := []string{}
if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil {
usageList := v.([]any)
if len(usageList) > 0 {
for _, used := range usageList {
usedUnit := used.(map[string]any)
usedUnitList := usedUnit["usedUnitContainer"].([]any)
if len(usedUnitList) > 0 {
for _, data := range usedUnitList {
udata := data.(map[string]any)
if dup, dupOk := udata["dataVolumeUplink"]; dupOk {
dataVolumeUplink = append(dataVolumeUplink, fmt.Sprint(parse.Number(dup)))
}
if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk {
dataVolumeDownlink = append(dataVolumeDownlink, fmt.Sprint(parse.Number(ddown)))
}
if dt, dtOk := udata["dataTotalVolume"]; dtOk {
dataTotalVolume = append(dataTotalVolume, fmt.Sprint(parse.Number(dt)))
}
}
}
}
}
}
// 时长
duration := "-"
if v, ok := cdrJSON["duration"]; ok && v != nil {
duration = fmt.Sprint(parse.Number(v))
}
// 调用时间
invocationTimestamp := ""
if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil {
invocationTimestamp = v.(string)
}
// 记录打开时间
pduSessionChargingInformation := ""
if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil {
pduInfo := v.(map[string]any)
User_Identifier := ""
if v, ok := pduInfo["userIdentifier"]; ok && v != nil {
User_Identifier = v.(string)
}
SSC_Mode := ""
if v, ok := pduInfo["sSCMode"]; ok && v != nil {
SSC_Mode = v.(string)
}
RAT_Type := ""
if v, ok := pduInfo["rATType"]; ok && v != nil {
RAT_Type = v.(string)
}
DNN_ID := ""
if v, ok := pduInfo["dNNID"]; ok && v != nil {
DNN_ID = v.(string)
}
PDU_Type := ""
if v, ok := pduInfo["pDUType"]; ok && v != nil {
PDU_Type = v.(string)
}
PDU_IPv4 := ""
PDU_IPv6 := ""
if v, ok := pduInfo["pDUAddress"]; ok && v != nil {
pDUAddress := v.(map[string]any)
if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil {
PDU_IPv4 = addr.(string)
}
if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil {
PDU_IPv6 = addr.(string)
}
}
pduSessionChargingInformation = fmt.Sprintf(`User Identifier: %s
SSC Mode: %s RAT Type: %s DNN ID: %s
PDU Type: %s
PDU IPv4 Address: %s
PDU IPv6 Addres Swith Prefix: %s`, User_Identifier, SSC_Mode, RAT_Type, DNN_ID, PDU_Type, PDU_IPv4, PDU_IPv6)
}
dataCells = append(dataCells, map[string]any{
"A" + idx: row.ID,
"B" + idx: chargingID,
"C" + idx: subscriptionIDData,
"D" + idx: subscriptionIDType,
"E" + idx: strings.Join(dataVolumeUplink, ","),
"F" + idx: strings.Join(dataVolumeDownlink, ","),
"G" + idx: strings.Join(dataTotalVolume, ","),
"H" + idx: duration,
"I" + idx: invocationTimestamp,
"J" + idx: pduSessionChargingInformation,
})
}
// 导出数据表格
saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "")
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.FileAttachment(saveFilePath, fileName)
}

View File

@@ -2,18 +2,19 @@ package controller
import (
"fmt"
"path/filepath"
"strings"
"time"
mmlclient "be.ems/lib/core/mml_client"
"be.ems/src/framework/constants/uploadsubpath"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/ssh"
"be.ems/src/framework/utils/telnet"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
@@ -21,21 +22,21 @@ import (
// 实例化控制层 UDMAuthController 结构体
var NewUDMAuth = &UDMAuthController{
udmAuthService: neService.NewUDMAuthImpl,
udmAuthService: neDataService.NewUDMAuthImpl,
neInfoService: neService.NewNeInfoImpl,
}
// UDM鉴权用户请求
// UDM鉴权用户
//
// PATH /udm/auth
type UDMAuthController struct {
// UDM鉴权信息服务
udmAuthService neService.IUDMAuth
udmAuthService neDataService.IUDMAuth
// 网元信息服务
neInfoService neService.INeInfo
}
// UDM鉴权用户-获取全部保存数据
// UDM鉴权用户重载数据
//
// POST /resetData/:neId
func (s *UDMAuthController) ResetData(c *gin.Context) {
@@ -47,21 +48,21 @@ func (s *UDMAuthController) ResetData(c *gin.Context) {
}
neId = ""
data := s.udmAuthService.Save(neId)
data := s.udmAuthService.ResetData(neId)
c.JSON(200, result.OkData(data))
}
// UDM鉴权用户
// UDM鉴权用户列表
//
// GET /list
func (s *UDMAuthController) List(c *gin.Context) {
querys := ctx.QueryMap(c)
querys["neId"] = ""
data := s.udmAuthService.Page(querys)
data := s.udmAuthService.SelectPage(querys)
c.JSON(200, result.Ok(data))
}
// UDM鉴权用户-信息
// UDM鉴权用户信息
//
// GET /:neId/:imsi
func (s *UDMAuthController) Info(c *gin.Context) {
@@ -80,10 +81,16 @@ func (s *UDMAuthController) Info(c *gin.Context) {
return
}
msg := fmt.Sprintf("dsp authdat:imsi=%s", imsi)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg)
cmd := fmt.Sprintf("dsp authdat:imsi=%s", imsi)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -94,31 +101,31 @@ func (s *UDMAuthController) Info(c *gin.Context) {
return
}
// 查询数据库是否存在并存入
neId = ""
var userInfo model.UDMAuth
list := s.udmAuthService.List(model.UDMAuth{NeID: neId, Imsi: imsi})
if len(list) > 0 {
userInfo = list[0]
// 返回查询的用户信息
userInfo.Amf = data["amf"]
userInfo.AlgoIndex = data["algo"]
userInfo.Opc = data["opc"]
userInfo.Ki = data["ki"]
} else {
userInfo := model.UDMAuth{
Imsi: imsi,
Amf: data["amf"],
AlgoIndex: data["algo"],
Opc: data["opc"],
Ki: data["ki"],
}
s.udmAuthService.Insert(neId, userInfo)
u := model.UDMAuth{
IMSI: imsi,
Amf: data["amf"],
Status: "1",
Ki: data["ki"],
AlgoIndex: data["algo"],
Opc: data["opc"],
NeId: neId,
}
c.JSON(200, result.OkData(userInfo))
// 查询imsi存在赋予id用于更新
list := s.udmAuthService.SelectList(u)
if len(list) > 0 {
item := list[0]
if item.ID != "" {
u.ID = item.ID
}
}
go s.udmAuthService.Insert(neId, u)
c.JSON(200, result.OkData(u))
}
// UDM鉴权用户-增加
// UDM鉴权用户新增
//
// POST /:neId
func (s *UDMAuthController) Add(c *gin.Context) {
@@ -131,7 +138,7 @@ func (s *UDMAuthController) Add(c *gin.Context) {
var body model.UDMAuth
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.Imsi == "" {
if err != nil || body.IMSI == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -143,10 +150,16 @@ func (s *UDMAuthController) Add(c *gin.Context) {
return
}
msg := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, body.Ki, body.Amf, body.AlgoIndex, body.Opc)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, body.Ki, body.Amf, body.AlgoIndex, body.Opc)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -155,12 +168,12 @@ func (s *UDMAuthController) Add(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmAuthService.Insert(neId, body)
go s.udmAuthService.Insert(neId, body)
}
c.JSON(200, result.OkData(data))
}
// UDM鉴权用户-批量添加
// UDM鉴权用户批量新增
//
// POST /:neId/:num
func (s *UDMAuthController) Adds(c *gin.Context) {
@@ -174,7 +187,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
var body model.UDMAuth
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.Imsi == "" {
if err != nil || body.IMSI == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -186,10 +199,16 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
return
}
msg := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -198,12 +217,12 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmAuthService.Inserts(neId, body, num)
go s.udmAuthService.LoadData(neId, body.IMSI, num)
}
c.JSON(200, result.OkData(data))
}
// UDM鉴权用户-修改
// UDM鉴权用户修改
//
// PUT /:neId
func (s *UDMAuthController) Edit(c *gin.Context) {
@@ -216,7 +235,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
var body model.UDMAuth
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.Imsi == "" {
if err != nil || body.IMSI == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -228,23 +247,29 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
return
}
msg := fmt.Sprintf("mod authdata:imsi=%s", body.Imsi)
// 修改的参数名称
if body.Ki != "" {
msg += fmt.Sprintf(",ki=%s", body.Ki)
}
if body.Amf != "" {
msg += fmt.Sprintf(",amf=%s", body.Amf)
}
if body.AlgoIndex != "" {
msg += fmt.Sprintf(",algo=%s", body.AlgoIndex)
}
if body.Opc != "" {
msg += fmt.Sprintf(",opc=%s", body.Opc)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("mod authdata:imsi=%s", body.IMSI)
// 修改的参数名称
if body.Ki != "" {
cmd += fmt.Sprintf(",ki=%s", body.Ki)
}
if body.Amf != "" {
cmd += fmt.Sprintf(",amf=%s", body.Amf)
}
if body.AlgoIndex != "" {
cmd += fmt.Sprintf(",algo=%s", body.AlgoIndex)
}
if body.Opc != "" {
cmd += fmt.Sprintf(",opc=%s", body.Opc)
}
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -253,12 +278,12 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmAuthService.Update(neId, body)
go s.udmAuthService.Insert(neId, body)
}
c.JSON(200, result.OkData(data))
}
// UDM鉴权用户-删除
// UDM鉴权用户删除
//
// DELETE /:neId/:imsi
func (s *UDMAuthController) Remove(c *gin.Context) {
@@ -285,27 +310,34 @@ func (s *UDMAuthController) Remove(c *gin.Context) {
return
}
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
resultData := map[string]string{}
for _, imsi := range uniqueIDs {
msg := fmt.Sprintf("del authdat:imsi=%s", imsi)
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("del authdat:imsi=%s", imsi)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[imsi] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmAuthService.Delete(neId, imsi)
resultData[imsi] = data
go s.udmAuthService.Delete(neId, imsi)
}
resultData[imsi] = data
}
c.JSON(200, result.OkData(resultData))
}
// UDM鉴权用户-批量删除
// UDM鉴权用户批量删除
//
// DELETE /:neId/:imsi/:num
func (s *UDMAuthController) Removes(c *gin.Context) {
@@ -325,10 +357,16 @@ func (s *UDMAuthController) Removes(c *gin.Context) {
return
}
msg := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -337,12 +375,12 @@ func (s *UDMAuthController) Removes(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmAuthService.Deletes(neId, imsi, num)
go s.udmAuthService.LoadData(neId, imsi, num)
}
c.JSON(200, result.OkData(data))
}
// UDM鉴权用户-导出
// UDM鉴权用户导出
//
// POST /export
func (s *UDMAuthController) Export(c *gin.Context) {
@@ -358,14 +396,14 @@ func (s *UDMAuthController) Export(c *gin.Context) {
}
if !(body.Type == "csv" || body.Type == "txt") {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errExportType")))
return
}
neId := ""
list := s.udmAuthService.List(model.UDMAuth{NeID: neId})
list := s.udmAuthService.SelectList(model.UDMAuth{NeId: neId})
// 文件名
fileName := fmt.Sprintf("OMC_AUTH_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type)
fileName := fmt.Sprintf("udm_auth_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type)
filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName)
if body.Type == "csv" {
@@ -373,7 +411,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
data := [][]string{}
data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"})
for _, v := range list {
data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc})
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc})
}
// 输出到文件
err := file.WriterFileCSV(data, filePath)
@@ -387,7 +425,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
// 转换数据
data := [][]string{}
for _, v := range list {
data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc})
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc})
}
// 输出到文件
err = file.WriterFileTXT(data, ",", filePath)
@@ -400,55 +438,68 @@ func (s *UDMAuthController) Export(c *gin.Context) {
c.FileAttachment(filePath, fileName)
}
// UDM鉴权用户-导入
// UDM鉴权用户导入
//
// POST /import
func (s *UDMAuthController) Import(c *gin.Context) {
language := ctx.AcceptLanguage(c)
neId := c.PostForm("neId")
if neId == "" {
var body struct {
NeId string `json:"neId" binding:"required"`
UploadPath string `json:"uploadPath" binding:"required"`
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
formFile, err := c.FormFile("file")
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 获取文件名
if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) {
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return
}
// 上传文件转存
upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
if neInfo.NeId != neId || neInfo.IP == "" {
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId)
if neInfo.NeId != body.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 本地文件
localPath := file.ParseUploadFilePath(upFilePath)
nePath := "/tmp" //config.Get("mml.upload").(string)
// 复制到远程
err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath)
// 网元主机的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()
fileName := localPath[strings.LastIndex(localPath, "/")+1:]
msg := fmt.Sprintf("import authdat:path=%s", fmt.Sprintf("%s/%s", nePath, fileName))
// 本地文件
localFilePath := file.ParseUploadFilePath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, result.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("import authdat:path=%s", neFilePath)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -456,15 +507,15 @@ func (s *UDMAuthController) Import(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
if strings.HasSuffix(fileName, ".csv") {
data := file.ReadFileCSV(localPath)
neId = ""
go s.udmAuthService.InsertCSV(neId, data)
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
neId := ""
go s.udmAuthService.InsertData(neId, "csv", data)
}
if strings.HasSuffix(fileName, ".txt") {
data := file.ReadFileTXT(",", localPath)
neId = ""
go s.udmAuthService.InsertTxt(neId, data)
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXT(",", localFilePath)
neId := ""
go s.udmAuthService.InsertData(neId, "txt", data)
}
}
c.JSON(200, result.OkMsg(data))

View File

@@ -2,19 +2,20 @@ package controller
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"time"
mmlclient "be.ems/lib/core/mml_client"
"be.ems/src/framework/constants/uploadsubpath"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/ssh"
"be.ems/src/framework/utils/telnet"
"be.ems/src/framework/vo/result"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
@@ -22,21 +23,21 @@ import (
// 实例化控制层 UDMSubController 结构体
var NewUDMSub = &UDMSubController{
udmSubService: neService.NewUDMSubImpl,
udmSubService: neDataService.NewUDMSubImpl,
neInfoService: neService.NewNeInfoImpl,
}
// UDM签约用户请求
// UDM签约用户
//
// PATH /udm/sub
type UDMSubController struct {
// UDM鉴权信息服务
udmSubService neService.IUDMSub
// UDM签约信息服务
udmSubService neDataService.IUDMSub
// 网元信息服务
neInfoService neService.INeInfo
}
// UDM签约用户-获取全部保存数据
// UDM签约用户重载数据
//
// POST /resetData/:neId
func (s *UDMSubController) ResetData(c *gin.Context) {
@@ -48,21 +49,21 @@ func (s *UDMSubController) ResetData(c *gin.Context) {
}
neId = ""
data := s.udmSubService.Save(neId)
data := s.udmSubService.ResetData(neId)
c.JSON(200, result.OkData(data))
}
// UDM签约用户
// UDM签约用户列表
//
// GET /list
func (s *UDMSubController) List(c *gin.Context) {
querys := ctx.QueryMap(c)
querys["neId"] = ""
data := s.udmSubService.Page(querys)
data := s.udmSubService.SelectPage(querys)
c.JSON(200, result.Ok(data))
}
// UDM签约用户-信息
// UDM签约用户信息
//
// GET /:neId/:imsi
func (s *UDMSubController) Info(c *gin.Context) {
@@ -81,10 +82,16 @@ func (s *UDMSubController) Info(c *gin.Context) {
return
}
msg := fmt.Sprintf("dsp udmuser:imsi=%s", imsi)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg)
cmd := fmt.Sprintf("dsp udmuser:imsi=%s", imsi)
data, err := telnet.ConvertToMap(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -103,8 +110,9 @@ func (s *UDMSubController) Info(c *gin.Context) {
if imsMsisdnLen != -1 {
msisdn = msisdn[:imsMsisdnLen]
}
userInfo := model.UDMSub{
Imsi: imsi,
neId = ""
u := model.UDMSub{
IMSI: imsi,
Msisdn: msisdn,
Ambr: data["AMBR"],
Arfb: data["AreaForbidden"],
@@ -114,35 +122,37 @@ func (s *UDMSubController) Info(c *gin.Context) {
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 {
userInfo.EpsDat = v
u.EpsDat = v
arr := strings.Split(v, ",")
userInfo.EpsFlag = arr[0]
userInfo.EpsOdb = arr[1]
userInfo.HplmnOdb = arr[2]
userInfo.Ard = arr[3]
userInfo.Epstpl = arr[4]
userInfo.ContextId = arr[5]
userInfo.ApnContext = arr[7]
userInfo.StaticIp = arr[8]
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]
}
// 查询数据库是否存在并存入更新
neId = ""
list := s.udmSubService.List(model.UDMSub{NeID: neId, Imsi: imsi})
// 查询imsi存在赋予id用于更新
list := s.udmSubService.SelectList(u)
if len(list) > 0 {
listItme := list[0]
userInfo.ID = listItme.ID
s.udmSubService.Update(neId, userInfo)
} else {
s.udmSubService.Insert(neId, userInfo)
item := list[0]
if item.ID != "" {
u.ID = item.ID
}
}
c.JSON(200, result.OkData(userInfo))
go s.udmSubService.Insert(neId, u)
c.JSON(200, result.OkData(u))
}
// UDM签约用户-增加
// UDM签约用户新增
//
// POST /:neId
func (s *UDMSubController) Add(c *gin.Context) {
@@ -155,7 +165,7 @@ func (s *UDMSubController) Add(c *gin.Context) {
var body model.UDMSub
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.Imsi == "" {
if err != nil || body.IMSI == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -167,15 +177,21 @@ func (s *UDMSubController) Add(c *gin.Context) {
return
}
msg := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
body.Imsi, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
// static_ip指给4G UE分配的静态IP没有可不带此字段名批量添加IP会自动递增
if body.StaticIp != "" {
msg += fmt.Sprintf(",static_ip=%s", body.StaticIp)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
body.IMSI, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
// static_ip指给4G UE分配的静态IP没有可不带此字段名批量添加IP会自动递增
if body.StaticIp != "" {
cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp)
}
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -184,12 +200,12 @@ func (s *UDMSubController) Add(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmSubService.Insert(neId, body)
go s.udmSubService.Insert(neId, body)
}
c.JSON(200, result.OkData(data))
}
// UDM签约用户-批量添加
// UDM签约用户批量新增
//
// POST /:neId/:num
func (s *UDMSubController) Adds(c *gin.Context) {
@@ -203,7 +219,7 @@ func (s *UDMSubController) Adds(c *gin.Context) {
var body model.UDMSub
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.Imsi == "" {
if err != nil || body.IMSI == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -215,15 +231,21 @@ func (s *UDMSubController) Adds(c *gin.Context) {
return
}
msg := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
body.Imsi, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
// static_ip指给4G UE分配的静态IP没有可不带此字段名批量添加IP会自动递增
if body.StaticIp != "" {
msg += fmt.Sprintf(",static_ip=%s", body.StaticIp)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s",
body.IMSI, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext)
// static_ip指给4G UE分配的静态IP没有可不带此字段名批量添加IP会自动递增
if body.StaticIp != "" {
cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp)
}
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -232,12 +254,12 @@ func (s *UDMSubController) Adds(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmSubService.Inserts(neId, body, num)
go s.udmSubService.LoadData(neId, body.IMSI, num)
}
c.JSON(200, result.OkData(data))
}
// UDM签约用户-修改
// UDM签约用户修改
//
// PUT /:neId
func (s *UDMSubController) Edit(c *gin.Context) {
@@ -250,7 +272,7 @@ func (s *UDMSubController) Edit(c *gin.Context) {
var body model.UDMSub
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.Imsi == "" {
if err != nil || body.IMSI == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
@@ -262,65 +284,71 @@ func (s *UDMSubController) Edit(c *gin.Context) {
return
}
msg := fmt.Sprintf("mod udmuser:imsi=%s", body.Imsi)
// 修改的参数名称
if body.Msisdn != "" {
msg += fmt.Sprintf(",msisdn=%s", body.Msisdn)
}
if body.Ambr != "" {
msg += fmt.Sprintf(",ambr=%s", body.Ambr)
}
if body.Nssai != "" {
msg += fmt.Sprintf(",nssai=%s", body.Nssai)
}
if body.Arfb != "" {
msg += fmt.Sprintf(",arfb=%s", body.Arfb)
}
if body.Sar != "" {
msg += fmt.Sprintf(",sar=%s", body.Sar)
}
if body.Rat != "" {
msg += fmt.Sprintf(",rat=%s", body.Rat)
}
if body.Cn != "" {
msg += fmt.Sprintf(",cn=%s", body.Cn)
}
if body.SmfSel != "" {
msg += fmt.Sprintf(",smf_sel=%s", body.SmfSel)
}
if body.SmData != "" {
msg += fmt.Sprintf(",sm_data=%s", body.SmData)
}
if body.EpsDat != "" {
msg += fmt.Sprintf(",eps_dat=%s", body.EpsDat)
}
if body.EpsFlag != "" {
msg += fmt.Sprintf(",eps_flag=%s", body.EpsFlag)
}
if body.EpsOdb != "" {
msg += fmt.Sprintf(",eps_odb=%s", body.EpsOdb)
}
if body.HplmnOdb != "" {
msg += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb)
}
if body.Epstpl != "" {
msg += fmt.Sprintf(",epstpl=%s", body.Epstpl)
}
if body.Ard != "" {
msg += fmt.Sprintf(",ard=%s", body.Ard)
}
if body.ContextId != "" {
msg += fmt.Sprintf(",context_id=%s", body.ContextId)
}
if body.ApnContext != "" {
msg += fmt.Sprintf(",apn_context=%s", body.ApnContext)
}
if body.StaticIp != "" {
msg += fmt.Sprintf(",static_ip=%s", body.StaticIp)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("mod udmuser:imsi=%s", body.IMSI)
// 修改的参数名称
if body.Msisdn != "" {
cmd += fmt.Sprintf(",msisdn=%s", body.Msisdn)
}
if body.Ambr != "" {
cmd += fmt.Sprintf(",ambr=%s", body.Ambr)
}
if body.Nssai != "" {
cmd += fmt.Sprintf(",nssai=%s", body.Nssai)
}
if body.Arfb != "" {
cmd += fmt.Sprintf(",arfb=%s", body.Arfb)
}
if body.Sar != "" {
cmd += fmt.Sprintf(",sar=%s", body.Sar)
}
if body.Rat != "" {
cmd += fmt.Sprintf(",rat=%s", body.Rat)
}
if body.Cn != "" {
cmd += fmt.Sprintf(",cn=%s", body.Cn)
}
if body.SmfSel != "" {
cmd += fmt.Sprintf(",smf_sel=%s", body.SmfSel)
}
if body.SmData != "" {
cmd += fmt.Sprintf(",sm_data=%s", body.SmData)
}
if body.EpsDat != "" {
cmd += fmt.Sprintf(",eps_dat=%s", body.EpsDat)
}
if body.EpsFlag != "" {
cmd += fmt.Sprintf(",eps_flag=%s", body.EpsFlag)
}
if body.EpsOdb != "" {
cmd += fmt.Sprintf(",eps_odb=%s", body.EpsOdb)
}
if body.HplmnOdb != "" {
cmd += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb)
}
if body.Epstpl != "" {
cmd += fmt.Sprintf(",epstpl=%s", body.Epstpl)
}
if body.Ard != "" {
cmd += fmt.Sprintf(",ard=%s", body.Ard)
}
if body.ContextId != "" {
cmd += fmt.Sprintf(",context_id=%s", body.ContextId)
}
if body.ApnContext != "" {
cmd += fmt.Sprintf(",apn_context=%s", body.ApnContext)
}
if body.StaticIp != "" {
cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp)
}
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -329,12 +357,12 @@ func (s *UDMSubController) Edit(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmSubService.Update(neId, body)
go s.udmSubService.Insert(neId, body)
}
c.JSON(200, result.OkData(data))
}
// UDM签约用户-删除
// UDM签约用户删除
//
// DELETE /:neId/:imsi
func (s *UDMSubController) Remove(c *gin.Context) {
@@ -361,27 +389,34 @@ func (s *UDMSubController) Remove(c *gin.Context) {
return
}
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
resultData := map[string]string{}
for _, imsi := range uniqueIDs {
msg := fmt.Sprintf("del udmuser:imsi=%s", imsi)
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("del udmuser:imsi=%s", imsi)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
resultData[imsi] = err.Error()
continue
}
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmSubService.Delete(neId, imsi)
resultData[imsi] = data
go s.udmSubService.Delete(neId, imsi)
}
resultData[imsi] = data
}
c.JSON(200, result.OkData(resultData))
}
// UDM签约用户-批量删除
// UDM签约用户批量删除
//
// DELETE /:neId/:imsi/:num
func (s *UDMSubController) Removes(c *gin.Context) {
@@ -401,10 +436,16 @@ func (s *UDMSubController) Removes(c *gin.Context) {
return
}
msg := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num)
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -413,12 +454,12 @@ func (s *UDMSubController) Removes(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
neId = ""
s.udmSubService.Deletes(neId, imsi, num)
go s.udmSubService.LoadData(neId, imsi, num)
}
c.JSON(200, result.OkData(data))
}
// UDM签约用户-导出
// UDM签约用户导出
//
// POST /export
func (s *UDMSubController) Export(c *gin.Context) {
@@ -439,9 +480,9 @@ func (s *UDMSubController) Export(c *gin.Context) {
}
neId := ""
list := s.udmSubService.List(model.UDMSub{NeID: neId})
list := s.udmSubService.SelectList(model.UDMSub{NeId: neId})
// 文件名
fileName := fmt.Sprintf("OMC_SUB_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type)
fileName := fmt.Sprintf("udm_sub_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type)
filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName)
if body.Type == "csv" {
@@ -450,7 +491,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)
@@ -465,7 +506,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)
@@ -478,55 +519,68 @@ func (s *UDMSubController) Export(c *gin.Context) {
c.FileAttachment(filePath, fileName)
}
// UDM签约用户-导入
// UDM签约用户导入
//
// POST /import
func (s *UDMSubController) Import(c *gin.Context) {
language := ctx.AcceptLanguage(c)
neId := c.PostForm("neId")
if neId == "" {
var body struct {
NeId string `json:"neId" binding:"required"`
UploadPath string `json:"uploadPath" binding:"required"`
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
formFile, err := c.FormFile("file")
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 获取文件名
if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) {
// 判断文件名
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
return
}
// 上传文件转存
upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
if neInfo.NeId != neId || neInfo.IP == "" {
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId)
if neInfo.NeId != body.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
// 本地文件
localPath := file.ParseUploadFilePath(upFilePath)
nePath := "/tmp" //config.Get("mml.upload").(string)
// 复制到远程
err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath)
// 网元主机的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()
fileName := localPath[strings.LastIndex(localPath, "/")+1:]
msg := fmt.Sprintf("import udmuser:path=%s", fmt.Sprintf("%s/%s", nePath, fileName))
// 本地文件
localFilePath := file.ParseUploadFilePath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, result.ErrMsg("error uploading file"))
return
}
// 网元主机的Telnet客户端
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer telnetClient.Close()
// 发送MML
data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg)
cmd := fmt.Sprintf("import udmuser:path=%s", neFilePath)
data, err := telnet.ConvertToStr(telnetClient, cmd)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
@@ -534,15 +588,15 @@ func (s *UDMSubController) Import(c *gin.Context) {
// 命令ok时
if strings.Contains(data, "ok") {
if strings.HasSuffix(fileName, ".csv") {
data := file.ReadFileCSV(localPath)
neId = ""
go s.udmSubService.InsertCSV(neId, data)
if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localFilePath)
neId := ""
go s.udmSubService.InsertData(neId, "csv", data)
}
if strings.HasSuffix(fileName, ".txt") {
data := file.ReadFileTXT(",", localPath)
neId = ""
go s.udmSubService.InsertTxt(neId, data)
if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXT(",", localFilePath)
neId := ""
go s.udmSubService.InsertData(neId, "txt", data)
}
}
c.JSON(200, result.OkMsg(data))

View File

@@ -2,20 +2,20 @@ package model
import "time"
// CDREvent CDR会话对象 cdr_event_ims/cdr_event_smf
type CDREvent struct {
// CDREventIMS CDR会话对象IMS cdr_event_ims
type CDREventIMS struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
}
// CDREventQuery CDR会话对象查询参数结构体
type CDREventQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型
// CDREventIMSQuery CDR会话对象IMS查询参数结构体
type CDREventIMSQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型IMS
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC MOSM MTSM

View File

@@ -2,29 +2,34 @@ package model
import "time"
// CDREvent CDR会话对象 cdr_event_smf
// CDREventSMF CDR会话对象SMF cdr_event_smf
type CDREventSMF struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"`
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
RecordType string `json:"recordType" gorm:"column:record_type"`
ChargingID string `json:"chargingID" gorm:"column:charging_id"`
SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"`
Duration string `json:"duration" gorm:"column:duration"`
DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"`
DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"`
DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"`
PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"`
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
// ====== 非数据库字段属性 ======
// RecordType string `json:"recordType" gorm:"column:record_type"`
// ChargingID string `json:"chargingID" gorm:"column:charging_id"`
// SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"`
// Duration string `json:"duration" gorm:"column:duration"`
// DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"`
// DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"`
// DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"`
// PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"`
}
type SMFCDREventQuery struct {
// CDREventSMFQuery CDR会话对象SMF查询参数结构体
type CDREventSMFQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // SMF
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
RecordType string `json:"recordType" form:"recordType"`
RecordType string `json:"recordType" form:"recordType"` // 暂时没用到
SubscriberID string `json:"subscriberID" form:"subscriberID"`
StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"`

View File

@@ -3,13 +3,13 @@ package model
// UDMAuth UDM鉴权用户对象 u_auth_user
type UDMAuth struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID
Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号
Amf string `json:"amf" gorm:"column:amf"` // ANF
Status string `json:"status" gorm:"column:status"` // 状态
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网元标识-子系统
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统
}
func (UDMAuth) TableName() string {

View File

@@ -4,7 +4,7 @@ package model
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卡号
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"`
@@ -14,7 +14,7 @@ type UDMSub struct {
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网元标识-子系统
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统
EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"`
EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"`
@@ -27,7 +27,6 @@ type UDMSub struct {
// ====== 非数据库字段属性 ======
SubNum string `json:"subNum,omitempty" gorm:"-"` // 批量数
}
func (UDMSub) TableName() string {

View File

@@ -2,20 +2,20 @@ package model
import "time"
// UEEvent UE会话对象 ue_event
type UEEvent struct {
// UEEventAMF UE会话对象AMF ue_event_amf
type UEEventAMF struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
EventType string `json:"eventType" gorm:"column:event_type"`
EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state
EventJSONStr string `json:"eventJSON" gorm:"column:event_json"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
}
// UEEventQuery UE会话对象查询参数结构体
type UEEventQuery struct {
// UEEventAMFQuery UE会话对象AMF查询参数结构体
type UEEventAMFQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持AMF
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`

View File

@@ -0,0 +1,30 @@
package model
import "time"
// UEEventMME UE会话对象MME ue_event_mme
type UEEventMME struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"`
RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有
Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state
EventJSONStr string `json:"eventJSON" gorm:"column:event_json"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
}
// UEEventMMEQuery UE会话对象MME查询参数结构体
type UEEventMMEQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持MME
NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"`
EventType string `json:"eventType" form:"eventType"` // 事件类型 auth-result detach cm-state
IMSI string `json:"imsi" form:"imsi"` // imsi
StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"`
SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段
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"`
}

View File

@@ -4,6 +4,7 @@ import (
"be.ems/src/framework/logger"
"be.ems/src/framework/middleware"
"be.ems/src/framework/middleware/collectlogs"
"be.ems/src/framework/middleware/repeat"
"be.ems/src/modules/network_data/controller"
"github.com/gin-gonic/gin"
@@ -44,49 +45,58 @@ func Setup(router *gin.Engine) {
// 网元IMS
imsGroup := neDataGroup.Group("/ims")
{
// CDR会话事件列表
imsGroup.GET("/cdr/list",
middleware.PreAuthorize(nil),
controller.NewIMSController.CDRList,
)
// CDR会话删除
imsGroup.DELETE("/cdr/:cdrIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewIMSController.CDRRemove,
)
imsGroup.POST("/cdr/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewIMSController.CDRExport,
)
}
// 网元SMF
smfGroup := neDataGroup.Group("/smf")
{
// CDR会话事件列表
smfGroup.GET("/cdr/list",
middleware.PreAuthorize(nil),
controller.NewSMFController.CDRList,
)
// CDR会话删除
smfGroup.DELETE("/cdr/:cdrIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMFController.CDRRemove,
)
smfGroup.POST("/cdr/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewSMFController.CDRExport,
)
}
// 网元AMF
amfGroup := neDataGroup.Group("/amf")
{
// UE会话事件
amfGroup.GET("/ue/list",
middleware.PreAuthorize(nil),
controller.NewAMFController.UEList,
)
// UE会话删除
amfGroup.DELETE("/ue/:ueIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewAMFController.UERemove,
)
amfGroup.POST("/ue/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewAMFController.UEExport,
)
}
// 网元UPF
@@ -98,4 +108,130 @@ func Setup(router *gin.Engine) {
)
}
// 网元UDM 鉴权用户信息
udmAuthGroup := neDataGroup.Group("/udm/auth")
{
udmAuthGroup.PUT("/resetData/:neId",
repeat.RepeatSubmit(5),
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMAuth.ResetData,
)
udmAuthGroup.GET("/list",
middleware.PreAuthorize(nil),
controller.NewUDMAuth.List,
)
udmAuthGroup.GET("/:neId/:imsi",
middleware.PreAuthorize(nil),
controller.NewUDMAuth.Info,
)
udmAuthGroup.POST("/:neId",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMAuth.Add,
)
udmAuthGroup.POST("/:neId/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMAuth.Adds,
)
udmAuthGroup.PUT("/:neId",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMAuth.Edit,
)
udmAuthGroup.DELETE("/:neId/:imsi",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMAuth.Remove,
)
udmAuthGroup.DELETE("/:neId/:imsi/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMAuth.Removes,
)
udmAuthGroup.POST("/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMAuth.Export,
)
udmAuthGroup.POST("/import",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMAuth.Import,
)
}
// 网元UDM 签约用户信息
udmSubGroup := neDataGroup.Group("/udm/sub")
{
udmSubGroup.PUT("/resetData/:neId",
repeat.RepeatSubmit(5),
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMSub.ResetData,
)
udmSubGroup.GET("/list",
middleware.PreAuthorize(nil),
controller.NewUDMSub.List,
)
udmSubGroup.GET("/:neId/:imsi",
middleware.PreAuthorize(nil),
controller.NewUDMSub.Info,
)
udmSubGroup.POST("/:neId",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMSub.Add,
)
udmSubGroup.POST("/:neId/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMSub.Adds,
)
udmSubGroup.PUT("/:neId",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMSub.Edit,
)
udmSubGroup.DELETE("/:neId/:imsi",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMSub.Remove,
)
udmSubGroup.DELETE("/:neId/:imsi/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMSub.Removes,
)
udmSubGroup.POST("/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMSub.Export,
)
udmSubGroup.POST("/import",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMSub.Import,
)
}
// 网元MME
mmeGroup := neDataGroup.Group("/mme")
{
mmeGroup.GET("/ue/list",
middleware.PreAuthorize(nil),
controller.NewMMEController.UEList,
)
mmeGroup.DELETE("/ue/:ueIds",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewMMEController.UERemove,
)
mmeGroup.POST("/ue/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewMMEController.UEExport,
)
}
}

View File

@@ -1,27 +0,0 @@
package repository
import "be.ems/src/modules/network_data/model"
// CDR会话事件 数据层接口
type ICDREvent interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.CDREventQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(cdrIds []string) []model.CDREvent
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) int64
}
// SMF CDR Event
type SMFCDREvent interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.SMFCDREventQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(cdrIds []string) []model.CDREventSMF
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) int64
}

View File

@@ -1,344 +0,0 @@
package repository
import (
"fmt"
"strings"
"be.ems/src/framework/datasource"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/repo"
"be.ems/src/modules/network_data/model"
)
// 实例化数据层 CDREventImpl 结构体
var NewCDREventImpl = &CDREventImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_ims`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_name": "NeName",
"rm_uid": "RmUID",
"timestamp": "Timestamp",
"cdr_json": "CDRJSONStr",
"created_at": "CreatedAt",
},
}
// CDREventImpl CDR会话事件 数据层处理
type CDREventImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// Instance of SMF CDREventImpl
var NewSMFCDREventImpl = &SMFCDREventImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, JSON_EXTRACT(cdr_json, '$.recordType') AS record_type, JSON_EXTRACT(cdr_json, '$.chargingID') AS charging_id, JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') AS subscriber_id, JSON_EXTRACT(cdr_json, '$.duration') AS duration, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeUplink') AS data_volume_uplink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeDownlink') AS data_volume_downlink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataTotalVolume') AS data_total_volume, JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.pDUAddress') AS pdu_address, created_at from cdr_event_smf`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_name": "NeName",
"rm_uid": "RmUID",
"timestamp": "Timestamp",
"record_type": "RecordType",
"charging_id": "ChargingID",
"subscriber_id": "SubscriberID",
"duration": "Duration",
"data_volume_uplink": "DataVolumeUplink",
"data_volume_downlink": "DataVolumeDownlink",
"data_total_volume": "DataTotalVolume",
"pdu_address": "PDUAddress",
"created_at": "CreatedAt",
},
}
// CDREventImpl CDR会话事件 数据层处理
type SMFCDREventImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *CDREventImpl) convertResultRows(rows []map[string]any) []model.CDREvent {
arr := make([]model.CDREvent, 0)
for _, row := range rows {
item := model.CDREvent{}
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 *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if querys.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, querys.NeType)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, beginDate.Unix())
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, endDate.Unix())
}
if querys.CallerParty != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.callerParty') = ?")
params = append(params, querys.CallerParty)
}
if querys.CalledParty != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.calledParty') = ?")
params = append(params, querys.CalledParty)
}
if querys.RecordType != "" {
recordTypes := strings.Split(querys.RecordType, ",")
placeholder := repo.KeyPlaceholderByQuery(len(recordTypes))
conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder))
for _, recordType := range recordTypes {
params = append(params, recordType)
}
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.CDREvent{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from cdr_event_ims"
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
}
// SelectByIds 通过ID查询
func (r *CDREventImpl) SelectByIds(cdrIds []string) []model.CDREvent {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.CDREvent{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *CDREventImpl) DeleteByIds(cdrIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
sql := "delete from cdr_event_ims where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
logger.Errorf("delete err => %v", err)
return 0
}
return results
}
// convertResultRows 将结果记录转实体结果组
func (r *SMFCDREventImpl) convertResultRows(rows []map[string]any) []model.CDREventSMF {
arr := make([]model.CDREventSMF, 0)
for _, row := range rows {
item := model.CDREventSMF{}
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 *SMFCDREventImpl) SelectPage(querys model.SMFCDREventQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if querys.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, querys.NeType)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, beginDate.Unix())
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, endDate.Unix())
}
if querys.RecordType != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.recordType') = ?")
params = append(params, querys.RecordType)
}
if querys.SubscriberID != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?")
params = append(params, querys.SubscriberID)
}
// if querys.RecordType != "" {
// recordTypes := strings.Split(querys.RecordType, ",")
// placeholder := repo.KeyPlaceholderByQuery(len(recordTypes))
// conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder))
// for _, recordType := range recordTypes {
// params = append(params, recordType)
// }
// }
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.CDREventSMF{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from cdr_event_smf"
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
}
// SelectByIds 通过ID查询
func (r *SMFCDREventImpl) SelectByIds(cdrIds []string) []model.CDREventSMF {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.CDREventSMF{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *SMFCDREventImpl) DeleteByIds(cdrIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
sql := "delete from cdr_event_smf where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
logger.Errorf("delete err => %v", err)
return 0
}
return results
}

View File

@@ -0,0 +1,15 @@
package repository
import "be.ems/src/modules/network_data/model"
// CDR会话事件IMS 数据层接口
type ICDREventIMS interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.CDREventIMSQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(cdrIds []string) []model.CDREventIMS
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) int64
}

View File

@@ -0,0 +1,178 @@
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"
)
// 实例化数据层 CDREventImpl 结构体
var NewCDREventIMSImpl = &CDREventIMSImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_ims`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_name": "NeName",
"rm_uid": "RmUID",
"timestamp": "Timestamp",
"cdr_json": "CDRJSONStr",
"created_at": "CreatedAt",
},
}
// CDREventIMSImpl CDR会话事件IMS 数据层处理
type CDREventIMSImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *CDREventIMSImpl) convertResultRows(rows []map[string]any) []model.CDREventIMS {
arr := make([]model.CDREventIMS, 0)
for _, row := range rows {
item := model.CDREventIMS{}
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 *CDREventIMSImpl) SelectPage(querys model.CDREventIMSQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if querys.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, querys.NeType)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
if len(querys.StartTime) == 13 {
querys.StartTime = querys.StartTime[:10]
}
params = append(params, querys.StartTime)
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
if len(querys.EndTime) == 13 {
querys.EndTime = querys.EndTime[:10]
}
params = append(params, querys.EndTime)
}
if querys.CallerParty != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.callerParty') = ?")
params = append(params, querys.CallerParty)
}
if querys.CalledParty != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.calledParty') = ?")
params = append(params, querys.CalledParty)
}
if querys.RecordType != "" {
recordTypes := strings.Split(querys.RecordType, ",")
placeholder := repo.KeyPlaceholderByQuery(len(recordTypes))
conditions = append(conditions, fmt.Sprintf("JSON_EXTRACT(cdr_json, '$.recordType') in (%s)", placeholder))
for _, recordType := range recordTypes {
params = append(params, recordType)
}
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.CDREventIMS{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from cdr_event_ims"
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
}
// SelectByIds 通过ID查询
func (r *CDREventIMSImpl) SelectByIds(cdrIds []string) []model.CDREventIMS {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.CDREventIMS{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *CDREventIMSImpl) DeleteByIds(cdrIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
sql := "delete from cdr_event_ims where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
logger.Errorf("delete err => %v", err)
return 0
}
return results
}

View File

@@ -0,0 +1,15 @@
package repository
import "be.ems/src/modules/network_data/model"
// CDR会话事件SMF 数据层接口
type ICDREventSMF interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.CDREventSMFQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(cdrIds []string) []model.CDREventSMF
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) int64
}

View File

@@ -0,0 +1,185 @@
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"
)
// 实例化数据层 CDREventSMFImpl 结构体
var NewCDREventSMFImpl = &CDREventSMFImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_smf`,
// selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, JSON_EXTRACT(cdr_json, '$.recordType') AS record_type, JSON_EXTRACT(cdr_json, '$.chargingID') AS charging_id, JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') AS subscriber_id, JSON_EXTRACT(cdr_json, '$.duration') AS duration, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeUplink') AS data_volume_uplink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeDownlink') AS data_volume_downlink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataTotalVolume') AS data_total_volume, JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.pDUAddress') AS pdu_address, created_at from cdr_event_smf`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_name": "NeName",
"rm_uid": "RmUID",
"timestamp": "Timestamp",
"cdr_json": "CDRJSONStr",
"created_at": "CreatedAt",
// "id": "ID",
// "ne_type": "NeType",
// "ne_name": "NeName",
// "rm_uid": "RmUID",
// "timestamp": "Timestamp",
// "record_type": "RecordType",
// "charging_id": "ChargingID",
// "subscriber_id": "SubscriberID",
// "duration": "Duration",
// "data_volume_uplink": "DataVolumeUplink",
// "data_volume_downlink": "DataVolumeDownlink",
// "data_total_volume": "DataTotalVolume",
// "pdu_address": "PDUAddress",
// "created_at": "CreatedAt",
},
}
// CDREventSMFImpl CDR会话事件 数据层处理
type CDREventSMFImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *CDREventSMFImpl) convertResultRows(rows []map[string]any) []model.CDREventSMF {
arr := make([]model.CDREventSMF, 0)
for _, row := range rows {
item := model.CDREventSMF{}
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 *CDREventSMFImpl) SelectPage(querys model.CDREventSMFQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if querys.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, querys.NeType)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
if len(querys.StartTime) == 13 {
querys.StartTime = querys.StartTime[:10]
}
params = append(params, querys.StartTime)
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
if len(querys.EndTime) == 13 {
querys.EndTime = querys.EndTime[:10]
}
params = append(params, querys.EndTime)
}
if querys.RecordType != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.recordType') = ?")
params = append(params, querys.RecordType)
}
if querys.SubscriberID != "" {
conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?")
params = append(params, querys.SubscriberID)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.CDREventSMF{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from cdr_event_smf"
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
}
// SelectByIds 通过ID查询
func (r *CDREventSMFImpl) SelectByIds(cdrIds []string) []model.CDREventSMF {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.CDREventSMF{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *CDREventSMFImpl) DeleteByIds(cdrIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(cdrIds))
sql := "delete from cdr_event_smf where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(cdrIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
logger.Errorf("delete err => %v", err)
return 0
}
return results
}

View File

@@ -96,19 +96,47 @@ func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string)
params = append(params, query.RmUID)
}
if query.NeType != "" {
conditions = append(conditions, "gk.ne_type = ?")
params = append(params, query.NeType)
//conditions = append(conditions, "gk.ne_type = ?")
// params = append(params, query.NeType)
tableName += strings.ToLower(query.NeType)
}
var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)"
var dateStr1, dateStr2, timeStr1, timeStr2 string
if query.StartTime != "" {
conditions = append(conditions, dateTimeStr+" >= ?")
params = append(params, query.StartTime)
dateStr1 = query.StartTime[:10]
timeStr1 = query.StartTime[11:]
}
if query.EndTime != "" {
conditions = append(conditions, dateTimeStr+" <= ?")
params = append(params, query.EndTime)
dateStr2 = query.EndTime[:10]
timeStr2 = query.EndTime[11:]
}
if dateStr1 == dateStr2 && dateStr1 != "" {
conditions = append(conditions, "gk.`date` = ?")
params = append(params, dateStr1)
conditions = append(conditions, "gk.`start_time` >= ?")
params = append(params, timeStr1)
conditions = append(conditions, "gk.`start_time` <= ?")
params = append(params, timeStr2)
} else {
if dateStr1 != "" {
conditions = append(conditions, "(gk.`date` > ? OR (gk.`date` = ? AND gk.`start_time` >= ?))")
params = append(params, dateStr1, dateStr1, timeStr1)
}
if dateStr2 != "" {
conditions = append(conditions, "(gk.`date` < ? OR (gk.`date` = ? AND gk.`start_time` <= ?))")
params = append(params, dateStr2, dateStr2, timeStr2)
}
}
// var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)"
// if query.StartTime != "" {
// conditions = append(conditions, dateTimeStr+" >= ?")
// params = append(params, query.StartTime)
// }
// if query.EndTime != "" {
// conditions = append(conditions, dateTimeStr+" <= ?")
// params = append(params, query.EndTime)
// }
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
@@ -116,6 +144,7 @@ func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string)
}
// 查询字段列
var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)"
timeFormat := "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:%i:')"
secondGroup := fmt.Sprintf("LPAD(FLOOR(SECOND(gk.start_time) / %d) * %d, 2, '0')", query.Interval, query.Interval)
groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, secondGroup)

View File

@@ -0,0 +1,26 @@
package repository
import (
"be.ems/src/modules/network_data/model"
)
// UDM鉴权信息 数据层接口
type IUDMAuth interface {
// ClearAndInsert 清空ne_id后新增实体
ClearAndInsert(neId string, uArr []model.UDMAuth) int64
// SelectPage 根据条件分页查询
SelectPage(query map[string]any) map[string]any
// SelectList 根据实体查询
SelectList(u model.UDMAuth) []model.UDMAuth
// Insert 批量添加
Inserts(uArr []model.UDMAuth) int64
// Delete 删除实体
Delete(neId, imsi string) int64
// DeletePrefixByIMSI 删除前缀匹配的实体
DeletePrefixByIMSI(neId, imsi string) int64
}

View File

@@ -1,13 +1,14 @@
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_element/model"
"be.ems/src/modules/network_data/model"
)
// 实例化数据层 UDMAuthImpl 结构体
@@ -16,13 +17,13 @@ var NewUDMAuthImpl = &UDMAuthImpl{
resultMap: map[string]string{
"id": "ID",
"imsi": "Imsi",
"imsi": "IMSI",
"amf": "Amf",
"status": "Status",
"ki": "Ki",
"algo_index": "AlgoIndex",
"opc": "Opc",
"ne_id": "NeID",
"ne_id": "NeId",
},
}
@@ -50,14 +51,13 @@ func (r *UDMAuthImpl) convertResultRows(rows []map[string]any) []model.UDMAuth {
}
// ClearAndInsert 清空ne_id后新增实体
func (r *UDMAuthImpl) ClearAndInsert(neID string, authArr []model.UDMAuth) int64 {
// 清空指定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(authArr)
return r.Inserts(uArr)
}
// SelectPage 根据条件分页查询
@@ -106,11 +106,9 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
params = append(params, pageSize)
// 排序
sortSql := ""
orderSql := ""
if v, ok := query["sortField"]; ok && v != "" {
if v == "imsi" {
sortSql += " order by imsi "
}
sortSql := v.(string)
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
if o == "desc" {
sortSql += " desc "
@@ -118,10 +116,11 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
sortSql += " asc "
}
}
orderSql = fmt.Sprintf(" order by %s ", sortSql)
}
// 查询数据
querySql := r.selectSql + whereSql + sortSql + pageSql
querySql := r.selectSql + whereSql + orderSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
@@ -133,17 +132,17 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
}
// SelectList 根据实体查询
func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth {
func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth {
// 查询条件拼接
var conditions []string
var params []any
if auth.Imsi != "" {
if u.IMSI != "" {
conditions = append(conditions, "imsi = ?")
params = append(params, auth.Imsi)
params = append(params, u.IMSI)
}
if auth.NeID != "" {
if u.NeId != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, auth.NeID)
params = append(params, u.NeId)
}
// 构建查询条件语句
@@ -164,8 +163,8 @@ func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth {
}
// Insert 批量添加
func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 {
tx := datasource.DefaultDB().CreateInBatches(authUsers, 3000)
func (r *UDMAuthImpl) Inserts(uArr []model.UDMAuth) int64 {
tx := datasource.DefaultDB().CreateInBatches(uArr, 3000)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
@@ -173,19 +172,19 @@ func (r *UDMAuthImpl) Inserts(authUsers []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 *UDMAuthImpl) Delete(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixImsi 删除前缀匹配的实体
func (r *UDMAuthImpl) DeletePrefixImsi(neID, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{})
// DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMAuthImpl) DeletePrefixByIMSI(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{})
if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixImsi err => %v", err)
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -0,0 +1,26 @@
package repository
import (
"be.ems/src/modules/network_data/model"
)
// UDM签约信息 数据层接口
type IUDMSub interface {
// ClearAndInsert 清空ne_id后新增实体
ClearAndInsert(neId string, uArr []model.UDMSub) int64
// SelectPage 根据条件分页查询
SelectPage(query map[string]any) map[string]any
// SelectList 根据实体查询
SelectList(u model.UDMSub) []model.UDMSub
// Insert 批量添加
Inserts(uArr []model.UDMSub) int64
// Delete 删除实体
Delete(neId, imsi string) int64
// DeletePrefixByIMSI 删除前缀匹配的实体
DeletePrefixByIMSI(neId, imsi string) int64
}

View File

@@ -1,14 +1,14 @@
package repository
import (
"strconv"
"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_element/model"
"be.ems/src/modules/network_data/model"
)
// 实例化数据层 UDMSubImpl 结构体
@@ -20,7 +20,7 @@ var NewUDMSubImpl = &UDMSubImpl{
resultMap: map[string]string{
"id": "ID",
"msisdn": "Msisdn",
"imsi": "Imsi",
"imsi": "IMSI",
"ambr": "Ambr",
"nssai": "Nssai",
"rat": "Rat",
@@ -30,7 +30,7 @@ var NewUDMSubImpl = &UDMSubImpl{
"sm_data": "SmData",
"smf_sel": "SmfSel",
"eps_dat": "EpsDat",
"ne_id": "NeID",
"ne_id": "NeId",
"eps_flag": "EpsFlag",
"eps_odb": "EpsOdb",
"hplmn_odb": "HplmnOdb",
@@ -66,14 +66,14 @@ func (r *UDMSubImpl) convertResultRows(rows []map[string]any) []model.UDMSub {
}
// ClearAndInsert 清空ne_id后新增实体
func (r *UDMSubImpl) ClearAndInsert(neID string, subArr []model.UDMSub) int64 {
// 清空指定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(subArr)
return r.Inserts(u)
}
// SelectPage 根据条件分页查询字典类型
@@ -126,14 +126,9 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
params = append(params, pageSize)
// 排序
sortSql := ""
orderSql := ""
if v, ok := query["sortField"]; ok && v != "" {
if v == "imsi" {
sortSql += " order by imsi "
}
if v == "msisdn" {
sortSql += " order by msisdn "
}
sortSql := v.(string)
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
if o == "desc" {
sortSql += " desc "
@@ -141,10 +136,11 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
sortSql += " asc "
}
}
orderSql = fmt.Sprintf(" order by %s ", sortSql)
}
// 查询数据
querySql := r.selectSql + whereSql + sortSql + pageSql
querySql := r.selectSql + whereSql + orderSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
@@ -157,17 +153,17 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
}
// SelectList 根据实体查询
func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub {
func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub {
// 查询条件拼接
var conditions []string
var params []any
if subUser.Imsi != "" {
if u.IMSI != "" {
conditions = append(conditions, "imsi = ?")
params = append(params, subUser.Imsi)
params = append(params, u.IMSI)
}
if subUser.NeID != "" {
if u.NeId != "" {
conditions = append(conditions, "ne_id = ?")
params = append(params, subUser.NeID)
params = append(params, u.NeId)
}
// 构建查询条件语句
@@ -187,126 +183,29 @@ func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub {
return r.convertResultRows(results)
}
// Insert 新增实体
func (r *UDMSubImpl) Insert(subUser model.UDMSub) string {
err := datasource.DefaultDB().Create(&subUser).Error
if err != nil {
logger.Errorf("Create err => %v", err)
}
return subUser.ID
}
// Insert 批量添加
func (r *UDMSubImpl) Inserts(subUser []model.UDMSub) int64 {
tx := datasource.DefaultDB().CreateInBatches(subUser, 2000)
func (r *UDMSubImpl) Inserts(uArr []model.UDMSub) int64 {
tx := datasource.DefaultDB().CreateInBatches(uArr, 2000)
if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err)
}
return tx.RowsAffected
}
// Update 修改更新
func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 {
// 查询先
var user model.UDMSub
err := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).First(&user).Error
if err != nil {
logger.Errorf("Update First err => %v", err)
}
if user.Msisdn != subUser.Msisdn {
user.Msisdn = subUser.Msisdn
}
if user.Ambr != subUser.Ambr {
user.Ambr = subUser.Ambr
}
if user.Arfb != subUser.Arfb {
user.Arfb = subUser.Arfb
}
if user.Sar != subUser.Sar {
user.Sar = subUser.Sar
}
if user.Rat != subUser.Rat {
user.Rat = subUser.Rat
}
if user.Cn != subUser.Cn {
user.Cn = subUser.Cn
}
if user.SmfSel != subUser.SmfSel {
user.SmfSel = subUser.SmfSel
}
if user.SmData != subUser.SmData {
user.SmData = subUser.SmData
}
if user.EpsDat != subUser.EpsDat {
user.EpsDat = subUser.EpsDat
}
if user.EpsFlag != subUser.EpsFlag {
user.EpsFlag = subUser.EpsFlag
}
if user.EpsDat != subUser.EpsDat {
user.EpsOdb = subUser.EpsOdb
}
if user.HplmnOdb != subUser.HplmnOdb {
user.HplmnOdb = subUser.HplmnOdb
}
if user.Epstpl != subUser.Epstpl {
user.Epstpl = subUser.Epstpl
}
if user.Ard != subUser.Ard {
user.Ard = subUser.Ard
}
if user.ContextId != subUser.ContextId {
user.ContextId = subUser.ContextId
}
if user.ApnContext != subUser.ApnContext {
user.ApnContext = subUser.ApnContext
}
if user.StaticIp != subUser.StaticIp {
user.StaticIp = subUser.StaticIp
}
tx := datasource.DefaultDB().Save(user)
if err := tx.Error; err != nil {
logger.Errorf("Update Save err => %v", err)
return 0
}
return tx.RowsAffected
}
// Delete 删除实体
func (r *UDMSubImpl) Delete(neID, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMSub{})
func (r *UDMSubImpl) Delete(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMSub{})
if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err)
}
return tx.RowsAffected
}
// DeletePrefixImsi 删除前缀匹配的实体
func (r *UDMSubImpl) DeletePrefixImsi(neID, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMSub{})
// 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("DeletePrefixImsi err => %v", err)
}
return tx.RowsAffected
}
// Delete 删除范围实体
func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 {
imsiV, err := strconv.Atoi(imsi)
if err != nil {
return 0
}
numV, err := strconv.Atoi(num)
if err != nil {
return 0
}
tx := datasource.DefaultDB().Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete(&model.UDMSub{})
if err := tx.Error; err != nil {
logger.Errorf("Deletes err => %v", err)
logger.Errorf("DeletePrefixByIMSI err => %v", err)
}
return tx.RowsAffected
}

View File

@@ -2,13 +2,13 @@ package repository
import "be.ems/src/modules/network_data/model"
// UE会话事件 数据层接口
type IUEEvent interface {
// UE会话事件AMF 数据层接口
type IUEEventAMF interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.UEEventQuery) map[string]any
SelectPage(querys model.UEEventAMFQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(ueIds []string) []model.UEEvent
SelectByIds(ueIds []string) []model.UEEventAMF
// DeleteByIds 批量删除信息
DeleteByIds(ueIds []string) int64

View File

@@ -6,15 +6,14 @@ import (
"be.ems/src/framework/datasource"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/repo"
"be.ems/src/modules/network_data/model"
)
// 实例化数据层 UEEventImpl 结构体
var NewUEEventImpl = &UEEventImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event`,
// 实例化数据层 UEEventAMFImpl 结构体
var NewUEEventAMFImpl = &UEEventAMFImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_amf`,
resultMap: map[string]string{
"id": "ID",
@@ -28,8 +27,8 @@ var NewUEEventImpl = &UEEventImpl{
},
}
// UEEventImpl UE会话事件 数据层处理
type UEEventImpl struct {
// UEEventAMFImpl UE会话事件 数据层处理
type UEEventAMFImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
@@ -37,10 +36,10 @@ type UEEventImpl struct {
}
// convertResultRows 将结果记录转实体结果组
func (r *UEEventImpl) convertResultRows(rows []map[string]any) []model.UEEvent {
arr := make([]model.UEEvent, 0)
func (r *UEEventAMFImpl) convertResultRows(rows []map[string]any) []model.UEEventAMF {
arr := make([]model.UEEventAMF, 0)
for _, row := range rows {
item := model.UEEvent{}
item := model.UEEventAMF{}
for key, value := range row {
if keyMapper, ok := r.resultMap[key]; ok {
repo.SetFieldValue(&item, keyMapper, value)
@@ -52,7 +51,7 @@ func (r *UEEventImpl) convertResultRows(rows []map[string]any) []model.UEEvent {
}
// SelectPage 根据条件分页查询
func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
func (r *UEEventAMFImpl) SelectPage(querys model.UEEventAMFQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
@@ -66,17 +65,17 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, beginDate.Unix())
if len(querys.StartTime) == 13 {
querys.StartTime = querys.StartTime[:10]
}
params = append(params, querys.StartTime)
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS)
params = append(params, endDate.Unix())
}
if querys.IMSI != "" {
conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?")
params = append(params, querys.IMSI)
if len(querys.EndTime) == 13 {
querys.EndTime = querys.EndTime[:10]
}
params = append(params, querys.EndTime)
}
if querys.EventType != "" {
eventTypes := strings.Split(querys.EventType, ",")
@@ -86,6 +85,10 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
params = append(params, eventType)
}
}
if querys.IMSI != "" {
conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?")
params = append(params, querys.IMSI)
}
// 构建查询条件语句
whereSql := ""
@@ -95,11 +98,11 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
result := map[string]any{
"total": 0,
"rows": []model.CDREvent{},
"rows": []model.UEEventAMF{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from ue_event"
totalSql := "select count(1) as 'total' from ue_event_amf"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
logger.Errorf("total err => %v", err)
@@ -145,23 +148,23 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
}
// SelectByIds 通过ID查询
func (r *UEEventImpl) SelectByIds(ueIds []string) []model.UEEvent {
func (r *UEEventAMFImpl) SelectByIds(ueIds []string) []model.UEEventAMF {
placeholder := repo.KeyPlaceholderByQuery(len(ueIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(ueIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.UEEvent{}
return []model.UEEventAMF{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *UEEventImpl) DeleteByIds(ueIds []string) int64 {
func (r *UEEventAMFImpl) DeleteByIds(ueIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(ueIds))
sql := "delete from ue_event where id in (" + placeholder + ")"
sql := "delete from ue_event_amf where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(ueIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {

View File

@@ -0,0 +1,15 @@
package repository
import "be.ems/src/modules/network_data/model"
// UE会话事件MME 数据层接口
type IUEEventMME interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.UEEventMMEQuery) map[string]any
// SelectByIds 通过ID查询
SelectByIds(ueIds []string) []model.UEEventMME
// DeleteByIds 批量删除信息
DeleteByIds(ueIds []string) int64
}

View File

@@ -0,0 +1,175 @@
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"
)
// 实例化数据层 UEEventMMEImpl 结构体
var NewUEEventMMEImpl = &UEEventMMEImpl{
selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_mme`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_name": "NeName",
"rm_uid": "RmUID",
"timestamp": "Timestamp",
"event_type": "EventType",
"event_json": "EventJSONStr",
"created_at": "CreatedAt",
},
}
// UEEventMMEImpl UE会话事件 数据层处理
type UEEventMMEImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *UEEventMMEImpl) convertResultRows(rows []map[string]any) []model.UEEventMME {
arr := make([]model.UEEventMME, 0)
for _, row := range rows {
item := model.UEEventMME{}
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 *UEEventMMEImpl) SelectPage(querys model.UEEventMMEQuery) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
if querys.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, querys.NeType)
}
if querys.RmUID != "" {
conditions = append(conditions, "rm_uid = ?")
params = append(params, querys.RmUID)
}
if querys.StartTime != "" {
conditions = append(conditions, "timestamp >= ?")
if len(querys.StartTime) == 13 {
querys.StartTime = querys.StartTime[:10]
}
params = append(params, querys.StartTime)
}
if querys.EndTime != "" {
conditions = append(conditions, "timestamp <= ?")
if len(querys.EndTime) == 13 {
querys.EndTime = querys.EndTime[:10]
}
params = append(params, querys.EndTime)
}
if querys.EventType != "" {
eventTypes := strings.Split(querys.EventType, ",")
placeholder := repo.KeyPlaceholderByQuery(len(eventTypes))
conditions = append(conditions, fmt.Sprintf("event_type in (%s)", placeholder))
for _, eventType := range eventTypes {
params = append(params, eventType)
}
}
if querys.IMSI != "" {
conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?")
params = append(params, querys.IMSI)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.UEEventMME{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from ue_event_mme"
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
}
// SelectByIds 通过ID查询
func (r *UEEventMMEImpl) SelectByIds(ueIds []string) []model.UEEventMME {
placeholder := repo.KeyPlaceholderByQuery(len(ueIds))
querySql := r.selectSql + " where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(ueIds)
results, err := datasource.RawDB("", querySql, parameters)
if err != nil {
logger.Errorf("query err => %v", err)
return []model.UEEventMME{}
}
// 转换实体
return r.convertResultRows(results)
}
// DeleteByIds 批量删除信息
func (r *UEEventMMEImpl) DeleteByIds(ueIds []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(ueIds))
sql := "delete from ue_event_mme where id in (" + placeholder + ")"
parameters := repo.ConvertIdsSlice(ueIds)
results, err := datasource.ExecDB("", sql, parameters)
if err != nil {
logger.Errorf("delete err => %v", err)
return 0
}
return results
}

View File

@@ -1,21 +0,0 @@
package service
import "be.ems/src/modules/network_data/model"
// CDR会话事件 服务层接口
type ICDREvent interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.CDREventQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) (int64, error)
}
// CDR会话事件 服务层接口
type SMFCDREvent interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.SMFCDREventQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) (int64, error)
}

View File

@@ -1,69 +0,0 @@
package service
import (
"fmt"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
)
// 实例化数据层 CDREventImpl 结构体
var NewCDREventImpl = &CDREventImpl{
cdrEventRepository: repository.NewCDREventImpl,
}
var NewSMFCDREventImpl = &SMFCDREventImpl{
cdrEventRepository: repository.NewSMFCDREventImpl,
}
// CDREventImpl CDR会话事件 服务层处理
type CDREventImpl struct {
// CDR会话事件数据信息
cdrEventRepository repository.ICDREvent
}
type SMFCDREventImpl struct {
// CDR会话事件数据信息
cdrEventRepository repository.SMFCDREvent
}
// SelectPage 根据条件分页查询
func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any {
return r.cdrEventRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *CDREventImpl) DeleteByIds(cdrIds []string) (int64, error) {
// 检查是否存在
ids := r.cdrEventRepository.SelectByIds(cdrIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(ids) == len(cdrIds) {
rows := r.cdrEventRepository.DeleteByIds(cdrIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}
func (r *SMFCDREventImpl) SelectPage(querys model.SMFCDREventQuery) map[string]any {
return r.cdrEventRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *SMFCDREventImpl) DeleteByIds(cdrIds []string) (int64, error) {
// 检查是否存在
ids := r.cdrEventRepository.SelectByIds(cdrIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(ids) == len(cdrIds) {
rows := r.cdrEventRepository.DeleteByIds(cdrIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}

View File

@@ -0,0 +1,12 @@
package service
import "be.ems/src/modules/network_data/model"
// CDR会话事件IMS 服务层接口
type ICDREventIMS interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.CDREventIMSQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) (int64, error)
}

View File

@@ -0,0 +1,40 @@
package service
import (
"fmt"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
)
// 实例化数据层 NewCDREventIMSImpl 结构体
var NewCDREventIMSImpl = &CDREventIMSImpl{
cdrEventIMSRepository: repository.NewCDREventIMSImpl,
}
// CDREventImpl CDR会话事件IMS 服务层处理
type CDREventIMSImpl struct {
// CDR会话事件数据信息
cdrEventIMSRepository repository.ICDREventIMS
}
// SelectPage 根据条件分页查询
func (r *CDREventIMSImpl) SelectPage(querys model.CDREventIMSQuery) map[string]any {
return r.cdrEventIMSRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *CDREventIMSImpl) DeleteByIds(cdrIds []string) (int64, error) {
// 检查是否存在
ids := r.cdrEventIMSRepository.SelectByIds(cdrIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(ids) == len(cdrIds) {
rows := r.cdrEventIMSRepository.DeleteByIds(cdrIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}

View File

@@ -0,0 +1,12 @@
package service
import "be.ems/src/modules/network_data/model"
// CDR会话事件SMF 服务层接口
type ICDREventSMF interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.CDREventSMFQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(cdrIds []string) (int64, error)
}

View File

@@ -0,0 +1,37 @@
package service
import (
"fmt"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
)
var NewCDREventSMFImpl = &CDREventSMFImpl{
cdrEventRepository: repository.NewCDREventSMFImpl,
}
type CDREventSMFImpl struct {
// CDR会话事件数据信息
cdrEventRepository repository.ICDREventSMF
}
func (r *CDREventSMFImpl) SelectPage(querys model.CDREventSMFQuery) map[string]any {
return r.cdrEventRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *CDREventSMFImpl) DeleteByIds(cdrIds []string) (int64, error) {
// 检查是否存在
ids := r.cdrEventRepository.SelectByIds(cdrIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("not data")
}
if len(ids) == len(cdrIds) {
rows := r.cdrEventRepository.DeleteByIds(cdrIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}

View File

@@ -0,0 +1,28 @@
package service
import "be.ems/src/modules/network_data/model"
// UDM鉴权信息 服务层接口
type IUDMAuth interface {
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
ResetData(neId string) int64
// SelectPage 分页查询数据库
SelectPage(query map[string]any) map[string]any
// SelectList 查询数据库
SelectList(u model.UDMAuth) []model.UDMAuth
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度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
}

View File

@@ -0,0 +1,146 @@
package service
import (
"fmt"
"strings"
"be.ems/src/framework/redis"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
)
// 实例化服务层 UDMAuthImpl 结构体
var NewUDMAuthImpl = &UDMAuthImpl{
udmAuthRepository: repository.NewUDMAuthImpl,
}
// UDM鉴权信息 服务层处理
type UDMAuthImpl struct {
// UDM鉴权信息数据信息
udmAuthRepository repository.IUDMAuth
}
// dataByRedis UDM鉴权用户 db:0 中 ausf:*
func (r *UDMAuthImpl) dataByRedis(imsi, neId string) []model.UDMAuth {
arr := []model.UDMAuth{}
key := fmt.Sprintf("ausf:%s", imsi)
ausfArr, err := redis.GetKeys("udmuser", key)
if err != nil {
return arr
}
for _, key := range ausfArr {
m, err := redis.GetHash("udmuser", key)
if err != nil {
continue
}
// 跳过-号数据
imsi := key[5:]
if strings.Contains(imsi, "-") {
continue
}
amf := ""
if v, ok := m["amf"]; ok {
amf = strings.Replace(v, "\r\n", "", 1)
}
a := model.UDMAuth{
IMSI: imsi,
Amf: amf,
Status: "1", // 默认给1
Ki: m["ki"],
AlgoIndex: m["algo"],
Opc: m["opc"],
NeId: neId,
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
func (r *UDMAuthImpl) ResetData(neId string) int64 {
authArr := r.dataByRedis("*", neId)
// 数据清空后添加
go r.udmAuthRepository.ClearAndInsert(neId, authArr)
return int64(len(authArr))
}
// SelectPage 分页查询数据库
func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
return r.udmAuthRepository.SelectPage(query)
}
// SelectList 查询数据库
func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth {
return r.udmAuthRepository.SelectList(u)
}
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度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
}

View File

@@ -0,0 +1,28 @@
package service
import "be.ems/src/modules/network_data/model"
// UDM签约用户信息 服务层接口
type IUDMSub interface {
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
ResetData(neId string) int64
// SelectPage 分页查询数据库
SelectPage(query map[string]any) map[string]any
// SelectList 查询数据库
SelectList(u model.UDMSub) []model.UDMSub
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度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
}

View File

@@ -0,0 +1,164 @@
package service
import (
"fmt"
"strings"
"be.ems/src/framework/redis"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
)
// 实例化服务层 UDMSubImpl 结构体
var NewUDMSubImpl = &UDMSubImpl{
udmSubRepository: repository.NewUDMSubImpl,
}
// UDM签约信息 服务层处理
type UDMSubImpl struct {
// UDM签约信息数据信息
udmSubRepository repository.IUDMSub
}
// dataByRedis UDM签约用户 db:0 中 udm-sd:*
func (r *UDMSubImpl) dataByRedis(imsi, neId string) []model.UDMSub {
arr := []model.UDMSub{}
key := fmt.Sprintf("udm-sd:%s", imsi)
udmsdArr, err := redis.GetKeys("udmuser", key)
if err != nil {
return arr
}
for _, key := range udmsdArr {
m, err := redis.GetHash("udmuser", key)
if err != nil {
continue
}
a := model.UDMSub{
IMSI: key[7:],
Msisdn: m["gpsi"], // 46003550072
SmfSel: m["smf-sel"],
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
NeId: neId,
}
// def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,-
if v, ok := m["am-dat"]; ok {
arr := strings.Split(v, ",")
a.Ambr = arr[0]
a.Nssai = arr[1]
a.Rat = arr[2]
a.Arfb = arr[3]
a.Sar = arr[4]
a.Cn = arr[5]
}
// 1,64,24,65,def_eps,1,2,010200000000,-
if v, ok := m["eps-dat"]; ok {
arr := strings.Split(v, ",")
// 跳过非常规数据
if len(arr) > 9 {
continue
}
a.EpsDat = v
a.EpsFlag = arr[0]
a.EpsOdb = arr[1]
a.HplmnOdb = arr[2]
a.Ard = arr[3]
a.Epstpl = arr[4]
a.ContextId = arr[5]
a.ApnContext = arr[7]
// [6] 是不要的,导入和导出不用
a.StaticIp = arr[8]
}
arr = append(arr, a)
}
return arr
}
// ResetData 重置鉴权用户数据清空数据库重新同步Redis数据
func (r *UDMSubImpl) ResetData(neId string) int64 {
subArr := r.dataByRedis("*", neId)
// 数据清空后添加
go r.udmSubRepository.ClearAndInsert(neId, subArr)
return int64(len(subArr))
}
// SelectPage 分页查询数据库
func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
return r.udmSubRepository.SelectPage(query)
}
// SelectList 查询数据库
func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub {
return r.udmSubRepository.SelectList(u)
}
// Insert 从数据中读取后删除imsi再存入数据库
// imsi长度15ki长度32opc长度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
}

View File

@@ -2,10 +2,10 @@ package service
import "be.ems/src/modules/network_data/model"
// UE会话事件 服务层接口
type IUEEvent interface {
// UE会话事件AMF 服务层接口
type IUEEventAMF interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.UEEventQuery) map[string]any
SelectPage(querys model.UEEventAMFQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(ueIds []string) (int64, error)

View File

@@ -7,24 +7,24 @@ import (
"be.ems/src/modules/network_data/repository"
)
// 实例化数据层 UEEventImpl 结构体
var NewUEEventImpl = &UEEventImpl{
ueEventRepository: repository.NewUEEventImpl,
// 实例化数据层 UEEventMMEImpl 结构体
var NewUEEventMMEImpl = &UEEventMMEImpl{
ueEventRepository: repository.NewUEEventMMEImpl,
}
// UEEventImpl UE会话事件 服务层处理
type UEEventImpl struct {
// UEEventMMEImpl UE会话事件MME 服务层处理
type UEEventMMEImpl struct {
// UE会话事件数据信息
ueEventRepository repository.IUEEvent
ueEventRepository repository.IUEEventMME
}
// SelectPage 根据条件分页查询
func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any {
func (r *UEEventMMEImpl) SelectPage(querys model.UEEventMMEQuery) map[string]any {
return r.ueEventRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *UEEventImpl) DeleteByIds(ueIds []string) (int64, error) {
func (r *UEEventMMEImpl) DeleteByIds(ueIds []string) (int64, error) {
// 检查是否存在
ids := r.ueEventRepository.SelectByIds(ueIds)
if len(ids) <= 0 {

View File

@@ -0,0 +1,12 @@
package service
import "be.ems/src/modules/network_data/model"
// UE会话事件MME 服务层接口
type IUEEventMME interface {
// SelectPage 根据条件分页查询
SelectPage(querys model.UEEventMMEQuery) map[string]any
// DeleteByIds 批量删除信息
DeleteByIds(ueIds []string) (int64, error)
}

View File

@@ -0,0 +1,40 @@
package service
import (
"fmt"
"be.ems/src/modules/network_data/model"
"be.ems/src/modules/network_data/repository"
)
// 实例化数据层 UEEventAMFImpl 结构体
var NewUEEventAMFImpl = &UEEventAMFImpl{
ueEventRepository: repository.NewUEEventAMFImpl,
}
// UEEventAMFImpl UE会话事件AMF 服务层处理
type UEEventAMFImpl struct {
// UE会话事件数据信息
ueEventRepository repository.IUEEventAMF
}
// SelectPage 根据条件分页查询
func (r *UEEventAMFImpl) SelectPage(querys model.UEEventAMFQuery) map[string]any {
return r.ueEventRepository.SelectPage(querys)
}
// DeleteByIds 批量删除信息
func (r *UEEventAMFImpl) DeleteByIds(ueIds []string) (int64, error) {
// 检查是否存在
ids := r.ueEventRepository.SelectByIds(ueIds)
if len(ids) <= 0 {
return 0, fmt.Errorf("no data")
}
if len(ids) == len(ueIds) {
rows := r.ueEventRepository.DeleteByIds(ueIds)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}

View File

@@ -3,6 +3,7 @@ package controller
import (
"fmt"
"path/filepath"
"runtime"
"strings"
"be.ems/src/framework/i18n"
@@ -50,19 +51,30 @@ func (s *NeActionController) PushFile(c *gin.Context) {
return
}
// 本地文件
localPath := file.ParseUploadFilePath(body.UploadPath)
nePath := "/tmp" //config.Get("mml.upload").(string)
// 复制到远程
err := ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath)
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
// 本地文件
localFilePath := file.ParseUploadFilePath(body.UploadPath)
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
// 复制到远程
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
c.JSON(200, result.ErrMsg(fmt.Sprintf("%s : please check if scp remote copy is allowed", neInfo.NeType)))
return
}
// 网元端文件路径
fileName := localPath[strings.LastIndex(localPath, "/")+1:]
neFilePath := fmt.Sprintf("%s/%s", nePath, fileName)
c.JSON(200, result.OkData(filepath.ToSlash(neFilePath)))
}
@@ -89,14 +101,32 @@ func (s *NeActionController) PullFile(c *gin.Context) {
return
}
nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName)
localPath := fmt.Sprintf("/tmp/omc/pullFile/%s", querys.FileName)
err := ssh.FileSCPNeToLocal(neInfo.IP, nePath, localPath)
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.FileAttachment(localPath, querys.FileName)
defer sshClient.Close()
// 网元主机的SSH客户端进行文件传输
sftpClient, err := sshClient.NewClientSFTP()
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer sftpClient.Close()
nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName)
localFilePath := fmt.Sprintf("/tmp/omc/pullFile%s", nePath)
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
}
c.FileAttachment(localFilePath, querys.FileName)
}
// 网元端文件列表
@@ -124,7 +154,16 @@ func (s *NeActionController) Files(c *gin.Context) {
return
}
totalSize, rows, err := ssh.FileList(querys.Path, neInfo.IP, querys.Search)
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
defer sshClient.Close()
// 获取文件列表
totalSize, rows, err := ssh.FileList(sshClient, querys.Path, querys.Search)
if err != nil {
c.JSON(200, result.Ok(map[string]any{
"path": querys.Path,
@@ -184,7 +223,7 @@ func (s *NeActionController) Service(c *gin.Context) {
cmdStr = fmt.Sprintf("nohup sh -c \"sudo systemctl stop restagent && sleep 5s && sudo systemctl %s restagent\" > /dev/null 2>&1 &", body.Action)
} else if neTypeLower == "ims" {
if body.Action == "restart" {
cmdStr = "sudo ims-stop || true && sudo ims-start"
cmdStr = "ims-stop || true && ims-start"
} else {
cmdStr = fmt.Sprintf("sudo ims-%s", body.Action)
}
@@ -197,7 +236,7 @@ func (s *NeActionController) Service(c *gin.Context) {
cmdStr = "sudo shutdown -h now"
}
_, err := s.neInfoService.NeRunCMD(body.NeType, body.NeID, cmdStr)
_, err := s.neInfoService.NeRunSSHCmd(body.NeType, body.NeID, cmdStr)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return

View File

@@ -0,0 +1,202 @@
package controller
import (
"encoding/json"
"strings"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
neFetchlink "be.ems/src/modules/network_element/fetch_link"
"be.ems/src/modules/network_element/model"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// NewNeConfig 网元参数配置 实例化控制层
var NewNeConfig = &NeConfigController{
neConfigService: neService.NewNeConfigImpl,
neInfoService: neService.NewNeInfoImpl,
}
// 网元参数配置
//
// PATH /config
type NeConfigController struct {
// 网元参数配置可用属性值服务
neConfigService neService.INeConfig
// 网元信息服务
neInfoService neService.INeInfo
}
// 网元参数配置可用属性值列表
//
// GET /list
func (s *NeConfigController) List(c *gin.Context) {
querys := ctx.QueryMap(c)
data := s.neConfigService.SelectPage(querys)
c.JSON(200, result.Ok(data))
}
// 网元参数配置可用属性值信息
//
// GET /info/:id
func (s *NeConfigController) 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.neConfigService.SelectById(id)
if data.ID != id {
// 没有可访问参数配置数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neConfig.noData")))
return
}
// 将字符串转json数据
if err := json.Unmarshal([]byte(data.ParamJSONStr), &data.ParamData); err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
return
}
c.JSON(200, result.OkData(data))
}
// 网元参数配置可用属性值新增
//
// POST /
func (s *NeConfigController) Add(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeConfig
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 将json数据转字符串存储
paramDataByte, err := json.Marshal(body.ParamData)
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
return
}
body.ParamJSONStr = string(paramDataByte)
insertId := s.neConfigService.Insert(body)
if insertId != "" {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元参数配置可用属性值修改
//
// PUT /
func (s *NeConfigController) Edit(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var body model.NeConfig
err := c.ShouldBindBodyWith(&body, binding.JSON)
if err != nil || body.ID == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 检查是否存在
data := s.neConfigService.SelectById(body.ID)
if data.ID != body.ID {
// 没有可访问主机命令数据!
c.JSON(200, result.ErrMsg(i18n.TKey(language, "neConfig.noData")))
return
}
// 将json数据转字符串存储
paramDataByte, err := json.Marshal(body.ParamData)
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
return
}
body.ParamJSONStr = string(paramDataByte)
rows := s.neConfigService.Update(body)
if rows > 0 {
c.JSON(200, result.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
}
// 网元参数配置可用属性值删除
//
// DELETE /:ids
func (s *NeConfigController) Remove(c *gin.Context) {
language := ctx.AcceptLanguage(c)
ids := c.Param("ids")
if ids == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 处理字符转id数组后去重
idsArr := strings.Split(ids, ",")
uniqueIDs := parse.RemoveDuplicates(idsArr)
if len(uniqueIDs) <= 0 {
c.JSON(200, result.Err(nil))
return
}
rows, err := s.neConfigService.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))
}
// 网元参数配置可用属性值列表指定网元类型全部无分页
//
// GET /list/:neType
func (s *NeConfigController) ListByNeType(c *gin.Context) {
language := ctx.AcceptLanguage(c)
neType := c.Param("neType")
if neType == "" {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
data := s.neConfigService.SelectNeConfigByNeType(neType)
c.JSON(200, result.OkData(data))
}
// 网元参数配置数据信息
//
// GET /data
func (s *NeConfigController) Data(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var querys struct {
NeType string `form:"neType" binding:"required"` // 网元类型
NeId string `form:"neId" binding:"required"` // 网元ID
TopTag string `form:"topTag" binding:"required"` // 可用属性
}
if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
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
}
// 网元直连
resData, err := neFetchlink.NeConfigInfo(neInfo, querys.TopTag)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
c.JSON(200, result.Ok(resData))
}

View File

@@ -203,6 +203,7 @@ func (s *NeHostController) Test(c *gin.Context) {
return
}
defer client.Close()
// 是否有终止符
if strings.HasSuffix(client.LastResult, ">") || strings.HasSuffix(client.LastResult, "> ") || strings.HasSuffix(client.LastResult, "# ") {
c.JSON(200, result.Ok(nil))
} else {

View File

@@ -9,6 +9,7 @@ import (
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
neFetchlink "be.ems/src/modules/network_element/fetch_link"
"be.ems/src/modules/network_element/model"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
@@ -60,7 +61,7 @@ func (s *NeInfoController) State(c *gin.Context) {
neKey := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)
// 网元直连
resData, err := neService.NeState(neInfo)
resData, err := neFetchlink.NeState(neInfo)
if err != nil {
mutex.Lock()
// 异常取上次缓存
@@ -287,12 +288,12 @@ func (s *NeInfoController) Add(c *gin.Context) {
}
// 获取网元状态是否正常
body.ServerState, err = neService.NeState(body)
body.ServerState, err = neFetchlink.NeState(body)
if err != nil {
body.Status = "0"
} else {
// 下发网管配置信息给网元
_, err = neService.NeConfigOMC(body)
_, err = neFetchlink.NeConfigOMC(body)
if err == nil {
body.Status = "1"
} else {
@@ -376,12 +377,12 @@ func (s *NeInfoController) Edit(c *gin.Context) {
}
// 获取网元状态是否正常
body.ServerState, err = neService.NeState(body)
body.ServerState, err = neFetchlink.NeState(body)
if err != nil {
body.Status = "0"
} else {
// 下发网管配置信息给网元
_, err = neService.NeConfigOMC(body)
_, err = neFetchlink.NeConfigOMC(body)
if err == nil {
body.Status = "1"
} else {

View File

@@ -6,6 +6,7 @@ import (
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/vo/result"
neFetchlink "be.ems/src/modules/network_element/fetch_link"
"be.ems/src/modules/network_element/model"
neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin"
@@ -18,17 +19,17 @@ var NewNeLicense = &NeLicenseController{
neInfoService: neService.NewNeInfoImpl,
}
// 网元授权激活信息请求
// 网元授权激活请求
//
// PATH /license
type NeLicenseController struct {
// 网元授权激活信息服务
// 网元授权激活服务
neLicenseService neService.INeLicense
// 网元信息服务
neInfoService neService.INeInfo
}
// 网元授权激活信息列表
// 网元授权激活列表
//
// GET /list
func (s *NeLicenseController) List(c *gin.Context) {
@@ -198,7 +199,7 @@ func (s *NeLicenseController) State(c *gin.Context) {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return
}
if neState, err := neService.NeState(neInfo); err == nil {
if neState, err := neFetchlink.NeState(neInfo); err == nil && neState["sn"] != nil {
neLicense.Status = "1"
neLicense.SerialNum = fmt.Sprint(neState["sn"])
neLicense.ExpiryDate = fmt.Sprint(neState["expire"])

View File

@@ -18,15 +18,15 @@ var NewNeSoftware = &NeSoftwareController{
neSoftwareService: neService.NewNeSoftwareImpl,
}
// 网元软件包信息请求
// 网元软件包请求
//
// PATH /software
type NeSoftwareController struct {
// 网元软件包信息服务
// 网元软件包服务
neSoftwareService neService.INeSoftware
}
// 网元软件包信息列表
// 网元软件包列表
//
// GET /list
func (s *NeSoftwareController) List(c *gin.Context) {
@@ -36,7 +36,7 @@ func (s *NeSoftwareController) List(c *gin.Context) {
c.JSON(200, result.Ok(data))
}
// 网元软件包信息信息
// 网元软件包信息
//
// GET /:softwareId
func (s *NeSoftwareController) Info(c *gin.Context) {
@@ -57,7 +57,7 @@ func (s *NeSoftwareController) Info(c *gin.Context) {
c.JSON(200, result.OkData(neSoftware))
}
// 网元软件包信息新增
// 网元软件包新增
//
// POST /
func (s *NeSoftwareController) Add(c *gin.Context) {
@@ -98,7 +98,7 @@ func (s *NeSoftwareController) Add(c *gin.Context) {
c.JSON(200, result.Err(nil))
}
// 网元软件包信息修改
// 网元软件包修改
//
// PUT /
func (s *NeSoftwareController) Edit(c *gin.Context) {
@@ -136,7 +136,7 @@ func (s *NeSoftwareController) Edit(c *gin.Context) {
c.JSON(200, result.Err(nil))
}
// 网元软件包信息删除
// 网元软件包删除
//
// DELETE /:softwareIds
func (s *NeSoftwareController) Remove(c *gin.Context) {

View File

@@ -14,15 +14,15 @@ var NewNeVersion = &NeVersionController{
neVersionService: neService.NewNeVersionImpl,
}
// 网元版本信息请求
// 网元版本请求
//
// PATH /version
type NeVersionController struct {
// 网元版本信息服务
// 网元版本服务
neVersionService neService.INeVersion
}
// 网元版本信息列表
// 网元版本列表
//
// GET /list
func (s *NeVersionController) List(c *gin.Context) {
@@ -32,7 +32,7 @@ func (s *NeVersionController) List(c *gin.Context) {
c.JSON(200, result.Ok(data))
}
// 网元版本信息信息
// 网元版本信息
//
// GET /:versionId
func (s *NeVersionController) Info(c *gin.Context) {

View File

@@ -1,50 +1,15 @@
package service
package fetchlink
import (
"encoding/json"
"fmt"
"strings"
"time"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/fetch"
"be.ems/src/modules/network_element/model"
)
// NeState 获取网元端服务状态
func NeState(neInfo model.NeInfo) (map[string]any, error) {
// 网元状态
neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType))
resBytes, err := fetch.Get(neUrl, nil, 1000)
if err != nil {
logger.Warnf("NeState %s", err.Error())
return nil, err
}
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Warnf("NeState Unmarshal %s", err.Error())
return nil, err
}
return map[string]any{
"neType": neInfo.NeType,
"neId": neInfo.NeId,
"neName": neInfo.NeName,
"neIP": neInfo.IP,
"refreshTime": time.Now().UnixMilli(), // 获取时间
"version": resData["version"],
"capability": resData["capability"],
"sn": resData["serialNum"],
"expire": resData["expiryDate"],
"cpu": resData["cpuUsage"],
"mem": resData["memUsage"],
"disk": resData["diskSpace"],
}, nil
}
// NeConfigOMC 网元配置对端网管信息
func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) {
// 网元配置对端网管信息
@@ -83,3 +48,23 @@ func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) {
return resData, nil
}
// NeConfigInfo 网元配置信息
func NeConfigInfo(neInfo model.NeInfo, name 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), name)
resBytes, err := fetch.Get(neUrl, nil, 1000)
if err != nil {
logger.Warnf("NeConfigInfo %s Get \"%s\"", err.Error(), neUrl)
return nil, err
}
// 序列化结果
var resData map[string]any
err = json.Unmarshal(resBytes, &resData)
if err != nil {
logger.Warnf("NeConfigInfo Unmarshal %s", err.Error())
return nil, err
}
return resData, nil
}

View File

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

View File

@@ -0,0 +1,21 @@
package model
// NeConfig 网元参数配置可用属性值
type NeConfig struct {
ID string `json:"id" gorm:"id"`
NeType string `json:"neType" binding:"required" gorm:"ne_type"` // 网元类型
NeId string `json:"-" gorm:"ne_id"`
TopTag string `json:"topTag" binding:"required" gorm:"top_tag"`
TopDisplay string `json:"topDisplay" binding:"required" gorm:"top_display"`
Method string `json:"method" gorm:"method"` // 操作属性 get只读强制不可编辑删除 put可编辑 delete可删除 post可新增
ParamJSONStr string `json:"-" gorm:"param_json"` // accesss属性控制只读read-only/read/ro 读写read-write
// ====== 非数据库字段属性 ======
ParamData map[string]any `json:"paramData,omitempty" binding:"required" gorm:"-"` // 与ParamJSONStr配合转换
}
// TableName 表名称
func (*NeConfig) TableName() string {
return "param_config"
}

View File

@@ -15,7 +15,6 @@ type NeSoftware struct {
// ====== 非数据库字段属性 ======
NeId string `json:"neId,omitempty" gorm:"-"` // 网元ID
}
// TableName 表名称

View File

@@ -4,7 +4,6 @@ import (
"be.ems/src/framework/logger"
"be.ems/src/framework/middleware"
"be.ems/src/framework/middleware/collectlogs"
"be.ems/src/framework/middleware/repeat"
"be.ems/src/modules/network_element/controller"
"be.ems/src/modules/network_element/service"
@@ -258,111 +257,39 @@ func Setup(router *gin.Engine) {
)
}
// UDM鉴权用户信息
udmAuthGroup := neGroup.Group("/udm/auth")
// 网元参数配置
neConfigGroup := neGroup.Group("/config")
{
udmAuthGroup.PUT("/resetData/:neId",
repeat.RepeatSubmit(5),
neConfigGroup.GET("/list",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMAuth.ResetData,
controller.NewNeConfig.List,
)
udmAuthGroup.GET("/list",
neConfigGroup.GET("/info/:id",
middleware.PreAuthorize(nil),
controller.NewUDMAuth.List,
controller.NewNeConfig.Info,
)
udmAuthGroup.GET("/:neId/:imsi",
neConfigGroup.POST("",
middleware.PreAuthorize(nil),
controller.NewUDMAuth.Info,
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewNeConfig.Add,
)
udmAuthGroup.POST("/:neId",
neConfigGroup.PUT("",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMAuth.Add,
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewNeConfig.Edit,
)
udmAuthGroup.POST("/:neId/:num",
neConfigGroup.DELETE("/:ids",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMAuth.Adds,
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewNeConfig.Remove,
)
udmAuthGroup.PUT("/:neId",
neConfigGroup.GET("/list/:neType",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMAuth.Edit,
controller.NewNeConfig.ListByNeType,
)
udmAuthGroup.DELETE("/:neId/:imsi",
neConfigGroup.GET("/data",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMAuth.Remove,
)
udmAuthGroup.DELETE("/:neId/:imsi/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMAuth.Removes,
)
udmAuthGroup.POST("/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMAuth.Export,
)
udmAuthGroup.POST("/import",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMAuth.Import,
)
}
// UDM签约用户信息
udmSubGroup := neGroup.Group("/udm/sub")
{
udmSubGroup.PUT("/resetData/:neId",
repeat.RepeatSubmit(5),
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)),
controller.NewUDMSub.ResetData,
)
udmSubGroup.GET("/list",
middleware.PreAuthorize(nil),
controller.NewUDMSub.List,
)
udmSubGroup.GET("/:neId/:imsi",
middleware.PreAuthorize(nil),
controller.NewUDMSub.Info,
)
udmSubGroup.POST("/:neId",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMSub.Add,
)
udmSubGroup.POST("/:neId/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
controller.NewUDMSub.Adds,
)
udmSubGroup.PUT("/:neId",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)),
controller.NewUDMSub.Edit,
)
udmSubGroup.DELETE("/:neId/:imsi",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMSub.Remove,
)
udmSubGroup.DELETE("/:neId/:imsi/:num",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewUDMSub.Removes,
)
udmSubGroup.POST("/export",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)),
controller.NewUDMSub.Export,
)
udmSubGroup.POST("/import",
middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)),
controller.NewUDMSub.Import,
controller.NewNeConfig.Data,
)
}
}
@@ -376,4 +303,7 @@ func InitLoad() {
if para5GMap, err := service.NewNeInfoImpl.NeConfPara5GRead(); para5GMap != nil && err == nil {
service.NewNeInfoImpl.NeConfPara5GWirte(para5GMap, nil)
}
// 启动时,清除缓存-网元参数配置可用属性值
service.NewNeConfigImpl.ClearNeCacheByNeType("*")
service.NewNeConfigImpl.RefreshByNeTypeAndNeID("*")
}

View File

@@ -0,0 +1,24 @@
package repository
import "be.ems/src/modules/network_element/model"
// INeConfig 网元参数配置可用属性值 数据层接口
type INeConfig interface {
// SelectPage 根据条件分页查询字典类型
SelectPage(query map[string]any) map[string]any
// SelectList 根据实体查询
SelectList(param model.NeConfig) []model.NeConfig
// SelectByIds 通过ID查询
SelectByIds(ids []string) []model.NeConfig
// Insert 新增信息
Insert(param model.NeConfig) string
// Update 修改信息
Update(param model.NeConfig) int64
// DeleteByIds 批量删除信息
DeleteByIds(ids []string) int64
}

View File

@@ -0,0 +1,254 @@
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/network_element/model"
)
// NewNeConfigImpl 网元参数配置可用属性值 实例化数据层
var NewNeConfigImpl = &NeConfigImpl{
selectSql: `select
id, ne_type, ne_id, top_tag, top_display, method, param_json
from param_config`,
resultMap: map[string]string{
"id": "ID",
"ne_type": "NeType",
"ne_id": "NeId",
"top_tag": "TopTag",
"top_display": "TopDisplay",
"method": "Method",
"param_json": "ParamJSONStr",
},
}
// NeConfigImpl 网元参数配置可用属性值 数据层处理
type NeConfigImpl struct {
// 查询视图对象SQL
selectSql string
// 结果字段与实体映射
resultMap map[string]string
}
// convertResultRows 将结果记录转实体结果组
func (r *NeConfigImpl) convertResultRows(rows []map[string]any) []model.NeConfig {
arr := make([]model.NeConfig, 0)
for _, row := range rows {
item := model.NeConfig{}
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 *NeConfigImpl) 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["topTag"]; ok && v != "" {
conditions = append(conditions, "top_tag = ?")
params = append(params, v)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
result := map[string]any{
"total": 0,
"rows": []model.NeHost{},
}
// 查询数量 长度为0直接返回
totalSql := "select count(id) as 'total' from param_config"
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)
return result
}
// 转换实体
result["rows"] = r.convertResultRows(results)
return result
}
// SelectList 根据实体查询
func (r *NeConfigImpl) SelectList(param model.NeConfig) []model.NeConfig {
// 查询条件拼接
var conditions []string
var params []any
if param.NeType != "" {
conditions = append(conditions, "ne_type = ?")
params = append(params, param.NeType)
}
if param.TopTag != "" {
conditions = append(conditions, "top_tag = ?")
params = append(params, param.TopTag)
}
// 构建查询条件语句
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
}
// 查询数据
querySql := r.selectSql + whereSql + " order by id asc "
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)
}
// 转换实体
return r.convertResultRows(results)
}
// SelectByIds 通过ID查询
func (r *NeConfigImpl) SelectByIds(ids []string) []model.NeConfig {
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.NeConfig{}
}
// 转换实体
return r.convertResultRows(results)
}
// Insert 新增信息
func (r *NeConfigImpl) Insert(param model.NeConfig) string {
// 参数拼接
params := make(map[string]any)
if param.NeType != "" {
params["ne_type"] = param.NeType
}
if param.NeId != "" {
params["ne_id"] = param.NeId
}
if param.TopTag != "" {
params["top_tag"] = param.TopTag
}
if param.TopDisplay != "" {
params["top_display"] = param.TopDisplay
}
if param.Method != "" {
params["method"] = param.Method
}
if param.ParamJSONStr != "" {
params["param_json"] = param.ParamJSONStr
}
// 构建执行语句
keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params)
sql := "insert into param_config (" + 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 *NeConfigImpl) Update(param model.NeConfig) int64 {
// 参数拼接
params := make(map[string]any)
if param.NeType != "" {
params["ne_type"] = param.NeType
}
if param.NeId != "" {
params["ne_id"] = param.NeId
}
if param.TopTag != "" {
params["top_tag"] = param.TopTag
}
if param.TopDisplay != "" {
params["top_display"] = param.TopDisplay
}
if param.Method != "" {
params["method"] = param.Method
}
if param.ParamJSONStr != "" {
params["param_json"] = param.ParamJSONStr
}
// 构建执行语句
keys, values := repo.KeyValueByUpdate(params)
sql := "update param_config set " + strings.Join(keys, ",") + " where id = ?"
// 执行更新
values = append(values, param.ID)
rows, err := datasource.ExecDB("", sql, values)
if err != nil {
logger.Errorf("update row : %v", err.Error())
return 0
}
return rows
}
// DeleteByIds 批量删除信息
func (r *NeConfigImpl) DeleteByIds(ids []string) int64 {
placeholder := repo.KeyPlaceholderByQuery(len(ids))
sql := "delete from param_config 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
}

View File

@@ -1,26 +0,0 @@
package repository
import (
"be.ems/src/modules/network_element/model"
)
// UDM鉴权信息 数据层接口
type IUDMAuth interface {
// ClearAndInsert 清空ne_id后新增实体
ClearAndInsert(neID string, authArr []model.UDMAuth) int64
// SelectPage 根据条件分页查询
SelectPage(query map[string]any) map[string]any
// SelectList 根据实体查询
SelectList(auth model.UDMAuth) []model.UDMAuth
// Insert 批量添加
Inserts(authUsers []model.UDMAuth) int64
// Delete 删除实体
Delete(neID, imsi string) int64
// DeletePrefixImsi 删除前缀匹配的实体
DeletePrefixImsi(neID, imsi string) int64
}

View File

@@ -1,35 +0,0 @@
package repository
import (
"be.ems/src/modules/network_element/model"
)
// UDM签约信息 数据层接口
type IUDMSub interface {
// ClearAndInsert 清空ne_id后新增实体
ClearAndInsert(neID string, subArr []model.UDMSub) int64
// SelectPage 根据条件分页查询字典类型
SelectPage(query map[string]any) map[string]any
// SelectList 根据实体查询
SelectList(subUser model.UDMSub) []model.UDMSub
// Insert 新增实体
Insert(subUser model.UDMSub) string
// Insert 批量添加
Inserts(subUser []model.UDMSub) int64
// Update 修改更新
Update(neID string, subUser model.UDMSub) int64
// Delete 删除实体
Delete(neID, imsi string) int64
// DeletePrefixImsi 删除前缀匹配的实体
DeletePrefixImsi(neID, imsi string) int64
// Delete 删除范围实体
Deletes(neID, imsi, num string) int64
}

View File

@@ -0,0 +1,33 @@
package service
import "be.ems/src/modules/network_element/model"
// INeConfig 网元参数配置可用属性值 服务层接口
type INeConfig interface {
// RefreshByNeType 通过ne_type刷新redis中的缓存
RefreshByNeTypeAndNeID(neType string) []model.NeConfig
// ClearNeCacheByNeType 清除网元类型参数配置缓存
ClearNeCacheByNeType(neType string) bool
// SelectNeConfigByNeType 查询网元类型参数配置
SelectNeConfigByNeType(neType string) []model.NeConfig
// SelectNeHostPage 分页查询列表数据
SelectPage(query map[string]any) map[string]any
// SelectList 根据实体查询
SelectList(param model.NeConfig) []model.NeConfig
// SelectByIds 通过ID查询
SelectById(id string) model.NeConfig
// Insert 新增信息
Insert(param model.NeConfig) string
// Update 修改信息
Update(param model.NeConfig) int64
// DeleteByIds 批量删除信息
DeleteByIds(ids []string) (int64, error)
}

View File

@@ -0,0 +1,151 @@
package service
import (
"encoding/json"
"fmt"
"strings"
"be.ems/src/framework/constants/cachekey"
"be.ems/src/framework/redis"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
// NewNeConfigImpl 网元参数配置可用属性值 实例化服务层
var NewNeConfigImpl = &NeConfigImpl{
neConfigRepository: repository.NewNeConfigImpl,
}
// NeConfigImpl 网元参数配置可用属性值 服务层处理
type NeConfigImpl struct {
// 网元参数配置可用属性值表
neConfigRepository repository.INeConfig
}
// RefreshByNeType 通过ne_type刷新redis中的缓存
func (r *NeConfigImpl) RefreshByNeTypeAndNeID(neType string) []model.NeConfig {
// 多个
if neType == "" || neType == "*" {
neConfigList := r.neConfigRepository.SelectList(model.NeConfig{})
if len(neConfigList) > 0 {
neConfigGroup := map[string][]model.NeConfig{}
for _, v := range neConfigList {
if item, ok := neConfigGroup[v.NeType]; ok {
neConfigGroup[v.NeType] = append(item, v)
} else {
neConfigGroup[v.NeType] = []model.NeConfig{v}
}
}
for k, v := range neConfigGroup {
key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(k))
redis.Del("", key)
if len(v) > 0 {
for i, item := range v {
if err := json.Unmarshal([]byte(item.ParamJSONStr), &item.ParamData); err != nil {
continue
}
v[i] = item
}
values, _ := json.Marshal(v)
redis.Set("", key, string(values))
}
}
}
return neConfigList
}
// 单个
key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(neType))
redis.Del("", key)
neConfigList := r.neConfigRepository.SelectList(model.NeConfig{
NeType: neType,
})
if len(neConfigList) > 0 {
for i, v := range neConfigList {
if err := json.Unmarshal([]byte(v.ParamJSONStr), &v.ParamData); err != nil {
continue
}
neConfigList[i] = v
}
values, _ := json.Marshal(neConfigList)
redis.Set("", key, string(values))
}
return neConfigList
}
// ClearNeCacheByNeType 清除网元类型参数配置缓存
func (r *NeConfigImpl) ClearNeCacheByNeType(neType string) bool {
key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, neType)
if neType == "*" {
key = fmt.Sprintf("%sparam_config:*", cachekey.NE_DATA_KEY)
}
keys, err := redis.GetKeys("", key)
if err != nil {
return false
}
delOk, _ := redis.DelKeys("", keys)
return delOk
}
// SelectNeConfigByNeType 查询网元类型参数配置
func (r *NeConfigImpl) SelectNeConfigByNeType(neType string) []model.NeConfig {
var neConfigList []model.NeConfig
key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(neType))
jsonStr, _ := redis.Get("", key)
if len(jsonStr) > 7 {
err := json.Unmarshal([]byte(jsonStr), &neConfigList)
if err != nil {
neConfigList = []model.NeConfig{}
}
} else {
neConfigList = r.RefreshByNeTypeAndNeID(neType)
}
return neConfigList
}
// SelectNeHostPage 分页查询列表数据
func (r *NeConfigImpl) SelectPage(query map[string]any) map[string]any {
return r.neConfigRepository.SelectPage(query)
}
// SelectConfigList 查询列表
func (r *NeConfigImpl) SelectList(param model.NeConfig) []model.NeConfig {
return r.neConfigRepository.SelectList(param)
}
// SelectByIds 通过ID查询
func (r *NeConfigImpl) SelectById(id string) model.NeConfig {
if id == "" {
return model.NeConfig{}
}
neHosts := r.neConfigRepository.SelectByIds([]string{id})
if len(neHosts) > 0 {
return neHosts[0]
}
return model.NeConfig{}
}
// Insert 新增信息
func (r *NeConfigImpl) Insert(param model.NeConfig) string {
return r.neConfigRepository.Insert(param)
}
// Update 修改信息
func (r *NeConfigImpl) Update(param model.NeConfig) int64 {
return r.neConfigRepository.Update(param)
}
// DeleteByIds 批量删除信息
func (r *NeConfigImpl) DeleteByIds(ids []string) (int64, error) {
// 检查是否存在
data := r.neConfigRepository.SelectByIds(ids)
if len(data) <= 0 {
return 0, fmt.Errorf("param.noData")
}
if len(data) == len(ids) {
rows := r.neConfigRepository.DeleteByIds(ids)
return rows, nil
}
// 删除信息失败!
return 0, fmt.Errorf("delete fail")
}

View File

@@ -2,6 +2,7 @@ package service
import (
"be.ems/src/framework/utils/ssh"
"be.ems/src/framework/utils/telnet"
"be.ems/src/modules/network_element/model"
)
@@ -47,11 +48,15 @@ type INeInfo interface {
// CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一
CheckUniqueNeTypeAndNeId(neType, neId, id string) bool
// NeRunSSHclient 网元主机的SSH客户端-为创建相关连接
NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error)
// NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close()
NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error)
// NeRunCMD 向网元发送cmd命令
NeRunCMD(neType, neId, cmd string) (string, error)
// NeRunSSHCmd 网元主机的SSH客户端发送cmd命令
NeRunSSHCmd(neType, neId, cmd string) (string, error)
// NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close()
// num 是网元主机telnet 14100 25200
NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error)
// neConfOAMRead 网元OAM配置文件读取
NeConfOAMRead(neType, neId string) (map[string]any, error)

View File

@@ -13,6 +13,8 @@ import (
"be.ems/src/framework/redis"
"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"
)
@@ -148,7 +150,7 @@ func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool, bandHost bool)
func (r *NeInfoImpl) bandNeStatus(arr *[]model.NeInfo) {
for i := range *arr {
v := (*arr)[i]
result, err := NeState(v)
result, err := neFetchlink.NeState(v)
if err != nil {
(*arr)[i].ServerState = map[string]any{
"online": false,
@@ -166,7 +168,7 @@ func (r *NeInfoImpl) bandNeStatus(arr *[]model.NeInfo) {
// 网元状态设置为在线
if v.Status != "1" {
// 下发网管配置信息给网元
_, err = NeConfigOMC(v)
_, err = neFetchlink.NeConfigOMC(v)
if err == nil {
v.Status = "1"
} else {
@@ -298,26 +300,26 @@ func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, id string) bool {
return uniqueId == ""
}
// NeRunSSHclient 网元主机的SSH客户端-为创建相关连接
func (r *NeInfoImpl) NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) {
// NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close()
func (r *NeInfoImpl) NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) {
neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
logger.Errorf("NeRunSSHclient NeType:%s NeID:%s not found", neType, neId)
logger.Errorf("NeRunSSHClient NeType:%s NeID:%s not found", neType, neId)
return nil, fmt.Errorf("neinfo not found")
}
// 取主机信息
if neInfo.HostIDs == "" {
logger.Errorf("NeRunSSHclient NeType:%s NeID:%s hostId not found", neType, neId)
logger.Errorf("NeRunSSHClient NeType:%s NeID:%s hostId not found", neType, neId)
return nil, fmt.Errorf("neinfo hostId not found")
}
neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ","))
if len(neInfo.Hosts) <= 0 {
logger.Errorf("NeRunSSHclient Hosts %s not found", neInfo.HostIDs)
logger.Errorf("NeRunSSHClient Hosts %s not found", neInfo.HostIDs)
return nil, fmt.Errorf("neinfo host not found")
}
neHost := neInfo.Hosts[0]
neHost := neInfo.Hosts[0] // 网元主机ssh 022
if neHost.HostType != "ssh" {
logger.Errorf("NeRunSSHclient Hosts first HostType %s not ssh", neHost.HostType)
logger.Errorf("NeRunSSHClient Hosts first HostType %s not ssh", neHost.HostType)
return nil, fmt.Errorf("neinfo host type not ssh")
}
@@ -331,15 +333,15 @@ func (r *NeInfoImpl) NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) {
client, err = connSSH.NewClient()
}
if err != nil {
logger.Errorf("NeRunSSHclient NewClient err => %s", err.Error())
logger.Errorf("NeRunSSHClient NewClient err => %s", err.Error())
return nil, fmt.Errorf("neinfo ssh client new err")
}
return client, nil
}
// NeRunCMD 向网元发送cmd命令
func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) {
sshClient, err := r.NeRunSSHclient(neType, neId)
// NeRunSSHCmd 网元主机的SSH客户端发送cmd命令
func (r *NeInfoImpl) NeRunSSHCmd(neType, neId, cmd string) (string, error) {
sshClient, err := r.NeRunSSHClient(neType, neId)
if err != nil {
return "", err
}
@@ -348,12 +350,43 @@ func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) {
// 执行命令
output, err := sshClient.RunCMD(cmd)
if err != nil {
logger.Errorf("NeRunCMD RunCMD %s err => %s", output, err.Error())
logger.Errorf("NeRunSSHCmd RunCMD %s err => %s", output, err.Error())
return "", fmt.Errorf("neinfo ssh run cmd err")
}
return output, nil
}
// NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close()
// num 是网元主机telnet 14100 25200
func (r *NeInfoImpl) NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) {
neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s not found", neType, neId)
return nil, fmt.Errorf("neinfo not found")
}
// 取主机信息
if neInfo.HostIDs == "" {
logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s hostId not found", neType, neId)
return nil, fmt.Errorf("neinfo hostId not found")
}
neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ","))
if len(neInfo.Hosts) <= 0 {
logger.Errorf("NeRunTelnetClient Hosts %s not found", neInfo.HostIDs)
return nil, fmt.Errorf("neinfo host not found")
}
neHost := neInfo.Hosts[num]
// 创建链接Telnet客户端
var connTelnet telnet.ConnTelnet
neHost.CopyTo(&connTelnet)
telnetClient, err := connTelnet.NewClient()
if err != nil {
logger.Errorf("NeRunTelnetClient NewClient err => %s", err.Error())
return nil, fmt.Errorf("neinfo telnet client new err")
}
return telnetClient, nil
}
// neConfOAMData 网元OAM配置文件默认格式数据
func (r *NeInfoImpl) neConfOAMData() map[string]any {
return map[string]any{
@@ -447,7 +480,7 @@ func (r *NeInfoImpl) neConfOAMWirte(neType, neId string, content any, sync bool)
// 同步到网元端
if sync {
// 网元主机的SSH客户端
sshClient, err := r.NeRunSSHclient(neType, neId)
sshClient, err := r.NeRunSSHClient(neType, neId)
if err != nil {
return err
}
@@ -609,7 +642,7 @@ func (r *NeInfoImpl) NeConfPara5GWirte(content map[string]any, syncNE []string)
for _, neTI := range syncNE {
ti := strings.SplitN(neTI, "@", 2)
// 网元主机的SSH客户端
sshClient, err := r.NeRunSSHclient(ti[0], ti[1])
sshClient, err := r.NeRunSSHClient(ti[0], ti[1])
if err != nil {
errMsg = append(errMsg, fmt.Sprintf("%s : %s", ti, err.Error()))
continue
@@ -672,20 +705,30 @@ func (r *NeInfoImpl) neConfPara5GDataConvert(content map[string]any) map[string]
}
n3IPAmdMask := external["upfn3_ip"].(string)
n3Arr := strings.Split(n3IPAmdMask, "/")
n3Arr := strings.SplitN(n3IPAmdMask, "/", 2)
n3IP := n3Arr[0]
n3Mask := parse.ConvertIPMask(parse.Number(n3Arr[1]))
n3Mask := "255.255.255.0"
if len(n3Arr) > 1 {
n3Mask = parse.ConvertIPMask(parse.Number(n3Arr[1]))
}
n6IPAmdMask := external["upfn6_ip"].(string)
n6Arr := strings.Split(n6IPAmdMask, "/")
n6Arr := strings.SplitN(n6IPAmdMask, "/", 2)
n6IP := n6Arr[0]
n6Mask := parse.ConvertIPMask(parse.Number(n6Arr[1]))
n6Mask := "255.255.255.0"
if len(n6Arr) > 1 {
n6Mask = parse.ConvertIPMask(parse.Number(n6Arr[1]))
}
ueIPAmdMask := external["ue_pool"].(string)
ueArr := strings.Split(ueIPAmdMask, "/")
ueArr := strings.SplitN(ueIPAmdMask, "/", 2)
ueIP := ueArr[0]
ueCicr := ueArr[1]
ueMask := parse.ConvertIPMask(parse.Number(ueArr[1]))
ueCicr := "24"
ueMask := "255.255.255.0"
if len(ueArr) > 1 {
ueCicr = ueArr[1]
ueMask = parse.ConvertIPMask(parse.Number(ueArr[1]))
}
return map[string]string{
// basic

View File

@@ -110,7 +110,7 @@ func (r *NeLicenseImpl) ReadLicenseInfo(neLicense model.NeLicense) (string, stri
nePath := fmt.Sprintf("/usr/local/etc/%s/license", neTypeLower)
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neLicense.NeType, neLicense.NeId)
sshClient, err := NewNeInfoImpl.NeRunSSHClient(neLicense.NeType, neLicense.NeId)
if err != nil {
return "", ""
}
@@ -149,7 +149,7 @@ func (r *NeLicenseImpl) UploadLicense(neLicense model.NeLicense) error {
}
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neLicense.NeType, neLicense.NeId)
sshClient, err := NewNeInfoImpl.NeRunSSHClient(neLicense.NeType, neLicense.NeId)
if err != nil {
return err
}
@@ -174,16 +174,16 @@ func (r *NeLicenseImpl) UploadLicense(neLicense model.NeLicense) error {
// 上传授权文件去覆盖
if err := sftpClient.CopyFileLocalToRemote(omcLicensePath, neLicensePath); err != nil {
return err
return fmt.Errorf("please check if scp remote copy is allowed")
}
// 重启服务
if neLicense.Reload {
cmdStr := fmt.Sprintf("sudo service %s restart", neTypeLower)
if neTypeLower == "ims" {
cmdStr = "sudo ims-stop || true && sudo ims-start"
cmdStr = "ims-stop || true && ims-start"
} else if neTypeLower == "omc" {
cmdStr = "sudo /usr/local/omc/bin/omcsvc.sh restart"
cmdStr = "sudo systemctl restart restagent"
}
sshClient.RunCMD(cmdStr)
}

View File

@@ -89,7 +89,7 @@ func (r *NeVersionImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeVersi
// action 安装行为install upgrade rollback
func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error) {
// 网元主机的SSH客户端
sshClient, err := NewNeInfoImpl.NeRunSSHclient(neVersion.NeType, neVersion.NeId)
sshClient, err := NewNeInfoImpl.NeRunSSHClient(neVersion.NeType, neVersion.NeId)
if err != nil {
return "", err
}
@@ -125,10 +125,6 @@ func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinp
if err != nil {
return "", err
}
// 操作自己omc时
if neVersion.NeType == "OMC" {
return sshClient.RunCMD(fmt.Sprintf("nohup sh -c \"sleep 3s && %s\" > /dev/null 2>&1 & \n", strings.Join(cmdStrArr, " && ")))
}
// ========= 执行阶段 =========
commandLine, err := r.operateRun(sshClient, preinput, cmdStrArr, neVersion.NeType, okFlagStr)
@@ -203,23 +199,30 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri
// 组合命令输入
cmdStrArr := []string{}
if neType == "OMC" {
cmdStrArr = append(cmdStrArr, pkgCmdStr)
omcStrArr := []string{}
omcStrArr = append(omcStrArr, pkgCmdStr)
if action == "install" {
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/setomc.sh -m install") // 初始化数据库
omcStrArr = append(omcStrArr, "sudo /usr/local/omc/bin/setomc.sh -m install") // 初始化数据库
} else {
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh stop")
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库
omcStrArr = append(omcStrArr, "sudo /usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库
}
cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh restart")
omcStrArr = append(omcStrArr, "sudo systemctl restart restagent") // 重启服务
omcStrArr = append(omcStrArr, fmt.Sprintf("sudo rm %s", strings.Join(neFilePaths, " "))) // 删除软件包
// 2s后安装
cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 2s && %s\" > /dev/null 2>&1 & \n", strings.Join(omcStrArr, " && ")))
// 结束
cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr))
return okFlagStr, cmdStrArr, nil
} else if neType == "IMS" {
if action == "install" {
para5GData := NewNeInfoImpl.Para5GData
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
// 公网 PLMN地址
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", para5GData["SIP_IP"], para5GData["MCC"], para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("/usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", para5GData["SIP_IP"], para5GData["MCC"], para5GData["MNC"]))
// 内网 服务地址
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modintraip.sh %s \n", para5GData["IMS_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("/usr/local/etc/ims/default/tools/modintraip.sh %s \n", para5GData["IMS_IP"]))
// IWF连接PCF服务
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/iwf/iwf_conf.yaml \n", para5GData["PCF_IP"]))
// 设置 HOST
@@ -245,16 +248,18 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri
smsHost := fmt.Sprintf("%s smsc.%s smsc", para5GData["SIP_IP"], imsOrgHost)
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", smsHost, smsHost))
// adb
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["ADB_IP"]))
cmdStrArr = append(cmdStrArr, "sudo ims-stop || true && sudo ims-start \n")
if strings.Contains(pkgCmdStr, "adb") {
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["ADB_IP"]))
cmdStrArr = append(cmdStrArr, "sudo service adb restart \n")
}
cmdStrArr = append(cmdStrArr, "ims-stop || true && ims-start \n")
// 30s后停止服务
// cmdStrArr = append(cmdStrArr, "nohup sh -c \"sleep 30s && sudo ims-stop\" > /dev/null 2>&1 & \n")
} else {
cmdStrArr = append(cmdStrArr, "sudo ims-stop \n")
cmdStrArr = append(cmdStrArr, "ims-stop \n")
cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n")
cmdStrArr = append(cmdStrArr, "sudo ims-start \n")
cmdStrArr = append(cmdStrArr, "ims-start \n")
}
} else {
if action == "install" {
@@ -319,11 +324,14 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/serviceSelection: 'ims'/serviceSelection: '%s'/g\" /usr/local/etc/udm/epsApn.yaml \n", para5GData["DNN_IMS"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: internet/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_DATA"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: ims/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_IMS"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.18.81/%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["SIP_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.110/%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["SIP_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s udm' /etc/hosts || echo '%s udm' | sudo tee -a /etc/hosts \n", para5GData["UDM_IP"], para5GData["UDM_IP"]))
// adb
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["ADB_IP"]))
if strings.Contains(pkgCmdStr, "adb") {
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["ADB_IP"]))
cmdStrArr = append(cmdStrArr, "sudo service adb restart \n")
}
}
// SMF配置修改
if neTypeLower == "smf" {
@@ -431,15 +439,19 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["SMF_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|192.168.8.220/20|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S1_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S11_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["MME_IP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.221/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S10_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MNC_DOMAIN"], para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/\"00101\"/\"%s%s\"/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MCC=\"001\" ; MNC=\"01\";/MCC=\"%s\" ; MNC=\"%s\";/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/TAC = \"1\";/TAC = \"%s\";/g\" /usr/local/etc/mme/mme.conf \n", para5GData["TAC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/TAC = 1;/TAC = %s;/g\" /usr/local/etc/mme/mme.conf \n", para5GData["TAC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MCC=\"001\"/MCC=\"%s\"/g' /usr/local/etc/mme/mme.conf \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MCC = \"001\"/MCC = \"%s\"/g' /usr/local/etc/mme/mme.conf \n", para5GData["MCC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MNC=\"01\";/MNC=\"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MNC = \"01\";/MNC = \"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["MNC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/TAC = \"1\";/TAC = \"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["TAC"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/TAC = 1;/TAC = %s;/g' /usr/local/etc/mme/mme.conf \n", para5GData["TAC"]))
// SMF开启
cmdStrArr = append(cmdStrArr, "sudo sed -i \"/^ *gxcfg:/,/^ *[^ ]/{s/enable: false/enable: true/;b};\" /usr/local/etc/smf/smf_conf.yaml \n")
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s mme' /etc/hosts || echo '%s mme' | sudo tee -a /etc/hosts \n", para5GData["S11_MMEIP"], para5GData["S11_MMEIP"]))
cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s mme' /etc/hosts || echo '%s mme' | sudo tee -a /etc/hosts \n", para5GData["MME_IP"], para5GData["MME_IP"]))
}
// N3IWF配置修改
if neTypeLower == "n3iwf" {

View File

@@ -1,37 +0,0 @@
package service
import "be.ems/src/modules/network_element/model"
// UDM鉴权信息 服务层接口
type IUDMAuth interface {
// Save UDM鉴权用户-获取redis全部保存数据库
Save(neID string) int64
// Page UDM鉴权用户-分页查询数据库
Page(query map[string]any) map[string]any
// List UDM鉴权用户-查询数据库
List(authUser model.UDMAuth) []model.UDMAuth
// Insert UDM鉴权用户-新增单个
// imsi长度15ki长度32opc长度0或者32
Insert(neID string, authUser model.UDMAuth) int64
// Insert UDM鉴权用户-批量添加
Inserts(neID string, authUser model.UDMAuth, num string) int64
// InsertCSV UDM鉴权用户-批量添加
InsertCSV(neID string, data []map[string]string) int64
// InsertTxt UDM鉴权用户-批量添加
InsertTxt(neID string, data [][]string) int64
// Insert UDM鉴权用户-修改更新
Update(neID string, authUser model.UDMAuth) int64
// Insert UDM鉴权用户-删除单个
Delete(neID, imsi string) int64
// Insert UDM鉴权用户-删除范围
Deletes(neID, imsi, num string) int64
}

View File

@@ -1,179 +0,0 @@
package service
import (
"fmt"
"strings"
"be.ems/src/framework/redis"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
// 实例化服务层 UDMAuthImpl 结构体
var NewUDMAuthImpl = &UDMAuthImpl{
udmAuthRepository: repository.NewUDMAuthImpl,
}
// UDM鉴权信息 服务层处理
type UDMAuthImpl struct {
// UDM鉴权信息数据信息
udmAuthRepository repository.IUDMAuth
}
// authDataByRedis UDM鉴权用户
func (r *UDMAuthImpl) authDataByRedis(imsi, neID string) []model.UDMAuth {
arr := []model.UDMAuth{}
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
}
status := "1" // 默认给1
amf := ""
if v, ok := m["amf"]; ok {
amf = strings.Replace(v, "\r\n", "", 1)
}
a := model.UDMAuth{
Imsi: imsi,
Amf: amf,
Status: status,
Ki: m["ki"],
AlgoIndex: m["algo"],
Opc: m["opc"],
NeID: neID,
}
arr = append(arr, a)
}
return arr
}
// Save UDM鉴权用户-获取redis全部保存数据库
func (r *UDMAuthImpl) Save(neID string) int64 {
authArr := r.authDataByRedis("*", neID)
// 数据清空后添加
go r.udmAuthRepository.ClearAndInsert(neID, authArr)
return int64(len(authArr))
}
// Page UDM鉴权用户-分页查询数据库
func (r *UDMAuthImpl) Page(query map[string]any) map[string]any {
return r.udmAuthRepository.SelectPage(query)
}
// List UDM鉴权用户-查询数据库
func (r *UDMAuthImpl) List(authUser model.UDMAuth) []model.UDMAuth {
return r.udmAuthRepository.SelectList(authUser)
}
// Insert UDM鉴权用户-新增单个
// imsi长度15ki长度32opc长度0或者32
func (r *UDMAuthImpl) Insert(neID string, authUser model.UDMAuth) int64 {
authArr := r.authDataByRedis(authUser.Imsi, neID)
if len(authArr) > 0 {
r.udmAuthRepository.Delete(neID, authUser.Imsi)
r.udmAuthRepository.Inserts(authArr)
}
return 0
}
// Insert UDM鉴权用户-批量添加
func (r *UDMAuthImpl) Inserts(neID string, authUser model.UDMAuth, num string) int64 {
startIMSI := authUser.Imsi
startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*"
// keys udm-sd:4600001000004*
authArr := r.authDataByRedis(startIMSI, neID)
if len(authArr) > 0 {
for _, v := range authArr {
r.udmAuthRepository.Delete(neID, v.Imsi)
}
return r.udmAuthRepository.Inserts(authArr)
}
return 0
}
// InsertCSV UDM鉴权用户-批量添加
func (r *UDMAuthImpl) InsertCSV(neID string, data []map[string]string) int64 {
prefixes := make(map[string]struct{})
for _, v := range data {
imsi := v["imsi"]
if len(imsi) < 5 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
// 分组插入
var num int64 = 0
for prefix := range prefixes {
r.udmAuthRepository.DeletePrefixImsi(neID, prefix)
subArr := r.authDataByRedis(prefix+"*", neID)
if len(subArr) > 0 {
num += r.udmAuthRepository.Inserts(subArr)
}
}
return num
}
// InsertTxt UDM鉴权用户-批量添加
func (r *UDMAuthImpl) InsertTxt(neID string, data [][]string) int64 {
prefixes := make(map[string]struct{})
for _, v := range data {
imsi := v[0]
if len(imsi) < 5 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
// 分组插入
var num int64 = 0
for prefix := range prefixes {
r.udmAuthRepository.DeletePrefixImsi(neID, prefix)
subArr := r.authDataByRedis(prefix+"*", neID)
if len(subArr) > 0 {
num += r.udmAuthRepository.Inserts(subArr)
}
}
return num
}
// Insert UDM鉴权用户-修改更新
func (r *UDMAuthImpl) Update(neID string, authUser model.UDMAuth) int64 {
authArr := r.authDataByRedis(authUser.Imsi, neID)
if len(authArr) > 0 {
r.udmAuthRepository.Delete(neID, authUser.Imsi)
return r.udmAuthRepository.Inserts(authArr)
}
return 0
}
// Insert UDM鉴权用户-删除单个
func (r *UDMAuthImpl) Delete(neID, imsi string) int64 {
return r.udmAuthRepository.Delete(neID, imsi)
}
// Insert UDM鉴权用户-删除范围
func (r *UDMAuthImpl) Deletes(neID, imsi, num string) int64 {
prefix := imsi[:len(imsi)-len(num)-1]
// 直接删除前缀的记录
r.udmAuthRepository.DeletePrefixImsi(neID, prefix)
// keys ausf:4600001000004*
authArr := r.authDataByRedis(prefix+"*", neID)
if len(authArr) > 0 {
return r.udmAuthRepository.Inserts(authArr)
}
return 0
}

View File

@@ -1,37 +0,0 @@
package service
import "be.ems/src/modules/network_element/model"
// UDM签约用户信息 服务层接口
type IUDMSub interface {
// Save UDM签约用户-获取redis全部保存数据库
Save(neID string) int64
// Page UDM签约用户-分页查询数据库
Page(query map[string]any) map[string]any
// List UDM签约用户-查询数据库
List(subUser model.UDMSub) []model.UDMSub
// Insert UDM签约用户-新增单个
// imsi长度15ki长度32opc长度0或者32
Insert(neID string, subUser model.UDMSub) int64
// Insert UDM签约用户-批量添加
Inserts(neID string, subUser model.UDMSub, num string) int64
// InsertCSV UDM签约用户-批量添加
InsertCSV(neID string, data []map[string]string) int64
// InsertTxt UDM签约用户-批量添加
InsertTxt(neID string, data [][]string) int64
// Insert UDM签约用户-修改更新
Update(neID string, subUser model.UDMSub) int64
// Insert UDM签约用户-删除单个
Delete(neID, imsi string) int64
// Insert UDM签约用户-删除范围
Deletes(neID, imsi, num string) int64
}

View File

@@ -1,195 +0,0 @@
package service
import (
"fmt"
"strings"
"be.ems/src/framework/redis"
"be.ems/src/modules/network_element/model"
"be.ems/src/modules/network_element/repository"
)
// 实例化服务层 UDMSubImpl 结构体
var NewUDMSubImpl = &UDMSubImpl{
udmSubRepository: repository.NewUDMSubImpl,
}
// UDM签约信息 服务层处理
type UDMSubImpl struct {
// UDM签约信息数据信息
udmSubRepository repository.IUDMSub
}
// subDataByRedis UDM签约用户
func (r *UDMSubImpl) subDataByRedis(imsi, neID string) []model.UDMSub {
arr := []model.UDMSub{}
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 strings.TrimPrefix(m["gpsi"], "86"),
SmfSel: m["smf-sel"],
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
NeID: neID,
}
// def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,-
if v, ok := m["am-dat"]; ok {
arr := strings.Split(v, ",")
a.Ambr = arr[0]
a.Nssai = arr[1]
a.Rat = arr[2]
a.Arfb = arr[3]
a.Sar = arr[4]
a.Cn = arr[5]
}
// 1,64,24,65,def_eps,1,2,010200000000,-
if v, ok := m["eps-dat"]; ok {
arr := strings.Split(v, ",")
// 跳过非常规数据
if len(arr) > 9 {
continue
}
a.EpsDat = v
a.EpsFlag = arr[0]
a.EpsOdb = arr[1]
a.HplmnOdb = arr[2]
a.Ard = arr[3]
a.Epstpl = arr[4]
a.ContextId = arr[5]
a.ApnContext = arr[7]
// [6] 是不要的,导入和导出不用
a.StaticIp = arr[8]
}
arr = append(arr, a)
}
return arr
}
// Save UDM签约用户-获取redis全部保存数据库
func (r *UDMSubImpl) Save(neID string) int64 {
subArr := r.subDataByRedis("*", neID)
// 数据清空后添加
go r.udmSubRepository.ClearAndInsert(neID, subArr)
return int64(len(subArr))
}
// Page UDM签约用户-分页查询数据库
func (r *UDMSubImpl) Page(query map[string]any) map[string]any {
return r.udmSubRepository.SelectPage(query)
}
// List UDM签约用户-查询数据库
func (r *UDMSubImpl) List(subUser model.UDMSub) []model.UDMSub {
return r.udmSubRepository.SelectList(subUser)
}
// Insert UDM签约用户-新增单个
// imsi长度15ki长度32opc长度0或者32
func (r *UDMSubImpl) Insert(neID string, subUser model.UDMSub) int64 {
authArr := r.subDataByRedis(subUser.Imsi, neID)
if len(authArr) > 0 {
r.udmSubRepository.Delete(neID, subUser.Imsi)
r.udmSubRepository.Inserts(authArr)
}
return 0
}
// Insert UDM签约用户-批量添加
func (r *UDMSubImpl) Inserts(neID string, subUser model.UDMSub, num string) int64 {
startIMSI := subUser.Imsi
startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*"
// keys udm-sd:4600001000004*
subArr := r.subDataByRedis(startIMSI, neID)
if len(subArr) > 0 {
for _, v := range subArr {
r.udmSubRepository.Delete(neID, v.Imsi)
}
return r.udmSubRepository.Inserts(subArr)
}
return 0
}
// InsertCSV UDM签约用户-批量添加
func (r *UDMSubImpl) InsertCSV(neID string, data []map[string]string) int64 {
prefixes := make(map[string]struct{})
for _, v := range data {
imsi := v["imsi"]
if len(imsi) < 5 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
// 分组插入
var num int64 = 0
for prefix := range prefixes {
r.udmSubRepository.DeletePrefixImsi(neID, prefix)
subArr := r.subDataByRedis(prefix+"*", neID)
if len(subArr) > 0 {
num += r.udmSubRepository.Inserts(subArr)
}
}
return num
}
// InsertTxt UDM签约用户-批量添加
func (r *UDMSubImpl) InsertTxt(neID string, data [][]string) int64 {
prefixes := make(map[string]struct{})
for _, v := range data {
imsi := v[0]
if len(imsi) < 5 {
continue
}
prefix := imsi[:len(imsi)-4]
prefixes[prefix] = struct{}{}
}
// 分组插入
var num int64 = 0
for prefix := range prefixes {
r.udmSubRepository.DeletePrefixImsi(neID, prefix)
subArr := r.subDataByRedis(prefix+"*", neID)
if len(subArr) > 0 {
num += r.udmSubRepository.Inserts(subArr)
}
}
return num
}
// Insert UDM签约用户-修改更新
func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 {
authArr := r.subDataByRedis(subUser.Imsi, neID)
if len(authArr) > 0 {
r.udmSubRepository.Delete(neID, subUser.Imsi)
return r.udmSubRepository.Inserts(authArr)
}
return 0
}
// Insert UDM签约用户-删除单个
func (r *UDMSubImpl) Delete(neID, imsi string) int64 {
return r.udmSubRepository.Delete(neID, imsi)
}
// Insert UDM签约用户-删除范围
func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 {
prefix := imsi[:len(imsi)-len(num)-1]
// 直接删除前缀的记录
r.udmSubRepository.DeletePrefixImsi(neID, prefix)
// keys udm-sd:4600001000004*
authArr := r.subDataByRedis(prefix+"*", neID)
if len(authArr) > 0 {
return r.udmSubRepository.Inserts(authArr)
}
return 0
}

View File

@@ -40,7 +40,8 @@ type SysLogLoginController struct {
// GET /list
func (s *SysLogLoginController) List(c *gin.Context) {
querys := ctx.QueryMap(c)
data := s.sysLogLoginService.SelectSysLogLoginPage(querys)
dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u")
data := s.sysLogLoginService.SelectSysLogLoginPage(querys, dataScopeSQL)
rows := data["rows"].([]model.SysLogLogin)
// 闭包函数处理多语言

View File

@@ -42,7 +42,8 @@ func (s *SysLogOperateController) List(c *gin.Context) {
querys["title"] = i18n.TFindKeyPrefix(language, "log.operate.title", v.(string))
}
data := s.SysLogOperateService.SelectSysLogOperatePage(querys)
dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u")
data := s.SysLogOperateService.SelectSysLogOperatePage(querys, dataScopeSQL)
rows := data["rows"].([]model.SysLogOperate)
// 闭包函数处理多语言

View File

@@ -60,7 +60,7 @@ func (s *SysProfileController) Info(c *gin.Context) {
}
isAdmin := config.IsAdmin(loginUser.UserID)
if isAdmin {
roleGroup = append(roleGroup, i18n.TKey(language, "role.admin"))
roleGroup = append(roleGroup, i18n.TKey(language, "role.system"))
}
// 查询用户所属岗位组

View File

@@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model"
// ISysLogLogin 系统登录日志表 数据层接口
type ISysLogLogin interface {
// SelectSysLogLoginPage 分页查询系统登录日志集合
SelectSysLogLoginPage(query map[string]any) map[string]any
SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any
// SelectSysLogLoginList 查询系统登录日志集合
SelectSysLogLoginList(sysLogLogin model.SysLogLogin) []model.SysLogLogin

View File

@@ -53,7 +53,7 @@ func (r *SysLogLoginImpl) convertResultRows(rows []map[string]any) []model.SysLo
}
// SelectSysLogLoginPage 分页查询系统登录日志集合
func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string]any {
func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
@@ -87,9 +87,23 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string
}
// 构建查询条件语句
selectSql := r.selectSql
totalSql := "select count(login_id) as 'total' from sys_log_login"
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
whereSql += dataScopeSQL
} else if dataScopeSQL != "" {
totalSql = `select count(o.login_id) as 'total'
from sys_log_login o
left join sys_user u on u.user_name = o.user_name
left join sys_dept d on u.dept_id = d.dept_id`
selectSql = `select o.login_id, o.user_name, o.ipaddr, o.login_location,
o.browser, o.os, o.status, o.msg, o.login_time
from sys_log_login o
left join sys_user u on u.user_name = o.user_name
left join sys_dept d on u.dept_id = d.dept_id`
whereSql += " where 1=1" + dataScopeSQL
}
// 查询结果
@@ -99,7 +113,6 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from sys_log_login"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
logger.Errorf("total err => %v", err)
@@ -119,7 +132,7 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string
params = append(params, pageSize)
// 查询数据
querySql := r.selectSql + whereSql + pageSql
querySql := selectSql + whereSql + dataScopeSQL + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)

View File

@@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model"
// ISysLogOperate 操作日志表 数据层接口
type ISysLogOperate interface {
// SelectSysLogOperatePage 分页查询系统操作日志集合
SelectSysLogOperatePage(query map[string]any) map[string]any
SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any
// SelectSysLogOperateList 查询系统操作日志集合
SelectSysLogOperateList(sysLogOperate model.SysLogOperate) []model.SysLogOperate

View File

@@ -62,7 +62,7 @@ func (r *SysLogOperateImpl) convertResultRows(rows []map[string]any) []model.Sys
}
// SelectSysLogOperatePage 分页查询系统操作日志集合
func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[string]any {
func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any {
// 查询条件拼接
var conditions []string
var params []any
@@ -100,9 +100,24 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st
}
// 构建查询条件语句
selectSql := r.selectSql
totalSql := "select count(oper_id) as 'total' from sys_log_operate"
whereSql := ""
if len(conditions) > 0 {
whereSql += " where " + strings.Join(conditions, " and ")
whereSql += dataScopeSQL
} else if dataScopeSQL != "" {
totalSql = `select count(o.oper_id) as 'total'
from sys_log_operate o
left join sys_user u on u.user_name = o.oper_name
left join sys_dept d on u.dept_id = d.dept_id`
selectSql = `select
o.oper_id, o.title, o.business_type, o.method, o.request_method, o.operator_type, o.oper_name, o.dept_name,
o.oper_url, o.oper_ip, o.oper_location, o.oper_param, o.oper_msg, o.status, o.oper_time, o.cost_time
from sys_log_operate o
left join sys_user u on u.user_name = o.oper_name
left join sys_dept d on u.dept_id = d.dept_id`
whereSql += " where 1=1" + dataScopeSQL
}
// 查询结果
@@ -112,7 +127,6 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st
}
// 查询数量 长度为0直接返回
totalSql := "select count(1) as 'total' from sys_log_operate"
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
if err != nil {
logger.Errorf("total err => %v", err)
@@ -132,7 +146,7 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st
params = append(params, pageSize)
// 查询数据
querySql := r.selectSql + whereSql + pageSql
querySql := selectSql + whereSql + pageSql
results, err := datasource.RawDB("", querySql, params)
if err != nil {
logger.Errorf("query err => %v", err)

View File

@@ -254,7 +254,7 @@ func (r *SysUserImpl) SelectAllocatedPage(query map[string]any, dataScopeSQL str
}
// 构建查询条件语句
whereSql := " where u.del_flag = '0' "
whereSql := " where u.del_flag = '0' and u.user_id != '1' "
if len(conditions) > 0 {
whereSql += " and " + strings.Join(conditions, " and ")
}

View File

@@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model"
// ISysLogLogin 系统登录日志 服务层接口
type ISysLogLogin interface {
// SelectSysLogLoginPage 分页查询系统登录日志集合
SelectSysLogLoginPage(query map[string]any) map[string]any
SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any
// SelectSysLogLoginList 查询系统登录日志集合
SelectSysLogLoginList(sysLogLogin model.SysLogLogin) []model.SysLogLogin

View File

@@ -17,8 +17,8 @@ type SysLogLoginImpl struct {
}
// SelectSysLogLoginPage 分页查询系统登录日志集合
func (s *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string]any {
return s.sysLogLoginService.SelectSysLogLoginPage(query)
func (s *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any {
return s.sysLogLoginService.SelectSysLogLoginPage(query, dataScopeSQL)
}
// SelectSysLogLoginList 查询系统登录日志集合

View File

@@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model"
// ISysLogOperate 操作日志表 服务层接口
type ISysLogOperate interface {
// SelectSysLogOperatePage 分页查询系统操作日志集合
SelectSysLogOperatePage(query map[string]any) map[string]any
SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any
// SelectSysLogOperateList 查询系统操作日志集合
SelectSysLogOperateList(sysLogOperate model.SysLogOperate) []model.SysLogOperate

View File

@@ -17,8 +17,8 @@ type SysLogOperateImpl struct {
}
// SelectSysLogOperatePage 分页查询系统操作日志集合
func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[string]any {
return r.SysLogOperateService.SelectSysLogOperatePage(query)
func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any {
return r.SysLogOperateService.SelectSysLogOperatePage(query, dataScopeSQL)
}
// SelectSysLogOperateList 查询系统操作日志集合

View File

@@ -209,7 +209,7 @@ func Setup(router *gin.Engine) {
controller.NewSysMenu.Remove,
)
sysMenuGroup.GET("/treeSelect",
middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:menu:list"}}),
middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:menu:list", "system:dept:list"}}),
controller.NewSysMenu.TreeSelect,
)
sysMenuGroup.GET("/roleMenuTreeSelect/:roleId",

View File

@@ -5,9 +5,7 @@ import (
"strings"
"time"
"be.ems/src/framework/config"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd"
"be.ems/src/framework/utils/date"
neService "be.ems/src/modules/network_element/service"
)
@@ -28,23 +26,26 @@ type TcpdumpImpl struct {
// DumpStart 触发tcpdump开始抓包 filePcapName, err
func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) {
// 检查网元信息
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
if neInfo.NeId != neId || neInfo.IP == "" {
return "", fmt.Errorf("noData")
}
// SSH命令
usernameNe := config.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP)
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
if err != nil {
return "", err
}
defer sshClient.Close()
// 是否拥有sudo权限并拼接
withSudo := ""
if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil {
if _, err := sshClient.RunCMD("sudo -n uname"); err == nil {
withSudo = "sudo "
}
if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil {
if msg, err := sshClient.RunCMD(fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil {
// stderr: bash: tcpdump未找到命令 => exit status 127
msg = strings.TrimSpace(msg)
logger.Warnf("DumpStart err: %s => %s", msg, err.Error())
@@ -58,7 +59,7 @@ func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) {
sendCmd := fmt.Sprintf("cd /tmp \n %s nohup timeout 30m tcpdump -i any %s -s0 -w %s.pcap > %s.log 2>&1 & \necho $!", withSudo, cmdStr, fileName, fileName)
// cd /tmp
// sudo nohup timeout 60m tcpdump -i any -n -s 0 -v -w -s0 -w 20240115140822_UDM_001.pcap > 20240115140822_UDM_001.log 2>&1 & echo $!
msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd)
msg, err := sshClient.RunCMD(sendCmd)
msg = strings.TrimSpace(msg)
if err != nil || strings.HasPrefix(msg, "stderr:") {
logger.Warnf("DumpStart err: %s => %s", msg, err.Error())
@@ -73,19 +74,22 @@ func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) {
// DumpStop 停止已存在抓包句柄
func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) {
// 检查网元信息
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
if neInfo.NeId != neId || neInfo.IP == "" {
return "", fmt.Errorf("noData")
}
// SSH命令
usernameNe := config.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP)
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
if err != nil {
return "", err
}
defer sshClient.Close()
// 是否拥有sudo权限并拼接
withSudo := ""
if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil {
if _, err := sshClient.RunCMD("sudo -n uname"); err == nil {
withSudo = "sudo "
}
@@ -104,7 +108,7 @@ func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) {
// 拼装命令
sendCmd := fmt.Sprintf("cd /tmp \n %s kill %s %s", withSudo, pid, viewLogFile)
msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd)
msg, err := sshClient.RunCMD(sendCmd)
delete(s.tcpdumpPIDMap, neTypeID)
if err != nil || strings.HasPrefix(msg, "stderr:") {
logger.Warnf("DumpStop err: %s => %s", strings.TrimSpace(msg), err.Error())
@@ -115,23 +119,26 @@ func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) {
// DumpUPF UPF标准版抓包
func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, error) {
// 检查网元信息
// 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId)
if neInfo.NeId != neId {
if neInfo.NeId != neId || neInfo.IP == "" {
return "", "", fmt.Errorf("noData")
}
// SSH命令
usernameNe := config.Get("ne.user").(string) // 网元统一用户
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP)
// 网元主机的SSH客户端
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
if err != nil {
return "", "", err
}
defer sshClient.Close()
// 是否拥有sudo权限并拼接
withSudo := ""
if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil {
if _, err := sshClient.RunCMD("sudo -n uname"); err == nil {
withSudo = "sudo "
}
if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s expect -version", withSudo)); err != nil {
if msg, err := sshClient.RunCMD(fmt.Sprintf("%s expect -version", withSudo)); err != nil {
// stderr: bash: expect未找到命令 => exit status 127
msg = strings.TrimSpace(msg)
logger.Warnf("DumpUPF err: %s => %s", msg, err.Error())
@@ -160,7 +167,7 @@ func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, erro
// sudo chmod +x pcapUPF.sh
// expect ./cap.sh 'pcap dispatch trace off' > 20240115165701_UDM_001.log 2>&1
// cat 20240115165701_UDM_001.log
msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd)
msg, err := sshClient.RunCMD(sendCmd)
msg = strings.TrimSpace(msg)
if err != nil || strings.HasPrefix(msg, "stderr:") {
logger.Warnf("DumpUPF err: %s => %s", msg, err.Error())

Some files were not shown because too many files have changed in this diff Show More