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

@@ -279,11 +279,7 @@ func PostCDREventFromSMF(w http.ResponseWriter, r *http.Request) {
} }
// 推送到ws订阅组 // 推送到ws订阅组
// if v, ok := cdrEvent.CDR["recordType"]; ok { wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_SMF_CDR, cdrEvent)
// if v == "MOC" || v == "MTSM" {
// wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_IMS_CDR, cdrEvent)
// }
// }
services.ResponseStatusOK204NoContent(w) services.ResponseStatusOK204NoContent(w)
} }

View File

@@ -8,7 +8,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"be.ems/lib/core/utils/ctx" "be.ems/lib/core/ctx"
"be.ems/lib/dborm" "be.ems/lib/dborm"
"be.ems/lib/log" "be.ems/lib/log"
"be.ems/lib/services" "be.ems/lib/services"

View File

@@ -3,7 +3,7 @@ package cm
import ( import (
"strings" "strings"
"be.ems/lib/core/utils/ctx" "be.ems/lib/core/ctx"
"be.ems/lib/global" "be.ems/lib/global"
"be.ems/lib/log" "be.ems/lib/log"
"be.ems/lib/services" "be.ems/lib/services"

View File

@@ -9,7 +9,7 @@ import (
"strings" "strings"
"time" "time"
"be.ems/lib/core/utils/ctx" "be.ems/lib/core/ctx"
"be.ems/lib/dborm" "be.ems/lib/dborm"
"be.ems/lib/global" "be.ems/lib/global"
"be.ems/lib/log" "be.ems/lib/log"

View File

@@ -2,26 +2,35 @@ package event
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"net/http"
"strings"
"time" "time"
"be.ems/lib/core/ctx"
"be.ems/lib/dborm" "be.ems/lib/dborm"
"be.ems/lib/global" "be.ems/lib/global"
"be.ems/lib/log" "be.ems/lib/log"
"be.ems/lib/services" "be.ems/lib/services"
"be.ems/restagent/config"
wsService "be.ems/src/modules/ws/service" wsService "be.ems/src/modules/ws/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
var ( var (
UriUEEvent = "/upload-ue/v1/:eventType" // 走Gin
UriUEEventAMF = "/upload-ue/v1/:eventType"
// 走Mux
UriUEEvent = config.DefaultUriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent"
CustomUriUEEvent = config.UriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent"
) )
type UEEvent struct { type UEEvent struct {
NeType string `json:"neType" xorm:"ne_type"` NeType string `json:"neType" xorm:"ne_type"`
NeName string `json:"neName" xorm:"ne_name"` NeName string `json:"neName" xorm:"ne_name"`
RmUID string `json:"rmUID" xorm:"rm_uid"` RmUID string `json:"rmUID" xorm:"rm_uid"`
Timestamp int `json:"timestamp" xorm:"timestamp"` Timestamp int64 `json:"timestamp" xorm:"timestamp"`
EventType string `json:"eventType" xorm:"event_type"` EventType string `json:"eventType" xorm:"event_type"`
EventJson map[string]any `json:"eventJSON" xorm:"event_json"` EventJson map[string]any `json:"eventJSON" xorm:"event_json"`
} }
@@ -51,13 +60,13 @@ func PostUEEventFromAMF(c *gin.Context) {
return return
} }
ueEvent.NeType = "AMF" ueEvent.NeType = "AMF"
ueEvent.Timestamp = int(time.Now().Unix()) ueEvent.Timestamp = time.Now().Unix()
ueEvent.EventType = eventType ueEvent.EventType = eventType
log.Trace("ueEvent:", ueEvent) log.Trace("ueEvent AMF:", ueEvent)
affected, err := dborm.XormInsertTableOne("ue_event", ueEvent) affected, err := dborm.XormInsertTableOne("ue_event_amf", ueEvent)
if err != nil && affected <= 0 { if err != nil && affected <= 0 {
log.Error("Failed to insert ue_event:", err) log.Error("Failed to insert ue_event_amf:", err)
services.ResponseInternalServerError500ProcessError(c.Writer, err) services.ResponseInternalServerError500ProcessError(c.Writer, err)
return return
} }
@@ -67,3 +76,30 @@ func PostUEEventFromAMF(c *gin.Context) {
services.ResponseStatusOK204NoContent(c.Writer) services.ResponseStatusOK204NoContent(c.Writer)
} }
func PostUEEvent(w http.ResponseWriter, r *http.Request) {
log.Info("PostUEEvent processing... ")
neType := ctx.GetParam(r, "elementTypeValue")
var ueEvent UEEvent
if err := ctx.ShouldBindJSON(r, &ueEvent); err != nil {
services.ResponseInternalServerError500ProcessError(w, err)
return
}
ueEvent.NeType = strings.ToUpper(neType)
tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType))
affected, err := dborm.XormInsertTableOne(tableName, ueEvent)
if err != nil && affected <= 0 {
log.Error("Failed to insert "+tableName, err)
services.ResponseInternalServerError500ProcessError(w, err)
return
}
// 推送到ws订阅组
if ueEvent.NeType == "MME" {
wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_MME_UE, ueEvent)
}
services.ResponseStatusOK204NoContent(w)
}

View File

@@ -5,7 +5,7 @@ import (
"net/http" "net/http"
"path/filepath" "path/filepath"
"be.ems/lib/core/utils/ctx" "be.ems/lib/core/ctx"
"be.ems/lib/dborm" "be.ems/lib/dborm"
"be.ems/lib/file" "be.ems/lib/file"
"be.ems/lib/log" "be.ems/lib/log"

View File

@@ -1,60 +0,0 @@
package fm
import (
"fmt"
"strings"
"be.ems/lib/log"
"be.ems/restagent/config"
"github.com/chzyer/readline"
"github.com/go-gsm/ucp"
)
func AlarmForwardBySMSC(alarmData *Alarm) error {
opt := &ucp.Options{
Addr: config.GetYamlConfig().Alarm.SMSC.Addr,
User: config.GetYamlConfig().Alarm.SMSC.SystemID,
Password: config.GetYamlConfig().Alarm.SMSC.Password,
AccessCode: config.GetYamlConfig().Alarm.SMSC.SystemType,
}
client := ucp.New(opt)
if err := client.Connect(); err != nil {
log.Error("Failed to connect:", err)
return err
}
defer client.Close()
reader, _ := readline.New(">>> ")
defer reader.Close()
for {
fmt.Print(">>> ")
lines, _ := reader.Readline()
fields := strings.Fields(lines)
if len(fields) == 1 {
// exit CLI
if fields[0] == "exit" {
return nil
}
// display help message
if fields[0] == "help" {
log.Trace("\n\tSend a 'message' to 'receiver' with a 'sender' mask\n\t>>> sender receiver message\n\n\tExit the cli\n\t>>> exit\n")
}
}
// sender receiver message...
if len(fields) >= 3 {
sender := fields[0]
receiver := fields[1]
message := strings.Join(fields[2:], " ")
ids, err := client.Send(sender, receiver, message)
if err != nil {
log.Error(err)
} else {
log.Debug("%v", ids)
}
}
}
}

View File

@@ -54,8 +54,8 @@ var (
var ( var (
TIME_DELAY_AFTER_WRITE time.Duration = 200 TIME_DELAY_AFTER_WRITE time.Duration = 200
TIME_DEAD_LINE time.Duration = 10 TIME_DEAD_LINE time.Duration = 10
WIN_ROW_SIZE byte = 100 WIN_ROW_SIZE int16 = 200
WIN_COL_SIZE byte = 100 WIN_COL_SIZE int16 = 120
BUFFER_SIZE int = 65535 BUFFER_SIZE int = 65535
) )
@@ -118,9 +118,15 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) {
// services.ResponseWithJson(w, http.StatusOK, response) // services.ResponseWithJson(w, http.StatusOK, response)
// return // return
// } // }
// 发送窗口大小设置命令 // 发送窗口大小设置命令
conn.Write([]byte{255, 251, 31}) // 发送WILL WINDOW SIZE conn.Write([]byte{255, 251, 31}) // 发送WILL WINDOW SIZE
conn.Write([]byte{255, 250, 31, 0, WIN_ROW_SIZE, 0, WIN_COL_SIZE, 255, 240}) // 发送设置 WINDOW SIZE conn.Write([]byte{
255, 250, 31,
byte(WIN_COL_SIZE >> 8), byte(WIN_COL_SIZE & 0xFF),
byte(WIN_ROW_SIZE >> 8), byte(WIN_ROW_SIZE & 0xFF),
255, 240,
}) // 发送设置 WINDOW SIZE
conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second))
loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password)

View File

@@ -8,12 +8,14 @@ import (
"strings" "strings"
"time" "time"
"be.ems/lib/core/ctx"
"be.ems/lib/dborm" "be.ems/lib/dborm"
"be.ems/lib/global" "be.ems/lib/global"
"be.ems/lib/log" "be.ems/lib/log"
"be.ems/lib/services" "be.ems/lib/services"
"be.ems/restagent/config" "be.ems/restagent/config"
tokenConst "be.ems/src/framework/constants/token" tokenConst "be.ems/src/framework/constants/token"
neService "be.ems/src/modules/network_element/service"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@@ -241,66 +243,38 @@ func GetSubscriptionsFromNSSF(w http.ResponseWriter, r *http.Request) {
// Get UEInfo from NF/NFs // Get UEInfo from NF/NFs
func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) {
log.Info("GetUEInfoFromNF processing... ") log.Debug("GetUEInfoFromNF processing... ")
vars := mux.Vars(r) neId := ctx.GetQuery(r, "neId")
neType := vars["elementTypeValue"] neType := ctx.GetParam(r, "elementTypeValue")
if neType == "" { if neType == "" || neId == "" {
services.ResponseNotFound404UriNotExist(w, r) log.Error("elementTypeValue/neId is empty")
return
}
//neTypeLower := strings.ToLower(neType)
var neId string
neIds := services.GetParamsArrByName("neId", r)
if len(neIds) == 1 {
neId = neIds[0]
} else {
services.ResponseNotFound404UriNotExist(w, r) services.ResponseNotFound404UriNotExist(w, r)
return return
} }
// token, err := services.CheckFrontValidRequest(w, r) neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId)
// if err != nil {
// log.Error("Request error:", err)
// return
// }
// log.Debug("token:", token)
neInfo, err := dborm.XormGetNeInfo(neType, neId) var response services.MapResponse
if err != nil { if neInfo.NeId == neId && neInfo.NeId != "" {
log.Error("Failed to XormGetNeInfo:", err) requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI)
services.ResponseInternalServerError500ProcessError(w, err) log.Debug("requestURI2NF:", requestURI2NF)
return resp, err := client.R().
} else if neInfo == nil { EnableTrace().
err := global.ErrCMNotFoundTargetNE SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
log.Error(global.ErrCMNotFoundTargetNE) SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
services.ResponseInternalServerError500ProcessError(w, err) Get(requestURI2NF)
return if err != nil {
log.Error("Failed to Get from NF:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else {
_ = json.Unmarshal(resp.Body(), &response)
}
log.Debug("response:", response)
} }
log.Trace("neInfo:", neInfo)
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) services.ResponseWithJson(w, http.StatusOK, response)
requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI)
log.Debug("requestURI2NF:", requestURI2NF)
resp, err := client.R().
EnableTrace().
SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}).
// SetHeaders(map[string]string{"accessToken": token}).
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI2NF)
if err != nil {
log.Error("Get system state from NF is failed:", err)
services.ResponseInternalServerError500ProcessError(w, err)
return
} else {
var response services.MapResponse
_ = json.Unmarshal(resp.Body(), &response)
services.ResponseWithJson(w, resp.StatusCode(), response)
return
}
} }
// POST User Info from NF/NFs // POST User Info from NF/NFs

15
go.mod
View File

