diff --git a/features/cdr/cdrevent.go b/features/cdr/cdrevent.go index 2f0efec..02c9524 100644 --- a/features/cdr/cdrevent.go +++ b/features/cdr/cdrevent.go @@ -279,11 +279,7 @@ func PostCDREventFromSMF(w http.ResponseWriter, r *http.Request) { } // 推送到ws订阅组 - // if v, ok := cdrEvent.CDR["recordType"]; ok { - // if v == "MOC" || v == "MTSM" { - // wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_IMS_CDR, cdrEvent) - // } - // } + wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_SMF_CDR, cdrEvent) services.ResponseStatusOK204NoContent(w) } diff --git a/features/cm/license.go b/features/cm/license.go index ffee447..ed4299c 100644 --- a/features/cm/license.go +++ b/features/cm/license.go @@ -8,7 +8,7 @@ import ( "os/exec" "strings" - "be.ems/lib/core/utils/ctx" + "be.ems/lib/core/ctx" "be.ems/lib/dborm" "be.ems/lib/log" "be.ems/lib/services" diff --git a/features/cm/param.go b/features/cm/param.go index 6ba6ccd..9e5a62f 100644 --- a/features/cm/param.go +++ b/features/cm/param.go @@ -3,7 +3,7 @@ package cm import ( "strings" - "be.ems/lib/core/utils/ctx" + "be.ems/lib/core/ctx" "be.ems/lib/global" "be.ems/lib/log" "be.ems/lib/services" diff --git a/features/dbrest/dbrest.go b/features/dbrest/dbrest.go index 1a03083..4d3888a 100644 --- a/features/dbrest/dbrest.go +++ b/features/dbrest/dbrest.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "be.ems/lib/core/utils/ctx" + "be.ems/lib/core/ctx" "be.ems/lib/dborm" "be.ems/lib/global" "be.ems/lib/log" diff --git a/features/event/event.go b/features/event/event.go index c0cb25c..66164b1 100644 --- a/features/event/event.go +++ b/features/event/event.go @@ -2,26 +2,35 @@ package event import ( "encoding/json" + "fmt" "io" + "net/http" + "strings" "time" + "be.ems/lib/core/ctx" "be.ems/lib/dborm" "be.ems/lib/global" "be.ems/lib/log" "be.ems/lib/services" + "be.ems/restagent/config" wsService "be.ems/src/modules/ws/service" "github.com/gin-gonic/gin" ) 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 { NeType string `json:"neType" xorm:"ne_type"` NeName string `json:"neName" xorm:"ne_name"` 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"` EventJson map[string]any `json:"eventJSON" xorm:"event_json"` } @@ -51,13 +60,13 @@ func PostUEEventFromAMF(c *gin.Context) { return } ueEvent.NeType = "AMF" - ueEvent.Timestamp = int(time.Now().Unix()) + ueEvent.Timestamp = time.Now().Unix() 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 { - log.Error("Failed to insert ue_event:", err) + log.Error("Failed to insert ue_event_amf:", err) services.ResponseInternalServerError500ProcessError(c.Writer, err) return } @@ -67,3 +76,30 @@ func PostUEEventFromAMF(c *gin.Context) { 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) +} diff --git a/features/file/file.go b/features/file/file.go index 7162b3f..8300f04 100644 --- a/features/file/file.go +++ b/features/file/file.go @@ -5,7 +5,7 @@ import ( "net/http" "path/filepath" - "be.ems/lib/core/utils/ctx" + "be.ems/lib/core/ctx" "be.ems/lib/dborm" "be.ems/lib/file" "be.ems/lib/log" diff --git a/features/fm/ucpcli.go b/features/fm/ucpcli.go deleted file mode 100644 index 4c7b0e0..0000000 --- a/features/fm/ucpcli.go +++ /dev/null @@ -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) - } - } - } -} diff --git a/features/mml/mml.go b/features/mml/mml.go index 1df4fca..0441773 100644 --- a/features/mml/mml.go +++ b/features/mml/mml.go @@ -54,8 +54,8 @@ var ( var ( TIME_DELAY_AFTER_WRITE time.Duration = 200 TIME_DEAD_LINE time.Duration = 10 - WIN_ROW_SIZE byte = 100 - WIN_COL_SIZE byte = 100 + WIN_ROW_SIZE int16 = 200 + WIN_COL_SIZE int16 = 120 BUFFER_SIZE int = 65535 ) @@ -118,9 +118,15 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { // services.ResponseWithJson(w, http.StatusOK, response) // return // } + // 发送窗口大小设置命令 - 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, 251, 31}) // 发送WILL 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)) loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) diff --git a/features/ue/ue.go b/features/ue/ue.go index 279e24b..5581bb6 100644 --- a/features/ue/ue.go +++ b/features/ue/ue.go @@ -8,12 +8,14 @@ import ( "strings" "time" + "be.ems/lib/core/ctx" "be.ems/lib/dborm" "be.ems/lib/global" "be.ems/lib/log" "be.ems/lib/services" "be.ems/restagent/config" tokenConst "be.ems/src/framework/constants/token" + neService "be.ems/src/modules/network_element/service" "github.com/go-resty/resty/v2" "github.com/gorilla/mux" ) @@ -241,66 +243,38 @@ func GetSubscriptionsFromNSSF(w http.ResponseWriter, r *http.Request) { // Get UEInfo from NF/NFs func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("GetUEInfoFromNF processing... ") + log.Debug("GetUEInfoFromNF processing... ") - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { + neId := ctx.GetQuery(r, "neId") + neType := ctx.GetParam(r, "elementTypeValue") + if neType == "" || neId == "" { + log.Error("elementTypeValue/neId is empty") services.ResponseNotFound404UriNotExist(w, r) return } - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) + neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return + var response services.MapResponse + if neInfo.NeId == neId && neInfo.NeId != "" { + requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) + log.Debug("requestURI2NF:", requestURI2NF) + resp, err := client.R(). + EnableTrace(). + 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("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) - 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 - } + services.ResponseWithJson(w, http.StatusOK, response) } // POST User Info from NF/NFs diff --git a/go.mod b/go.mod index 0dc59fa..9fd185c 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,10 @@ go 1.21 toolchain go1.21.0 require ( - github.com/chzyer/readline v1.5.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dlclark/regexp2 v1.10.0 github.com/gin-gonic/gin v1.9.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-sql-driver/mysql v1.7.1 github.com/golang-jwt/jwt/v5 v5.0.0 @@ -46,11 +44,14 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // 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-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/time v0.1.0 // indirect ) require ( @@ -62,6 +63,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // 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/cpuguy83/go-md2man/v2 v2.0.3 // 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/pelletier/go-toml/v2 v2.0.8 // 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/prometheus/client_golang v1.19.1 github.com/reiver/go-oi v1.0.0 // indirect github.com/richardlehane/mscfb v1.0.4 // 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/text v0.14.0 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/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/kyokomi/emoji.v1 v1.5.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 4e517ec..e0c3d72 100644 --- a/go.sum +++ b/go.sum @@ -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/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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 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/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/wechat v0.0.0-20201110083048-0180211b69fd h1:TM3wjEWel4U31J72dlhnwCBqPC0+FA0Ejm2NCbn5a5U= 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-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 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.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 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 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/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= @@ -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/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-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.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 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.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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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/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= @@ -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/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/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= 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/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/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 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/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.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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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 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.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-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-20190812154241-14fe0d1b01d4/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.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 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-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.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/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= @@ -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/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.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +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/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 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-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.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.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= 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-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-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-20181201002055-351d144fa1fc/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-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.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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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-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-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-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-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.5.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-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.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.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= 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.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.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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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-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.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-20180828015842-6cd1fcedba52/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.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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +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/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/lib/core/constants/cachekey/cachekey.go b/lib/core/constants/cachekey/cachekey.go deleted file mode 100644 index 0e69445..0000000 --- a/lib/core/constants/cachekey/cachekey.go +++ /dev/null @@ -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:" diff --git a/lib/core/utils/ctx/ctx.go b/lib/core/ctx/ctx.go similarity index 96% rename from lib/core/utils/ctx/ctx.go rename to lib/core/ctx/ctx.go index fefb6b4..723dd80 100644 --- a/lib/core/utils/ctx/ctx.go +++ b/lib/core/ctx/ctx.go @@ -17,8 +17,8 @@ import ( "golang.org/x/text/language" ) -// Param 地址栏参数{id} -func Param(r *http.Request, key string) string { +// GetParam 地址栏参数{id} +func GetParam(r *http.Request, key string) string { vars := mux.Vars(r) v, ok := vars[key] if ok { @@ -47,7 +47,7 @@ func QueryMap(r *http.Request) map[string]any { return queryParams } -// ShouldBindQuery 查询参数读取json请求结构团体 +// ShouldBindQuery 查询参数读取json请求结构团体 &xxx func ShouldBindQuery(r *http.Request, args any) error { queryParams := QueryMap(r) body, err := json.Marshal(queryParams) @@ -57,7 +57,7 @@ func ShouldBindQuery(r *http.Request, args any) error { return json.Unmarshal(body, args) } -// 读取json请求结构团体 +// ShouldBindJSON 读取json请求结构团体 &xxx func ShouldBindJSON(r *http.Request, args any) error { body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 设置较大的长度,例如 1<<20 (1MB) if err != nil { diff --git a/lib/core/datasource/datasource.go b/lib/core/datasource/datasource.go deleted file mode 100644 index 1ef16af..0000000 --- a/lib/core/datasource/datasource.go +++ /dev/null @@ -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 -} diff --git a/lib/core/datasource/repo.go b/lib/core/datasource/repo.go deleted file mode 100644 index 7b81a4e..0000000 --- a/lib/core/datasource/repo.go +++ /dev/null @@ -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 -} diff --git a/lib/core/mml_client/mml_client.go b/lib/core/mml_client/mml_client.go deleted file mode 100644 index a004024..0000000 --- a/lib/core/mml_client/mml_client.go +++ /dev/null @@ -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() -} diff --git a/lib/core/mml_client/send.go b/lib/core/mml_client/send.go deleted file mode 100644 index 943772c..0000000 --- a/lib/core/mml_client/send.go +++ /dev/null @@ -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 -} diff --git a/lib/core/utils/date/date.go b/lib/core/utils/date/date.go deleted file mode 100644 index d6235ea..0000000 --- a/lib/core/utils/date/date.go +++ /dev/null @@ -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") -} diff --git a/lib/core/utils/parse/parse.go b/lib/core/utils/parse/parse.go deleted file mode 100644 index ed2fd5d..0000000 --- a/lib/core/utils/parse/parse.go +++ /dev/null @@ -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 -} diff --git a/lib/core/utils/regular/regular.go b/lib/core/utils/regular/regular.go deleted file mode 100644 index e4b9cc6..0000000 --- a/lib/core/utils/regular/regular.go +++ /dev/null @@ -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 -} diff --git a/lib/core/utils/scan/scan.go b/lib/core/utils/scan/scan.go deleted file mode 100644 index 6313763..0000000 --- a/lib/core/utils/scan/scan.go +++ /dev/null @@ -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) -} diff --git a/lib/core/vo/login_user.go b/lib/core/vo/login_user.go index 1d4c977..0b4899f 100644 --- a/lib/core/vo/login_user.go +++ b/lib/core/vo/login_user.go @@ -23,6 +23,4 @@ type LoginUser struct { // User 用户信息 User dborm.User `json:"user"` - - Session dborm.Session `json:"-"` } diff --git a/lib/core/vo/router.go b/lib/core/vo/router.go deleted file mode 100644 index a3cc408..0000000 --- a/lib/core/vo/router.go +++ /dev/null @@ -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"` -} diff --git a/lib/core/vo/router_meta.go b/lib/core/vo/router_meta.go deleted file mode 100644 index b3447e0..0000000 --- a/lib/core/vo/router_meta.go +++ /dev/null @@ -1,17 +0,0 @@ -package vo - -// RouterMeta 路由元信息对象 -type RouterMeta struct { - // 设置该菜单在侧边栏和面包屑中展示的名字 - Title string `json:"title"` - // 设置该菜单的图标 - Icon string `json:"icon"` - // 设置为true,则不会被 缓存 - Cache bool `json:"cache"` - // 内链地址(http(s)://开头), 打开目标位置 '_blank' | '_self' | '' - Target string `json:"target"` - // 在菜单中隐藏子节点 - HideChildInMenu bool `json:"hideChildInMenu"` - // 在菜单中隐藏自己和子节点 - HideInMenu bool `json:"hideInMenu"` -} diff --git a/lib/core/vo/treeselect.go b/lib/core/vo/treeselect.go deleted file mode 100644 index 2677626..0000000 --- a/lib/core/vo/treeselect.go +++ /dev/null @@ -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 -// } diff --git a/lib/midware/arrow_ip_addr.go b/lib/midware/arrow_ip_addr.go deleted file mode 100644 index c9c7a32..0000000 --- a/lib/midware/arrow_ip_addr.go +++ /dev/null @@ -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, "网关登录策略-不在开放时间范围内") - } - }) -} diff --git a/lib/midware/authorize.go b/lib/midware/authorize.go deleted file mode 100644 index b56e9c3..0000000 --- a/lib/midware/authorize.go +++ /dev/null @@ -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 -} diff --git a/lib/midware/cors.go b/lib/midware/cors.go deleted file mode 100644 index a924369..0000000 --- a/lib/midware/cors.go +++ /dev/null @@ -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) - }) -} diff --git a/lib/midware/mml_log.go b/lib/midware/mml_log.go index 9171147..c63ac73 100644 --- a/lib/midware/mml_log.go +++ b/lib/midware/mml_log.go @@ -9,10 +9,10 @@ import ( "strings" "time" - "be.ems/lib/core/datasource" - "be.ems/lib/core/utils/ctx" - "be.ems/lib/core/utils/date" + "be.ems/lib/core/ctx" "be.ems/lib/log" + "be.ems/src/framework/datasource" + "be.ems/src/framework/utils/date" ) // LogMML mml操作日志搜集 @@ -36,7 +36,7 @@ func LogMML(next http.Handler) http.Handler { // 收尾存入数据库的参数 mmlCmd := bodyArgs["mml"].([]any)[0] ipAddr := strings.Split(r.RemoteAddr, ":")[0] - neType := ctx.Param(r, "elementTypeValue") + neType := ctx.GetParam(r, "elementTypeValue") neId := ctx.GetQuery(r, "ne_id") timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS) diff --git a/lib/midware/operate_log.go b/lib/midware/operate_log.go index d8bc396..a264728 100644 --- a/lib/midware/operate_log.go +++ b/lib/midware/operate_log.go @@ -11,11 +11,11 @@ import ( "strings" "time" - "be.ems/lib/core/utils/ctx" - "be.ems/lib/core/utils/parse" + "be.ems/lib/core/ctx" "be.ems/src/framework/constants/common" "be.ems/src/framework/middleware/collectlogs" "be.ems/src/framework/utils/ip2region" + "be.ems/src/framework/utils/parse" "be.ems/src/modules/system/model" "be.ems/src/modules/system/service" ) diff --git a/lib/routes/routes.go b/lib/routes/routes.go index baddb75..537a938 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -9,11 +9,11 @@ import ( "be.ems/features/cdr" "be.ems/features/cm" "be.ems/features/dbrest" + "be.ems/features/event" "be.ems/features/file" "be.ems/features/fm" "be.ems/features/lm" "be.ems/features/mml" - "be.ems/features/nbi" "be.ems/features/pm" "be.ems/features/security" "be.ems/features/sm" @@ -172,9 +172,9 @@ func init() { Register("POST", mml.CustomUriMML2, mml.PostMML2ToNF, nil) // 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 Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil) @@ -261,9 +261,7 @@ func init() { Register("DELETE", ue.CustomUriPCFUserM, ue.DeletePCFUserInfo, nil) //PCF User file Register("GET", ue.UriPCFUserFileExport, ue.GetUEInfoFileExportNF, nil) - Register("GET", ue.CustomUriPCFUserFileExport, ue.GetUEInfoFromNF, nil) Register("PUT", ue.UriPCFUserFileImport, ue.PutPCFUserInfo, nil) - Register("PUT", ue.CustomUriPCFUserFileImport, ue.PutPCFUserInfo, nil) // UE Number Register("GET", ue.UriUENum, ue.GetUENumFromNF, nil) @@ -289,6 +287,9 @@ func init() { Register("POST", cdr.UriSMFCDREvent, 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处理 //Register("POST", event.UriUEEvent, event.PostUEEventFromAMF, nil) diff --git a/lib/wsinfo/client.go b/lib/wsinfo/client.go deleted file mode 100644 index 36201cd..0000000 --- a/lib/wsinfo/client.go +++ /dev/null @@ -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) - } -} diff --git a/lib/wsinfo/process_data.go b/lib/wsinfo/process_data.go deleted file mode 100644 index e19aa62..0000000 --- a/lib/wsinfo/process_data.go +++ /dev/null @@ -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 = "" - } - 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 -} diff --git a/restagent/config/config.go b/restagent/config/config.go index 181cbef..59585c8 100644 --- a/restagent/config/config.go +++ b/restagent/config/config.go @@ -177,8 +177,8 @@ type MMLParam struct { Port2 int `yaml:"port2"` Sleep int64 `yaml:"sleep"` DeadLine int64 `yaml:"deadLine"` - SizeRow byte `yaml:"sizeRow"` - SizeCol byte `yaml:"sizeCol"` + SizeRow int16 `yaml:"sizeRow"` + SizeCol int16 `yaml:"sizeCol"` BufferSize int `yaml:"bufferSize"` User string `yaml:"user"` Password string `ymal:"password"` @@ -226,8 +226,8 @@ func NewYamlConfig() YamlConfig { ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True", }, MML: MMLParam{ - SizeRow: 100, - SizeCol: 128, + SizeRow: 200, + SizeCol: 120, BufferSize: 65535, }, Alarm: AlarmConfig{ diff --git a/restagent/etc/restconf-t.yaml b/restagent/etc/restconf-t.yaml index d3323c6..9b44711 100644 --- a/restagent/etc/restconf-t.yaml +++ b/restagent/etc/restconf-t.yaml @@ -54,14 +54,14 @@ redis: # OMC系统使用库 default: port: 6379 # Redis port - host: "192.168.2.219" # Redis host - password: "123456" + host: "127.0.0.1" # Redis host + password: "helloearth" db: 10 # Redis db_num # UDM网元用户库 udmuser: port: 6379 # Redis port - host: "192.168.2.219" - password: "123456" + host: "127.0.0.1" + password: "helloearth" db: 0 # Redis db_num # 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: "default" @@ -73,13 +73,12 @@ mml: port2: 5002 sleep: 200 deadLine: 10 - sizeRow: 100 + sizeRow: 600 sizeCol: 128 bufferSize: 65535 user: admin password: admin mmlHome: ./mmlhome - upload: /home/manager # NE config ne: diff --git a/restagent/etc/restconf.yaml b/restagent/etc/restconf.yaml index 9fb9aea..94f8274 100644 --- a/restagent/etc/restconf.yaml +++ b/restagent/etc/restconf.yaml @@ -21,17 +21,9 @@ rest: - ipv4: 0.0.0.0 ipv6: 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: - enabled: true + enabled: false rootDir: d:/local.git/fe.ems.vue3/dist listen: - addr: :80 @@ -46,10 +38,10 @@ webServer: database: type: mysql user: root - password: 1000omc@kp! - host: 127.0.0.1 - port: 33066 - name: omc_db + password: "root@1234" + host: "192.168.5.59" + port: 3306 + name: "omc_db" connParam: charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True backup: d:/local.git/be.ems/restagent/database @@ -59,14 +51,14 @@ redis: # OMC系统使用库 default: port: 6379 # Redis port - host: "192.168.2.219" # Redis host - password: "123456" + host: "192.168.5.59" # Redis host + password: "redis@1234" db: 10 # Redis db_num # UDM网元用户库 udmuser: port: 6379 # Redis port - host: "192.168.2.219" - password: "123456" + host: "192.168.5.60" + password: "helloearth" db: 0 # Redis db_num # 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: "default" @@ -78,7 +70,7 @@ mml: port2: 5002 sleep: 200 deadLine: 10 - sizeRow: 100 + sizeRow: 600 sizeCol: 128 bufferSize: 65535 user: admin @@ -87,7 +79,7 @@ mml: # NE config ne: - user: root + user: omcuser etcdir: /usr/local/etc bindir: /usr/local/bin omcdir: /usr/local/omc @@ -116,12 +108,12 @@ omc: checksign: false rootDir: ./ binDir: ./bin - backup: ./backup - upload: ./upload - frontUpload: d:/local.git/fe.ems/upload - frontTraceDir: d:/local.git/fe.ems/trace - software: ./software - license: ./license + backup: C:/usr/local/omc/backup + upload: C:/usr/local/omc/upload + frontUpload: C:/usr/local/omc/upload + frontTraceDir: C:/usr/local/omc/trace + software: C:/usr/local/omc/software + license: C:/usr/local/omc/license gtpUri: gtp:192.168.2.219:2152 checkContentType: false testMode: false @@ -134,7 +126,7 @@ omc: # email/sms # smProxy: sms(Short Message Service)/smsc(SMS Centre) alarm: - forwardAlarm: true + forwardAlarm: false email: smtp: mail.agrandtech.com port: 25 @@ -189,12 +181,12 @@ testConfig: file: ./etc/testconfig.yaml # 静态文件配置, 相对项目根路径或填绝对路径 -staticFile: - # 默认资源,dir目录需要预先创建 - default: - prefix: "/static" - dir: "./static" - # 文件上传资源目录映射,与项目目录同级 - upload: - prefix: "/upload" - dir: "./upload" +# staticFile: +# # 默认资源,dir目录需要预先创建 +# default: +# prefix: "/static" +# dir: "./static" +# # 文件上传资源目录映射,与项目目录同级 +# upload: +# prefix: "/upload" +# dir: "./upload" diff --git a/restagent/makefile b/restagent/makefile index 2f41274..a4954bb 100644 --- a/restagent/makefile +++ b/restagent/makefile @@ -1,7 +1,7 @@ # Makefile for rest agent project PROJECT = OMC -VERSION = 2.2405.4 +VERSION = 2.2407.1 PLATFORM = amd64 ARMPLATFORM = aarch64 BUILDDIR = ../../build @@ -14,7 +14,7 @@ BINNAME = restagent .PHONY: 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.GoVer=`go version`'" diff --git a/restagent/restagent.go b/restagent/restagent.go index ec8afd3..734cf30 100644 --- a/restagent/restagent.go +++ b/restagent/restagent.go @@ -249,7 +249,7 @@ func main() { uriGroup := app.Group(config.UriPrefix) uriGroup.Any("/*any", gin.WrapH(routes.NewRouter())) // AMF上报的UE事件, 无前缀,暂时特殊处理 - app.POST(event.UriUEEvent, event.PostUEEventFromAMF) + app.POST(event.UriUEEventAMF, event.PostUEEventFromAMF) var listenLocalhost bool = false for _, rest := range conf.Rest { diff --git a/src/framework/config/config/config.default.yaml b/src/framework/config/config/config.default.yaml index c5a30c6..ee39665 100644 --- a/src/framework/config/config/config.default.yaml +++ b/src/framework/config/config/config.default.yaml @@ -1,7 +1,7 @@ # 项目信息 framework: name: "CN EMS" - version: "2.2405.4" + version: "2.2407.1" # 应用服务配置 server: diff --git a/src/framework/constants/admin/admin.go b/src/framework/constants/admin/admin.go index 7ac32c5..1c158a8 100644 --- a/src/framework/constants/admin/admin.go +++ b/src/framework/constants/admin/admin.go @@ -1,12 +1,12 @@ package admin -// 管理员常量信息 +// 系统管理员常量信息 -// 管理员-系统指定角色ID +// 系统管理员-系统指定角色ID const ROLE_ID = "1" -// 管理员-系统指定角色KEY -const ROLE_KEY = "admin" +// 系统管理员-系统指定角色KEY +const ROLE_KEY = "system" -// 管理员-系统指定权限 +// 系统管理员-系统指定权限 const PERMISSION = "*:*:*" diff --git a/src/framework/middleware/collectlogs/operate_log.go b/src/framework/middleware/collectlogs/operate_log.go index 49ec04f..9528ace 100644 --- a/src/framework/middleware/collectlogs/operate_log.go +++ b/src/framework/middleware/collectlogs/operate_log.go @@ -8,6 +8,7 @@ import ( "time" "be.ems/src/framework/constants/common" + tokenConstants "be.ems/src/framework/constants/token" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/parse" @@ -178,6 +179,8 @@ var maskProperties []string = []string{ "oldPassword", "newPassword", "confirmPassword", + tokenConstants.RESPONSE_FIELD, + tokenConstants.ACCESS_TOKEN, } // processSensitiveFields 处理敏感属性字段 diff --git a/src/framework/middleware/pre_authorize.go b/src/framework/middleware/pre_authorize.go index d840a9f..588ad29 100644 --- a/src/framework/middleware/pre_authorize.go +++ b/src/framework/middleware/pre_authorize.go @@ -20,6 +20,7 @@ var URL_WHITE_LIST = []string{ "/systemState", "/omcNeConfig", "/cdrEvent", + "/ueEvent", "/upload-ue", "/oauth/token", } diff --git a/src/framework/utils/ctx/ctx.go b/src/framework/utils/ctx/ctx.go index fd7503c..cc17a09 100644 --- a/src/framework/utils/ctx/ctx.go +++ b/src/framework/utils/ctx/ctx.go @@ -84,8 +84,8 @@ func Authorization(c *gin.Context) string { return "" } // 拆分 Authorization 请求头,提取 JWT 令牌部分 - arr := strings.Split(authHeader, token.HEADER_PREFIX) - if len(arr) == 2 && arr[1] == "" { + arr := strings.SplitN(authHeader, token.HEADER_PREFIX, 2) + if len(arr) < 2 { return "" } return arr[1] @@ -212,6 +212,11 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string) conditions = append(conditions, sql) } + if roledatascope.DEPT == dataScope { + sql := fmt.Sprintf(`%s.dept_id = '%s'`, deptAlias, userInfo.DeptID) + conditions = append(conditions, sql) + } + if roledatascope.DEPT_AND_CHILD == dataScope { sql := fmt.Sprintf(`%s.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = '%s' or find_in_set('%s' , ancestors ) )`, deptAlias, userInfo.DeptID, userInfo.DeptID) conditions = append(conditions, sql) @@ -220,7 +225,7 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string) if roledatascope.SELF == dataScope { // 数据权限为仅本人且没有userAlias别名不查询任何数据 if userAlias == "" { - sql := fmt.Sprintf(`%s.dept_id = '0'`, deptAlias) + sql := fmt.Sprintf(`%s.parent_id = '0'`, deptAlias) conditions = append(conditions, sql) } else { sql := fmt.Sprintf(`%s.user_id = '%s'`, userAlias, userInfo.UserID) diff --git a/src/framework/utils/date/date.go b/src/framework/utils/date/date.go index 84ae33d..35cf339 100644 --- a/src/framework/utils/date/date.go +++ b/src/framework/utils/date/date.go @@ -48,7 +48,14 @@ func ParseDateToStr(date any, formatStr string) string { if v == 0 { return "" } - t = time.UnixMilli(v) + if v > 9999999999 { + t = time.UnixMilli(v) + } else if v > 999999999 { + t = time.Unix(v, 0) + } else { + logger.Infof("utils ParseDateToStr err %v", "Invalid timestamp") + return "" + } case string: parsedTime, err := time.Parse(formatStr, v) if err != nil { diff --git a/src/framework/utils/parse/parse.go b/src/framework/utils/parse/parse.go index 8eb27dc..67fb831 100644 --- a/src/framework/utils/parse/parse.go +++ b/src/framework/utils/parse/parse.go @@ -172,10 +172,10 @@ func Color(colorStr string) *color.RGBA { } } -// ConvertIPMask 转换IP网络地址掩码 24 -> 255.255.255.0 +// ConvertIPMask 转换IP网络地址掩码 24->"255.255.255.0" 20->"255.255.240.0" func ConvertIPMask(bits int64) string { if bits < 0 || bits > 32 { - return "Invalid Mask Bits" + return "255.255.255.255" } // 构建一个32位的uint32类型掩码,指定前bits位为1,其余为0 diff --git a/src/framework/utils/repo/repo.go b/src/framework/utils/repo/repo.go index 5bd59fe..6e5e82f 100644 --- a/src/framework/utils/repo/repo.go +++ b/src/framework/utils/repo/repo.go @@ -66,12 +66,12 @@ func SetFieldValue(obj any, fieldName string, value any) { } fieldValue.SetFloat(floatValue) case reflect.Struct: - fmt.Printf("%s 时间解析 %s %v \n", fieldName, fieldValue.Type(), value) + fmt.Printf("%s time resolution %s %v \n", fieldName, fieldValue.Type(), value) if fieldValue.Type() == reflect.TypeOf(time.Time{}) && value != nil { // 解析 value 并转换为 time.Time 类型 parsedTime, err := time.Parse("2006-01-02 15:04:05 +0800 CST", fmt.Sprintf("%v", value)) if err != nil { - fmt.Println("时间解析出错:", err) + fmt.Println("Time resolution error:", err) } else { // 设置字段的值 fieldValue.Set(reflect.ValueOf(parsedTime)) diff --git a/src/framework/utils/ssh/files.go b/src/framework/utils/ssh/files.go index 59eefe5..d9d5f42 100644 --- a/src/framework/utils/ssh/files.go +++ b/src/framework/utils/ssh/files.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "be.ems/src/framework/config" "be.ems/src/framework/logger" "be.ems/src/framework/utils/cmd" "be.ems/src/framework/utils/parse" @@ -23,35 +22,31 @@ type FileListRow struct { } // 文件列表 -// neIp 网元IP空字符串为本地 // search 文件名后模糊* // // return 目录大小,行记录,异常 -func FileList(path, neIp, search string) (string, []FileListRow, error) { +func FileList(sshClient *ConnSSH, path, search string) (string, []FileListRow, error) { totalSize := "" var rows []FileListRow rowStr := "" // 发送命令 - searchStr := "" + searchStr := "*" if search != "" { - searchStr = search + "*" + searchStr = search + searchStr } - pathStr := fmt.Sprintf("cd %s \n", path) - cmdStr := fmt.Sprintf("ls -lht --time-style=+%%s %s \n", searchStr) + cmdStr := fmt.Sprintf("cd %s && ls -lthd --time-style=+%%s %s", path, searchStr) - // 是否远程读取 - if neIp != "" { - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neIp) - resultStr, err := cmd.ExecWithCheck("ssh", sshHost, pathStr, cmdStr) + // 是否远程客户端读取 + if sshClient == nil { + resultStr, err := cmd.Execf(cmdStr) if err != nil { logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error()) return totalSize, rows, err } rowStr = resultStr } else { - resultStr, err := cmd.Execf(pathStr, cmdStr) + resultStr, err := sshClient.RunCMD(cmdStr) if err != nil { logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error()) return totalSize, rows, err diff --git a/src/framework/utils/ssh/scp.go b/src/framework/utils/ssh/scp.go deleted file mode 100644 index 33beb53..0000000 --- a/src/framework/utils/ssh/scp.go +++ /dev/null @@ -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 -} diff --git a/src/framework/utils/ssh/sftp.go b/src/framework/utils/ssh/sftp.go new file mode 100644 index 0000000..3336733 --- /dev/null +++ b/src/framework/utils/ssh/sftp.go @@ -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 +} diff --git a/src/framework/utils/ssh/ssh.go b/src/framework/utils/ssh/ssh.go index eaf5c3d..29a5fb7 100644 --- a/src/framework/utils/ssh/ssh.go +++ b/src/framework/utils/ssh/ssh.go @@ -1,14 +1,10 @@ package ssh import ( - "bytes" "fmt" - "io" "os" "os/user" - "path/filepath" "strings" - "sync" "time" "be.ems/src/framework/logger" @@ -89,24 +85,6 @@ func (c *ConnSSH) Close() { } } -// NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连 -// -// ssh.ConnSSH{ -// User: "user", -// Addr: "192.168.x.x", -// Port: body.Port, -// } -func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) { - c.Port = 22 - c.AuthMode = "1" - privateKey, err := c.CurrentUserRsaKey(false) - if err != nil { - return nil, err - } - c.PrivateKey = privateKey - return c.NewClient() -} - // RunCMD 执行单次命令 func (c *ConnSSH) RunCMD(cmd string) (string, error) { if c.Client == nil { @@ -128,57 +106,6 @@ func (c *ConnSSH) RunCMD(cmd string) (string, error) { return c.LastResult, err } -// SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥 -func (c *ConnSSH) SendToAuthorizedKeys() error { - publicKey, err := c.CurrentUserRsaKey(true) - if err != nil { - return err - } - authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey)) - cmdStrArr := []string{ - fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User), - fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User), - fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User), - } - _, err = c.RunCMD(strings.Join(cmdStrArr, " && ")) - if err != nil { - logger.Errorf("SendAuthorizedKeys echo err %s", err.Error()) - return err - } - return nil -} - -// CurrentUserRsaKey 当前用户OMC使用的RSA私钥 -// 默认读取私钥 -// ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa -// ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub -func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) { - usr, err := user.Current() - if err != nil { - logger.Errorf("CurrentUserRsaKey get => %s", err.Error()) - return "", err - } - - // 是否存在私钥并创建 - keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir) - if _, err := os.Stat(keyPath); err != nil { - if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil { - logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error()) - } - } - - // 读取用户默认的文件 - if publicKey { - keyPath = keyPath + ".pub" - } - key, err := os.ReadFile(keyPath) - if err != nil { - logger.Errorf("CurrentUserRsaKey [%s] read => %s", usr.Username, err.Error()) - return "", fmt.Errorf("read file %s fail", keyPath) - } - return string(key), nil -} - // NewClientSession 创建SSH客户端会话对象 func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) { sshSession, err := c.Client.NewSession() @@ -216,69 +143,6 @@ func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) { }, nil } -// SSHClientSession SSH客户端会话对象 -type SSHClientSession struct { - Stdin io.WriteCloser - Stdout *singleWriter - Session *gossh.Session -} - -// Close 关闭会话 -func (s *SSHClientSession) Close() { - if s.Stdin != nil { - s.Stdin.Close() - } - if s.Stdout != nil { - s.Stdout = nil - } - if s.Session != nil { - s.Session.Close() - } -} - -// Write 写入命令 回车(\n)才会执行 -func (s *SSHClientSession) Write(cmd string) (int, error) { - if s.Stdin == nil { - return 0, fmt.Errorf("ssh client session is nil to content write failed") - } - return s.Stdin.Write([]byte(cmd)) -} - -// Read 读取结果 -func (s *SSHClientSession) Read() []byte { - if s.Stdout == nil { - return []byte{} - } - bs := s.Stdout.Bytes() - if len(bs) > 0 { - s.Stdout.Reset() - return bs - } - return []byte{} -} - -// singleWriter SSH客户端会话消息 -type singleWriter struct { - b bytes.Buffer - mu sync.Mutex -} - -func (w *singleWriter) Write(p []byte) (int, error) { - w.mu.Lock() - defer w.mu.Unlock() - return w.b.Write(p) -} -func (w *singleWriter) Bytes() []byte { - w.mu.Lock() - defer w.mu.Unlock() - return w.b.Bytes() -} -func (w *singleWriter) Reset() { - w.mu.Lock() - defer w.mu.Unlock() - w.b.Reset() -} - // NewClientSFTP 创建SSH客户端SFTP对象 func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) { sftpClient, err := gosftp.NewClient(c.Client) @@ -292,193 +156,70 @@ func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) { }, nil } -// SSHClientSFTP SSH客户端SFTP对象 -type SSHClientSFTP struct { - Client *gosftp.Client +// NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连 +// +// ssh.ConnSSH{ +// User: "user", +// Addr: "192.168.x.x", +// Port: body.Port, +// } +func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) { + c.Port = 22 + c.AuthMode = "1" + privateKey, err := c.CurrentUserRsaKey(false) + if err != nil { + return nil, err + } + c.PrivateKey = privateKey + return c.NewClient() } -// Close 关闭会话 -func (s *SSHClientSFTP) Close() { - if s.Client != nil { - s.Client.Close() - } -} - -// CopyDirRemoteToLocal 复制目录-远程到本地 -func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error { - // 列出远程目录中的文件和子目录 - remoteFiles, err := s.Client.ReadDir(remoteDir) +// CurrentUserRsaKey 当前用户OMC使用的RSA私钥 +// 默认读取私钥 +// ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa +// ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub +func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) { + usr, err := user.Current() if err != nil { - logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error()) - return err + logger.Errorf("CurrentUserRsaKey get => %s", err.Error()) + return "", err } - // 创建本地目录 - err = os.MkdirAll(localDir, 0775) - if err != nil { - logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error()) - return err - } - - // 遍历远程文件和子目录并复制到本地 - for _, remoteFile := range remoteFiles { - remotePath := filepath.Join(remoteDir, remoteFile.Name()) - localPath := filepath.Join(localDir, remoteFile.Name()) - - if remoteFile.IsDir() { - // 如果是子目录,则递归复制子目录 - err = s.CopyDirRemoteToLocal(remotePath, localPath) - if err != nil { - logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error()) - continue - } - } else { - // 如果是文件,则复制文件内容 - remoteFile, err := s.Client.Open(remotePath) - if err != nil { - logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error()) - continue - } - defer remoteFile.Close() - - localFile, err := os.Create(localPath) - if err != nil { - logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error()) - continue - } - defer localFile.Close() - - _, err = io.Copy(localFile, remoteFile) - if err != nil { - logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error()) - continue - } + // 是否存在私钥并创建 + keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir) + if _, err := os.Stat(keyPath); err != nil { + if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil { + logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error()) } } - return nil + + // 读取用户默认的文件 + if publicKey { + keyPath = keyPath + ".pub" + } + key, err := os.ReadFile(keyPath) + if err != nil { + logger.Errorf("CurrentUserRsaKey [%s] read => %s", usr.Username, err.Error()) + return "", fmt.Errorf("read file %s fail", keyPath) + } + return string(key), nil } -// CopyDirRemoteToLocal 复制目录-本地到远程 -func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error { - // 创建远程目录 - err := s.Client.MkdirAll(remoteDir) +// SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥 +func (c *ConnSSH) SendToAuthorizedKeys() error { + publicKey, err := c.CurrentUserRsaKey(true) if err != nil { - logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error()) return err } - - // 遍历本地目录中的文件和子目录并复制到远程 - err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - // 生成远程路径 - remotePath := filepath.Join(remoteDir, localPath[len(localDir):]) - - if info.IsDir() { - // 如果是子目录,则创建远程目录 - err := s.Client.MkdirAll(remotePath) - if err != nil { - logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error()) - return nil - } - } else { - // 如果是文件,则复制文件内容 - localFile, err := os.Open(localPath) - if err != nil { - logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error()) - return nil - } - defer localFile.Close() - - remoteFile, err := s.Client.Create(remotePath) - if err != nil { - logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error()) - return nil - } - defer remoteFile.Close() - - _, err = io.Copy(remoteFile, localFile) - if err != nil { - logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error()) - return nil - } - } - - return nil - }) + authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey)) + cmdStrArr := []string{ + fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User), + fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User), + fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User), + } + _, err = c.RunCMD(strings.Join(cmdStrArr, " && ")) if err != nil { - logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error()) - return err - } - return nil -} - -// CopyDirRemoteToLocal 复制文件-远程到本地 -func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error { - // 打开远程文件 - remoteFile, err := s.Client.Open(remotePath) - if err != nil { - logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error()) - return err - } - defer remoteFile.Close() - - if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil { - return err - } - - // 如果目标文件已经存在,先将目标文件重命名 - // if info, err := os.Stat(localPath); err == nil && !info.IsDir() { - // ext := filepath.Ext(localPath) - // name := localPath[0 : len(localPath)-len(ext)] - // newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext) - // err := os.Rename(localPath, newName) - // if err != nil { - // return err - // } - // } - - // 创建本地文件 - localFile, err := os.Create(localPath) - if err != nil { - logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error()) - return err - } - defer localFile.Close() - - // 复制文件内容 - _, err = io.Copy(localFile, remoteFile) - if err != nil { - logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error()) - return err - } - return nil -} - -// CopyDirRemoteToLocal 复制文件-本地到远程 -func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error { - // 打开本地文件 - localFile, err := os.Open(localPath) - if err != nil { - logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error()) - return err - } - defer localFile.Close() - - // 创建远程文件 - remoteFile, err := s.Client.Create(remotePath) - if err != nil { - logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error()) - return err - } - defer remoteFile.Close() - - // 复制文件内容 - _, err = io.Copy(remoteFile, localFile) - if err != nil { - logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error()) + logger.Errorf("SendAuthorizedKeys echo err %s", err.Error()) return err } return nil diff --git a/src/framework/utils/ssh/ssh_session.go b/src/framework/utils/ssh/ssh_session.go new file mode 100644 index 0000000..1244ac2 --- /dev/null +++ b/src/framework/utils/ssh/ssh_session.go @@ -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() +} diff --git a/src/framework/utils/telnet/parse.go b/src/framework/utils/telnet/parse.go new file mode 100644 index 0000000..31e46bc --- /dev/null +++ b/src/framework/utils/telnet/parse.go @@ -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 +} diff --git a/src/framework/utils/telnet/telnet.go b/src/framework/utils/telnet/telnet.go index 078fd47..bcafd08 100644 --- a/src/framework/utils/telnet/telnet.go +++ b/src/framework/utils/telnet/telnet.go @@ -50,11 +50,11 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) { // fmt.Fprintln(client, c.User) // fmt.Fprintln(client, c.Password) - // 需要确保接收方理解并正确处理发送窗口大小设置命令 - client.Write([]byte{255, 251, 31}) // 发送窗口大小选项 - client.Write([]byte{255, 250, 31, 0, 128, 0, 120, 255, 240}) // 发送窗口行和列的大小 c.Client = &client + // 调整窗口大小 (120 列 x 128 行) + requestPty(c.Client, 120, 128) + // 排空连接登录的信息 c.RunCMD("") return c, nil @@ -73,8 +73,6 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) { return "", fmt.Errorf("telnet client not connected") } conn := *c.Client - var buf bytes.Buffer - tmp := make([]byte, 1024) // 写入命令 if cmd != "" { @@ -83,22 +81,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) { } } - // 读取命令消息 + var buf bytes.Buffer + tmp := make([]byte, 1024) for { - // 设置读取超时时间为1000毫秒 - conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond)) + // 读取命令消息 n, err := conn.Read(tmp) - if err != nil { - // 判断是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - break - } + if n == 0 || err != nil { + tmp = nil break } - if n == 0 { + + tmpStr := string(tmp[:n]) + buf.WriteString(tmpStr) + + // 是否有终止符 + if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") { + tmp = nil break } - buf.Write(tmp[:n]) } defer buf.Reset() @@ -107,77 +107,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) { } // NewClient 创建Telnet客户端会话对象 -func (c *ConnTelnet) NewClientSession(cols, rows uint8) (*TelnetClientSession, error) { +func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) { if c.Client == nil { return nil, fmt.Errorf("telnet client not connected") } + requestPty(c.Client, cols, rows) return &TelnetClientSession{ Client: *c.Client, }, nil } -// TelnetClientSession Telnet客户端会话对象 -type TelnetClientSession struct { - Client net.Conn -} - -// Close 关闭会话 -func (s *TelnetClientSession) Close() { - if s.Client != nil { - s.Client.Close() - } -} - -// Write 写入命令 不带回车(\n)也会执行根据客户端情况 -func (s *TelnetClientSession) Write(cmd string) (int, error) { - if s.Client == nil { - return 0, fmt.Errorf("client is nil to content write failed") - } - return s.Client.Write([]byte(cmd)) -} - -// Read 读取结果 等待一会才有结果 -func (s *TelnetClientSession) Read() []byte { - if s.Client == nil { - return []byte{} - } - - buf := make([]byte, 1024) - // 设置读取超时时间为100毫秒 - s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - _, err := s.Client.Read(buf) - if err != nil { - return []byte{} - } - return buf -} - -// CombinedOutput 发送命令带结果返回 -func (s *TelnetClientSession) CombinedOutput(cmd string) (string, error) { - n, err := s.Write(cmd) - if n == 0 || err != nil { - return "", err - } - - var buf bytes.Buffer - tmp := make([]byte, 1024) - for { - // 设置读取超时时间为1000毫秒 - s.Client.SetReadDeadline(time.Now().Add(1000 * time.Millisecond)) - n, err := s.Client.Read(tmp) - if err != nil { - // 判断是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - break - } - break - } - if n == 0 { - break - } - buf.Write(tmp[:n]) - } - defer buf.Reset() - - return buf.String(), nil +// requestPty 调整终端窗口大小 +func requestPty(client *net.Conn, cols, rows int) error { + if client == nil { + return fmt.Errorf("telnet client not connected") + } + conn := *client + // 需要确保接收方理解并正确处理发送窗口大小设置命令 + conn.Write([]byte{255, 251, 31}) + conn.Write([]byte{255, 250, 31, byte(cols >> 8), byte(cols & 0xFF), byte(rows >> 8), byte(rows & 0xFF), 255, 240}) + return nil } diff --git a/src/framework/utils/telnet/telnet_session.go b/src/framework/utils/telnet/telnet_session.go new file mode 100644 index 0000000..9289eeb --- /dev/null +++ b/src/framework/utils/telnet/telnet_session.go @@ -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 +} diff --git a/src/modules/network_data/controller/alarm.go b/src/modules/network_data/controller/all_alarm.go similarity index 100% rename from src/modules/network_data/controller/alarm.go rename to src/modules/network_data/controller/all_alarm.go diff --git a/src/modules/network_data/controller/perf_kpi.go b/src/modules/network_data/controller/all_kpi.go similarity index 98% rename from src/modules/network_data/controller/perf_kpi.go rename to src/modules/network_data/controller/all_kpi.go index fe231d5..6131c12 100644 --- a/src/modules/network_data/controller/perf_kpi.go +++ b/src/modules/network_data/controller/all_kpi.go @@ -1,9 +1,9 @@ package controller import ( - "be.ems/lib/core/utils/date" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/date" "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" diff --git a/src/modules/network_data/controller/amf.go b/src/modules/network_data/controller/amf.go index 4611797..fbc7142 100644 --- a/src/modules/network_data/controller/amf.go +++ b/src/modules/network_data/controller/amf.go @@ -1,22 +1,30 @@ package controller import ( + "encoding/json" + "fmt" + "strconv" "strings" + "time" "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" + sysService "be.ems/src/modules/system/service" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" ) // 实例化控制层 AMFController 结构体 var NewAMFController = &AMFController{ neInfoService: neService.NewNeInfoImpl, - ueEventService: neDataService.NewUEEventImpl, + ueEventService: neDataService.NewUEEventAMFImpl, } // 网元AMF @@ -25,8 +33,8 @@ var NewAMFController = &AMFController{ type AMFController struct { // 网元信息服务 neInfoService neService.INeInfo - // CDR会话事件服务 - ueEventService neDataService.IUEEvent + // UE会话事件服务 + ueEventService neDataService.IUEEventAMF } // UE会话列表 @@ -34,19 +42,19 @@ type AMFController struct { // GET /ue/list func (s *AMFController) UEList(c *gin.Context) { language := ctx.AcceptLanguage(c) - var querys model.UEEventQuery + var querys model.UEEventAMFQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - querys.RmUID = neInfo.RmUID + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID // 查询数据 data := s.ueEventService.SelectPage(querys) @@ -78,3 +86,125 @@ func (s *AMFController) UERemove(c *gin.Context) { msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) c.JSON(200, result.OkMsg(msg)) } + +// UE会话列表导出 +// +// POST /ue/export +func (s *AMFController) UEExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.UEEventAMFQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.ueEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.UEEventAMF) + + // 导出文件名称 + fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := "" + for _, v := range dictUEEventType { + if row.EventType == v.DictValue { + eventType = i18n.TKey(language, v.DictLabel) + break + } + } + // 取结果 + eventResult := "" + // 取时间 + timeStr := "" + if row.EventType == "auth-result" { + if v, ok := eventJSON["authTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["authCode"]; ok && v != nil { + eventResult = v.(string) + for _, v := range dictUEAauthCode { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + if row.EventType == "detach" { + if v, ok := eventJSON["detachTime"]; ok && v != nil { + timeStr = v.(string) + } + eventResult = "Success" + } + if row.EventType == "cm-state" { + if v, ok := eventJSON["changeTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["status"]; ok && v != nil { + eventResult = v.(string) + for _, v := range dictUEEventCmState { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index 4ddf7ba..feef381 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -1,22 +1,31 @@ package controller import ( + "encoding/json" + "fmt" + "strconv" "strings" + "time" "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/date" + "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" + sysService "be.ems/src/modules/system/service" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" ) // 实例化控制层 IMSController 结构体 var NewIMSController = &IMSController{ neInfoService: neService.NewNeInfoImpl, - cdrEventService: neDataService.NewCDREventImpl, + cdrEventService: neDataService.NewCDREventIMSImpl, } // 网元IMS @@ -26,7 +35,7 @@ type IMSController struct { // 网元信息服务 neInfoService neService.INeInfo // CDR会话事件服务 - cdrEventService neDataService.ICDREvent + cdrEventService neDataService.ICDREventIMS } // CDR会话列表 @@ -34,19 +43,19 @@ type IMSController struct { // GET /cdr/list func (s *IMSController) CDRList(c *gin.Context) { language := ctx.AcceptLanguage(c) - var querys model.CDREventQuery + var querys model.CDREventIMSQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - querys.RmUID = neInfo.RmUID + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID // 查询数据 data := s.cdrEventService.SelectPage(querys) @@ -78,3 +87,126 @@ func (s *IMSController) CDRRemove(c *gin.Context) { msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) c.JSON(200, result.OkMsg(msg)) } + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *IMSController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.CDREventIMSQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.cdrEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.CDREventIMS) + + // 导出文件名称 + fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Record Behavior", + "C1": "Type", + "D1": "Called", + "E1": "Caller", + "F1": "Duration", + "G1": "Result", + "H1": "Time", + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := sysService.NewSysDictDataImpl.SelectDictDataByType("cdr_sip_code") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := sysService.NewSysDictDataImpl.SelectDictDataByType("cdr_call_type") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 呼叫类型 + callType := "sms" + callTypeLable := "SMS" + if v, ok := cdrJSON["callType"]; ok && v != nil { + callType = v.(string) + for _, v := range dictCDRCallType { + if callType == v.DictValue { + callTypeLable = i18n.TKey(language, v.DictLabel) + break + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { + duration = fmt.Sprint(parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Success" + if v, ok := cdrJSON["cause"]; ok && v != nil && callType != "sms" { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DictValue { + callResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["releaseTime"]; ok && v != nil { + releaseTime := parse.Number(v) + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: recordType, + "C" + idx: callTypeLable, + "D" + idx: called, + "E" + idx: caller, + "F" + idx: duration, + "G" + idx: callResult, + "H" + idx: timeStr, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/mme.go b/src/modules/network_data/controller/mme.go new file mode 100644 index 0000000..a7707a1 --- /dev/null +++ b/src/modules/network_data/controller/mme.go @@ -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) +} diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go index ee3ddb9..2e03338 100644 --- a/src/modules/network_data/controller/smf.go +++ b/src/modules/network_data/controller/smf.go @@ -1,32 +1,39 @@ package controller import ( + "encoding/json" + "fmt" + "strconv" "strings" + "time" "be.ems/src/framework/i18n" + "be.ems/src/framework/logger" "be.ems/src/framework/utils/ctx" + "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" "be.ems/src/modules/network_data/model" neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" ) -// 实例化控制层 IMSController 结构体 +// 实例化控制层 SMFController 结构体 var NewSMFController = &SMFController{ neInfoService: neService.NewNeInfoImpl, - cdrEventService: neDataService.NewSMFCDREventImpl, + cdrEventService: neDataService.NewCDREventSMFImpl, } -// 网元IMS +// 网元SMF // -// PATH /ims +// PATH /smf type SMFController struct { // 网元信息服务 neInfoService neService.INeInfo - // SMF CDR会话事件服务 - cdrEventService neDataService.SMFCDREvent + // CDR会话事件服务 + cdrEventService neDataService.ICDREventSMF } // CDR会话列表 @@ -34,19 +41,19 @@ type SMFController struct { // GET /cdr/list func (s *SMFController) CDRList(c *gin.Context) { language := ctx.AcceptLanguage(c) - var querys model.SMFCDREventQuery + var querys model.CDREventSMFQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - querys.RmUID = neInfo.RmUID + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID // 查询数据 data := s.cdrEventService.SelectPage(querys) @@ -78,3 +85,174 @@ func (s *SMFController) CDRRemove(c *gin.Context) { msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) c.JSON(200, result.OkMsg(msg)) } + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *SMFController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.CDREventSMFQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.cdrEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.CDREventSMF) + + // 导出文件名称 + fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Charging ID", + "C1": "Subscriber ID Data", + "D1": "Subscriber ID Type", + "E1": "Data Volume Uplink", + "F1": "Data Volume Downlink", + "G1": "Data Total Volume", + "H1": "Duration", + "I1": "Invocation Time", + "J1": "PDU Session Charging Information", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // 订阅 ID 类型 + subscriptionIDType := "-" + // 订阅 ID 数据 + subscriptionIDData := "-" + if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { + if sub, subOk := v.(map[string]any); subOk && sub != nil { + subscriptionIDType = sub["subscriptionIDType"].(string) + subscriptionIDData = sub["subscriptionIDData"].(string) + } + } + // 数据量上行链路 + dataVolumeUplink := []string{} + // 数据量下行链路 + dataVolumeDownlink := []string{} + // 数据总量 + dataTotalVolume := []string{} + if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + usedUnitList := usedUnit["usedUnitContainer"].([]any) + if len(usedUnitList) > 0 { + for _, data := range usedUnitList { + udata := data.(map[string]any) + if dup, dupOk := udata["dataVolumeUplink"]; dupOk { + dataVolumeUplink = append(dataVolumeUplink, fmt.Sprint(parse.Number(dup))) + } + if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { + dataVolumeDownlink = append(dataVolumeDownlink, fmt.Sprint(parse.Number(ddown))) + } + if dt, dtOk := udata["dataTotalVolume"]; dtOk { + dataTotalVolume = append(dataTotalVolume, fmt.Sprint(parse.Number(dt))) + } + } + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { + invocationTimestamp = v.(string) + } + // 记录打开时间 + pduSessionChargingInformation := "" + if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { + pduInfo := v.(map[string]any) + + User_Identifier := "" + if v, ok := pduInfo["userIdentifier"]; ok && v != nil { + User_Identifier = v.(string) + } + SSC_Mode := "" + if v, ok := pduInfo["sSCMode"]; ok && v != nil { + SSC_Mode = v.(string) + } + RAT_Type := "" + if v, ok := pduInfo["rATType"]; ok && v != nil { + RAT_Type = v.(string) + } + DNN_ID := "" + if v, ok := pduInfo["dNNID"]; ok && v != nil { + DNN_ID = v.(string) + } + PDU_Type := "" + if v, ok := pduInfo["pDUType"]; ok && v != nil { + PDU_Type = v.(string) + } + PDU_IPv4 := "" + PDU_IPv6 := "" + if v, ok := pduInfo["pDUAddress"]; ok && v != nil { + pDUAddress := v.(map[string]any) + if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { + PDU_IPv4 = addr.(string) + } + if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { + PDU_IPv6 = addr.(string) + } + } + + pduSessionChargingInformation = fmt.Sprintf(`User Identifier: %s +SSC Mode: %s RAT Type: %s DNN ID: %s +PDU Type: %s +PDU IPv4 Address: %s +PDU IPv6 Addres Swith Prefix: %s`, User_Identifier, SSC_Mode, RAT_Type, DNN_ID, PDU_Type, PDU_IPv4, PDU_IPv6) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: chargingID, + "C" + idx: subscriptionIDData, + "D" + idx: subscriptionIDType, + "E" + idx: strings.Join(dataVolumeUplink, ","), + "F" + idx: strings.Join(dataVolumeDownlink, ","), + "G" + idx: strings.Join(dataTotalVolume, ","), + "H" + idx: duration, + "I" + idx: invocationTimestamp, + "J" + idx: pduSessionChargingInformation, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_element/controller/udm_auth.go b/src/modules/network_data/controller/udm_auth.go similarity index 60% rename from src/modules/network_element/controller/udm_auth.go rename to src/modules/network_data/controller/udm_auth.go index f7910fe..e19888a 100644 --- a/src/modules/network_element/controller/udm_auth.go +++ b/src/modules/network_data/controller/udm_auth.go @@ -2,18 +2,19 @@ package controller import ( "fmt" + "path/filepath" "strings" "time" - mmlclient "be.ems/lib/core/mml_client" "be.ems/src/framework/constants/uploadsubpath" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/ssh" + "be.ems/src/framework/utils/telnet" "be.ems/src/framework/vo/result" - "be.ems/src/modules/network_element/model" + "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" @@ -21,21 +22,21 @@ import ( // 实例化控制层 UDMAuthController 结构体 var NewUDMAuth = &UDMAuthController{ - udmAuthService: neService.NewUDMAuthImpl, + udmAuthService: neDataService.NewUDMAuthImpl, neInfoService: neService.NewNeInfoImpl, } -// UDM鉴权用户请求 +// UDM鉴权用户 // // PATH /udm/auth type UDMAuthController struct { // UDM鉴权信息服务 - udmAuthService neService.IUDMAuth + udmAuthService neDataService.IUDMAuth // 网元信息服务 neInfoService neService.INeInfo } -// UDM鉴权用户-获取全部保存数据库 +// UDM鉴权用户重载数据 // // POST /resetData/:neId func (s *UDMAuthController) ResetData(c *gin.Context) { @@ -47,21 +48,21 @@ func (s *UDMAuthController) ResetData(c *gin.Context) { } neId = "" - data := s.udmAuthService.Save(neId) + data := s.udmAuthService.ResetData(neId) c.JSON(200, result.OkData(data)) } -// UDM鉴权用户 +// UDM鉴权用户列表 // // GET /list func (s *UDMAuthController) List(c *gin.Context) { querys := ctx.QueryMap(c) querys["neId"] = "" - data := s.udmAuthService.Page(querys) + data := s.udmAuthService.SelectPage(querys) c.JSON(200, result.Ok(data)) } -// UDM鉴权用户-信息 +// UDM鉴权用户信息 // // GET /:neId/:imsi func (s *UDMAuthController) Info(c *gin.Context) { @@ -80,10 +81,16 @@ func (s *UDMAuthController) Info(c *gin.Context) { return } - msg := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg) + cmd := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + data, err := telnet.ConvertToMap(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -94,31 +101,31 @@ func (s *UDMAuthController) Info(c *gin.Context) { return } - // 查询数据库是否存在并存入 neId = "" - var userInfo model.UDMAuth - list := s.udmAuthService.List(model.UDMAuth{NeID: neId, Imsi: imsi}) - if len(list) > 0 { - userInfo = list[0] - // 返回查询的用户信息 - userInfo.Amf = data["amf"] - userInfo.AlgoIndex = data["algo"] - userInfo.Opc = data["opc"] - userInfo.Ki = data["ki"] - } else { - userInfo := model.UDMAuth{ - Imsi: imsi, - Amf: data["amf"], - AlgoIndex: data["algo"], - Opc: data["opc"], - Ki: data["ki"], - } - s.udmAuthService.Insert(neId, userInfo) + u := model.UDMAuth{ + IMSI: imsi, + Amf: data["amf"], + Status: "1", + Ki: data["ki"], + AlgoIndex: data["algo"], + Opc: data["opc"], + NeId: neId, } - c.JSON(200, result.OkData(userInfo)) + + // 查询imsi存在赋予id用于更新 + list := s.udmAuthService.SelectList(u) + if len(list) > 0 { + item := list[0] + if item.ID != "" { + u.ID = item.ID + } + } + go s.udmAuthService.Insert(neId, u) + + c.JSON(200, result.OkData(u)) } -// UDM鉴权用户-增加 +// UDM鉴权用户新增 // // POST /:neId func (s *UDMAuthController) Add(c *gin.Context) { @@ -131,7 +138,7 @@ func (s *UDMAuthController) Add(c *gin.Context) { var body model.UDMAuth err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -143,10 +150,16 @@ func (s *UDMAuthController) Add(c *gin.Context) { return } - msg := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -155,12 +168,12 @@ func (s *UDMAuthController) Add(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Insert(neId, body) + go s.udmAuthService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-批量添加 +// UDM鉴权用户批量新增 // // POST /:neId/:num func (s *UDMAuthController) Adds(c *gin.Context) { @@ -174,7 +187,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) { var body model.UDMAuth err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -186,10 +199,16 @@ func (s *UDMAuthController) Adds(c *gin.Context) { return } - msg := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -198,12 +217,12 @@ func (s *UDMAuthController) Adds(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Inserts(neId, body, num) + go s.udmAuthService.LoadData(neId, body.IMSI, num) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-修改 +// UDM鉴权用户修改 // // PUT /:neId func (s *UDMAuthController) Edit(c *gin.Context) { @@ -216,7 +235,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) { var body model.UDMAuth err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -228,23 +247,29 @@ func (s *UDMAuthController) Edit(c *gin.Context) { return } - msg := fmt.Sprintf("mod authdata:imsi=%s", body.Imsi) - // 修改的参数名称 - if body.Ki != "" { - msg += fmt.Sprintf(",ki=%s", body.Ki) - } - if body.Amf != "" { - msg += fmt.Sprintf(",amf=%s", body.Amf) - } - if body.AlgoIndex != "" { - msg += fmt.Sprintf(",algo=%s", body.AlgoIndex) - } - if body.Opc != "" { - msg += fmt.Sprintf(",opc=%s", body.Opc) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("mod authdata:imsi=%s", body.IMSI) + // 修改的参数名称 + if body.Ki != "" { + cmd += fmt.Sprintf(",ki=%s", body.Ki) + } + if body.Amf != "" { + cmd += fmt.Sprintf(",amf=%s", body.Amf) + } + if body.AlgoIndex != "" { + cmd += fmt.Sprintf(",algo=%s", body.AlgoIndex) + } + if body.Opc != "" { + cmd += fmt.Sprintf(",opc=%s", body.Opc) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -253,12 +278,12 @@ func (s *UDMAuthController) Edit(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Update(neId, body) + go s.udmAuthService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-删除 +// UDM鉴权用户删除 // // DELETE /:neId/:imsi func (s *UDMAuthController) Remove(c *gin.Context) { @@ -285,27 +310,34 @@ func (s *UDMAuthController) Remove(c *gin.Context) { return } + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + resultData := map[string]string{} for _, imsi := range uniqueIDs { - msg := fmt.Sprintf("del authdat:imsi=%s", imsi) - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("del authdat:imsi=%s", imsi) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { resultData[imsi] = err.Error() + continue } // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Delete(neId, imsi) - resultData[imsi] = data + go s.udmAuthService.Delete(neId, imsi) } + resultData[imsi] = data } c.JSON(200, result.OkData(resultData)) } -// UDM鉴权用户-批量删除 +// UDM鉴权用户批量删除 // // DELETE /:neId/:imsi/:num func (s *UDMAuthController) Removes(c *gin.Context) { @@ -325,10 +357,16 @@ func (s *UDMAuthController) Removes(c *gin.Context) { return } - msg := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -337,12 +375,12 @@ func (s *UDMAuthController) Removes(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Deletes(neId, imsi, num) + go s.udmAuthService.LoadData(neId, imsi, num) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-导出 +// UDM鉴权用户导出 // // POST /export func (s *UDMAuthController) Export(c *gin.Context) { @@ -358,14 +396,14 @@ func (s *UDMAuthController) Export(c *gin.Context) { } if !(body.Type == "csv" || body.Type == "txt") { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errExportType"))) return } neId := "" - list := s.udmAuthService.List(model.UDMAuth{NeID: neId}) + list := s.udmAuthService.SelectList(model.UDMAuth{NeId: neId}) // 文件名 - fileName := fmt.Sprintf("OMC_AUTH_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) + fileName := fmt.Sprintf("udm_auth_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName) if body.Type == "csv" { @@ -373,7 +411,7 @@ func (s *UDMAuthController) Export(c *gin.Context) { data := [][]string{} data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"}) for _, v := range list { - data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) } // 输出到文件 err := file.WriterFileCSV(data, filePath) @@ -387,7 +425,7 @@ func (s *UDMAuthController) Export(c *gin.Context) { // 转换数据 data := [][]string{} for _, v := range list { - data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) } // 输出到文件 err = file.WriterFileTXT(data, ",", filePath) @@ -400,55 +438,68 @@ func (s *UDMAuthController) Export(c *gin.Context) { c.FileAttachment(filePath, fileName) } -// UDM鉴权用户-导入 +// UDM鉴权用户导入 // // POST /import func (s *UDMAuthController) Import(c *gin.Context) { language := ctx.AcceptLanguage(c) - neId := c.PostForm("neId") - if neId == "" { + var body struct { + NeId string `json:"neId" binding:"required"` + UploadPath string `json:"uploadPath" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - formFile, err := c.FormFile("file") - if err != nil { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - // 获取文件名 - if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) { + + // 判断文件名 + if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) return } - // 上传文件转存 - upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil) - if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) - return - } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) - if neInfo.NeId != neId || neInfo.IP == "" { + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - // 本地文件 - localPath := file.ParseUploadFilePath(upFilePath) - nePath := "/tmp" //config.Get("mml.upload").(string) - // 复制到远程 - err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() - fileName := localPath[strings.LastIndex(localPath, "/")+1:] - msg := fmt.Sprintf("import authdat:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg("error uploading file")) + return + } + + // 网元主机的Telnet客户端 + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("import authdat:path=%s", neFilePath) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -456,15 +507,15 @@ func (s *UDMAuthController) Import(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { - if strings.HasSuffix(fileName, ".csv") { - data := file.ReadFileCSV(localPath) - neId = "" - go s.udmAuthService.InsertCSV(neId, data) + if strings.HasSuffix(body.UploadPath, ".csv") { + data := file.ReadFileCSV(localFilePath) + neId := "" + go s.udmAuthService.InsertData(neId, "csv", data) } - if strings.HasSuffix(fileName, ".txt") { - data := file.ReadFileTXT(",", localPath) - neId = "" - go s.udmAuthService.InsertTxt(neId, data) + if strings.HasSuffix(body.UploadPath, ".txt") { + data := file.ReadFileTXT(",", localFilePath) + neId := "" + go s.udmAuthService.InsertData(neId, "txt", data) } } c.JSON(200, result.OkMsg(data)) diff --git a/src/modules/network_element/controller/udm_sub.go b/src/modules/network_data/controller/udm_sub.go similarity index 62% rename from src/modules/network_element/controller/udm_sub.go rename to src/modules/network_data/controller/udm_sub.go index 80bf805..62f57ac 100644 --- a/src/modules/network_element/controller/udm_sub.go +++ b/src/modules/network_data/controller/udm_sub.go @@ -2,19 +2,20 @@ package controller import ( "fmt" + "path/filepath" "strconv" "strings" "time" - mmlclient "be.ems/lib/core/mml_client" "be.ems/src/framework/constants/uploadsubpath" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" - "be.ems/src/framework/utils/ssh" + "be.ems/src/framework/utils/telnet" "be.ems/src/framework/vo/result" - "be.ems/src/modules/network_element/model" + "be.ems/src/modules/network_data/model" + neDataService "be.ems/src/modules/network_data/service" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" @@ -22,21 +23,21 @@ import ( // 实例化控制层 UDMSubController 结构体 var NewUDMSub = &UDMSubController{ - udmSubService: neService.NewUDMSubImpl, + udmSubService: neDataService.NewUDMSubImpl, neInfoService: neService.NewNeInfoImpl, } -// UDM签约用户请求 +// UDM签约用户 // // PATH /udm/sub type UDMSubController struct { - // UDM鉴权信息服务 - udmSubService neService.IUDMSub + // UDM签约信息服务 + udmSubService neDataService.IUDMSub // 网元信息服务 neInfoService neService.INeInfo } -// UDM签约用户-获取全部保存数据库 +// UDM签约用户重载数据 // // POST /resetData/:neId func (s *UDMSubController) ResetData(c *gin.Context) { @@ -48,21 +49,21 @@ func (s *UDMSubController) ResetData(c *gin.Context) { } neId = "" - data := s.udmSubService.Save(neId) + data := s.udmSubService.ResetData(neId) c.JSON(200, result.OkData(data)) } -// UDM签约用户 +// UDM签约用户列表 // // GET /list func (s *UDMSubController) List(c *gin.Context) { querys := ctx.QueryMap(c) querys["neId"] = "" - data := s.udmSubService.Page(querys) + data := s.udmSubService.SelectPage(querys) c.JSON(200, result.Ok(data)) } -// UDM签约用户-信息 +// UDM签约用户信息 // // GET /:neId/:imsi func (s *UDMSubController) Info(c *gin.Context) { @@ -81,10 +82,16 @@ func (s *UDMSubController) Info(c *gin.Context) { return } - msg := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg) + cmd := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + data, err := telnet.ConvertToMap(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -103,8 +110,9 @@ func (s *UDMSubController) Info(c *gin.Context) { if imsMsisdnLen != -1 { msisdn = msisdn[:imsMsisdnLen] } - userInfo := model.UDMSub{ - Imsi: imsi, + neId = "" + u := model.UDMSub{ + IMSI: imsi, Msisdn: msisdn, Ambr: data["AMBR"], Arfb: data["AreaForbidden"], @@ -114,35 +122,37 @@ func (s *UDMSubController) Info(c *gin.Context) { Nssai: data["NSSAI"], SmfSel: data["Smf-Selection"], Rat: fmt.Sprint(rat), + NeId: neId, } // 1,64,24,65,def_eps,1,2,010200000000,- if v, ok := data["EPS-Data"]; ok { - userInfo.EpsDat = v + u.EpsDat = v arr := strings.Split(v, ",") - userInfo.EpsFlag = arr[0] - userInfo.EpsOdb = arr[1] - userInfo.HplmnOdb = arr[2] - userInfo.Ard = arr[3] - userInfo.Epstpl = arr[4] - userInfo.ContextId = arr[5] - userInfo.ApnContext = arr[7] - userInfo.StaticIp = arr[8] + u.EpsFlag = arr[0] + u.EpsOdb = arr[1] + u.HplmnOdb = arr[2] + u.Ard = arr[3] + u.Epstpl = arr[4] + u.ContextId = arr[5] + u.ApnContext = arr[7] + // [6] 是不要的,导入和导出不用 + u.StaticIp = arr[8] } - // 查询数据库是否存在并存入更新 - neId = "" - list := s.udmSubService.List(model.UDMSub{NeID: neId, Imsi: imsi}) + // 查询imsi存在赋予id用于更新 + list := s.udmSubService.SelectList(u) if len(list) > 0 { - listItme := list[0] - userInfo.ID = listItme.ID - s.udmSubService.Update(neId, userInfo) - } else { - s.udmSubService.Insert(neId, userInfo) + item := list[0] + if item.ID != "" { + u.ID = item.ID + } } - c.JSON(200, result.OkData(userInfo)) + go s.udmSubService.Insert(neId, u) + + c.JSON(200, result.OkData(u)) } -// UDM签约用户-增加 +// UDM签约用户新增 // // POST /:neId func (s *UDMSubController) Add(c *gin.Context) { @@ -155,7 +165,7 @@ func (s *UDMSubController) Add(c *gin.Context) { var body model.UDMSub err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -167,15 +177,21 @@ func (s *UDMSubController) Add(c *gin.Context) { return } - msg := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", - body.Imsi, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) - // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", + body.IMSI, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) + // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -184,12 +200,12 @@ func (s *UDMSubController) Add(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Insert(neId, body) + go s.udmSubService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-批量添加 +// UDM签约用户批量新增 // // POST /:neId/:num func (s *UDMSubController) Adds(c *gin.Context) { @@ -203,7 +219,7 @@ func (s *UDMSubController) Adds(c *gin.Context) { var body model.UDMSub err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -215,15 +231,21 @@ func (s *UDMSubController) Adds(c *gin.Context) { return } - msg := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", - body.Imsi, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) - // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", + body.IMSI, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) + // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -232,12 +254,12 @@ func (s *UDMSubController) Adds(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Inserts(neId, body, num) + go s.udmSubService.LoadData(neId, body.IMSI, num) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-修改 +// UDM签约用户修改 // // PUT /:neId func (s *UDMSubController) Edit(c *gin.Context) { @@ -250,7 +272,7 @@ func (s *UDMSubController) Edit(c *gin.Context) { var body model.UDMSub err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -262,65 +284,71 @@ func (s *UDMSubController) Edit(c *gin.Context) { return } - msg := fmt.Sprintf("mod udmuser:imsi=%s", body.Imsi) - // 修改的参数名称 - if body.Msisdn != "" { - msg += fmt.Sprintf(",msisdn=%s", body.Msisdn) - } - if body.Ambr != "" { - msg += fmt.Sprintf(",ambr=%s", body.Ambr) - } - if body.Nssai != "" { - msg += fmt.Sprintf(",nssai=%s", body.Nssai) - } - if body.Arfb != "" { - msg += fmt.Sprintf(",arfb=%s", body.Arfb) - } - if body.Sar != "" { - msg += fmt.Sprintf(",sar=%s", body.Sar) - } - if body.Rat != "" { - msg += fmt.Sprintf(",rat=%s", body.Rat) - } - if body.Cn != "" { - msg += fmt.Sprintf(",cn=%s", body.Cn) - } - if body.SmfSel != "" { - msg += fmt.Sprintf(",smf_sel=%s", body.SmfSel) - } - if body.SmData != "" { - msg += fmt.Sprintf(",sm_data=%s", body.SmData) - } - if body.EpsDat != "" { - msg += fmt.Sprintf(",eps_dat=%s", body.EpsDat) - } - if body.EpsFlag != "" { - msg += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) - } - if body.EpsOdb != "" { - msg += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) - } - if body.HplmnOdb != "" { - msg += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) - } - if body.Epstpl != "" { - msg += fmt.Sprintf(",epstpl=%s", body.Epstpl) - } - if body.Ard != "" { - msg += fmt.Sprintf(",ard=%s", body.Ard) - } - if body.ContextId != "" { - msg += fmt.Sprintf(",context_id=%s", body.ContextId) - } - if body.ApnContext != "" { - msg += fmt.Sprintf(",apn_context=%s", body.ApnContext) - } - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("mod udmuser:imsi=%s", body.IMSI) + // 修改的参数名称 + if body.Msisdn != "" { + cmd += fmt.Sprintf(",msisdn=%s", body.Msisdn) + } + if body.Ambr != "" { + cmd += fmt.Sprintf(",ambr=%s", body.Ambr) + } + if body.Nssai != "" { + cmd += fmt.Sprintf(",nssai=%s", body.Nssai) + } + if body.Arfb != "" { + cmd += fmt.Sprintf(",arfb=%s", body.Arfb) + } + if body.Sar != "" { + cmd += fmt.Sprintf(",sar=%s", body.Sar) + } + if body.Rat != "" { + cmd += fmt.Sprintf(",rat=%s", body.Rat) + } + if body.Cn != "" { + cmd += fmt.Sprintf(",cn=%s", body.Cn) + } + if body.SmfSel != "" { + cmd += fmt.Sprintf(",smf_sel=%s", body.SmfSel) + } + if body.SmData != "" { + cmd += fmt.Sprintf(",sm_data=%s", body.SmData) + } + if body.EpsDat != "" { + cmd += fmt.Sprintf(",eps_dat=%s", body.EpsDat) + } + if body.EpsFlag != "" { + cmd += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) + } + if body.EpsOdb != "" { + cmd += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) + } + if body.HplmnOdb != "" { + cmd += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) + } + if body.Epstpl != "" { + cmd += fmt.Sprintf(",epstpl=%s", body.Epstpl) + } + if body.Ard != "" { + cmd += fmt.Sprintf(",ard=%s", body.Ard) + } + if body.ContextId != "" { + cmd += fmt.Sprintf(",context_id=%s", body.ContextId) + } + if body.ApnContext != "" { + cmd += fmt.Sprintf(",apn_context=%s", body.ApnContext) + } + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -329,12 +357,12 @@ func (s *UDMSubController) Edit(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Update(neId, body) + go s.udmSubService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-删除 +// UDM签约用户删除 // // DELETE /:neId/:imsi func (s *UDMSubController) Remove(c *gin.Context) { @@ -361,27 +389,34 @@ func (s *UDMSubController) Remove(c *gin.Context) { return } + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + resultData := map[string]string{} for _, imsi := range uniqueIDs { - msg := fmt.Sprintf("del udmuser:imsi=%s", imsi) - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("del udmuser:imsi=%s", imsi) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { resultData[imsi] = err.Error() + continue } // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Delete(neId, imsi) - resultData[imsi] = data + go s.udmSubService.Delete(neId, imsi) } + resultData[imsi] = data } c.JSON(200, result.OkData(resultData)) } -// UDM签约用户-批量删除 +// UDM签约用户批量删除 // // DELETE /:neId/:imsi/:num func (s *UDMSubController) Removes(c *gin.Context) { @@ -401,10 +436,16 @@ func (s *UDMSubController) Removes(c *gin.Context) { return } - msg := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -413,12 +454,12 @@ func (s *UDMSubController) Removes(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Deletes(neId, imsi, num) + go s.udmSubService.LoadData(neId, imsi, num) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-导出 +// UDM签约用户导出 // // POST /export func (s *UDMSubController) Export(c *gin.Context) { @@ -439,9 +480,9 @@ func (s *UDMSubController) Export(c *gin.Context) { } neId := "" - list := s.udmSubService.List(model.UDMSub{NeID: neId}) + list := s.udmSubService.SelectList(model.UDMSub{NeId: neId}) // 文件名 - fileName := fmt.Sprintf("OMC_SUB_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) + fileName := fmt.Sprintf("udm_sub_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName) if body.Type == "csv" { @@ -450,7 +491,7 @@ func (s *UDMSubController) Export(c *gin.Context) { data = append(data, []string{"imsi", "msisdn", "ambr", "nssai", "arfb", "sar", "rat", "cn", "smf_sel", "sm_dat", "eps_dat"}) for _, v := range list { epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) - data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) + data = append(data, []string{v.IMSI, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) } // 输出到文件 err = file.WriterFileCSV(data, filePath) @@ -465,7 +506,7 @@ func (s *UDMSubController) Export(c *gin.Context) { data := [][]string{} for _, v := range list { epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) - data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) + data = append(data, []string{v.IMSI, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) } // 输出到文件 err = file.WriterFileTXT(data, ",", filePath) @@ -478,55 +519,68 @@ func (s *UDMSubController) Export(c *gin.Context) { c.FileAttachment(filePath, fileName) } -// UDM签约用户-导入 +// UDM签约用户导入 // // POST /import func (s *UDMSubController) Import(c *gin.Context) { language := ctx.AcceptLanguage(c) - neId := c.PostForm("neId") - if neId == "" { + var body struct { + NeId string `json:"neId" binding:"required"` + UploadPath string `json:"uploadPath" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - formFile, err := c.FormFile("file") - if err != nil { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - // 获取文件名 - if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) { + + // 判断文件名 + if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat"))) return } - // 上传文件转存 - upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil) - if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) - return - } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) - if neInfo.NeId != neId || neInfo.IP == "" { + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - // 本地文件 - localPath := file.ParseUploadFilePath(upFilePath) - nePath := "/tmp" //config.Get("mml.upload").(string) - // 复制到远程 - err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() - fileName := localPath[strings.LastIndex(localPath, "/")+1:] - msg := fmt.Sprintf("import udmuser:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg("error uploading file")) + return + } + + // 网元主机的Telnet客户端 + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("import udmuser:path=%s", neFilePath) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -534,15 +588,15 @@ func (s *UDMSubController) Import(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { - if strings.HasSuffix(fileName, ".csv") { - data := file.ReadFileCSV(localPath) - neId = "" - go s.udmSubService.InsertCSV(neId, data) + if strings.HasSuffix(body.UploadPath, ".csv") { + data := file.ReadFileCSV(localFilePath) + neId := "" + go s.udmSubService.InsertData(neId, "csv", data) } - if strings.HasSuffix(fileName, ".txt") { - data := file.ReadFileTXT(",", localPath) - neId = "" - go s.udmSubService.InsertTxt(neId, data) + if strings.HasSuffix(body.UploadPath, ".txt") { + data := file.ReadFileTXT(",", localFilePath) + neId := "" + go s.udmSubService.InsertData(neId, "txt", data) } } c.JSON(200, result.OkMsg(data)) diff --git a/src/modules/network_data/model/cdr_event.go b/src/modules/network_data/model/cdr_event_ims.go similarity index 83% rename from src/modules/network_data/model/cdr_event.go rename to src/modules/network_data/model/cdr_event_ims.go index ae49041..ffe280c 100644 --- a/src/modules/network_data/model/cdr_event.go +++ b/src/modules/network_data/model/cdr_event_ims.go @@ -2,20 +2,20 @@ package model import "time" -// CDREvent CDR会话对象 cdr_event_ims/cdr_event_smf -type CDREvent struct { +// CDREventIMS CDR会话对象IMS cdr_event_ims +type CDREventIMS struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } -// CDREventQuery CDR会话对象查询参数结构体 -type CDREventQuery struct { - NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型 +// CDREventIMSQuery CDR会话对象IMS查询参数结构体 +type CDREventIMSQuery struct { + NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型IMS NeID string `json:"neId" form:"neId" binding:"required"` RmUID string `json:"rmUID" form:"rmUID"` RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC MOSM MTSM diff --git a/src/modules/network_data/model/cdr_event_smf.go b/src/modules/network_data/model/cdr_event_smf.go index 0234f91..259c102 100644 --- a/src/modules/network_data/model/cdr_event_smf.go +++ b/src/modules/network_data/model/cdr_event_smf.go @@ -2,29 +2,34 @@ package model import "time" -// CDREvent CDR会话对象 cdr_event_smf +// CDREventSMF CDR会话对象SMF cdr_event_smf type CDREventSMF struct { - ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` - RecordType string `json:"recordType" gorm:"column:record_type"` - ChargingID string `json:"chargingID" gorm:"column:charging_id"` - SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"` - Duration string `json:"duration" gorm:"column:duration"` - DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"` - DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"` - DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"` - PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"` - CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeName string `json:"neName" gorm:"column:ne_name"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` + CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` + CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` + + // ====== 非数据库字段属性 ====== + + // RecordType string `json:"recordType" gorm:"column:record_type"` + // ChargingID string `json:"chargingID" gorm:"column:charging_id"` + // SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"` + // Duration string `json:"duration" gorm:"column:duration"` + // DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"` + // DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"` + // DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"` + // PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"` } -type SMFCDREventQuery struct { +// CDREventSMFQuery CDR会话对象SMF查询参数结构体 +type CDREventSMFQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // SMF NeID string `json:"neId" form:"neId" binding:"required"` RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` + RecordType string `json:"recordType" form:"recordType"` // 暂时没用到 SubscriberID string `json:"subscriberID" form:"subscriberID"` StartTime string `json:"startTime" form:"startTime"` EndTime string `json:"endTime" form:"endTime"` diff --git a/src/modules/network_element/model/udm_auth.go b/src/modules/network_data/model/udm_auth.go similarity index 81% rename from src/modules/network_element/model/udm_auth.go rename to src/modules/network_data/model/udm_auth.go index 9069858..6f7c1d1 100644 --- a/src/modules/network_element/model/udm_auth.go +++ b/src/modules/network_data/model/udm_auth.go @@ -3,13 +3,13 @@ package model // UDMAuth UDM鉴权用户对象 u_auth_user type UDMAuth struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID - Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号 Amf string `json:"amf" gorm:"column:amf"` // ANF - Status string `json:"status" gorm:"column:status"` // 状态 + Status string `json:"status" gorm:"column:status"` // 状态 默认给1 Ki string `json:"ki" gorm:"column:ki"` // ki AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex Opc string `json:"opc" gorm:"column:opc"` // opc - NeID string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 + NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 } func (UDMAuth) TableName() string { diff --git a/src/modules/network_element/model/udm_sub.go b/src/modules/network_data/model/udm_sub.go similarity index 86% rename from src/modules/network_element/model/udm_sub.go rename to src/modules/network_data/model/udm_sub.go index 55a56ef..a4f3acd 100644 --- a/src/modules/network_element/model/udm_sub.go +++ b/src/modules/network_data/model/udm_sub.go @@ -4,7 +4,7 @@ package model type UDMSub struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` Msisdn string `json:"msisdn" gorm:"column:msisdn"` // 相当手机号 - Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号 Ambr string `json:"ambr" gorm:"column:ambr"` Nssai string `json:"nssai" gorm:"column:nssai"` Rat string `json:"rat" gorm:"column:rat"` @@ -14,7 +14,7 @@ type UDMSub struct { SmData string `json:"smData" gorm:"column:sm_data"` SmfSel string `json:"smfSel" gorm:"column:smf_sel"` EpsDat string `json:"epsDat" gorm:"column:eps_dat"` - NeID string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 + NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"` EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"` @@ -27,7 +27,6 @@ type UDMSub struct { // ====== 非数据库字段属性 ====== - SubNum string `json:"subNum,omitempty" gorm:"-"` // 批量数 } func (UDMSub) TableName() string { diff --git a/src/modules/network_data/model/ue_event.go b/src/modules/network_data/model/ue_event_amf.go similarity index 83% rename from src/modules/network_data/model/ue_event.go rename to src/modules/network_data/model/ue_event_amf.go index 4045465..6fa549b 100644 --- a/src/modules/network_data/model/ue_event.go +++ b/src/modules/network_data/model/ue_event_amf.go @@ -2,20 +2,20 @@ package model import "time" -// UEEvent UE会话对象 ue_event -type UEEvent struct { +// UEEventAMF UE会话对象AMF ue_event_amf +type UEEventAMF struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` - EventType string `json:"eventType" gorm:"column:event_type"` + EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } -// UEEventQuery UE会话对象查询参数结构体 -type UEEventQuery struct { +// UEEventAMFQuery UE会话对象AMF查询参数结构体 +type UEEventAMFQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持AMF NeID string `json:"neId" form:"neId" binding:"required"` RmUID string `json:"rmUID" form:"rmUID"` diff --git a/src/modules/network_data/model/ue_event_mme.go b/src/modules/network_data/model/ue_event_mme.go new file mode 100644 index 0000000..8ceab12 --- /dev/null +++ b/src/modules/network_data/model/ue_event_mme.go @@ -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"` +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index 8d56e69..1f48464 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -4,6 +4,7 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/middleware" "be.ems/src/framework/middleware/collectlogs" + "be.ems/src/framework/middleware/repeat" "be.ems/src/modules/network_data/controller" "github.com/gin-gonic/gin" @@ -44,49 +45,58 @@ func Setup(router *gin.Engine) { // 网元IMS imsGroup := neDataGroup.Group("/ims") { - // CDR会话事件列表 imsGroup.GET("/cdr/list", middleware.PreAuthorize(nil), controller.NewIMSController.CDRList, ) - // CDR会话删除 imsGroup.DELETE("/cdr/:cdrIds", middleware.PreAuthorize(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewIMSController.CDRRemove, ) + imsGroup.POST("/cdr/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewIMSController.CDRExport, + ) } // 网元SMF smfGroup := neDataGroup.Group("/smf") { - // CDR会话事件列表 smfGroup.GET("/cdr/list", middleware.PreAuthorize(nil), controller.NewSMFController.CDRList, ) - // CDR会话删除 smfGroup.DELETE("/cdr/:cdrIds", middleware.PreAuthorize(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewSMFController.CDRRemove, ) + smfGroup.POST("/cdr/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewSMFController.CDRExport, + ) } // 网元AMF amfGroup := neDataGroup.Group("/amf") { - // UE会话事件 amfGroup.GET("/ue/list", middleware.PreAuthorize(nil), controller.NewAMFController.UEList, ) - // UE会话删除 amfGroup.DELETE("/ue/:ueIds", middleware.PreAuthorize(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewAMFController.UERemove, ) + amfGroup.POST("/ue/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewAMFController.UEExport, + ) } // 网元UPF @@ -98,4 +108,130 @@ func Setup(router *gin.Engine) { ) } + // 网元UDM 鉴权用户信息 + udmAuthGroup := neDataGroup.Group("/udm/auth") + { + udmAuthGroup.PUT("/resetData/:neId", + repeat.RepeatSubmit(5), + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)), + controller.NewUDMAuth.ResetData, + ) + udmAuthGroup.GET("/list", + middleware.PreAuthorize(nil), + controller.NewUDMAuth.List, + ) + udmAuthGroup.GET("/:neId/:imsi", + middleware.PreAuthorize(nil), + controller.NewUDMAuth.Info, + ) + udmAuthGroup.POST("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMAuth.Add, + ) + udmAuthGroup.POST("/:neId/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMAuth.Adds, + ) + udmAuthGroup.PUT("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewUDMAuth.Edit, + ) + udmAuthGroup.DELETE("/:neId/:imsi", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMAuth.Remove, + ) + udmAuthGroup.DELETE("/:neId/:imsi/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMAuth.Removes, + ) + udmAuthGroup.POST("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewUDMAuth.Export, + ) + udmAuthGroup.POST("/import", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewUDMAuth.Import, + ) + } + + // 网元UDM 签约用户信息 + udmSubGroup := neDataGroup.Group("/udm/sub") + { + udmSubGroup.PUT("/resetData/:neId", + repeat.RepeatSubmit(5), + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)), + controller.NewUDMSub.ResetData, + ) + udmSubGroup.GET("/list", + middleware.PreAuthorize(nil), + controller.NewUDMSub.List, + ) + udmSubGroup.GET("/:neId/:imsi", + middleware.PreAuthorize(nil), + controller.NewUDMSub.Info, + ) + udmSubGroup.POST("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMSub.Add, + ) + udmSubGroup.POST("/:neId/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMSub.Adds, + ) + udmSubGroup.PUT("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewUDMSub.Edit, + ) + udmSubGroup.DELETE("/:neId/:imsi", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMSub.Remove, + ) + udmSubGroup.DELETE("/:neId/:imsi/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMSub.Removes, + ) + udmSubGroup.POST("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewUDMSub.Export, + ) + udmSubGroup.POST("/import", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewUDMSub.Import, + ) + } + + // 网元MME + mmeGroup := neDataGroup.Group("/mme") + { + mmeGroup.GET("/ue/list", + middleware.PreAuthorize(nil), + controller.NewMMEController.UEList, + ) + mmeGroup.DELETE("/ue/:ueIds", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewMMEController.UERemove, + ) + mmeGroup.POST("/ue/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewMMEController.UEExport, + ) + } } diff --git a/src/modules/network_data/repository/cdr_event.go b/src/modules/network_data/repository/cdr_event.go deleted file mode 100644 index bd5c562..0000000 --- a/src/modules/network_data/repository/cdr_event.go +++ /dev/null @@ -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 -} diff --git a/src/modules/network_data/repository/cdr_event.impl.go b/src/modules/network_data/repository/cdr_event.impl.go deleted file mode 100644 index c9903b8..0000000 --- a/src/modules/network_data/repository/cdr_event.impl.go +++ /dev/null @@ -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 -} diff --git a/src/modules/network_data/repository/cdr_event_ims.go b/src/modules/network_data/repository/cdr_event_ims.go new file mode 100644 index 0000000..fcc9a7b --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_ims.go @@ -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 +} diff --git a/src/modules/network_data/repository/cdr_event_ims.impl.go b/src/modules/network_data/repository/cdr_event_ims.impl.go new file mode 100644 index 0000000..8ab83dd --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_ims.impl.go @@ -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 +} diff --git a/src/modules/network_data/repository/cdr_event_smf.go b/src/modules/network_data/repository/cdr_event_smf.go new file mode 100644 index 0000000..1a950a2 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smf.go @@ -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 +} diff --git a/src/modules/network_data/repository/cdr_event_smf.impl.go b/src/modules/network_data/repository/cdr_event_smf.impl.go new file mode 100644 index 0000000..818f1f2 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smf.impl.go @@ -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 +} diff --git a/src/modules/network_data/repository/perf_kpi.impl.go b/src/modules/network_data/repository/perf_kpi.impl.go index fab63d0..94e2aa2 100644 --- a/src/modules/network_data/repository/perf_kpi.impl.go +++ b/src/modules/network_data/repository/perf_kpi.impl.go @@ -96,19 +96,47 @@ func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) params = append(params, query.RmUID) } if query.NeType != "" { - conditions = append(conditions, "gk.ne_type = ?") - params = append(params, query.NeType) + //conditions = append(conditions, "gk.ne_type = ?") + // params = append(params, query.NeType) tableName += strings.ToLower(query.NeType) } - var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" + + var dateStr1, dateStr2, timeStr1, timeStr2 string if query.StartTime != "" { - conditions = append(conditions, dateTimeStr+" >= ?") - params = append(params, query.StartTime) + dateStr1 = query.StartTime[:10] + timeStr1 = query.StartTime[11:] } if query.EndTime != "" { - conditions = append(conditions, dateTimeStr+" <= ?") - params = append(params, query.EndTime) + dateStr2 = query.EndTime[:10] + timeStr2 = query.EndTime[11:] } + if dateStr1 == dateStr2 && dateStr1 != "" { + conditions = append(conditions, "gk.`date` = ?") + params = append(params, dateStr1) + conditions = append(conditions, "gk.`start_time` >= ?") + params = append(params, timeStr1) + conditions = append(conditions, "gk.`start_time` <= ?") + params = append(params, timeStr2) + } else { + if dateStr1 != "" { + conditions = append(conditions, "(gk.`date` > ? OR (gk.`date` = ? AND gk.`start_time` >= ?))") + params = append(params, dateStr1, dateStr1, timeStr1) + } + if dateStr2 != "" { + conditions = append(conditions, "(gk.`date` < ? OR (gk.`date` = ? AND gk.`start_time` <= ?))") + params = append(params, dateStr2, dateStr2, timeStr2) + } + } + + // var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" + // if query.StartTime != "" { + // conditions = append(conditions, dateTimeStr+" >= ?") + // params = append(params, query.StartTime) + // } + // if query.EndTime != "" { + // conditions = append(conditions, dateTimeStr+" <= ?") + // params = append(params, query.EndTime) + // } // 构建查询条件语句 whereSql := "" if len(conditions) > 0 { @@ -116,6 +144,7 @@ func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) } // 查询字段列 + var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" timeFormat := "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:%i:')" secondGroup := fmt.Sprintf("LPAD(FLOOR(SECOND(gk.start_time) / %d) * %d, 2, '0')", query.Interval, query.Interval) groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, secondGroup) diff --git a/src/modules/network_data/repository/udm_auth.go b/src/modules/network_data/repository/udm_auth.go new file mode 100644 index 0000000..90a3bea --- /dev/null +++ b/src/modules/network_data/repository/udm_auth.go @@ -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 +} diff --git a/src/modules/network_element/repository/udm_auth.impl.go b/src/modules/network_data/repository/udm_auth.impl.go similarity index 80% rename from src/modules/network_element/repository/udm_auth.impl.go rename to src/modules/network_data/repository/udm_auth.impl.go index 682ab8c..5fee2f0 100644 --- a/src/modules/network_element/repository/udm_auth.impl.go +++ b/src/modules/network_data/repository/udm_auth.impl.go @@ -1,13 +1,14 @@ package repository import ( + "fmt" "strings" "be.ems/src/framework/datasource" "be.ems/src/framework/logger" "be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/repo" - "be.ems/src/modules/network_element/model" + "be.ems/src/modules/network_data/model" ) // 实例化数据层 UDMAuthImpl 结构体 @@ -16,13 +17,13 @@ var NewUDMAuthImpl = &UDMAuthImpl{ resultMap: map[string]string{ "id": "ID", - "imsi": "Imsi", + "imsi": "IMSI", "amf": "Amf", "status": "Status", "ki": "Ki", "algo_index": "AlgoIndex", "opc": "Opc", - "ne_id": "NeID", + "ne_id": "NeId", }, } @@ -50,14 +51,13 @@ func (r *UDMAuthImpl) convertResultRows(rows []map[string]any) []model.UDMAuth { } // ClearAndInsert 清空ne_id后新增实体 -func (r *UDMAuthImpl) ClearAndInsert(neID string, authArr []model.UDMAuth) int64 { - // 清空指定ne_id +func (r *UDMAuthImpl) ClearAndInsert(neId string, uArr []model.UDMAuth) int64 { + // 不指定neID时,用 TRUNCATE 清空表快 _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) if err != nil { logger.Errorf("TRUNCATE err => %v", err) } - - return r.Inserts(authArr) + return r.Inserts(uArr) } // SelectPage 根据条件分页查询 @@ -106,11 +106,9 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { params = append(params, pageSize) // 排序 - sortSql := "" + orderSql := "" if v, ok := query["sortField"]; ok && v != "" { - if v == "imsi" { - sortSql += " order by imsi " - } + sortSql := v.(string) if o, ok := query["sortOrder"]; ok && o != nil && v != "" { if o == "desc" { sortSql += " desc " @@ -118,10 +116,11 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { sortSql += " asc " } } + orderSql = fmt.Sprintf(" order by %s ", sortSql) } // 查询数据 - querySql := r.selectSql + whereSql + sortSql + pageSql + querySql := r.selectSql + whereSql + orderSql + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) @@ -133,17 +132,17 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { } // SelectList 根据实体查询 -func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth { +func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth { // 查询条件拼接 var conditions []string var params []any - if auth.Imsi != "" { + if u.IMSI != "" { conditions = append(conditions, "imsi = ?") - params = append(params, auth.Imsi) + params = append(params, u.IMSI) } - if auth.NeID != "" { + if u.NeId != "" { conditions = append(conditions, "ne_id = ?") - params = append(params, auth.NeID) + params = append(params, u.NeId) } // 构建查询条件语句 @@ -164,8 +163,8 @@ func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth { } // Insert 批量添加 -func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 { - tx := datasource.DefaultDB().CreateInBatches(authUsers, 3000) +func (r *UDMAuthImpl) Inserts(uArr []model.UDMAuth) int64 { + tx := datasource.DefaultDB().CreateInBatches(uArr, 3000) if err := tx.Error; err != nil { logger.Errorf("CreateInBatches err => %v", err) } @@ -173,19 +172,19 @@ func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 { } // Delete 删除实体 -func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) +func (r *UDMAuthImpl) Delete(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{}) if err := tx.Error; err != nil { logger.Errorf("Delete err => %v", err) } return tx.RowsAffected } -// DeletePrefixImsi 删除前缀匹配的实体 -func (r *UDMAuthImpl) DeletePrefixImsi(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) +// DeletePrefixByIMSI 删除前缀匹配的实体 +func (r *UDMAuthImpl) DeletePrefixByIMSI(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{}) if err := tx.Error; err != nil { - logger.Errorf("DeletePrefixImsi err => %v", err) + logger.Errorf("DeletePrefixByIMSI err => %v", err) } return tx.RowsAffected } diff --git a/src/modules/network_data/repository/udm_sub.go b/src/modules/network_data/repository/udm_sub.go new file mode 100644 index 0000000..db8db0f --- /dev/null +++ b/src/modules/network_data/repository/udm_sub.go @@ -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 +} diff --git a/src/modules/network_element/repository/udm_sub.impl.go b/src/modules/network_data/repository/udm_sub.impl.go similarity index 58% rename from src/modules/network_element/repository/udm_sub.impl.go rename to src/modules/network_data/repository/udm_sub.impl.go index 9a1dc91..c5ddda8 100644 --- a/src/modules/network_element/repository/udm_sub.impl.go +++ b/src/modules/network_data/repository/udm_sub.impl.go @@ -1,14 +1,14 @@ package repository import ( - "strconv" + "fmt" "strings" "be.ems/src/framework/datasource" "be.ems/src/framework/logger" "be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/repo" - "be.ems/src/modules/network_element/model" + "be.ems/src/modules/network_data/model" ) // 实例化数据层 UDMSubImpl 结构体 @@ -20,7 +20,7 @@ var NewUDMSubImpl = &UDMSubImpl{ resultMap: map[string]string{ "id": "ID", "msisdn": "Msisdn", - "imsi": "Imsi", + "imsi": "IMSI", "ambr": "Ambr", "nssai": "Nssai", "rat": "Rat", @@ -30,7 +30,7 @@ var NewUDMSubImpl = &UDMSubImpl{ "sm_data": "SmData", "smf_sel": "SmfSel", "eps_dat": "EpsDat", - "ne_id": "NeID", + "ne_id": "NeId", "eps_flag": "EpsFlag", "eps_odb": "EpsOdb", "hplmn_odb": "HplmnOdb", @@ -66,14 +66,14 @@ func (r *UDMSubImpl) convertResultRows(rows []map[string]any) []model.UDMSub { } // ClearAndInsert 清空ne_id后新增实体 -func (r *UDMSubImpl) ClearAndInsert(neID string, subArr []model.UDMSub) int64 { - // 清空指定ne_id +func (r *UDMSubImpl) ClearAndInsert(neID string, u []model.UDMSub) int64 { + // 不指定neID时,用 TRUNCATE 清空表快 _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) if err != nil { logger.Errorf("TRUNCATE err => %v", err) } - return r.Inserts(subArr) + return r.Inserts(u) } // SelectPage 根据条件分页查询字典类型 @@ -126,14 +126,9 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { params = append(params, pageSize) // 排序 - sortSql := "" + orderSql := "" if v, ok := query["sortField"]; ok && v != "" { - if v == "imsi" { - sortSql += " order by imsi " - } - if v == "msisdn" { - sortSql += " order by msisdn " - } + sortSql := v.(string) if o, ok := query["sortOrder"]; ok && o != nil && v != "" { if o == "desc" { sortSql += " desc " @@ -141,10 +136,11 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { sortSql += " asc " } } + orderSql = fmt.Sprintf(" order by %s ", sortSql) } // 查询数据 - querySql := r.selectSql + whereSql + sortSql + pageSql + querySql := r.selectSql + whereSql + orderSql + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) @@ -157,17 +153,17 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { } // SelectList 根据实体查询 -func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub { +func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub { // 查询条件拼接 var conditions []string var params []any - if subUser.Imsi != "" { + if u.IMSI != "" { conditions = append(conditions, "imsi = ?") - params = append(params, subUser.Imsi) + params = append(params, u.IMSI) } - if subUser.NeID != "" { + if u.NeId != "" { conditions = append(conditions, "ne_id = ?") - params = append(params, subUser.NeID) + params = append(params, u.NeId) } // 构建查询条件语句 @@ -187,126 +183,29 @@ func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub { return r.convertResultRows(results) } -// Insert 新增实体 -func (r *UDMSubImpl) Insert(subUser model.UDMSub) string { - err := datasource.DefaultDB().Create(&subUser).Error - if err != nil { - logger.Errorf("Create err => %v", err) - } - return subUser.ID -} - // Insert 批量添加 -func (r *UDMSubImpl) Inserts(subUser []model.UDMSub) int64 { - tx := datasource.DefaultDB().CreateInBatches(subUser, 2000) +func (r *UDMSubImpl) Inserts(uArr []model.UDMSub) int64 { + tx := datasource.DefaultDB().CreateInBatches(uArr, 2000) if err := tx.Error; err != nil { logger.Errorf("CreateInBatches err => %v", err) } return tx.RowsAffected } -// Update 修改更新 -func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 { - // 查询先 - var user model.UDMSub - err := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).First(&user).Error - if err != nil { - logger.Errorf("Update First err => %v", err) - } - - if user.Msisdn != subUser.Msisdn { - user.Msisdn = subUser.Msisdn - } - if user.Ambr != subUser.Ambr { - user.Ambr = subUser.Ambr - } - if user.Arfb != subUser.Arfb { - user.Arfb = subUser.Arfb - } - if user.Sar != subUser.Sar { - user.Sar = subUser.Sar - } - if user.Rat != subUser.Rat { - user.Rat = subUser.Rat - } - if user.Cn != subUser.Cn { - user.Cn = subUser.Cn - } - if user.SmfSel != subUser.SmfSel { - user.SmfSel = subUser.SmfSel - } - if user.SmData != subUser.SmData { - user.SmData = subUser.SmData - } - if user.EpsDat != subUser.EpsDat { - user.EpsDat = subUser.EpsDat - } - if user.EpsFlag != subUser.EpsFlag { - user.EpsFlag = subUser.EpsFlag - } - if user.EpsDat != subUser.EpsDat { - user.EpsOdb = subUser.EpsOdb - } - if user.HplmnOdb != subUser.HplmnOdb { - user.HplmnOdb = subUser.HplmnOdb - } - if user.Epstpl != subUser.Epstpl { - user.Epstpl = subUser.Epstpl - } - if user.Ard != subUser.Ard { - user.Ard = subUser.Ard - } - if user.ContextId != subUser.ContextId { - user.ContextId = subUser.ContextId - } - if user.ApnContext != subUser.ApnContext { - user.ApnContext = subUser.ApnContext - } - if user.StaticIp != subUser.StaticIp { - user.StaticIp = subUser.StaticIp - } - - tx := datasource.DefaultDB().Save(user) - if err := tx.Error; err != nil { - logger.Errorf("Update Save err => %v", err) - return 0 - } - return tx.RowsAffected -} - // Delete 删除实体 -func (r *UDMSubImpl) Delete(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) +func (r *UDMSubImpl) Delete(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMSub{}) if err := tx.Error; err != nil { logger.Errorf("Delete err => %v", err) } return tx.RowsAffected } -// DeletePrefixImsi 删除前缀匹配的实体 -func (r *UDMSubImpl) DeletePrefixImsi(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) +// DeletePrefixByIMSI 删除前缀匹配的实体 +func (r *UDMSubImpl) DeletePrefixByIMSI(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMSub{}) if err := tx.Error; err != nil { - logger.Errorf("DeletePrefixImsi err => %v", err) - } - return tx.RowsAffected -} - -// Delete 删除范围实体 -func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 { - imsiV, err := strconv.Atoi(imsi) - if err != nil { - return 0 - } - - numV, err := strconv.Atoi(num) - if err != nil { - return 0 - } - - tx := datasource.DefaultDB().Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete(&model.UDMSub{}) - if err := tx.Error; err != nil { - logger.Errorf("Deletes err => %v", err) + logger.Errorf("DeletePrefixByIMSI err => %v", err) } return tx.RowsAffected } diff --git a/src/modules/network_data/repository/ue_event.go b/src/modules/network_data/repository/ue_event_amf.go similarity index 55% rename from src/modules/network_data/repository/ue_event.go rename to src/modules/network_data/repository/ue_event_amf.go index 58b9046..4e053a0 100644 --- a/src/modules/network_data/repository/ue_event.go +++ b/src/modules/network_data/repository/ue_event_amf.go @@ -2,13 +2,13 @@ package repository import "be.ems/src/modules/network_data/model" -// UE会话事件 数据层接口 -type IUEEvent interface { +// UE会话事件AMF 数据层接口 +type IUEEventAMF interface { // SelectPage 根据条件分页查询 - SelectPage(querys model.UEEventQuery) map[string]any + SelectPage(querys model.UEEventAMFQuery) map[string]any // SelectByIds 通过ID查询 - SelectByIds(ueIds []string) []model.UEEvent + SelectByIds(ueIds []string) []model.UEEventAMF // DeleteByIds 批量删除信息 DeleteByIds(ueIds []string) int64 diff --git a/src/modules/network_data/repository/ue_event.impl.go b/src/modules/network_data/repository/ue_event_amf.impl.go similarity index 78% rename from src/modules/network_data/repository/ue_event.impl.go rename to src/modules/network_data/repository/ue_event_amf.impl.go index 8046ffc..b442207 100644 --- a/src/modules/network_data/repository/ue_event.impl.go +++ b/src/modules/network_data/repository/ue_event_amf.impl.go @@ -6,15 +6,14 @@ import ( "be.ems/src/framework/datasource" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/repo" "be.ems/src/modules/network_data/model" ) -// 实例化数据层 UEEventImpl 结构体 -var NewUEEventImpl = &UEEventImpl{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event`, +// 实例化数据层 UEEventAMFImpl 结构体 +var NewUEEventAMFImpl = &UEEventAMFImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_amf`, resultMap: map[string]string{ "id": "ID", @@ -28,8 +27,8 @@ var NewUEEventImpl = &UEEventImpl{ }, } -// UEEventImpl UE会话事件 数据层处理 -type UEEventImpl struct { +// UEEventAMFImpl UE会话事件 数据层处理 +type UEEventAMFImpl struct { // 查询视图对象SQL selectSql string // 结果字段与实体映射 @@ -37,10 +36,10 @@ type UEEventImpl struct { } // convertResultRows 将结果记录转实体结果组 -func (r *UEEventImpl) convertResultRows(rows []map[string]any) []model.UEEvent { - arr := make([]model.UEEvent, 0) +func (r *UEEventAMFImpl) convertResultRows(rows []map[string]any) []model.UEEventAMF { + arr := make([]model.UEEventAMF, 0) for _, row := range rows { - item := model.UEEvent{} + item := model.UEEventAMF{} for key, value := range row { if keyMapper, ok := r.resultMap[key]; ok { repo.SetFieldValue(&item, keyMapper, value) @@ -52,7 +51,7 @@ func (r *UEEventImpl) convertResultRows(rows []map[string]any) []model.UEEvent { } // SelectPage 根据条件分页查询 -func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { +func (r *UEEventAMFImpl) SelectPage(querys model.UEEventAMFQuery) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -66,17 +65,17 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { } if querys.StartTime != "" { conditions = append(conditions, "timestamp >= ?") - beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS) - params = append(params, beginDate.Unix()) + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) } if querys.EndTime != "" { conditions = append(conditions, "timestamp <= ?") - endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS) - params = append(params, endDate.Unix()) - } - if querys.IMSI != "" { - conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?") - params = append(params, querys.IMSI) + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) } if querys.EventType != "" { eventTypes := strings.Split(querys.EventType, ",") @@ -86,6 +85,10 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { params = append(params, eventType) } } + if querys.IMSI != "" { + conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?") + params = append(params, querys.IMSI) + } // 构建查询条件语句 whereSql := "" @@ -95,11 +98,11 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { result := map[string]any{ "total": 0, - "rows": []model.CDREvent{}, + "rows": []model.UEEventAMF{}, } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from ue_event" + totalSql := "select count(1) as 'total' from ue_event_amf" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -145,23 +148,23 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { } // SelectByIds 通过ID查询 -func (r *UEEventImpl) SelectByIds(ueIds []string) []model.UEEvent { +func (r *UEEventAMFImpl) SelectByIds(ueIds []string) []model.UEEventAMF { placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) querySql := r.selectSql + " where id in (" + placeholder + ")" parameters := repo.ConvertIdsSlice(ueIds) results, err := datasource.RawDB("", querySql, parameters) if err != nil { logger.Errorf("query err => %v", err) - return []model.UEEvent{} + return []model.UEEventAMF{} } // 转换实体 return r.convertResultRows(results) } // DeleteByIds 批量删除信息 -func (r *UEEventImpl) DeleteByIds(ueIds []string) int64 { +func (r *UEEventAMFImpl) DeleteByIds(ueIds []string) int64 { placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) - sql := "delete from ue_event where id in (" + placeholder + ")" + sql := "delete from ue_event_amf where id in (" + placeholder + ")" parameters := repo.ConvertIdsSlice(ueIds) results, err := datasource.ExecDB("", sql, parameters) if err != nil { diff --git a/src/modules/network_data/repository/ue_event_mme.go b/src/modules/network_data/repository/ue_event_mme.go new file mode 100644 index 0000000..7a77fb1 --- /dev/null +++ b/src/modules/network_data/repository/ue_event_mme.go @@ -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 +} diff --git a/src/modules/network_data/repository/ue_event_mme.impl.go b/src/modules/network_data/repository/ue_event_mme.impl.go new file mode 100644 index 0000000..180bc9d --- /dev/null +++ b/src/modules/network_data/repository/ue_event_mme.impl.go @@ -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 +} diff --git a/src/modules/network_data/service/cdr_event.go b/src/modules/network_data/service/cdr_event.go deleted file mode 100644 index b05234c..0000000 --- a/src/modules/network_data/service/cdr_event.go +++ /dev/null @@ -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) -} diff --git a/src/modules/network_data/service/cdr_event.impl.go b/src/modules/network_data/service/cdr_event.impl.go deleted file mode 100644 index fef4a13..0000000 --- a/src/modules/network_data/service/cdr_event.impl.go +++ /dev/null @@ -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") -} diff --git a/src/modules/network_data/service/cdr_event_ims.go b/src/modules/network_data/service/cdr_event_ims.go new file mode 100644 index 0000000..2f5be53 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_ims.go @@ -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) +} diff --git a/src/modules/network_data/service/cdr_event_ims.impl.go b/src/modules/network_data/service/cdr_event_ims.impl.go new file mode 100644 index 0000000..15dfbd8 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_ims.impl.go @@ -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") +} diff --git a/src/modules/network_data/service/cdr_event_smf.go b/src/modules/network_data/service/cdr_event_smf.go new file mode 100644 index 0000000..1e55a69 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smf.go @@ -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) +} diff --git a/src/modules/network_data/service/cdr_event_smf.impl.go b/src/modules/network_data/service/cdr_event_smf.impl.go new file mode 100644 index 0000000..09d2e48 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smf.impl.go @@ -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") +} diff --git a/src/modules/network_data/service/udm_auth.go b/src/modules/network_data/service/udm_auth.go new file mode 100644 index 0000000..6e2b14e --- /dev/null +++ b/src/modules/network_data/service/udm_auth.go @@ -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长度15,ki长度32,opc长度0或者32 + Insert(neId string, u model.UDMAuth) int64 + + // InsertData 导入文件数据 dataType目前两种:txt/csv + InsertData(neId, dataType string, data any) int64 + + // Delete 删除单个不重新加载 + Delete(neID, imsi string) int64 + + // LoadData 删除范围后重新加载 num表示imsi后几位 + LoadData(neID, imsi, num string) int64 +} diff --git a/src/modules/network_data/service/udm_auth.impl.go b/src/modules/network_data/service/udm_auth.impl.go new file mode 100644 index 0000000..d7998a1 --- /dev/null +++ b/src/modules/network_data/service/udm_auth.impl.go @@ -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长度15,ki长度32,opc长度0或者32 +func (r *UDMAuthImpl) Insert(neId string, u model.UDMAuth) int64 { + uArr := r.dataByRedis(u.IMSI, neId) + if len(uArr) > 0 { + r.udmAuthRepository.Delete(neId, u.IMSI) + return r.udmAuthRepository.Inserts(uArr) + } + return 0 +} + +// InsertData 导入文件数据 dataType目前两种:txt/csv +func (r *UDMAuthImpl) InsertData(neId, dataType string, data any) int64 { + // imsi截取前缀,重新获取部分数据 + prefixes := make(map[string]struct{}) + + if dataType == "csv" { + for _, v := range data.([]map[string]string) { + imsi := v["imsi"] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + if dataType == "txt" { + for _, v := range data.([][]string) { + imsi := v[0] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + + // 根据前缀重新加载插入 + var num int64 = 0 + for prefix := range prefixes { + // 直接删除前缀的记录 + r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix) + // keys ausf:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + num += r.udmAuthRepository.Inserts(authArr) + } + } + return num +} + +// Delete 删除单个不重新加载 +func (r *UDMAuthImpl) Delete(neId, imsi string) int64 { + return r.udmAuthRepository.Delete(neId, imsi) +} + +// LoadData 删除范围后重新加载 num表示imsi后几位 +func (r *UDMAuthImpl) LoadData(neId, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)-1] + // 直接删除前缀的记录 + delNum := r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix) + // keys ausf:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + return r.udmAuthRepository.Inserts(authArr) + } + return delNum +} diff --git a/src/modules/network_data/service/udm_sub.go b/src/modules/network_data/service/udm_sub.go new file mode 100644 index 0000000..cb03afe --- /dev/null +++ b/src/modules/network_data/service/udm_sub.go @@ -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长度15,ki长度32,opc长度0或者32 + Insert(neId string, u model.UDMSub) int64 + + // InsertData 导入文件数据 dataType目前两种:txt/csv + InsertData(neId, dataType string, data any) int64 + + // Delete 删除单个不重新加载 + Delete(neId, imsi string) int64 + + // LoadData 删除范围后重新加载 num表示imsi后几位 + LoadData(neId, imsi, num string) int64 +} diff --git a/src/modules/network_data/service/udm_sub.impl.go b/src/modules/network_data/service/udm_sub.impl.go new file mode 100644 index 0000000..768e48a --- /dev/null +++ b/src/modules/network_data/service/udm_sub.impl.go @@ -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长度15,ki长度32,opc长度0或者32 +func (r *UDMSubImpl) Insert(neId string, u model.UDMSub) int64 { + uArr := r.dataByRedis(u.IMSI, neId) + if len(uArr) > 0 { + r.udmSubRepository.Delete(neId, u.IMSI) + return r.udmSubRepository.Inserts(uArr) + } + return 0 +} + +// InsertData 导入文件数据 dataType目前两种:txt/csv +func (r *UDMSubImpl) InsertData(neId, dataType string, data any) int64 { + // imsi截取前缀,重新获取部分数据 + prefixes := make(map[string]struct{}) + + if dataType == "csv" { + for _, v := range data.([]map[string]string) { + imsi := v["imsi"] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + if dataType == "txt" { + for _, v := range data.([][]string) { + imsi := v[0] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + + // 根据前缀重新加载插入 + var num int64 = 0 + for prefix := range prefixes { + // 直接删除前缀的记录 + r.udmSubRepository.DeletePrefixByIMSI(neId, prefix) + // keys udm-sd:4600001000004* + subArr := r.dataByRedis(prefix+"*", neId) + if len(subArr) > 0 { + num += r.udmSubRepository.Inserts(subArr) + } + } + return num +} + +// Delete 删除单个不重新加载 +func (r *UDMSubImpl) Delete(neId, imsi string) int64 { + return r.udmSubRepository.Delete(neId, imsi) +} + +// LoadData 删除范围后重新加载 num表示imsi后几位 +func (r *UDMSubImpl) LoadData(neId, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)-1] + // 直接删除前缀的记录 + delNum := r.udmSubRepository.DeletePrefixByIMSI(neId, prefix) + // keys udm-sd:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + return r.udmSubRepository.Inserts(authArr) + } + return delNum +} diff --git a/src/modules/network_data/service/ue_event.go b/src/modules/network_data/service/ue_event_amf.go similarity index 60% rename from src/modules/network_data/service/ue_event.go rename to src/modules/network_data/service/ue_event_amf.go index 367bb24..e5f77a6 100644 --- a/src/modules/network_data/service/ue_event.go +++ b/src/modules/network_data/service/ue_event_amf.go @@ -2,10 +2,10 @@ package service import "be.ems/src/modules/network_data/model" -// UE会话事件 服务层接口 -type IUEEvent interface { +// UE会话事件AMF 服务层接口 +type IUEEventAMF interface { // SelectPage 根据条件分页查询 - SelectPage(querys model.UEEventQuery) map[string]any + SelectPage(querys model.UEEventAMFQuery) map[string]any // DeleteByIds 批量删除信息 DeleteByIds(ueIds []string) (int64, error) diff --git a/src/modules/network_data/service/ue_event.impl.go b/src/modules/network_data/service/ue_event_amf.impl.go similarity index 58% rename from src/modules/network_data/service/ue_event.impl.go rename to src/modules/network_data/service/ue_event_amf.impl.go index 16f7e07..8d5f61c 100644 --- a/src/modules/network_data/service/ue_event.impl.go +++ b/src/modules/network_data/service/ue_event_amf.impl.go @@ -7,24 +7,24 @@ import ( "be.ems/src/modules/network_data/repository" ) -// 实例化数据层 UEEventImpl 结构体 -var NewUEEventImpl = &UEEventImpl{ - ueEventRepository: repository.NewUEEventImpl, +// 实例化数据层 UEEventMMEImpl 结构体 +var NewUEEventMMEImpl = &UEEventMMEImpl{ + ueEventRepository: repository.NewUEEventMMEImpl, } -// UEEventImpl UE会话事件 服务层处理 -type UEEventImpl struct { +// UEEventMMEImpl UE会话事件MME 服务层处理 +type UEEventMMEImpl struct { // UE会话事件数据信息 - ueEventRepository repository.IUEEvent + ueEventRepository repository.IUEEventMME } // SelectPage 根据条件分页查询 -func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { +func (r *UEEventMMEImpl) SelectPage(querys model.UEEventMMEQuery) map[string]any { return r.ueEventRepository.SelectPage(querys) } // DeleteByIds 批量删除信息 -func (r *UEEventImpl) DeleteByIds(ueIds []string) (int64, error) { +func (r *UEEventMMEImpl) DeleteByIds(ueIds []string) (int64, error) { // 检查是否存在 ids := r.ueEventRepository.SelectByIds(ueIds) if len(ids) <= 0 { diff --git a/src/modules/network_data/service/ue_event_mme.go b/src/modules/network_data/service/ue_event_mme.go new file mode 100644 index 0000000..d4b5dd8 --- /dev/null +++ b/src/modules/network_data/service/ue_event_mme.go @@ -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) +} diff --git a/src/modules/network_data/service/ue_event_mme.impl.go b/src/modules/network_data/service/ue_event_mme.impl.go new file mode 100644 index 0000000..9c7e071 --- /dev/null +++ b/src/modules/network_data/service/ue_event_mme.impl.go @@ -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") +} diff --git a/src/modules/network_element/controller/ne_action.go b/src/modules/network_element/controller/action.go similarity index 75% rename from src/modules/network_element/controller/ne_action.go rename to src/modules/network_element/controller/action.go index f38e68a..4d59735 100644 --- a/src/modules/network_element/controller/ne_action.go +++ b/src/modules/network_element/controller/action.go @@ -3,6 +3,7 @@ package controller import ( "fmt" "path/filepath" + "runtime" "strings" "be.ems/src/framework/i18n" @@ -50,19 +51,30 @@ func (s *NeActionController) PushFile(c *gin.Context) { return } - // 本地文件 - localPath := file.ParseUploadFilePath(body.UploadPath) - nePath := "/tmp" //config.Get("mml.upload").(string) - // 复制到远程 - err := ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() + + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg(fmt.Sprintf("%s : please check if scp remote copy is allowed", neInfo.NeType))) + return + } - // 网元端文件路径 - fileName := localPath[strings.LastIndex(localPath, "/")+1:] - neFilePath := fmt.Sprintf("%s/%s", nePath, fileName) c.JSON(200, result.OkData(filepath.ToSlash(neFilePath))) } @@ -89,14 +101,32 @@ func (s *NeActionController) PullFile(c *gin.Context) { return } - nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName) - localPath := fmt.Sprintf("/tmp/omc/pullFile/%s", querys.FileName) - err := ssh.FileSCPNeToLocal(neInfo.IP, nePath, localPath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } - c.FileAttachment(localPath, querys.FileName) + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() + + nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName) + localFilePath := fmt.Sprintf("/tmp/omc/pullFile%s", nePath) + if runtime.GOOS == "windows" { + localFilePath = fmt.Sprintf("C:%s", localFilePath) + } + // 复制到本地 + if err = sftpClient.CopyFileRemoteToLocal(nePath, localFilePath); err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.FileAttachment(localFilePath, querys.FileName) } // 网元端文件列表 @@ -124,7 +154,16 @@ func (s *NeActionController) Files(c *gin.Context) { return } - totalSize, rows, err := ssh.FileList(querys.Path, neInfo.IP, querys.Search) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sshClient.Close() + + // 获取文件列表 + totalSize, rows, err := ssh.FileList(sshClient, querys.Path, querys.Search) if err != nil { c.JSON(200, result.Ok(map[string]any{ "path": querys.Path, @@ -184,7 +223,7 @@ func (s *NeActionController) Service(c *gin.Context) { cmdStr = fmt.Sprintf("nohup sh -c \"sudo systemctl stop restagent && sleep 5s && sudo systemctl %s restagent\" > /dev/null 2>&1 &", body.Action) } else if neTypeLower == "ims" { if body.Action == "restart" { - cmdStr = "sudo ims-stop || true && sudo ims-start" + cmdStr = "ims-stop || true && ims-start" } else { cmdStr = fmt.Sprintf("sudo ims-%s", body.Action) } @@ -197,7 +236,7 @@ func (s *NeActionController) Service(c *gin.Context) { cmdStr = "sudo shutdown -h now" } - _, err := s.neInfoService.NeRunCMD(body.NeType, body.NeID, cmdStr) + _, err := s.neInfoService.NeRunSSHCmd(body.NeType, body.NeID, cmdStr) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return diff --git a/src/modules/network_element/controller/ne_config.go b/src/modules/network_element/controller/ne_config.go new file mode 100644 index 0000000..9c804ae --- /dev/null +++ b/src/modules/network_element/controller/ne_config.go @@ -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)) +} diff --git a/src/modules/network_element/controller/ne_host.go b/src/modules/network_element/controller/ne_host.go index 9336733..5768574 100644 --- a/src/modules/network_element/controller/ne_host.go +++ b/src/modules/network_element/controller/ne_host.go @@ -203,6 +203,7 @@ func (s *NeHostController) Test(c *gin.Context) { return } defer client.Close() + // 是否有终止符 if strings.HasSuffix(client.LastResult, ">") || strings.HasSuffix(client.LastResult, "> ") || strings.HasSuffix(client.LastResult, "# ") { c.JSON(200, result.Ok(nil)) } else { diff --git a/src/modules/network_element/controller/ne_info.go b/src/modules/network_element/controller/ne_info.go index 177a19b..ea0ded6 100644 --- a/src/modules/network_element/controller/ne_info.go +++ b/src/modules/network_element/controller/ne_info.go @@ -9,6 +9,7 @@ import ( "be.ems/src/framework/utils/ctx" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo/result" + neFetchlink "be.ems/src/modules/network_element/fetch_link" "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -60,7 +61,7 @@ func (s *NeInfoController) State(c *gin.Context) { neKey := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) // 网元直连 - resData, err := neService.NeState(neInfo) + resData, err := neFetchlink.NeState(neInfo) if err != nil { mutex.Lock() // 异常取上次缓存 @@ -287,12 +288,12 @@ func (s *NeInfoController) Add(c *gin.Context) { } // 获取网元状态是否正常 - body.ServerState, err = neService.NeState(body) + body.ServerState, err = neFetchlink.NeState(body) if err != nil { body.Status = "0" } else { // 下发网管配置信息给网元 - _, err = neService.NeConfigOMC(body) + _, err = neFetchlink.NeConfigOMC(body) if err == nil { body.Status = "1" } else { @@ -376,12 +377,12 @@ func (s *NeInfoController) Edit(c *gin.Context) { } // 获取网元状态是否正常 - body.ServerState, err = neService.NeState(body) + body.ServerState, err = neFetchlink.NeState(body) if err != nil { body.Status = "0" } else { // 下发网管配置信息给网元 - _, err = neService.NeConfigOMC(body) + _, err = neFetchlink.NeConfigOMC(body) if err == nil { body.Status = "1" } else { diff --git a/src/modules/network_element/controller/ne_license.go b/src/modules/network_element/controller/ne_license.go index d503b8d..3b4dd4c 100644 --- a/src/modules/network_element/controller/ne_license.go +++ b/src/modules/network_element/controller/ne_license.go @@ -6,6 +6,7 @@ import ( "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" "be.ems/src/framework/vo/result" + neFetchlink "be.ems/src/modules/network_element/fetch_link" "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -18,17 +19,17 @@ var NewNeLicense = &NeLicenseController{ neInfoService: neService.NewNeInfoImpl, } -// 网元授权激活信息请求 +// 网元授权激活请求 // // PATH /license type NeLicenseController struct { - // 网元授权激活信息服务 + // 网元授权激活服务 neLicenseService neService.INeLicense // 网元信息服务 neInfoService neService.INeInfo } -// 网元授权激活信息列表 +// 网元授权激活列表 // // GET /list func (s *NeLicenseController) List(c *gin.Context) { @@ -198,7 +199,7 @@ func (s *NeLicenseController) State(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - if neState, err := neService.NeState(neInfo); err == nil { + if neState, err := neFetchlink.NeState(neInfo); err == nil && neState["sn"] != nil { neLicense.Status = "1" neLicense.SerialNum = fmt.Sprint(neState["sn"]) neLicense.ExpiryDate = fmt.Sprint(neState["expire"]) diff --git a/src/modules/network_element/controller/ne_software.go b/src/modules/network_element/controller/ne_software.go index d5658d7..fb15beb 100644 --- a/src/modules/network_element/controller/ne_software.go +++ b/src/modules/network_element/controller/ne_software.go @@ -18,15 +18,15 @@ var NewNeSoftware = &NeSoftwareController{ neSoftwareService: neService.NewNeSoftwareImpl, } -// 网元软件包信息请求 +// 网元软件包请求 // // PATH /software type NeSoftwareController struct { - // 网元软件包信息服务 + // 网元软件包服务 neSoftwareService neService.INeSoftware } -// 网元软件包信息列表 +// 网元软件包列表 // // GET /list func (s *NeSoftwareController) List(c *gin.Context) { @@ -36,7 +36,7 @@ func (s *NeSoftwareController) List(c *gin.Context) { c.JSON(200, result.Ok(data)) } -// 网元软件包信息信息 +// 网元软件包信息 // // GET /:softwareId func (s *NeSoftwareController) Info(c *gin.Context) { @@ -57,7 +57,7 @@ func (s *NeSoftwareController) Info(c *gin.Context) { c.JSON(200, result.OkData(neSoftware)) } -// 网元软件包信息新增 +// 网元软件包新增 // // POST / func (s *NeSoftwareController) Add(c *gin.Context) { @@ -98,7 +98,7 @@ func (s *NeSoftwareController) Add(c *gin.Context) { c.JSON(200, result.Err(nil)) } -// 网元软件包信息修改 +// 网元软件包修改 // // PUT / func (s *NeSoftwareController) Edit(c *gin.Context) { @@ -136,7 +136,7 @@ func (s *NeSoftwareController) Edit(c *gin.Context) { c.JSON(200, result.Err(nil)) } -// 网元软件包信息删除 +// 网元软件包删除 // // DELETE /:softwareIds func (s *NeSoftwareController) Remove(c *gin.Context) { diff --git a/src/modules/network_element/controller/ne_version.go b/src/modules/network_element/controller/ne_version.go index 94bc2d8..8df9b01 100644 --- a/src/modules/network_element/controller/ne_version.go +++ b/src/modules/network_element/controller/ne_version.go @@ -14,15 +14,15 @@ var NewNeVersion = &NeVersionController{ neVersionService: neService.NewNeVersionImpl, } -// 网元版本信息请求 +// 网元版本请求 // // PATH /version type NeVersionController struct { - // 网元版本信息服务 + // 网元版本服务 neVersionService neService.INeVersion } -// 网元版本信息列表 +// 网元版本列表 // // GET /list func (s *NeVersionController) List(c *gin.Context) { @@ -32,7 +32,7 @@ func (s *NeVersionController) List(c *gin.Context) { c.JSON(200, result.Ok(data)) } -// 网元版本信息信息 +// 网元版本信息 // // GET /:versionId func (s *NeVersionController) Info(c *gin.Context) { diff --git a/src/modules/network_element/service/ne_direct_link.go b/src/modules/network_element/fetch_link/ne_config.go similarity index 65% rename from src/modules/network_element/service/ne_direct_link.go rename to src/modules/network_element/fetch_link/ne_config.go index 7d5afaf..cb93a2b 100644 --- a/src/modules/network_element/service/ne_direct_link.go +++ b/src/modules/network_element/fetch_link/ne_config.go @@ -1,50 +1,15 @@ -package service +package fetchlink import ( "encoding/json" "fmt" "strings" - "time" "be.ems/src/framework/logger" "be.ems/src/framework/utils/fetch" "be.ems/src/modules/network_element/model" ) -// NeState 获取网元端服务状态 -func NeState(neInfo model.NeInfo) (map[string]any, error) { - // 网元状态 - neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType)) - resBytes, err := fetch.Get(neUrl, nil, 1000) - if err != nil { - logger.Warnf("NeState %s", err.Error()) - return nil, err - } - - // 序列化结果 - var resData map[string]any - err = json.Unmarshal(resBytes, &resData) - if err != nil { - logger.Warnf("NeState Unmarshal %s", err.Error()) - return nil, err - } - - return map[string]any{ - "neType": neInfo.NeType, - "neId": neInfo.NeId, - "neName": neInfo.NeName, - "neIP": neInfo.IP, - "refreshTime": time.Now().UnixMilli(), // 获取时间 - "version": resData["version"], - "capability": resData["capability"], - "sn": resData["serialNum"], - "expire": resData["expiryDate"], - "cpu": resData["cpuUsage"], - "mem": resData["memUsage"], - "disk": resData["diskSpace"], - }, nil -} - // NeConfigOMC 网元配置对端网管信息 func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) { // 网元配置对端网管信息 @@ -83,3 +48,23 @@ func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) { return resData, nil } + +// NeConfigInfo 网元配置信息 +func NeConfigInfo(neInfo model.NeInfo, name string) (map[string]any, error) { + // 网元配置对端网管信息 + neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType), name) + resBytes, err := fetch.Get(neUrl, nil, 1000) + if err != nil { + logger.Warnf("NeConfigInfo %s Get \"%s\"", err.Error(), neUrl) + return nil, err + } + + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Warnf("NeConfigInfo Unmarshal %s", err.Error()) + return nil, err + } + return resData, nil +} diff --git a/src/modules/network_element/fetch_link/ne_state.go b/src/modules/network_element/fetch_link/ne_state.go new file mode 100644 index 0000000..4ed27aa --- /dev/null +++ b/src/modules/network_element/fetch_link/ne_state.go @@ -0,0 +1,56 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/fetch" + "be.ems/src/modules/network_element/model" +) + +// NeState 获取网元端服务状态 +func NeState(neInfo model.NeInfo) (map[string]any, error) { + // 网元状态 + neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType)) + resBytes, err := fetch.Get(neUrl, nil, 1000) + if err != nil { + logger.Warnf("NeState %s", err.Error()) + return nil, err + } + + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Warnf("NeState Unmarshal %s", err.Error()) + return nil, err + } + + // 检查是否有许可时间 + if v, ok := resData["expiryDate"]; ok && v != nil { + expiryDate := v.(string) + // UPF存在2000的许可时间,MME会有空字符 + if strings.HasPrefix(expiryDate, "2000") || expiryDate == "" { + logger.Warnf("NeState %s License Expiration Aanomaly. Get \"%s\"", neInfo.NeType, neUrl) + return nil, fmt.Errorf("%s License Expiration Aanomaly", neInfo.NeType) + } + } + + return map[string]any{ + "neType": neInfo.NeType, + "neId": neInfo.NeId, + "neName": neInfo.NeName, + "neIP": neInfo.IP, + "refreshTime": time.Now().UnixMilli(), // 获取时间 + "version": resData["version"], + "capability": resData["capability"], + "sn": resData["serialNum"], + "expire": resData["expiryDate"], + "cpu": resData["cpuUsage"], + "mem": resData["memUsage"], + "disk": resData["diskSpace"], + }, nil +} diff --git a/src/modules/network_element/model/ne_config.go b/src/modules/network_element/model/ne_config.go new file mode 100644 index 0000000..dcc7e05 --- /dev/null +++ b/src/modules/network_element/model/ne_config.go @@ -0,0 +1,21 @@ +package model + +// NeConfig 网元参数配置可用属性值 +type NeConfig struct { + ID string `json:"id" gorm:"id"` + NeType string `json:"neType" binding:"required" gorm:"ne_type"` // 网元类型 + NeId string `json:"-" gorm:"ne_id"` + TopTag string `json:"topTag" binding:"required" gorm:"top_tag"` + TopDisplay string `json:"topDisplay" binding:"required" gorm:"top_display"` + Method string `json:"method" gorm:"method"` // 操作属性 get只读强制不可编辑删除 put可编辑 delete可删除 post可新增 + ParamJSONStr string `json:"-" gorm:"param_json"` // accesss属性控制:只读read-only/read/ro 读写read-write + + // ====== 非数据库字段属性 ====== + + ParamData map[string]any `json:"paramData,omitempty" binding:"required" gorm:"-"` // 与ParamJSONStr配合转换 +} + +// TableName 表名称 +func (*NeConfig) TableName() string { + return "param_config" +} diff --git a/src/modules/network_element/model/ne_software.go b/src/modules/network_element/model/ne_software.go index 3eaf956..53a5321 100644 --- a/src/modules/network_element/model/ne_software.go +++ b/src/modules/network_element/model/ne_software.go @@ -15,7 +15,6 @@ type NeSoftware struct { // ====== 非数据库字段属性 ====== - NeId string `json:"neId,omitempty" gorm:"-"` // 网元ID } // TableName 表名称 diff --git a/src/modules/network_element/network_element.go b/src/modules/network_element/network_element.go index e44c612..e6a6c61 100644 --- a/src/modules/network_element/network_element.go +++ b/src/modules/network_element/network_element.go @@ -4,7 +4,6 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/middleware" "be.ems/src/framework/middleware/collectlogs" - "be.ems/src/framework/middleware/repeat" "be.ems/src/modules/network_element/controller" "be.ems/src/modules/network_element/service" @@ -258,111 +257,39 @@ func Setup(router *gin.Engine) { ) } - // UDM鉴权用户信息 - udmAuthGroup := neGroup.Group("/udm/auth") + // 网元参数配置 + neConfigGroup := neGroup.Group("/config") { - udmAuthGroup.PUT("/resetData/:neId", - repeat.RepeatSubmit(5), + neConfigGroup.GET("/list", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)), - controller.NewUDMAuth.ResetData, + controller.NewNeConfig.List, ) - udmAuthGroup.GET("/list", + neConfigGroup.GET("/info/:id", middleware.PreAuthorize(nil), - controller.NewUDMAuth.List, + controller.NewNeConfig.Info, ) - udmAuthGroup.GET("/:neId/:imsi", + neConfigGroup.POST("", middleware.PreAuthorize(nil), - controller.NewUDMAuth.Info, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewNeConfig.Add, ) - udmAuthGroup.POST("/:neId", + neConfigGroup.PUT("", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMAuth.Add, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewNeConfig.Edit, ) - udmAuthGroup.POST("/:neId/:num", + neConfigGroup.DELETE("/:ids", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMAuth.Adds, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewNeConfig.Remove, ) - udmAuthGroup.PUT("/:neId", + neConfigGroup.GET("/list/:neType", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)), - controller.NewUDMAuth.Edit, + controller.NewNeConfig.ListByNeType, ) - udmAuthGroup.DELETE("/:neId/:imsi", + neConfigGroup.GET("/data", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMAuth.Remove, - ) - udmAuthGroup.DELETE("/:neId/:imsi/:num", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMAuth.Removes, - ) - udmAuthGroup.POST("/export", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)), - controller.NewUDMAuth.Export, - ) - udmAuthGroup.POST("/import", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)), - controller.NewUDMAuth.Import, - ) - } - - // UDM签约用户信息 - udmSubGroup := neGroup.Group("/udm/sub") - { - udmSubGroup.PUT("/resetData/:neId", - repeat.RepeatSubmit(5), - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)), - controller.NewUDMSub.ResetData, - ) - udmSubGroup.GET("/list", - middleware.PreAuthorize(nil), - controller.NewUDMSub.List, - ) - udmSubGroup.GET("/:neId/:imsi", - middleware.PreAuthorize(nil), - controller.NewUDMSub.Info, - ) - udmSubGroup.POST("/:neId", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMSub.Add, - ) - udmSubGroup.POST("/:neId/:num", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMSub.Adds, - ) - udmSubGroup.PUT("/:neId", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)), - controller.NewUDMSub.Edit, - ) - udmSubGroup.DELETE("/:neId/:imsi", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMSub.Remove, - ) - udmSubGroup.DELETE("/:neId/:imsi/:num", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMSub.Removes, - ) - udmSubGroup.POST("/export", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)), - controller.NewUDMSub.Export, - ) - udmSubGroup.POST("/import", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)), - controller.NewUDMSub.Import, + controller.NewNeConfig.Data, ) } } @@ -376,4 +303,7 @@ func InitLoad() { if para5GMap, err := service.NewNeInfoImpl.NeConfPara5GRead(); para5GMap != nil && err == nil { service.NewNeInfoImpl.NeConfPara5GWirte(para5GMap, nil) } + // 启动时,清除缓存-网元参数配置可用属性值 + service.NewNeConfigImpl.ClearNeCacheByNeType("*") + service.NewNeConfigImpl.RefreshByNeTypeAndNeID("*") } diff --git a/src/modules/network_element/repository/ne_config.go b/src/modules/network_element/repository/ne_config.go new file mode 100644 index 0000000..5f555b3 --- /dev/null +++ b/src/modules/network_element/repository/ne_config.go @@ -0,0 +1,24 @@ +package repository + +import "be.ems/src/modules/network_element/model" + +// INeConfig 网元参数配置可用属性值 数据层接口 +type INeConfig interface { + // SelectPage 根据条件分页查询字典类型 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(param model.NeConfig) []model.NeConfig + + // SelectByIds 通过ID查询 + SelectByIds(ids []string) []model.NeConfig + + // Insert 新增信息 + Insert(param model.NeConfig) string + + // Update 修改信息 + Update(param model.NeConfig) int64 + + // DeleteByIds 批量删除信息 + DeleteByIds(ids []string) int64 +} diff --git a/src/modules/network_element/repository/ne_config.impl.go b/src/modules/network_element/repository/ne_config.impl.go new file mode 100644 index 0000000..8ea0db5 --- /dev/null +++ b/src/modules/network_element/repository/ne_config.impl.go @@ -0,0 +1,254 @@ +package repository + +import ( + "strings" + + "be.ems/src/framework/datasource" + "be.ems/src/framework/logger" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/utils/repo" + "be.ems/src/modules/network_element/model" +) + +// NewNeConfigImpl 网元参数配置可用属性值 实例化数据层 +var NewNeConfigImpl = &NeConfigImpl{ + selectSql: `select + id, ne_type, ne_id, top_tag, top_display, method, param_json + from param_config`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_id": "NeId", + "top_tag": "TopTag", + "top_display": "TopDisplay", + "method": "Method", + "param_json": "ParamJSONStr", + }, +} + +// NeConfigImpl 网元参数配置可用属性值 数据层处理 +type NeConfigImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *NeConfigImpl) convertResultRows(rows []map[string]any) []model.NeConfig { + arr := make([]model.NeConfig, 0) + for _, row := range rows { + item := model.NeConfig{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询字典类型 +func (r *NeConfigImpl) SelectPage(query map[string]any) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if v, ok := query["neType"]; ok && v != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, v) + } + if v, ok := query["topTag"]; ok && v != "" { + conditions = append(conditions, "top_tag = ?") + params = append(params, v) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.NeHost{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(id) as 'total' from param_config" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 查询数据 + querySql := r.selectSql + whereSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + return result + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectList 根据实体查询 +func (r *NeConfigImpl) SelectList(param model.NeConfig) []model.NeConfig { + // 查询条件拼接 + var conditions []string + var params []any + if param.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, param.NeType) + } + if param.TopTag != "" { + conditions = append(conditions, "top_tag = ?") + params = append(params, param.TopTag) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + " order by id asc " + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// SelectByIds 通过ID查询 +func (r *NeConfigImpl) SelectByIds(ids []string) []model.NeConfig { + placeholder := repo.KeyPlaceholderByQuery(len(ids)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(ids) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.NeConfig{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 新增信息 +func (r *NeConfigImpl) Insert(param model.NeConfig) string { + // 参数拼接 + params := make(map[string]any) + if param.NeType != "" { + params["ne_type"] = param.NeType + } + if param.NeId != "" { + params["ne_id"] = param.NeId + } + if param.TopTag != "" { + params["top_tag"] = param.TopTag + } + if param.TopDisplay != "" { + params["top_display"] = param.TopDisplay + } + if param.Method != "" { + params["method"] = param.Method + } + if param.ParamJSONStr != "" { + params["param_json"] = param.ParamJSONStr + } + + // 构建执行语句 + keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) + sql := "insert into param_config (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" + + db := datasource.DefaultDB() + // 开启事务 + tx := db.Begin() + // 执行插入 + err := tx.Exec(sql, values...).Error + if err != nil { + logger.Errorf("insert row : %v", err.Error()) + tx.Rollback() + return "" + } + // 获取生成的自增 ID + var insertedID string + err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID) + if err != nil { + logger.Errorf("insert last id : %v", err.Error()) + tx.Rollback() + return "" + } + // 提交事务 + tx.Commit() + return insertedID +} + +// Update 修改信息 +func (r *NeConfigImpl) Update(param model.NeConfig) int64 { + // 参数拼接 + params := make(map[string]any) + if param.NeType != "" { + params["ne_type"] = param.NeType + } + if param.NeId != "" { + params["ne_id"] = param.NeId + } + if param.TopTag != "" { + params["top_tag"] = param.TopTag + } + if param.TopDisplay != "" { + params["top_display"] = param.TopDisplay + } + if param.Method != "" { + params["method"] = param.Method + } + if param.ParamJSONStr != "" { + params["param_json"] = param.ParamJSONStr + } + + // 构建执行语句 + keys, values := repo.KeyValueByUpdate(params) + sql := "update param_config set " + strings.Join(keys, ",") + " where id = ?" + + // 执行更新 + values = append(values, param.ID) + rows, err := datasource.ExecDB("", sql, values) + if err != nil { + logger.Errorf("update row : %v", err.Error()) + return 0 + } + return rows +} + +// DeleteByIds 批量删除信息 +func (r *NeConfigImpl) DeleteByIds(ids []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(ids)) + sql := "delete from param_config where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(ids) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_element/repository/udm_auth.go b/src/modules/network_element/repository/udm_auth.go deleted file mode 100644 index 2d1d58d..0000000 --- a/src/modules/network_element/repository/udm_auth.go +++ /dev/null @@ -1,26 +0,0 @@ -package repository - -import ( - "be.ems/src/modules/network_element/model" -) - -// UDM鉴权信息 数据层接口 -type IUDMAuth interface { - // ClearAndInsert 清空ne_id后新增实体 - ClearAndInsert(neID string, authArr []model.UDMAuth) int64 - - // SelectPage 根据条件分页查询 - SelectPage(query map[string]any) map[string]any - - // SelectList 根据实体查询 - SelectList(auth model.UDMAuth) []model.UDMAuth - - // Insert 批量添加 - Inserts(authUsers []model.UDMAuth) int64 - - // Delete 删除实体 - Delete(neID, imsi string) int64 - - // DeletePrefixImsi 删除前缀匹配的实体 - DeletePrefixImsi(neID, imsi string) int64 -} diff --git a/src/modules/network_element/repository/udm_sub.go b/src/modules/network_element/repository/udm_sub.go deleted file mode 100644 index 970639e..0000000 --- a/src/modules/network_element/repository/udm_sub.go +++ /dev/null @@ -1,35 +0,0 @@ -package repository - -import ( - "be.ems/src/modules/network_element/model" -) - -// UDM签约信息 数据层接口 -type IUDMSub interface { - // ClearAndInsert 清空ne_id后新增实体 - ClearAndInsert(neID string, subArr []model.UDMSub) int64 - - // SelectPage 根据条件分页查询字典类型 - SelectPage(query map[string]any) map[string]any - - // SelectList 根据实体查询 - SelectList(subUser model.UDMSub) []model.UDMSub - - // Insert 新增实体 - Insert(subUser model.UDMSub) string - - // Insert 批量添加 - Inserts(subUser []model.UDMSub) int64 - - // Update 修改更新 - Update(neID string, subUser model.UDMSub) int64 - - // Delete 删除实体 - Delete(neID, imsi string) int64 - - // DeletePrefixImsi 删除前缀匹配的实体 - DeletePrefixImsi(neID, imsi string) int64 - - // Delete 删除范围实体 - Deletes(neID, imsi, num string) int64 -} diff --git a/src/modules/network_element/service/ne_config.go b/src/modules/network_element/service/ne_config.go new file mode 100644 index 0000000..fff9fe7 --- /dev/null +++ b/src/modules/network_element/service/ne_config.go @@ -0,0 +1,33 @@ +package service + +import "be.ems/src/modules/network_element/model" + +// INeConfig 网元参数配置可用属性值 服务层接口 +type INeConfig interface { + // RefreshByNeType 通过ne_type刷新redis中的缓存 + RefreshByNeTypeAndNeID(neType string) []model.NeConfig + + // ClearNeCacheByNeType 清除网元类型参数配置缓存 + ClearNeCacheByNeType(neType string) bool + + // SelectNeConfigByNeType 查询网元类型参数配置 + SelectNeConfigByNeType(neType string) []model.NeConfig + + // SelectNeHostPage 分页查询列表数据 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(param model.NeConfig) []model.NeConfig + + // SelectByIds 通过ID查询 + SelectById(id string) model.NeConfig + + // Insert 新增信息 + Insert(param model.NeConfig) string + + // Update 修改信息 + Update(param model.NeConfig) int64 + + // DeleteByIds 批量删除信息 + DeleteByIds(ids []string) (int64, error) +} diff --git a/src/modules/network_element/service/ne_config.impl.go b/src/modules/network_element/service/ne_config.impl.go new file mode 100644 index 0000000..6b4a4b8 --- /dev/null +++ b/src/modules/network_element/service/ne_config.impl.go @@ -0,0 +1,151 @@ +package service + +import ( + "encoding/json" + "fmt" + "strings" + + "be.ems/src/framework/constants/cachekey" + "be.ems/src/framework/redis" + "be.ems/src/modules/network_element/model" + "be.ems/src/modules/network_element/repository" +) + +// NewNeConfigImpl 网元参数配置可用属性值 实例化服务层 +var NewNeConfigImpl = &NeConfigImpl{ + neConfigRepository: repository.NewNeConfigImpl, +} + +// NeConfigImpl 网元参数配置可用属性值 服务层处理 +type NeConfigImpl struct { + // 网元参数配置可用属性值表 + neConfigRepository repository.INeConfig +} + +// RefreshByNeType 通过ne_type刷新redis中的缓存 +func (r *NeConfigImpl) RefreshByNeTypeAndNeID(neType string) []model.NeConfig { + // 多个 + if neType == "" || neType == "*" { + neConfigList := r.neConfigRepository.SelectList(model.NeConfig{}) + if len(neConfigList) > 0 { + neConfigGroup := map[string][]model.NeConfig{} + for _, v := range neConfigList { + if item, ok := neConfigGroup[v.NeType]; ok { + neConfigGroup[v.NeType] = append(item, v) + } else { + neConfigGroup[v.NeType] = []model.NeConfig{v} + } + } + for k, v := range neConfigGroup { + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(k)) + redis.Del("", key) + if len(v) > 0 { + for i, item := range v { + if err := json.Unmarshal([]byte(item.ParamJSONStr), &item.ParamData); err != nil { + continue + } + v[i] = item + } + values, _ := json.Marshal(v) + redis.Set("", key, string(values)) + } + } + } + return neConfigList + } + // 单个 + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(neType)) + redis.Del("", key) + neConfigList := r.neConfigRepository.SelectList(model.NeConfig{ + NeType: neType, + }) + if len(neConfigList) > 0 { + for i, v := range neConfigList { + if err := json.Unmarshal([]byte(v.ParamJSONStr), &v.ParamData); err != nil { + continue + } + neConfigList[i] = v + } + values, _ := json.Marshal(neConfigList) + redis.Set("", key, string(values)) + } + return neConfigList +} + +// ClearNeCacheByNeType 清除网元类型参数配置缓存 +func (r *NeConfigImpl) ClearNeCacheByNeType(neType string) bool { + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, neType) + if neType == "*" { + key = fmt.Sprintf("%sparam_config:*", cachekey.NE_DATA_KEY) + } + keys, err := redis.GetKeys("", key) + if err != nil { + return false + } + delOk, _ := redis.DelKeys("", keys) + return delOk +} + +// SelectNeConfigByNeType 查询网元类型参数配置 +func (r *NeConfigImpl) SelectNeConfigByNeType(neType string) []model.NeConfig { + var neConfigList []model.NeConfig + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(neType)) + jsonStr, _ := redis.Get("", key) + if len(jsonStr) > 7 { + err := json.Unmarshal([]byte(jsonStr), &neConfigList) + if err != nil { + neConfigList = []model.NeConfig{} + } + } else { + neConfigList = r.RefreshByNeTypeAndNeID(neType) + } + return neConfigList +} + +// SelectNeHostPage 分页查询列表数据 +func (r *NeConfigImpl) SelectPage(query map[string]any) map[string]any { + return r.neConfigRepository.SelectPage(query) +} + +// SelectConfigList 查询列表 +func (r *NeConfigImpl) SelectList(param model.NeConfig) []model.NeConfig { + return r.neConfigRepository.SelectList(param) +} + +// SelectByIds 通过ID查询 +func (r *NeConfigImpl) SelectById(id string) model.NeConfig { + if id == "" { + return model.NeConfig{} + } + neHosts := r.neConfigRepository.SelectByIds([]string{id}) + if len(neHosts) > 0 { + return neHosts[0] + } + return model.NeConfig{} +} + +// Insert 新增信息 +func (r *NeConfigImpl) Insert(param model.NeConfig) string { + return r.neConfigRepository.Insert(param) +} + +// Update 修改信息 +func (r *NeConfigImpl) Update(param model.NeConfig) int64 { + return r.neConfigRepository.Update(param) +} + +// DeleteByIds 批量删除信息 +func (r *NeConfigImpl) DeleteByIds(ids []string) (int64, error) { + // 检查是否存在 + data := r.neConfigRepository.SelectByIds(ids) + if len(data) <= 0 { + return 0, fmt.Errorf("param.noData") + } + + if len(data) == len(ids) { + rows := r.neConfigRepository.DeleteByIds(ids) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} diff --git a/src/modules/network_element/service/ne_info.go b/src/modules/network_element/service/ne_info.go index 5945fb3..b3e9838 100644 --- a/src/modules/network_element/service/ne_info.go +++ b/src/modules/network_element/service/ne_info.go @@ -2,6 +2,7 @@ package service import ( "be.ems/src/framework/utils/ssh" + "be.ems/src/framework/utils/telnet" "be.ems/src/modules/network_element/model" ) @@ -47,11 +48,15 @@ type INeInfo interface { // CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一 CheckUniqueNeTypeAndNeId(neType, neId, id string) bool - // NeRunSSHclient 网元主机的SSH客户端-为创建相关连接 - NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) + // NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close() + NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) - // NeRunCMD 向网元发送cmd命令 - NeRunCMD(neType, neId, cmd string) (string, error) + // NeRunSSHCmd 网元主机的SSH客户端发送cmd命令 + NeRunSSHCmd(neType, neId, cmd string) (string, error) + + // NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close() + // num 是网元主机telnet 1:4100 2:5200 + NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) // neConfOAMRead 网元OAM配置文件读取 NeConfOAMRead(neType, neId string) (map[string]any, error) diff --git a/src/modules/network_element/service/ne_info.impl.go b/src/modules/network_element/service/ne_info.impl.go index de5b6a8..7b5041c 100644 --- a/src/modules/network_element/service/ne_info.impl.go +++ b/src/modules/network_element/service/ne_info.impl.go @@ -13,6 +13,8 @@ import ( "be.ems/src/framework/redis" "be.ems/src/framework/utils/parse" "be.ems/src/framework/utils/ssh" + "be.ems/src/framework/utils/telnet" + neFetchlink "be.ems/src/modules/network_element/fetch_link" "be.ems/src/modules/network_element/model" "be.ems/src/modules/network_element/repository" ) @@ -148,7 +150,7 @@ func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool, bandHost bool) func (r *NeInfoImpl) bandNeStatus(arr *[]model.NeInfo) { for i := range *arr { v := (*arr)[i] - result, err := NeState(v) + result, err := neFetchlink.NeState(v) if err != nil { (*arr)[i].ServerState = map[string]any{ "online": false, @@ -166,7 +168,7 @@ func (r *NeInfoImpl) bandNeStatus(arr *[]model.NeInfo) { // 网元状态设置为在线 if v.Status != "1" { // 下发网管配置信息给网元 - _, err = NeConfigOMC(v) + _, err = neFetchlink.NeConfigOMC(v) if err == nil { v.Status = "1" } else { @@ -298,26 +300,26 @@ func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, id string) bool { return uniqueId == "" } -// NeRunSSHclient 网元主机的SSH客户端-为创建相关连接 -func (r *NeInfoImpl) NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) { +// NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close() +func (r *NeInfoImpl) NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) { neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId) if neInfo.NeId != neId { - logger.Errorf("NeRunSSHclient NeType:%s NeID:%s not found", neType, neId) + logger.Errorf("NeRunSSHClient NeType:%s NeID:%s not found", neType, neId) return nil, fmt.Errorf("neinfo not found") } // 取主机信息 if neInfo.HostIDs == "" { - logger.Errorf("NeRunSSHclient NeType:%s NeID:%s hostId not found", neType, neId) + logger.Errorf("NeRunSSHClient NeType:%s NeID:%s hostId not found", neType, neId) return nil, fmt.Errorf("neinfo hostId not found") } neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) if len(neInfo.Hosts) <= 0 { - logger.Errorf("NeRunSSHclient Hosts %s not found", neInfo.HostIDs) + logger.Errorf("NeRunSSHClient Hosts %s not found", neInfo.HostIDs) return nil, fmt.Errorf("neinfo host not found") } - neHost := neInfo.Hosts[0] + neHost := neInfo.Hosts[0] // 网元主机ssh 0:22 if neHost.HostType != "ssh" { - logger.Errorf("NeRunSSHclient Hosts first HostType %s not ssh", neHost.HostType) + logger.Errorf("NeRunSSHClient Hosts first HostType %s not ssh", neHost.HostType) return nil, fmt.Errorf("neinfo host type not ssh") } @@ -331,15 +333,15 @@ func (r *NeInfoImpl) NeRunSSHclient(neType, neId string) (*ssh.ConnSSH, error) { client, err = connSSH.NewClient() } if err != nil { - logger.Errorf("NeRunSSHclient NewClient err => %s", err.Error()) + logger.Errorf("NeRunSSHClient NewClient err => %s", err.Error()) return nil, fmt.Errorf("neinfo ssh client new err") } return client, nil } -// NeRunCMD 向网元发送cmd命令 -func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) { - sshClient, err := r.NeRunSSHclient(neType, neId) +// NeRunSSHCmd 网元主机的SSH客户端发送cmd命令 +func (r *NeInfoImpl) NeRunSSHCmd(neType, neId, cmd string) (string, error) { + sshClient, err := r.NeRunSSHClient(neType, neId) if err != nil { return "", err } @@ -348,12 +350,43 @@ func (r *NeInfoImpl) NeRunCMD(neType, neId, cmd string) (string, error) { // 执行命令 output, err := sshClient.RunCMD(cmd) if err != nil { - logger.Errorf("NeRunCMD RunCMD %s err => %s", output, err.Error()) + logger.Errorf("NeRunSSHCmd RunCMD %s err => %s", output, err.Error()) return "", fmt.Errorf("neinfo ssh run cmd err") } return output, nil } +// NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close() +// num 是网元主机telnet 1:4100 2:5200 +func (r *NeInfoImpl) NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) { + neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId) + if neInfo.NeId != neId { + logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s not found", neType, neId) + return nil, fmt.Errorf("neinfo not found") + } + // 取主机信息 + if neInfo.HostIDs == "" { + logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s hostId not found", neType, neId) + return nil, fmt.Errorf("neinfo hostId not found") + } + neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) + if len(neInfo.Hosts) <= 0 { + logger.Errorf("NeRunTelnetClient Hosts %s not found", neInfo.HostIDs) + return nil, fmt.Errorf("neinfo host not found") + } + neHost := neInfo.Hosts[num] + + // 创建链接Telnet客户端 + var connTelnet telnet.ConnTelnet + neHost.CopyTo(&connTelnet) + telnetClient, err := connTelnet.NewClient() + if err != nil { + logger.Errorf("NeRunTelnetClient NewClient err => %s", err.Error()) + return nil, fmt.Errorf("neinfo telnet client new err") + } + return telnetClient, nil +} + // neConfOAMData 网元OAM配置文件默认格式数据 func (r *NeInfoImpl) neConfOAMData() map[string]any { return map[string]any{ @@ -447,7 +480,7 @@ func (r *NeInfoImpl) neConfOAMWirte(neType, neId string, content any, sync bool) // 同步到网元端 if sync { // 网元主机的SSH客户端 - sshClient, err := r.NeRunSSHclient(neType, neId) + sshClient, err := r.NeRunSSHClient(neType, neId) if err != nil { return err } @@ -609,7 +642,7 @@ func (r *NeInfoImpl) NeConfPara5GWirte(content map[string]any, syncNE []string) for _, neTI := range syncNE { ti := strings.SplitN(neTI, "@", 2) // 网元主机的SSH客户端 - sshClient, err := r.NeRunSSHclient(ti[0], ti[1]) + sshClient, err := r.NeRunSSHClient(ti[0], ti[1]) if err != nil { errMsg = append(errMsg, fmt.Sprintf("%s : %s", ti, err.Error())) continue @@ -672,20 +705,30 @@ func (r *NeInfoImpl) neConfPara5GDataConvert(content map[string]any) map[string] } n3IPAmdMask := external["upfn3_ip"].(string) - n3Arr := strings.Split(n3IPAmdMask, "/") + n3Arr := strings.SplitN(n3IPAmdMask, "/", 2) n3IP := n3Arr[0] - n3Mask := parse.ConvertIPMask(parse.Number(n3Arr[1])) + n3Mask := "255.255.255.0" + if len(n3Arr) > 1 { + n3Mask = parse.ConvertIPMask(parse.Number(n3Arr[1])) + } n6IPAmdMask := external["upfn6_ip"].(string) - n6Arr := strings.Split(n6IPAmdMask, "/") + n6Arr := strings.SplitN(n6IPAmdMask, "/", 2) n6IP := n6Arr[0] - n6Mask := parse.ConvertIPMask(parse.Number(n6Arr[1])) + n6Mask := "255.255.255.0" + if len(n6Arr) > 1 { + n6Mask = parse.ConvertIPMask(parse.Number(n6Arr[1])) + } ueIPAmdMask := external["ue_pool"].(string) - ueArr := strings.Split(ueIPAmdMask, "/") + ueArr := strings.SplitN(ueIPAmdMask, "/", 2) ueIP := ueArr[0] - ueCicr := ueArr[1] - ueMask := parse.ConvertIPMask(parse.Number(ueArr[1])) + ueCicr := "24" + ueMask := "255.255.255.0" + if len(ueArr) > 1 { + ueCicr = ueArr[1] + ueMask = parse.ConvertIPMask(parse.Number(ueArr[1])) + } return map[string]string{ // basic diff --git a/src/modules/network_element/service/ne_license.impl.go b/src/modules/network_element/service/ne_license.impl.go index d6f684e..9d11804 100644 --- a/src/modules/network_element/service/ne_license.impl.go +++ b/src/modules/network_element/service/ne_license.impl.go @@ -110,7 +110,7 @@ func (r *NeLicenseImpl) ReadLicenseInfo(neLicense model.NeLicense) (string, stri nePath := fmt.Sprintf("/usr/local/etc/%s/license", neTypeLower) // 网元主机的SSH客户端 - sshClient, err := NewNeInfoImpl.NeRunSSHclient(neLicense.NeType, neLicense.NeId) + sshClient, err := NewNeInfoImpl.NeRunSSHClient(neLicense.NeType, neLicense.NeId) if err != nil { return "", "" } @@ -149,7 +149,7 @@ func (r *NeLicenseImpl) UploadLicense(neLicense model.NeLicense) error { } // 网元主机的SSH客户端 - sshClient, err := NewNeInfoImpl.NeRunSSHclient(neLicense.NeType, neLicense.NeId) + sshClient, err := NewNeInfoImpl.NeRunSSHClient(neLicense.NeType, neLicense.NeId) if err != nil { return err } @@ -174,16 +174,16 @@ func (r *NeLicenseImpl) UploadLicense(neLicense model.NeLicense) error { // 上传授权文件去覆盖 if err := sftpClient.CopyFileLocalToRemote(omcLicensePath, neLicensePath); err != nil { - return err + return fmt.Errorf("please check if scp remote copy is allowed") } // 重启服务 if neLicense.Reload { cmdStr := fmt.Sprintf("sudo service %s restart", neTypeLower) if neTypeLower == "ims" { - cmdStr = "sudo ims-stop || true && sudo ims-start" + cmdStr = "ims-stop || true && ims-start" } else if neTypeLower == "omc" { - cmdStr = "sudo /usr/local/omc/bin/omcsvc.sh restart" + cmdStr = "sudo systemctl restart restagent" } sshClient.RunCMD(cmdStr) } diff --git a/src/modules/network_element/service/ne_version.impl.go b/src/modules/network_element/service/ne_version.impl.go index 473f109..caea08f 100644 --- a/src/modules/network_element/service/ne_version.impl.go +++ b/src/modules/network_element/service/ne_version.impl.go @@ -89,7 +89,7 @@ func (r *NeVersionImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeVersi // action 安装行为:install upgrade rollback func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error) { // 网元主机的SSH客户端 - sshClient, err := NewNeInfoImpl.NeRunSSHclient(neVersion.NeType, neVersion.NeId) + sshClient, err := NewNeInfoImpl.NeRunSSHClient(neVersion.NeType, neVersion.NeId) if err != nil { return "", err } @@ -125,10 +125,6 @@ func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinp if err != nil { return "", err } - // 操作自己omc时 - if neVersion.NeType == "OMC" { - return sshClient.RunCMD(fmt.Sprintf("nohup sh -c \"sleep 3s && %s\" > /dev/null 2>&1 & \n", strings.Join(cmdStrArr, " && "))) - } // ========= 执行阶段 ========= commandLine, err := r.operateRun(sshClient, preinput, cmdStrArr, neVersion.NeType, okFlagStr) @@ -203,23 +199,30 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri // 组合命令输入 cmdStrArr := []string{} if neType == "OMC" { - cmdStrArr = append(cmdStrArr, pkgCmdStr) + omcStrArr := []string{} + omcStrArr = append(omcStrArr, pkgCmdStr) if action == "install" { - cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/setomc.sh -m install") // 初始化数据库 + omcStrArr = append(omcStrArr, "sudo /usr/local/omc/bin/setomc.sh -m install") // 初始化数据库 } else { - cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh stop") - cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库 + omcStrArr = append(omcStrArr, "sudo /usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库 } - cmdStrArr = append(cmdStrArr, "sudo /usr/local/omc/bin/omcsvc.sh restart") + omcStrArr = append(omcStrArr, "sudo systemctl restart restagent") // 重启服务 + omcStrArr = append(omcStrArr, fmt.Sprintf("sudo rm %s", strings.Join(neFilePaths, " "))) // 删除软件包 + + // 2s后安装 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 2s && %s\" > /dev/null 2>&1 & \n", strings.Join(omcStrArr, " && "))) + // 结束 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr)) + return okFlagStr, cmdStrArr, nil } else if neType == "IMS" { if action == "install" { para5GData := NewNeInfoImpl.Para5GData cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") // 公网 PLMN地址 - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", para5GData["SIP_IP"], para5GData["MCC"], para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("/usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", para5GData["SIP_IP"], para5GData["MCC"], para5GData["MNC"])) // 内网 服务地址 - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo /usr/local/etc/ims/default/tools/modintraip.sh %s \n", para5GData["IMS_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("/usr/local/etc/ims/default/tools/modintraip.sh %s \n", para5GData["IMS_IP"])) // IWF连接PCF服务 cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/iwf/iwf_conf.yaml \n", para5GData["PCF_IP"])) // 设置 HOST @@ -245,16 +248,18 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri smsHost := fmt.Sprintf("%s smsc.%s smsc", para5GData["SIP_IP"], imsOrgHost) cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", smsHost, smsHost)) // adb - cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n") - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["ADB_IP"])) - - cmdStrArr = append(cmdStrArr, "sudo ims-stop || true && sudo ims-start \n") + if strings.Contains(pkgCmdStr, "adb") { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["ADB_IP"])) + cmdStrArr = append(cmdStrArr, "sudo service adb restart \n") + } + cmdStrArr = append(cmdStrArr, "ims-stop || true && ims-start \n") // 30s后停止服务 // cmdStrArr = append(cmdStrArr, "nohup sh -c \"sleep 30s && sudo ims-stop\" > /dev/null 2>&1 & \n") } else { - cmdStrArr = append(cmdStrArr, "sudo ims-stop \n") + cmdStrArr = append(cmdStrArr, "ims-stop \n") cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") - cmdStrArr = append(cmdStrArr, "sudo ims-start \n") + cmdStrArr = append(cmdStrArr, "ims-start \n") } } else { if action == "install" { @@ -319,11 +324,14 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/serviceSelection: 'ims'/serviceSelection: '%s'/g\" /usr/local/etc/udm/epsApn.yaml \n", para5GData["DNN_IMS"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: internet/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_DATA"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: ims/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_IMS"])) - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.18.81/%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["SIP_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.110/%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["SIP_IP"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s udm' /etc/hosts || echo '%s udm' | sudo tee -a /etc/hosts \n", para5GData["UDM_IP"], para5GData["UDM_IP"])) // adb - cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n") - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["ADB_IP"])) + if strings.Contains(pkgCmdStr, "adb") { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["ADB_IP"])) + cmdStrArr = append(cmdStrArr, "sudo service adb restart \n") + } } // SMF配置修改 if neTypeLower == "smf" { @@ -431,15 +439,19 @@ func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []stri cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["SMF_IP"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|192.168.8.220/20|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S1_MMEIP"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S11_MMEIP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["MME_IP"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.221/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S10_MMEIP"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MNC_DOMAIN"], para5GData["MCC"])) cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/\"00101\"/\"%s%s\"/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"])) - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MCC=\"001\" ; MNC=\"01\";/MCC=\"%s\" ; MNC=\"%s\";/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"])) - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/TAC = \"1\";/TAC = \"%s\";/g\" /usr/local/etc/mme/mme.conf \n", para5GData["TAC"])) - cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/TAC = 1;/TAC = %s;/g\" /usr/local/etc/mme/mme.conf \n", para5GData["TAC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MCC=\"001\"/MCC=\"%s\"/g' /usr/local/etc/mme/mme.conf \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MCC = \"001\"/MCC = \"%s\"/g' /usr/local/etc/mme/mme.conf \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MNC=\"01\";/MNC=\"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MNC = \"01\";/MNC = \"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/TAC = \"1\";/TAC = \"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["TAC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/TAC = 1;/TAC = %s;/g' /usr/local/etc/mme/mme.conf \n", para5GData["TAC"])) // SMF开启 cmdStrArr = append(cmdStrArr, "sudo sed -i \"/^ *gxcfg:/,/^ *[^ ]/{s/enable: false/enable: true/;b};\" /usr/local/etc/smf/smf_conf.yaml \n") - cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s mme' /etc/hosts || echo '%s mme' | sudo tee -a /etc/hosts \n", para5GData["S11_MMEIP"], para5GData["S11_MMEIP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s mme' /etc/hosts || echo '%s mme' | sudo tee -a /etc/hosts \n", para5GData["MME_IP"], para5GData["MME_IP"])) } // N3IWF配置修改 if neTypeLower == "n3iwf" { diff --git a/src/modules/network_element/service/udm_auth.go b/src/modules/network_element/service/udm_auth.go deleted file mode 100644 index 4ed5108..0000000 --- a/src/modules/network_element/service/udm_auth.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import "be.ems/src/modules/network_element/model" - -// UDM鉴权信息 服务层接口 -type IUDMAuth interface { - // Save UDM鉴权用户-获取redis全部保存数据库 - Save(neID string) int64 - - // Page UDM鉴权用户-分页查询数据库 - Page(query map[string]any) map[string]any - - // List UDM鉴权用户-查询数据库 - List(authUser model.UDMAuth) []model.UDMAuth - - // Insert UDM鉴权用户-新增单个 - // imsi长度15,ki长度32,opc长度0或者32 - Insert(neID string, authUser model.UDMAuth) int64 - - // Insert UDM鉴权用户-批量添加 - Inserts(neID string, authUser model.UDMAuth, num string) int64 - - // InsertCSV UDM鉴权用户-批量添加 - InsertCSV(neID string, data []map[string]string) int64 - - // InsertTxt UDM鉴权用户-批量添加 - InsertTxt(neID string, data [][]string) int64 - - // Insert UDM鉴权用户-修改更新 - Update(neID string, authUser model.UDMAuth) int64 - - // Insert UDM鉴权用户-删除单个 - Delete(neID, imsi string) int64 - - // Insert UDM鉴权用户-删除范围 - Deletes(neID, imsi, num string) int64 -} diff --git a/src/modules/network_element/service/udm_auth.impl.go b/src/modules/network_element/service/udm_auth.impl.go deleted file mode 100644 index a3c9689..0000000 --- a/src/modules/network_element/service/udm_auth.impl.go +++ /dev/null @@ -1,179 +0,0 @@ -package service - -import ( - "fmt" - "strings" - - "be.ems/src/framework/redis" - "be.ems/src/modules/network_element/model" - "be.ems/src/modules/network_element/repository" -) - -// 实例化服务层 UDMAuthImpl 结构体 -var NewUDMAuthImpl = &UDMAuthImpl{ - udmAuthRepository: repository.NewUDMAuthImpl, -} - -// UDM鉴权信息 服务层处理 -type UDMAuthImpl struct { - // UDM鉴权信息数据信息 - udmAuthRepository repository.IUDMAuth -} - -// authDataByRedis UDM鉴权用户 -func (r *UDMAuthImpl) authDataByRedis(imsi, neID string) []model.UDMAuth { - arr := []model.UDMAuth{} - key := fmt.Sprintf("ausf:%s", imsi) - ausfArr, err := redis.GetKeys("udmuser", key) - if err != nil { - return arr - } - for _, key := range ausfArr { - m, err := redis.GetHash("udmuser", key) - if err != nil { - continue - } - - // 跳过-号数据 - imsi := key[5:] - if strings.Contains(imsi, "-") { - continue - } - - status := "1" // 默认给1 - - amf := "" - if v, ok := m["amf"]; ok { - amf = strings.Replace(v, "\r\n", "", 1) - } - a := model.UDMAuth{ - Imsi: imsi, - Amf: amf, - Status: status, - Ki: m["ki"], - AlgoIndex: m["algo"], - Opc: m["opc"], - NeID: neID, - } - arr = append(arr, a) - } - return arr -} - -// Save UDM鉴权用户-获取redis全部保存数据库 -func (r *UDMAuthImpl) Save(neID string) int64 { - authArr := r.authDataByRedis("*", neID) - // 数据清空后添加 - go r.udmAuthRepository.ClearAndInsert(neID, authArr) - return int64(len(authArr)) -} - -// Page UDM鉴权用户-分页查询数据库 -func (r *UDMAuthImpl) Page(query map[string]any) map[string]any { - return r.udmAuthRepository.SelectPage(query) -} - -// List UDM鉴权用户-查询数据库 -func (r *UDMAuthImpl) List(authUser model.UDMAuth) []model.UDMAuth { - return r.udmAuthRepository.SelectList(authUser) -} - -// Insert UDM鉴权用户-新增单个 -// imsi长度15,ki长度32,opc长度0或者32 -func (r *UDMAuthImpl) Insert(neID string, authUser model.UDMAuth) int64 { - authArr := r.authDataByRedis(authUser.Imsi, neID) - if len(authArr) > 0 { - r.udmAuthRepository.Delete(neID, authUser.Imsi) - r.udmAuthRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM鉴权用户-批量添加 -func (r *UDMAuthImpl) Inserts(neID string, authUser model.UDMAuth, num string) int64 { - startIMSI := authUser.Imsi - startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*" - // keys udm-sd:4600001000004* - authArr := r.authDataByRedis(startIMSI, neID) - if len(authArr) > 0 { - for _, v := range authArr { - r.udmAuthRepository.Delete(neID, v.Imsi) - } - return r.udmAuthRepository.Inserts(authArr) - } - return 0 -} - -// InsertCSV UDM鉴权用户-批量添加 -func (r *UDMAuthImpl) InsertCSV(neID string, data []map[string]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v["imsi"] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmAuthRepository.DeletePrefixImsi(neID, prefix) - subArr := r.authDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmAuthRepository.Inserts(subArr) - } - } - return num -} - -// InsertTxt UDM鉴权用户-批量添加 -func (r *UDMAuthImpl) InsertTxt(neID string, data [][]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v[0] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmAuthRepository.DeletePrefixImsi(neID, prefix) - subArr := r.authDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmAuthRepository.Inserts(subArr) - } - } - return num -} - -// Insert UDM鉴权用户-修改更新 -func (r *UDMAuthImpl) Update(neID string, authUser model.UDMAuth) int64 { - authArr := r.authDataByRedis(authUser.Imsi, neID) - if len(authArr) > 0 { - r.udmAuthRepository.Delete(neID, authUser.Imsi) - return r.udmAuthRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM鉴权用户-删除单个 -func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { - return r.udmAuthRepository.Delete(neID, imsi) -} - -// Insert UDM鉴权用户-删除范围 -func (r *UDMAuthImpl) Deletes(neID, imsi, num string) int64 { - prefix := imsi[:len(imsi)-len(num)-1] - // 直接删除前缀的记录 - r.udmAuthRepository.DeletePrefixImsi(neID, prefix) - // keys ausf:4600001000004* - authArr := r.authDataByRedis(prefix+"*", neID) - if len(authArr) > 0 { - return r.udmAuthRepository.Inserts(authArr) - } - return 0 -} diff --git a/src/modules/network_element/service/udm_sub.go b/src/modules/network_element/service/udm_sub.go deleted file mode 100644 index 14e5af5..0000000 --- a/src/modules/network_element/service/udm_sub.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import "be.ems/src/modules/network_element/model" - -// UDM签约用户信息 服务层接口 -type IUDMSub interface { - // Save UDM签约用户-获取redis全部保存数据库 - Save(neID string) int64 - - // Page UDM签约用户-分页查询数据库 - Page(query map[string]any) map[string]any - - // List UDM签约用户-查询数据库 - List(subUser model.UDMSub) []model.UDMSub - - // Insert UDM签约用户-新增单个 - // imsi长度15,ki长度32,opc长度0或者32 - Insert(neID string, subUser model.UDMSub) int64 - - // Insert UDM签约用户-批量添加 - Inserts(neID string, subUser model.UDMSub, num string) int64 - - // InsertCSV UDM签约用户-批量添加 - InsertCSV(neID string, data []map[string]string) int64 - - // InsertTxt UDM签约用户-批量添加 - InsertTxt(neID string, data [][]string) int64 - - // Insert UDM签约用户-修改更新 - Update(neID string, subUser model.UDMSub) int64 - - // Insert UDM签约用户-删除单个 - Delete(neID, imsi string) int64 - - // Insert UDM签约用户-删除范围 - Deletes(neID, imsi, num string) int64 -} diff --git a/src/modules/network_element/service/udm_sub.impl.go b/src/modules/network_element/service/udm_sub.impl.go deleted file mode 100644 index e031071..0000000 --- a/src/modules/network_element/service/udm_sub.impl.go +++ /dev/null @@ -1,195 +0,0 @@ -package service - -import ( - "fmt" - "strings" - - "be.ems/src/framework/redis" - "be.ems/src/modules/network_element/model" - "be.ems/src/modules/network_element/repository" -) - -// 实例化服务层 UDMSubImpl 结构体 -var NewUDMSubImpl = &UDMSubImpl{ - udmSubRepository: repository.NewUDMSubImpl, -} - -// UDM签约信息 服务层处理 -type UDMSubImpl struct { - // UDM签约信息数据信息 - udmSubRepository repository.IUDMSub -} - -// subDataByRedis UDM签约用户 -func (r *UDMSubImpl) subDataByRedis(imsi, neID string) []model.UDMSub { - arr := []model.UDMSub{} - key := fmt.Sprintf("udm-sd:%s", imsi) - udmsdArr, err := redis.GetKeys("udmuser", key) - if err != nil { - return arr - } - for _, key := range udmsdArr { - m, err := redis.GetHash("udmuser", key) - if err != nil { - continue - } - - a := model.UDMSub{ - Imsi: key[7:], - Msisdn: m["gpsi"], // 46003550072 strings.TrimPrefix(m["gpsi"], "86"), - SmfSel: m["smf-sel"], - SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet - NeID: neID, - } - - // def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,- - if v, ok := m["am-dat"]; ok { - arr := strings.Split(v, ",") - a.Ambr = arr[0] - a.Nssai = arr[1] - a.Rat = arr[2] - a.Arfb = arr[3] - a.Sar = arr[4] - a.Cn = arr[5] - } - // 1,64,24,65,def_eps,1,2,010200000000,- - if v, ok := m["eps-dat"]; ok { - arr := strings.Split(v, ",") - // 跳过非常规数据 - if len(arr) > 9 { - continue - } - a.EpsDat = v - a.EpsFlag = arr[0] - a.EpsOdb = arr[1] - a.HplmnOdb = arr[2] - a.Ard = arr[3] - a.Epstpl = arr[4] - a.ContextId = arr[5] - a.ApnContext = arr[7] - // [6] 是不要的,导入和导出不用 - a.StaticIp = arr[8] - } - - arr = append(arr, a) - } - return arr -} - -// Save UDM签约用户-获取redis全部保存数据库 -func (r *UDMSubImpl) Save(neID string) int64 { - subArr := r.subDataByRedis("*", neID) - // 数据清空后添加 - go r.udmSubRepository.ClearAndInsert(neID, subArr) - return int64(len(subArr)) -} - -// Page UDM签约用户-分页查询数据库 -func (r *UDMSubImpl) Page(query map[string]any) map[string]any { - return r.udmSubRepository.SelectPage(query) -} - -// List UDM签约用户-查询数据库 -func (r *UDMSubImpl) List(subUser model.UDMSub) []model.UDMSub { - return r.udmSubRepository.SelectList(subUser) -} - -// Insert UDM签约用户-新增单个 -// imsi长度15,ki长度32,opc长度0或者32 -func (r *UDMSubImpl) Insert(neID string, subUser model.UDMSub) int64 { - authArr := r.subDataByRedis(subUser.Imsi, neID) - if len(authArr) > 0 { - r.udmSubRepository.Delete(neID, subUser.Imsi) - r.udmSubRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM签约用户-批量添加 -func (r *UDMSubImpl) Inserts(neID string, subUser model.UDMSub, num string) int64 { - startIMSI := subUser.Imsi - startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*" - // keys udm-sd:4600001000004* - subArr := r.subDataByRedis(startIMSI, neID) - if len(subArr) > 0 { - for _, v := range subArr { - r.udmSubRepository.Delete(neID, v.Imsi) - } - return r.udmSubRepository.Inserts(subArr) - } - return 0 -} - -// InsertCSV UDM签约用户-批量添加 -func (r *UDMSubImpl) InsertCSV(neID string, data []map[string]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v["imsi"] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmSubRepository.DeletePrefixImsi(neID, prefix) - subArr := r.subDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmSubRepository.Inserts(subArr) - } - } - return num -} - -// InsertTxt UDM签约用户-批量添加 -func (r *UDMSubImpl) InsertTxt(neID string, data [][]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v[0] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmSubRepository.DeletePrefixImsi(neID, prefix) - subArr := r.subDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmSubRepository.Inserts(subArr) - } - } - return num -} - -// Insert UDM签约用户-修改更新 -func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 { - authArr := r.subDataByRedis(subUser.Imsi, neID) - if len(authArr) > 0 { - r.udmSubRepository.Delete(neID, subUser.Imsi) - return r.udmSubRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM签约用户-删除单个 -func (r *UDMSubImpl) Delete(neID, imsi string) int64 { - return r.udmSubRepository.Delete(neID, imsi) -} - -// Insert UDM签约用户-删除范围 -func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 { - prefix := imsi[:len(imsi)-len(num)-1] - // 直接删除前缀的记录 - r.udmSubRepository.DeletePrefixImsi(neID, prefix) - // keys udm-sd:4600001000004* - authArr := r.subDataByRedis(prefix+"*", neID) - if len(authArr) > 0 { - return r.udmSubRepository.Inserts(authArr) - } - return 0 -} diff --git a/src/modules/system/controller/sys_log_login.go b/src/modules/system/controller/sys_log_login.go index 7a75b49..ad6a7a7 100644 --- a/src/modules/system/controller/sys_log_login.go +++ b/src/modules/system/controller/sys_log_login.go @@ -40,7 +40,8 @@ type SysLogLoginController struct { // GET /list func (s *SysLogLoginController) List(c *gin.Context) { querys := ctx.QueryMap(c) - data := s.sysLogLoginService.SelectSysLogLoginPage(querys) + dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u") + data := s.sysLogLoginService.SelectSysLogLoginPage(querys, dataScopeSQL) rows := data["rows"].([]model.SysLogLogin) // 闭包函数处理多语言 diff --git a/src/modules/system/controller/sys_log_operate.go b/src/modules/system/controller/sys_log_operate.go index 3c542a9..85f6426 100644 --- a/src/modules/system/controller/sys_log_operate.go +++ b/src/modules/system/controller/sys_log_operate.go @@ -42,7 +42,8 @@ func (s *SysLogOperateController) List(c *gin.Context) { querys["title"] = i18n.TFindKeyPrefix(language, "log.operate.title", v.(string)) } - data := s.SysLogOperateService.SelectSysLogOperatePage(querys) + dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u") + data := s.SysLogOperateService.SelectSysLogOperatePage(querys, dataScopeSQL) rows := data["rows"].([]model.SysLogOperate) // 闭包函数处理多语言 diff --git a/src/modules/system/controller/sys_profile.go b/src/modules/system/controller/sys_profile.go index 8b5669d..55095bc 100644 --- a/src/modules/system/controller/sys_profile.go +++ b/src/modules/system/controller/sys_profile.go @@ -60,7 +60,7 @@ func (s *SysProfileController) Info(c *gin.Context) { } isAdmin := config.IsAdmin(loginUser.UserID) if isAdmin { - roleGroup = append(roleGroup, i18n.TKey(language, "role.admin")) + roleGroup = append(roleGroup, i18n.TKey(language, "role.system")) } // 查询用户所属岗位组 diff --git a/src/modules/system/repository/sys_log_login.go b/src/modules/system/repository/sys_log_login.go index 6fc0d69..8dfbc82 100644 --- a/src/modules/system/repository/sys_log_login.go +++ b/src/modules/system/repository/sys_log_login.go @@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model" // ISysLogLogin 系统登录日志表 数据层接口 type ISysLogLogin interface { // SelectSysLogLoginPage 分页查询系统登录日志集合 - SelectSysLogLoginPage(query map[string]any) map[string]any + SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogLoginList 查询系统登录日志集合 SelectSysLogLoginList(sysLogLogin model.SysLogLogin) []model.SysLogLogin diff --git a/src/modules/system/repository/sys_log_login.impl.go b/src/modules/system/repository/sys_log_login.impl.go index 178a745..d32e17b 100644 --- a/src/modules/system/repository/sys_log_login.impl.go +++ b/src/modules/system/repository/sys_log_login.impl.go @@ -53,7 +53,7 @@ func (r *SysLogLoginImpl) convertResultRows(rows []map[string]any) []model.SysLo } // SelectSysLogLoginPage 分页查询系统登录日志集合 -func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string]any { +func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -87,9 +87,23 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string } // 构建查询条件语句 + selectSql := r.selectSql + totalSql := "select count(login_id) as 'total' from sys_log_login" whereSql := "" if len(conditions) > 0 { whereSql += " where " + strings.Join(conditions, " and ") + whereSql += dataScopeSQL + } else if dataScopeSQL != "" { + totalSql = `select count(o.login_id) as 'total' + from sys_log_login o + left join sys_user u on u.user_name = o.user_name + left join sys_dept d on u.dept_id = d.dept_id` + selectSql = `select o.login_id, o.user_name, o.ipaddr, o.login_location, + o.browser, o.os, o.status, o.msg, o.login_time + from sys_log_login o + left join sys_user u on u.user_name = o.user_name + left join sys_dept d on u.dept_id = d.dept_id` + whereSql += " where 1=1" + dataScopeSQL } // 查询结果 @@ -99,7 +113,6 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_log_login" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -119,7 +132,7 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string params = append(params, pageSize) // 查询数据 - querySql := r.selectSql + whereSql + pageSql + querySql := selectSql + whereSql + dataScopeSQL + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) diff --git a/src/modules/system/repository/sys_log_operate.go b/src/modules/system/repository/sys_log_operate.go index 9f8a98c..5f8cb01 100644 --- a/src/modules/system/repository/sys_log_operate.go +++ b/src/modules/system/repository/sys_log_operate.go @@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model" // ISysLogOperate 操作日志表 数据层接口 type ISysLogOperate interface { // SelectSysLogOperatePage 分页查询系统操作日志集合 - SelectSysLogOperatePage(query map[string]any) map[string]any + SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogOperateList 查询系统操作日志集合 SelectSysLogOperateList(sysLogOperate model.SysLogOperate) []model.SysLogOperate diff --git a/src/modules/system/repository/sys_log_operate.impl.go b/src/modules/system/repository/sys_log_operate.impl.go index 649c312..b6a0869 100644 --- a/src/modules/system/repository/sys_log_operate.impl.go +++ b/src/modules/system/repository/sys_log_operate.impl.go @@ -62,7 +62,7 @@ func (r *SysLogOperateImpl) convertResultRows(rows []map[string]any) []model.Sys } // SelectSysLogOperatePage 分页查询系统操作日志集合 -func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[string]any { +func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -100,9 +100,24 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st } // 构建查询条件语句 + selectSql := r.selectSql + totalSql := "select count(oper_id) as 'total' from sys_log_operate" whereSql := "" if len(conditions) > 0 { whereSql += " where " + strings.Join(conditions, " and ") + whereSql += dataScopeSQL + } else if dataScopeSQL != "" { + totalSql = `select count(o.oper_id) as 'total' + from sys_log_operate o + left join sys_user u on u.user_name = o.oper_name + left join sys_dept d on u.dept_id = d.dept_id` + selectSql = `select + o.oper_id, o.title, o.business_type, o.method, o.request_method, o.operator_type, o.oper_name, o.dept_name, + o.oper_url, o.oper_ip, o.oper_location, o.oper_param, o.oper_msg, o.status, o.oper_time, o.cost_time + from sys_log_operate o + left join sys_user u on u.user_name = o.oper_name + left join sys_dept d on u.dept_id = d.dept_id` + whereSql += " where 1=1" + dataScopeSQL } // 查询结果 @@ -112,7 +127,6 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_log_operate" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -132,7 +146,7 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st params = append(params, pageSize) // 查询数据 - querySql := r.selectSql + whereSql + pageSql + querySql := selectSql + whereSql + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) diff --git a/src/modules/system/repository/sys_user.impl.go b/src/modules/system/repository/sys_user.impl.go index bbcbe84..afa2236 100644 --- a/src/modules/system/repository/sys_user.impl.go +++ b/src/modules/system/repository/sys_user.impl.go @@ -254,7 +254,7 @@ func (r *SysUserImpl) SelectAllocatedPage(query map[string]any, dataScopeSQL str } // 构建查询条件语句 - whereSql := " where u.del_flag = '0' " + whereSql := " where u.del_flag = '0' and u.user_id != '1' " if len(conditions) > 0 { whereSql += " and " + strings.Join(conditions, " and ") } diff --git a/src/modules/system/service/sys_log_login.go b/src/modules/system/service/sys_log_login.go index 2bda2f4..9b62ac3 100644 --- a/src/modules/system/service/sys_log_login.go +++ b/src/modules/system/service/sys_log_login.go @@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model" // ISysLogLogin 系统登录日志 服务层接口 type ISysLogLogin interface { // SelectSysLogLoginPage 分页查询系统登录日志集合 - SelectSysLogLoginPage(query map[string]any) map[string]any + SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogLoginList 查询系统登录日志集合 SelectSysLogLoginList(sysLogLogin model.SysLogLogin) []model.SysLogLogin diff --git a/src/modules/system/service/sys_log_login.impl.go b/src/modules/system/service/sys_log_login.impl.go index 83fe9a2..226b0da 100644 --- a/src/modules/system/service/sys_log_login.impl.go +++ b/src/modules/system/service/sys_log_login.impl.go @@ -17,8 +17,8 @@ type SysLogLoginImpl struct { } // SelectSysLogLoginPage 分页查询系统登录日志集合 -func (s *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string]any { - return s.sysLogLoginService.SelectSysLogLoginPage(query) +func (s *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any { + return s.sysLogLoginService.SelectSysLogLoginPage(query, dataScopeSQL) } // SelectSysLogLoginList 查询系统登录日志集合 diff --git a/src/modules/system/service/sys_log_operate.go b/src/modules/system/service/sys_log_operate.go index 8a7eeb2..d0857b6 100644 --- a/src/modules/system/service/sys_log_operate.go +++ b/src/modules/system/service/sys_log_operate.go @@ -5,7 +5,7 @@ import "be.ems/src/modules/system/model" // ISysLogOperate 操作日志表 服务层接口 type ISysLogOperate interface { // SelectSysLogOperatePage 分页查询系统操作日志集合 - SelectSysLogOperatePage(query map[string]any) map[string]any + SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogOperateList 查询系统操作日志集合 SelectSysLogOperateList(sysLogOperate model.SysLogOperate) []model.SysLogOperate diff --git a/src/modules/system/service/sys_log_operate.impl.go b/src/modules/system/service/sys_log_operate.impl.go index 540e5fd..c6edb18 100644 --- a/src/modules/system/service/sys_log_operate.impl.go +++ b/src/modules/system/service/sys_log_operate.impl.go @@ -17,8 +17,8 @@ type SysLogOperateImpl struct { } // SelectSysLogOperatePage 分页查询系统操作日志集合 -func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[string]any { - return r.SysLogOperateService.SelectSysLogOperatePage(query) +func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any { + return r.SysLogOperateService.SelectSysLogOperatePage(query, dataScopeSQL) } // SelectSysLogOperateList 查询系统操作日志集合 diff --git a/src/modules/system/system.go b/src/modules/system/system.go index 407a94e..850f72e 100644 --- a/src/modules/system/system.go +++ b/src/modules/system/system.go @@ -209,7 +209,7 @@ func Setup(router *gin.Engine) { controller.NewSysMenu.Remove, ) sysMenuGroup.GET("/treeSelect", - middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:menu:list"}}), + middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:menu:list", "system:dept:list"}}), controller.NewSysMenu.TreeSelect, ) sysMenuGroup.GET("/roleMenuTreeSelect/:roleId", diff --git a/src/modules/trace/service/tcpdump.impl.go b/src/modules/trace/service/tcpdump.impl.go index 5fb1c2e..005ee2b 100644 --- a/src/modules/trace/service/tcpdump.impl.go +++ b/src/modules/trace/service/tcpdump.impl.go @@ -5,9 +5,7 @@ import ( "strings" "time" - "be.ems/src/framework/config" "be.ems/src/framework/logger" - "be.ems/src/framework/utils/cmd" "be.ems/src/framework/utils/date" neService "be.ems/src/modules/network_element/service" ) @@ -28,23 +26,26 @@ type TcpdumpImpl struct { // DumpStart 触发tcpdump开始抓包 filePcapName, err func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) { - // 检查网元信息 + // 查询网元获取IP neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.IP == "" { return "", fmt.Errorf("noData") } - // SSH命令 - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + return "", err + } + defer sshClient.Close() // 是否拥有sudo权限并拼接 withSudo := "" - if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil { + if _, err := sshClient.RunCMD("sudo -n uname"); err == nil { withSudo = "sudo " } - if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil { + if msg, err := sshClient.RunCMD(fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil { // stderr: bash: tcpdump:未找到命令 => exit status 127 msg = strings.TrimSpace(msg) logger.Warnf("DumpStart err: %s => %s", msg, err.Error()) @@ -58,7 +59,7 @@ func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) { sendCmd := fmt.Sprintf("cd /tmp \n %s nohup timeout 30m tcpdump -i any %s -s0 -w %s.pcap > %s.log 2>&1 & \necho $!", withSudo, cmdStr, fileName, fileName) // cd /tmp // sudo nohup timeout 60m tcpdump -i any -n -s 0 -v -w -s0 -w 20240115140822_UDM_001.pcap > 20240115140822_UDM_001.log 2>&1 & echo $! - msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd) + msg, err := sshClient.RunCMD(sendCmd) msg = strings.TrimSpace(msg) if err != nil || strings.HasPrefix(msg, "stderr:") { logger.Warnf("DumpStart err: %s => %s", msg, err.Error()) @@ -73,19 +74,22 @@ func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) { // DumpStop 停止已存在抓包句柄 func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) { - // 检查网元信息 + // 查询网元获取IP neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.IP == "" { return "", fmt.Errorf("noData") } - // SSH命令 - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + return "", err + } + defer sshClient.Close() // 是否拥有sudo权限并拼接 withSudo := "" - if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil { + if _, err := sshClient.RunCMD("sudo -n uname"); err == nil { withSudo = "sudo " } @@ -104,7 +108,7 @@ func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) { // 拼装命令 sendCmd := fmt.Sprintf("cd /tmp \n %s kill %s %s", withSudo, pid, viewLogFile) - msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd) + msg, err := sshClient.RunCMD(sendCmd) delete(s.tcpdumpPIDMap, neTypeID) if err != nil || strings.HasPrefix(msg, "stderr:") { logger.Warnf("DumpStop err: %s => %s", strings.TrimSpace(msg), err.Error()) @@ -115,23 +119,26 @@ func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) { // DumpUPF UPF标准版抓包 func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, error) { - // 检查网元信息 + // 查询网元获取IP neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.IP == "" { return "", "", fmt.Errorf("noData") } - // SSH命令 - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + return "", "", err + } + defer sshClient.Close() // 是否拥有sudo权限并拼接 withSudo := "" - if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil { + if _, err := sshClient.RunCMD("sudo -n uname"); err == nil { withSudo = "sudo " } - if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s expect -version", withSudo)); err != nil { + if msg, err := sshClient.RunCMD(fmt.Sprintf("%s expect -version", withSudo)); err != nil { // stderr: bash: expect:未找到命令 => exit status 127 msg = strings.TrimSpace(msg) logger.Warnf("DumpUPF err: %s => %s", msg, err.Error()) @@ -160,7 +167,7 @@ func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, erro // sudo chmod +x pcapUPF.sh // expect ./cap.sh 'pcap dispatch trace off' > 20240115165701_UDM_001.log 2>&1 // cat 20240115165701_UDM_001.log - msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd) + msg, err := sshClient.RunCMD(sendCmd) msg = strings.TrimSpace(msg) if err != nil || strings.HasPrefix(msg, "stderr:") { logger.Warnf("DumpUPF err: %s => %s", msg, err.Error()) diff --git a/src/modules/trace/trace.go b/src/modules/trace/trace.go index f045f70..dd38c72 100644 --- a/src/modules/trace/trace.go +++ b/src/modules/trace/trace.go @@ -13,8 +13,10 @@ import ( func Setup(router *gin.Engine) { logger.Infof("开始加载 ====> trace 模块路由") + traceGroup := router.Group("/trace") + // 信令抓包 - tcpdumpGroup := router.Group("/tcpdump") + tcpdumpGroup := traceGroup.Group("/tcpdump") { tcpdumpGroup.POST("/start", middleware.PreAuthorize(nil), diff --git a/src/modules/ws/controller/ws.go b/src/modules/ws/controller/ws.go index 04257dd..8e077c0 100644 --- a/src/modules/ws/controller/ws.go +++ b/src/modules/ws/controller/ws.go @@ -257,18 +257,18 @@ func (s *WSController) Telnet(c *gin.Context) { defer client.Close() // 终端单行字符数 - cols, err := strconv.Atoi(c.Query("cols")) - if err != nil || cols > 254 { - cols = 80 + cols, err := strconv.Atoi(c.DefaultQuery("cols", "120")) + if err != nil { + cols = 120 } // 终端显示行数 - rows, err := strconv.Atoi(c.Query("rows")) - if err != nil || cols > rows { - rows = 40 + rows, err := strconv.Atoi(c.DefaultQuery("rows", "128")) + if err != nil { + rows = 128 } // 创建Telnet客户端会话 - clientSession, err := client.NewClientSession(uint8(cols), uint8(rows)) + clientSession, err := client.NewClientSession(cols, rows) if err != nil { // 连接主机失败,请检查连接参数后重试 c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) diff --git a/src/modules/ws/processor/cdr_connect.go b/src/modules/ws/processor/cdr_connect.go index bd05465..fc8dc1e 100644 --- a/src/modules/ws/processor/cdr_connect.go +++ b/src/modules/ws/processor/cdr_connect.go @@ -10,17 +10,17 @@ import ( neDataService "be.ems/src/modules/network_data/service" ) -// GetCDRConnect 获取CDR会话事件-IMS -func GetCDRConnect(requestID string, data any) ([]byte, error) { +// GetCDRConnectByIMS 获取CDR会话事件-IMS +func GetCDRConnectByIMS(requestID string, data any) ([]byte, error) { msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventQuery + var query neDataModel.CDREventIMSQuery err := json.Unmarshal(msgByte, &query) if err != nil { logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewCDREventImpl.SelectPage(query) + dataMap := neDataService.NewCDREventIMSImpl.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, "data": dataMap, @@ -28,17 +28,17 @@ func GetCDRConnect(requestID string, data any) ([]byte, error) { return resultByte, err } -// GetCDRConnect 获取CDR会话事件-SMF -func GetSMFCDRConnect(requestID string, data any) ([]byte, error) { +// GetCDRConnectBySMF 获取CDR会话事件-SMF +func GetCDRConnectBySMF(requestID string, data any) ([]byte, error) { msgByte, _ := json.Marshal(data) - var query neDataModel.SMFCDREventQuery + var query neDataModel.CDREventSMFQuery err := json.Unmarshal(msgByte, &query) if err != nil { logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewSMFCDREventImpl.SelectPage(query) + dataMap := neDataService.NewCDREventSMFImpl.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, "data": dataMap, diff --git a/src/modules/ws/processor/ne_state.go b/src/modules/ws/processor/ne_state.go index dcf5df1..64e76e7 100644 --- a/src/modules/ws/processor/ne_state.go +++ b/src/modules/ws/processor/ne_state.go @@ -6,6 +6,7 @@ import ( "be.ems/src/framework/logger" "be.ems/src/framework/vo/result" + neFetchlink "be.ems/src/modules/network_element/fetch_link" neService "be.ems/src/modules/network_element/service" ) @@ -33,7 +34,7 @@ func GetNeState(requestID string, data any) ([]byte, error) { } // 网元直连 - resData, err := neService.NeState(neInfo) + resData, err := neFetchlink.NeState(neInfo) if err != nil { resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, diff --git a/src/modules/ws/processor/ue_connect.go b/src/modules/ws/processor/ue_connect.go index 29caace..bb0f649 100644 --- a/src/modules/ws/processor/ue_connect.go +++ b/src/modules/ws/processor/ue_connect.go @@ -10,17 +10,35 @@ import ( neDataService "be.ems/src/modules/network_data/service" ) -// GetUEConnect 获取UE会话事件-AMF -func GetUEConnect(requestID string, data any) ([]byte, error) { +// GetUEConnectByAMF 获取UE会话事件-AMF +func GetUEConnectByAMF(requestID string, data any) ([]byte, error) { msgByte, _ := json.Marshal(data) - var query neDataModel.UEEventQuery + var query neDataModel.UEEventAMFQuery err := json.Unmarshal(msgByte, &query) if err != nil { - logger.Warnf("ws processor GetUEConnect err: %s", err.Error()) + logger.Warnf("ws processor GetUEConnectByAMF err: %s", err.Error()) return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewUEEventImpl.SelectPage(query) + dataMap := neDataService.NewUEEventAMFImpl.SelectPage(query) + resultByte, err := json.Marshal(result.Ok(map[string]any{ + "requestId": requestID, + "data": dataMap, + })) + return resultByte, err +} + +// GetUEConnectByMME 获取UE会话事件-MME +func GetUEConnectByMME(requestID string, data any) ([]byte, error) { + msgByte, _ := json.Marshal(data) + var query neDataModel.UEEventMMEQuery + err := json.Unmarshal(msgByte, &query) + if err != nil { + logger.Warnf("ws processor GetUEConnectByMME err: %s", err.Error()) + return nil, fmt.Errorf("query data structure error") + } + + dataMap := neDataService.NewUEEventMMEImpl.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, "data": dataMap, diff --git a/src/modules/ws/service/ws_receive.impl.go b/src/modules/ws/service/ws_receive.impl.go index 3df4930..553b1c6 100644 --- a/src/modules/ws/service/ws_receive.impl.go +++ b/src/modules/ws/service/ws_receive.impl.go @@ -68,10 +68,14 @@ func (s *WSReceiveImpl) AsyncReceive(client *model.WSClient, reqMsg model.WSRequ resByte, err = processor.GetProcessData(reqMsg.RequestID, reqMsg.Data) case "net": resByte, err = processor.GetNetConnections(reqMsg.RequestID, reqMsg.Data) - case "cdr": - resByte, err = processor.GetCDRConnect(reqMsg.RequestID, reqMsg.Data) - case "ue": - resByte, err = processor.GetUEConnect(reqMsg.RequestID, reqMsg.Data) + case "ims_cdr": + resByte, err = processor.GetCDRConnectByIMS(reqMsg.RequestID, reqMsg.Data) + case "smf_cdr": + resByte, err = processor.GetCDRConnectBySMF(reqMsg.RequestID, reqMsg.Data) + case "amf_ue": + resByte, err = processor.GetUEConnectByAMF(reqMsg.RequestID, reqMsg.Data) + case "mme_ue": + resByte, err = processor.GetUEConnectByMME(reqMsg.RequestID, reqMsg.Data) case "upf_tf": resByte, err = processor.GetUPFTotalFlow(reqMsg.RequestID, reqMsg.Data) case "ne_state": diff --git a/src/modules/ws/service/ws_send.impl.go b/src/modules/ws/service/ws_send.impl.go index 0720cc2..94c23b7 100644 --- a/src/modules/ws/service/ws_send.impl.go +++ b/src/modules/ws/service/ws_send.impl.go @@ -18,8 +18,12 @@ const ( GROUP_KPI_UPF = "12" // 组号-IMS_CDR会话事件 GROUP_IMS_CDR = "1005" + // 组号-SMF_CDR会话事件 + GROUP_SMF_CDR = "1006" // 组号-AMF_UE会话事件 GROUP_AMF_UE = "1010" + // 组号-MME_UE会话事件 + GROUP_MME_UE = "1011" ) // 实例化服务层 WSSendImpl 结构体