@@ -5,12 +5,10 @@ go 1.21
toolchain go1.21.0 toolchain go1.21.0
require ( require (
github.com/chzyer/readline v1.5.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/dlclark/regexp2 v1.10.0 github.com/dlclark/regexp2 v1.10.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-admin-team/go-admin-core/sdk v1.5.1 github.com/go-admin-team/go-admin-core/sdk v1.5.1
github.com/go-gsm/ucp v0.0.1
github.com/go-resty/resty/v2 v2.7.0 github.com/go-resty/resty/v2 v2.7.0
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-jwt/jwt/v5 v5.0.0
@@ -46,11 +44,14 @@ require (
) )
require ( require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/creack/pty v1.1.9 // indirect github.com/creack/pty v1.1.9 // indirect
github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f // indirect github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f // indirect
github.com/go-gsm/charset v1.0.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
golang.org/x/sync v0.6.0 // indirect golang.org/x/sync v0.6.0 // indirect
golang.org/x/time v0.1.0 // indirect
) )
require ( require (
@@ -62,6 +63,7 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect
github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect
github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -112,7 +114,9 @@ require (
github.com/nyaruka/phonenumbers v1.0.55 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/sftp v1.13.6
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_golang v1.19.1
github.com/reiver/go-oi v1.0.0 // indirect github.com/reiver/go-oi v1.0.0 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect
@@ -139,10 +143,9 @@ require (
golang.org/x/sys v0.17.0 // indirect golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 golang.org/x/text v0.14.0
golang.org/x/tools v0.16.1 // indirect golang.org/x/tools v0.16.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect

45
go.sum
View File

@@ -65,6 +65,7 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0=
@@ -92,18 +93,14 @@ github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973/go.mod h1:9+sJ9zv
github.com/chanxuehong/util v0.0.0-20200304121633-ca8141845b13/go.mod h1:XEYt99iTxMqkv+gW85JX/DdUINHUe43Sbe5AtqSaDAQ= github.com/chanxuehong/util v0.0.0-20200304121633-ca8141845b13/go.mod h1:XEYt99iTxMqkv+gW85JX/DdUINHUe43Sbe5AtqSaDAQ=
github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd h1:TM3wjEWel4U31J72dlhnwCBqPC0+FA0Ejm2NCbn5a5U= github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd h1:TM3wjEWel4U31J72dlhnwCBqPC0+FA0Ejm2NCbn5a5U=
github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd/go.mod h1:/dvhOIRCjjiZu6NV0QTTiMcc5XwoORbxfDSsRY2IfaM= github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd/go.mod h1:/dvhOIRCjjiZu6NV0QTTiMcc5XwoORbxfDSsRY2IfaM=
github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a h1:yTfhjWYoPomJkHVArtNHpo36FuOa6Kc2ZjTLvyyQ5Lg=
github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
@@ -179,10 +176,6 @@ github.com/go-forks/fsnotify v1.4.7/go.mod h1:AU8mot+GznW5+B4jRJHxKg/2EeO+jMORGR
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gsm/charset v1.0.0 h1:6k6LOKHtxgCPXE15X0unRewjOksyhmHBIp6x7qLQ6Ls=
github.com/go-gsm/charset v1.0.0/go.mod h1:sC8+2VpAM2sZDlxv11MxWIZiuf8MipOgM/hCYsRQRps=
github.com/go-gsm/ucp v0.0.1 h1:vM5ly5iRNGMGGiVx4K3+puF9AhpwkC76BkiV9LFv0bw=
github.com/go-gsm/ucp v0.0.1/go.mod h1:58/PrXWFcmaQyZ5p/Dp2YiCnhlVx0HdKXFGmqiVO/mI=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
@@ -278,8 +271,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -435,10 +429,10 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -585,6 +579,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@@ -596,18 +592,26 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
@@ -626,8 +630,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
@@ -780,6 +784,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
@@ -827,7 +832,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -868,6 +872,7 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
@@ -959,11 +964,11 @@ golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -974,6 +979,7 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
@@ -986,6 +992,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
@@ -994,8 +1001,6 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1162,8 +1167,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/AlecAivazis/survey.v1 v1.8.5 h1:QoEEmn/d5BbuPIL2qvXwzJdttFFhRQFkaq+tEKb7SMI= gopkg.in/AlecAivazis/survey.v1 v1.8.5 h1:QoEEmn/d5BbuPIL2qvXwzJdttFFhRQFkaq+tEKb7SMI=
gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=

View File

@@ -1,24 +0,0 @@
package cachekey
// 缓存的key常量
// 登录用户
const LOGIN_TOKEN_KEY = "login_tokens:"
// 验证码
const CAPTCHA_CODE_KEY = "captcha_codes:"
// 参数管理
const SYS_CONFIG_KEY = "sys_config:"
// 字典管理
const SYS_DICT_KEY = "sys_dict:"
// 防重提交
const REPEAT_SUBMIT_KEY = "repeat_submit:"
// 限流
const RATE_LIMIT_KEY = "rate_limit:"
// 登录账户密码错误次数
const PWD_ERR_CNT_KEY = "pwd_err_cnt:"

View File

@@ -17,8 +17,8 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
) )
// Param 地址栏参数{id} // GetParam 地址栏参数{id}
func Param(r *http.Request, key string) string { func GetParam(r *http.Request, key string) string {
vars := mux.Vars(r) vars := mux.Vars(r)
v, ok := vars[key] v, ok := vars[key]
if ok { if ok {
@@ -47,7 +47,7 @@ func QueryMap(r *http.Request) map[string]any {
return queryParams return queryParams
} }
// ShouldBindQuery 查询参数读取json请求结构团体 // ShouldBindQuery 查询参数读取json请求结构团体 &xxx
func ShouldBindQuery(r *http.Request, args any) error { func ShouldBindQuery(r *http.Request, args any) error {
queryParams := QueryMap(r) queryParams := QueryMap(r)
body, err := json.Marshal(queryParams) body, err := json.Marshal(queryParams)
@@ -57,7 +57,7 @@ func ShouldBindQuery(r *http.Request, args any) error {
return json.Unmarshal(body, args) return json.Unmarshal(body, args)
} }
// 读取json请求结构团体 // ShouldBindJSON 读取json请求结构团体 &xxx
func ShouldBindJSON(r *http.Request, args any) error { func ShouldBindJSON(r *http.Request, args any) error {
body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 设置较大的长度,例如 1<<20 (1MB) body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 设置较大的长度,例如 1<<20 (1MB)
if err != nil { if err != nil {

View File

@@ -1,49 +0,0 @@
package datasource
import (
"database/sql"
"regexp"
"be.ems/lib/dborm"
"xorm.io/xorm"
)
// 获取默认数据源
func DefaultDB() *xorm.Engine {
return dborm.DbClient.XEngine
}
// RawDB 原生查询语句
func RawDB(source string, sql string, parameters []any) ([]map[string]any, error) {
// 数据源
db := DefaultDB()
// 使用正则表达式替换连续的空白字符为单个空格
fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ")
// log.Infof("sql=> %v", fmtSql)
// log.Infof("parameters=> %v", parameters)
// 查询结果
var rows []map[string]any
err := db.SQL(fmtSql, parameters...).Find(&rows)
if err != nil {
return nil, err
}
return rows, nil
}
// ExecDB 原生执行语句
func ExecDB(source string, sql string, parameters []any) (sql.Result, error) {
// 数据源
db := DefaultDB()
// 使用正则表达式替换连续的空白字符为单个空格
fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ")
// 执行结果
res, err := db.Exec(append([]any{fmtSql}, parameters...)...)
if err != nil {
return nil, err
}
return res, err
}

View File

@@ -1,126 +0,0 @@
package datasource
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// PageNumSize 分页页码记录数
func PageNumSize(pageNum, pageSize any) (int, int) {
// 记录起始索引
pageNumStr := fmt.Sprintf("%v", pageNum)
num := 1
if v, err := strconv.Atoi(pageNumStr); err == nil && v > 0 {
num = v
}
// 显示记录数
pageSizeStr := fmt.Sprintf("%v", pageSize)
size := 10
if v, err := strconv.Atoi(pageSizeStr); err == nil && v > 0 {
size = v
}
return num - 1, size
}
// SetFieldValue 判断结构体内是否存在指定字段并设置值
func SetFieldValue(obj any, fieldName string, value any) {
// 获取结构体的反射值
userValue := reflect.ValueOf(obj)
// 获取字段的反射值
fieldValue := userValue.Elem().FieldByName(fieldName)
// 检查字段是否存在
if fieldValue.IsValid() && fieldValue.CanSet() {
// 获取字段的类型
fieldType := fieldValue.Type()
// 转换传入的值类型为字段类型
switch fieldType.Kind() {
case reflect.String:
if value == nil {
fieldValue.SetString("")
} else {
fieldValue.SetString(fmt.Sprintf("%v", value))
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
intValue, err := strconv.ParseInt(fmt.Sprintf("%v", value), 10, 64)
if err != nil {
intValue = 0
}
fieldValue.SetInt(intValue)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uintValue, err := strconv.ParseUint(fmt.Sprintf("%v", value), 10, 64)
if err != nil {
uintValue = 0
}
fieldValue.SetUint(uintValue)
case reflect.Float32, reflect.Float64:
floatValue, err := strconv.ParseFloat(fmt.Sprintf("%v", value), 64)
if err != nil {
floatValue = 0
}
fieldValue.SetFloat(floatValue)
default:
// 设置字段的值
fieldValue.Set(reflect.ValueOf(value).Convert(fieldValue.Type()))
}
}
}
// ConvertIdsSlice 将 []string 转换为 []any
func ConvertIdsSlice(ids []string) []any {
// 将 []string 转换为 []any
arr := make([]any, len(ids))
for i, v := range ids {
arr[i] = v
}
return arr
}
// 查询-参数值的占位符
func KeyPlaceholderByQuery(sum int) string {
placeholders := make([]string, sum)
for i := 0; i < sum; i++ {
placeholders[i] = "?"
}
return strings.Join(placeholders, ",")
}
// 插入-参数映射键值占位符 keys, placeholder, values
func KeyPlaceholderValueByInsert(params map[string]any) ([]string, string, []any) {
// 参数映射的键
keys := make([]string, len(params))
// 参数映射的值
values := make([]any, len(params))
sum := 0
for k, v := range params {
keys[sum] = k
values[sum] = v
sum++
}
// 参数值的占位符
placeholders := make([]string, sum)
for i := 0; i < sum; i++ {
placeholders[i] = "?"
}
return keys, strings.Join(placeholders, ","), values
}
// 更新-参数映射键值占位符 keys, values
func KeyValueByUpdate(params map[string]any) ([]string, []any) {
// 参数映射的键
keys := make([]string, len(params))
// 参数映射的值
values := make([]any, len(params))
sum := 0
for k, v := range params {
keys[sum] = k + "=?"
values[sum] = v
sum++
}
return keys, values
}

View File

@@ -1,87 +0,0 @@
package mmlclient
import (
"bufio"
"fmt"
"io"
"net"
"time"
"be.ems/lib/core/conf"
)
// 定义MMLClient结构体
type MMLClient struct {
awaitTime time.Duration // 等待时间
conn net.Conn
reader *bufio.Reader
size int // 包含字符
}
// 封装NewMMLClient函数用于创建MMLClient实例
// 网元UDM的IP地址 "198.51.100.1"
func NewMMLClient(ip string) (*MMLClient, error) {
// 创建TCP连接
portMML := conf.Get("mml.port").(int)
hostMML := fmt.Sprintf("%s:%d", ip, portMML)
conn, err := net.Dial("tcp", hostMML)
if err != nil {
return nil, err
}
// 进行登录
usernameMML := conf.Get("mml.user").(string)
passwordMML := conf.Get("mml.password").(string)
fmt.Fprintln(conn, usernameMML)
fmt.Fprintln(conn, passwordMML)
// 发送后等待
awaitTime := time.Duration(300) * time.Millisecond
time.Sleep(awaitTime)
// 读取内容
buf := make([]byte, 1024*1024*1)
n, err := conn.Read(buf)
if err != nil {
return nil, err
}
// 创建MMLClient实例
client := &MMLClient{
conn: conn,
reader: bufio.NewReader(conn),
awaitTime: awaitTime,
size: n,
}
return client, nil
}
// 封装Send函数用于向TCP连接发送数据
func (c *MMLClient) Send(msg string) error {
_, err := fmt.Fprintln(c.conn, msg)
if err != nil {
return err
}
time.Sleep(c.awaitTime)
return nil
}
// 封装Receive函数用于从TCP连接中接收数据
func (c *MMLClient) Receive() (string, error) {
buf := make([]byte, 1024*1024*1)
n, err := c.reader.Read(buf)
if err != nil {
if err == io.EOF {
return "", fmt.Errorf("server closed the connection")
}
return "", err
}
c.size += n
return string(buf[0:n]), nil
}
// 封装Close函数用于关闭TCP连接
func (c *MMLClient) Close() error {
return c.conn.Close()
}

View File

@@ -1,105 +0,0 @@
package mmlclient
import (
"fmt"
"strings"
)
// 发送MML原始消息
// ip 网元IP地址
// msg 指令
func MMLSendMsg(ip, msg string) (string, error) {
// 创建MMLClient实例
client, err := NewMMLClient(ip)
if err != nil {
return "", fmt.Errorf("failed to create MMLClient instance: %v", err)
}
defer client.Close()
// 发送数据
err = client.Send(msg)
if err != nil {
return "", fmt.Errorf("sending data failed: %v", err)
}
// 接收数据
data, err := client.Receive()
if err != nil {
return "", fmt.Errorf("failed to receive data: %v", err)
}
return data, nil
}
// 发送MML
// ip 网元IP地址
// msg 指令
func MMLSendMsgToString(ip, msg string) (string, error) {
// 发送获取数据
str, err := MMLSendMsg(ip, msg)
if err != nil {
return "", err
}
str = strings.ToLower(str)
// 截断
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)
}
// 发送MML
// ip 网元IP地址
// msg 指令
func MMLSendMsgToMap(ip, msg string) (map[string]string, error) {
// 发送获取数据
str, err := MMLSendMsg(ip, msg)
if err != nil {
return nil, err
}
// 无数据
if strings.HasPrefix(str, "No Auth Data") {
return nil, fmt.Errorf("no auth data")
}
// 初始化一个map用于存储拆分后的键值对
m := make(map[string]string)
var items []string
if strings.Contains(str, "\r\n") {
// 按照分隔符"\r\n"进行拆分
items = strings.Split(str, "\r\n")
} else if strings.Contains(str, "\n") {
// 按照分隔符"\n"进行拆分
items = strings.Split(str, "\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

@@ -1,70 +0,0 @@
package date
import (
"fmt"
"time"
"be.ems/lib/log"
)
const (
// 年 列如2022
YYYY = "2006"
// 年-月 列如2022-12
YYYY_MM = "2006-01"
// 年-月-日 列如2022-12-30
YYYY_MM_DD = "2006-01-02"
// 年月日时分秒 列如20221230010159
YYYYMMDDHHMMSS = "20060102150405"
// 年-月-日 时:分:秒 列如2022-12-30 01:01:59
YYYY_MM_DD_HH_MM_SS = "2006-01-02 15:04:05"
)
// 格式时间字符串
//
// dateStr 时间字符串
//
// formatStr 时间格式 默认YYYY-MM-DD HH:mm:ss
func ParseStrToDate(dateStr, formatStr string) time.Time {
t, err := time.Parse(formatStr, dateStr)
if err != nil {
log.Infof("utils ParseStrToDate err %v", err)
return time.Time{}
}
return t
}
// 格式时间
//
// date 可转的Date对象
//
// formatStr 时间格式 默认YYYY-MM-DD HH:mm:ss
func ParseDateToStr(date any, formatStr string) string {
t, ok := date.(time.Time)
if !ok {
switch v := date.(type) {
case int64:
if v == 0 {
return ""
}
t = time.UnixMilli(v)
case string:
parsedTime, err := time.Parse(formatStr, v)
if err != nil {
fmt.Printf("utils ParseDateToStr err %v \n", err)
return ""
}
t = parsedTime
default:
return ""
}
}
return t.Format(formatStr)
}
// 格式时间成日期路径
//
// 年/月 列如2022/12
func ParseDatePath(date time.Time) string {
return date.Format("2006/01")
}

View File

@@ -1,139 +0,0 @@
package parse
import (
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"github.com/robfig/cron/v3"
)
// Number 解析数值型
func Number(str any) int64 {
switch str := str.(type) {
case string:
if str == "" {
return 0
}
num, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return 0
}
return num
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(str).Int()
case float32, float64:
return int64(reflect.ValueOf(str).Float())
default:
return 0
}
}
// Boolean 解析布尔型
func Boolean(str any) bool {
switch str := str.(type) {
case string:
if str == "" || str == "false" || str == "0" {
return false
}
// 尝试将字符串解析为数字
if num, err := strconv.ParseFloat(str, 64); err == nil {
return num != 0
}
return true
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
num := reflect.ValueOf(str).Int()
return num != 0
case float32, float64:
num := reflect.ValueOf(str).Float()
return num != 0
default:
return false
}
}
// FirstUpper 首字母转大写
//
// 字符串 abc_123!@# 结果 Abc_123
func FirstUpper(str string) string {
if len(str) == 0 {
return str
}
reg := regexp.MustCompile(`[^_\w]+`)
str = reg.ReplaceAllString(str, "")
return strings.ToUpper(str[:1]) + str[1:]
}
// Bit 比特位为单位
func Bit(bit float64) string {
var GB, MB, KB string
if bit > float64(1<<30) {
GB = fmt.Sprintf("%0.2f", bit/(1<<30))
}
if bit > float64(1<<20) && bit < (1<<30) {
MB = fmt.Sprintf("%.2f", bit/(1<<20))
}
if bit > float64(1<<10) && bit < (1<<20) {
KB = fmt.Sprintf("%.2f", bit/(1<<10))
}
if GB != "" {
return GB + "GB"
} else if MB != "" {
return MB + "MB"
} else if KB != "" {
return KB + "KB"
} else {
return fmt.Sprintf("%vB", bit)
}
}
// CronExpression 解析 Cron 表达式,返回下一次执行的时间戳(毫秒)
//
// 【*/5 * * * * ?】 6个参数
func CronExpression(expression string) int64 {
specParser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
schedule, err := specParser.Parse(expression)
if err != nil {
fmt.Println(err)
return 0
}
return schedule.Next(time.Now()).UnixMilli()
}
// SafeContent 内容值进行安全掩码
func SafeContent(value string) string {
if len(value) < 3 {
return strings.Repeat("*", len(value))
} else if len(value) < 6 {
return string(value[0]) + strings.Repeat("*", len(value)-1)
} else if len(value) < 10 {
return string(value[0]) + strings.Repeat("*", len(value)-2) + string(value[len(value)-1])
} else if len(value) < 15 {
return value[:2] + strings.Repeat("*", len(value)-4) + value[len(value)-2:]
} else {
return value[:3] + strings.Repeat("*", len(value)-6) + value[len(value)-3:]
}
}
// RemoveDuplicates 数组内字符串去重
func RemoveDuplicates(ids []string) []string {
uniqueIDs := make(map[string]bool)
uniqueIDSlice := make([]string, 0)
for _, id := range ids {
_, ok := uniqueIDs[id]
if !ok && id != "" {
uniqueIDs[id] = true
uniqueIDSlice = append(uniqueIDSlice, id)
}
}
return uniqueIDSlice
}

View File

@@ -1,54 +0,0 @@
package regular
import (
"regexp"
)
// Replace 正则替换
func Replace(originStr, pattern, repStr string) string {
regex := regexp.MustCompile(pattern)
return regex.ReplaceAllString(originStr, repStr)
}
// 判断是否为有效用户名格式
//
// 用户名不能以数字开头可包含大写小写字母数字且不少于5位
func ValidUsername(username string) bool {
if username == "" {
return false
}
pattern := `^[a-zA-Z][a-z0-9A-Z]{5,}`
match, err := regexp.MatchString(pattern, username)
if err != nil {
return false
}
return match
}
// 判断是否为有效手机号格式1开头的11位手机号
func ValidMobile(mobile string) bool {
if mobile == "" {
return false
}
pattern := `^1[3|4|5|6|7|8|9][0-9]\d{8}$`
match, err := regexp.MatchString(pattern, mobile)
if err != nil {
return false
}
return match
}
// 判断是否为http(s)://开头
//
// link 网络链接
func ValidHttp(link string) bool {
if link == "" {
return false
}
pattern := `^http(s)?:\/\/+`
match, err := regexp.MatchString(pattern, link)
if err != nil {
return false
}
return match
}

View File

@@ -1,31 +0,0 @@
package scan
import (
"net"
"strconv"
)
func ScanPort(port int) bool {
ln, err := net.Listen("tcp", ":"+strconv.Itoa(port))
if err != nil {
return true
}
defer ln.Close()
return false
}
func ScanUDPPort(port int) bool {
ln, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port})
if err != nil {
return true
}
defer ln.Close()
return false
}
func ScanPortWithProto(port int, proto string) bool {
if proto == "udp" {
return ScanUDPPort(port)
}
return ScanPort(port)
}

View File

@@ -23,6 +23,4 @@ type LoginUser struct {
// User 用户信息 // User 用户信息
User dborm.User `json:"user"` User dborm.User `json:"user"`
Session dborm.Session `json:"-"`
} }

View File

@@ -1,17 +0,0 @@
package vo
// Router 路由信息对象
type Router struct {
// 路由名字 英文首字母大写
Name string `json:"name"`
// 路由地址
Path string `json:"path"`
// 其他元素
Meta RouterMeta `json:"meta"`
// 组件地址
Component string `json:"component"`
// 重定向地址
Redirect string `json:"redirect"`
// 子路由
Children []Router `json:"children,omitempty"`
}

View File

@@ -1,17 +0,0 @@
package vo
// RouterMeta 路由元信息对象
type RouterMeta struct {
// 设置该菜单在侧边栏和面包屑中展示的名字
Title string `json:"title"`
// 设置该菜单的图标
Icon string `json:"icon"`
// 设置为true则不会被 <keep-alive>缓存
Cache bool `json:"cache"`
// 内链地址http(s)://开头), 打开目标位置 '_blank' | '_self' | ''
Target string `json:"target"`
// 在菜单中隐藏子节点
HideChildInMenu bool `json:"hideChildInMenu"`
// 在菜单中隐藏自己和子节点
HideInMenu bool `json:"hideInMenu"`
}

View File

@@ -1,36 +0,0 @@
package vo
// import sysmenu "be.ems/features/sys_menu"
// TreeSelect 树结构实体类
type TreeSelect struct {
// ID 节点ID
ID string `json:"id"`
// Label 节点名称
Label string `json:"label"`
// Title 节点名称旧版本layui
Title string `json:"title"`
// Children 子节点
Children []TreeSelect `json:"children"`
}
// // SysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象
// func SysMenuTreeSelect(sysMenu sysmenu.SysMenu) TreeSelect {
// t := TreeSelect{}
// t.ID = sysMenu.MenuID
// t.Label = sysMenu.MenuName
// if len(sysMenu.Children) > 0 {
// for _, menu := range sysMenu.Children {
// child := SysMenuTreeSelect(menu)
// t.Children = append(t.Children, child)
// }
// } else {
// t.Children = []TreeSelect{}
// }
// return t
// }

View File

@@ -1,78 +0,0 @@
package midware
import (
"encoding/json"
"net/http"
"strings"
"time"
"be.ems/lib/dborm"
"be.ems/lib/services"
)
// 已禁用
// 登录策略限制登录时间和访问ip范围
func ArrowIPAddr(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ipAddr := strings.Split(r.RemoteAddr, ":")[0]
// 读取配置信息 登录策略设置
result, err := dborm.XormGetConfig("Security", "loginSecurity")
if err != nil {
next.ServeHTTP(w, r)
return
}
data := make(map[string]any)
err = json.Unmarshal([]byte(result["value_json"].(string)), &data)
if err != nil {
next.ServeHTTP(w, r)
return
}
// 开关
switchStr := data["switch"].(string)
if switchStr == "0" {
next.ServeHTTP(w, r)
return
}
ipRange := data["ipRange"].(string)
logintimeRange := data["logintime_range"].(string)
// 检查ip
ips := strings.Split(ipRange, "/")
hasIP := false
for _, ip := range ips {
if ipAddr == ip {
hasIP = true
}
}
if !hasIP {
services.ResponseErrorWithJson(w, 502, "网关登录策略-IP限制: "+ipAddr)
return
}
// 检查开放时间
logintimeRangeArr := strings.Split(logintimeRange, " - ")
// 加载中国时区
loc, _ := time.LoadLocation("Asia/Shanghai")
// 获取当前时间
currentTime := time.Now().In(loc)
// 获取当前日期
currentDate := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location())
ymd := currentDate.Format("2006-01-02")
// 定义开始时间和结束时间
startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", ymd+" "+logintimeRangeArr[0], loc)
endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", ymd+" "+logintimeRangeArr[1], loc)
// 判断当前时间是否在范围内
if currentTime.After(startTime) && currentTime.Before(endTime) {
next.ServeHTTP(w, r)
} else {
services.ResponseErrorWithJson(w, 502, "网关登录策略-不在开放时间范围内")
}
})
}

View File

@@ -1,229 +0,0 @@
package midware
import (
"context"
"fmt"
"net/http"
"be.ems/lib/core/cache"
"be.ems/lib/core/utils/ctx"
"be.ems/lib/core/vo"
"be.ems/lib/core/vo/result"
"be.ems/lib/dborm"
commonConstants "be.ems/src/framework/constants/common"
tokenUtils "be.ems/src/framework/utils/token"
)
// 已禁用由Gin部分接管
// Authorize 用户身份授权认证校验
//
// 只需含有其中角色 "hasRoles": {"xxx"},
//
// 只需含有其中权限 "hasPerms": {"xxx"},
//
// 同时匹配其中角色 "matchRoles": {"xxx"},
//
// 同时匹配其中权限 "matchPerms": {"xxx"},
func Authorize(options map[string][]string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 获取请求头标识信息
tokenStr := ctx.Authorization(r)
// 获取请求头标识信息-旧头
accessToken := r.Header.Get("AccessToken")
if tokenStr == "" && accessToken != "" {
// 验证令牌 == 这里直接查数据库session
if !dborm.XormExistValidToken(accessToken, 0) {
ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization valid error"))
return
}
se, err := dborm.XormUpdateSessionShakeTime(accessToken)
if err != nil {
ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization shake error"))
return
}
// 获取缓存的用户信息
data, ok := cache.GetLocalTTL(se.AccountId)
if data == nil || !ok {
ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization info error"))
return
}
loginUser := data.(vo.LoginUser)
// 登录用户角色权限校验
if options != nil {
var roles []string
for _, item := range loginUser.User.Roles {
roles = append(roles, item.RoleKey)
}
perms := loginUser.Permissions
verifyOk := verifyRolePermission(roles, perms, options)
if !verifyOk {
msg := fmt.Sprintf("Unauthorized access %s %s", r.Method, r.RequestURI)
ctx.JSON(w, 403, result.CodeMsg(403, msg))
return
}
}
// 在请求的 Context 中存储数据
rContext := r.Context()
rContext = context.WithValue(rContext, ctx.ContextKey(commonConstants.CTX_LOGIN_USER), loginUser)
// 继续处理请求
next.ServeHTTP(w, r.WithContext(rContext))
return
}
// 获取请求头标识信息
if tokenStr == "" {
ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization token error"))
return
}
// 验证令牌
claims, err := tokenUtils.Verify(tokenStr)
if err != nil {
ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization valid error"))
return
}
// 获取缓存的用户信息
loginUser := tokenUtils.LoginUser(claims)
if loginUser.UserID == "" {
ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization shake error"))
return
}
// 检查刷新有效期后存入上下文
tokenUtils.RefreshIn(&loginUser)
// 登录用户角色权限校验
if options != nil {
var roles []string
for _, item := range loginUser.User.Roles {
roles = append(roles, item.RoleKey)
}
perms := loginUser.Permissions
verifyOk := verifyRolePermission(roles, perms, options)
if !verifyOk {
msg := fmt.Sprintf("Unauthorized access %s %s", r.Method, r.RequestURI)
ctx.JSON(w, 403, result.CodeMsg(403, msg))
return
}
}
// 在请求的 Context 中存储数据
rContext := r.Context()
rContext = context.WithValue(rContext, ctx.ContextKey(commonConstants.CTX_LOGIN_USER), loginUser)
// 继续处理请求
next.ServeHTTP(w, r.WithContext(rContext))
})
}
}
// verifyRolePermission 校验角色权限是否满足
//
// roles 角色字符数组
//
// perms 权限字符数组
//
// options 参数
func verifyRolePermission(roles, perms []string, options map[string][]string) bool {
// 直接放行 管理员角色或任意权限
if contains(roles, "admin") || contains(perms, "*:*:*") {
return true
}
opts := make([]bool, 4)
// 只需含有其中角色
hasRole := false
if arr, ok := options["hasRoles"]; ok && len(arr) > 0 {
hasRole = some(roles, arr)
opts[0] = true
}
// 只需含有其中权限
hasPerms := false
if arr, ok := options["hasPerms"]; ok && len(arr) > 0 {
hasPerms = some(perms, arr)
opts[1] = true
}
// 同时匹配其中角色
matchRoles := false
if arr, ok := options["matchRoles"]; ok && len(arr) > 0 {
matchRoles = every(roles, arr)
opts[2] = true
}
// 同时匹配其中权限
matchPerms := false
if arr, ok := options["matchPerms"]; ok && len(arr) > 0 {
matchPerms = every(perms, arr)
opts[3] = true
}
// 同时判断 含有其中
if opts[0] && opts[1] {
return hasRole || hasPerms
}
// 同时判断 匹配其中
if opts[2] && opts[3] {
return matchRoles && matchPerms
}
// 同时判断 含有其中且匹配其中
if opts[0] && opts[3] {
return hasRole && matchPerms
}
if opts[1] && opts[2] {
return hasPerms && matchRoles
}
return hasRole || hasPerms || matchRoles || matchPerms
}
// contains 检查字符串数组中是否包含指定的字符串
func contains(arr []string, target string) bool {
for _, str := range arr {
if str == target {
return true
}
}
return false
}
// some 检查字符串数组中含有其中一项
func some(origin []string, target []string) bool {
has := false
for _, t := range target {
for _, o := range origin {
if t == o {
has = true
break
}
}
if has {
break
}
}
return has
}
// every 检查字符串数组中同时包含所有项
func every(origin []string, target []string) bool {
match := true
for _, t := range target {
found := false
for _, o := range origin {
if t == o {
found = true
break
}
}
if !found {
match = false
break
}
}
return match
}

View File

@@ -1,67 +0,0 @@
package midware
import (
"net/http"
"strings"
)
// 已禁用由Gin部分接管
// Cors 跨域
func Cors(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 设置Vary头部
w.Header().Set("Vary", "Origin")
w.Header().Set("Keep-Alive", "timeout=5")
requestOrigin := r.Header.Get("Origin")
if requestOrigin == "" {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Credentials", "true")
// OPTIONS
if r.Method == "OPTIONS" {
requestMethod := r.Header.Get("Access-Control-Request-Method")
if requestMethod == "" {
next.ServeHTTP(w, r)
return
}
// 响应最大时间值
w.Header().Set("Access-Control-Max-Age", "31536000")
// 允许方法
allowMethods := []string{
"OPTIONS",
"HEAD",
"GET",
"POST",
"PUT",
"DELETE",
"PATCH",
}
w.Header().Set("Access-Control-Allow-Methods", strings.Join(allowMethods, ","))
// 允许请求头
allowHeaders := []string{
"Accesstoken",
"Content-Type",
"operationtype",
}
w.Header().Set("Access-Control-Allow-Headers", strings.Join(allowHeaders, ","))
w.WriteHeader(204)
return
}
// 暴露请求头
exposeHeaders := []string{"X-RepeatSubmit-Rest", "AccessToken"}
w.Header().Set("Access-Control-Expose-Headers", strings.Join(exposeHeaders, ","))
next.ServeHTTP(w, r)
})
}

View File

@@ -9,10 +9,10 @@ import (
"strings" "strings"
"time" "time"
"be.ems/lib/core/datasource" "be.ems/lib/core/ctx"
"be.ems/lib/core/utils/ctx"
"be.ems/lib/core/utils/date"
"be.ems/lib/log" "be.ems/lib/log"
"be.ems/src/framework/datasource"
"be.ems/src/framework/utils/date"
) )
// LogMML mml操作日志搜集 // LogMML mml操作日志搜集
@@ -36,7 +36,7 @@ func LogMML(next http.Handler) http.Handler {
// 收尾存入数据库的参数 // 收尾存入数据库的参数
mmlCmd := bodyArgs["mml"].([]any)[0] mmlCmd := bodyArgs["mml"].([]any)[0]
ipAddr := strings.Split(r.RemoteAddr, ":")[0] ipAddr := strings.Split(r.RemoteAddr, ":")[0]
neType := ctx.Param(r, "elementTypeValue") neType := ctx.GetParam(r, "elementTypeValue")
neId := ctx.GetQuery(r, "ne_id") neId := ctx.GetQuery(r, "ne_id")
timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS) timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS)

View File

@@ -11,11 +11,11 @@ import (
"strings" "strings"
"time" "time"
"be.ems/lib/core/utils/ctx" "be.ems/lib/core/ctx"
"be.ems/lib/core/utils/parse"
"be.ems/src/framework/constants/common" "be.ems/src/framework/constants/common"
"be.ems/src/framework/middleware/collectlogs" "be.ems/src/framework/middleware/collectlogs"
"be.ems/src/framework/utils/ip2region" "be.ems/src/framework/utils/ip2region"
"be.ems/src/framework/utils/parse"
"be.ems/src/modules/system/model" "be.ems/src/modules/system/model"
"be.ems/src/modules/system/service" "be.ems/src/modules/system/service"
) )

View File

@@ -9,11 +9,11 @@ import (
"be.ems/features/cdr" "be.ems/features/cdr"
"be.ems/features/cm" "be.ems/features/cm"
"be.ems/features/dbrest" "be.ems/features/dbrest"
"be.ems/features/event"
"be.ems/features/file" "be.ems/features/file"
"be.ems/features/fm" "be.ems/features/fm"
"be.ems/features/lm" "be.ems/features/lm"
"be.ems/features/mml" "be.ems/features/mml"
"be.ems/features/nbi"
"be.ems/features/pm" "be.ems/features/pm"
"be.ems/features/security" "be.ems/features/security"
"be.ems/features/sm" "be.ems/features/sm"
@@ -172,9 +172,9 @@ func init() {
Register("POST", mml.CustomUriMML2, mml.PostMML2ToNF, nil) Register("POST", mml.CustomUriMML2, mml.PostMML2ToNF, nil)
// Northbound Get NRM // Northbound Get NRM
Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil) // Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil)
Register("GET", nbi.CustomGetNRMUri, nbi.NBIGetNRMFromNF, nil) // Register("GET", nbi.CustomGetNRMUri, nbi.NBIGetNRMFromNF, nil)
// Import/Export NF CM // Import/Export NF CM
Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil) Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil)
@@ -261,9 +261,7 @@ func init() {
Register("DELETE", ue.CustomUriPCFUserM, ue.DeletePCFUserInfo, nil) Register("DELETE", ue.CustomUriPCFUserM, ue.DeletePCFUserInfo, nil)
//PCF User file //PCF User file
Register("GET", ue.UriPCFUserFileExport, ue.GetUEInfoFileExportNF, nil) Register("GET", ue.UriPCFUserFileExport, ue.GetUEInfoFileExportNF, nil)
Register("GET", ue.CustomUriPCFUserFileExport, ue.GetUEInfoFromNF, nil)
Register("PUT", ue.UriPCFUserFileImport, ue.PutPCFUserInfo, nil) Register("PUT", ue.UriPCFUserFileImport, ue.PutPCFUserInfo, nil)
Register("PUT", ue.CustomUriPCFUserFileImport, ue.PutPCFUserInfo, nil)
// UE Number // UE Number
Register("GET", ue.UriUENum, ue.GetUENumFromNF, nil) Register("GET", ue.UriUENum, ue.GetUENumFromNF, nil)
@@ -289,6 +287,9 @@ func init() {
Register("POST", cdr.UriSMFCDREvent, cdr.PostCDREventFromSMF, nil) Register("POST", cdr.UriSMFCDREvent, cdr.PostCDREventFromSMF, nil)
Register("POST", cdr.CustomUriSMFCDREvent, cdr.PostCDREventFromSMF, nil) Register("POST", cdr.CustomUriSMFCDREvent, cdr.PostCDREventFromSMF, nil)
// UE event 上报的UE事件
Register("POST", event.UriUEEvent, event.PostUEEvent, nil)
// UE event AMF上报的UE事件, 无前缀给到Gin处理 // UE event AMF上报的UE事件, 无前缀给到Gin处理
//Register("POST", event.UriUEEvent, event.PostUEEventFromAMF, nil) //Register("POST", event.UriUEEvent, event.PostUEEventFromAMF, nil)

View File

@@ -1,45 +0,0 @@
package wsinfo
import (
"github.com/gorilla/websocket"
)
type Client struct {
ID string
Socket *websocket.Conn
Msg chan []byte
}
func NewWsClient(ID string, socket *websocket.Conn) *Client {
return &Client{
ID: ID,
Socket: socket,
Msg: make(chan []byte, 100),
}
}
func (c *Client) Read() {
defer func() {
close(c.Msg)
}()
for {
_, message, err := c.Socket.ReadMessage()
if err != nil {
return
}
ProcessData(c, message)
}
}
func (c *Client) Write() {
defer func() {
c.Socket.Close()
}()
for {
message, ok := <-c.Msg
if !ok {
return
}
_ = c.Socket.WriteMessage(websocket.TextMessage, message)
}
}

View File

@@ -1,382 +0,0 @@
package wsinfo
import (
"encoding/json"
"fmt"
"sort"
"strings"
"sync"
"time"
"be.ems/lib/log"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/net"
"github.com/shirou/gopsutil/v3/process"
)
type WsInput struct {
Type string `json:"type"`
DownloadProgress
PsProcessConfig
SSHSessionConfig
NetConfig
}
type DownloadProgress struct {
Keys []string `json:"keys"`
}
type PsProcessConfig struct {
Pid int32 `json:"pid"`
Name string `json:"name"`
Username string `json:"username"`
}
type SSHSessionConfig struct {
LoginUser string `json:"loginUser"`
LoginIP string `json:"loginIP"`
}
type NetConfig struct {
Port uint32 `json:"port"`
ProcessName string `json:"processName"`
ProcessID int32 `json:"processID"`
}
type PsProcessData struct {
PID int32 `json:"PID"`
Name string `json:"name"`
PPID int32 `json:"PPID"`
Username string `json:"username"`
Status string `json:"status"`
StartTime string `json:"startTime"`
NumThreads int32 `json:"numThreads"`
NumConnections int `json:"numConnections"`
CpuPercent string `json:"cpuPercent"`
DiskRead string `json:"diskRead"`
DiskWrite string `json:"diskWrite"`
CmdLine string `json:"cmdLine"`
Rss string `json:"rss"`
VMS string `json:"vms"`
HWM string `json:"hwm"`
Data string `json:"data"`
Stack string `json:"stack"`
Locked string `json:"locked"`
Swap string `json:"swap"`
CpuValue float64 `json:"cpuValue"`
RssValue uint64 `json:"rssValue"`
Envs []string `json:"envs"`
OpenFiles []process.OpenFilesStat `json:"openFiles"`
Connects []processConnect `json:"connects"`
}
type processConnect struct {
Type string `json:"type"`
Status string `json:"status"`
Laddr net.Addr `json:"localaddr"`
Raddr net.Addr `json:"remoteaddr"`
PID int32 `json:"PID"`
Name string `json:"name"`
}
type ProcessConnects []processConnect
func (p ProcessConnects) Len() int {
return len(p)
}
func (p ProcessConnects) Less(i, j int) bool {
return p[i].PID < p[j].PID
}
func (p ProcessConnects) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
type sshSession struct {
Username string `json:"username"`
PID int32 `json:"PID"`
Terminal string `json:"terminal"`
Host string `json:"host"`
LoginTime string `json:"loginTime"`
}
func ProcessData(c *Client, inputMsg []byte) {
wsInput := &WsInput{}
err := json.Unmarshal(inputMsg, wsInput)
if err != nil {
log.Errorf("unmarshal wsInput error,err %s", err.Error())
return
}
switch wsInput.Type {
case "ps":
res, err := getProcessData(wsInput.PsProcessConfig)
if err != nil {
return
}
c.Msg <- res
case "ssh":
res, err := getSSHSessions(wsInput.SSHSessionConfig)
if err != nil {
return
}
c.Msg <- res
case "net":
res, err := getNetConnections(wsInput.NetConfig)
if err != nil {
return
}
c.Msg <- res
}
}
type Process struct {
Total uint64 `json:"total"`
Written uint64 `json:"written"`
Percent float64 `json:"percent"`
Name string `json:"name"`
}
const (
b = uint64(1)
kb = 1024 * b
mb = 1024 * kb
gb = 1024 * mb
)
func formatBytes(bytes uint64) string {
switch {
case bytes < kb:
return fmt.Sprintf("%dB", bytes)
case bytes < mb:
return fmt.Sprintf("%.2fKB", float64(bytes)/float64(kb))
case bytes < gb:
return fmt.Sprintf("%.2fMB", float64(bytes)/float64(mb))
default:
return fmt.Sprintf("%.2fGB", float64(bytes)/float64(gb))
}
}
func getProcessData(processConfig PsProcessConfig) (res []byte, err error) {
var processes []*process.Process
processes, err = process.Processes()
if err != nil {
return
}
var (
result []PsProcessData
resultMutex sync.Mutex
wg sync.WaitGroup
numWorkers = 4
)
handleData := func(proc *process.Process) {
procData := PsProcessData{
PID: proc.Pid,
}
if processConfig.Pid > 0 && processConfig.Pid != proc.Pid {
return
}
if procName, err := proc.Name(); err == nil {
procData.Name = procName
} else {
procData.Name = "<UNKNOWN>"
}
if processConfig.Name != "" && !strings.Contains(procData.Name, processConfig.Name) {
return
}
if username, err := proc.Username(); err == nil {
procData.Username = username
}
if processConfig.Username != "" && !strings.Contains(procData.Username, processConfig.Username) {
return
}
procData.PPID, _ = proc.Ppid()
statusArray, _ := proc.Status()
if len(statusArray) > 0 {
procData.Status = strings.Join(statusArray, ",")
}
createTime, procErr := proc.CreateTime()
if procErr == nil {
t := time.Unix(createTime/1000, 0)
procData.StartTime = t.Format("2006-1-2 15:04:05")
}
procData.NumThreads, _ = proc.NumThreads()
connections, procErr := proc.Connections()
if procErr == nil {
procData.NumConnections = len(connections)
for _, conn := range connections {
if conn.Laddr.IP != "" || conn.Raddr.IP != "" {
procData.Connects = append(procData.Connects, processConnect{
Status: conn.Status,
Laddr: conn.Laddr,
Raddr: conn.Raddr,
})
}
}
}
procData.CpuValue, _ = proc.CPUPercent()
procData.CpuPercent = fmt.Sprintf("%.2f", procData.CpuValue) + "%"
menInfo, procErr := proc.MemoryInfo()
if procErr == nil {
procData.Rss = formatBytes(menInfo.RSS)
procData.RssValue = menInfo.RSS
procData.Data = formatBytes(menInfo.Data)
procData.VMS = formatBytes(menInfo.VMS)
procData.HWM = formatBytes(menInfo.HWM)
procData.Stack = formatBytes(menInfo.Stack)
procData.Locked = formatBytes(menInfo.Locked)
procData.Swap = formatBytes(menInfo.Swap)
} else {
procData.Rss = "--"
procData.Data = "--"
procData.VMS = "--"
procData.HWM = "--"
procData.Stack = "--"
procData.Locked = "--"
procData.Swap = "--"
procData.RssValue = 0
}
ioStat, procErr := proc.IOCounters()
if procErr == nil {
procData.DiskWrite = formatBytes(ioStat.WriteBytes)
procData.DiskRead = formatBytes(ioStat.ReadBytes)
} else {
procData.DiskWrite = "--"
procData.DiskRead = "--"
}
procData.CmdLine, _ = proc.Cmdline()
procData.OpenFiles, _ = proc.OpenFiles()
procData.Envs, _ = proc.Environ()
resultMutex.Lock()
result = append(result, procData)
resultMutex.Unlock()
}
chunkSize := (len(processes) + numWorkers - 1) / numWorkers
for i := 0; i < numWorkers; i++ {
wg.Add(1)
start := i * chunkSize
end := (i + 1) * chunkSize
if end > len(processes) {
end = len(processes)
}
go func(start, end int) {
defer wg.Done()
for j := start; j < end; j++ {
handleData(processes[j])
}
}(start, end)
}
wg.Wait()
sort.Slice(result, func(i, j int) bool {
return result[i].PID < result[j].PID
})
res, err = json.Marshal(result)
return
}
func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
var (
result []sshSession
users []host.UserStat
processes []*process.Process
)
processes, err = process.Processes()
if err != nil {
return
}
users, err = host.Users()
if err != nil {
return
}
for _, proc := range processes {
name, _ := proc.Name()
if name != "sshd" || proc.Pid == 0 {
continue
}
connections, _ := proc.Connections()
for _, conn := range connections {
for _, user := range users {
if user.Host == "" {
continue
}
if conn.Raddr.IP == user.Host {
if config.LoginUser != "" && !strings.Contains(user.User, config.LoginUser) {
continue
}
if config.LoginIP != "" && !strings.Contains(user.Host, config.LoginIP) {
continue
}
if terminal, err := proc.Cmdline(); err == nil {
if strings.Contains(terminal, user.Terminal) {
session := sshSession{
Username: user.User,
Host: user.Host,
Terminal: user.Terminal,
PID: proc.Pid,
}
t := time.Unix(int64(user.Started), 0)
session.LoginTime = t.Format("2006-1-2 15:04:05")
result = append(result, session)
}
}
}
}
}
}
res, err = json.Marshal(result)
return
}
var netTypes = [...]string{"tcp", "udp"}
func getNetConnections(config NetConfig) (res []byte, err error) {
var (
result []processConnect
proc *process.Process
)
for _, netType := range netTypes {
connections, _ := net.Connections(netType)
if err == nil {
for _, conn := range connections {
if config.ProcessID > 0 && config.ProcessID != conn.Pid {
continue
}
proc, err = process.NewProcess(conn.Pid)
if err == nil {
name, _ := proc.Name()
if name != "" && config.ProcessName != "" && !strings.Contains(name, config.ProcessName) {
continue
}
if config.Port > 0 && config.Port != conn.Laddr.Port && config.Port != conn.Raddr.Port {
continue
}
result = append(result, processConnect{
Type: netType,
Status: conn.Status,
Laddr: conn.Laddr,
Raddr: conn.Raddr,
PID: conn.Pid,
Name: name,
})
}
}
}
}
res, err = json.Marshal(result)
return
}

View File

@@ -177,8 +177,8 @@ type MMLParam struct {
Port2 int `yaml:"port2"` Port2 int `yaml:"port2"`
Sleep int64 `yaml:"sleep"` Sleep int64 `yaml:"sleep"`
DeadLine int64 `yaml:"deadLine"` DeadLine int64 `yaml:"deadLine"`
SizeRow byte `yaml:"sizeRow"` SizeRow int16 `yaml:"sizeRow"`
SizeCol byte `yaml:"sizeCol"` SizeCol int16 `yaml:"sizeCol"`
BufferSize int `yaml:"bufferSize"` BufferSize int `yaml:"bufferSize"`
User string `yaml:"user"` User string `yaml:"user"`
Password string `ymal:"password"` Password string `ymal:"password"`
@@ -226,8 +226,8 @@ func NewYamlConfig() YamlConfig {
ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True", ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True",
}, },
MML: MMLParam{ MML: MMLParam{
SizeRow: 100, SizeRow: 200,
SizeCol: 128, SizeCol: 120,
BufferSize: 65535, BufferSize: 65535,
}, },
Alarm: AlarmConfig{ Alarm: AlarmConfig{

View File

@@ -54,14 +54,14 @@ redis:
# OMC系统使用库 # OMC系统使用库
default: default:
port: 6379 # Redis port port: 6379 # Redis port
host: "192.168.2.219" # Redis host host: "127.0.0.1" # Redis host
password: "123456" password: "helloearth"
db: 10 # Redis db_num db: 10 # Redis db_num
# UDM网元用户库 # UDM网元用户库
udmuser: udmuser:
port: 6379 # Redis port port: 6379 # Redis port
host: "192.168.2.219" host: "127.0.0.1"
password: "123456" password: "helloearth"
db: 0 # Redis db_num db: 0 # Redis db_num
# 多个数据源时可以用这个指定默认的数据源 # 多个数据源时可以用这个指定默认的数据源
defaultDataSourceName: "default" defaultDataSourceName: "default"
@@ -73,13 +73,12 @@ mml:
port2: 5002 port2: 5002
sleep: 200 sleep: 200
deadLine: 10 deadLine: 10
sizeRow: 100 sizeRow: 600
sizeCol: 128 sizeCol: 128
bufferSize: 65535 bufferSize: 65535
user: admin user: admin
password: admin password: admin
mmlHome: ./mmlhome mmlHome: ./mmlhome
upload: /home/manager
# NE config # NE config
ne: ne:

View File

@@ -21,17 +21,9 @@ rest:
- ipv4: 0.0.0.0 - ipv4: 0.0.0.0
ipv6: ipv6:
port: 33040 port: 33040
- ipv4: 0.0.0.0
ipv6:
port: 34443
scheme: https
clientAuthType: 0
caFile: ./etc/certs/omc-ca.crt
certFile: ./etc/certs/omc-server.crt
keyFile: ./etc/certs/omc-server.key
webServer: webServer:
enabled: true enabled: false
rootDir: d:/local.git/fe.ems.vue3/dist rootDir: d:/local.git/fe.ems.vue3/dist
listen: listen:
- addr: :80 - addr: :80
@@ -46,10 +38,10 @@ webServer:
database: database:
type: mysql type: mysql
user: root user: root
password: 1000omc@kp! password: "root@1234"
host: 127.0.0.1 host: "192.168.5.59"
port: 33066 port: 3306
name: omc_db name: "omc_db"
connParam: charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True connParam: charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True
backup: d:/local.git/be.ems/restagent/database backup: d:/local.git/be.ems/restagent/database
@@ -59,14 +51,14 @@ redis:
# OMC系统使用库 # OMC系统使用库
default: default:
port: 6379 # Redis port port: 6379 # Redis port
host: "192.168.2.219" # Redis host host: "192.168.5.59" # Redis host
password: "123456" password: "redis@1234"
db: 10 # Redis db_num db: 10 # Redis db_num
# UDM网元用户库 # UDM网元用户库
udmuser: udmuser:
port: 6379 # Redis port port: 6379 # Redis port
host: "192.168.2.219" host: "192.168.5.60"
password: "123456" password: "helloearth"
db: 0 # Redis db_num db: 0 # Redis db_num
# 多个数据源时可以用这个指定默认的数据源 # 多个数据源时可以用这个指定默认的数据源
defaultDataSourceName: "default" defaultDataSourceName: "default"
@@ -78,7 +70,7 @@ mml:
port2: 5002 port2: 5002
sleep: 200 sleep: 200
deadLine: 10 deadLine: 10
sizeRow: 100 sizeRow: 600
sizeCol: 128 sizeCol: 128
bufferSize: 65535 bufferSize: 65535
user: admin user: admin
@@ -87,7 +79,7 @@ mml:
# NE config # NE config
ne: ne:
user: root user: omcuser
etcdir: /usr/local/etc etcdir: /usr/local/etc
bindir: /usr/local/bin bindir: /usr/local/bin
omcdir: /usr/local/omc omcdir: /usr/local/omc
@@ -116,12 +108,12 @@ omc:
checksign: false checksign: false
rootDir: ./ rootDir: ./
binDir: ./bin binDir: ./bin
backup: ./backup backup: C:/usr/local/omc/backup
upload: ./upload upload: C:/usr/local/omc/upload
frontUpload: d:/local.git/fe.ems/upload frontUpload: C:/usr/local/omc/upload
frontTraceDir: d:/local.git/fe.ems/trace frontTraceDir: C:/usr/local/omc/trace
software: ./software software: C:/usr/local/omc/software
license: ./license license: C:/usr/local/omc/license
gtpUri: gtp:192.168.2.219:2152 gtpUri: gtp:192.168.2.219:2152
checkContentType: false checkContentType: false
testMode: false testMode: false
@@ -134,7 +126,7 @@ omc:
# email/sms # email/sms
# smProxy: sms(Short Message Service)/smsc(SMS Centre) # smProxy: sms(Short Message Service)/smsc(SMS Centre)
alarm: alarm:
forwardAlarm: true forwardAlarm: false
email: email:
smtp: mail.agrandtech.com smtp: mail.agrandtech.com
port: 25 port: 25
@@ -189,12 +181,12 @@ testConfig:
file: ./etc/testconfig.yaml file: ./etc/testconfig.yaml
# 静态文件配置, 相对项目根路径或填绝对路径 # 静态文件配置, 相对项目根路径或填绝对路径
staticFile: # staticFile:
# 默认资源dir目录需要预先创建 # # 默认资源dir目录需要预先创建
default: # default:
prefix: "/static" # prefix: "/static"
dir: "./static" # dir: "./static"
# 文件上传资源目录映射,与项目目录同级 # # 文件上传资源目录映射,与项目目录同级
upload: # upload:
prefix: "/upload" # prefix: "/upload"
dir: "./upload" # dir: "./upload"

View File

@@ -1,7 +1,7 @@
# Makefile for rest agent project # Makefile for rest agent project
PROJECT = OMC PROJECT = OMC
VERSION = 2.2405.4 VERSION = 2.2407.1
PLATFORM = amd64 PLATFORM = amd64
ARMPLATFORM = aarch64 ARMPLATFORM = aarch64
BUILDDIR = ../../build BUILDDIR = ../../build
@@ -14,7 +14,7 @@ BINNAME = restagent
.PHONY: build $(BINNAME) .PHONY: build $(BINNAME)
build $(BINNAME): build $(BINNAME):
go build -o $(BINNAME) -v -ldflags "-X '$(LIBDIR)/global.Version=$(VERSION)' \ go build -o $(BINNAME) -v -ldflags "-s -w -X '$(LIBDIR)/global.Version=$(VERSION)' \
-X '$(LIBDIR)/global.BuildTime=`date`' \ -X '$(LIBDIR)/global.BuildTime=`date`' \
-X '$(LIBDIR)/global.GoVer=`go version`'" -X '$(LIBDIR)/global.GoVer=`go version`'"

View File

@@ -249,7 +249,7 @@ func main() {
uriGroup := app.Group(config.UriPrefix) uriGroup := app.Group(config.UriPrefix)
uriGroup.Any("/*any", gin.WrapH(routes.NewRouter())) uriGroup.Any("/*any", gin.WrapH(routes.NewRouter()))
// AMF上报的UE事件, 无前缀,暂时特殊处理 // AMF上报的UE事件, 无前缀,暂时特殊处理
app.POST(event.UriUEEvent, event.PostUEEventFromAMF) app.POST(event.UriUEEventAMF, event.PostUEEventFromAMF)
var listenLocalhost bool = false var listenLocalhost bool = false
for _, rest := range conf.Rest { for _, rest := range conf.Rest {

View File

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

View File

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

View File

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

View File

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

View File

@@ -84,8 +84,8 @@ func Authorization(c *gin.Context) string {
return "" return ""
} }
// 拆分 Authorization 请求头,提取 JWT 令牌部分 // 拆分 Authorization 请求头,提取 JWT 令牌部分
arr := strings.Split(authHeader, token.HEADER_PREFIX) arr := strings.SplitN(authHeader, token.HEADER_PREFIX, 2)
if len(arr) == 2 && arr[1] == "" { if len(arr) < 2 {
return "" return ""
} }
return arr[1] return arr[1]
@@ -212,6 +212,11 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string)
conditions = append(conditions, sql) 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 { 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) 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) conditions = append(conditions, sql)
@@ -220,7 +225,7 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string)
if roledatascope.SELF == dataScope { if roledatascope.SELF == dataScope {
// 数据权限为仅本人且没有userAlias别名不查询任何数据 // 数据权限为仅本人且没有userAlias别名不查询任何数据
if userAlias == "" { if userAlias == "" {
sql := fmt.Sprintf(`%s.dept_id = '0'`, deptAlias) sql := fmt.Sprintf(`%s.parent_id = '0'`, deptAlias)
conditions = append(conditions, sql) conditions = append(conditions, sql)
} else { } else {
sql := fmt.Sprintf(`%s.user_id = '%s'`, userAlias, userInfo.UserID) 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 { if v == 0 {
return "" 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: case string:
parsedTime, err := time.Parse(formatStr, v) parsedTime, err := time.Parse(formatStr, v)
if err != nil { 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 { func ConvertIPMask(bits int64) string {
if bits < 0 || bits > 32 { if bits < 0 || bits > 32 {
return "Invalid Mask Bits" return "255.255.255.255"
} }
// 构建一个32位的uint32类型掩码指定前bits位为1其余为0 // 构建一个32位的uint32类型掩码指定前bits位为1其余为0

View File

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

View File

@@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"strings" "strings"
"be.ems/src/framework/config"
"be.ems/src/framework/logger" "be.ems/src/framework/logger"
"be.ems/src/framework/utils/cmd" "be.ems/src/framework/utils/cmd"
"be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/parse"
@@ -23,35 +22,31 @@ type FileListRow struct {
} }
// 文件列表 // 文件列表
// neIp 网元IP空字符串为本地
// search 文件名后模糊* // search 文件名后模糊*
// //
// return 目录大小,行记录,异常 // return 目录大小,行记录,异常
func FileList(path, neIp, search string) (string, []FileListRow, error) { func FileList(sshClient *ConnSSH, path, search string) (string, []FileListRow, error) {
totalSize := "" totalSize := ""
var rows []FileListRow var rows []FileListRow
rowStr := "" rowStr := ""
// 发送命令 // 发送命令
searchStr := "" searchStr := "*"
if search != "" { if search != "" {
searchStr = search + "*" searchStr = search + searchStr
} }
pathStr := fmt.Sprintf("cd %s \n", path) cmdStr := fmt.Sprintf("cd %s && ls -lthd --time-style=+%%s %s", path, searchStr)
cmdStr := fmt.Sprintf("ls -lht --time-style=+%%s %s \n", searchStr)
// 是否远程读取 // 是否远程客户端读取
if neIp != "" { if sshClient == nil {
usernameNe := config.Get("ne.user").(string) // 网元统一用户 resultStr, err := cmd.Execf(cmdStr)
sshHost := fmt.Sprintf("%s@%s", usernameNe, neIp)
resultStr, err := cmd.ExecWithCheck("ssh", sshHost, pathStr, cmdStr)
if err != nil { if err != nil {
logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error()) logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error())
return totalSize, rows, err return totalSize, rows, err
} }
rowStr = resultStr rowStr = resultStr
} else { } else {
resultStr, err := cmd.Execf(pathStr, cmdStr) resultStr, err := sshClient.RunCMD(cmdStr)
if err != nil { if err != nil {
logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error()) logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error())
return totalSize, rows, err 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 package ssh
import ( import (
"bytes"
"fmt" "fmt"
"io"
"os" "os"
"os/user" "os/user"
"path/filepath"
"strings" "strings"
"sync"
"time" "time"
"be.ems/src/framework/logger" "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 执行单次命令 // RunCMD 执行单次命令
func (c *ConnSSH) RunCMD(cmd string) (string, error) { func (c *ConnSSH) RunCMD(cmd string) (string, error) {
if c.Client == nil { if c.Client == nil {
@@ -128,57 +106,6 @@ func (c *ConnSSH) RunCMD(cmd string) (string, error) {
return c.LastResult, err 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客户端会话对象 // NewClientSession 创建SSH客户端会话对象
func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) { func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) {
sshSession, err := c.Client.NewSession() sshSession, err := c.Client.NewSession()
@@ -216,69 +143,6 @@ func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) {
}, nil }, 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对象 // NewClientSFTP 创建SSH客户端SFTP对象
func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) { func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
sftpClient, err := gosftp.NewClient(c.Client) sftpClient, err := gosftp.NewClient(c.Client)
@@ -292,193 +156,70 @@ func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) {
}, nil }, nil
} }
// SSHClientSFTP SSH客户端SFTP对象 // NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连
type SSHClientSFTP struct { //
Client *gosftp.Client // 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 关闭会话 // CurrentUserRsaKey 当前用户OMC使用的RSA私钥
func (s *SSHClientSFTP) Close() { // 默认读取私钥
if s.Client != nil { // ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
s.Client.Close() // ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub
} func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) {
} usr, err := user.Current()
// CopyDirRemoteToLocal 复制目录-远程到本地
func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error {
// 列出远程目录中的文件和子目录
remoteFiles, err := s.Client.ReadDir(remoteDir)
if err != nil { if err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error()) logger.Errorf("CurrentUserRsaKey get => %s", err.Error())
return err return "", err
} }
// 创建本地目录 // 是否存在私钥并创建
err = os.MkdirAll(localDir, 0775) keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir)
if err != nil { if _, err := os.Stat(keyPath); err != nil {
logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error()) if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil {
return err logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error())
}
// 遍历远程文件和子目录并复制到本地
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
// 读取用户默认的文件
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 复制目录-本地到远程 // SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥
func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error { func (c *ConnSSH) SendToAuthorizedKeys() error {
// 创建远程目录 publicKey, err := c.CurrentUserRsaKey(true)
err := s.Client.MkdirAll(remoteDir)
if err != nil { if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error())
return err return err
} }
authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey))
// 遍历本地目录中的文件和子目录并复制到远程 cmdStrArr := []string{
err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error { 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),
if err != nil { 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),
return err fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User),
} }
_, err = c.RunCMD(strings.Join(cmdStrArr, " && "))
// 生成远程路径
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 { if err != nil {
logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error()) logger.Errorf("SendAuthorizedKeys echo err %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 err
} }
return nil 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.User)
// fmt.Fprintln(client, c.Password) // 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 c.Client = &client
// 调整窗口大小 (120 列 x 128 行)
requestPty(c.Client, 120, 128)
// 排空连接登录的信息 // 排空连接登录的信息
c.RunCMD("") c.RunCMD("")
return c, nil return c, nil
@@ -73,8 +73,6 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
return "", fmt.Errorf("telnet client not connected") return "", fmt.Errorf("telnet client not connected")
} }
conn := *c.Client conn := *c.Client
var buf bytes.Buffer
tmp := make([]byte, 1024)
// 写入命令 // 写入命令
if cmd != "" { if cmd != "" {
@@ -83,22 +81,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
} }
} }
// 读取命令消息 var buf bytes.Buffer
tmp := make([]byte, 1024)
for { for {
// 设置读取超时时间为1000毫秒 // 读取命令消息
conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
n, err := conn.Read(tmp) n, err := conn.Read(tmp)
if err != nil { if n == 0 || err != nil {
// 判断是否是超时错误 tmp = nil
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
break
}
break break
} }
if n == 0 {
tmpStr := string(tmp[:n])
buf.WriteString(tmpStr)
// 是否有终止符
if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") {
tmp = nil
break break
} }
buf.Write(tmp[:n])
} }
defer buf.Reset() defer buf.Reset()
@@ -107,77 +107,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) {
} }
// NewClient 创建Telnet客户端会话对象 // NewClient 创建Telnet客户端会话对象
func (c *ConnTelnet) NewClientSession(cols, rows uint8) (*TelnetClientSession, error) { func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) {
if c.Client == nil { if c.Client == nil {
return nil, fmt.Errorf("telnet client not connected") return nil, fmt.Errorf("telnet client not connected")
} }
requestPty(c.Client, cols, rows)
return &TelnetClientSession{ return &TelnetClientSession{
Client: *c.Client, Client: *c.Client,
}, nil }, nil
} }
// TelnetClientSession Telnet客户端会话对象 // requestPty 调整终端窗口大小
type TelnetClientSession struct { func requestPty(client *net.Conn, cols, rows int) error {
Client net.Conn if client == nil {
} return fmt.Errorf("telnet client not connected")
}
// Close 关闭会话 conn := *client
func (s *TelnetClientSession) Close() { // 需要确保接收方理解并正确处理发送窗口大小设置命令
if s.Client != nil { conn.Write([]byte{255, 251, 31})
s.Client.Close() conn.Write([]byte{255, 250, 31, byte(cols >> 8), byte(cols & 0xFF), byte(rows >> 8), byte(rows & 0xFF), 255, 240})
} return nil
}
// 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

@@ -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 package controller
import ( import (
"be.ems/lib/core/utils/date"
"be.ems/src/framework/i18n" "be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/vo/result" "be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model" "be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service" neDataService "be.ems/src/modules/network_data/service"

View File

@@ -1,22 +1,30 @@
package controller package controller
import ( import (
"encoding/json"
"fmt"
"strconv"
"strings" "strings"
"time"
"be.ems/src/framework/i18n" "be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result" "be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model" "be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service" neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/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"
"github.com/gin-gonic/gin/binding"
) )
// 实例化控制层 AMFController 结构体 // 实例化控制层 AMFController 结构体
var NewAMFController = &AMFController{ var NewAMFController = &AMFController{
neInfoService: neService.NewNeInfoImpl, neInfoService: neService.NewNeInfoImpl,
ueEventService: neDataService.NewUEEventImpl, ueEventService: neDataService.NewUEEventAMFImpl,
} }
// 网元AMF // 网元AMF
@@ -25,8 +33,8 @@ var NewAMFController = &AMFController{
type AMFController struct { type AMFController struct {
// 网元信息服务 // 网元信息服务
neInfoService neService.INeInfo neInfoService neService.INeInfo
// CDR会话事件服务 // UE会话事件服务
ueEventService neDataService.IUEEvent ueEventService neDataService.IUEEventAMF
} }
// UE会话列表 // UE会话列表
@@ -34,19 +42,19 @@ type AMFController struct {
// GET /ue/list // GET /ue/list
func (s *AMFController) UEList(c *gin.Context) { func (s *AMFController) UEList(c *gin.Context) {
language := ctx.AcceptLanguage(c) language := ctx.AcceptLanguage(c)
var querys model.UEEventQuery var querys model.UEEventAMFQuery
if err := c.ShouldBindQuery(&querys); err != nil { if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
// 查询网元获取IP // 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != querys.NeID || neInfo.IP == "" { // if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return // return
} // }
querys.RmUID = neInfo.RmUID // querys.RmUID = neInfo.RmUID
// 查询数据 // 查询数据
data := s.ueEventService.SelectPage(querys) 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}) msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg)) 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 package controller
import ( import (
"encoding/json"
"fmt"
"strconv"
"strings" "strings"
"time"
"be.ems/src/framework/i18n" "be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx" "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/utils/parse"
"be.ems/src/framework/vo/result" "be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model" "be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service" neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/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"
"github.com/gin-gonic/gin/binding"
) )
// 实例化控制层 IMSController 结构体 // 实例化控制层 IMSController 结构体
var NewIMSController = &IMSController{ var NewIMSController = &IMSController{
neInfoService: neService.NewNeInfoImpl, neInfoService: neService.NewNeInfoImpl,
cdrEventService: neDataService.NewCDREventImpl, cdrEventService: neDataService.NewCDREventIMSImpl,
} }
// 网元IMS // 网元IMS
@@ -26,7 +35,7 @@ type IMSController struct {
// 网元信息服务 // 网元信息服务
neInfoService neService.INeInfo neInfoService neService.INeInfo
// CDR会话事件服务 // CDR会话事件服务
cdrEventService neDataService.ICDREvent cdrEventService neDataService.ICDREventIMS
} }
// CDR会话列表 // CDR会话列表
@@ -34,19 +43,19 @@ type IMSController struct {
// GET /cdr/list // GET /cdr/list
func (s *IMSController) CDRList(c *gin.Context) { func (s *IMSController) CDRList(c *gin.Context) {
language := ctx.AcceptLanguage(c) language := ctx.AcceptLanguage(c)
var querys model.CDREventQuery var querys model.CDREventIMSQuery
if err := c.ShouldBindQuery(&querys); err != nil { if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
// 查询网元获取IP // 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != querys.NeID || neInfo.IP == "" { // if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return // return
} // }
querys.RmUID = neInfo.RmUID // querys.RmUID = neInfo.RmUID
// 查询数据 // 查询数据
data := s.cdrEventService.SelectPage(querys) 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}) msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg)) 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 package controller
import ( import (
"encoding/json"
"fmt"
"strconv"
"strings" "strings"
"time"
"be.ems/src/framework/i18n" "be.ems/src/framework/i18n"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result" "be.ems/src/framework/vo/result"
"be.ems/src/modules/network_data/model" "be.ems/src/modules/network_data/model"
neDataService "be.ems/src/modules/network_data/service" neDataService "be.ems/src/modules/network_data/service"
neService "be.ems/src/modules/network_element/service" neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
) )
// 实例化控制层 IMSController 结构体 // 实例化控制层 SMFController 结构体
var NewSMFController = &SMFController{ var NewSMFController = &SMFController{
neInfoService: neService.NewNeInfoImpl, neInfoService: neService.NewNeInfoImpl,
cdrEventService: neDataService.NewSMFCDREventImpl, cdrEventService: neDataService.NewCDREventSMFImpl,
} }
// 网元IMS // 网元SMF
// //
// PATH /ims // PATH /smf
type SMFController struct { type SMFController struct {
// 网元信息服务 // 网元信息服务
neInfoService neService.INeInfo neInfoService neService.INeInfo
// SMF CDR会话事件服务 // CDR会话事件服务
cdrEventService neDataService.SMFCDREvent cdrEventService neDataService.ICDREventSMF
} }
// CDR会话列表 // CDR会话列表
@@ -34,19 +41,19 @@ type SMFController struct {
// GET /cdr/list // GET /cdr/list
func (s *SMFController) CDRList(c *gin.Context) { func (s *SMFController) CDRList(c *gin.Context) {
language := ctx.AcceptLanguage(c) language := ctx.AcceptLanguage(c)
var querys model.SMFCDREventQuery var querys model.CDREventSMFQuery
if err := c.ShouldBindQuery(&querys); err != nil { if err := c.ShouldBindQuery(&querys); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
// 查询网元获取IP // 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID)
if neInfo.NeId != querys.NeID || neInfo.IP == "" { // if neInfo.NeId != querys.NeID || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return // return
} // }
querys.RmUID = neInfo.RmUID // querys.RmUID = neInfo.RmUID
// 查询数据 // 查询数据
data := s.cdrEventService.SelectPage(querys) 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}) msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows})
c.JSON(200, result.OkMsg(msg)) 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 ( import (
"fmt" "fmt"
"path/filepath"
"strings" "strings"
"time" "time"
mmlclient "be.ems/lib/core/mml_client"
"be.ems/src/framework/constants/uploadsubpath" "be.ems/src/framework/constants/uploadsubpath"
"be.ems/src/framework/i18n" "be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/ctx"
"be.ems/src/framework/utils/file" "be.ems/src/framework/utils/file"
"be.ems/src/framework/utils/parse" "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/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" neService "be.ems/src/modules/network_element/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
@@ -21,21 +22,21 @@ import (
// 实例化控制层 UDMAuthController 结构体 // 实例化控制层 UDMAuthController 结构体
var NewUDMAuth = &UDMAuthController{ var NewUDMAuth = &UDMAuthController{
udmAuthService: neService.NewUDMAuthImpl, udmAuthService: neDataService.NewUDMAuthImpl,
neInfoService: neService.NewNeInfoImpl, neInfoService: neService.NewNeInfoImpl,
} }
// UDM鉴权用户请求 // UDM鉴权用户
// //
// PATH /udm/auth // PATH /udm/auth
type UDMAuthController struct { type UDMAuthController struct {
// UDM鉴权信息服务 // UDM鉴权信息服务
udmAuthService neService.IUDMAuth udmAuthService neDataService.IUDMAuth
// 网元信息服务 // 网元信息服务
neInfoService neService.INeInfo neInfoService neService.INeInfo
} }
// UDM鉴权用户-获取全部保存数据 // UDM鉴权用户重载数据
// //
// POST /resetData/:neId // POST /resetData/:neId
func (s *UDMAuthController) ResetData(c *gin.Context) { func (s *UDMAuthController) ResetData(c *gin.Context) {
@@ -47,21 +48,21 @@ func (s *UDMAuthController) ResetData(c *gin.Context) {
} }
neId = "" neId = ""
data := s.udmAuthService.Save(neId) data := s.udmAuthService.ResetData(neId)
c.JSON(200, result.OkData(data)) c.JSON(200, result.OkData(data))
} }
// UDM鉴权用户 // UDM鉴权用户列表
// //
// GET /list // GET /list
func (s *UDMAuthController) List(c *gin.Context) { func (s *UDMAuthController) List(c *gin.Context) {
querys := ctx.QueryMap(c) querys := ctx.QueryMap(c)
querys["neId"] = "" querys["neId"] = ""
data := s.udmAuthService.Page(querys) data := s.udmAuthService.SelectPage(querys)
c.JSON(200, result.Ok(data)) c.JSON(200, result.Ok(data))
} }
// UDM鉴权用户-信息 // UDM鉴权用户信息
// //
// GET /:neId/:imsi // GET /:neId/:imsi
func (s *UDMAuthController) Info(c *gin.Context) { func (s *UDMAuthController) Info(c *gin.Context) {
@@ -80,10 +81,16 @@ func (s *UDMAuthController) Info(c *gin.Context) {
return 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 // 发送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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return return
@@ -94,31 +101,31 @@ func (s *UDMAuthController) Info(c *gin.Context) {
return return
} }
// 查询数据库是否存在并存入
neId = "" neId = ""
var userInfo model.UDMAuth u := model.UDMAuth{
list := s.udmAuthService.List(model.UDMAuth{NeID: neId, Imsi: imsi}) IMSI: imsi,
if len(list) > 0 { Amf: data["amf"],
userInfo = list[0] Status: "1",
// 返回查询的用户信息 Ki: data["ki"],
userInfo.Amf = data["amf"] AlgoIndex: data["algo"],
userInfo.AlgoIndex = data["algo"] Opc: data["opc"],
userInfo.Opc = data["opc"] NeId: neId,
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)
} }
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 // POST /:neId
func (s *UDMAuthController) Add(c *gin.Context) { func (s *UDMAuthController) Add(c *gin.Context) {
@@ -131,7 +138,7 @@ func (s *UDMAuthController) Add(c *gin.Context) {
var body model.UDMAuth var body model.UDMAuth
err := c.ShouldBindBodyWith(&body, binding.JSON) 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"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
@@ -143,10 +150,16 @@ func (s *UDMAuthController) Add(c *gin.Context) {
return 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 // 发送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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return return
@@ -155,12 +168,12 @@ func (s *UDMAuthController) Add(c *gin.Context) {
// 命令ok时 // 命令ok时
if strings.Contains(data, "ok") { if strings.Contains(data, "ok") {
neId = "" neId = ""
s.udmAuthService.Insert(neId, body) go s.udmAuthService.Insert(neId, body)
} }
c.JSON(200, result.OkData(data)) c.JSON(200, result.OkData(data))
} }
// UDM鉴权用户-批量添加 // UDM鉴权用户批量新增
// //
// POST /:neId/:num // POST /:neId/:num
func (s *UDMAuthController) Adds(c *gin.Context) { func (s *UDMAuthController) Adds(c *gin.Context) {
@@ -174,7 +187,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
var body model.UDMAuth var body model.UDMAuth
err := c.ShouldBindBodyWith(&body, binding.JSON) 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"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
@@ -186,10 +199,16 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
return 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 // 发送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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return return
@@ -198,12 +217,12 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
// 命令ok时 // 命令ok时
if strings.Contains(data, "ok") { if strings.Contains(data, "ok") {
neId = "" neId = ""
s.udmAuthService.Inserts(neId, body, num) go s.udmAuthService.LoadData(neId, body.IMSI, num)
} }
c.JSON(200, result.OkData(data)) c.JSON(200, result.OkData(data))
} }
// UDM鉴权用户-修改 // UDM鉴权用户修改
// //
// PUT /:neId // PUT /:neId
func (s *UDMAuthController) Edit(c *gin.Context) { func (s *UDMAuthController) Edit(c *gin.Context) {
@@ -216,7 +235,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
var body model.UDMAuth var body model.UDMAuth
err := c.ShouldBindBodyWith(&body, binding.JSON) 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"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
@@ -228,23 +247,29 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
return return
} }
msg := fmt.Sprintf("mod authdata:imsi=%s", body.Imsi) telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
// 修改的参数名称 if err != nil {
if body.Ki != "" { c.JSON(200, result.ErrMsg(err.Error()))
msg += fmt.Sprintf(",ki=%s", body.Ki) return
}
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)
} }
defer telnetClient.Close()
// 发送MML // 发送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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return return
@@ -253,12 +278,12 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
// 命令ok时 // 命令ok时
if strings.Contains(data, "ok") { if strings.Contains(data, "ok") {
neId = "" neId = ""
s.udmAuthService.Update(neId, body) go s.udmAuthService.Insert(neId, body)
} }
c.JSON(200, result.OkData(data)) c.JSON(200, result.OkData(data))
} }
// UDM鉴权用户-删除 // UDM鉴权用户删除
// //
// DELETE /:neId/:imsi // DELETE /:neId/:imsi
func (s *UDMAuthController) Remove(c *gin.Context) { func (s *UDMAuthController) Remove(c *gin.Context) {
@@ -285,27 +310,34 @@ func (s *UDMAuthController) Remove(c *gin.Context) {
return 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{} resultData := map[string]string{}
for _, imsi := range uniqueIDs { for _, imsi := range uniqueIDs {
msg := fmt.Sprintf("del authdat:imsi=%s", imsi)
// 发送MML // 发送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 { if err != nil {
resultData[imsi] = err.Error() resultData[imsi] = err.Error()
continue
} }
// 命令ok时 // 命令ok时
if strings.Contains(data, "ok") { if strings.Contains(data, "ok") {
neId = "" neId = ""
s.udmAuthService.Delete(neId, imsi) go s.udmAuthService.Delete(neId, imsi)
resultData[imsi] = data
} }
resultData[imsi] = data
} }
c.JSON(200, result.OkData(resultData)) c.JSON(200, result.OkData(resultData))
} }
// UDM鉴权用户-批量删除 // UDM鉴权用户批量删除
// //
// DELETE /:neId/:imsi/:num // DELETE /:neId/:imsi/:num
func (s *UDMAuthController) Removes(c *gin.Context) { func (s *UDMAuthController) Removes(c *gin.Context) {
@@ -325,10 +357,16 @@ func (s *UDMAuthController) Removes(c *gin.Context) {
return 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 // 发送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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return return
@@ -337,12 +375,12 @@ func (s *UDMAuthController) Removes(c *gin.Context) {
// 命令ok时 // 命令ok时
if strings.Contains(data, "ok") { if strings.Contains(data, "ok") {
neId = "" neId = ""
s.udmAuthService.Deletes(neId, imsi, num) go s.udmAuthService.LoadData(neId, imsi, num)
} }
c.JSON(200, result.OkData(data)) c.JSON(200, result.OkData(data))
} }
// UDM鉴权用户-导出 // UDM鉴权用户导出
// //
// POST /export // POST /export
func (s *UDMAuthController) Export(c *gin.Context) { 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") { 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 return
} }
neId := "" 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) filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName)
if body.Type == "csv" { if body.Type == "csv" {
@@ -373,7 +411,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
data := [][]string{} data := [][]string{}
data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"}) data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"})
for _, v := range list { 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) err := file.WriterFileCSV(data, filePath)
@@ -387,7 +425,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
// 转换数据 // 转换数据
data := [][]string{} data := [][]string{}
for _, v := range list { 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) err = file.WriterFileTXT(data, ",", filePath)
@@ -400,55 +438,68 @@ func (s *UDMAuthController) Export(c *gin.Context) {
c.FileAttachment(filePath, fileName) c.FileAttachment(filePath, fileName)
} }
// UDM鉴权用户-导入 // UDM鉴权用户导入
// //
// POST /import // POST /import
func (s *UDMAuthController) Import(c *gin.Context) { func (s *UDMAuthController) Import(c *gin.Context) {
language := ctx.AcceptLanguage(c) language := ctx.AcceptLanguage(c)
neId := c.PostForm("neId") var body struct {
if neId == "" { 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"))) c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return return
} }
formFile, err := c.FormFile("file")
if err != nil { // 判断文件名
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
return
}
// 获取文件名
if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
return return
} }
// 上传文件转存
upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
return
}
// 查询网元获取IP // 查询网元获取IP
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId)
if neInfo.NeId != neId || neInfo.IP == "" { if neInfo.NeId != body.NeId || neInfo.IP == "" {
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
return return
} }
// 本地文件 // 网元主机的SSH客户端
localPath := file.ParseUploadFilePath(upFilePath) sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
nePath := "/tmp" //config.Get("mml.upload").(string)
// 复制到远程
err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath)
if err != nil { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return 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 // 发送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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return return
@@ -456,15 +507,15 @@ func (s *UDMAuthController) Import(c *gin.Context) {
// 命令ok时 // 命令ok时
if strings.Contains(data, "ok") { if strings.Contains(data, "ok") {
if strings.HasSuffix(fileName, ".csv") { if strings.HasSuffix(body.UploadPath, ".csv") {
data := file.ReadFileCSV(localPath) data := file.ReadFileCSV(localFilePath)
neId = "" neId := ""
go s.udmAuthService.InsertCSV(neId, data) go s.udmAuthService.InsertData(neId, "csv", data)
} }
if strings.HasSuffix(fileName, ".txt") { if strings.HasSuffix(body.UploadPath, ".txt") {
data := file.ReadFileTXT(",", localPath) data := file.ReadFileTXT(",", localFilePath)
neId = "" neId := ""
go s.udmAuthService.InsertTxt(neId, data) go s.udmAuthService.InsertData(neId, "txt", data)
} }
} }
c.JSON(200, result.OkMsg(data)) c.JSON(200, result.OkMsg(data))

View File

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

View File

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

View File

@@ -2,29 +2,34 @@ package model
import "time" import "time"
// CDREvent CDR会话对象 cdr_event_smf // CDREventSMF CDR会话对象SMF cdr_event_smf
type CDREventSMF struct { type CDREventSMF struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"` NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"` 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"` Timestamp int64 `json:"timestamp" gorm:"column:timestamp"`
RecordType string `json:"recordType" gorm:"column:record_type"` CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"`
ChargingID string `json:"chargingID" gorm:"column:charging_id"` CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
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"` // RecordType string `json:"recordType" gorm:"column:record_type"`
DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"` // ChargingID string `json:"chargingID" gorm:"column:charging_id"`
PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"` // SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` // 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 NeType string `json:"neType" form:"neType" binding:"required"` // SMF
NeID string `json:"neId" form:"neId" binding:"required"` NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"` RmUID string `json:"rmUID" form:"rmUID"`
RecordType string `json:"recordType" form:"recordType"` RecordType string `json:"recordType" form:"recordType"` // 暂时没用到
SubscriberID string `json:"subscriberID" form:"subscriberID"` SubscriberID string `json:"subscriberID" form:"subscriberID"`
StartTime string `json:"startTime" form:"startTime"` StartTime string `json:"startTime" form:"startTime"`
EndTime string `json:"endTime" form:"endTime"` EndTime string `json:"endTime" form:"endTime"`

View File

@@ -3,13 +3,13 @@ package model
// UDMAuth UDM鉴权用户对象 u_auth_user // UDMAuth UDM鉴权用户对象 u_auth_user
type UDMAuth struct { type UDMAuth struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID 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 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 Ki string `json:"ki" gorm:"column:ki"` // ki
AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex
Opc string `json:"opc" gorm:"column:opc"` // opc 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 { func (UDMAuth) TableName() string {

View File

@@ -4,7 +4,7 @@ package model
type UDMSub struct { type UDMSub struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
Msisdn string `json:"msisdn" gorm:"column:msisdn"` // 相当手机号 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"` Ambr string `json:"ambr" gorm:"column:ambr"`
Nssai string `json:"nssai" gorm:"column:nssai"` Nssai string `json:"nssai" gorm:"column:nssai"`
Rat string `json:"rat" gorm:"column:rat"` Rat string `json:"rat" gorm:"column:rat"`
@@ -14,7 +14,7 @@ type UDMSub struct {
SmData string `json:"smData" gorm:"column:sm_data"` SmData string `json:"smData" gorm:"column:sm_data"`
SmfSel string `json:"smfSel" gorm:"column:smf_sel"` SmfSel string `json:"smfSel" gorm:"column:smf_sel"`
EpsDat string `json:"epsDat" gorm:"column:eps_dat"` 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"` EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"`
EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"` 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 { func (UDMSub) TableName() string {

View File

@@ -2,20 +2,20 @@ package model
import "time" import "time"
// UEEvent UE会话对象 ue_event // UEEventAMF UE会话对象AMF ue_event_amf
type UEEvent struct { type UEEventAMF struct {
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"`
NeType string `json:"neType" gorm:"column:ne_type"` NeType string `json:"neType" gorm:"column:ne_type"`
NeName string `json:"neName" gorm:"column:ne_name"` 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"` 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"` EventJSONStr string `json:"eventJSON" gorm:"column:event_json"`
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"`
} }
// UEEventQuery UE会话对象查询参数结构体 // UEEventAMFQuery UE会话对象AMF查询参数结构体
type UEEventQuery struct { type UEEventAMFQuery struct {
NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持AMF NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持AMF
NeID string `json:"neId" form:"neId" binding:"required"` NeID string `json:"neId" form:"neId" binding:"required"`
RmUID string `json:"rmUID" form:"rmUID"` 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/logger"
"be.ems/src/framework/middleware" "be.ems/src/framework/middleware"
"be.ems/src/framework/middleware/collectlogs" "be.ems/src/framework/middleware/collectlogs"
"be.ems/src/framework/middleware/repeat"
"be.ems/src/modules/network_data/controller" "be.ems/src/modules/network_data/controller"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -44,49 +45,58 @@ func Setup(router *gin.Engine) {
// 网元IMS // 网元IMS
imsGroup := neDataGroup.Group("/ims") imsGroup := neDataGroup.Group("/ims")
{ {
// CDR会话事件列表
imsGroup.GET("/cdr/list", imsGroup.GET("/cdr/list",
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
controller.NewIMSController.CDRList, controller.NewIMSController.CDRList,
) )
// CDR会话删除
imsGroup.DELETE("/cdr/:cdrIds", imsGroup.DELETE("/cdr/:cdrIds",
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewIMSController.CDRRemove, 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 // 网元SMF
smfGroup := neDataGroup.Group("/smf") smfGroup := neDataGroup.Group("/smf")
{ {
// CDR会话事件列表
smfGroup.GET("/cdr/list", smfGroup.GET("/cdr/list",
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
controller.NewSMFController.CDRList, controller.NewSMFController.CDRList,
) )
// CDR会话删除
smfGroup.DELETE("/cdr/:cdrIds", smfGroup.DELETE("/cdr/:cdrIds",
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewSMFController.CDRRemove, 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 // 网元AMF
amfGroup := neDataGroup.Group("/amf") amfGroup := neDataGroup.Group("/amf")
{ {
// UE会话事件
amfGroup.GET("/ue/list", amfGroup.GET("/ue/list",
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
controller.NewAMFController.UEList, controller.NewAMFController.UEList,
) )
// UE会话删除
amfGroup.DELETE("/ue/:ueIds", amfGroup.DELETE("/ue/:ueIds",
middleware.PreAuthorize(nil), middleware.PreAuthorize(nil),
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)),
controller.NewAMFController.UERemove, 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 // 网元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) params = append(params, query.RmUID)
} }
if query.NeType != "" { if query.NeType != "" {
conditions = append(conditions, "gk.ne_type = ?") //conditions = append(conditions, "gk.ne_type = ?")
params = append(params, query.NeType) // params = append(params, query.NeType)
tableName += strings.ToLower(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 != "" { if query.StartTime != "" {
conditions = append(conditions, dateTimeStr+" >= ?") dateStr1 = query.StartTime[:10]
params = append(params, query.StartTime) timeStr1 = query.StartTime[11:]
} }
if query.EndTime != "" { if query.EndTime != "" {
conditions = append(conditions, dateTimeStr+" <= ?") dateStr2 = query.EndTime[:10]
params = append(params, query.EndTime) 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 := "" whereSql := ""
if len(conditions) > 0 { 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:')" 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) 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) 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 package repository
import ( import (
"fmt"
"strings" "strings"
"be.ems/src/framework/datasource" "be.ems/src/framework/datasource"
"be.ems/src/framework/logger" "be.ems/src/framework/logger"
"be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/repo" "be.ems/src/framework/utils/repo"
"be.ems/src/modules/network_element/model" "be.ems/src/modules/network_data/model"
) )
// 实例化数据层 UDMAuthImpl 结构体 // 实例化数据层 UDMAuthImpl 结构体
@@ -16,13 +17,13 @@ var NewUDMAuthImpl = &UDMAuthImpl{
resultMap: map[string]string{ resultMap: map[string]string{
"id": "ID", "id": "ID",
"imsi": "Imsi", "imsi": "IMSI",
"amf": "Amf", "amf": "Amf",
"status": "Status", "status": "Status",
"ki": "Ki", "ki": "Ki",
"algo_index": "AlgoIndex", "algo_index": "AlgoIndex",
"opc": "Opc", "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后新增实体 // ClearAndInsert 清空ne_id后新增实体
func (r *UDMAuthImpl) ClearAndInsert(neID string, authArr []model.UDMAuth) int64 { func (r *UDMAuthImpl) ClearAndInsert(neId string, uArr []model.UDMAuth) int64 {
// 清空指定ne_id // 指定neID时用 TRUNCATE 清空表快
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil)
if err != nil { if err != nil {
logger.Errorf("TRUNCATE err => %v", err) logger.Errorf("TRUNCATE err => %v", err)
} }
return r.Inserts(uArr)
return r.Inserts(authArr)
} }
// SelectPage 根据条件分页查询 // SelectPage 根据条件分页查询
@@ -106,11 +106,9 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
params = append(params, pageSize) params = append(params, pageSize)
// 排序 // 排序
sortSql := "" orderSql := ""
if v, ok := query["sortField"]; ok && v != "" { if v, ok := query["sortField"]; ok && v != "" {
if v == "imsi" { sortSql := v.(string)
sortSql += " order by imsi "
}
if o, ok := query["sortOrder"]; ok && o != nil && v != "" { if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
if o == "desc" { if o == "desc" {
sortSql += " desc " sortSql += " desc "
@@ -118,10 +116,11 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
sortSql += " asc " 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) results, err := datasource.RawDB("", querySql, params)
if err != nil { if err != nil {
logger.Errorf("query err => %v", err) logger.Errorf("query err => %v", err)
@@ -133,17 +132,17 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any {
} }
// SelectList 根据实体查询 // SelectList 根据实体查询
func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth { func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth {
// 查询条件拼接 // 查询条件拼接
var conditions []string var conditions []string
var params []any var params []any
if auth.Imsi != "" { if u.IMSI != "" {
conditions = append(conditions, "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 = ?") 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 批量添加 // Insert 批量添加
func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 { func (r *UDMAuthImpl) Inserts(uArr []model.UDMAuth) int64 {
tx := datasource.DefaultDB().CreateInBatches(authUsers, 3000) tx := datasource.DefaultDB().CreateInBatches(uArr, 3000)
if err := tx.Error; err != nil { if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err) logger.Errorf("CreateInBatches err => %v", err)
} }
@@ -173,19 +172,19 @@ func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 {
} }
// Delete 删除实体 // Delete 删除实体
func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { func (r *UDMAuthImpl) Delete(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{})
if err := tx.Error; err != nil { if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err) logger.Errorf("Delete err => %v", err)
} }
return tx.RowsAffected return tx.RowsAffected
} }
// DeletePrefixImsi 删除前缀匹配的实体 // DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMAuthImpl) DeletePrefixImsi(neID, imsi string) int64 { func (r *UDMAuthImpl) DeletePrefixByIMSI(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{})
if err := tx.Error; err != nil { if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixImsi err => %v", err) logger.Errorf("DeletePrefixByIMSI err => %v", err)
} }
return tx.RowsAffected 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 package repository
import ( import (
"strconv" "fmt"
"strings" "strings"
"be.ems/src/framework/datasource" "be.ems/src/framework/datasource"
"be.ems/src/framework/logger" "be.ems/src/framework/logger"
"be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/parse"
"be.ems/src/framework/utils/repo" "be.ems/src/framework/utils/repo"
"be.ems/src/modules/network_element/model" "be.ems/src/modules/network_data/model"
) )
// 实例化数据层 UDMSubImpl 结构体 // 实例化数据层 UDMSubImpl 结构体
@@ -20,7 +20,7 @@ var NewUDMSubImpl = &UDMSubImpl{
resultMap: map[string]string{ resultMap: map[string]string{
"id": "ID", "id": "ID",
"msisdn": "Msisdn", "msisdn": "Msisdn",
"imsi": "Imsi", "imsi": "IMSI",
"ambr": "Ambr", "ambr": "Ambr",
"nssai": "Nssai", "nssai": "Nssai",
"rat": "Rat", "rat": "Rat",
@@ -30,7 +30,7 @@ var NewUDMSubImpl = &UDMSubImpl{
"sm_data": "SmData", "sm_data": "SmData",
"smf_sel": "SmfSel", "smf_sel": "SmfSel",
"eps_dat": "EpsDat", "eps_dat": "EpsDat",
"ne_id": "NeID", "ne_id": "NeId",
"eps_flag": "EpsFlag", "eps_flag": "EpsFlag",
"eps_odb": "EpsOdb", "eps_odb": "EpsOdb",
"hplmn_odb": "HplmnOdb", "hplmn_odb": "HplmnOdb",
@@ -66,14 +66,14 @@ func (r *UDMSubImpl) convertResultRows(rows []map[string]any) []model.UDMSub {
} }
// ClearAndInsert 清空ne_id后新增实体 // ClearAndInsert 清空ne_id后新增实体
func (r *UDMSubImpl) ClearAndInsert(neID string, subArr []model.UDMSub) int64 { func (r *UDMSubImpl) ClearAndInsert(neID string, u []model.UDMSub) int64 {
// 清空指定ne_id // 指定neID时用 TRUNCATE 清空表快
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil)
if err != nil { if err != nil {
logger.Errorf("TRUNCATE err => %v", err) logger.Errorf("TRUNCATE err => %v", err)
} }
return r.Inserts(subArr) return r.Inserts(u)
} }
// SelectPage 根据条件分页查询字典类型 // SelectPage 根据条件分页查询字典类型
@@ -126,14 +126,9 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
params = append(params, pageSize) params = append(params, pageSize)
// 排序 // 排序
sortSql := "" orderSql := ""
if v, ok := query["sortField"]; ok && v != "" { if v, ok := query["sortField"]; ok && v != "" {
if v == "imsi" { sortSql := v.(string)
sortSql += " order by imsi "
}
if v == "msisdn" {
sortSql += " order by msisdn "
}
if o, ok := query["sortOrder"]; ok && o != nil && v != "" { if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
if o == "desc" { if o == "desc" {
sortSql += " desc " sortSql += " desc "
@@ -141,10 +136,11 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
sortSql += " asc " 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) results, err := datasource.RawDB("", querySql, params)
if err != nil { if err != nil {
logger.Errorf("query err => %v", err) logger.Errorf("query err => %v", err)
@@ -157,17 +153,17 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any {
} }
// SelectList 根据实体查询 // SelectList 根据实体查询
func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub { func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub {
// 查询条件拼接 // 查询条件拼接
var conditions []string var conditions []string
var params []any var params []any
if subUser.Imsi != "" { if u.IMSI != "" {
conditions = append(conditions, "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 = ?") 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) 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 批量添加 // Insert 批量添加
func (r *UDMSubImpl) Inserts(subUser []model.UDMSub) int64 { func (r *UDMSubImpl) Inserts(uArr []model.UDMSub) int64 {
tx := datasource.DefaultDB().CreateInBatches(subUser, 2000) tx := datasource.DefaultDB().CreateInBatches(uArr, 2000)
if err := tx.Error; err != nil { if err := tx.Error; err != nil {
logger.Errorf("CreateInBatches err => %v", err) logger.Errorf("CreateInBatches err => %v", err)
} }
return tx.RowsAffected 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 删除实体 // Delete 删除实体
func (r *UDMSubImpl) Delete(neID, imsi string) int64 { func (r *UDMSubImpl) Delete(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMSub{})
if err := tx.Error; err != nil { if err := tx.Error; err != nil {
logger.Errorf("Delete err => %v", err) logger.Errorf("Delete err => %v", err)
} }
return tx.RowsAffected return tx.RowsAffected
} }
// DeletePrefixImsi 删除前缀匹配的实体 // DeletePrefixByIMSI 删除前缀匹配的实体
func (r *UDMSubImpl) DeletePrefixImsi(neID, imsi string) int64 { func (r *UDMSubImpl) DeletePrefixByIMSI(neId, imsi string) int64 {
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMSub{})
if err := tx.Error; err != nil { if err := tx.Error; err != nil {
logger.Errorf("DeletePrefixImsi err => %v", err) logger.Errorf("DeletePrefixByIMSI 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)
} }
return tx.RowsAffected return tx.RowsAffected
} }

View File

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

View File

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

View File

@@ -7,24 +7,24 @@ import (
"be.ems/src/modules/network_data/repository" "be.ems/src/modules/network_data/repository"
) )
// 实例化数据层 UEEventImpl 结构体 // 实例化数据层 UEEventMMEImpl 结构体
var NewUEEventImpl = &UEEventImpl{ var NewUEEventMMEImpl = &UEEventMMEImpl{
ueEventRepository: repository.NewUEEventImpl, ueEventRepository: repository.NewUEEventMMEImpl,
} }
// UEEventImpl UE会话事件 服务层处理 // UEEventMMEImpl UE会话事件MME 服务层处理
type UEEventImpl struct { type UEEventMMEImpl struct {
// UE会话事件数据信息 // UE会话事件数据信息
ueEventRepository repository.IUEEvent ueEventRepository repository.IUEEventMME
} }
// SelectPage 根据条件分页查询 // 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) return r.ueEventRepository.SelectPage(querys)
} }
// DeleteByIds 批量删除信息 // DeleteByIds 批量删除信息
func (r *UEEventImpl) DeleteByIds(ueIds []string) (int64, error) { func (r *UEEventMMEImpl) DeleteByIds(ueIds []string) (int64, error) {
// 检查是否存在 // 检查是否存在
ids := r.ueEventRepository.SelectByIds(ueIds) ids := r.ueEventRepository.SelectByIds(ueIds)
if len(ids) <= 0 { 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 ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"runtime"
"strings" "strings"
"be.ems/src/framework/i18n" "be.ems/src/framework/i18n"
@@ -50,19 +51,30 @@ func (s *NeActionController) PushFile(c *gin.Context) {
return return
} }
// 本地文件 // 网元主机的SSH客户端
localPath := file.ParseUploadFilePath(body.UploadPath) sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
nePath := "/tmp" //config.Get("mml.upload").(string)
// 复制到远程
err := ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath)
if err != nil { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return 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))) c.JSON(200, result.OkData(filepath.ToSlash(neFilePath)))
} }
@@ -89,14 +101,32 @@ func (s *NeActionController) PullFile(c *gin.Context) {
return return
} }
nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName) // 网元主机的SSH客户端
localPath := fmt.Sprintf("/tmp/omc/pullFile/%s", querys.FileName) sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
err := ssh.FileSCPNeToLocal(neInfo.IP, nePath, localPath)
if err != nil { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return 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 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 { if err != nil {
c.JSON(200, result.Ok(map[string]any{ c.JSON(200, result.Ok(map[string]any{
"path": querys.Path, "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) 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" { } else if neTypeLower == "ims" {
if body.Action == "restart" { if body.Action == "restart" {
cmdStr = "sudo ims-stop || true && sudo ims-start" cmdStr = "ims-stop || true && ims-start"
} else { } else {
cmdStr = fmt.Sprintf("sudo ims-%s", body.Action) cmdStr = fmt.Sprintf("sudo ims-%s", body.Action)
} }
@@ -197,7 +236,7 @@ func (s *NeActionController) Service(c *gin.Context) {
cmdStr = "sudo shutdown -h now" 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 { if err != nil {
c.JSON(200, result.ErrMsg(err.Error())) c.JSON(200, result.ErrMsg(err.Error()))
return 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))
}

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