feat: 删除不需要文件夹
This commit is contained in:
32
.gitignore
vendored
32
.gitignore
vendored
@@ -9,6 +9,38 @@
|
|||||||
# Local History for Visual Studio Code
|
# Local History for Visual Studio Code
|
||||||
.history/
|
.history/
|
||||||
|
|
||||||
|
# Run temp file and dir
|
||||||
|
crontask/log/
|
||||||
|
crontask/ftp/
|
||||||
|
crontask/database/
|
||||||
|
crontask/export/
|
||||||
|
crontask/temp
|
||||||
|
crontask/crontask
|
||||||
|
|
||||||
|
restagent/backup/
|
||||||
|
restagent/log/
|
||||||
|
restagent/upload/
|
||||||
|
restagent/software/
|
||||||
|
restagent/database/
|
||||||
|
restagent/restagent
|
||||||
|
|
||||||
|
sshsvc/sshsvc
|
||||||
|
sshsvc/mmllog/
|
||||||
|
sshsvc/mmlhome/
|
||||||
|
sshsvc/log/
|
||||||
|
|
||||||
|
captrace/captrace
|
||||||
|
captrace/log/
|
||||||
|
|
||||||
|
tools/loadmconf/loadmconf
|
||||||
|
tools/loadpconf/loadpconf
|
||||||
|
|
||||||
|
vendor
|
||||||
|
|
||||||
# Built Visual Studio Code Extensions
|
# Built Visual Studio Code Extensions
|
||||||
*.vsix
|
*.vsix
|
||||||
|
*.log
|
||||||
|
*.log-*
|
||||||
|
*.bak
|
||||||
|
__debug_bin*.exe
|
||||||
|
|
||||||
|
|||||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": []
|
||||||
|
}
|
||||||
41
.vscode/launch.json
vendored
Normal file
41
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
// 使用 IntelliSense 了解相关属性。
|
||||||
|
// 悬停以查看现有属性的描述。
|
||||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "调试模式",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "./restagent/restagent.go",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "DEBUG restagent",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "d:/local.git/ems.agt/restagent/restagent.go",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug sshsvc",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "d:/local.git/ems.agt/sshsvc/sshsvc.go",
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug loadpconf",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "d:/local.git/ems.agt/tools/loadpconf",
|
||||||
|
"args": ["-p","../../config/param/upf_param_config.yaml"],
|
||||||
|
"console": "integratedTerminal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"go.toolsEnvVars": {
|
||||||
|
"GOARCH": "amd64",
|
||||||
|
"GOOS": "windows"
|
||||||
|
},
|
||||||
|
"go.testEnvVars": {
|
||||||
|
"GOARCH": "wasm",
|
||||||
|
"GOOS": "js"
|
||||||
|
},
|
||||||
|
"commentTranslate.hover.enabled": true
|
||||||
|
}
|
||||||
142
features/aaaa/aaaa.go
Normal file
142
features/aaaa/aaaa.go
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package aaaa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/oauth"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriAAAASSO = config.DefaultUriPrefix + "/aaaa/{apiVersion}/security/sso" // for 4A external
|
||||||
|
|
||||||
|
CustomUriAAAASSO = config.UriPrefix + "/aaaa/{apiVersion}/security/sso" // for 4A external
|
||||||
|
)
|
||||||
|
|
||||||
|
var client = resty.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
/*
|
||||||
|
client.
|
||||||
|
SetTimeout(10 * time.Second).
|
||||||
|
SetRetryCount(1).
|
||||||
|
SetRetryWaitTime(1 * time.Second).
|
||||||
|
SetRetryMaxWaitTime(2 * time.Second).
|
||||||
|
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||||||
|
return 0, errors.New("quota exceeded")
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
client.SetTimeout(3 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AAAATicket struct {
|
||||||
|
Ticket string `json:"ticket"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SSOResult struct {
|
||||||
|
SSO struct {
|
||||||
|
Result string `json:"result"`
|
||||||
|
ResultMsg string `json:"result_msg"`
|
||||||
|
Ticket string `json:"ticket"`
|
||||||
|
ResultMsgcode string `json:"result_msgcode"`
|
||||||
|
Account []struct {
|
||||||
|
Accid string `json:"accid"`
|
||||||
|
} `json:"account"`
|
||||||
|
} `json:"sso"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get system state from NF/NFs
|
||||||
|
func GetSSOFromAAAA(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("GetSSOFromAAAA processing... ")
|
||||||
|
|
||||||
|
vars := r.URL.Query()
|
||||||
|
ticket := vars["ticket"]
|
||||||
|
if len(ticket) == 0 {
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("ticket:", ticket)
|
||||||
|
|
||||||
|
log.Debugf("r.RemoteAddr:%s r.Host: %s", r.RemoteAddr, r.Host)
|
||||||
|
|
||||||
|
aaaaIp := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
|
||||||
|
omcIp := r.Host[:strings.Index(r.Host, ":")]
|
||||||
|
|
||||||
|
log.Debugf("aaaaIp=%s omcIp=%s", aaaaIp, omcIp)
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:8080/qryUserByTicket", aaaaIp)
|
||||||
|
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
aaaaTicket := &AAAATicket{
|
||||||
|
Ticket: ticket[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := json.Marshal(aaaaTicket)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to json.Marshal:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Post(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Post:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("response:", response)
|
||||||
|
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
ssoResult := new(SSOResult)
|
||||||
|
json.Unmarshal(response.Body(), ssoResult)
|
||||||
|
var accid string
|
||||||
|
if len(ssoResult.SSO.Account) != 0 {
|
||||||
|
accid = ssoResult.SSO.Account[0].Accid
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("accid:", accid)
|
||||||
|
exist, err := dborm.XormIsExistUser(accid)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token := oauth.GenRandToken("aaaa") // Generate new token to session ID
|
||||||
|
affected, err := dborm.XormInsertSession(accid, r.RemoteAddr, token,
|
||||||
|
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormInsertSession:", err)
|
||||||
|
if affected == -1 {
|
||||||
|
services.ResponseForbidden403MultiLoginNotAllowed(w)
|
||||||
|
} else {
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if exist == true {
|
||||||
|
redirectUrl := fmt.Sprintf("http://%s:8888/home.html?user=%s&token=%s", omcIp, accid, token)
|
||||||
|
services.ResponseRedirect(w, redirectUrl, accid, token)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
services.ResponseForbidden403NotPermission(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
66
features/cm/exec_linux.go
Normal file
66
features/cm/exec_linux.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package cm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExecCmd(command string) error {
|
||||||
|
log.Debug("Exec command:", command)
|
||||||
|
|
||||||
|
cmd := exec.Command("/bin/bash", "-c", command)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Tracef("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("exe cmd error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Error("Start error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Error("Wait error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecShell(command string) error {
|
||||||
|
in := bytes.NewBuffer(nil)
|
||||||
|
cmd := exec.Command("sh")
|
||||||
|
cmd.Stdin = in
|
||||||
|
in.WriteString(command)
|
||||||
|
in.WriteString("exit\n")
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecOsCmd(command, os string) error {
|
||||||
|
log.Debugf("Exec %s command:%s", os, command)
|
||||||
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch os {
|
||||||
|
case "Linux":
|
||||||
|
cmd = exec.Command(command)
|
||||||
|
case "Windows":
|
||||||
|
cmd = exec.Command("cmd", "/C", command)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Tracef("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("exe cmd error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
53
features/cm/exec_windows.go
Normal file
53
features/cm/exec_windows.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package cm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExecCmd(command string) error {
|
||||||
|
log.Debug("Exec command:", command)
|
||||||
|
|
||||||
|
cmd := exec.Command("cmd", "/C", command)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Tracef("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("exe cmd error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
log.Error("Start error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
log.Error("Wait error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecOsCmd(command, os string) error {
|
||||||
|
log.Debugf("Exec %s command:%s", os, command)
|
||||||
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch os {
|
||||||
|
case "Linux":
|
||||||
|
cmd = exec.Command(command)
|
||||||
|
case "Windows":
|
||||||
|
cmd = exec.Command("cmd", "/C", command)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Tracef("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("exe cmd error: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
151
features/cm/license.go
Normal file
151
features/cm/license.go
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
package cm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// License
|
||||||
|
LicenseUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/license"
|
||||||
|
NeLicenseUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/license/{neId}"
|
||||||
|
|
||||||
|
CustomLicenseUri = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/license"
|
||||||
|
CustomNeLicenseUri = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/license/{neId}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UploadLicenseFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("UploadLicenseFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// neTypeUpper := strings.ToUpper(neType)
|
||||||
|
// neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadLicenseFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DownloadLicenseFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// // neTypeUpper := strings.ToUpper(neType)
|
||||||
|
// //neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
// version := vars["version"]
|
||||||
|
// if version == "" {
|
||||||
|
// log.Error("version is empty")
|
||||||
|
// services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
// neSoftware, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// } else if len(*neSoftware) == 0 {
|
||||||
|
// err := global.ErrCMNotFoundTargetSoftware
|
||||||
|
// log.Error(err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fileName := (*neSoftware)[0]["file_name"]
|
||||||
|
// path := (*neSoftware)[0]["path"]
|
||||||
|
// md5Sum := (*neSoftware)[0]["md5_sum"]
|
||||||
|
|
||||||
|
// services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteLcenseFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// neTypeUpper := strings.ToUpper(neType)
|
||||||
|
// //neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
// version := vars["version"]
|
||||||
|
// if version == "" {
|
||||||
|
// log.Error("version is empty")
|
||||||
|
// services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
// neSoftware, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// } else if len(*neSoftware) == 0 {
|
||||||
|
// err := global.ErrCMNotFoundTargetSoftware
|
||||||
|
// log.Error(err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
// affected, err := dborm.XormDeleteDataByWhere(where, "ne_software")
|
||||||
|
// if err != nil || affected == 0 {
|
||||||
|
// log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fileName := (*neSoftware)[0]["file_name"]
|
||||||
|
// path := (*neSoftware)[0]["path"]
|
||||||
|
// filePath := fmt.Sprintf("%s/%s", path, fileName)
|
||||||
|
// err = os.Remove(filePath)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Faile to Remove:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
906
features/cm/ne.go
Normal file
906
features/cm/ne.go
Normal file
@@ -0,0 +1,906 @@
|
|||||||
|
package cm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriParamOmcNeConfig = config.DefaultUriPrefix + "/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig"
|
||||||
|
// NE CM export/import
|
||||||
|
NeCmUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm"
|
||||||
|
// NE info
|
||||||
|
UriNeInfo = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo"
|
||||||
|
// NE backup file
|
||||||
|
UriNeCmFile = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}"
|
||||||
|
// service action uri, action: start/stop/restart
|
||||||
|
UriNeService = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/service/{action}"
|
||||||
|
// nf instance action uri, action: start/stop/restart
|
||||||
|
UriNeInstance = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/instance/{action}"
|
||||||
|
|
||||||
|
CustomUriParamOmcNeConfig = config.UriPrefix + "/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig"
|
||||||
|
CustomNeCmUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm"
|
||||||
|
CustomUriNeInfo = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo"
|
||||||
|
CustomUriNeCmFile = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}"
|
||||||
|
// service action uri, action: start/stop/restart
|
||||||
|
CustomUriNeService = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/service/{action}"
|
||||||
|
// nf instance action uri, action: start/stop/restart
|
||||||
|
CustomUriNeInstance = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/instance/{action}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNeInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetNeInfo processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// no, _ := strconv.ParseInt(neId, 10, 64)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response services.DataResponse
|
||||||
|
response.Data = neInfo
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
type OmcNeConfig struct {
|
||||||
|
NeId string `json:"neId" xorm:"ne_id"` // 网元标识(内部),
|
||||||
|
RmUID string `json:"rmUID" xorm:"rm_uid"` // rmUID 网元唯一标识
|
||||||
|
NeName string `json:"neName" xorm:"ne_name"` // 网元名称(内部)/友好名称(北向资源/性能等使用)
|
||||||
|
PvFlag string `json:"pvFlag" xorm:"pv_flag"` // 网元虚实性标识 VNF/PNF: 虚拟/物理
|
||||||
|
Province string `json:"province" xorm:"province"` // 网元所在省份
|
||||||
|
VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称
|
||||||
|
// ManagedBy string `json:"managedBy" xorm:"managed_by"` // 管理ManagedElement的ManagementNode对象类的DN值
|
||||||
|
Dn string `json:"dn" xorm:"dn"` // 资源里边的ManagedBy,性能的Dn,网络唯一标识
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostNeInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostNeInfo processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Body:", string(body))
|
||||||
|
|
||||||
|
neInfo := new(dborm.NeInfo)
|
||||||
|
err = json.Unmarshal(body, neInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to json.Unmarshal:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neInfo.UpdateTime = time.Now().Format(time.DateTime)
|
||||||
|
log.Debug("NE info:", neInfo)
|
||||||
|
|
||||||
|
hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port)
|
||||||
|
//hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
apiUri := fmt.Sprintf(UriParamOmcNeConfig, strings.ToLower(neInfo.NeType))
|
||||||
|
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
omcNeConfig := &OmcNeConfig{
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
RmUID: neInfo.RmUID,
|
||||||
|
NeName: neInfo.NeName,
|
||||||
|
PvFlag: neInfo.PvFlag,
|
||||||
|
Province: neInfo.Province,
|
||||||
|
VendorName: neInfo.VendorName,
|
||||||
|
Dn: neInfo.Dn,
|
||||||
|
}
|
||||||
|
body, _ = json.Marshal(omcNeConfig)
|
||||||
|
client := resty.New()
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Put(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Put:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Info("StatusCode: ", response.StatusCode())
|
||||||
|
|
||||||
|
if !config.GetYamlConfig().OMC.Chk2Ne {
|
||||||
|
affected, err := dborm.XormInsertNeInfo(neInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to insert Ne info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow["data"] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
respMsg := make(map[string]interface{})
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
affected, err := dborm.XormInsertNeInfo(neInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormInsertNeInfo:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Infof("Not record affected to insert ne_info")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
log.Info("response body:", string(response.Body()))
|
||||||
|
body := new(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(response.Body(), &body)
|
||||||
|
respMsg["error"] = body
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, response.StatusCode(), respMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutNeInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PutNeInfo processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo := new(dborm.NeInfo)
|
||||||
|
_ = json.Unmarshal(body, neInfo)
|
||||||
|
neInfo.NeType = strings.ToUpper(neType)
|
||||||
|
neInfo.UpdateTime = time.Now().Format(time.DateTime)
|
||||||
|
log.Debug("NE info:", neInfo)
|
||||||
|
|
||||||
|
hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port)
|
||||||
|
//hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
apiUri := fmt.Sprintf(UriParamOmcNeConfig, strings.ToLower(neType))
|
||||||
|
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
omcNeConfig := &OmcNeConfig{
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
RmUID: neInfo.RmUID,
|
||||||
|
NeName: neInfo.NeName,
|
||||||
|
PvFlag: neInfo.PvFlag,
|
||||||
|
Province: neInfo.Province,
|
||||||
|
VendorName: neInfo.VendorName,
|
||||||
|
Dn: neInfo.Dn,
|
||||||
|
}
|
||||||
|
body, _ = json.Marshal(omcNeConfig)
|
||||||
|
client := resty.New()
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Put(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Put:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Info("StatusCode: ", response.StatusCode())
|
||||||
|
|
||||||
|
if !config.GetYamlConfig().OMC.Chk2Ne {
|
||||||
|
affected, err := dborm.XormUpdateNeInfo(neInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to update Ne info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow["data"] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
respMsg := make(map[string]interface{})
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
affected, err := dborm.XormUpdateNeInfo(neInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormUpdateNeInfo:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Infof("Not record affected to insert ne_info")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
log.Info("response body:", string(response.Body()))
|
||||||
|
body := new(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(response.Body(), &body)
|
||||||
|
respMsg["error"] = body
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, response.StatusCode(), respMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteNeInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteNeInfo processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo := new(dborm.NeInfo)
|
||||||
|
_ = json.Unmarshal(body, neInfo)
|
||||||
|
neInfo.NeType = strings.ToUpper(neType)
|
||||||
|
neInfo.NeId = services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
neInfo, err = dborm.XormGetNeInfo(neInfo.NeType, neInfo.NeId)
|
||||||
|
if err != nil || neInfo == nil {
|
||||||
|
log.Error("Failed to delete Ne info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("NE info:", neInfo)
|
||||||
|
|
||||||
|
// if NE in active status, can't delete NE
|
||||||
|
if !IsActiveNF(neInfo) {
|
||||||
|
affected, err := dborm.XormDeleteNeInfo(neInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to delete Ne info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow["data"] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = global.ErrCMCannotDeleteActiveNE
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsActiveNF(neInfo *dborm.NeInfo) bool {
|
||||||
|
log.Debug("IsActiveNF processing... ")
|
||||||
|
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
requestURI := fmt.Sprintf(config.UriPrefix+"/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
strings.ToLower(neInfo.NeType))
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
Get(hostUri + requestURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Get:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExportCmFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExportCmFromNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// neInfo := new(dborm.NeInfo)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get ne_info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neInfo:", neInfo)
|
||||||
|
nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Backup, neTypeLower)
|
||||||
|
isExist, err := global.PathExists(nePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to stat:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if isExist {
|
||||||
|
err = os.RemoveAll(nePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to RemoveAll:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(nePath, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to MkdirAll:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var scpCmd string
|
||||||
|
ipType := global.ParseIPAddr(neInfo.Ip)
|
||||||
|
if neTypeLower != "omc" {
|
||||||
|
if ipType == global.IsIPv4 {
|
||||||
|
scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
|
||||||
|
neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
|
||||||
|
neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
|
||||||
|
} else {
|
||||||
|
scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
|
||||||
|
neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
|
||||||
|
neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ipType == global.IsIPv4 {
|
||||||
|
scpCmd = fmt.Sprintf("scp -r %s@%s:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
|
||||||
|
neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower)
|
||||||
|
} else {
|
||||||
|
scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
|
||||||
|
neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zipFile := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, strings.ToLower(neInfo.NeId), time.Now().Format(global.DateData))
|
||||||
|
zipFilePath := config.GetYamlConfig().OMC.Backup + "/" + zipFile
|
||||||
|
zipCmd := fmt.Sprintf("cd %s/etc && zip -r %s %s/*", config.GetYamlConfig().OMC.Backup, zipFilePath, neTypeLower)
|
||||||
|
|
||||||
|
command := fmt.Sprintf("%s&&%s", scpCmd, zipCmd)
|
||||||
|
|
||||||
|
log.Debug("command:", command)
|
||||||
|
err = ExecCmd(command)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to exec command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
md5Sum, err := global.GetFileMD5Sum(zipFilePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to md5sum:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//log.Debug("md5Str:", md5Sum)
|
||||||
|
path := config.GetYamlConfig().OMC.Backup
|
||||||
|
neBackup := dborm.NeBackup{NeType: neTypeUpper, NeId: neId, FileName: zipFile, Path: path, Md5Sum: md5Sum}
|
||||||
|
_, err = dborm.XormInsertTableOne("ne_backup", neBackup)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//services.ResponseFileWithNameAndMD5(w, http.StatusOK, zipFile, path, md5Sum)
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImportCMJson struct {
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImportCmToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ImportCmToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
var fileName, path string
|
||||||
|
if services.IsJsonContentType(r) {
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Body:", string(body))
|
||||||
|
|
||||||
|
importCMJson := new(ImportCMJson)
|
||||||
|
_ = json.Unmarshal(body, importCMJson)
|
||||||
|
fileName = importCMJson.FileName
|
||||||
|
path = config.GetYamlConfig().OMC.Backup
|
||||||
|
} else {
|
||||||
|
path = config.GetYamlConfig().OMC.Upload
|
||||||
|
fileName, err = services.HandleUploadFile(r, path, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to HandleUploadFile:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filePath := fmt.Sprintf("%s/%s", path, fileName)
|
||||||
|
|
||||||
|
// neInfo := new(dborm.NeInfo)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get ne_info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neInfo:", neInfo)
|
||||||
|
|
||||||
|
md5Sum, err := global.GetFileMD5Sum(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to GetFileMD5Sum:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
|
||||||
|
//log.Debug("neBackup:", neBackup)
|
||||||
|
where := fmt.Sprintf("ne_type='%s' and ne_id='%s' and md5_sum='%s'", neTypeUpper, neId, md5Sum)
|
||||||
|
has, err := dborm.XormExistTableOne("ne_backup", where)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if !has {
|
||||||
|
err = global.ErrCMInvalidBackupFile
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower)
|
||||||
|
// isExist, err := global.PathExists(nePath)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Errorf("Failed to stat:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if isExist {
|
||||||
|
// err = os.RemoveAll(nePath)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Errorf("Failed to remove:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// unzipCmd := fmt.Sprintf("unzip -o %s -d %s", filePath, config.GetYamlConfig().OMC.Upload)
|
||||||
|
|
||||||
|
// var scpCmd string
|
||||||
|
// ipType := global.ParseIPAddr(neInfo.Ip)
|
||||||
|
// if ipType == global.IsIPv4 {
|
||||||
|
// scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@%s:%s", config.GetYamlConfig().OMC.Upload,
|
||||||
|
// neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir)
|
||||||
|
// } else {
|
||||||
|
// scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@[%s]:%s", config.GetYamlConfig().OMC.Upload,
|
||||||
|
// neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = ExecCmd(fmt.Sprintf("%s && %s", unzipCmd, scpCmd))
|
||||||
|
// if err != nil {
|
||||||
|
// log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower)
|
||||||
|
// isExist, err := global.PathExists(nePath)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Errorf("Failed to stat:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if isExist {
|
||||||
|
// err = os.RemoveAll(nePath)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Errorf("Failed to remove:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
var scpZipCmd string
|
||||||
|
ipType := global.ParseIPAddr(neInfo.Ip)
|
||||||
|
if ipType == global.IsIPv4 {
|
||||||
|
scpZipCmd = fmt.Sprintf("scp -r %s %s@%s:%s", filePath,
|
||||||
|
config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
|
||||||
|
} else {
|
||||||
|
scpZipCmd = fmt.Sprintf("scp -r %s %s@[%s]:%s", filePath,
|
||||||
|
config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
|
||||||
|
}
|
||||||
|
err = ExecCmd(scpZipCmd)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + fileName
|
||||||
|
var unzipCmd string
|
||||||
|
if neTypeLower != "omc" {
|
||||||
|
unzipCmd = fmt.Sprintf("sudo unzip -o %s -d %s", neFilePath, config.GetYamlConfig().NE.EtcDir)
|
||||||
|
} else {
|
||||||
|
unzipCmd = fmt.Sprintf("sudo unzip -oj %s -d %s/etc", neFilePath, config.GetYamlConfig().NE.OmcDir)
|
||||||
|
}
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
|
||||||
|
cmd := exec.Command("ssh", sshHost, unzipCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Tracef("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute rpm command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadNeBackupFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DownloadNeBackupFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
//neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
fileName := vars["fileName"]
|
||||||
|
if fileName == "" {
|
||||||
|
log.Error("fileName is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
|
||||||
|
neBackup, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neBackup) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetBackupFile
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := (*neBackup)[0]["path"]
|
||||||
|
md5Sum := (*neBackup)[0]["md5_sum"]
|
||||||
|
|
||||||
|
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteNeBackupFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteNeBackupFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
//neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
fileName := vars["fileName"]
|
||||||
|
if fileName == "" {
|
||||||
|
log.Error("fileName is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
|
||||||
|
neBackup, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neBackup) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetBackupFile
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
where := fmt.Sprintf("ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
|
||||||
|
affected, err := dborm.XormDeleteDataByWhere(where, "ne_backup")
|
||||||
|
if err != nil || affected == 0 {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path := (*neBackup)[0]["path"]
|
||||||
|
filePath := fmt.Sprintf("%s/%s", path, fileName)
|
||||||
|
err = os.Remove(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Remove:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostNeServiceAction(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostNeServiceAction processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
action := vars["action"]
|
||||||
|
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// neInfo := new(dborm.NeInfo)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get ne_info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neInfo:", neInfo)
|
||||||
|
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
|
||||||
|
switch neTypeLower {
|
||||||
|
case "omc":
|
||||||
|
actionCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh %s", config.GetYamlConfig().NE.OmcDir, action)
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to execute ssh %s omc:%v", action, err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "ims":
|
||||||
|
switch action {
|
||||||
|
case "start", "stop":
|
||||||
|
actionCmd := fmt.Sprintf("sudo ims-%s", action)
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to execute %s command:%v", actionCmd, err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "restart":
|
||||||
|
actionCmd := "sudo ims-stop && sudo ims-start"
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to execute %s command:%v", actionCmd, err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = global.ErrCMUnknownServiceAction
|
||||||
|
log.Errorf("%v, action:%s", err, action)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
actionCmd := fmt.Sprintf("sudo systemctl %s %s.service", action, neTypeLower)
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostNeInstanceAction(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostNeInstanceAction processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//neTypeUpper := strings.ToUpper(neType)
|
||||||
|
//neTypeLower := strings.ToLower(neType)
|
||||||
|
action := vars["action"]
|
||||||
|
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// neInfo := new(dborm.NeInfo)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get ne_info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neInfo:", neInfo)
|
||||||
|
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
|
||||||
|
switch action {
|
||||||
|
case "poweron":
|
||||||
|
actionCmd := "sudo poweron"
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh %s omc:", action, err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "poweroff":
|
||||||
|
actionCmd := "sudo poweroff"
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh sudo poweroff:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "reboot":
|
||||||
|
actionCmd := "sudo reboot"
|
||||||
|
cmd := exec.Command("ssh", sshHost, actionCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh sudo reboot:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = global.ErrCMUnknownInstanceAction
|
||||||
|
log.Errorf("%v, action:%s", err, action)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
242
features/cm/param.go
Normal file
242
features/cm/param.go
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
package cm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// parameter config management
|
||||||
|
ParamConfigUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}"
|
||||||
|
|
||||||
|
CustomParamConfigUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetParamConfigFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetParamConfigFromNF processing... ")
|
||||||
|
|
||||||
|
// data := make([]map[string]interface{}, 1)
|
||||||
|
var response services.DataResponse
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
|
||||||
|
getNeInfoPattern := fmt.Sprintf(config.UriPrefix+"/databaseManagement/v1/%s/ne_info", config.GetYamlConfig().Database.Name)
|
||||||
|
getNeInfoURI := restHostPort + getNeInfoPattern
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", true, false)
|
||||||
|
if neId == "" {
|
||||||
|
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%s'", neType)
|
||||||
|
} else {
|
||||||
|
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%v'+and+ne_id+in+%v", neType, neId)
|
||||||
|
}
|
||||||
|
log.Debug("getNeInfoURI:", getNeInfoURI)
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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(getNeInfoURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get from database is failure!")
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("NE info:", string(resp.Body()))
|
||||||
|
|
||||||
|
// var neList []dborm.NeInfo
|
||||||
|
neList, _ := dborm.XormParseResult(resp.Body())
|
||||||
|
|
||||||
|
if len(neList) >= 1 {
|
||||||
|
s := neList[0]
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", s.Ip, s.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostParamConfigToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostParamConfigToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// no, _ := strconv.ParseInt(neId, 10, 64)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: POST ", requestURI2NF)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Post(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to POST to NF:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusNoContent, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutParamConfigToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PutParamConfigToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// no, _ := strconv.ParseInt(neId, 10, 64)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: PUT ", requestURI2NF)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Put(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Put to NF:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusNoContent, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteParamConfigToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteParamConfigToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", false, false)
|
||||||
|
|
||||||
|
// no, _ := strconv.ParseInt(neId, 10, 64)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: DELETE ", requestURI2NF)
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
response, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
Delete(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to delete parameter:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusNoContent, response)
|
||||||
|
}
|
||||||
911
features/cm/software.go
Normal file
911
features/cm/software.go
Normal file
@@ -0,0 +1,911 @@
|
|||||||
|
package cm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SoftwareStatusUploaded = "Uploaded"
|
||||||
|
SoftwareStatusInactive = "Inactive"
|
||||||
|
SoftwareStatusActive = "Active"
|
||||||
|
DigestsSignOkString = "digests signatures OK"
|
||||||
|
SoftwareVerifiedOk = "Verified OK"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriSoftware = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}"
|
||||||
|
UriSoftwareNE = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}"
|
||||||
|
|
||||||
|
CustomUriSoftware = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}"
|
||||||
|
CustomUriSoftwareNE = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/software/{version}/{neId}"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 验证签名
|
||||||
|
func verify_signature(public_key_name string, source_cms_file string, source_file string) bytes.Buffer {
|
||||||
|
cmd := exec.Command("/usr/local/omc/run/iv", "verify_signature", public_key_name, source_cms_file, source_file)
|
||||||
|
var out bytes.Buffer
|
||||||
|
cmd.Stdout = &out
|
||||||
|
cmd.Env = append(os.Environ(),
|
||||||
|
"FOO=duplicate_value", // 重复被忽略
|
||||||
|
"FOO=actual_value", // 实际被使用
|
||||||
|
)
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadSoftwareFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("UploadSoftwareFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false)
|
||||||
|
|
||||||
|
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("io.ReadAll is failed:", err)
|
||||||
|
// services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// neSWBody := new(dborm.NeSoftware)
|
||||||
|
// _ = json.Unmarshal(body, neSWBody)
|
||||||
|
// log.Trace("neSoftware:", neSWBody)
|
||||||
|
|
||||||
|
softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower)
|
||||||
|
fileName, err := services.HandleUploadFile(r, softwarePath, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to HandleUploadFile:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePrefix := fileName[:strings.Index(fileName, ".zip")]
|
||||||
|
filePath := fmt.Sprintf("%s/%s", softwarePath, fileName)
|
||||||
|
log.Debugf("filePath:%s filePrefix:%s softwarePath:%s", filePath, filePrefix, softwarePath)
|
||||||
|
cmd := exec.Command("unzip", "-o", filePath)
|
||||||
|
cmd.Dir = softwarePath
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec outpout:%s", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to unzip:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
md5File, err := global.GetFileMD5Sum(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to GetFileMD5Sum:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if md5File != md5Param {
|
||||||
|
err = global.ErrCMNotMatchMD5File
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rpmFileName := filePrefix + ".rpm"
|
||||||
|
if config.GetYamlConfig().OMC.CheckSign {
|
||||||
|
rpmFilePath := softwarePath + "/" + rpmFileName
|
||||||
|
cmsFileName := rpmFileName + ".cms"
|
||||||
|
cmsFilePath := softwarePath + "/" + cmsFileName
|
||||||
|
log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey)
|
||||||
|
result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath)
|
||||||
|
log.Debug("result:", result.String())
|
||||||
|
if !strings.Contains(result.String(), SoftwareVerifiedOk) {
|
||||||
|
err = global.ErrCMNotMatchSignFile
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// cmd := exec.Command("rpm", "-K", filePath)
|
||||||
|
// out, err := cmd.CombinedOutput()
|
||||||
|
// log.Debugf("Exec outpout:%s", string(out))
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to execute rpm:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !strings.Contains(string(out), DigestsSignOkString) {
|
||||||
|
// err = global.ErrCMNotMatchSignFile
|
||||||
|
// log.Error(err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
//neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
|
||||||
|
//log.Debug("neBackup:", neBackup)
|
||||||
|
where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
has, err := dborm.XormExistTableOne("ne_software", where)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if has {
|
||||||
|
err = global.ErrCMExistSoftwareFile
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neSoftware := dborm.NeSoftware{
|
||||||
|
NeType: neTypeUpper,
|
||||||
|
FileName: rpmFileName,
|
||||||
|
Path: softwarePath,
|
||||||
|
Version: version,
|
||||||
|
Md5Sum: md5Param,
|
||||||
|
Comment: neType + " 5GC " + version,
|
||||||
|
//Comment: neSWBody.Comment,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormInsertTableOne("ne_software", neSoftware)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("UploadSoftwareMultiFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false)
|
||||||
|
|
||||||
|
softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower)
|
||||||
|
err = os.MkdirAll(softwarePath, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Mkdir:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//fileName, err := services.HandleUploadFile(r, softwarePath, "")
|
||||||
|
|
||||||
|
// 解析multipart/form-data请求
|
||||||
|
err = r.ParseMultipartForm(200 << 20) // 200MB
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to ParseMultipartForm:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件和数据
|
||||||
|
swFile := r.MultipartForm.File["file"]
|
||||||
|
cmsFile := r.MultipartForm.File["cms"]
|
||||||
|
data := r.MultipartForm.Value["comment"]
|
||||||
|
|
||||||
|
var softwareFileName, cmsFileName, comment string
|
||||||
|
|
||||||
|
// 处理软件rpm/deb文件
|
||||||
|
if len(swFile) > 0 {
|
||||||
|
file := swFile[0]
|
||||||
|
// 打开文件
|
||||||
|
f, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Open:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// 创建本地文件
|
||||||
|
dst, err := os.Create(softwarePath + "/" + file.Filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Create:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
softwareFileName = file.Filename
|
||||||
|
// 将文件内容拷贝到本地文件
|
||||||
|
_, err = io.Copy(dst, f)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Copy:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理cms文件
|
||||||
|
if len(cmsFile) > 0 {
|
||||||
|
file := cmsFile[0]
|
||||||
|
// 打开文件
|
||||||
|
f, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Open:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// 创建本地文件
|
||||||
|
dst, err := os.Create(softwarePath + "/" + file.Filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Create:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
cmsFileName = file.Filename
|
||||||
|
// 将文件内容拷贝到本地文件
|
||||||
|
_, err = io.Copy(dst, f)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Copy:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理数据
|
||||||
|
if len(data) > 0 {
|
||||||
|
comment = data[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.GetYamlConfig().OMC.CheckSign && cmsFileName != "" {
|
||||||
|
rpmFilePath := softwarePath + "/" + softwareFileName
|
||||||
|
cmsFileName := cmsFileName
|
||||||
|
cmsFilePath := softwarePath + "/" + cmsFileName
|
||||||
|
log.Debugf("cmsFilePath:%s rpmFilePath:%s publicKey:%s", rpmFilePath, cmsFilePath, config.GetYamlConfig().Auth.PublicKey)
|
||||||
|
result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath)
|
||||||
|
log.Debug("result:", result.String())
|
||||||
|
if !strings.Contains(result.String(), SoftwareVerifiedOk) {
|
||||||
|
err = global.ErrCMNotMatchSignFile
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// cmd := exec.Command("rpm", "-K", filePath)
|
||||||
|
// out, err := cmd.CombinedOutput()
|
||||||
|
// log.Debugf("Exec outpout:%s", string(out))
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to execute rpm:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !strings.Contains(string(out), DigestsSignOkString) {
|
||||||
|
// err = global.ErrCMNotMatchSignFile
|
||||||
|
// log.Error(err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// //neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
|
||||||
|
// //log.Debug("neBackup:", neBackup)
|
||||||
|
// where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
// has, err := dborm.XormExistTableOne("ne_software", where)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// } else if has == true {
|
||||||
|
// err = global.ErrCMExistSoftwareFile
|
||||||
|
// log.Error(err)
|
||||||
|
// services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
neSoftware := dborm.NeSoftware{
|
||||||
|
NeType: neTypeUpper,
|
||||||
|
FileName: softwareFileName,
|
||||||
|
Path: softwarePath,
|
||||||
|
Version: version,
|
||||||
|
Md5Sum: md5Param,
|
||||||
|
Comment: comment,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormInsertTableOne("ne_software", neSoftware)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DownloadSoftwareFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
//neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
neSoftware, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neSoftware) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetSoftware
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := (*neSoftware)[0]["file_name"]
|
||||||
|
path := (*neSoftware)[0]["path"]
|
||||||
|
md5Sum := (*neSoftware)[0]["md5_sum"]
|
||||||
|
|
||||||
|
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteSoftwareFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
//neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
neSoftware, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neSoftware) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetSoftware
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
where := fmt.Sprintf("ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
affected, err := dborm.XormDeleteDataByWhere(where, "ne_software")
|
||||||
|
if err != nil || affected == 0 {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := (*neSoftware)[0]["file_name"]
|
||||||
|
path := (*neSoftware)[0]["path"]
|
||||||
|
filePath := fmt.Sprintf("%s/%s", path, fileName)
|
||||||
|
err = os.Remove(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to Remove:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DistributeSoftwareFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neId := vars["neId"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("neId is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
neSoftware, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neSoftware) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetSoftware
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neSoftware:", neSoftware)
|
||||||
|
|
||||||
|
sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId)
|
||||||
|
neVersion, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neVersion:", neVersion)
|
||||||
|
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
|
||||||
|
mkdirCmd := fmt.Sprintf("sudo mkdir -p %s/software/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower)
|
||||||
|
cmd := exec.Command("ssh", sshHost, mkdirCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to mkdir:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := (*neSoftware)[0]["file_name"]
|
||||||
|
path := (*neSoftware)[0]["path"]
|
||||||
|
srcFile := fmt.Sprintf("%s/%s", path, fileName)
|
||||||
|
|
||||||
|
scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User,
|
||||||
|
neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
|
||||||
|
cmd = exec.Command("scp", "-r", srcFile, scpDir)
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + fileName
|
||||||
|
cpCmd := fmt.Sprintf("sudo cp -f %s %s/software/%s", neFilePath,
|
||||||
|
config.GetYamlConfig().NE.OmcDir, neTypeLower)
|
||||||
|
cmd = exec.Command("ssh", sshHost, cpCmd)
|
||||||
|
out, err = cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute cp command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*neVersion) == 0 {
|
||||||
|
neVersionData := dborm.NeVersion{
|
||||||
|
NeType: neTypeUpper,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
Version: (*neSoftware)[0]["version"],
|
||||||
|
FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
|
||||||
|
PreVersion: "",
|
||||||
|
PreFile: "",
|
||||||
|
Status: SoftwareStatusInactive,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormInsertTableOne("ne_version", neVersionData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
|
||||||
|
neVersionData := dborm.NeVersion{
|
||||||
|
NeType: neTypeUpper,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
Version: (*neSoftware)[0]["version"],
|
||||||
|
FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName),
|
||||||
|
PreVersion: (*neVersion)[0]["version"],
|
||||||
|
PreFile: (*neVersion)[0]["file_path"],
|
||||||
|
Status: SoftwareStatusInactive,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to UpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ActiveSoftwareToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neId := vars["neId"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("neId is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version)
|
||||||
|
neSoftware, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neSoftware) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetSoftware
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neVersion:", neSoftware)
|
||||||
|
|
||||||
|
sql = fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s' and version='%s'", neTypeUpper, neId, version)
|
||||||
|
neVersion, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neVersion) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetNeVersion
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neVersion:", neVersion)
|
||||||
|
|
||||||
|
if !config.GetYamlConfig().OMC.TestMode {
|
||||||
|
filePath := (*neVersion)[0]["file_path"]
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
|
||||||
|
fileType := global.IsRpmOrDebPackage(filePath)
|
||||||
|
if fileType == 1 {
|
||||||
|
rpmCmd := fmt.Sprintf("sudo rpm -Uvh '%s'", filePath)
|
||||||
|
cmd := exec.Command("ssh", sshHost, rpmCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute rpm command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if fileType == 2 {
|
||||||
|
dpkgCmd := fmt.Sprintf("sudo dpkg -i '%s'", filePath)
|
||||||
|
cmd := exec.Command("ssh", sshHost, dpkgCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute dpkg command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := global.ErrCMUnknownSoftwareFormat
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch neTypeLower {
|
||||||
|
case "omc":
|
||||||
|
restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir)
|
||||||
|
cmd := exec.Command("ssh", sshHost, restartCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh restart omc:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "ims":
|
||||||
|
restartCmd := "sudo ims-stop && sudo ims-start"
|
||||||
|
cmd := exec.Command("ssh", sshHost, restartCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh sudo systemctl command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower)
|
||||||
|
cmd := exec.Command("ssh", sshHost, restartCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh sudo systemctl command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
|
||||||
|
neVersionData := dborm.NeVersion{
|
||||||
|
Status: SoftwareStatusActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to UpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ActiveSoftwareToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neTypeUpper := strings.ToUpper(neType)
|
||||||
|
neTypeLower := strings.ToLower(neType)
|
||||||
|
|
||||||
|
version := vars["version"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("version is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neId := vars["neId"]
|
||||||
|
if version == "" {
|
||||||
|
log.Error("neId is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neTypeUpper, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sql := fmt.Sprintf("select * from ne_version where ne_type='%s' and ne_id='%s'", neTypeUpper, neId)
|
||||||
|
neVersion, err := dborm.XormGetDataBySQL(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to XormGetDataBySQL:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
} else if len(*neVersion) == 0 {
|
||||||
|
err := global.ErrCMNotFoundTargetNeVersion
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neVersion:", neVersion)
|
||||||
|
|
||||||
|
filePath := (*neVersion)[0]["pre_file"]
|
||||||
|
if filePath == "" {
|
||||||
|
err := global.ErrCMNotFoundRollbackNeVersion
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.GetYamlConfig().OMC.TestMode {
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
|
||||||
|
fileType := global.IsRpmOrDebPackage(filePath)
|
||||||
|
if fileType == 1 {
|
||||||
|
rpmCmd := fmt.Sprintf("sudo rpm -Uvh --oldpackage '%s'", filePath)
|
||||||
|
cmd := exec.Command("ssh", sshHost, rpmCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute rpm command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if fileType == 2 {
|
||||||
|
dpkgCmd := fmt.Sprintf("sudo dpkg -i '%s'", filePath)
|
||||||
|
cmd := exec.Command("ssh", sshHost, dpkgCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute dpkg command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := global.ErrCMUnknownSoftwareFormat
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch neTypeLower {
|
||||||
|
case "omc":
|
||||||
|
restartCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh restart", config.GetYamlConfig().NE.OmcDir)
|
||||||
|
cmd := exec.Command("ssh", sshHost, restartCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh restart omc:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "ims":
|
||||||
|
restartCmd := "sudo ims-stop && sudo ims-start"
|
||||||
|
cmd := exec.Command("ssh", sshHost, restartCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh sudo systemctl command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
restartCmd := fmt.Sprintf("sudo systemctl restart %s.service", neTypeLower)
|
||||||
|
cmd := exec.Command("ssh", sshHost, restartCmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to execute ssh sudo systemctl command:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"])
|
||||||
|
neVersionData := dborm.NeVersion{
|
||||||
|
Version: (*neVersion)[0]["pre_version"],
|
||||||
|
FilePath: (*neVersion)[0]["pre_file"],
|
||||||
|
PreVersion: "-",
|
||||||
|
PreFile: "-",
|
||||||
|
NewVersion: (*neVersion)[0]["version"],
|
||||||
|
NewFile: (*neVersion)[0]["file_path"],
|
||||||
|
Status: SoftwareStatusActive,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormUpdateTableById(idNeVersion, "ne_version", neVersionData)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to UpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
134
features/dbrest/backup.go
Normal file
134
features/dbrest/backup.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package dbrest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 系统备份-数据库备份
|
||||||
|
UriDbBackup = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbBackup"
|
||||||
|
CustomUriDbBackup = config.UriPrefix + "/dataManagement/{apiVersion}/dbBackup" // for external
|
||||||
|
|
||||||
|
// 系统备份-文件备份
|
||||||
|
UriConfBackup = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/confBackup"
|
||||||
|
CustomUriConfBackup = config.UriPrefix + "/dataManagement/{apiVersion}/confBackup" // for external
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
// DbBackup 系统备份-数据库备份1
|
||||||
|
func DbBackup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dbConfigHost := conf.Get("database.host").(string)
|
||||||
|
dbConfigUser := conf.Get("database.user").(string)
|
||||||
|
dbConfigPassword := conf.Get("database.password").(string)
|
||||||
|
dbConfigBackup := conf.Get("database.backup").(string)
|
||||||
|
|
||||||
|
// 备份SQL文件路径
|
||||||
|
fileName := "database_backup_" + time.Now().Format("20060102150405") + ".sql"
|
||||||
|
backupFile := dbConfigBackup + "/" + fileName
|
||||||
|
|
||||||
|
// 执行mysqldump命令进行备份
|
||||||
|
cmd := exec.Command("mysqldump", "-u", dbConfigUser, "-p"+dbConfigPassword, "-h", dbConfigHost, "--all-databases", ">", backupFile)
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备份结果
|
||||||
|
res, err := dborm.DbClient.XEngine.Exec("INSERT INTO `sys_backup`(`id`, `created_at`, `updated_at`, `backup_type`, `backup_way`, `name`, `path`) VALUES (null, ?, ?, '1', '0', ?, ?);", time.Now(), time.Now(), fileName, backupFile)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, res)
|
||||||
|
log.Info("Backup completed successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 系统备份-文件备份0
|
||||||
|
func ConfBackup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dbConfigBackup := conf.Get("database.backup").(string)
|
||||||
|
etcDir := conf.Get("ne.omcdir").(string)
|
||||||
|
|
||||||
|
// 文件名
|
||||||
|
fileName := "conf_backup_" + time.Now().Format("20060102150405") + ".tar.gz"
|
||||||
|
backupFile := dbConfigBackup + "/" + fileName
|
||||||
|
|
||||||
|
err := createTarGz(etcDir, backupFile)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备份结果
|
||||||
|
res, err := dborm.DbClient.XEngine.Exec("INSERT INTO `sys_backup`(`id`, `created_at`, `updated_at`, `backup_type`, `backup_way`, `name`, `path`) VALUES (null, ?, ?, '1', '0', ?, ?);", time.Now(), time.Now(), fileName, backupFile)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, res)
|
||||||
|
log.Info("Backup completed successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打压缩
|
||||||
|
func createTarGz(source, target string) error {
|
||||||
|
tarFile, err := os.Create(target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tarFile.Close()
|
||||||
|
|
||||||
|
gw := gzip.NewWriter(tarFile)
|
||||||
|
defer gw.Close()
|
||||||
|
|
||||||
|
tw := tar.NewWriter(gw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := tar.FileInfoHeader(info, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
relPath, err := filepath.Rel(source, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header.Name = relPath
|
||||||
|
|
||||||
|
if err := tw.WriteHeader(header); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !info.Mode().IsRegular() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(tw, file)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
916
features/dbrest/dbrest.go
Normal file
916
features/dbrest/dbrest.go
Normal file
@@ -0,0 +1,916 @@
|
|||||||
|
package dbrest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type XormResponse struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type XormInsertResponse struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// database management rest pattern, discard
|
||||||
|
XormGetDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
|
||||||
|
XormSelectDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/select/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
XormInsertDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/insert/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
XormUpdateDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/update/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
XormDeleteDataUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/delete/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
|
||||||
|
CustomXormGetDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
|
||||||
|
CustomXormSelectDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/select/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
CustomXormInsertDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/insert/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
CustomXormUpdateDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/update/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
CustomXormDeleteDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/delete/{elementTypeValue}/{objectTypeValue}"
|
||||||
|
|
||||||
|
XormCommonUri = config.DefaultUriPrefix + "/databaseManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for internal
|
||||||
|
XormDatabaseUri = config.DefaultUriPrefix + "/database/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for crontask
|
||||||
|
XormExtDataUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external
|
||||||
|
XormDataSQLUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external
|
||||||
|
|
||||||
|
CustomXormCommonUri = config.UriPrefix + "/databaseManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for internal
|
||||||
|
CustomXormExtDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external
|
||||||
|
CustomXormDataSQLUri = config.UriPrefix + "/dataManagement/{apiVersion}/{elementTypeValue}/{objectTypeValue}" // for external
|
||||||
|
|
||||||
|
// 查询数据库连接情况
|
||||||
|
UriDbConnection = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbConnection"
|
||||||
|
CustomUriDbConnection = config.UriPrefix + "/dataManagement/{apiVersion}/dbConnection" // for external
|
||||||
|
|
||||||
|
// 终结非法的数据库连接
|
||||||
|
UriDbStop = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/dbStop"
|
||||||
|
CustomUriDbStop = config.UriPrefix + "/dataManagement/{apiVersion}/dbStop" // for external
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
var xormResponse XormResponse
|
||||||
|
|
||||||
|
var XEngine *xorm.Engine
|
||||||
|
|
||||||
|
type DatabaseClient struct {
|
||||||
|
dbType string
|
||||||
|
dbUrl string
|
||||||
|
dbConnMaxLifetime time.Duration
|
||||||
|
dbMaxIdleConns int
|
||||||
|
dbMaxOpenConns int
|
||||||
|
IsShowSQL bool
|
||||||
|
|
||||||
|
XEngine *xorm.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
var DbClient DatabaseClient
|
||||||
|
|
||||||
|
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
|
||||||
|
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbUser, dbPassword, dbHost, dbPort, dbName)
|
||||||
|
DbClient.dbType = dbType
|
||||||
|
DbClient.dbConnMaxLifetime = 0
|
||||||
|
DbClient.dbMaxIdleConns = 0
|
||||||
|
DbClient.dbMaxOpenConns = 0
|
||||||
|
if log.GetLevel() == log.LOG_TRACE {
|
||||||
|
DbClient.IsShowSQL = true
|
||||||
|
}
|
||||||
|
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbType, dbUser, dbHost, dbPort, dbName)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connet database:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
|
||||||
|
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
|
||||||
|
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
|
||||||
|
if DbClient.IsShowSQL {
|
||||||
|
DbClient.XEngine.ShowSQL(true)
|
||||||
|
}
|
||||||
|
XEngine = DbClient.XEngine
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUriSQLArray(r *http.Request) []string {
|
||||||
|
var sa []string
|
||||||
|
vars := r.URL.Query()
|
||||||
|
|
||||||
|
// 默认SQL
|
||||||
|
if s, ok := vars["SQL"]; ok {
|
||||||
|
for _, r := range s {
|
||||||
|
if r != "" {
|
||||||
|
sa = append(sa, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询总数
|
||||||
|
if totalSQL, ok := vars["totalSQL"]; ok {
|
||||||
|
if totalSQL[0] != "" {
|
||||||
|
sa = append(sa, totalSQL[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 查询列表
|
||||||
|
if rowsSQL, ok := vars["rowsSQL"]; ok {
|
||||||
|
if rowsSQL[0] != "" {
|
||||||
|
sa = append(sa, rowsSQL[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sa) == 0 {
|
||||||
|
log.Info("SQL is not exist")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("SQL array:", sa)
|
||||||
|
return sa
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get table name from SQL
|
||||||
|
func GetTableNameFromSQL(s string) string {
|
||||||
|
ls := strings.ToLower(s)
|
||||||
|
i1 := strings.Index(ls, "from")
|
||||||
|
i2 := strings.Index(ls, "where")
|
||||||
|
|
||||||
|
var ts string
|
||||||
|
if i1 > 0 {
|
||||||
|
if i2 > 0 && i2 > i1 {
|
||||||
|
ts = ls[i1+4 : i2]
|
||||||
|
}
|
||||||
|
if i2 < 0 {
|
||||||
|
ts = ls[i1+4:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tn := strings.Trim(ts, " ")
|
||||||
|
log.Debug("i1:", i1, "i2:", i2, "tn:", tn)
|
||||||
|
return tn
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTableName(sql string) string {
|
||||||
|
ls := strings.ToLower(sql)
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`from\s+(\S+)`)
|
||||||
|
matches := re.FindStringSubmatch(ls)
|
||||||
|
if len(matches) < 2 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsQuerySQL(s string) bool {
|
||||||
|
ts := strings.Trim(strings.ToLower(s), " ")
|
||||||
|
if strings.Index(ts, "select") != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorm Get data from database
|
||||||
|
func ExtDatabaseExecSQL(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExtDatabaseExecSQL processing... ")
|
||||||
|
|
||||||
|
var sql []string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
_, err = services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//vars := mux.Vars(r)
|
||||||
|
//tblName := vars["objectTypeValue"]
|
||||||
|
sql = GetUriSQLArray(r)
|
||||||
|
// select as must, todo ...
|
||||||
|
|
||||||
|
ls := services.ExtGetUriPageLimitString(r)
|
||||||
|
|
||||||
|
// data := make([]map[string]interface{}, 0)
|
||||||
|
// xormResponse := make([]map[string]interface{}, len(sql))
|
||||||
|
var xormResponse XormResponse
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
for i, s := range sql {
|
||||||
|
log.Tracef("SQL[%d]: %s", i, sql[i])
|
||||||
|
|
||||||
|
//rows := make([]map[string]interface{}, 0)
|
||||||
|
mapRows := make(map[string]interface{})
|
||||||
|
|
||||||
|
if s != "" {
|
||||||
|
// err = XEngine.SQL(s).Find(&rows)
|
||||||
|
// if IsQuerySQL(s) == false {
|
||||||
|
// services.ResponseNotAcceptable406QuerySQLError(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
querySQL := s
|
||||||
|
if i == (len(sql) - 1) {
|
||||||
|
querySQL = querySQL + " " + ls
|
||||||
|
}
|
||||||
|
log.Debug("querySQL:", querySQL)
|
||||||
|
rows, err := DbClient.XEngine.Exec(querySQL)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("SQL failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tableName := GetTableName(s)
|
||||||
|
log.Debugf("s:%s tableName:%s", s, tableName)
|
||||||
|
mapRows[tableName] = rows
|
||||||
|
data = append(data, mapRows)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
xormResponse.Data = data
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, xormResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorm Get data from database
|
||||||
|
func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExtDatabaseGetData processing... ")
|
||||||
|
|
||||||
|
var sql []string
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pack := "dbrest"
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
module := ""
|
||||||
|
dbname := vars["elementTypeValue"]
|
||||||
|
tbname := vars["objectTypeValue"]
|
||||||
|
|
||||||
|
log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)
|
||||||
|
|
||||||
|
// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to get permission:", err)
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// log.Error("Not permission!")
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
sql = GetUriSQLArray(r)
|
||||||
|
// select as must, todo ...
|
||||||
|
if sql == nil {
|
||||||
|
wc := services.GetUriLocString(r)
|
||||||
|
if wc == "" {
|
||||||
|
sql = append(sql, fmt.Sprintf("select * from %s", tbname))
|
||||||
|
} else {
|
||||||
|
sql = append(sql, fmt.Sprintf("select * from %s where %s", tbname, wc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := services.ExtGetUriPageLimitString(r)
|
||||||
|
|
||||||
|
// data := make([]map[string]interface{}, 0)
|
||||||
|
// xormResponse := make([]map[string]interface{}, len(sql))
|
||||||
|
var xormResponse XormResponse
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
for i, s := range sql {
|
||||||
|
log.Tracef("SQL[%d]: %s", i, sql[i])
|
||||||
|
|
||||||
|
rows := make([]map[string]interface{}, 0)
|
||||||
|
mapRows := make(map[string]interface{})
|
||||||
|
|
||||||
|
if s != "" {
|
||||||
|
// err = XEngine.SQL(s).Find(&rows)
|
||||||
|
if IsQuerySQL(s) == false {
|
||||||
|
services.ResponseNotAcceptable406QuerySQLError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
querySQL := s
|
||||||
|
if i == (len(sql) - 1) {
|
||||||
|
querySQL = querySQL + " " + ls
|
||||||
|
}
|
||||||
|
log.Debug("querySQL:", querySQL)
|
||||||
|
rows, err = DbClient.XEngine.QueryInterface(querySQL)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("SQL failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tableName := GetTableName(s)
|
||||||
|
log.Debugf("s:%s tableName:%s", s, tableName)
|
||||||
|
mapRows[tableName] = rows
|
||||||
|
data = append(data, mapRows)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
xormResponse.Data = data
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, xormResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExtDatabaseInsertData processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
module := ""
|
||||||
|
dbname := vars["elementTypeValue"]
|
||||||
|
tbname := vars["objectTypeValue"]
|
||||||
|
pack := "dbrest"
|
||||||
|
|
||||||
|
log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)
|
||||||
|
|
||||||
|
// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to get permission:", err)
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// log.Error("permission deny!")
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
log.Debug("Request body:", string(body), "dataObject:", tbname)
|
||||||
|
insertData := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(body, &insertData)
|
||||||
|
|
||||||
|
tn, sql := dborm.ConstructInsertSQL(tbname, insertData)
|
||||||
|
log.Tracef("tn: %s sql :%s", tn, sql)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
var affected int64
|
||||||
|
for _, s := range sql {
|
||||||
|
res, err := xSession.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Insert failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, _ := res.RowsAffected()
|
||||||
|
affected = affected + n
|
||||||
|
}
|
||||||
|
xSession.Commit()
|
||||||
|
// affected, err := InsertDataWithJson(insertData)
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tn] = row
|
||||||
|
// xormResponse.Data = mapRow
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExtDatabaseUpdateData processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
module := ""
|
||||||
|
dbname := vars["elementTypeValue"]
|
||||||
|
tbname := vars["objectTypeValue"]
|
||||||
|
pack := "dbrest"
|
||||||
|
|
||||||
|
log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack)
|
||||||
|
|
||||||
|
// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to get permission:", err)
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// log.Error("Not permission!")
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
wc := services.GetUriLocString(r)
|
||||||
|
|
||||||
|
log.Debug("Request body:", string(body), "Tablename:", tbname, "wc:", wc)
|
||||||
|
updateData := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(body, &updateData)
|
||||||
|
|
||||||
|
tn, sql := dborm.ConstructUpdateSQL(tbname, updateData, wc)
|
||||||
|
log.Tracef("tn: %s sql :%s", tn, sql)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
var affected int64
|
||||||
|
for _, s := range sql {
|
||||||
|
res, err := xSession.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Update failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, _ := res.RowsAffected()
|
||||||
|
affected = affected + n
|
||||||
|
}
|
||||||
|
xSession.Commit()
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tn] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtDatabaseDeleteData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExtDatabaseDeleteData processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
module := ""
|
||||||
|
dbname := vars["elementTypeValue"]
|
||||||
|
tbname := vars["objectTypeValue"]
|
||||||
|
pack := "dbreset"
|
||||||
|
|
||||||
|
log.Debugf("token:%s, method:%s, module:%, dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack)
|
||||||
|
|
||||||
|
// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to get permission:", err)
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// log.Error("Not permission!")
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
wc := services.GetUriLocString(r)
|
||||||
|
|
||||||
|
log.Debug("Table name:", tbname, "wc:", wc)
|
||||||
|
|
||||||
|
sql := dborm.ConstructDeleteSQL(tbname, wc)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
res, err := xSession.Exec(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Update failed, err:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
affected, _ := res.RowsAffected()
|
||||||
|
xSession.Commit()
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow["data"] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorm Get data from database
|
||||||
|
func DatabaseGetData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseGetData processing... ")
|
||||||
|
|
||||||
|
var sql []string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
_, err = services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tblName := vars["objectTypeValue"]
|
||||||
|
sql = GetUriSQLArray(r)
|
||||||
|
// select as must, todo ...
|
||||||
|
|
||||||
|
if sql == nil {
|
||||||
|
wc := services.GetUriWhereString(r)
|
||||||
|
if wc == "" {
|
||||||
|
sql = append(sql, fmt.Sprintf("select * from %s", tblName))
|
||||||
|
} else {
|
||||||
|
sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := services.GetUriPageLimitString(r)
|
||||||
|
|
||||||
|
// data := make([]map[string]interface{}, 0)
|
||||||
|
// xormResponse := make([]map[string]interface{}, len(sql))
|
||||||
|
var xormResponse XormResponse
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
for i, s := range sql {
|
||||||
|
log.Tracef("SQL[%d]: %s", i, sql[i])
|
||||||
|
|
||||||
|
rows := make([]map[string]interface{}, 0)
|
||||||
|
mapRows := make(map[string]interface{})
|
||||||
|
|
||||||
|
if s != "" {
|
||||||
|
// err = XEngine.SQL(s).Find(&rows)
|
||||||
|
if IsQuerySQL(s) == false {
|
||||||
|
services.ResponseNotAcceptable406QuerySQLError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
querySQL := s
|
||||||
|
if i == (len(sql) - 1) {
|
||||||
|
querySQL = querySQL + " " + ls
|
||||||
|
}
|
||||||
|
log.Debug("querySQL:", querySQL)
|
||||||
|
rows, err = DbClient.XEngine.QueryInterface(querySQL)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("SQL failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tableName := GetTableName(s)
|
||||||
|
log.Debugf("s:%s tableName:%s", s, tableName)
|
||||||
|
mapRows[tableName] = rows
|
||||||
|
data = append(data, mapRows)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
xormResponse.Data = data
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, xormResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DatabaseInsertData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseInsertData processing... ")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tableName := vars["objectTypeValue"]
|
||||||
|
log.Debug("Request body:", string(body), "tableName:", tableName)
|
||||||
|
insertData := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(body, &insertData)
|
||||||
|
|
||||||
|
// 操作日志的IP
|
||||||
|
if tableName == "operation_log" || tableName == "security_log" {
|
||||||
|
ipAddr := strings.Split(r.RemoteAddr, ":")[0]
|
||||||
|
s := insertData["data"].([]any)
|
||||||
|
a := s[0].(map[string]any)
|
||||||
|
a["op_ip"] = ipAddr
|
||||||
|
} else if tableName == "mml_log" {
|
||||||
|
ipAddr := strings.Split(r.RemoteAddr, ":")[0]
|
||||||
|
s := insertData["data"].([]any)
|
||||||
|
a := s[0].(map[string]any)
|
||||||
|
a["ip"] = ipAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
tn, sql := dborm.ConstructInsertSQL(tableName, insertData)
|
||||||
|
log.Tracef("tn: %s sql :%s", tn, sql)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
var affected int64
|
||||||
|
for _, s := range sql {
|
||||||
|
res, err := xSession.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Insert failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, _ := res.RowsAffected()
|
||||||
|
affected = affected + n
|
||||||
|
}
|
||||||
|
xSession.Commit()
|
||||||
|
// affected, err := InsertDataWithJson(insertData)
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tn] = row
|
||||||
|
// xormResponse.Data = mapRow
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseUpdateData processing... ")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tblName := vars["objectTypeValue"]
|
||||||
|
wc := services.GetUriWhereString(r)
|
||||||
|
|
||||||
|
log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc)
|
||||||
|
updateData := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(body, &updateData)
|
||||||
|
|
||||||
|
tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc)
|
||||||
|
log.Tracef("tn: %s sql :%s", tn, sql)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
var affected int64
|
||||||
|
for _, s := range sql {
|
||||||
|
res, err := xSession.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Update failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, _ := res.RowsAffected()
|
||||||
|
affected = affected + n
|
||||||
|
}
|
||||||
|
xSession.Commit()
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tn] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DatabaseDeleteData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseDeleteData processing... ")
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tblName := vars["objectTypeValue"]
|
||||||
|
wc := services.GetUriWhereString(r)
|
||||||
|
|
||||||
|
log.Debug("Table name:", tblName, "wc:", wc)
|
||||||
|
|
||||||
|
sql := dborm.ConstructDeleteSQL(tblName, wc)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
res, err := xSession.Exec(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Update failed, err:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
affected, _ := res.RowsAffected()
|
||||||
|
xSession.Commit()
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow["data"] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接用户实例
|
||||||
|
func DbConnection(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if dborm.DbClient.XEngine == nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, "无连接")
|
||||||
|
}
|
||||||
|
// 查询实例
|
||||||
|
result, err := dborm.DbClient.XEngine.QueryString("SHOW PROCESSLIST;")
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 500, err.Error())
|
||||||
|
}
|
||||||
|
filterData := []map[string]string{}
|
||||||
|
for _, r := range result {
|
||||||
|
if r["User"] != "system user" {
|
||||||
|
filterData = append(filterData, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sleep:连接处于空闲状态,没有执行任何操作。
|
||||||
|
// Query:连接正在执行一个查询语句。
|
||||||
|
// Execute:连接正在执行一个准备好的 SQL 语句。
|
||||||
|
// Connect:连接正在建立但尚未完成。
|
||||||
|
services.ResponseWithJson(w, 200, filterData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭数据库连接
|
||||||
|
func DbStop(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if dborm.DbClient.XEngine == nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, "无连接")
|
||||||
|
}
|
||||||
|
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs struct {
|
||||||
|
ID string `json:"ID" validate:"required"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭
|
||||||
|
rse, err := dborm.DbClient.XEngine.Exec("KILL ?;", bodyArgs.ID)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, rse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// xorm Get data from database
|
||||||
|
func TaskDatabaseGetData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseGetData processing... ")
|
||||||
|
|
||||||
|
var sql []string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tblName := vars["objectTypeValue"]
|
||||||
|
sql = GetUriSQLArray(r)
|
||||||
|
// select as must, todo ...
|
||||||
|
|
||||||
|
if sql == nil {
|
||||||
|
wc := services.GetUriWhereString(r)
|
||||||
|
if wc == "" {
|
||||||
|
sql = append(sql, fmt.Sprintf("select * from %s", tblName))
|
||||||
|
} else {
|
||||||
|
sql = append(sql, fmt.Sprintf("select * from %s where %s", tblName, wc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ls := services.GetUriPageLimitString(r)
|
||||||
|
|
||||||
|
// data := make([]map[string]interface{}, 0)
|
||||||
|
// xormResponse := make([]map[string]interface{}, len(sql))
|
||||||
|
var xormResponse XormResponse
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
for i, s := range sql {
|
||||||
|
log.Tracef("SQL[%d]: %s", i, sql[i])
|
||||||
|
|
||||||
|
rows := make([]map[string]interface{}, 0)
|
||||||
|
mapRows := make(map[string]interface{})
|
||||||
|
|
||||||
|
if s != "" {
|
||||||
|
// err = XEngine.SQL(s).Find(&rows)
|
||||||
|
if IsQuerySQL(s) == false {
|
||||||
|
services.ResponseNotAcceptable406QuerySQLError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
querySQL := s
|
||||||
|
if i == (len(sql) - 1) {
|
||||||
|
querySQL = querySQL + " " + ls
|
||||||
|
}
|
||||||
|
log.Debug("querySQL:", querySQL)
|
||||||
|
rows, err = DbClient.XEngine.QueryInterface(querySQL)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("SQL failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tableName := GetTableName(s)
|
||||||
|
log.Debugf("s:%s tableName:%s", s, tableName)
|
||||||
|
mapRows[tableName] = rows
|
||||||
|
data = append(data, mapRows)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
xormResponse.Data = data
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, xormResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskDatabaseInsertData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseInsertData processing... ")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tableName := vars["objectTypeValue"]
|
||||||
|
log.Debug("Request body:", string(body), "tableName:", tableName)
|
||||||
|
insertData := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(body, &insertData)
|
||||||
|
|
||||||
|
tn, sql := dborm.ConstructInsertSQL(tableName, insertData)
|
||||||
|
log.Tracef("tn: %s sql :%s", tn, sql)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
var affected int64
|
||||||
|
for _, s := range sql {
|
||||||
|
res, err := xSession.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Insert failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, _ := res.RowsAffected()
|
||||||
|
affected = affected + n
|
||||||
|
}
|
||||||
|
xSession.Commit()
|
||||||
|
// affected, err := InsertDataWithJson(insertData)
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tn] = row
|
||||||
|
// xormResponse.Data = mapRow
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskDatabaseUpdateData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseUpdateData processing... ")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tblName := vars["objectTypeValue"]
|
||||||
|
wc := services.GetUriWhereString(r)
|
||||||
|
|
||||||
|
log.Debug("Request body:", string(body), "Table name:", tblName, "wc:", wc)
|
||||||
|
updateData := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(body, &updateData)
|
||||||
|
|
||||||
|
tn, sql := dborm.ConstructUpdateSQL(tblName, updateData, wc)
|
||||||
|
log.Tracef("tn: %s sql :%s", tn, sql)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
var affected int64
|
||||||
|
for _, s := range sql {
|
||||||
|
res, err := xSession.Exec(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Update failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, _ := res.RowsAffected()
|
||||||
|
affected = affected + n
|
||||||
|
}
|
||||||
|
xSession.Commit()
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tn] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskDatabaseDeleteData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DatabaseDeleteData processing... ")
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
tblName := vars["objectTypeValue"]
|
||||||
|
wc := services.GetUriWhereString(r)
|
||||||
|
|
||||||
|
log.Debug("Table name:", tblName, "wc:", wc)
|
||||||
|
|
||||||
|
sql := dborm.ConstructDeleteSQL(tblName, wc)
|
||||||
|
xSession := DbClient.XEngine.NewSession()
|
||||||
|
defer xSession.Close()
|
||||||
|
res, err := xSession.Exec(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Update failed, err:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
affected, _ := res.RowsAffected()
|
||||||
|
xSession.Commit()
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow["data"] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
194
features/file/file.go
Normal file
194
features/file/file.go
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/file"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// parameter config management
|
||||||
|
UriFile = config.DefaultUriPrefix + "/fileManagement/{apiVersion}/{location}/file"
|
||||||
|
|
||||||
|
CustomUriFile = config.UriPrefix + "/fileManagement/{apiVersion}/{location}/file"
|
||||||
|
|
||||||
|
// 获取磁盘列表
|
||||||
|
UriDiskList = config.DefaultUriPrefix + "/fileManagement/{apiVersion}/files/diskList"
|
||||||
|
|
||||||
|
// 获取文件列表
|
||||||
|
UriListFiles = config.DefaultUriPrefix + "/fileManagement/{apiVersion}/files/listFiles"
|
||||||
|
)
|
||||||
|
|
||||||
|
// func init() {
|
||||||
|
// routes.Register("POST", UriFile, UploadFile, nil)
|
||||||
|
// routes.Register("GET", UriFile, DownloadFile, nil)
|
||||||
|
// routes.Register("DELETE", UriFile, DeleteFile, nil)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func UploadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("UploadFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Http request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
location := vars["location"]
|
||||||
|
if location == "" {
|
||||||
|
log.Error("location is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params := r.URL.Query()
|
||||||
|
rename, ok := params["rename"]
|
||||||
|
if !ok {
|
||||||
|
log.Info("rename parameter is not exist")
|
||||||
|
}
|
||||||
|
log.Debug("rename:", rename)
|
||||||
|
|
||||||
|
var path, fileName string
|
||||||
|
if len(rename) > 0 {
|
||||||
|
fileName = rename[0]
|
||||||
|
}
|
||||||
|
if location == "upload" {
|
||||||
|
path = config.GetYamlConfig().OMC.Upload
|
||||||
|
fileName, err = services.HandleUploadFile(r, path, fileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to HandleUploadFile:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path = config.GetYamlConfig().OMC.FrontUpload
|
||||||
|
fileName, err = services.HandleUploadFile(r, path, fileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to HandleUploadFile:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debugf("upload file=%s to path=%s", fileName, path)
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DownloadFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
location := vars["location"]
|
||||||
|
if location == "" {
|
||||||
|
log.Error("location is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全路径文件下载
|
||||||
|
filePath := r.URL.Query().Get("path")
|
||||||
|
if location == "path" && filePath != "" {
|
||||||
|
// 截取文件路径
|
||||||
|
dir := filepath.Dir(filePath)
|
||||||
|
// 截取文件名
|
||||||
|
fileName := filepath.Base(filePath)
|
||||||
|
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, dir, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params := r.URL.Query()
|
||||||
|
fileNames, ok := params["loc"]
|
||||||
|
if !ok {
|
||||||
|
log.Info("loc parameter is not exist")
|
||||||
|
}
|
||||||
|
var path string
|
||||||
|
if location == "upload" {
|
||||||
|
path = config.GetYamlConfig().OMC.Upload
|
||||||
|
} else {
|
||||||
|
path = config.GetYamlConfig().OMC.FrontUpload
|
||||||
|
}
|
||||||
|
for _, fileName := range fileNames {
|
||||||
|
services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, "")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFile(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteFile processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("neType is empty")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 磁盘列表
|
||||||
|
func DiskList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
disks := make([]map[string]string, 0)
|
||||||
|
|
||||||
|
partitions, err := disk.Partitions(false)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseWithJson(w, 200, disks)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, partition := range partitions {
|
||||||
|
usage, err := disk.Usage(partition.Mountpoint)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
disks = append(disks, map[string]string{
|
||||||
|
"size": file.FormatFileSize(float64(usage.Total)),
|
||||||
|
"used": file.FormatFileSize(float64(usage.Used)),
|
||||||
|
"avail": file.FormatFileSize(float64(usage.Free)),
|
||||||
|
"pcent": fmt.Sprintf("%.1f%%", usage.UsedPercent),
|
||||||
|
"target": partition.Device,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, disks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文件列表 /files/search
|
||||||
|
func ListFiles(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs FileOption
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil || dborm.DbClient.XEngine == nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := GetFileList(bodyArgs)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, files)
|
||||||
|
}
|
||||||
85
features/file/model.go
Normal file
85
features/file/model.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileOption struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Search string `json:"search"`
|
||||||
|
ContainSub bool `json:"containSub"`
|
||||||
|
Expand bool `json:"expand"`
|
||||||
|
Dir bool `json:"dir"`
|
||||||
|
ShowHidden bool `json:"showHidden"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"pageSize"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileInfo struct {
|
||||||
|
Fs afero.Fs `json:"-"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Extension string `json:"extension"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
IsDir bool `json:"isDir"`
|
||||||
|
IsSymlink bool `json:"isSymlink"`
|
||||||
|
IsHidden bool `json:"isHidden"`
|
||||||
|
LinkPath string `json:"linkPath"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
MimeType string `json:"mimeType"`
|
||||||
|
UpdateTime time.Time `json:"updateTime"`
|
||||||
|
ModTime time.Time `json:"modTime"`
|
||||||
|
FileMode os.FileMode `json:"-"`
|
||||||
|
Items []*FileInfo `json:"items"`
|
||||||
|
ItemTotal int `json:"itemTotal"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileInfo) search(search string, count int) (files []FileSearchInfo, total int, err error) {
|
||||||
|
cmd := exec.Command("find", f.Path, "-name", fmt.Sprintf("*%s*", search))
|
||||||
|
output, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = cmd.Start(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = cmd.Wait()
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
}()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(output)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
info, err := os.Stat(line)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
total++
|
||||||
|
if total > count {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
files = append(files, FileSearchInfo{
|
||||||
|
Path: line,
|
||||||
|
FileInfo: info,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err = scanner.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileSearchInfo struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
fs.FileInfo
|
||||||
|
}
|
||||||
206
features/file/service.go
Normal file
206
features/file/service.go
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/file"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取文件列表
|
||||||
|
func GetFileList(op FileOption) (FileInfo, error) {
|
||||||
|
var fileInfo FileInfo
|
||||||
|
if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) {
|
||||||
|
return fileInfo, nil
|
||||||
|
}
|
||||||
|
info, err := NewFileInfo(op)
|
||||||
|
if err != nil {
|
||||||
|
return fileInfo, err
|
||||||
|
}
|
||||||
|
fileInfo = *info
|
||||||
|
return fileInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFileInfo(op FileOption) (*FileInfo, error) {
|
||||||
|
var appFs = afero.NewOsFs()
|
||||||
|
|
||||||
|
info, err := appFs.Stat(op.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo := &FileInfo{
|
||||||
|
Fs: appFs,
|
||||||
|
Path: op.Path,
|
||||||
|
Name: info.Name(),
|
||||||
|
IsDir: info.IsDir(),
|
||||||
|
FileMode: info.Mode(),
|
||||||
|
ModTime: info.ModTime(),
|
||||||
|
Size: info.Size(),
|
||||||
|
IsSymlink: file.IsSymlink(info.Mode()),
|
||||||
|
Extension: filepath.Ext(info.Name()),
|
||||||
|
IsHidden: file.IsHidden(op.Path),
|
||||||
|
Mode: fmt.Sprintf("%04o", info.Mode().Perm()),
|
||||||
|
MimeType: file.GetMimeType(op.Path),
|
||||||
|
}
|
||||||
|
if fileInfo.IsSymlink {
|
||||||
|
fileInfo.LinkPath = file.GetSymlink(op.Path)
|
||||||
|
}
|
||||||
|
if op.Expand {
|
||||||
|
if fileInfo.IsDir {
|
||||||
|
if err := listChildren(fileInfo, op.Dir, op.ShowHidden, op.ContainSub, op.Search, op.Page, op.PageSize); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fileInfo, nil
|
||||||
|
} else {
|
||||||
|
if err := getContent(fileInfo); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listChildren(f *FileInfo, dir, showHidden, containSub bool, search string, page, pageSize int) error {
|
||||||
|
afs := &afero.Afero{Fs: f.Fs}
|
||||||
|
var (
|
||||||
|
files []FileSearchInfo
|
||||||
|
err error
|
||||||
|
total int
|
||||||
|
)
|
||||||
|
|
||||||
|
if search != "" && containSub {
|
||||||
|
files, total, err = f.search(search, page*pageSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dirFiles, err := afs.ReadDir(f.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, file := range dirFiles {
|
||||||
|
files = append(files, FileSearchInfo{
|
||||||
|
Path: f.Path,
|
||||||
|
FileInfo: file,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []*FileInfo
|
||||||
|
for _, df := range files {
|
||||||
|
if dir && !df.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := df.Name()
|
||||||
|
fPath := path.Join(df.Path, df.Name())
|
||||||
|
if search != "" {
|
||||||
|
if containSub {
|
||||||
|
fPath = df.Path
|
||||||
|
name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/")
|
||||||
|
} else {
|
||||||
|
lowerName := strings.ToLower(name)
|
||||||
|
lowerSearch := strings.ToLower(search)
|
||||||
|
if !strings.Contains(lowerName, lowerSearch) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !showHidden && file.IsHidden(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f.ItemTotal++
|
||||||
|
isSymlink, isInvalidLink := false, false
|
||||||
|
if file.IsSymlink(df.Mode()) {
|
||||||
|
isSymlink = true
|
||||||
|
info, err := f.Fs.Stat(fPath)
|
||||||
|
if err == nil {
|
||||||
|
df.FileInfo = info
|
||||||
|
} else {
|
||||||
|
isInvalidLink = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInfo := &FileInfo{
|
||||||
|
Fs: f.Fs,
|
||||||
|
Name: name,
|
||||||
|
Size: df.Size(),
|
||||||
|
ModTime: df.ModTime(),
|
||||||
|
FileMode: df.Mode(),
|
||||||
|
IsDir: df.IsDir(),
|
||||||
|
IsSymlink: isSymlink,
|
||||||
|
IsHidden: file.IsHidden(fPath),
|
||||||
|
Extension: filepath.Ext(name),
|
||||||
|
Path: fPath,
|
||||||
|
Mode: fmt.Sprintf("%04o", df.Mode().Perm()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if isSymlink {
|
||||||
|
fileInfo.LinkPath = file.GetSymlink(fPath)
|
||||||
|
}
|
||||||
|
if df.Size() > 0 {
|
||||||
|
fileInfo.MimeType = file.GetMimeType(fPath)
|
||||||
|
}
|
||||||
|
if isInvalidLink {
|
||||||
|
fileInfo.Type = "invalid_link"
|
||||||
|
}
|
||||||
|
items = append(items, fileInfo)
|
||||||
|
}
|
||||||
|
if containSub {
|
||||||
|
f.ItemTotal = total
|
||||||
|
}
|
||||||
|
start := (page - 1) * pageSize
|
||||||
|
end := pageSize + start
|
||||||
|
var result []*FileInfo
|
||||||
|
if start < 0 || start > f.ItemTotal || end < 0 || start > end {
|
||||||
|
result = items
|
||||||
|
} else {
|
||||||
|
if end > f.ItemTotal {
|
||||||
|
result = items[start:]
|
||||||
|
} else {
|
||||||
|
result = items[start:end]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Items = result
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContent(f *FileInfo) error {
|
||||||
|
if f.Size <= 10*1024*1024 {
|
||||||
|
afs := &afero.Afero{Fs: f.Fs}
|
||||||
|
cByte, err := afs.ReadFile(f.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(cByte) > 0 && detectBinary(cByte) {
|
||||||
|
return errors.New("ErrFileCanNotRead")
|
||||||
|
}
|
||||||
|
f.Content = string(cByte)
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New("ErrFileCanNotRead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectBinary(buf []byte) bool {
|
||||||
|
whiteByte := 0
|
||||||
|
n := 1024
|
||||||
|
if len(buf) < 1024 {
|
||||||
|
n = len(buf)
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if (buf[i] >= 0x20) || buf[i] == 9 || buf[i] == 10 || buf[i] == 13 {
|
||||||
|
whiteByte++
|
||||||
|
} else if buf[i] <= 6 || (buf[i] >= 14 && buf[i] <= 31) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return whiteByte < 1
|
||||||
|
}
|
||||||
88
features/firewall/api_firewall.go
Normal file
88
features/firewall/api_firewall.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package firewall
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"ems.agt/features/firewall/model"
|
||||||
|
"ems.agt/features/firewall/service"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 防火墙管理接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 FirewallApi 结构体
|
||||||
|
var apis = &FirewallApi{
|
||||||
|
firewallService: *service.NewServiceFirewall,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/base",
|
||||||
|
Handler: apis.BaseInfo,
|
||||||
|
Middleware: nil, //midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/rule",
|
||||||
|
Handler: apis.Rule,
|
||||||
|
Middleware: nil, //midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/firewallManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防火墙管理
|
||||||
|
//
|
||||||
|
// PATH /firewallManage
|
||||||
|
type FirewallApi struct {
|
||||||
|
firewallService service.ServiceFirewall
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取防火墙基础信息
|
||||||
|
//
|
||||||
|
// GET /base
|
||||||
|
func (s *FirewallApi) BaseInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
data, err := s.firewallService.LoadBaseInfo()
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取防火墙规则列表分页
|
||||||
|
//
|
||||||
|
// GET /rule
|
||||||
|
func (s *FirewallApi) Rule(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.RuleQuerys
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.Type == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := s.firewallService.RulePage(body)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 400, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
}
|
||||||
13
features/firewall/model/firewall.go
Normal file
13
features/firewall/model/firewall.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type Firewall struct {
|
||||||
|
ID int64 `json:"id" xorm:"id"`
|
||||||
|
CreatedAt int64 `json:"createdAt" xorm:"created_at"`
|
||||||
|
UpdatedAt int64 `json:"updatedAt" xorm:"updated_at"`
|
||||||
|
Type string `json:"type" xorm:"type"`
|
||||||
|
Port string `json:"port" xorm:"port"`
|
||||||
|
Protocol string `json:"protocol" xorm:"protocol"`
|
||||||
|
Address string `json:"address" xorm:"address"`
|
||||||
|
Strategy string `json:"strategy" xorm:"strategy"`
|
||||||
|
Description string `json:"description" xorm:"description"`
|
||||||
|
}
|
||||||
64
features/firewall/model/firewall_vo.go
Normal file
64
features/firewall/model/firewall_vo.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type FirewallBaseInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
PingStatus string `json:"pingStatus"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RuleQuerys struct {
|
||||||
|
PageNum int `json:"pageNum" validate:"required,number"`
|
||||||
|
PageSize int `json:"pageSize" validate:"required,number"`
|
||||||
|
Info string `json:"info"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Strategy string `json:"strategy"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FirewallOperation struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=start stop disablePing enablePing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port string `json:"port" validate:"required"`
|
||||||
|
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateFirewallDescription struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port string `json:"port"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address" validate:"required"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleUpdate struct {
|
||||||
|
OldRule PortRuleOperate `json:"oldRule"`
|
||||||
|
NewRule PortRuleOperate `json:"newRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleUpdate struct {
|
||||||
|
OldRule AddrRuleOperate `json:"oldRule"`
|
||||||
|
NewRule AddrRuleOperate `json:"newRule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type BatchRuleOperate struct {
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
Rules []PortRuleOperate `json:"rules"`
|
||||||
|
}
|
||||||
133
features/firewall/repo/repo_firewall.go
Normal file
133
features/firewall/repo/repo_firewall.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/firewall/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoFirewall 结构体
|
||||||
|
var NewRepoFirewall = &RepoFirewall{
|
||||||
|
selectSql: `select
|
||||||
|
id, created_at, updated_at, type, port, protocol, address, strategy, description
|
||||||
|
from monitor_firewall`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"id": "ID",
|
||||||
|
"created_at": "CreatedAt",
|
||||||
|
"updated_at": "UpdatedAt",
|
||||||
|
"type": "Type",
|
||||||
|
"port": "Port",
|
||||||
|
"protocol": "Protocol",
|
||||||
|
"address": "Address",
|
||||||
|
"strategy": "Strategy",
|
||||||
|
"description": "Description",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoFirewall 防火墙 数据层处理
|
||||||
|
type RepoFirewall struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoFirewall) convertResultRows(rows []map[string]any) []model.Firewall {
|
||||||
|
arr := make([]model.Firewall, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
UdmUser := model.Firewall{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&UdmUser, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, UdmUser)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// List 根据实体查询
|
||||||
|
func (r *RepoFirewall) List(f model.Firewall) []model.Firewall {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if f.Type != "" {
|
||||||
|
conditions = append(conditions, "type = ?")
|
||||||
|
params = append(params, f.Type)
|
||||||
|
}
|
||||||
|
if f.Protocol != "" {
|
||||||
|
conditions = append(conditions, "protocol = ?")
|
||||||
|
params = append(params, f.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 新增实体
|
||||||
|
func (r *RepoFirewall) Insert(f model.Firewall) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("monitor_firewall").Insert(f)
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改更新
|
||||||
|
func (r *RepoFirewall) Update(f model.Firewall) int64 {
|
||||||
|
// 查询先
|
||||||
|
var fd model.Firewall
|
||||||
|
if f.Type == "port" {
|
||||||
|
has, err := datasource.DefaultDB().Table("monitor_firewall").Where("type = ? AND port = ? AND protocol = ? AND address = ? AND strategy = ?", "port", f.Port, f.Protocol, f.Address, f.Strategy).Get(&fd)
|
||||||
|
if !has || err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
has, err := datasource.DefaultDB().Table("monitor_firewall").Where("type = ? AND address = ? AND strategy = ?", "address", f.Address, f.Strategy).Get(&fd)
|
||||||
|
if !has || err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.ID = fd.ID
|
||||||
|
|
||||||
|
results, err := datasource.DefaultDB().Table("monitor_firewall").Where("id = ?", f.ID).Update(f)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除实体
|
||||||
|
func (r *RepoFirewall) Delete(id int64) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Where("id = ?", id).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteFirewallRecord 删除实体
|
||||||
|
func (r *RepoFirewall) DeleteFirewallRecord(fType, port, protocol, address, strategy string) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Where("type = ? AND port = ? AND protocol = ? AND address = ? AND strategy = ?", fType, port, protocol, address, strategy).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
207
features/firewall/service/service_firewall.go
Normal file
207
features/firewall/service/service_firewall.go
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/firewall/model"
|
||||||
|
"ems.agt/features/firewall/repo"
|
||||||
|
"ems.agt/lib/core/cmd"
|
||||||
|
"ems.agt/lib/core/utils/firewall"
|
||||||
|
fireClient "ems.agt/lib/core/utils/firewall/client"
|
||||||
|
"ems.agt/lib/core/utils/scan"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceFirewall 结构体
|
||||||
|
var NewServiceFirewall = &ServiceFirewall{
|
||||||
|
repoFirewall: *repo.NewRepoFirewall,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceFirewall 防火墙 服务层处理
|
||||||
|
type ServiceFirewall struct {
|
||||||
|
repoFirewall repo.RepoFirewall
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBaseInfo 获取防火墙基础信息
|
||||||
|
func (s *ServiceFirewall) LoadBaseInfo() (model.FirewallBaseInfo, error) {
|
||||||
|
var baseInfo model.FirewallBaseInfo
|
||||||
|
baseInfo.PingStatus = s.pingStatus()
|
||||||
|
baseInfo.Status = "not running"
|
||||||
|
baseInfo.Version = "-"
|
||||||
|
baseInfo.Name = "-"
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "no such type" {
|
||||||
|
return baseInfo, nil
|
||||||
|
}
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
baseInfo.Name = client.Name()
|
||||||
|
baseInfo.Status, err = client.Status()
|
||||||
|
if err != nil {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
if baseInfo.Status == "not running" {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
baseInfo.Version, err = client.Version()
|
||||||
|
if err != nil {
|
||||||
|
return baseInfo, err
|
||||||
|
}
|
||||||
|
return baseInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBaseInfo 获取防火墙基础信息
|
||||||
|
func (s *ServiceFirewall) RulePage(querys model.RuleQuerys) (map[string]any, error) {
|
||||||
|
var (
|
||||||
|
datas []fireClient.FireInfo
|
||||||
|
backDatas []fireClient.FireInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
data := map[string]any{
|
||||||
|
"total": 0,
|
||||||
|
"rows": backDatas,
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
if querys.Type == "port" {
|
||||||
|
ports, err := client.ListPort()
|
||||||
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
if len(querys.Info) != 0 {
|
||||||
|
for _, port := range ports {
|
||||||
|
if strings.Contains(port.Port, querys.Info) {
|
||||||
|
datas = append(datas, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datas = ports
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addrs, err := client.ListAddress()
|
||||||
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
if len(querys.Info) != 0 {
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if strings.Contains(addr.Address, querys.Info) {
|
||||||
|
datas = append(datas, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datas = addrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var datasFilterStatus []fireClient.FireInfo
|
||||||
|
if len(querys.Status) != 0 {
|
||||||
|
for _, data := range datas {
|
||||||
|
portItem, _ := strconv.Atoi(data.Port)
|
||||||
|
if querys.Status == "free" && !scan.ScanPortWithProto(portItem, data.Protocol) {
|
||||||
|
datasFilterStatus = append(datasFilterStatus, data)
|
||||||
|
}
|
||||||
|
if querys.Status == "used" && scan.ScanPortWithProto(portItem, data.Protocol) {
|
||||||
|
datasFilterStatus = append(datasFilterStatus, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datasFilterStatus = datas
|
||||||
|
}
|
||||||
|
var datasFilterStrategy []fireClient.FireInfo
|
||||||
|
if len(querys.Strategy) != 0 {
|
||||||
|
for _, data := range datasFilterStatus {
|
||||||
|
if querys.Strategy == data.Strategy {
|
||||||
|
datasFilterStrategy = append(datasFilterStrategy, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
datasFilterStrategy = datasFilterStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
total, start, end := len(datasFilterStrategy), (querys.PageNum-1)*querys.PageSize, querys.PageNum*querys.PageSize
|
||||||
|
if start > total {
|
||||||
|
backDatas = make([]fireClient.FireInfo, 0)
|
||||||
|
} else {
|
||||||
|
if end >= total {
|
||||||
|
end = total
|
||||||
|
}
|
||||||
|
backDatas = datasFilterStrategy[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
datasFromDB := s.repoFirewall.List(model.Firewall{})
|
||||||
|
for i := 0; i < len(backDatas); i++ {
|
||||||
|
for _, des := range datasFromDB {
|
||||||
|
if querys.Type != des.Type {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if backDatas[i].Port == des.Port && querys.Type == "port" &&
|
||||||
|
backDatas[i].Protocol == des.Protocol &&
|
||||||
|
backDatas[i].Strategy == des.Strategy &&
|
||||||
|
backDatas[i].Address == des.Address {
|
||||||
|
backDatas[i].Description = des.Description
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if querys.Type == "address" && backDatas[i].Strategy == des.Strategy && backDatas[i].Address == des.Address {
|
||||||
|
backDatas[i].Description = des.Description
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if querys.Type == "port" {
|
||||||
|
for i := 0; i < len(backDatas); i++ {
|
||||||
|
port, _ := strconv.Atoi(backDatas[i].Port)
|
||||||
|
backDatas[i].IsUsed = scan.ScanPort(port)
|
||||||
|
if backDatas[i].Protocol == "udp" {
|
||||||
|
backDatas[i].IsUsed = scan.ScanUDPPort(port)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go s.cleanUnUsedData(client)
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceFirewall) pingStatus() string {
|
||||||
|
if _, err := os.Stat("/etc/sysctl.conf"); err != nil {
|
||||||
|
return "None"
|
||||||
|
}
|
||||||
|
sudo := cmd.SudoHandleCmd()
|
||||||
|
command := fmt.Sprintf("%s cat /etc/sysctl.conf | grep net/ipv4/icmp_echo_ignore_all= ", sudo)
|
||||||
|
stdout, _ := cmd.Exec(command)
|
||||||
|
if stdout == "net/ipv4/icmp_echo_ignore_all=1\n" {
|
||||||
|
return "Enable"
|
||||||
|
}
|
||||||
|
return "Disable"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceFirewall) cleanUnUsedData(client firewall.FirewallClient) {
|
||||||
|
list, _ := client.ListPort()
|
||||||
|
addressList, _ := client.ListAddress()
|
||||||
|
list = append(list, addressList...)
|
||||||
|
if len(list) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
records := s.repoFirewall.List(model.Firewall{})
|
||||||
|
if len(records) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, item := range list {
|
||||||
|
for i := 0; i < len(records); i++ {
|
||||||
|
if records[i].Port == item.Port && records[i].Protocol == item.Protocol && records[i].Strategy == item.Strategy && records[i].Address == item.Address {
|
||||||
|
records = append(records[:i], records[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, record := range records {
|
||||||
|
_ = s.repoFirewall.Delete(record.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
700
features/fm/alarm.go
Normal file
700
features/fm/alarm.go
Normal file
@@ -0,0 +1,700 @@
|
|||||||
|
package fm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlarmStatusClear = 0
|
||||||
|
AlarmStatusActive = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClearTypeUnclear = 0
|
||||||
|
ClearTypeAutoClear = 1
|
||||||
|
ClearTypeManualClear = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AckStateUnacked = 0
|
||||||
|
AckStateAcked = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlarmTypeCommunicationAlarm = 1
|
||||||
|
AlarmTypeEquipmentAlarm = 2
|
||||||
|
AlarmTypeProcessingFailure = 3
|
||||||
|
AlarmTypeEnvironmentalAlarm = 4
|
||||||
|
AlarmTypeQualityOfServiceAlarm = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlarmPerceivedSeverityCritical = 1
|
||||||
|
AlarmPerceivedSeverityMajor = 2
|
||||||
|
AlarmPerceivedSeverityMinor = 3
|
||||||
|
AlarmPerceivedSeverityWarning = 4
|
||||||
|
AlarmPerceivedSeverityEvent = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlarmSeqBeginNumber = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alarm struct {
|
||||||
|
AlarmSeq int `json:"alarmSeq"`
|
||||||
|
AlarmId string `json:"alarmId" xorm:"alarm_id"`
|
||||||
|
NeId string `json:"neId"`
|
||||||
|
AlarmCode int `json:"alarmCode"`
|
||||||
|
AlarmTitle string `json:"alarmTitle"`
|
||||||
|
EventTime string `json:"eventTime"`
|
||||||
|
AlarmType string `json:"alarmType"`
|
||||||
|
OrigSeverity string `json:"origSeverity"`
|
||||||
|
PerceivedSeverity string `json:"perceivedSeverity"`
|
||||||
|
PVFlag string `json:"pvFlag" xorm:"pv_flag"`
|
||||||
|
NeName string `json:"neName"`
|
||||||
|
NeType string `json:"neType"`
|
||||||
|
ObjectUid string `json:"objectUid" xorm:"object_uid"`
|
||||||
|
ObjectName string `json:"objectName" xorm:"object_name"`
|
||||||
|
ObjectType string `json:"objectType" xorm:"object_type"`
|
||||||
|
LocationInfo string `json:"locationInfo"`
|
||||||
|
Province string `json:"province"`
|
||||||
|
AlarmStatus int `json:"alarmStatus"`
|
||||||
|
SpecificProblem string `json:"specificProblem"`
|
||||||
|
SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"`
|
||||||
|
AddInfo string `json:"addInfo"`
|
||||||
|
|
||||||
|
AckState int `json:"ackState"`
|
||||||
|
AckTime sql.NullTime `json:"ackTime"`
|
||||||
|
AckUser string `json:"ackUser"`
|
||||||
|
ClearType int `json:"clearType"` // 0: Unclear, 1: Auto clear, 2: Manual clear
|
||||||
|
ClearTime sql.NullTime `json:"clearTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlarmLog struct {
|
||||||
|
NeType string `json:"neType" xorm:"ne_type"`
|
||||||
|
NeId string `json:"neId" xorm:"ne_id"`
|
||||||
|
AlarmSeq int `json:"alarmSeq" xorm:"alarm_seq"`
|
||||||
|
AlarmId string `json:"alarmId" xorm:"alarm_id"`
|
||||||
|
AlarmCode int `json:"alarmCode" xorm:"alarm_code"`
|
||||||
|
AlarmStatus int `json:"alarmStatus" xorm:"alarm_status"`
|
||||||
|
EventTime string `json:"eventTime" xorm:"event_time"`
|
||||||
|
// ClearTime sql.NullTime `json:"clearTime" xorm:"clear_time"`
|
||||||
|
LogTime string `json:"logTime" xorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// alarm management
|
||||||
|
UriAlarms = config.DefaultUriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms"
|
||||||
|
UriAlarmsFmt = config.DefaultUriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms"
|
||||||
|
|
||||||
|
CustomUriAlarms = config.UriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms"
|
||||||
|
CustomUriAlarmsFmt = config.UriPrefix + "/faultManagement/v1/elementType/%s/objectType/alarms"
|
||||||
|
)
|
||||||
|
|
||||||
|
var xEngine *xorm.Engine
|
||||||
|
|
||||||
|
type DatabaseClient struct {
|
||||||
|
dbType string
|
||||||
|
dbUrl string
|
||||||
|
dbConnMaxLifetime time.Duration
|
||||||
|
dbMaxIdleConns int
|
||||||
|
dbMaxOpenConns int
|
||||||
|
IsShowSQL bool
|
||||||
|
|
||||||
|
XEngine *xorm.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
var DbClient DatabaseClient
|
||||||
|
|
||||||
|
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
|
||||||
|
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbUser, dbPassword, dbHost, dbPort, dbName)
|
||||||
|
DbClient.dbType = dbType
|
||||||
|
DbClient.dbConnMaxLifetime = 0
|
||||||
|
DbClient.dbMaxIdleConns = 0
|
||||||
|
DbClient.dbMaxOpenConns = 0
|
||||||
|
if log.GetLevel() == log.LOG_TRACE {
|
||||||
|
DbClient.IsShowSQL = true
|
||||||
|
}
|
||||||
|
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbType, dbUser, dbHost, dbPort, dbName)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connet database:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
|
||||||
|
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
|
||||||
|
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
|
||||||
|
if DbClient.IsShowSQL {
|
||||||
|
DbClient.XEngine.ShowSQL(true)
|
||||||
|
}
|
||||||
|
xEngine = DbClient.XEngine
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) {
|
||||||
|
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbUser, dbPassword, dbHost, dbPort, dbName)
|
||||||
|
log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbType, dbUser, dbHost, dbPort, dbName)
|
||||||
|
var err error
|
||||||
|
xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect database:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if log.GetLevel() == log.LOG_TRACE {
|
||||||
|
xEngine.ShowSQL(true)
|
||||||
|
}
|
||||||
|
return xEngine, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNeedToAckAlarm(valueJson *dborm.ValueJson, alarm *Alarm) bool {
|
||||||
|
log.Info("IsNeedToAckAlarm processing... ")
|
||||||
|
if valueJson != nil {
|
||||||
|
status, _ := strconv.Atoi(valueJson.AlarmStatus)
|
||||||
|
log.Tracef("alarm.AlarmStatus=%d, alarm.AlarmType=%s, alarm.OrigSeverity=%s", alarm.AlarmStatus, alarm.AlarmType, alarm.OrigSeverity)
|
||||||
|
log.Tracef("status=%d, valueJson.AlarmType=%s, valueJson.OrigSeverity=%s", status, valueJson.AlarmType, valueJson.OrigSeverity)
|
||||||
|
|
||||||
|
if alarm.AlarmStatus == status &&
|
||||||
|
alarm.AlarmType == valueJson.AlarmType &&
|
||||||
|
alarm.OrigSeverity == valueJson.OrigSeverity {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetAlarmAckInfo(valueJson *dborm.ValueJson, alarm *Alarm) {
|
||||||
|
log.Info("SetAlarmAckInfo processing... ")
|
||||||
|
alarm.AckState = AckStateAcked
|
||||||
|
alarm.AckTime.Valid = true
|
||||||
|
alarm.AckTime.Time = time.Now()
|
||||||
|
alarm.AckUser = valueJson.AckUser
|
||||||
|
}
|
||||||
|
|
||||||
|
// process alarm post message from NFs
|
||||||
|
func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostAlarmFromNF processing... ")
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != global.ApiVersionV1 {
|
||||||
|
log.Error("Uri api version is invalid. apiVersion:", apiVer)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("Request body:", string(body))
|
||||||
|
alarmArray := new([]Alarm)
|
||||||
|
|
||||||
|
err = json.Unmarshal(body, &alarmArray)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Unmarshal:", err)
|
||||||
|
services.ResponseBadRequest400InvalidJson(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
valueJson, err := dborm.XormGetAAConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormGetAAConfig:", err)
|
||||||
|
//services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
//return
|
||||||
|
}
|
||||||
|
log.Trace("valueJson:", valueJson)
|
||||||
|
// session := xEngine.NewSession()
|
||||||
|
// defer session.Close()
|
||||||
|
var activeAlarmNum int = 0
|
||||||
|
for _, alarmData := range *alarmArray {
|
||||||
|
log.Debug("alarmData:", alarmData)
|
||||||
|
|
||||||
|
session := xEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
if alarmData.AlarmStatus == AlarmStatusClear {
|
||||||
|
alarmData.ClearType = ClearTypeAutoClear
|
||||||
|
alarmData.ClearTime.Valid = true
|
||||||
|
tm, _ := time.Parse(time.RFC3339, alarmData.EventTime)
|
||||||
|
log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime))
|
||||||
|
alarmData.ClearTime.Time = tm
|
||||||
|
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
|
||||||
|
SetAlarmAckInfo(valueJson, &alarmData)
|
||||||
|
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
|
||||||
|
Cols("alarm_status", "clear_type", "clear_time", "ack_state", "ack_time", "ack_user").
|
||||||
|
Update(alarmData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to update alarm data:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
|
||||||
|
Cols("alarm_status", "clear_type", "clear_time").
|
||||||
|
Update(alarmData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to update alarm data:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Trace("alarmData:", alarmData)
|
||||||
|
var currentSeq string
|
||||||
|
var seq int
|
||||||
|
has, err := xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
|
||||||
|
Desc("alarm_seq").
|
||||||
|
Cols("alarm_seq").
|
||||||
|
Limit(1).
|
||||||
|
Get(¤tSeq)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if has == true {
|
||||||
|
seq, _ = strconv.Atoi(currentSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
|
||||||
|
alarmLog := new(AlarmLog)
|
||||||
|
alarmLog.NeType = alarmData.NeType
|
||||||
|
alarmLog.NeId = alarmData.NeId
|
||||||
|
alarmLog.AlarmSeq = seq
|
||||||
|
alarmLog.AlarmId = alarmData.AlarmId
|
||||||
|
alarmLog.AlarmCode = alarmData.AlarmCode
|
||||||
|
alarmLog.AlarmStatus = alarmData.AlarmStatus
|
||||||
|
alarmLog.EventTime = eventTime
|
||||||
|
log.Debug("alarmLog:", alarmLog)
|
||||||
|
|
||||||
|
affected, err := session.Insert(alarmLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert alarm_log:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: PerceivedSeverity set color
|
||||||
|
var severity string
|
||||||
|
has, err = xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
|
||||||
|
Asc("orig_severity").
|
||||||
|
Cols("orig_severity").
|
||||||
|
Limit(1).
|
||||||
|
Get(&severity)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
|
||||||
|
|
||||||
|
if has == true && severity > alarmData.OrigSeverity {
|
||||||
|
// update exist record
|
||||||
|
_, err := session.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
Update(&Alarm{PerceivedSeverity: severity})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to update alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session.Commit()
|
||||||
|
// for alarm forward time format
|
||||||
|
alarmData.EventTime = eventTime
|
||||||
|
} else {
|
||||||
|
activeAlarmNum++
|
||||||
|
has, err := xEngine.Table("alarm").
|
||||||
|
Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1",
|
||||||
|
alarmData.AlarmId, alarmData.NeType, alarmData.NeId).
|
||||||
|
Exist()
|
||||||
|
if err == nil && has == true {
|
||||||
|
log.Warn("Exist the same alarm")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentSeq string
|
||||||
|
has, err = xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
|
||||||
|
Desc("alarm_seq").
|
||||||
|
//Desc("event_time").
|
||||||
|
Cols("alarm_seq").
|
||||||
|
Limit(1).
|
||||||
|
Get(¤tSeq)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("neType=%s, neId=%s, currentSeq=%s activeAlarmNum=%d",
|
||||||
|
alarmData.NeType, alarmData.NeId, currentSeq, activeAlarmNum)
|
||||||
|
|
||||||
|
if has == true {
|
||||||
|
seq, _ := strconv.Atoi(currentSeq)
|
||||||
|
alarmData.AlarmSeq = seq + 1
|
||||||
|
if alarmData.AlarmSeq > global.MaxInt32Number {
|
||||||
|
alarmData.AlarmSeq = AlarmSeqBeginNumber
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alarmData.AlarmSeq = AlarmSeqBeginNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: PerceivedSeverity set color
|
||||||
|
var severity string
|
||||||
|
has, err = xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
|
||||||
|
Asc("orig_severity").
|
||||||
|
Cols("orig_severity").
|
||||||
|
Limit(1).
|
||||||
|
Get(&severity)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
|
||||||
|
|
||||||
|
if has == false || severity == alarmData.OrigSeverity {
|
||||||
|
alarmData.PerceivedSeverity = alarmData.OrigSeverity
|
||||||
|
} else if severity > alarmData.OrigSeverity {
|
||||||
|
alarmData.PerceivedSeverity = alarmData.OrigSeverity
|
||||||
|
} else {
|
||||||
|
alarmData.PerceivedSeverity = severity
|
||||||
|
// update exist record
|
||||||
|
_, err := session.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
Update(&Alarm{PerceivedSeverity: alarmData.PerceivedSeverity})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to update alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
|
||||||
|
alarmData.ObjectUid = alarmData.NeId
|
||||||
|
alarmData.ObjectType = "VNFM"
|
||||||
|
alarmData.EventTime = eventTime
|
||||||
|
if alarmData.LocationInfo == "" {
|
||||||
|
alarmData.LocationInfo = fmt.Sprintf("Host:%s", r.RemoteAddr)
|
||||||
|
}
|
||||||
|
if alarmData.AddInfo == "" {
|
||||||
|
alarmData.LocationInfo = fmt.Sprintf("subNeInfo:%s", alarmData.NeType)
|
||||||
|
}
|
||||||
|
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
|
||||||
|
SetAlarmAckInfo(valueJson, &alarmData)
|
||||||
|
}
|
||||||
|
log.Debug("alarmData:", alarmData)
|
||||||
|
affected, err := session.Insert(alarmData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert alarm data:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
alarmLog := new(AlarmLog)
|
||||||
|
alarmLog.NeType = alarmData.NeType
|
||||||
|
alarmLog.NeId = alarmData.NeId
|
||||||
|
alarmLog.AlarmSeq = alarmData.AlarmSeq
|
||||||
|
alarmLog.AlarmId = alarmData.AlarmId
|
||||||
|
alarmLog.AlarmCode = alarmData.AlarmCode
|
||||||
|
alarmLog.AlarmStatus = alarmData.AlarmStatus
|
||||||
|
alarmLog.EventTime = eventTime
|
||||||
|
log.Trace("alarmLog:", alarmLog)
|
||||||
|
|
||||||
|
affected, err = session.Insert(alarmLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert alarm_log:", err)
|
||||||
|
}
|
||||||
|
session.Commit()
|
||||||
|
}
|
||||||
|
if config.GetYamlConfig().Alarm.ForwardAlarm {
|
||||||
|
if err = AlarmEmailForward(&alarmData); err != nil {
|
||||||
|
log.Error("Failed to AlarmEmailForward:", err)
|
||||||
|
}
|
||||||
|
if err = AlarmForwardBySMS(&alarmData); err != nil {
|
||||||
|
log.Error("Failed to AlarmForwardBySMS:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process alarm get from NFs
|
||||||
|
func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetAlarmFromNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//var neInfo *dborm.NeInfo
|
||||||
|
var nes []dborm.NeInfo
|
||||||
|
_, err = dborm.XormGetAllNeInfo(&nes)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get all ne info:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ne := range nes {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
|
||||||
|
apiUri := fmt.Sprintf(UriAlarmsFmt, strings.ToLower(ne.NeType))
|
||||||
|
requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
|
||||||
|
log.Debug("requestURI2NF: Get ", requestURI2NF)
|
||||||
|
client := resty.New()
|
||||||
|
response, 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:", err)
|
||||||
|
//services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
body := response.Body()
|
||||||
|
log.Debug("Request body:", string(body))
|
||||||
|
alarmArray := new([]Alarm)
|
||||||
|
err = json.Unmarshal(body, &alarmArray)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Unmarshal:", err)
|
||||||
|
//services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
valueJson, err := dborm.XormGetAAConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormGetAAConfig:", err)
|
||||||
|
//services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if alarmArray == nil {
|
||||||
|
log.Info("Not found sync alarms, neType=%s, neId=%s", ne.NeType, ne.NeId)
|
||||||
|
//services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// session := xEngine.NewSession()
|
||||||
|
// defer session.Close()
|
||||||
|
var activeAlarmNum int = 0
|
||||||
|
for _, alarmData := range *alarmArray {
|
||||||
|
log.Debug("alarmData:", alarmData)
|
||||||
|
|
||||||
|
session := xEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
// todo: clear alarm ....
|
||||||
|
if alarmData.AlarmStatus == AlarmStatusClear {
|
||||||
|
exist, err := session.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
|
||||||
|
Exist()
|
||||||
|
if err == nil || exist == false {
|
||||||
|
log.Info("Not found active alarm: ne_id=%s, alarm_id=%s", alarmData.NeId, alarmData.AlarmId)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
alarmData.ClearType = ClearTypeAutoClear
|
||||||
|
alarmData.ClearTime.Valid = true
|
||||||
|
tm, _ := time.Parse(time.RFC3339, alarmData.EventTime)
|
||||||
|
log.Debugf("EventTime:%s tm:%d tm-datetime:%s", alarmData.EventTime, tm, tm.Local().Format(time.DateTime))
|
||||||
|
alarmData.ClearTime.Time = tm
|
||||||
|
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
|
||||||
|
SetAlarmAckInfo(valueJson, &alarmData)
|
||||||
|
log.Debug("alarmData:", alarmData)
|
||||||
|
affected, err := session.
|
||||||
|
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
|
||||||
|
Cols("alarm_status", "clear_type", "clear_time", "ack_state", "ack_time", "ack_user").
|
||||||
|
Update(alarmData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to update alarm data:", err)
|
||||||
|
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
affected, err := session.
|
||||||
|
Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId).
|
||||||
|
Cols("alarm_status", "clear_type", "clear_time").
|
||||||
|
Update(alarmData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to update alarm data:", err)
|
||||||
|
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eventTime := global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
|
||||||
|
alarmLog := new(AlarmLog)
|
||||||
|
alarmLog.NeType = alarmData.NeType
|
||||||
|
alarmLog.NeId = alarmData.NeId
|
||||||
|
alarmLog.AlarmSeq = alarmData.AlarmSeq
|
||||||
|
alarmLog.AlarmId = alarmData.AlarmId
|
||||||
|
alarmLog.AlarmCode = alarmData.AlarmCode
|
||||||
|
alarmLog.AlarmStatus = alarmData.AlarmStatus
|
||||||
|
alarmLog.EventTime = eventTime
|
||||||
|
log.Debug("alarmLog:", alarmLog)
|
||||||
|
|
||||||
|
affected, err := session.Insert(alarmLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert alarm_log:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: PerceivedSeverity set color
|
||||||
|
var severity string
|
||||||
|
has, err := xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
|
||||||
|
Asc("orig_severity").
|
||||||
|
Cols("orig_severity").
|
||||||
|
Limit(1).
|
||||||
|
Get(&severity)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
|
||||||
|
|
||||||
|
if has == true && severity > alarmData.OrigSeverity {
|
||||||
|
// update exist record
|
||||||
|
_, err := session.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
Update(&Alarm{PerceivedSeverity: severity})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to update alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session.Commit()
|
||||||
|
// for alarm forward time format
|
||||||
|
alarmData.EventTime = eventTime
|
||||||
|
} else {
|
||||||
|
activeAlarmNum++
|
||||||
|
has, err := xEngine.Table("alarm").
|
||||||
|
Where("alarm_id=? and ne_type=? and ne_id=? and alarm_status=1",
|
||||||
|
alarmData.AlarmId, alarmData.NeType, alarmData.NeId).
|
||||||
|
Exist()
|
||||||
|
if err == nil && has == true {
|
||||||
|
log.Warn("Exist the same alarm")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentSeq string
|
||||||
|
has, err = xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=?", alarmData.NeType, alarmData.NeId).
|
||||||
|
Desc("alarm_seq").
|
||||||
|
//Desc("event_time").
|
||||||
|
Cols("alarm_seq").
|
||||||
|
Limit(1).
|
||||||
|
Get(¤tSeq)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("neType=%s, neId=%s, currentSeq=%s, activeAlarmNum=%d",
|
||||||
|
alarmData.NeType, alarmData.NeId, currentSeq, activeAlarmNum)
|
||||||
|
|
||||||
|
if has == true {
|
||||||
|
seq, _ := strconv.Atoi(currentSeq)
|
||||||
|
alarmData.AlarmSeq = seq + 1
|
||||||
|
if alarmData.AlarmSeq > global.MaxInt32Number {
|
||||||
|
alarmData.AlarmSeq = AlarmSeqBeginNumber
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alarmData.AlarmSeq = AlarmSeqBeginNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: PerceivedSeverity set color
|
||||||
|
var severity string
|
||||||
|
has, err = xEngine.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
//OrderBy("FIELD(orig_severity, 'Critical', 'Major', 'Minor', 'Warning', 'Event') ASC").
|
||||||
|
Asc("orig_severity").
|
||||||
|
Cols("orig_severity").
|
||||||
|
Limit(1).
|
||||||
|
Get(&severity)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Debugf("neType=%s, neId=%s, eventTime=%s, severity=%s", alarmData.NeType, alarmData.NeId, alarmData.EventTime, severity)
|
||||||
|
|
||||||
|
if has == false || severity == alarmData.OrigSeverity {
|
||||||
|
alarmData.PerceivedSeverity = alarmData.OrigSeverity
|
||||||
|
} else if severity > alarmData.OrigSeverity {
|
||||||
|
alarmData.PerceivedSeverity = alarmData.OrigSeverity
|
||||||
|
} else {
|
||||||
|
alarmData.PerceivedSeverity = severity
|
||||||
|
// update exist record
|
||||||
|
_, err := session.Table("alarm").
|
||||||
|
Where("ne_type=? and ne_id=? and event_time=?", alarmData.NeType, alarmData.NeId, alarmData.EventTime).
|
||||||
|
Update(&Alarm{PerceivedSeverity: alarmData.PerceivedSeverity})
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to update alarm:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alarmData.ObjectUid = alarmData.NeId
|
||||||
|
alarmData.ObjectType = "VNFM"
|
||||||
|
alarmData.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
|
||||||
|
if IsNeedToAckAlarm(valueJson, &alarmData) == true {
|
||||||
|
SetAlarmAckInfo(valueJson, &alarmData)
|
||||||
|
}
|
||||||
|
log.Trace("alarmData:", alarmData)
|
||||||
|
affected, err := session.Insert(alarmData)
|
||||||
|
if err == nil && affected > 0 {
|
||||||
|
alarmLog := new(AlarmLog)
|
||||||
|
alarmLog.NeType = alarmData.NeType
|
||||||
|
alarmLog.NeId = alarmData.NeId
|
||||||
|
alarmLog.AlarmSeq = alarmData.AlarmSeq
|
||||||
|
alarmLog.AlarmId = alarmData.AlarmId
|
||||||
|
alarmLog.AlarmCode = alarmData.AlarmCode
|
||||||
|
alarmLog.AlarmStatus = alarmData.AlarmStatus
|
||||||
|
alarmLog.EventTime = global.GetFmtTimeString(time.RFC3339, alarmData.EventTime, time.DateTime)
|
||||||
|
log.Debug("alarmLog:", alarmLog)
|
||||||
|
affected, err = session.Insert(alarmLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert data:", err)
|
||||||
|
//services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
session.Commit()
|
||||||
|
if config.GetYamlConfig().Alarm.ForwardAlarm {
|
||||||
|
if err = AlarmEmailForward(&alarmData); err != nil {
|
||||||
|
log.Error("Failed to AlarmEmailForward:", err)
|
||||||
|
}
|
||||||
|
if err = AlarmForwardBySMS(&alarmData); err != nil {
|
||||||
|
log.Error("Failed to AlarmForwardBySMS:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Warn("Failed to insert alarm data:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
111
features/fm/email.go
Normal file
111
features/fm/email.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package fm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"gopkg.in/gomail.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AlarmEmailForward(alarmData *Alarm) error {
|
||||||
|
log.Info("AlarmEmailForward processing... ")
|
||||||
|
|
||||||
|
message := `
|
||||||
|
<p> Hello information,</p>
|
||||||
|
test, test
|
||||||
|
<p style="text-indent:2em">Best Wishes!</p>
|
||||||
|
`
|
||||||
|
|
||||||
|
// QQ 邮箱:
|
||||||
|
// SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25)
|
||||||
|
// 163 邮箱:
|
||||||
|
// SMTP 服务器地址:smtp.163.com(端口:25)
|
||||||
|
// host := "mail.agrandtech.com"
|
||||||
|
// port := 25
|
||||||
|
// userName := "smtpext@agrandtech.com"
|
||||||
|
// password := "1000smtp@omc!"
|
||||||
|
|
||||||
|
host := config.GetYamlConfig().Alarm.Email.Smtp
|
||||||
|
port := int(config.GetYamlConfig().Alarm.Email.Port)
|
||||||
|
userName := config.GetYamlConfig().Alarm.Email.User
|
||||||
|
password := config.GetYamlConfig().Alarm.Email.Password
|
||||||
|
|
||||||
|
m := gomail.NewMessage()
|
||||||
|
m.SetHeader("From", userName) // 发件人
|
||||||
|
//m.SetHeader("From", "alias"+"<"+"aliastest"+">") // 增加发件人别名
|
||||||
|
|
||||||
|
emails, err := dborm.XormGetAlarmForward("Email")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormGetAlarmForward:", err)
|
||||||
|
return err
|
||||||
|
} else if emails == nil || len(*emails) == 0 {
|
||||||
|
err := errors.New("not found forward email list")
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
forwardLog := &dborm.AlarmForwardLog{
|
||||||
|
NeType: alarmData.NeType,
|
||||||
|
NeID: alarmData.NeId,
|
||||||
|
AlarmID: alarmData.AlarmId,
|
||||||
|
AlarmTitle: alarmData.AlarmTitle,
|
||||||
|
AlarmSeq: alarmData.AlarmSeq,
|
||||||
|
EventTime: alarmData.EventTime,
|
||||||
|
ToUser: strings.Join(*emails, ","),
|
||||||
|
}
|
||||||
|
for _, email := range *emails {
|
||||||
|
m.SetHeader("To", email) // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
|
||||||
|
}
|
||||||
|
|
||||||
|
//m.SetHeader("To", "zhangshuzhong@agrandtech.com", "simonzhangsz@outlook.com") // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接
|
||||||
|
//m.SetHeader("Cc", "******@qq.com") // 抄送,可以多个
|
||||||
|
//m.SetHeader("Bcc", "******@qq.com") // 暗送,可以多个
|
||||||
|
m.SetHeader("Subject", "Alarm from OMC!") // 邮件主题
|
||||||
|
|
||||||
|
// text/html 的意思是将文件的 content-type 设置为 text/html 的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
|
||||||
|
// 可以通过 text/html 处理文本格式进行特殊处理,如换行、缩进、加粗等等
|
||||||
|
//m.SetBody("text/html", fmt.Sprintf(message, *alarm))
|
||||||
|
m.SetBody("text/html", message)
|
||||||
|
|
||||||
|
// text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理
|
||||||
|
// m.SetBody("text/plain", "纯文本")
|
||||||
|
// m.Attach("test.sh") // 附件文件,可以是文件,照片,视频等等
|
||||||
|
// m.Attach("lolcatVideo.mp4") // 视频
|
||||||
|
// m.Attach("lolcat.jpg") // 照片
|
||||||
|
|
||||||
|
d := gomail.NewDialer(
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
userName,
|
||||||
|
password,
|
||||||
|
)
|
||||||
|
// 关闭SSL协议认证
|
||||||
|
d.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
|
||||||
|
if err := d.DialAndSend(m); err != nil {
|
||||||
|
operResult := fmt.Sprintf("Failed to DialAndSend:%v", err)
|
||||||
|
log.Error(operResult)
|
||||||
|
forwardLog.OperResult = operResult
|
||||||
|
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert data:", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
operResult := fmt.Sprintf("Email sent successfully!:", err)
|
||||||
|
log.Error(operResult)
|
||||||
|
forwardLog.OperResult = operResult
|
||||||
|
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert data:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
103
features/fm/smsforward.go
Normal file
103
features/fm/smsforward.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package fm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AlarmForwardBySMS(alarmData *Alarm) error {
|
||||||
|
log.Info("AlarmForwardBySMS processing... ")
|
||||||
|
|
||||||
|
SMSFforwardconfig := config.GetYamlConfig().Alarm.SMS
|
||||||
|
// 阿里云短信API的请求地址
|
||||||
|
apiURL := SMSFforwardconfig.ApiURL
|
||||||
|
|
||||||
|
// 阿里云短信API的AccessKey ID和AccessKey Secret
|
||||||
|
//accessKeyID := SMSFforwardconfig.AccessKeyID
|
||||||
|
accessKeySecret := SMSFforwardconfig.AccessKeySecret
|
||||||
|
|
||||||
|
toUsers, err := dborm.XormGetAlarmForward("SMS")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormGetAlarmForward:", err)
|
||||||
|
return err
|
||||||
|
} else if toUsers == nil {
|
||||||
|
err := errors.New("not found forward phone number")
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, toUser := range *toUsers {
|
||||||
|
// 短信相关参数
|
||||||
|
params := url.Values{}
|
||||||
|
params.Set("PhoneNumbers", toUser)
|
||||||
|
params.Set("SignName", SMSFforwardconfig.SignName)
|
||||||
|
params.Set("TemplateCode", SMSFforwardconfig.TemplateCode)
|
||||||
|
params.Set("TemplateParam", `{"message":"alarm"}`)
|
||||||
|
|
||||||
|
// 构建请求URL
|
||||||
|
reqURL := apiURL + "?Action=SendSms&" + params.Encode()
|
||||||
|
|
||||||
|
// 创建HTTP请求
|
||||||
|
req, err := http.NewRequest("GET", reqURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to create request:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加请求头部
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Set("Authorization", "APPCODE "+accessKeySecret)
|
||||||
|
|
||||||
|
forwardLog := &dborm.AlarmForwardLog{
|
||||||
|
NeType: alarmData.NeType,
|
||||||
|
NeID: alarmData.NeId,
|
||||||
|
AlarmID: alarmData.AlarmId,
|
||||||
|
AlarmTitle: alarmData.AlarmTitle,
|
||||||
|
AlarmSeq: alarmData.AlarmSeq,
|
||||||
|
EventTime: alarmData.EventTime,
|
||||||
|
ToUser: toUser,
|
||||||
|
}
|
||||||
|
// 发送请求
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
operResult := fmt.Sprintf("Failed to send request:%v", err)
|
||||||
|
log.Error(operResult)
|
||||||
|
forwardLog.OperResult = operResult
|
||||||
|
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert data:", err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
log.Info("SMS sent successfully!")
|
||||||
|
operResult := fmt.Sprintf("SMS sent successfully!")
|
||||||
|
forwardLog.OperResult = operResult
|
||||||
|
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert data:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
operResult := fmt.Sprintf("Failed to send SMS, StatusCode=%d", resp.StatusCode)
|
||||||
|
log.Error(operResult)
|
||||||
|
forwardLog.OperResult = operResult
|
||||||
|
affected, err := dborm.XormInsertAlarmForwardLog(forwardLog)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert data:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
586
features/handle/handle.go
Normal file
586
features/handle/handle.go
Normal file
@@ -0,0 +1,586 @@
|
|||||||
|
package handle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
g "github.com/gosnmp/gosnmp"
|
||||||
|
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/oauth"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/lib/session"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var TodoList []stTodo
|
||||||
|
|
||||||
|
type stTodo struct {
|
||||||
|
No string
|
||||||
|
Item string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorOAuthResponse struct {
|
||||||
|
Error map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FailOAuthResponse struct {
|
||||||
|
Error struct {
|
||||||
|
ErrorCode string
|
||||||
|
ErrorInfo string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApiResponse struct {
|
||||||
|
ResultCode string
|
||||||
|
ResultMessage interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalSession = session.NewSessManager("restagent")
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
conf := config.GetYamlConfig()
|
||||||
|
// Default is a pointer to a GoSNMP struct that contains sensible defaults
|
||||||
|
// eg port 161, community public, etc
|
||||||
|
g.Default.Target = conf.NE.Addr
|
||||||
|
g.Default.Port = conf.NE.Port
|
||||||
|
err := g.Default.Connect()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Connect() err: %v", err)
|
||||||
|
}
|
||||||
|
//defer g.Default.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func IsValidOAuthInfo(oAuthBody OAuthBody) bool {
|
||||||
|
log.Debug("IsValidOAuthInfo processing... ")
|
||||||
|
|
||||||
|
conf := config.GetYamlConfig()
|
||||||
|
for _, o := range conf.Auth {
|
||||||
|
if oAuthBody.GrantType == o.Type && oAuthBody.UserName == o.User && oAuthBody.Value == o.Password {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsWrongOAuthInfo(oAuthBody OAuthBody) bool {
|
||||||
|
log.Debug("IsWrongOAuthInfo processing... ")
|
||||||
|
|
||||||
|
if oAuthBody.GrantType == "" || strings.ToLower(oAuthBody.GrantType) != "password" || oAuthBody.UserName == "" || oAuthBody.Value == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func IsValidOAuthUri(r *http.Request) bool {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
Uri := vars["apiCategory"] + "/" + vars["apiVersion"] // 获取Uri
|
||||||
|
if Uri != "securityManagement/v1" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsVallidContentType(r *http.Request) bool {
|
||||||
|
log.Debug("IsVallidContentType processing ...")
|
||||||
|
|
||||||
|
ctype := r.Header["Content-Type"]
|
||||||
|
if len(ctype) != 0 && !strings.Contains(ctype[0], "application/json") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("LoginFromOMC processing... ")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Debug(err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
/* if !IsVallidContentType(r) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check extend uri, response 404
|
||||||
|
if !IsValidOAuthUri(r) {
|
||||||
|
log.Debug("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
// Error process ....
|
||||||
|
// response 400-7
|
||||||
|
if !json.Valid([]byte(body)) {
|
||||||
|
log.Debug("Invalid Json Format")
|
||||||
|
services.ResponseBadRequest400InvalidJson(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var oAuthBody oauth.OAuthBody
|
||||||
|
_ = json.Unmarshal(body, &oAuthBody) //转为json
|
||||||
|
log.Debug("body:", string(body), "oAuthBody:", oAuthBody)
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
// response 400-5
|
||||||
|
if oauth.IsWrongOAuthInfo(oAuthBody) {
|
||||||
|
log.Debug("Wrong parameter value")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if oauth.IsValidOAuthInfo(oAuthBody) {
|
||||||
|
plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
|
||||||
|
log.Debug("Permission list:", plist)
|
||||||
|
|
||||||
|
token := globalSession.NewSession(w, r, plist)
|
||||||
|
services.ResponseStatusOK200Login(w, token)
|
||||||
|
} else {
|
||||||
|
// response 400-4
|
||||||
|
log.Debug("Authentication failed, mismatch user or password")
|
||||||
|
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
validUser, changePassword, _ := dborm.XormCheckLoginUser(oAuthBody.UserName,
|
||||||
|
oAuthBody.Value, config.GetYamlConfig().Auth.Crypt)
|
||||||
|
if validUser {
|
||||||
|
// plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
|
||||||
|
plist := []bool{true, true, true, true}
|
||||||
|
log.Debug("Permission list:", plist)
|
||||||
|
|
||||||
|
token := globalSession.NewSession(w, r, plist)
|
||||||
|
services.ResponseStatusOK200Login(w, token, changePassword)
|
||||||
|
} else {
|
||||||
|
// response 400-4
|
||||||
|
log.Error("Authentication failed, mismatch user or password")
|
||||||
|
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogoutFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("LogoutFromOMC processing... ")
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
if !IsVallidContentType(r) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check extend uri, response 404
|
||||||
|
if !IsValidOAuthUri(r) {
|
||||||
|
log.Debug("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// error processing ...
|
||||||
|
// 401-1 response
|
||||||
|
token, ret := globalSession.IsCarriedToken(r)
|
||||||
|
if ret == false {
|
||||||
|
log.Debug("AccessToken is not carried")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 401-2 response
|
||||||
|
if globalSession.IsValidToken(token) == false {
|
||||||
|
log.Debug("AccessToken fails or does not exist")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotExist(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
globalSession.EndSession(w, r)
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("HandshakeFromOMC processing... ")
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
if !IsVallidContentType(r) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check extend uri, response 404
|
||||||
|
if !IsValidOAuthUri(r) {
|
||||||
|
log.Debug("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// error processing ...
|
||||||
|
// 401-1 response
|
||||||
|
token, ret := globalSession.IsCarriedToken(r)
|
||||||
|
if ret == false {
|
||||||
|
log.Debug("AccessToken is not carried")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !globalSession.ShakeSession(token) {
|
||||||
|
// 401-2 response
|
||||||
|
log.Debug("AccessToken fails or does not exist")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotExist(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 200 response
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig()
|
||||||
|
MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig()
|
||||||
|
MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig()
|
||||||
|
MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig()
|
||||||
|
MAX_URI_LEN = config.GetUriMaxLenFromConfig()
|
||||||
|
RMUID_REGEXP = config.GetRmUIDRegexpFromConfig()
|
||||||
|
)
|
||||||
|
|
||||||
|
func CheckParameterName(r *http.Request) []string {
|
||||||
|
var errorParams []string
|
||||||
|
vars := r.URL.Query()
|
||||||
|
for k, v := range vars {
|
||||||
|
log.Debug("vars:", k, v)
|
||||||
|
if k != "rmUIDs" && k != "fields" {
|
||||||
|
errorParams = append(errorParams, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorParams
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRmUIDArr(r *http.Request) []string {
|
||||||
|
vars := r.URL.Query()
|
||||||
|
rmUIDs, ok := vars["rmUIDs"]
|
||||||
|
if !ok {
|
||||||
|
log.Debug("rmUIDs is not exist")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var rmUIDValues []string
|
||||||
|
for _, r := range rmUIDs {
|
||||||
|
if r != "" {
|
||||||
|
rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rmUIDValues
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAttrNameArr(r *http.Request) []string {
|
||||||
|
vars := r.URL.Query()
|
||||||
|
fields, ok := vars["fields"]
|
||||||
|
if !ok {
|
||||||
|
log.Debug("attributeNames does not exist")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var attrNames []string
|
||||||
|
for _, a := range fields {
|
||||||
|
if a != "" {
|
||||||
|
attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrNames
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckValidRmUID(rmUIDs []string) []string {
|
||||||
|
log.Debug("GetLocalRmUID processing... ")
|
||||||
|
|
||||||
|
var invalidRmUIDs []string
|
||||||
|
for _, r := range rmUIDs {
|
||||||
|
if !global.MatchRmUID(RMUID_REGEXP, r) {
|
||||||
|
invalidRmUIDs = append(invalidRmUIDs, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return invalidRmUIDs
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckLocalRmUID(rmUIDs []string) string {
|
||||||
|
log.Debug("GetLocalRmUID processing... ")
|
||||||
|
|
||||||
|
rmUID := config.GetRmUIDFromConfig()
|
||||||
|
for _, r := range rmUIDs {
|
||||||
|
if r == rmUID {
|
||||||
|
return rmUID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNRMByUri(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetNRMByUri processing... ")
|
||||||
|
|
||||||
|
// response 414-4 uri too long ? (optional)
|
||||||
|
// todo ... ?
|
||||||
|
if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN {
|
||||||
|
log.Debug("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil))
|
||||||
|
services.ResponseRequestURITooLong414UriTooLong(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
// response 415-1
|
||||||
|
if !IsVallidContentType(r) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// error processing ...
|
||||||
|
// 401-1 response
|
||||||
|
token, ret := globalSession.IsCarriedToken(r)
|
||||||
|
if ret == false {
|
||||||
|
log.Debug("AccessToken is not carried")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 401-2 response
|
||||||
|
if globalSession.IsValidToken(token) == false {
|
||||||
|
log.Debug("AccessToken fails or does not exist")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotExist(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// response 403 Forbidden, permissions deny
|
||||||
|
// todo...
|
||||||
|
plist := globalSession.GetPermissionFromSession(token)
|
||||||
|
log.Debug("permission list:", plist)
|
||||||
|
if len(plist) == 0 || plist[0] == false {
|
||||||
|
log.Debug("User permission deny")
|
||||||
|
services.ResponseForbidden403NotPermission(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"]
|
||||||
|
log.Debug("Get by Uri: ", qeuryUri)
|
||||||
|
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != "v1" {
|
||||||
|
log.Debug("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 406-1
|
||||||
|
rmUIDValues := GetRmUIDArr(r)
|
||||||
|
if rmUIDValues == nil {
|
||||||
|
log.Debug("missing parameter: rmUIDs")
|
||||||
|
services.ResponseNotAcceptable406MissingParam(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 406-2
|
||||||
|
errorParams := CheckParameterName(r)
|
||||||
|
if errorParams != nil {
|
||||||
|
log.Debug("parameter name error: ", errorParams)
|
||||||
|
services.ResponseNotAcceptable406ParamError(w, errorParams)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 400-5
|
||||||
|
if len(rmUIDValues) == 0 {
|
||||||
|
log.Debug("rmUIDs is wrong or NULL")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 414-1
|
||||||
|
if len(rmUIDValues) > MAX_RMUID_NUM {
|
||||||
|
log.Debug("rmUID greater than", MAX_RMUID_NUM)
|
||||||
|
services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 400-1
|
||||||
|
// check rmUID is valid
|
||||||
|
// todo ...
|
||||||
|
invalidRmUIDs := CheckValidRmUID(rmUIDValues)
|
||||||
|
if len(invalidRmUIDs) != 0 {
|
||||||
|
log.Debug("rmUID is invalid")
|
||||||
|
services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 404-2
|
||||||
|
rmUID := CheckLocalRmUID(rmUIDValues)
|
||||||
|
if rmUID == "" {
|
||||||
|
log.Debug("rmUID does not exist")
|
||||||
|
services.ResponseNotFound404NRMNotExist(w, rmUIDValues)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 404-1, uri is not exist in map
|
||||||
|
attrNames := GetAttrNameArr(r)
|
||||||
|
var Oids []string
|
||||||
|
Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids)
|
||||||
|
if len(Oids) == 0 {
|
||||||
|
log.Debug("Nothing of config map")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 404-1, uri is not exist in map
|
||||||
|
var nameOids []config.NameOid
|
||||||
|
nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids)
|
||||||
|
if len(nameOids) == 0 {
|
||||||
|
log.Debug("Nothing of config map")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS
|
||||||
|
if err2 != nil {
|
||||||
|
log.Fatalf("Get() err: %v", err2)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// var nameValues []config.NameValue
|
||||||
|
var nameValue config.NameValue
|
||||||
|
|
||||||
|
nameValues := make(map[string]interface{})
|
||||||
|
nameValues["rmUID"] = rmUID
|
||||||
|
for i, variable := range result.Variables {
|
||||||
|
nameValue.Name = nameOids[i].Name
|
||||||
|
log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name)
|
||||||
|
// if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) {
|
||||||
|
if nameOids[i].Oid == variable.Name {
|
||||||
|
// the Value of each variable returned by Get() implements
|
||||||
|
// interface{}. You could do a type switch...
|
||||||
|
switch variable.Type {
|
||||||
|
case g.OctetString:
|
||||||
|
bytes := variable.Value.([]byte)
|
||||||
|
log.Debugf("string: %s\n", string(bytes))
|
||||||
|
nameValue.Value = string(bytes)
|
||||||
|
nameValues[nameValue.Name] = nameValue.Value
|
||||||
|
case g.Integer:
|
||||||
|
value := variable.Value.(int)
|
||||||
|
log.Debugf("integer: %d\n", value)
|
||||||
|
nameValue.Value = strconv.Itoa(value)
|
||||||
|
nameValues[nameValue.Name] = nameValue.Value
|
||||||
|
case g.IPAddress:
|
||||||
|
value := variable.Value.(string)
|
||||||
|
log.Debugf("IPAddress: %s\n", variable.Value)
|
||||||
|
nameValue.Value = value
|
||||||
|
nameValues[nameValue.Name] = nameValue.Value
|
||||||
|
default:
|
||||||
|
// ... or often you're just interested in numeric values.
|
||||||
|
// ToBigInt() will return the Value as a BigInt, for plugging
|
||||||
|
// into your calculations.
|
||||||
|
log.Debugf("number: %d\n", g.ToBigInt(variable.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponse := services.DataResponse{nameValues}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, getResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestfulPut(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
queryNo := vars["no"]
|
||||||
|
var targetTodo stTodo
|
||||||
|
for _, Todo := range TodoList {
|
||||||
|
if Todo.No == queryNo {
|
||||||
|
targetTodo = Todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response := ApiResponse{"200", targetTodo}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestfulHead(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var targetTodo stTodo
|
||||||
|
|
||||||
|
response := ApiResponse{"200", targetTodo}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveElement(TodoList []stTodo, No string) stTodo {
|
||||||
|
// var targetTodo stTodo
|
||||||
|
j := 0
|
||||||
|
if len(TodoList) == 0 {
|
||||||
|
return TodoList[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(TodoList); i++ {
|
||||||
|
if TodoList[i].No != No {
|
||||||
|
if i != j {
|
||||||
|
TodoList[i], TodoList[j] = TodoList[j], TodoList[i]
|
||||||
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug(TodoList[j].No, TodoList[j].Item)
|
||||||
|
return TodoList[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestfulDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
queryNo := vars["no"] //获取No
|
||||||
|
|
||||||
|
log.Debug("RestfulDelete processing... ")
|
||||||
|
|
||||||
|
targetTodo := RemoveElement(TodoList, queryNo)
|
||||||
|
response := ApiResponse{"200", targetTodo}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestfulOptions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var targetTodo stTodo
|
||||||
|
|
||||||
|
response := ApiResponse{"200", targetTodo}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestfulTrace(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var targetTodo stTodo
|
||||||
|
|
||||||
|
response := ApiResponse{"200", targetTodo}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func RestfulPatch(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var targetTodo stTodo
|
||||||
|
|
||||||
|
response := ApiResponse{"200", targetTodo}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
|
||||||
|
}
|
||||||
149
features/lm/logbak.go
Normal file
149
features/lm/logbak.go
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
package lm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type XormResponse struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type XormInsertResponse struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ExtBackupDataUri = config.DefaultUriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}/backup" // for external
|
||||||
|
|
||||||
|
CustomExtBackupDataUri = config.UriPrefix + "/dataManagement/{apiVersion}/{dataStorage}/{dataObject}/backup" // for external
|
||||||
|
)
|
||||||
|
|
||||||
|
var XEngine *xorm.Engine
|
||||||
|
|
||||||
|
type DatabaseClient struct {
|
||||||
|
dbType string
|
||||||
|
dbUrl string
|
||||||
|
dbConnMaxLifetime time.Duration
|
||||||
|
dbMaxIdleConns int
|
||||||
|
dbMaxOpenConns int
|
||||||
|
IsShowSQL bool
|
||||||
|
|
||||||
|
XEngine *xorm.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
var DbClient DatabaseClient
|
||||||
|
|
||||||
|
// func init() {
|
||||||
|
// conf := config.GetYamlConfig()
|
||||||
|
// InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
|
||||||
|
// conf.Database.Host, conf.Database.Port, conf.Database.Name)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
|
||||||
|
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbUser, dbPassword, dbHost, dbPort, dbName)
|
||||||
|
DbClient.dbType = dbType
|
||||||
|
DbClient.dbConnMaxLifetime = 0
|
||||||
|
DbClient.dbMaxIdleConns = 0
|
||||||
|
DbClient.dbMaxOpenConns = 0
|
||||||
|
if log.GetLevel() == log.LOG_TRACE {
|
||||||
|
DbClient.IsShowSQL = true
|
||||||
|
}
|
||||||
|
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbType, dbUser, dbHost, dbPort, dbName)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connet database:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
|
||||||
|
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
|
||||||
|
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
|
||||||
|
if DbClient.IsShowSQL {
|
||||||
|
DbClient.XEngine.ShowSQL(true)
|
||||||
|
}
|
||||||
|
XEngine = DbClient.XEngine
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtDatabaseBackupData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ExtDatabaseBackupData processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
module := vars["managementModule"]
|
||||||
|
dbname := vars["dataStorage"]
|
||||||
|
tbname := vars["dataObject"]
|
||||||
|
pack := "lm"
|
||||||
|
log.Debugf("token:%s, method:%s, module:%s dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack)
|
||||||
|
// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to get permission:", err)
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// log.Error("permission deny!")
|
||||||
|
// services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
var sql string
|
||||||
|
var filePath string
|
||||||
|
switch tbname {
|
||||||
|
case "operation_log":
|
||||||
|
filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData))
|
||||||
|
sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'op_id','account_name','op_ip','subsys_tag','op_type','op_content','op_result','begin_time','end_time','vnf_flag','log_time' union select op_id,account_name,op_ip,subsys_tag,op_type,op_content,op_result,begin_time,end_time,vnf_flag,log_time from operation_log) b", filePath)
|
||||||
|
case "security_log":
|
||||||
|
filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData))
|
||||||
|
sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'id','account_name','account_type','op_ip','op_type','op_content','op_result','op_time' union select id,account_name,account_type,op_ip,op_type,op_content,op_result,op_time from security_log) b", filePath)
|
||||||
|
case "alarm_log":
|
||||||
|
filePath = fmt.Sprintf("/tmp/%s-%s.csv", tbname, time.Now().Local().Format(global.DateData))
|
||||||
|
sql = fmt.Sprintf("select * into outfile '%s' fields terminated by ',' escaped by '' optionally enclosed by '' lines terminated by '\n' from (select 'id','ne_type','ne_id','alarm_seq','alarm_id','alarm_code','alarm_status','event_time','log_time' union select id,ne_type,ne_id,alarm_seq,alarm_id,alarm_code,alarm_status,event_time,log_time from alarm_log) b", filePath)
|
||||||
|
default:
|
||||||
|
log.Error("error target table")
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := DbClient.XEngine.Exec(sql)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to exec SQL:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
affected, _ := res.RowsAffected()
|
||||||
|
|
||||||
|
log.Debugf("filePath:%s backup dir:%s", filePath, config.GetYamlConfig().Database.Backup)
|
||||||
|
cmd := exec.Command("cp", "-rf", filePath, config.GetYamlConfig().Database.Backup)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
log.Debugf("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to exec:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapRow := make(map[string]interface{})
|
||||||
|
row := map[string]interface{}{"affectedRows": affected}
|
||||||
|
mapRow[tbname] = row
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, mapRow)
|
||||||
|
}
|
||||||
313
features/maintenance/maintenance.go
Normal file
313
features/maintenance/maintenance.go
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
package maintenance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理;
|
||||||
|
// 对于虚拟化部署OMC系统,能够对虚机内存、虚机CPU、虚拟存储空间、文件系统资源、数据库空间等指标进行监控,提供界面截图 ;
|
||||||
|
|
||||||
|
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图 ;
|
||||||
|
|
||||||
|
// (3) OMC能够方便的查询数据库连接情况;并可手工干预数据库的连接,能方便的终结非法的数据库连接 ;
|
||||||
|
|
||||||
|
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
|
||||||
|
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
|
||||||
|
|
||||||
|
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据,要求OMC能够保存至少3个月,提供界面截图 ;
|
||||||
|
// (7) 用户可以按照需求自定义报表模板并生成OMC系统维护数据报表,提供界面截图 ;
|
||||||
|
|
||||||
|
// (8) OMC具备自身告警管理功能,对于传统OMC系统,如:服务器单电源告警,存储硬盘告警、OMC系统软件故障等;
|
||||||
|
// 对于虚拟化OMC系统,如虚机告警、虚拟硬盘告警等,提供界面截图 。
|
||||||
|
|
||||||
|
var (
|
||||||
|
// parameter config management
|
||||||
|
Uri = config.UriPrefix + "/maintenance/{apiVersion}/zz"
|
||||||
|
|
||||||
|
// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理;
|
||||||
|
UriPref = config.UriPrefix + "/maintenance/{apiVersion}/pref"
|
||||||
|
|
||||||
|
// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据,要求OMC能够保存至少3个月,提供界面截图 ;
|
||||||
|
UriPrefLog = config.UriPrefix + "/maintenance/{apiVersion}/prefLog"
|
||||||
|
|
||||||
|
// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图 ;
|
||||||
|
UriConfig = config.UriPrefix + "/maintenance/{apiVersion}/config"
|
||||||
|
|
||||||
|
// (3) OMC能够方便的查询数据库连接情况;并可手工干预数据库的连接,能方便的终结非法的数据库连接
|
||||||
|
UriSqlClient = config.UriPrefix + "/maintenance/{apiVersion}/sqlClient"
|
||||||
|
|
||||||
|
// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图
|
||||||
|
// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图
|
||||||
|
UriTop = config.UriPrefix + "/maintenance/{apiVersion}/top"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 定時收集 TODO
|
||||||
|
prefLogSave("")
|
||||||
|
}
|
||||||
|
|
||||||
|
func List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Println("zz List")
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 性能指標
|
||||||
|
func prefInfo(dirName string) map[string]any {
|
||||||
|
data := make(map[string]any)
|
||||||
|
|
||||||
|
// 显示文件資源目录
|
||||||
|
dirPath := "D://"
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
dirPath = "/home"
|
||||||
|
}
|
||||||
|
// 訪問下級
|
||||||
|
if dirName != "" {
|
||||||
|
dirPath = path.Join(dirPath, dirName)
|
||||||
|
}
|
||||||
|
dir_list, e := os.ReadDir(dirPath)
|
||||||
|
if e != nil {
|
||||||
|
log.Error(e)
|
||||||
|
}
|
||||||
|
list := make([]map[string]any, 0)
|
||||||
|
for _, v := range dir_list {
|
||||||
|
o, err := v.Info()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
list = append(list, map[string]any{
|
||||||
|
"name": o.Name(),
|
||||||
|
"size": o.Size(),
|
||||||
|
"mode": o.Mode().String(),
|
||||||
|
"modTime": o.ModTime().Format("2006-01-02 15:04:05"),
|
||||||
|
"isDir": o.IsDir(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
data["dirList"] = list
|
||||||
|
|
||||||
|
// 文件資源使用率
|
||||||
|
u, _ := disk.Usage(dirPath)
|
||||||
|
usedGB := int(u.Used) / (1024 * 1024 * 1024 * 1)
|
||||||
|
data["dirUse"] = fmt.Sprintf("%d", usedGB)
|
||||||
|
|
||||||
|
// CPU使用率
|
||||||
|
percent, err := cpu.Percent(time.Second, false)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
data["cpuUse"] = fmt.Sprintf("%.2f", percent[0])
|
||||||
|
|
||||||
|
// 内存使用率
|
||||||
|
memInfo, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
data["memUse"] = memInfo.UsedPercent
|
||||||
|
|
||||||
|
// 獲取數據庫占用空間
|
||||||
|
if dborm.DbClient.XEngine != nil {
|
||||||
|
conf := config.GetYamlConfig()
|
||||||
|
result, err := dborm.DbClient.XEngine.QueryString(`SELECT
|
||||||
|
CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size,
|
||||||
|
CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size,
|
||||||
|
CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free,
|
||||||
|
CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size
|
||||||
|
FROM information_schema.tables WHERE TABLE_SCHEMA = ?;
|
||||||
|
`, conf.Database.Name)
|
||||||
|
if err == nil {
|
||||||
|
data["dbInfo"] = result[0]
|
||||||
|
} else {
|
||||||
|
data["dbInfo"] = map[string]string{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 性能指標存入數據庫
|
||||||
|
func prefLogSave(dirName string) {
|
||||||
|
if dborm.DbClient.XEngine != nil {
|
||||||
|
data := prefInfo(dirName)
|
||||||
|
|
||||||
|
dirListByte, err := json.Marshal(data["dirList"])
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
dbInfoByte, err := json.Marshal(data["dbInfo"])
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
rse, err := dborm.DbClient.XEngine.Exec(`INSERT INTO sys_perf_data
|
||||||
|
(id, create_time, dir_used, dir_list, db_info, mem_used, cpu_used)
|
||||||
|
VALUES(NULL, NOW(), ?, ?, ?, ?, ?);
|
||||||
|
`, data["dirUse"], string(dirListByte), string(dbInfoByte), data["memUse"], data["cpuUse"])
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
fmt.Println(rse.LastInsertId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/pref?dir=true
|
||||||
|
func Pref(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 知道下級文件資源目录
|
||||||
|
dirName := r.URL.Query().Get("dirName")
|
||||||
|
data := prefInfo(dirName)
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST http://192.168.21.183:3040/api/rest/maintenance/v1/config
|
||||||
|
func Config(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 進行值更新
|
||||||
|
if dborm.DbClient.XEngine != nil {
|
||||||
|
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result)
|
||||||
|
rse, err := dborm.DbClient.XEngine.Exec("UPDATE sys_config SET value = ? where id = ?", "true", 100)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Println(rse)
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=close
|
||||||
|
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=connet
|
||||||
|
// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=user
|
||||||
|
func SqlClient(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 关闭
|
||||||
|
isClose := r.URL.Query().Get("type")
|
||||||
|
if isClose == "close" && dborm.DbClient.XEngine != nil {
|
||||||
|
dborm.DbClient.XEngine.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重连
|
||||||
|
isConnet := r.URL.Query().Get("type")
|
||||||
|
if isConnet == "connet" && dborm.DbClient.XEngine == nil {
|
||||||
|
conf := config.GetYamlConfig()
|
||||||
|
err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password,
|
||||||
|
conf.Database.Host, conf.Database.Port, conf.Database.Name)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("dborm.initDbClient err:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询实例
|
||||||
|
isUser := r.URL.Query().Get("type")
|
||||||
|
if isUser == "user" && dborm.DbClient.XEngine != nil {
|
||||||
|
result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Println(result)
|
||||||
|
rse, err := dborm.DbClient.XEngine.Exec("KILL CONNECTION CONNECTION_ID()")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
fmt.Println(rse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 进行连接测试
|
||||||
|
err := dborm.DbClient.XEngine.Ping()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET http://192.168.21.183:3040/api/rest/maintenance/v1/top?grep=
|
||||||
|
func Top(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 過濾命令
|
||||||
|
grep := r.URL.Query().Get("grep")
|
||||||
|
// 命令拼接
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
command := "ps -ef "
|
||||||
|
if grep != "" {
|
||||||
|
command += grep
|
||||||
|
}
|
||||||
|
cmd = exec.Command(command)
|
||||||
|
case "windows":
|
||||||
|
command := "wmic process list brief "
|
||||||
|
if grep != "" {
|
||||||
|
command += grep
|
||||||
|
}
|
||||||
|
cmd = exec.Command("cmd", "/C", command)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
fmt.Println(string(out))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PATCH http://192.168.21.183:3040/api/rest/maintenance/v1/top?ops=&name=
|
||||||
|
func TopOps(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs struct {
|
||||||
|
Ops string `json:"ops"`
|
||||||
|
Pid string `json:"pid"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 命令拼接
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
switch bodyArgs.Ops {
|
||||||
|
case "kill":
|
||||||
|
cmd = exec.Command("kill", "-9", bodyArgs.Pid)
|
||||||
|
}
|
||||||
|
case "windows":
|
||||||
|
switch bodyArgs.Ops {
|
||||||
|
case "kill":
|
||||||
|
cmd = exec.Command("cmd", "/C", "taskkill", "-PID", bodyArgs.Pid, "-F")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
fmt.Println(string(out))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, string(out))
|
||||||
|
}
|
||||||
246
features/mml/mml.go
Normal file
246
features/mml/mml.go
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
package mml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/mmlp"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
//经过测试,linux下,延时需要大于100ms
|
||||||
|
TIME_DELAY_AFTER_WRITE = 200
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Data []string `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MMLRequest struct {
|
||||||
|
MML []string `json:"mml"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// MML interface
|
||||||
|
UriMML = config.DefaultUriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
|
||||||
|
UriMMLDiscard = config.DefaultUriPrefix + "/opeartionManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
|
||||||
|
UriNeOmMml = config.DefaultUriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}"
|
||||||
|
UriOmMmlExt = config.DefaultUriPrefix + "/{managedType}/{apiVersion}/elementType/OMC/objectType/mml"
|
||||||
|
UriOmMmlInt = config.DefaultUriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}"
|
||||||
|
|
||||||
|
CustomUriMML = config.UriPrefix + "/operationManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/mml"
|
||||||
|
CustomUriNeOmMml = config.UriPrefix + "/omManagement/{apiVersion}/mml/{netype}/{neid}"
|
||||||
|
CustomUriOmMmlExt = config.UriPrefix + "/opeartionManagement/{apiVersion}/elementType/OMC/objectType/mml"
|
||||||
|
CustomUriOmMmlInt = config.UriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PostMMLToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostMMLToNF processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pack := "mml"
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
module := vars["managedType"]
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
params := r.URL.Query()
|
||||||
|
neId := params["ne_id"]
|
||||||
|
if len(neId) == 0 {
|
||||||
|
log.Error("NOT FOUND ne_id")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("neType:", neType, "neId", neId)
|
||||||
|
|
||||||
|
log.Debugf("token:%s, method:%s, managementType:%s dbname:%s, tbname:%s pack:%s",
|
||||||
|
token, r.Method, module, neType, neId[0], pack)
|
||||||
|
|
||||||
|
var buf [8192]byte
|
||||||
|
var n int
|
||||||
|
var mmlResult []string
|
||||||
|
|
||||||
|
// exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, neType, neId[0], pack)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Error("Failed to get permission:", err)
|
||||||
|
// errMsg := fmt.Sprintf("RetCode = -1 operation failed: do not have the operation permissions")
|
||||||
|
// log.Error(errMsg)
|
||||||
|
// mmlResult = append(mmlResult, errMsg)
|
||||||
|
// response := Response{mmlResult}
|
||||||
|
// services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
// //services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// if !exist {
|
||||||
|
// log.Error("Not permission!")
|
||||||
|
// errMsg := fmt.Sprintf("RetCode = -1 operation failed: do not have the operation permissions")
|
||||||
|
// log.Error(errMsg)
|
||||||
|
// mmlResult = append(mmlResult, errMsg)
|
||||||
|
// response := Response{mmlResult}
|
||||||
|
// services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
// //services.ResponseForbidden403NotPermission(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
if strings.ToLower(neType) == "omc" {
|
||||||
|
PostMMLToOMC(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo := new(dborm.NeInfo)
|
||||||
|
neInfo, err = dborm.XormGetNeInfo(neType, neId[0])
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if neInfo != nil {
|
||||||
|
hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, config.GetYamlConfig().MML.Port)
|
||||||
|
conn, err := net.Dial("tcp", hostMML)
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err)
|
||||||
|
log.Error(errMsg)
|
||||||
|
mmlResult = append(mmlResult, errMsg)
|
||||||
|
response := Response{mmlResult}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password)
|
||||||
|
n, err = conn.Write([]byte(loginStr))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)
|
||||||
|
|
||||||
|
n, err = conn.Read(buf[0:])
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug(string(buf[0:n]))
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Body:", string(body))
|
||||||
|
|
||||||
|
mmlRequest := new(MMLRequest)
|
||||||
|
_ = json.Unmarshal(body, mmlRequest)
|
||||||
|
|
||||||
|
for _, mml := range mmlRequest.MML {
|
||||||
|
mmlCommand := fmt.Sprintf("%s\n", mml)
|
||||||
|
log.Debug("mml command:", mmlCommand)
|
||||||
|
n, err = conn.Write([]byte(mmlCommand))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * TIME_DELAY_AFTER_WRITE)
|
||||||
|
|
||||||
|
n, err = conn.Read(buf[0:])
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug(string(buf[0 : n-len(neType)-2]))
|
||||||
|
mmlResult = append(mmlResult, string(buf[0:n-len(neType)-2]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response := Response{mmlResult}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostMMLToOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostMMLToOMC processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckExtValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to CheckMmlValidRequest:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params := r.URL.Query()
|
||||||
|
neId := params["ne_id"]
|
||||||
|
if len(neId) == 0 {
|
||||||
|
log.Error("NOT FOUND ne_id ")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo := new(dborm.NeInfo)
|
||||||
|
neInfo, err = dborm.XormGetNeInfo("OMC", neId[0])
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("neInfo:", neInfo)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Body:", string(body))
|
||||||
|
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%s", neInfo.Ip, neInfo.Port)
|
||||||
|
|
||||||
|
omcMmlVar := &mmlp.MmlVar{
|
||||||
|
Version: "16.1.1",
|
||||||
|
Output: mmlp.DefaultFormatType,
|
||||||
|
MmlHome: config.GetYamlConfig().MML.MmlHome,
|
||||||
|
Limit: 50,
|
||||||
|
User: "",
|
||||||
|
SessionToken: token,
|
||||||
|
HttpUri: hostUri,
|
||||||
|
UserAgent: config.GetDefaultUserAgent(),
|
||||||
|
}
|
||||||
|
mmlRequest := new(MMLRequest)
|
||||||
|
_ = json.Unmarshal(body, mmlRequest)
|
||||||
|
|
||||||
|
var mmlResult []string
|
||||||
|
mmlLine := strings.Join(mmlRequest.MML, ";")
|
||||||
|
|
||||||
|
var mmlCmds []mmlp.MmlCommand
|
||||||
|
if err = mmlp.ParseMMLCommand(mmlLine, &mmlCmds); err != nil {
|
||||||
|
response := fmt.Sprintf("parse command error: %v\n", err)
|
||||||
|
mmlResult = append(mmlResult, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mmlCmd := range mmlCmds {
|
||||||
|
output, err := mmlp.TransMml2HttpReq(omcMmlVar, &mmlCmd)
|
||||||
|
if err != nil {
|
||||||
|
response := fmt.Sprintf("translate MML command error: %v]\n", err)
|
||||||
|
mmlResult = append(mmlResult, response)
|
||||||
|
}
|
||||||
|
mmlResult = append(mmlResult, string(*output))
|
||||||
|
}
|
||||||
|
|
||||||
|
response := Response{mmlResult}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
55
features/monitor/monitor/model.go
Normal file
55
features/monitor/monitor/model.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package monitor
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type MonitorBase struct {
|
||||||
|
ID uint `xorm:"id" json:"id"`
|
||||||
|
CreatedAt time.Time `xorm:"created_at" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"`
|
||||||
|
|
||||||
|
Cpu float64 `xorm:"cpu" json:"cpu"`
|
||||||
|
|
||||||
|
LoadUsage float64 `xorm:"load_usage" json:"loadUsage"`
|
||||||
|
CpuLoad1 float64 `xorm:"cpu_load1" json:"cpuLoad1"`
|
||||||
|
CpuLoad5 float64 `xorm:"cpu_load5" json:"cpuLoad5"`
|
||||||
|
CpuLoad15 float64 `xorm:"cpu_load15" json:"cpuLoad15"`
|
||||||
|
|
||||||
|
Memory float64 `xorm:"memory" json:"memory"`
|
||||||
|
|
||||||
|
DbSize uint `xorm:"db_size" json:"dbSize"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitorIO struct {
|
||||||
|
ID uint `xorm:"id" json:"id"`
|
||||||
|
CreatedAt time.Time `xorm:"created_at" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"`
|
||||||
|
|
||||||
|
Name string `xorm:"name" json:"name"`
|
||||||
|
Read uint64 `xorm:"read" json:"read"`
|
||||||
|
Write uint64 `xorm:"write" json:"write"`
|
||||||
|
Count uint64 `xorm:"count" json:"count"`
|
||||||
|
Time uint64 `xorm:"time" json:"time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitorNetwork struct {
|
||||||
|
ID uint `xorm:"id" json:"id"`
|
||||||
|
CreatedAt time.Time `xorm:"created_at" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"`
|
||||||
|
|
||||||
|
Name string `xorm:"name" json:"name"`
|
||||||
|
Up float64 `xorm:"up" json:"up"`
|
||||||
|
Down float64 `xorm:"down" json:"down"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitorSearch struct {
|
||||||
|
Param string `json:"param" validate:"required,oneof=all cpu memory load io network"`
|
||||||
|
Info string `json:"info"`
|
||||||
|
StartTime time.Time `json:"startTime"`
|
||||||
|
EndTime time.Time `json:"endTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitorData struct {
|
||||||
|
Param string `json:"param" validate:"required,oneof=cpu memory load io network"`
|
||||||
|
Date []time.Time `json:"date"`
|
||||||
|
Value []interface{} `json:"value"`
|
||||||
|
}
|
||||||
162
features/monitor/monitor/monitor.go
Normal file
162
features/monitor/monitor/monitor.go
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
package monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 点击【主机 - 监控】菜单,进入监控报表,直观的了解服务器的运行状态,包含【平均负载】、【CPU性能监控】、【内存使用监控】、【磁盘IO监控】、【网络IO监控】
|
||||||
|
|
||||||
|
// 可以查看昨天,今天,最近7天,最近30天,自定义时间的监控指标情况。
|
||||||
|
// 默认监控是开启的,可以在【面板设置 - 监控】页面中根据需求对监控进行开启和关闭。
|
||||||
|
// 监控数据默认保存30天,可以自行修改,也可手动清理该日志。
|
||||||
|
|
||||||
|
var (
|
||||||
|
// IP地址
|
||||||
|
UriIPAddr = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/ipaddr"
|
||||||
|
// 可选网络
|
||||||
|
UriNetOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/netoptions"
|
||||||
|
// 可选磁盘
|
||||||
|
UriIoOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/iooptions"
|
||||||
|
// 加载
|
||||||
|
UriLoad = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/load"
|
||||||
|
|
||||||
|
// IP地址
|
||||||
|
UriIPAddrOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/ipaddr"
|
||||||
|
// 可选网络
|
||||||
|
UriNetOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/netoptions"
|
||||||
|
// 可选磁盘
|
||||||
|
UriIoOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/iooptions"
|
||||||
|
// 加载
|
||||||
|
UriLoadOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/load"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IPAddr IP地址
|
||||||
|
func IPAddr(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ipAddrs := []map[string]string{}
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err == nil {
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
addrs := map[string]string{}
|
||||||
|
for _, v := range iface.Addrs {
|
||||||
|
prefix := strings.Split(v.Addr, "/")[0]
|
||||||
|
if strings.Contains(prefix, "::") {
|
||||||
|
addrs["IPv6"] = prefix
|
||||||
|
}
|
||||||
|
if strings.Contains(prefix, ".") {
|
||||||
|
addrs["IPv4"] = prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipAddrs = append(ipAddrs, addrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, ipAddrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Netoptions 可选网络
|
||||||
|
func Netoptions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
netStat, _ := net.IOCounters(true)
|
||||||
|
var options []string
|
||||||
|
options = append(options, "all")
|
||||||
|
for _, net := range netStat {
|
||||||
|
options = append(options, net.Name)
|
||||||
|
}
|
||||||
|
sort.Strings(options)
|
||||||
|
services.ResponseWithJson(w, 200, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iooptions 可选磁盘
|
||||||
|
func Iooptions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
diskStat, _ := disk.IOCounters()
|
||||||
|
var options []string
|
||||||
|
options = append(options, "all")
|
||||||
|
for _, net := range diskStat {
|
||||||
|
options = append(options, net.Name)
|
||||||
|
}
|
||||||
|
sort.Strings(options)
|
||||||
|
services.ResponseWithJson(w, 200, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadMonitor 载入监控
|
||||||
|
func LoadMonitor(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs MonitorSearch
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil || dborm.DbClient.XEngine == nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loc := time.Now().Location()
|
||||||
|
bodyArgs.StartTime = bodyArgs.StartTime.In(loc)
|
||||||
|
bodyArgs.EndTime = bodyArgs.EndTime.In(loc)
|
||||||
|
|
||||||
|
var backdatas []MonitorData
|
||||||
|
if bodyArgs.Param == "all" || bodyArgs.Param == "cpu" || bodyArgs.Param == "memory" || bodyArgs.Param == "load" {
|
||||||
|
var bases []MonitorBase
|
||||||
|
err := dborm.DbClient.XEngine.Table("monitor_base").
|
||||||
|
Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime).
|
||||||
|
Desc("created_at").
|
||||||
|
Find(&bases)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemData MonitorData
|
||||||
|
itemData.Param = "base"
|
||||||
|
for _, base := range bases {
|
||||||
|
itemData.Date = append(itemData.Date, base.CreatedAt)
|
||||||
|
itemData.Value = append(itemData.Value, base)
|
||||||
|
}
|
||||||
|
backdatas = append(backdatas, itemData)
|
||||||
|
}
|
||||||
|
if bodyArgs.Param == "all" || bodyArgs.Param == "io" {
|
||||||
|
var bases []MonitorIO
|
||||||
|
err := dborm.DbClient.XEngine.Table("monitor_io").
|
||||||
|
Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime).
|
||||||
|
Desc("created_at").
|
||||||
|
Find(&bases)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemData MonitorData
|
||||||
|
itemData.Param = "io"
|
||||||
|
for _, base := range bases {
|
||||||
|
itemData.Date = append(itemData.Date, base.CreatedAt)
|
||||||
|
itemData.Value = append(itemData.Value, base)
|
||||||
|
}
|
||||||
|
backdatas = append(backdatas, itemData)
|
||||||
|
}
|
||||||
|
if bodyArgs.Param == "all" || bodyArgs.Param == "network" {
|
||||||
|
var bases []MonitorNetwork
|
||||||
|
err := dborm.DbClient.XEngine.Table("monitor_network").
|
||||||
|
Where("name = ? AND created_at > ? AND created_at < ?", bodyArgs.Info, bodyArgs.StartTime, bodyArgs.EndTime).
|
||||||
|
Desc("created_at").
|
||||||
|
Find(&bases)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemData MonitorData
|
||||||
|
itemData.Param = "network"
|
||||||
|
for _, base := range bases {
|
||||||
|
itemData.Date = append(itemData.Date, base.CreatedAt)
|
||||||
|
itemData.Value = append(itemData.Value, base)
|
||||||
|
}
|
||||||
|
backdatas = append(backdatas, itemData)
|
||||||
|
}
|
||||||
|
services.ResponseWithJson(w, 200, backdatas)
|
||||||
|
}
|
||||||
233
features/monitor/monitor/task.go
Normal file
233
features/monitor/monitor/task.go
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
package monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
"github.com/shirou/gopsutil/v3/disk"
|
||||||
|
"github.com/shirou/gopsutil/v3/load"
|
||||||
|
"github.com/shirou/gopsutil/v3/mem"
|
||||||
|
"github.com/shirou/gopsutil/v3/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MonitorService struct{}
|
||||||
|
|
||||||
|
type IMonitorService interface {
|
||||||
|
Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIMonitorService() IMonitorService {
|
||||||
|
return &MonitorService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MonitorService) Run() {
|
||||||
|
// monitorStatus, _ := dborm.XormGetConfig("SystemMonitor", "MonitorStatus")
|
||||||
|
// if monitorStatus["value"] == "disable" {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
var itemModel MonitorBase
|
||||||
|
itemModel.CreatedAt = time.Now()
|
||||||
|
itemModel.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
totalPercent, _ := cpu.Percent(3*time.Second, false)
|
||||||
|
if len(totalPercent) == 1 {
|
||||||
|
itemModel.Cpu = totalPercent[0]
|
||||||
|
}
|
||||||
|
cpuCount, _ := cpu.Counts(false)
|
||||||
|
|
||||||
|
loadInfo, _ := load.Avg()
|
||||||
|
itemModel.CpuLoad1 = loadInfo.Load1
|
||||||
|
itemModel.CpuLoad5 = loadInfo.Load5
|
||||||
|
itemModel.CpuLoad15 = loadInfo.Load15
|
||||||
|
itemModel.LoadUsage = loadInfo.Load1 / (float64(cpuCount*2) * 0.75) * 100
|
||||||
|
|
||||||
|
memoryInfo, _ := mem.VirtualMemory()
|
||||||
|
itemModel.Memory = memoryInfo.UsedPercent
|
||||||
|
|
||||||
|
var dataSize int
|
||||||
|
conf := config.GetYamlConfig()
|
||||||
|
result, err := dborm.DbClient.XEngine.QueryString("SELECT SUM(data_length) AS data_size FROM information_schema.tables WHERE TABLE_SCHEMA = ?;", conf.Database.Name)
|
||||||
|
if err != nil {
|
||||||
|
dataSize = 0
|
||||||
|
} else {
|
||||||
|
v, _ := strconv.Atoi(result[0]["data_size"])
|
||||||
|
dataSize = v
|
||||||
|
}
|
||||||
|
itemModel.DbSize = uint(dataSize)
|
||||||
|
|
||||||
|
_, errx := dborm.DbClient.XEngine.Table("monitor_base").Insert(itemModel)
|
||||||
|
if errx != nil {
|
||||||
|
log.Errorf("Insert basic monitoring data failed, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go loadDiskIO()
|
||||||
|
go loadNetIO()
|
||||||
|
|
||||||
|
// 删除保留的记录
|
||||||
|
// monitorStoreDays, _ := dborm.XormGetConfig("SystemMonitor", "MonitorStoreDays")
|
||||||
|
// if monitorStoreDays["value"] != "" {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// storeDays, err := strconv.Atoi(MonitorStoreDays.Value)
|
||||||
|
// if err != nil {
|
||||||
|
// timeForDelete := time.Now().AddDate(0, 0, -storeDays)
|
||||||
|
// DelMonitorBase(timeForDelete)
|
||||||
|
// DelMonitorIO(timeForDelete)
|
||||||
|
// DelMonitorNet(timeForDelete)
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadDiskIO() {
|
||||||
|
ioStat, _ := disk.IOCounters()
|
||||||
|
|
||||||
|
time.Sleep(60 * time.Second)
|
||||||
|
|
||||||
|
ioStat2, _ := disk.IOCounters()
|
||||||
|
var ioList []MonitorIO
|
||||||
|
for _, io2 := range ioStat2 {
|
||||||
|
for _, io1 := range ioStat {
|
||||||
|
if io2.Name == io1.Name {
|
||||||
|
var itemIO MonitorIO
|
||||||
|
itemIO.CreatedAt = time.Now()
|
||||||
|
itemIO.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
itemIO.Name = io1.Name
|
||||||
|
if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes {
|
||||||
|
itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / 60)
|
||||||
|
}
|
||||||
|
if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes {
|
||||||
|
itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / 60)
|
||||||
|
}
|
||||||
|
|
||||||
|
if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount {
|
||||||
|
itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / 60)
|
||||||
|
}
|
||||||
|
writeCount := uint64(0)
|
||||||
|
if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount {
|
||||||
|
writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / 60)
|
||||||
|
}
|
||||||
|
if writeCount > itemIO.Count {
|
||||||
|
itemIO.Count = writeCount
|
||||||
|
}
|
||||||
|
|
||||||
|
if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime {
|
||||||
|
itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / 60)
|
||||||
|
}
|
||||||
|
writeTime := uint64(0)
|
||||||
|
if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime {
|
||||||
|
writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / 60)
|
||||||
|
}
|
||||||
|
if writeTime > itemIO.Time {
|
||||||
|
itemIO.Time = writeTime
|
||||||
|
}
|
||||||
|
ioList = append(ioList, itemIO)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := dborm.DbClient.XEngine.Table("monitor_io").Insert(ioList)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Insert io monitoring data failed, err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNetIO() {
|
||||||
|
netStat, _ := net.IOCounters(true)
|
||||||
|
netStatAll, _ := net.IOCounters(false)
|
||||||
|
|
||||||
|
time.Sleep(60 * time.Second)
|
||||||
|
|
||||||
|
netStat2, _ := net.IOCounters(true)
|
||||||
|
var netList []MonitorNetwork
|
||||||
|
for _, net2 := range netStat2 {
|
||||||
|
for _, net1 := range netStat {
|
||||||
|
if net2.Name == net1.Name {
|
||||||
|
var itemNet MonitorNetwork
|
||||||
|
itemNet.CreatedAt = time.Now()
|
||||||
|
itemNet.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
itemNet.Name = net1.Name
|
||||||
|
|
||||||
|
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
|
||||||
|
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60
|
||||||
|
}
|
||||||
|
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
|
||||||
|
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60
|
||||||
|
}
|
||||||
|
netList = append(netList, itemNet)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
netStatAll2, _ := net.IOCounters(false)
|
||||||
|
for _, net2 := range netStatAll2 {
|
||||||
|
for _, net1 := range netStatAll {
|
||||||
|
if net2.Name == net1.Name {
|
||||||
|
var itemNet MonitorNetwork
|
||||||
|
itemNet.Name = net1.Name
|
||||||
|
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
|
||||||
|
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
|
||||||
|
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60
|
||||||
|
}
|
||||||
|
netList = append(netList, itemNet)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := dborm.DbClient.XEngine.Table("monitor_network").Insert(netList)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Insert network monitoring data failed, err: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var c *cron.Cron
|
||||||
|
var monitorCronID int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
c = cron.New()
|
||||||
|
c.Start()
|
||||||
|
monitorCronID = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartMonitor 开始监控任务 removeBefore删除上次任务,间隔interval分钟
|
||||||
|
func StartMonitor(removeBefore bool, interval string) error {
|
||||||
|
if removeBefore {
|
||||||
|
c.Remove(cron.EntryID(monitorCronID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取配置
|
||||||
|
if interval == "" {
|
||||||
|
v, err := dborm.XormGetConfig("SystemMonitor", "sampleTime")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data := make(map[string]any)
|
||||||
|
err = json.Unmarshal([]byte(v["value_json"].(string)), &data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("json StartMonitor:%s", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
interval = data["sampleTime"].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
imservice := NewIMonitorService()
|
||||||
|
monitorID, err := c.AddJob(fmt.Sprintf("@every %sm", interval), imservice)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
imservice.Run()
|
||||||
|
monitorCronID = int(monitorID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
93
features/monitor/psnet/psnet.go
Normal file
93
features/monitor/psnet/psnet.go
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
package psnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/lib/wsinfo"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/shirou/gopsutil/process"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// websockte通信
|
||||||
|
UriWs = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/ws"
|
||||||
|
// 停止进程
|
||||||
|
UriStop = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/stop"
|
||||||
|
|
||||||
|
// 检查ip端口请求
|
||||||
|
UriPing = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/ping"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 进程管理
|
||||||
|
var wsUpgrade = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessWs
|
||||||
|
func ProcessWs(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ws, err := wsUpgrade.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wsClient := wsinfo.NewWsClient("processClient", ws)
|
||||||
|
go wsClient.Read()
|
||||||
|
go wsClient.Write()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止进程 {"PID":30040}
|
||||||
|
func StopProcess(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs struct {
|
||||||
|
PID int32 `json:"PID" validate:"required"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := process.NewProcess(bodyArgs.PID)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := proc.Kill(); err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查ip端口请求
|
||||||
|
func Ping(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// json 請求參數獲取
|
||||||
|
var bodyArgs struct {
|
||||||
|
Host string `json:"host" validate:"required"`
|
||||||
|
Port string `json:"port" validate:"required"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &bodyArgs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", bodyArgs.Host, bodyArgs.Port), 3*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
|
||||||
|
}
|
||||||
259
features/nbi/nbi.go
Normal file
259
features/nbi/nbi.go
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
package nbi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/oauth"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/lib/session"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorOAuthResponse struct {
|
||||||
|
Error map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FailOAuthResponse struct {
|
||||||
|
Error struct {
|
||||||
|
ErrorCode string
|
||||||
|
ErrorInfo string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApiResponse struct {
|
||||||
|
ResultCode string
|
||||||
|
ResultMessage interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalSession = session.NewSessManager("restagent")
|
||||||
|
|
||||||
|
var (
|
||||||
|
MAX_RMUID_NUM int
|
||||||
|
MAX_ALARMID_NUM int
|
||||||
|
MAX_PMUID_NUM int
|
||||||
|
MAX_SUBID_NUM int
|
||||||
|
MAX_URI_LEN int
|
||||||
|
RMUID_REGEXP string
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Northbound interface
|
||||||
|
GetNRMUri = config.DefaultUriPrefix + "/resourceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
|
||||||
|
NorthboundGetAlarmUri = config.DefaultUriPrefix + "/faultManagement/{apiVersion}/alarms" // ?alarmIds={alarmIdValues}
|
||||||
|
|
||||||
|
CustomGetNRMUri = config.UriPrefix + "/resourceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CheckParameterName(r *http.Request) []string {
|
||||||
|
var errorParams []string
|
||||||
|
vars := r.URL.Query()
|
||||||
|
for k, v := range vars {
|
||||||
|
log.Debug("vars:", k, v)
|
||||||
|
if k != "rmUIDs" && k != "fields" {
|
||||||
|
errorParams = append(errorParams, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorParams
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRmUIDArr(r *http.Request) []string {
|
||||||
|
vars := r.URL.Query()
|
||||||
|
rmUIDs, ok := vars["rmUIDs"]
|
||||||
|
if !ok {
|
||||||
|
log.Debug("rmUIDs is not exist")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var rmUIDValues []string
|
||||||
|
for _, r := range rmUIDs {
|
||||||
|
if r != "" {
|
||||||
|
rmUIDValues = global.MergeStringArr(rmUIDValues, strings.Split(r, `,`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rmUIDValues
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAttrNameArr(r *http.Request) []string {
|
||||||
|
vars := r.URL.Query()
|
||||||
|
fields, ok := vars["fields"]
|
||||||
|
if !ok {
|
||||||
|
log.Debug("attributeNames does not exist")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var attrNames []string
|
||||||
|
for _, a := range fields {
|
||||||
|
if a != "" {
|
||||||
|
attrNames = global.MergeStringArr(attrNames, strings.Split(a, `,`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrNames
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckValidRmUID(rmUIDs []string) []string {
|
||||||
|
log.Debug("CheckValidRmUID processing... ")
|
||||||
|
|
||||||
|
var invalidRmUIDs []string
|
||||||
|
for _, r := range rmUIDs {
|
||||||
|
if !global.MatchRmUID(RMUID_REGEXP, r) {
|
||||||
|
invalidRmUIDs = append(invalidRmUIDs, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return invalidRmUIDs
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckLocalRmUID(rmUIDs []string) string {
|
||||||
|
log.Debug("GetLocalRmUID processing... ")
|
||||||
|
|
||||||
|
rmUID := config.GetRmUIDFromConfig()
|
||||||
|
for _, r := range rmUIDs {
|
||||||
|
if r == rmUID {
|
||||||
|
return rmUID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func NBIGetNRMFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("NBIGetNRMFromNF processing... ")
|
||||||
|
|
||||||
|
// response 414-4 uri too long ? (optional)
|
||||||
|
// todo ... ?
|
||||||
|
if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() {
|
||||||
|
log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig())
|
||||||
|
services.ResponseRequestURITooLong414UriTooLong(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
// response 415-1
|
||||||
|
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// error processing ...
|
||||||
|
// 401-1 response
|
||||||
|
token, ret := oauth.IsCarriedToken(r)
|
||||||
|
if ret == false {
|
||||||
|
log.Error("AccessToken is not carried")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 401-2 response
|
||||||
|
if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false {
|
||||||
|
log.Error("AccessToken fails or does not exist")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotExist(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := dborm.XormUpdateSessionShakeTime(token)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to update session table:", err)
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotExist(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// response 403 Forbidden, permissions deny
|
||||||
|
// todo...
|
||||||
|
plist := globalSession.GetPermissionFromSession(token)
|
||||||
|
log.Debug("permission list:", plist)
|
||||||
|
if len(plist) == 0 || plist[0] == false {
|
||||||
|
log.Debug("User permission deny")
|
||||||
|
services.ResponseForbidden403NotPermission(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != "v1" {
|
||||||
|
log.Error("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 406-1
|
||||||
|
rmUIDValues := GetRmUIDArr(r)
|
||||||
|
if rmUIDValues == nil {
|
||||||
|
log.Error("missing parameter: rmUIDs")
|
||||||
|
services.ResponseNotAcceptable406MissingParam(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 406-2
|
||||||
|
errorParams := CheckParameterName(r)
|
||||||
|
if errorParams != nil {
|
||||||
|
log.Error("parameter name error: ", errorParams)
|
||||||
|
services.ResponseNotAcceptable406ParamError(w, errorParams)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 400-5
|
||||||
|
if len(rmUIDValues) == 0 {
|
||||||
|
log.Error("rmUIDs is wrong or NULL")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 414-1
|
||||||
|
if len(rmUIDValues) > config.GetYamlConfig().Params.RmUIDMaxNum {
|
||||||
|
log.Error("rmUID greater than", config.GetYamlConfig().Params.RmUIDMaxNum)
|
||||||
|
services.ResponseRequestURITooLong414NRMNumExceed(w, config.GetYamlConfig().Params.RmUIDMaxNum)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var response *resty.Response
|
||||||
|
respMsg := make(map[string]interface{})
|
||||||
|
for _, rmUID := range rmUIDValues {
|
||||||
|
neInfo, err := dborm.XormGetNeInfoByRmUID(neType, rmUID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: GET ", requestURI2NF)
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
response, 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.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated:
|
||||||
|
respMsg["data"] = response
|
||||||
|
default:
|
||||||
|
if response != nil {
|
||||||
|
services.TransportResponse(w, response.StatusCode(), response.Body())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.TransportResponse(w, response.StatusCode(), response.Body())
|
||||||
|
}
|
||||||
203
features/nbi/snmp.go
Normal file
203
features/nbi/snmp.go
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
package nbi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
g "github.com/gosnmp/gosnmp"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
conf := config.GetYamlConfig()
|
||||||
|
// Default is a pointer to a GoSNMP struct that contains sensible defaults
|
||||||
|
// eg port 161, community public, etc
|
||||||
|
g.Default.Target = conf.NE.Addr
|
||||||
|
g.Default.Port = conf.NE.Port
|
||||||
|
err := g.Default.Connect()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Connect() err: %v", err)
|
||||||
|
}
|
||||||
|
//defer g.Default.Conn.Close()
|
||||||
|
MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig()
|
||||||
|
MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig()
|
||||||
|
MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig()
|
||||||
|
MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig()
|
||||||
|
MAX_URI_LEN = config.GetUriMaxLenFromConfig()
|
||||||
|
RMUID_REGEXP = config.GetRmUIDRegexpFromConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNRMByUri(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetNRMByUri processing... ")
|
||||||
|
|
||||||
|
// response 414-4 uri too long ? (optional)
|
||||||
|
// todo ... ?
|
||||||
|
if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN {
|
||||||
|
log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil))
|
||||||
|
services.ResponseRequestURITooLong414UriTooLong(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
// response 415-1
|
||||||
|
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// error processing ...
|
||||||
|
// 401-1 response
|
||||||
|
token, ret := globalSession.IsCarriedToken(r)
|
||||||
|
if ret == false {
|
||||||
|
log.Error("AccessToken is not carried")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 401-2 response
|
||||||
|
if globalSession.IsValidToken(token) == false {
|
||||||
|
log.Error("AccessToken fails or does not exist")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotExist(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// response 403 Forbidden, permissions deny
|
||||||
|
// todo...
|
||||||
|
plist := globalSession.GetPermissionFromSession(token)
|
||||||
|
log.Debug("permission list:", plist)
|
||||||
|
if len(plist) == 0 || plist[0] == false {
|
||||||
|
log.Error("User permission deny")
|
||||||
|
services.ResponseForbidden403NotPermission(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"]
|
||||||
|
log.Debug("Get by Uri: ", qeuryUri)
|
||||||
|
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != "v1" {
|
||||||
|
log.Error("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 406-1
|
||||||
|
rmUIDValues := GetRmUIDArr(r)
|
||||||
|
if rmUIDValues == nil {
|
||||||
|
log.Error("missing parameter: rmUIDs")
|
||||||
|
services.ResponseNotAcceptable406MissingParam(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 406-2
|
||||||
|
errorParams := CheckParameterName(r)
|
||||||
|
if errorParams != nil {
|
||||||
|
log.Error("parameter name error: ", errorParams)
|
||||||
|
services.ResponseNotAcceptable406ParamError(w, errorParams)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 400-5
|
||||||
|
if len(rmUIDValues) == 0 {
|
||||||
|
log.Error("rmUIDs is wrong or NULL")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 414-1
|
||||||
|
if len(rmUIDValues) > MAX_RMUID_NUM {
|
||||||
|
log.Error("rmUID greater than", MAX_RMUID_NUM)
|
||||||
|
services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 400-1
|
||||||
|
// check rmUID is valid
|
||||||
|
// todo ...
|
||||||
|
invalidRmUIDs := CheckValidRmUID(rmUIDValues)
|
||||||
|
if len(invalidRmUIDs) != 0 {
|
||||||
|
log.Error("rmUID is invalid")
|
||||||
|
services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 404-2
|
||||||
|
rmUID := CheckLocalRmUID(rmUIDValues)
|
||||||
|
if rmUID == "" {
|
||||||
|
log.Error("rmUID does not exist")
|
||||||
|
services.ResponseNotFound404NRMNotExist(w, rmUIDValues)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 404-1, uri is not exist in map
|
||||||
|
attrNames := GetAttrNameArr(r)
|
||||||
|
var Oids []string
|
||||||
|
Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids)
|
||||||
|
if len(Oids) == 0 {
|
||||||
|
log.Error("Nothing of config map")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// response 404-1, uri is not exist in map
|
||||||
|
var nameOids []config.NameOid
|
||||||
|
nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids)
|
||||||
|
if len(nameOids) == 0 {
|
||||||
|
log.Error("Nothing of config map")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS
|
||||||
|
if err2 != nil {
|
||||||
|
log.Fatalf("Get() err: %v", err2)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// var nameValues []config.NameValue
|
||||||
|
var nameValue config.NameValue
|
||||||
|
|
||||||
|
nameValues := make(map[string]interface{})
|
||||||
|
nameValues["rmUID"] = rmUID
|
||||||
|
for i, variable := range result.Variables {
|
||||||
|
nameValue.Name = nameOids[i].Name
|
||||||
|
log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name)
|
||||||
|
// if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) {
|
||||||
|
if nameOids[i].Oid == variable.Name {
|
||||||
|
// the Value of each variable returned by Get() implements
|
||||||
|
// interface{}. You could do a type switch...
|
||||||
|
switch variable.Type {
|
||||||
|
case g.OctetString:
|
||||||
|
bytes := variable.Value.([]byte)
|
||||||
|
log.Debugf("string: %s\n", string(bytes))
|
||||||
|
nameValue.Value = string(bytes)
|
||||||
|
nameValues[nameValue.Name] = nameValue.Value
|
||||||
|
case g.Integer:
|
||||||
|
value := variable.Value.(int)
|
||||||
|
log.Debugf("integer: %d\n", value)
|
||||||
|
nameValue.Value = strconv.Itoa(value)
|
||||||
|
nameValues[nameValue.Name] = nameValue.Value
|
||||||
|
case g.IPAddress:
|
||||||
|
value := variable.Value.(string)
|
||||||
|
log.Debugf("IPAddress: %s\n", variable.Value)
|
||||||
|
nameValue.Value = value
|
||||||
|
nameValues[nameValue.Name] = nameValue.Value
|
||||||
|
default:
|
||||||
|
// ... or often you're just interested in numeric values.
|
||||||
|
// ToBigInt() will return the Value as a BigInt, for plugging
|
||||||
|
// into your calculations.
|
||||||
|
log.Debugf("number: %d\n", g.ToBigInt(variable.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponse := services.DataResponse{nameValues}
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, getResponse)
|
||||||
|
}
|
||||||
977
features/pm/performance.go
Normal file
977
features/pm/performance.go
Normal file
@@ -0,0 +1,977 @@
|
|||||||
|
package pm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KpiReport struct {
|
||||||
|
Timestamp string `json:"TimeStamp"`
|
||||||
|
Task struct {
|
||||||
|
Period struct {
|
||||||
|
StartTime string `json:"StartTime"`
|
||||||
|
EndTime string `json:"EndTime"`
|
||||||
|
} `json:"Period"`
|
||||||
|
NE struct {
|
||||||
|
NEName string `json:"NEName"`
|
||||||
|
RmUID string `json:"rmUID"`
|
||||||
|
NeType string `json:"NeType"`
|
||||||
|
KPIs []struct {
|
||||||
|
KPIID string `json:"KPIID"`
|
||||||
|
Value int `json:"Value"`
|
||||||
|
Err string `json:"Err"`
|
||||||
|
} `json:"KPIs"`
|
||||||
|
} `json:"NE"`
|
||||||
|
} `json:"Task"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GoldKpi struct {
|
||||||
|
// Id int `json:"-" xorm:"pk 'id' autoincr"`
|
||||||
|
Date string `json:"date" xorm:"date"`
|
||||||
|
Index int `json:"index"`
|
||||||
|
StartTime string `json:"startTime"`
|
||||||
|
EndTime string `json:"endTime"`
|
||||||
|
NEName string `json:"neName" xorm:"ne_name"`
|
||||||
|
RmUid string `json:"rmUid" xorm:"rm_uid"`
|
||||||
|
NEType string `json:"neType" xorm:"ne_type"`
|
||||||
|
KpiId string `json:"kpiId" xorm:"kpi_id"`
|
||||||
|
Value int `json:"value"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// performance management
|
||||||
|
PerformanceUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}"
|
||||||
|
MeasureTaskUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureTask"
|
||||||
|
MeasureReportUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureReport"
|
||||||
|
MeasureReportFmt = config.DefaultUriPrefix + "/performanceManagement/v1/elementType/%s/objectType/measureReport"
|
||||||
|
MeasurementUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measurement/{index}"
|
||||||
|
UriMeasureTask = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/measureTask/{netype}"
|
||||||
|
|
||||||
|
// performance management
|
||||||
|
CustomPerformanceUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}"
|
||||||
|
CustomMeasureTaskUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureTask"
|
||||||
|
CustomMeasureReportUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureReport"
|
||||||
|
CustomMeasureReportFmt = config.UriPrefix + "/performanceManagement/v1/elementType/%s/objectType/measureReport"
|
||||||
|
CustomMeasurementUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measurement/{index}"
|
||||||
|
CustomUriMeasureTask = config.UriPrefix + "/performanceManagement/{apiVersion}/measureTask/{netype}"
|
||||||
|
)
|
||||||
|
|
||||||
|
var xEngine *xorm.Engine
|
||||||
|
|
||||||
|
type DatabaseClient struct {
|
||||||
|
dbType string
|
||||||
|
dbUrl string
|
||||||
|
dbConnMaxLifetime time.Duration
|
||||||
|
dbMaxIdleConns int
|
||||||
|
dbMaxOpenConns int
|
||||||
|
IsShowSQL bool
|
||||||
|
|
||||||
|
XEngine *xorm.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
var DbClient DatabaseClient
|
||||||
|
|
||||||
|
func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error {
|
||||||
|
DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbUser, dbPassword, dbHost, dbPort, dbName)
|
||||||
|
DbClient.dbType = dbType
|
||||||
|
DbClient.dbConnMaxLifetime = 0
|
||||||
|
DbClient.dbMaxIdleConns = 0
|
||||||
|
DbClient.dbMaxOpenConns = 0
|
||||||
|
if log.GetLevel() == log.LOG_TRACE {
|
||||||
|
DbClient.IsShowSQL = true
|
||||||
|
}
|
||||||
|
log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbType, dbUser, dbHost, dbPort, dbName)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connet database:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime)
|
||||||
|
DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns)
|
||||||
|
DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns)
|
||||||
|
if DbClient.IsShowSQL {
|
||||||
|
DbClient.XEngine.ShowSQL(true)
|
||||||
|
}
|
||||||
|
xEngine = DbClient.XEngine
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func XormConnectDatabase(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) (*xorm.Engine, error) {
|
||||||
|
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbUser, dbPassword, dbHost, dbPort, dbName)
|
||||||
|
log.Debugf("dbType:%s Connect to:%s:******@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbType, dbUser, dbHost, dbPort, dbName)
|
||||||
|
var err error
|
||||||
|
xEngine, err = xorm.NewEngine(dbType, sqlStr) //1、Create xorm engine
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect database:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if log.GetLevel() == log.LOG_TRACE {
|
||||||
|
xEngine.ShowSQL(true)
|
||||||
|
}
|
||||||
|
return xEngine, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDateFromTimeString(fmtString string, timeString string) string {
|
||||||
|
t, _ := time.ParseInLocation(fmtString, timeString, time.Local)
|
||||||
|
return t.Format("2006-01-02")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDateTimeFromTimeString(fmtString string, timeString string) string {
|
||||||
|
t, _ := time.ParseInLocation(fmtString, timeString, time.Local)
|
||||||
|
return t.Format(global.DateTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process alarm post message from NFs
|
||||||
|
func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostKPIReportFromNF processing... ")
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != global.ApiVersionV1 {
|
||||||
|
log.Error("Uri api version is invalid. apiVersion:", apiVer)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to io.ReadAll: ", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Request body:", string(body))
|
||||||
|
kpiReport := new(KpiReport)
|
||||||
|
_ = json.Unmarshal(body, &kpiReport)
|
||||||
|
log.Debug("kpiReport:", kpiReport)
|
||||||
|
|
||||||
|
session := xEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
goldKpi := new(GoldKpi)
|
||||||
|
layout := time.RFC3339Nano
|
||||||
|
goldKpi.Date = GetDateFromTimeString(layout, kpiReport.Task.Period.StartTime)
|
||||||
|
goldKpi.Index, _ = strconv.Atoi(vars["index"])
|
||||||
|
goldKpi.StartTime = global.GetFmtTimeString(layout, kpiReport.Task.Period.StartTime, time.DateTime)
|
||||||
|
goldKpi.EndTime = global.GetFmtTimeString(layout, kpiReport.Task.Period.EndTime, time.DateTime)
|
||||||
|
goldKpi.NEName = kpiReport.Task.NE.NEName
|
||||||
|
goldKpi.RmUid = kpiReport.Task.NE.RmUID
|
||||||
|
goldKpi.NEType = kpiReport.Task.NE.NeType
|
||||||
|
goldKpi.Timestamp = global.GetFmtTimeString(layout, kpiReport.Timestamp, time.DateTime)
|
||||||
|
for _, k := range kpiReport.Task.NE.KPIs {
|
||||||
|
goldKpi.KpiId = k.KPIID
|
||||||
|
goldKpi.Value = k.Value
|
||||||
|
goldKpi.Error = k.Err
|
||||||
|
log.Trace("goldKpi:", goldKpi)
|
||||||
|
|
||||||
|
// 启动事务
|
||||||
|
err := session.Begin()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Begin gold_kpi:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gkpi := &GoldKpi{}
|
||||||
|
_, err = session.Where("id = ?", 1).ForUpdate().Get(gkpi)
|
||||||
|
if err != nil {
|
||||||
|
// 回滚事务
|
||||||
|
session.Rollback()
|
||||||
|
log.Error("Failed to ForUpdate gold_kpi:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
affected, err := session.Insert(goldKpi)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
session.Rollback()
|
||||||
|
log.Error("Failed to insert gold_kpi:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 提交事务
|
||||||
|
err = session.Commit()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Commit gold_kpi:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeasureTask struct {
|
||||||
|
Tasks []Task `json:"Tasks"`
|
||||||
|
NotifyUrl string `json:"NotifyUrl"` /* "http://xEngine.xEngine.xEngine.x:xxxx/api/rest/performanceManagement/v1/elementType/smf/objectType/measureReport */
|
||||||
|
}
|
||||||
|
|
||||||
|
type Task struct {
|
||||||
|
Id int `json:"Id"`
|
||||||
|
|
||||||
|
StartTime string `json:"StartTime"`
|
||||||
|
EndTime string `json:"EndTime"`
|
||||||
|
|
||||||
|
Schedule struct {
|
||||||
|
Type string `json:"Type"` // 计划类型:Weekly/Monthly, 如果type为"", 则任务以StartTime和EndTime为条件进行统计, 否则以Shedule方式进行
|
||||||
|
Days []int `json:"Days"` // Weekly: [0,1,...,5,6] 星期日为0, Monthly: [1,2,3,...,30,31]
|
||||||
|
Periods []dborm.Period `json:"Periods"`
|
||||||
|
/*
|
||||||
|
Periods []struct {
|
||||||
|
Start string `json:"Start"` // 零点或者零点加测量粒度的整数倍
|
||||||
|
End string `json:"End"` //零点加测量粒度的整数倍
|
||||||
|
} `json:"Periods"`
|
||||||
|
*/
|
||||||
|
} `json:"Schedule"`
|
||||||
|
|
||||||
|
GranulOption string `json:"GranulOption"` // 测量粒度选项:15M/30M/60M/24H
|
||||||
|
KPISet []dborm.KpiSetJ `json:"KPISet"`
|
||||||
|
/*
|
||||||
|
KPISet []struct {
|
||||||
|
Code string `json:"Code"` // 统计编码 如:SMFHA01
|
||||||
|
KPIs []string `json:"KPIs` // 指标项集合 ["SMF.AttCreatePduSession", "SMF.AttCreatePduSession._Dnn"]
|
||||||
|
} `json:"KPISet"`
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeasureReport struct {
|
||||||
|
Id int `json:"Id"`
|
||||||
|
TimeStamp string `json:"TimeStamp"`
|
||||||
|
NeName string `json:"NeName"`
|
||||||
|
RmUID string `json:"rmUID"`
|
||||||
|
NeType string `json:"NeType"`
|
||||||
|
|
||||||
|
Report struct {
|
||||||
|
Period struct {
|
||||||
|
StartTime string `json:"StartTime"`
|
||||||
|
EndTime string `json:"EndTime"`
|
||||||
|
} `json:"Period"`
|
||||||
|
|
||||||
|
Datas []struct {
|
||||||
|
Code string `json:"Code"` // 统计编码 如:SMFHA01
|
||||||
|
KPIs []struct {
|
||||||
|
KPIID string `json:"KPIID"` // 指标项, 如: SMF.AttCreatePduSession._Dnn
|
||||||
|
KPIValues []struct {
|
||||||
|
Name string `json:"Name"` // 单个的写"Total", 或者指标项有多个测量项,如Dnn的名称写对应的Dnn"cmnet"/"ims"
|
||||||
|
Value int64 `json:"Value"`
|
||||||
|
} `json:"KPIValues"`
|
||||||
|
} `json:"KPIs"`
|
||||||
|
} `json:"Datas"`
|
||||||
|
} `json:"Report"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeasureData struct {
|
||||||
|
// Id int `json:"id" xorm:"pk 'id' autoincr"`
|
||||||
|
Id int `json:"id" xorm:"-"`
|
||||||
|
Date string `json:"date" xorm:"date"`
|
||||||
|
TaskId int `json:"taskId"`
|
||||||
|
NeType string `json:"neType" xorm:"ne_type"`
|
||||||
|
NeName string `json:"neName" xorm:"ne_name"`
|
||||||
|
RmUid string `json:"rmUid" xorm:"rm_uid"`
|
||||||
|
GranulOption string `json:"granulOption" xorm:"granul_option"`
|
||||||
|
StartTime string `json:"startTime"`
|
||||||
|
EndTime string `json:"endTime"`
|
||||||
|
KpiCode string `json:"kpiCode" xorm:"kpi_code"`
|
||||||
|
KpiId string `json:"kpiId" xorm:"kpi_id"`
|
||||||
|
KpiExt string `json:"kpiExt" xorm:"kpi_ext"`
|
||||||
|
Value int64 `json:"value"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// process measure report from NFs
|
||||||
|
func PostMeasureReportFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostMeasureReportFromNF processing... ")
|
||||||
|
|
||||||
|
// vars := mux.Vars(r)
|
||||||
|
// neType := vars["elementTypeValue"]
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != global.ApiVersionV1 {
|
||||||
|
log.Error("Uri api version is invalid. apiVersion:", apiVer)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to io.ReadAll: ", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Request body:", string(body))
|
||||||
|
measureReport := new(MeasureReport)
|
||||||
|
_ = json.Unmarshal(body, &measureReport)
|
||||||
|
log.Debug("measureReport:", measureReport)
|
||||||
|
|
||||||
|
session := xEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
measureData := new(MeasureData)
|
||||||
|
layout := global.DateTime
|
||||||
|
measureData.Date = GetDateFromTimeString(layout, measureReport.Report.Period.StartTime)
|
||||||
|
measureData.TaskId = measureReport.Id
|
||||||
|
measureData.StartTime = measureReport.Report.Period.StartTime
|
||||||
|
measureData.EndTime = measureReport.Report.Period.EndTime
|
||||||
|
measureData.NeType = measureReport.NeType
|
||||||
|
measureData.NeName = measureReport.NeName
|
||||||
|
measureData.RmUid = measureReport.RmUID
|
||||||
|
measureData.GranulOption, _ = dborm.XormGetSingleCol("measure_task", "granul_option", fmt.Sprintf("id=%d", measureReport.Id))
|
||||||
|
t, _ := strconv.ParseInt(measureReport.TimeStamp, 10, 64)
|
||||||
|
timestamp := time.Unix(t, 0)
|
||||||
|
log.Debug("timestamp:", timestamp.Format(layout))
|
||||||
|
measureData.Timestamp = timestamp.Format(layout)
|
||||||
|
log.Debug("Datas:", measureReport.Report.Datas)
|
||||||
|
for _, d := range measureReport.Report.Datas {
|
||||||
|
measureData.KpiCode = d.Code
|
||||||
|
|
||||||
|
log.Debug("KPIs:", d.KPIs)
|
||||||
|
for _, k := range d.KPIs {
|
||||||
|
measureData.KpiId = k.KPIID
|
||||||
|
|
||||||
|
log.Debug("KPIValues:", k.KPIValues)
|
||||||
|
if len(k.KPIValues) != 0 {
|
||||||
|
for _, v := range k.KPIValues {
|
||||||
|
measureData.KpiExt = v.Name
|
||||||
|
measureData.Value = v.Value
|
||||||
|
log.Debug("measureData:", measureData)
|
||||||
|
|
||||||
|
affected, err := session.Insert(measureData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert measure_data:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
measureData.Value = 0
|
||||||
|
log.Debug("measureData:", measureData)
|
||||||
|
|
||||||
|
affected, err := session.Insert(measureData)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert measure_data:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PostMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostMeasureTaskToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
params := r.URL.Query()
|
||||||
|
taskIds := params["id"]
|
||||||
|
log.Debug("taskIds:", taskIds)
|
||||||
|
|
||||||
|
var response *resty.Response
|
||||||
|
client := resty.New()
|
||||||
|
measureTask := new(MeasureTask)
|
||||||
|
measureTask.Tasks = make([]Task, 1)
|
||||||
|
for _, taskId := range taskIds {
|
||||||
|
id, _ := strconv.Atoi(taskId)
|
||||||
|
task, err := dborm.GetMeasureTask(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect database: ", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Table Task:", task)
|
||||||
|
|
||||||
|
measureTask.Tasks[0].Id = task.Id
|
||||||
|
measureTask.Tasks[0].StartTime = task.StartTime
|
||||||
|
measureTask.Tasks[0].EndTime = task.EndTime
|
||||||
|
// v := new(dborm.ScheduleJson)
|
||||||
|
// _ = json.Unmarshal(task.Schedule, v)
|
||||||
|
// measureTask.Task[0].Schedule.Type = v.Type
|
||||||
|
// measureTask.Task[0].Schedule.Days = v.Days
|
||||||
|
if len(task.Schedule) >= 1 {
|
||||||
|
measureTask.Tasks[0].Schedule.Type = task.Schedule[0].Type
|
||||||
|
measureTask.Tasks[0].Schedule.Days = task.Schedule[0].Days
|
||||||
|
}
|
||||||
|
//v := new(dborm.ScheduleJ)
|
||||||
|
//_ = json.Unmarshal(task.Schedule, v)
|
||||||
|
measureTask.Tasks[0].Schedule.Periods = task.Periods
|
||||||
|
measureTask.Tasks[0].GranulOption = task.GranulOption
|
||||||
|
|
||||||
|
measureTask.Tasks[0].KPISet = task.KpiSet
|
||||||
|
ips, err := global.GetIps()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to get local IP:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("ips:", ips)
|
||||||
|
|
||||||
|
measureTask.NotifyUrl = global.SetNotifyUrl(ips[0], config.GetYamlConfig().Rest[0].Port, fmt.Sprintf(MeasureReportFmt, neType))
|
||||||
|
log.Debug("Measure Task to NF:", measureTask)
|
||||||
|
|
||||||
|
if len(task.NeIds) == 0 {
|
||||||
|
var neInfos []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, neInfo := range neInfos {
|
||||||
|
task.NeIds = append(task.NeIds, neInfo.NeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, neId := range task.NeIds {
|
||||||
|
var err error
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfo:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if neInfo == nil {
|
||||||
|
err := errors.New(fmt.Sprintf("not found target NE neType=%s, neId=%s", neType, neId))
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: POST ", requestURI2NF)
|
||||||
|
|
||||||
|
switch task.Status {
|
||||||
|
case dborm.MeasureTaskStatusInactive:
|
||||||
|
body, _ := json.Marshal(measureTask)
|
||||||
|
log.Debug("body: ", string(body))
|
||||||
|
|
||||||
|
log.Debug("User-Agent: ", config.GetDefaultUserAgent())
|
||||||
|
response, err = client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
SetContentLength(true).
|
||||||
|
Post(requestURI2NF)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Post to NF failed:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("response info: ")
|
||||||
|
log.Debug("Status Code:", response.StatusCode())
|
||||||
|
log.Debug("Status:", response.Status())
|
||||||
|
log.Debug("Proto:", response.Proto())
|
||||||
|
log.Debug("Time:", response.Time())
|
||||||
|
log.Debug("Received At:", response.ReceivedAt())
|
||||||
|
log.Debug("Size:", response.Size())
|
||||||
|
|
||||||
|
case dborm.MeasureTaskStatusSuspend:
|
||||||
|
body, _ := json.Marshal(measureTask)
|
||||||
|
log.Debug("body: ", string(body))
|
||||||
|
response, err = client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
SetContentLength(true).
|
||||||
|
Put(requestURI2NF)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Put to NF failed:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = errors.New(fmt.Sprintf("measure task status must be inactive id=%d", id))
|
||||||
|
log.Error("Unable to active measure task:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("StatusCode: ", response.StatusCode())
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusActive
|
||||||
|
taskInfo.CreateTime = time.Now().Format(time.DateTime)
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Error("NF return failure to active measure task")
|
||||||
|
if response != nil {
|
||||||
|
log.Info("response body:", string(response.Body()))
|
||||||
|
services.TransportResponse(w, response.StatusCode(), response.Body())
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
err = errors.New(fmt.Sprintf("failed to active measure task, NF return error status=%v", response.Status()))
|
||||||
|
log.Error("Unable to active measure task:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteMeasureTaskToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
params := r.URL.Query()
|
||||||
|
taskIds := params["id"]
|
||||||
|
log.Debug("taskIds:", taskIds)
|
||||||
|
|
||||||
|
var response *resty.Response
|
||||||
|
respMsg := make(map[string]interface{})
|
||||||
|
for _, taskId := range taskIds {
|
||||||
|
id, _ := strconv.Atoi(taskId)
|
||||||
|
task, err := dborm.GetMeasureTask(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect database: ", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Measure Task:", task)
|
||||||
|
|
||||||
|
if len(task.NeIds) == 0 {
|
||||||
|
var neInfos []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, neInfo := range neInfos {
|
||||||
|
task.NeIds = append(task.NeIds, neInfo.NeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("neIds:", task.NeIds)
|
||||||
|
if len(task.NeIds) == 0 {
|
||||||
|
log.Warn("Not found target NE in the measure task")
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusDeleted
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, neId := range task.NeIds {
|
||||||
|
var err error
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if neInfo != nil {
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: DELETE ", requestURI2NF)
|
||||||
|
client := resty.New()
|
||||||
|
response, err = client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
Delete(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
// to avoid can't delete the task for abnormal NF
|
||||||
|
log.Error("Failed to resty delete:", err)
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusDeleted
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("StatusCode: ", response.StatusCode())
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusDeleted
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Infof("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
log.Info("response body:", string(response.Body()))
|
||||||
|
body := new(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(response.Body(), &body)
|
||||||
|
respMsg["error"] = body
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusDeleted
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, response.StatusCode(), respMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PatchMeasureTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PatchMeasureTaskToNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
params := r.URL.Query()
|
||||||
|
taskIds := params["id"]
|
||||||
|
log.Debug("taskIds:", taskIds)
|
||||||
|
|
||||||
|
var response *resty.Response
|
||||||
|
respMsg := make(map[string]interface{})
|
||||||
|
for _, taskId := range taskIds {
|
||||||
|
id, _ := strconv.Atoi(taskId)
|
||||||
|
task, err := dborm.GetMeasureTask(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect database: ", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Measure Task:", task)
|
||||||
|
|
||||||
|
// for neType
|
||||||
|
if len(task.NeIds) == 0 {
|
||||||
|
var neInfos []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, neInfo := range neInfos {
|
||||||
|
task.NeIds = append(task.NeIds, neInfo.NeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(task.NeIds) == 0 {
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusInactive
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, neId := range task.NeIds {
|
||||||
|
var err error
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if neInfo == nil {
|
||||||
|
em := errors.New("Not found NE info in database")
|
||||||
|
log.Error(em)
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusInactive
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
//services.ResponseInternalServerError500ProcessError(w, em)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: PATCH ", requestURI2NF)
|
||||||
|
client := resty.New()
|
||||||
|
response, err = client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
Patch(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Patch to NF failed:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("StatusCode: ", response.StatusCode())
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
taskInfo := new(dborm.MeasureTask)
|
||||||
|
taskInfo.Status = dborm.MeasureTaskStatusInactive
|
||||||
|
affected, err := dborm.XormUpdateTableById(id, dborm.TableNameMeasureTask, taskInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormUpdateTableById is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
} else if affected <= 0 {
|
||||||
|
log.Info("Not record affected in measure_task")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Debug("response body:", string(response.Body()))
|
||||||
|
body := new(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(response.Body(), &body)
|
||||||
|
respMsg["error"] = body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, response.StatusCode(), respMsg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Measurement struct {
|
||||||
|
Id int `json:"-" xorm:"pk 'id' autoincr"`
|
||||||
|
Date string `json:"-" xorm:"date"`
|
||||||
|
Index int `json:"Index"` // 1天中测量时间粒度(如15分钟)的切片索引: 0~95
|
||||||
|
Timestamp string `json:"TimeStamp" xorm:"-"`
|
||||||
|
NeName string `json:"NeName"` // UserLabel
|
||||||
|
RmUID string `json:"RmUID" xorm:"rm_uid"`
|
||||||
|
NeType string `json:"NeType"` // 网元类型
|
||||||
|
PmVersion string `json:"PmVersion"` // 性能数据版本号
|
||||||
|
Dn string `json:"Dn"` // (???)网元标识, 如:RJN-CMZJ-TZ,SubNetwork=5GC88,ManagedElement=SMF53456,SmfFunction=53456
|
||||||
|
Period string `json:"Period"` // 测量时间粒度选项:5/15/30/60
|
||||||
|
TimeZone string `json:"TimeZone"`
|
||||||
|
StartTime string `json:"StartTime"`
|
||||||
|
|
||||||
|
Datas []Data `json:"Datas"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KPIValue struct {
|
||||||
|
Name string `json:"Name"` // 单个的写"Total", 或者指标项有多个测量项,如Dnn的名称写对应的Dnn"cmnet"/"ims"
|
||||||
|
Value int64 `json:"Value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KPI struct {
|
||||||
|
KPIID string `json:"KPIID"` // 指标项, 如: SMF.AttCreatePduSession._Dnn
|
||||||
|
KPIValues []KPIValue `json:"KPIValues"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
ObjectType string `json:"ObjectType"` // 网络资源类别名称, Pm指标项列表中为空间粒度 如:SmfFunction
|
||||||
|
KPIs []KPI `json:"KPIs"` // 指标项, 如: SMF.AttCreatePduSession._Dnn
|
||||||
|
}
|
||||||
|
|
||||||
|
// process measurement post message from NFs
|
||||||
|
func PostMeasurementFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostMeasurementFromNF processing... ")
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != global.ApiVersionV1 {
|
||||||
|
log.Error("Uri api version is invalid. apiVersion:", apiVer)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Faile to io.ReadAll: ", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("Request body:", string(body))
|
||||||
|
// measurement := new(dborm.NorthboundPm)
|
||||||
|
measurement := new(dborm.NorthboundPm)
|
||||||
|
_ = json.Unmarshal(body, &measurement)
|
||||||
|
log.Debug("measurement:", measurement)
|
||||||
|
|
||||||
|
session := dborm.DbClient.XEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
// layout := global.DateTime
|
||||||
|
layout := time.RFC3339
|
||||||
|
measurement.Date = GetDateFromTimeString(layout, measurement.StartTime)
|
||||||
|
measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime)
|
||||||
|
affected, err := session.Table("northbound_pm").Insert(measurement)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert northbound_pm:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get measurement message from NFs
|
||||||
|
func GetMeasurementFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetMeasurementFromNF processing... ")
|
||||||
|
|
||||||
|
_, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
apiVer := vars["apiVersion"]
|
||||||
|
if apiVer != global.ApiVersionV1 {
|
||||||
|
log.Error("Uri api version is invalid. apiVersion:", apiVer)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
if neType == "" {
|
||||||
|
log.Error("elementTypeValue is null.")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params := r.URL.Query()
|
||||||
|
neIds := params["ne_id"]
|
||||||
|
if len(neIds) == 0 {
|
||||||
|
log.Error("ne_id NOT FOUND")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debugf("neType: %s neId:%s", neType, neIds)
|
||||||
|
|
||||||
|
//var neInfo *dborm.NeInfo
|
||||||
|
neInfo := new(dborm.NeInfo)
|
||||||
|
|
||||||
|
neInfo, err = dborm.XormGetNeInfo(neType, neIds[0])
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.Ip, neInfo.Port, r.RequestURI)
|
||||||
|
log.Debug("requestURI2NF: GET ", requestURI2NF)
|
||||||
|
|
||||||
|
client := resty.New()
|
||||||
|
response, 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.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
respMsg := make(map[string]interface{})
|
||||||
|
switch response.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
log.Debug("response:", response)
|
||||||
|
// measurement := new(dborm.NorthboundPm)
|
||||||
|
measurement := new(dborm.NorthboundPm)
|
||||||
|
_ = json.Unmarshal(response.Body(), &measurement)
|
||||||
|
log.Debug("measurement:", measurement)
|
||||||
|
|
||||||
|
session := dborm.DbClient.XEngine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
layout := time.RFC3339
|
||||||
|
measurement.Date = GetDateFromTimeString(layout, measurement.StartTime)
|
||||||
|
measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime)
|
||||||
|
affected, err := session.Table("northbound_pm").Insert(measurement)
|
||||||
|
if err != nil && affected <= 0 {
|
||||||
|
log.Error("Failed to insert northbound_pm:", err)
|
||||||
|
services.ResponseInternalServerError500DatabaseOperationFailed(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Debug("response body:", string(response.Body()))
|
||||||
|
body := new(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(response.Body(), &body)
|
||||||
|
respMsg["error"] = body
|
||||||
|
}
|
||||||
|
|
||||||
|
services.ResponseWithJson(w, response.StatusCode(), respMsg)
|
||||||
|
}
|
||||||
409
features/security/account.go
Normal file
409
features/security/account.go
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
package security
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/features/security/service"
|
||||||
|
sysConfigService "ems.agt/features/sys_config/service"
|
||||||
|
"ems.agt/lib/core/account"
|
||||||
|
"ems.agt/lib/core/cache"
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/core/constants/cachekey"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/oauth"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/go-admin-team/go-admin-core/logger"
|
||||||
|
"github.com/mojocn/base64Captcha"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriOauthToken = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token"
|
||||||
|
UriOauthHandshake = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake"
|
||||||
|
|
||||||
|
CustomUriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token"
|
||||||
|
CustomUriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake"
|
||||||
|
|
||||||
|
// 系统登录
|
||||||
|
UriLogin = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/login"
|
||||||
|
CustomUriLogin = config.UriPrefix + "/securityManagement/{apiVersion}/login"
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
UriCaptchaImage = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/captchaImage"
|
||||||
|
CustomUriCaptchaImage = config.UriPrefix + "/securityManagement/{apiVersion}/captchaImage"
|
||||||
|
|
||||||
|
// 登录用户信息
|
||||||
|
UriUserInfo = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
|
||||||
|
CustomUriUserInfo = config.UriPrefix + "/securityManagement/{apiVersion}/getUserInfo"
|
||||||
|
|
||||||
|
// 登录用户路由信息
|
||||||
|
UriRouters = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getRouters"
|
||||||
|
CustomUriRouters = config.UriPrefix + "/securityManagement/{apiVersion}/getRouters"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoginFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("LoginFromOMC processing... ")
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to ReadAll:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// // check extend uri, response 404
|
||||||
|
// if !IsValidOAuthUri(r) {
|
||||||
|
// log.Debug("Uri is invalid")
|
||||||
|
// services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Error process ....
|
||||||
|
// response 400-7
|
||||||
|
if !json.Valid([]byte(body)) {
|
||||||
|
log.Error("Invalid Json Format")
|
||||||
|
services.ResponseBadRequest400InvalidJson(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var oAuthBody oauth.OAuthBody
|
||||||
|
_ = json.Unmarshal(body, &oAuthBody) //转为json
|
||||||
|
//log.Debug("body:", string(body), "oAuthBody:", oAuthBody)
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
// response 400-5
|
||||||
|
if oauth.IsWrongOAuthInfo(oAuthBody) {
|
||||||
|
log.Error("Wrong parameter value")
|
||||||
|
services.ResponseBadRequest400WrongParamValue(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if oauth.IsValidOAuthInfo(oAuthBody) {
|
||||||
|
plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType)
|
||||||
|
log.Debug("Permission list:", plist)
|
||||||
|
|
||||||
|
token := globalSession.NewSession(w, r, plist)
|
||||||
|
services.ResponseStatusOK200Login(w, token)
|
||||||
|
} else {
|
||||||
|
// response 400-4
|
||||||
|
log.Debug("Authentication failed, mismatch user or password")
|
||||||
|
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
validUser, user, err := dborm.XormCheckLoginUser(oAuthBody.UserName,
|
||||||
|
oAuthBody.Value, config.GetYamlConfig().Auth.Crypt)
|
||||||
|
if !validUser || err != nil {
|
||||||
|
// response 400-4
|
||||||
|
log.Error("Authentication failed, mismatch user or password")
|
||||||
|
services.ResponseErrorWithJson(w, 400, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token := oauth.GenRandToken("omc") // Generate new token to session ID
|
||||||
|
sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
|
||||||
|
affected, err := dborm.XormInsertSession(oAuthBody.UserName, sourceAddr, token,
|
||||||
|
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormInsertSession:", err)
|
||||||
|
if affected == -1 {
|
||||||
|
services.ResponseForbidden403MultiLoginNotAllowed(w)
|
||||||
|
} else {
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
// 缓存用户信息
|
||||||
|
account.CacheLoginUser(user)
|
||||||
|
// 角色权限集合,管理员拥有所有权限
|
||||||
|
userId := fmt.Sprint(user.Id)
|
||||||
|
isAdmin := conf.IsAdmin(userId)
|
||||||
|
roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin)
|
||||||
|
services.ResponseStatusOK200LoginWhitRP(w, token, user, roles, perms)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogoutFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("LogoutFromOMC processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// // check media type(content type) only support "application/json"
|
||||||
|
// if services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) == false {
|
||||||
|
// log.Error("Invalid Content-Type")
|
||||||
|
// services.ResponseUnsupportedMediaType415(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // check extend uri, response 404
|
||||||
|
// if !services.IsValidOAuthUri(r) {
|
||||||
|
// log.Error("Uri is invalid")
|
||||||
|
// services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // error processing ...
|
||||||
|
// // 401-1 response
|
||||||
|
// token, ret := oauth.IsCarriedToken(r)
|
||||||
|
// if ret == false {
|
||||||
|
// log.Error("AccessToken is not carried")
|
||||||
|
// services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
se, err := dborm.XormLogoutUpdateSession(token)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 清除缓存用户信息
|
||||||
|
account.ClearLoginUser(se.AccountId)
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("HandshakeFromOMC processing... ")
|
||||||
|
|
||||||
|
// check media type(content type) only support "application/json"
|
||||||
|
if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
|
||||||
|
log.Debug("Invalid Content-Type")
|
||||||
|
services.ResponseUnsupportedMediaType415(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check extend uri, response 404
|
||||||
|
if !services.IsValidOAuthUri(r) {
|
||||||
|
log.Error("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// error processing ...
|
||||||
|
// 401-1 response
|
||||||
|
token, ret := oauth.IsCarriedToken(r)
|
||||||
|
if !ret {
|
||||||
|
log.Error("AccessToken is not carried")
|
||||||
|
services.ResponseUnauthorized401AccessTokenNotCarried(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := dborm.XormUpdateSessionShakeTime(token)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Uri is invalid")
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK200Null(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 系统登录
|
||||||
|
//
|
||||||
|
// POST /login
|
||||||
|
func LoginOMC(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("LoginOMC processing... ")
|
||||||
|
var body struct {
|
||||||
|
Username string `json:"username" binding:"required"` // Username 用户名
|
||||||
|
Password string `json:"password" binding:"required"` // Password 用户密码
|
||||||
|
Code string `json:"code"` // Code 验证码
|
||||||
|
UUID string `json:"uuid"` // UUID 验证码唯一标识
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Invalid Json Format")
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// response 400-5
|
||||||
|
if body.Username == "" || body.Password == "" {
|
||||||
|
log.Error("Wrong parameter value")
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验验证码
|
||||||
|
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||||
|
captchaEnabledStr := sysConfigService.NewServiceSysConfig.SelectConfigValueByKey("sys.account.captchaEnabled")
|
||||||
|
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
|
||||||
|
if err != nil {
|
||||||
|
captchaEnabled = false
|
||||||
|
}
|
||||||
|
if captchaEnabled {
|
||||||
|
if body.Code == "" || body.UUID == "" {
|
||||||
|
log.Error("Authentication failed, mismatch captcha")
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "验证码信息错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verifyKey := cachekey.CAPTCHA_CODE_KEY + body.UUID
|
||||||
|
captcha, ok := cache.GetLocalTTL(verifyKey)
|
||||||
|
if captcha == nil || !ok {
|
||||||
|
log.Error("Authentication failed, captcha emtry")
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "验证码已失效"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cache.DeleteLocalTTL(verifyKey)
|
||||||
|
if captcha.(string) != body.Code {
|
||||||
|
log.Error("Authentication failed, not match captcha")
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "验证码错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validUser, user, err := dborm.XormCheckLoginUser(body.Username, body.Password, config.GetYamlConfig().Auth.Crypt)
|
||||||
|
if !validUser || err != nil {
|
||||||
|
// response 400-4
|
||||||
|
log.Error("Authentication failed, mismatch user or password")
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token := oauth.GenRandToken("omc") // Generate new token to session ID
|
||||||
|
sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
|
||||||
|
affected, err := dborm.XormInsertSession(body.Username, sourceAddr, token,
|
||||||
|
config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to XormInsertSession:", err)
|
||||||
|
if affected == -1 {
|
||||||
|
services.ResponseForbidden403MultiLoginNotAllowed(w)
|
||||||
|
} else {
|
||||||
|
services.ResponseBadRequest400IncorrectLogin(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
// 缓存用户信息
|
||||||
|
account.CacheLoginUser(user)
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"accessToken": token,
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
//
|
||||||
|
// GET /captchaImage
|
||||||
|
func CaptchaImage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
configService := sysConfigService.NewServiceSysConfig
|
||||||
|
|
||||||
|
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||||
|
captchaEnabledStr := configService.SelectConfigValueByKey("sys.account.captchaEnabled")
|
||||||
|
captchaEnabled, err := strconv.ParseBool(captchaEnabledStr)
|
||||||
|
if err != nil {
|
||||||
|
captchaEnabled = false
|
||||||
|
}
|
||||||
|
if !captchaEnabled {
|
||||||
|
ctx.JSON(w, 200, result.Ok(map[string]any{
|
||||||
|
"captchaEnabled": captchaEnabled,
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成唯一标识
|
||||||
|
verifyKey := ""
|
||||||
|
data := map[string]any{
|
||||||
|
"captchaEnabled": captchaEnabled,
|
||||||
|
"uuid": "",
|
||||||
|
"img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
||||||
|
}
|
||||||
|
|
||||||
|
// char 字符验证
|
||||||
|
driverCaptcha := &base64Captcha.DriverString{
|
||||||
|
//Height png height in pixel.
|
||||||
|
Height: 40,
|
||||||
|
// Width Captcha png width in pixel.
|
||||||
|
Width: 120,
|
||||||
|
//NoiseCount text noise count.
|
||||||
|
NoiseCount: 4,
|
||||||
|
//Length random string length.
|
||||||
|
Length: 4,
|
||||||
|
//Source is a unicode which is the rand string from.
|
||||||
|
Source: "023456789abcdefghjkmnprstuvwxyz",
|
||||||
|
//ShowLineOptions := OptionShowHollowLine | OptionShowSlimeLine | OptionShowSineLine .
|
||||||
|
ShowLineOptions: base64Captcha.OptionShowHollowLine,
|
||||||
|
//BgColor captcha image background color (optional)
|
||||||
|
BgColor: &color.RGBA{
|
||||||
|
R: 250,
|
||||||
|
G: 250,
|
||||||
|
B: 250,
|
||||||
|
A: 255, // 不透明
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// 验证码生成
|
||||||
|
id, question, answer := driverCaptcha.GenerateIdQuestionAnswer()
|
||||||
|
// 验证码表达式解析输出
|
||||||
|
item, err := driverCaptcha.DrawCaptcha(question)
|
||||||
|
if err != nil {
|
||||||
|
logger.Infof("Generate Id Question Answer %s : %v", question, err)
|
||||||
|
} else {
|
||||||
|
data["uuid"] = id
|
||||||
|
data["img"] = item.EncodeB64string()
|
||||||
|
verifyKey = cachekey.CAPTCHA_CODE_KEY + id
|
||||||
|
cache.SetLocalTTL(verifyKey, answer, 120*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地开发下返回验证码结果,方便接口调试
|
||||||
|
// text, ok := cache.GetLocalTTL(verifyKey)
|
||||||
|
// if ok {
|
||||||
|
// data["text"] = text.(string)
|
||||||
|
// }
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录用户信息
|
||||||
|
func UserInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
|
loginUser, err := ctx.LoginUser(r)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.OkData(err.Error()))
|
||||||
|
}
|
||||||
|
// 角色权限集合,管理员拥有所有权限
|
||||||
|
userId := fmt.Sprint(loginUser.UserID)
|
||||||
|
isAdmin := conf.IsAdmin(userId)
|
||||||
|
roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin)
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"user": loginUser.User,
|
||||||
|
"roles": roles,
|
||||||
|
"permissions": perms,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录用户路由信息
|
||||||
|
func Routers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID := ctx.LoginUserToUserID(r)
|
||||||
|
|
||||||
|
// 前端路由,管理员拥有所有
|
||||||
|
isAdmin := conf.IsAdmin(userID)
|
||||||
|
buildMenus := service.NewServiceAccount.RouteMenus(userID, isAdmin)
|
||||||
|
ctx.JSON(w, 200, result.OkData(buildMenus))
|
||||||
|
}
|
||||||
56
features/security/service/service_account.go
Normal file
56
features/security/service/service_account.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
menuService "ems.agt/features/sys_menu/service"
|
||||||
|
roleService "ems.agt/features/sys_role/service"
|
||||||
|
userService "ems.agt/features/sys_user/service"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/vo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceAccount 结构体
|
||||||
|
var NewServiceAccount = &ServiceAccount{
|
||||||
|
sysUserService: userService.NewServiceSysUser,
|
||||||
|
sysRoleService: roleService.NewServiceSysRole,
|
||||||
|
sysMenuService: menuService.NewServiceSysMenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账号身份操作服务 服务层处理
|
||||||
|
type ServiceAccount struct {
|
||||||
|
// 用户信息服务
|
||||||
|
sysUserService *userService.ServiceSysUser
|
||||||
|
// 角色服务
|
||||||
|
sysRoleService *roleService.ServiceSysRole
|
||||||
|
// 菜单服务
|
||||||
|
sysMenuService *menuService.ServiceSysMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleAndMenuPerms 角色和菜单数据权限
|
||||||
|
func (s *ServiceAccount) RoleAndMenuPerms(userId string, isAdmin bool) ([]string, []string) {
|
||||||
|
if isAdmin {
|
||||||
|
return []string{"admin"}, []string{"*:*:*"}
|
||||||
|
} else {
|
||||||
|
// 角色key
|
||||||
|
roleGroup := []string{}
|
||||||
|
roles := s.sysRoleService.SelectRoleListByUserId(userId)
|
||||||
|
for _, role := range roles {
|
||||||
|
roleGroup = append(roleGroup, role.RoleKey)
|
||||||
|
}
|
||||||
|
// 菜单权限key
|
||||||
|
perms := s.sysMenuService.SelectMenuPermsByUserId(userId)
|
||||||
|
return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RouteMenus 前端路由所需要的菜单
|
||||||
|
func (s *ServiceAccount) RouteMenus(userId string, isAdmin bool) []vo.Router {
|
||||||
|
var buildMenus []vo.Router
|
||||||
|
if isAdmin {
|
||||||
|
menus := s.sysMenuService.SelectMenuTreeByUserId("*")
|
||||||
|
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
|
||||||
|
} else {
|
||||||
|
menus := s.sysMenuService.SelectMenuTreeByUserId(userId)
|
||||||
|
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
|
||||||
|
}
|
||||||
|
return buildMenus
|
||||||
|
}
|
||||||
109
features/sm/backup.go
Normal file
109
features/sm/backup.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package sm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dbConfig = config.GetYamlConfig().Database
|
||||||
|
|
||||||
|
func DatabaseWhoreBackup() {
|
||||||
|
// MySQL数据库连接信息
|
||||||
|
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Name)
|
||||||
|
db, err := sql.Open("mysql", sqlStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect to database:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// 备份SQL文件路径
|
||||||
|
backupFile := dbConfig.Backup + "/" + "whore_backup_" + dbConfig.Name + ".sql"
|
||||||
|
|
||||||
|
// 执行mysqldump命令进行备份
|
||||||
|
cmd := exec.Command("mysqldump", "-u", dbConfig.User, "-p"+dbConfig.Password, "-h", dbConfig.Host, dbConfig.Name)
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to execute mysqldump command:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将备份结果写入SQL文件
|
||||||
|
file, err := os.Create(backupFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to create backup file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = file.Write(output)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to write backup file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Backup completed successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func DatabaseIncrementalBackup() {
|
||||||
|
// MySQL数据库连接信息
|
||||||
|
sqlStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true&loc=Local",
|
||||||
|
dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Name)
|
||||||
|
db, err := sql.Open("mysql", sqlStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to connect to database:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// 备份SQL文件路径
|
||||||
|
backupFile := dbConfig.Backup + "/" + "incremental_backup_" + dbConfig.Name + ".sql"
|
||||||
|
|
||||||
|
// 上次备份的时间点
|
||||||
|
lastBackupTime := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.Local)
|
||||||
|
|
||||||
|
// 构建增量备份SQL语句
|
||||||
|
query := fmt.Sprintf("SELECT * FROM table WHERE modified_at > '%s'", lastBackupTime.Format("2006-01-02 15:04:05"))
|
||||||
|
|
||||||
|
// 执行查询
|
||||||
|
rows, err := db.Query(query)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to execute query:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// 创建增量备份SQL文件
|
||||||
|
file, err := os.Create(backupFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to create backup file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 将查询结果写入SQL文件
|
||||||
|
for rows.Next() {
|
||||||
|
var data string
|
||||||
|
err := rows.Scan(&data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to scan row:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = file.WriteString(data + "\n")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to write backup file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Incremental backup completed successfully.")
|
||||||
|
}
|
||||||
852
features/state/getstate.go
Normal file
852
features/state/getstate.go
Normal file
@@ -0,0 +1,852 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CpuUsage struct {
|
||||||
|
NfCpuUsage uint16 `json:"nfCpuUsage"`
|
||||||
|
SysCpuUsage uint16 `json:"sysCpuUsage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemUsage struct {
|
||||||
|
TotalMem uint32 `json:"totalMem"`
|
||||||
|
NfUsedMem uint32 `json:"nfUsedMem"`
|
||||||
|
SysMemUsage uint16 `json:"sysMemUsage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PartitionInfo struct {
|
||||||
|
Total uint32 `json:"total"` // MB
|
||||||
|
Used uint32 `json:"used"` // MB
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiskSpace struct {
|
||||||
|
PartitionNum uint8 `json:"partitionNum"`
|
||||||
|
PartitionInfo []PartitionInfo `json:"partitionInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HardwareInfo struct {
|
||||||
|
CPUs int `json:"cpus"`
|
||||||
|
Memory int `json:"memory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SysState struct {
|
||||||
|
HostName string `json:"hostName"` // linux命令: hostname
|
||||||
|
OsInfo string `json:"osInfo"` // linux命令: uname -a
|
||||||
|
DbInfo string `json:"dbInfo"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version
|
||||||
|
Version string `json:"version"` // 软件版本信息: 16.1.1
|
||||||
|
IpAddr []string `json:"ipAddr"` // 网管的ipv4和ipv6列表
|
||||||
|
Port uint16 `json:"port"` // 用于网管的port
|
||||||
|
Capability uint32 `json:"capability"`
|
||||||
|
SerialNum string `json:"serialNum"`
|
||||||
|
ExpiryDate string `json:"expiryDate"`
|
||||||
|
HardwareInfo HardwareInfo `json:"hardwareInfo"`
|
||||||
|
CpuUsage CpuUsage `json:"cpuUsage"`
|
||||||
|
MemUsage MemUsage `json:"memUsage"`
|
||||||
|
DiskSpace DiskSpace `json:"diskSpace"`
|
||||||
|
//Timestamp string `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SystemState struct {
|
||||||
|
HostName string `json:"hostName"` // linux命令: hostname
|
||||||
|
OsInfo string `json:"osInfo"` // linux命令: uname -a
|
||||||
|
DbInfo string `json:"dbInfo"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version
|
||||||
|
Version string `json:"version"` // 软件版本信息: 16.1.1
|
||||||
|
IpAddr []string `json:"ipAddr"` // 网管的ipv4和ipv6列表
|
||||||
|
Port uint16 `json:"port"` // 用于网管的port
|
||||||
|
Capability uint32 `json:"capability"`
|
||||||
|
SerialNum string `json:"serialNum"`
|
||||||
|
ExpiryDate string `json:"expiryDate"`
|
||||||
|
HardwareInfo struct {
|
||||||
|
CPUs int `json:"cpus"` // 主机(裸机/虚拟机)的cpu个数
|
||||||
|
Memory int `json:"memory"` // 主机(裸机/虚拟机): 配置的内存
|
||||||
|
} `json:"hardwareInfo"`
|
||||||
|
CpuUsage struct {
|
||||||
|
NfCpuUsage uint16 `json:"nfCpuUsage"`
|
||||||
|
SysCpuUsage uint16 `json:"sysCpuUsage"`
|
||||||
|
} `json:"cpuUsage"`
|
||||||
|
MemUsage struct {
|
||||||
|
TotalMem uint32 `json:"totalMem"`
|
||||||
|
NfUsedMem uint32 `json:"nfUsedMem"`
|
||||||
|
SysMemUsage uint16 `json:"sysMemUsage"`
|
||||||
|
} `json:"memUsage"`
|
||||||
|
DiskSpace struct {
|
||||||
|
PartitionNum uint8 `json:"partitionNum"`
|
||||||
|
PartitionInfo []struct {
|
||||||
|
Total uint32 `json:"total"` // MB
|
||||||
|
Used uint32 `json:"used"` // MB
|
||||||
|
} `json:"partitionInfo"`
|
||||||
|
} `json:"diskSpace"`
|
||||||
|
//Timestamp string `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SystemInfo struct {
|
||||||
|
NeType string `json:"neType" map:"neType, omitempty"`
|
||||||
|
NeId string `json:"neId" map:"neId, omitempty"`
|
||||||
|
HostName string `json:"hostName" map:"hostName, omitempty"` // linux命令: hostname
|
||||||
|
OsInfo string `json:"osInfo" map:"osInfo, omitempty"` // linux命令: uname -a
|
||||||
|
DbInfo string `json:"dbInfo" map:"dbInfo, omitempty"` // 网元如果有db, 显示数据库名和版本信息, OMC: mysql --version
|
||||||
|
Version string `json:"version" map:"version, omitempty"` // 软件版本信息: 16.1.1
|
||||||
|
IpAddr string `json:"ipAddr" map:"ipAddr, omitempty"` // 网管的ipv4和ipv6列表
|
||||||
|
Port uint16 `json:"port" map:"port, omitempty"` // 用于网管的port
|
||||||
|
CPUs int `json:"cpus" map:"cpus, omitempty"`
|
||||||
|
TotalMem int `json:"totalMem" map:"totalMem, omitempty"`
|
||||||
|
PvFlag string `json:"pvFlag" map:"pvFlag, omitempty"`
|
||||||
|
Status string `json:"status" map:"status, omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LicenseInfo struct {
|
||||||
|
NeType string `json:"neType"`
|
||||||
|
NeId string `json:"neId"`
|
||||||
|
SerialNum string `json:"serialNum"`
|
||||||
|
Capability uint32 `json:"capability"`
|
||||||
|
CapUsed uint32 `json:"capUsed"`
|
||||||
|
FeatureEnabled []string `json:"featureEnabled"`
|
||||||
|
ExpiryDate string `json:"expiryDate"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriSysState = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/systemState"
|
||||||
|
UriSysState2 = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/systemState"
|
||||||
|
UriSysInfoAll = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/sysInfo"
|
||||||
|
UriSysInfoOne = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/sysInfo/{neType}/{neId}"
|
||||||
|
UriLicenseInfoAll = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/licenseInfo"
|
||||||
|
UriLicenseInfoOne = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/licenseInfo/{neType}/{neId}"
|
||||||
|
|
||||||
|
CustomUriSysState = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/systemState"
|
||||||
|
CustomUriSysState2 = config.UriPrefix + "/systemManagement/{apiVersion}/{elementTypeValue}/systemState"
|
||||||
|
CustomUriSysInfoAll = config.UriPrefix + "/systemManagement/{apiVersion}/sysInfo"
|
||||||
|
CustomUriSysInfoOne = config.UriPrefix + "/systemManagement/{apiVersion}/sysInfo/{neType}/{neId}"
|
||||||
|
CustomUriLicenseInfoAll = config.UriPrefix + "/systemManagement/{apiVersion}/licenseInfo"
|
||||||
|
CustomUriLicenseInfoOne = config.UriPrefix + "/systemManagement/{apiVersion}/licenseInfo/{neType}/{neId}"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client = resty.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
/*
|
||||||
|
client.
|
||||||
|
SetTimeout(10 * time.Second).
|
||||||
|
SetRetryCount(1).
|
||||||
|
SetRetryWaitTime(1 * time.Second).
|
||||||
|
SetRetryMaxWaitTime(2 * time.Second).
|
||||||
|
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||||||
|
return 0, errors.New("quota exceeded")
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
client.SetTimeout(3 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NeStatusEnumToStr(intStatus int) string {
|
||||||
|
switch intStatus {
|
||||||
|
case 0:
|
||||||
|
return "active"
|
||||||
|
case 1:
|
||||||
|
return "offline"
|
||||||
|
case 2:
|
||||||
|
return "standby"
|
||||||
|
case 3:
|
||||||
|
return "maintain"
|
||||||
|
default:
|
||||||
|
return "unkown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get system state from NF/NFs
|
||||||
|
func GetOneLicenseInfoFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetOneLicenseInfoFromNF processing... ")
|
||||||
|
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
neId := vars["neId"]
|
||||||
|
if neType == "" || neId == "" {
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
log.Trace("neInfo:", neInfo)
|
||||||
|
|
||||||
|
//systemState := make(map[string]interface{})
|
||||||
|
systemState := &SysState{}
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
//sysInfo := &SystemInfo{}
|
||||||
|
omcNeTypeLower := "omc"
|
||||||
|
if config.GetYamlConfig().OMC.NeType != "" {
|
||||||
|
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
|
||||||
|
}
|
||||||
|
if neType != omcNeTypeLower {
|
||||||
|
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
|
||||||
|
var requestURI2NF string
|
||||||
|
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(neType) != "udm" {
|
||||||
|
var udmNEs []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get system state from NF is failed:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(udmNEs) > 0 {
|
||||||
|
udmNe := udmNEs[0]
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(udmNe.NeType))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(neInfo.NeType))
|
||||||
|
}
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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 {
|
||||||
|
log.Trace("resp.Body():", string(resp.Body()))
|
||||||
|
_ = json.Unmarshal(resp.Body(), &systemState)
|
||||||
|
|
||||||
|
log.Trace("systemState:", systemState)
|
||||||
|
capUsed := config.TDatas[neInfo.NeType].CapUsed
|
||||||
|
log.Tracef("neInfo.NeType:%s capUsed: %v", capUsed)
|
||||||
|
licenseInfo := &LicenseInfo{
|
||||||
|
NeType: neInfo.NeType,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
SerialNum: systemState.SerialNum,
|
||||||
|
Capability: systemState.Capability,
|
||||||
|
CapUsed: capUsed,
|
||||||
|
FeatureEnabled: config.TDatas[neInfo.NeType].FeatureEnabled,
|
||||||
|
ExpiryDate: systemState.ExpiryDate,
|
||||||
|
}
|
||||||
|
//neItem := strings.ToUpper(neType) + "/" + neId
|
||||||
|
result, err = global.ToMap(*licenseInfo, "json")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
systemState := GetEMSState(neInfo.Ip)
|
||||||
|
licenseInfo := &LicenseInfo{
|
||||||
|
NeType: neInfo.NeType,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
SerialNum: systemState.SerialNum,
|
||||||
|
Capability: systemState.Capability,
|
||||||
|
CapUsed: config.TDatas[neInfo.NeType].CapUsed,
|
||||||
|
FeatureEnabled: config.TDatas[neInfo.NeType].FeatureEnabled,
|
||||||
|
ExpiryDate: systemState.ExpiryDate,
|
||||||
|
}
|
||||||
|
result, err = global.ToMap(*licenseInfo, "json")
|
||||||
|
// neItem := strings.ToUpper(neType) + "/" + neId
|
||||||
|
// result[neItem] = sysInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, result)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
|
||||||
|
var response Response
|
||||||
|
response.Data = data
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get system state from NF/NFs
|
||||||
|
func GetAllLicenseInfoFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetAllLicenseInfoFromNF processing... ")
|
||||||
|
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
var neList []dborm.NeInfo
|
||||||
|
_, err = dborm.XormGetAllNeInfo(&neList)
|
||||||
|
omcNeTypeLower := "omc"
|
||||||
|
if config.GetYamlConfig().OMC.NeType != "" {
|
||||||
|
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ne := range neList {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
|
||||||
|
log.Debug("ne: ", ne)
|
||||||
|
//if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) {
|
||||||
|
if strings.ToLower(ne.NeType) != omcNeTypeLower {
|
||||||
|
// hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
|
||||||
|
// requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
// hostUri, strings.ToLower(ne.NeType))
|
||||||
|
var requestURI2NF string
|
||||||
|
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(ne.NeType) != "udm" {
|
||||||
|
var udmNEs []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get system state from NF is failed:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(udmNEs) > 0 {
|
||||||
|
udmNe := udmNEs[0]
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(udmNe.NeType))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(ne.NeType))
|
||||||
|
}
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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)
|
||||||
|
// errorMessage := services.ErrorMessage{
|
||||||
|
// ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused",
|
||||||
|
// }
|
||||||
|
// //result["error"] = errorMessage
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
systemState := &SysState{}
|
||||||
|
_ = json.Unmarshal(resp.Body(), &systemState)
|
||||||
|
licenseInfo := &LicenseInfo{
|
||||||
|
NeType: ne.NeType,
|
||||||
|
NeId: ne.NeId,
|
||||||
|
SerialNum: systemState.SerialNum,
|
||||||
|
Capability: systemState.Capability,
|
||||||
|
CapUsed: config.TDatas[ne.NeType].CapUsed,
|
||||||
|
FeatureEnabled: config.TDatas[ne.NeType].FeatureEnabled,
|
||||||
|
ExpiryDate: systemState.ExpiryDate,
|
||||||
|
}
|
||||||
|
result, err = global.ToMap(*licenseInfo, "json")
|
||||||
|
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
|
||||||
|
// result[neItem] = sysInfo
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
systemState := GetEMSState(ne.Ip)
|
||||||
|
licenseInfo := &LicenseInfo{
|
||||||
|
NeType: ne.NeType,
|
||||||
|
NeId: ne.NeId,
|
||||||
|
SerialNum: systemState.SerialNum,
|
||||||
|
Capability: systemState.Capability,
|
||||||
|
CapUsed: config.TDatas[ne.NeType].CapUsed,
|
||||||
|
FeatureEnabled: config.TDatas[ne.NeType].FeatureEnabled,
|
||||||
|
ExpiryDate: systemState.ExpiryDate,
|
||||||
|
}
|
||||||
|
result, err = global.ToMap(*licenseInfo, "json")
|
||||||
|
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
|
||||||
|
// result[neItem] = sysInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, result)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var response Response
|
||||||
|
response.Data = data
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get system state from NF/NFs
|
||||||
|
func GetOneSysinfoFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetOneSysinfoFromNF processing... ")
|
||||||
|
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["neType"]
|
||||||
|
neId := vars["neId"]
|
||||||
|
if neType == "" || neId == "" {
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
log.Trace("neInfo:", neInfo)
|
||||||
|
|
||||||
|
//systemState := make(map[string]interface{})
|
||||||
|
systemState := &SysState{}
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
//sysInfo := &SystemInfo{}
|
||||||
|
omcNeTypeLower := "omc"
|
||||||
|
if config.GetYamlConfig().OMC.NeType != "" {
|
||||||
|
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
|
||||||
|
}
|
||||||
|
if neType != omcNeTypeLower {
|
||||||
|
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
|
||||||
|
var requestURI2NF string
|
||||||
|
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(neType) != "udm" {
|
||||||
|
var udmNEs []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get system state from NF is failed:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(udmNEs) > 0 {
|
||||||
|
udmNe := udmNEs[0]
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(udmNe.NeType))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(neInfo.NeType))
|
||||||
|
}
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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 {
|
||||||
|
log.Trace("resp.Body():", string(resp.Body()))
|
||||||
|
_ = json.Unmarshal(resp.Body(), &systemState)
|
||||||
|
|
||||||
|
log.Trace("systemState:", systemState)
|
||||||
|
hostName := "5gc"
|
||||||
|
if systemState.HostName != "" {
|
||||||
|
hostName = systemState.HostName
|
||||||
|
}
|
||||||
|
osInfo := "Linux 5gc 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux"
|
||||||
|
if systemState.OsInfo != "" {
|
||||||
|
osInfo = systemState.OsInfo
|
||||||
|
}
|
||||||
|
dbInfo := "adb v1.0.1"
|
||||||
|
if systemState.OsInfo != "" {
|
||||||
|
dbInfo = systemState.DbInfo
|
||||||
|
}
|
||||||
|
port, _ := strconv.Atoi(neInfo.Port)
|
||||||
|
cpus := 4
|
||||||
|
if systemState.HardwareInfo.CPUs != 0 {
|
||||||
|
cpus = systemState.HardwareInfo.CPUs
|
||||||
|
}
|
||||||
|
totalMem := 34029125632
|
||||||
|
if systemState.HardwareInfo.Memory != 0 {
|
||||||
|
totalMem = systemState.HardwareInfo.Memory
|
||||||
|
}
|
||||||
|
sysInfo := &SystemInfo{
|
||||||
|
NeType: neInfo.NeType,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
HostName: hostName,
|
||||||
|
OsInfo: osInfo,
|
||||||
|
DbInfo: dbInfo,
|
||||||
|
Version: systemState.Version,
|
||||||
|
IpAddr: neInfo.Ip,
|
||||||
|
Port: uint16(port),
|
||||||
|
CPUs: cpus,
|
||||||
|
TotalMem: totalMem,
|
||||||
|
PvFlag: neInfo.PvFlag,
|
||||||
|
Status: NeStatusEnumToStr(neInfo.Status),
|
||||||
|
}
|
||||||
|
//neItem := strings.ToUpper(neType) + "/" + neId
|
||||||
|
result, err = global.ToMap(*sysInfo, "json")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
systemState := GetEMSState(neInfo.Ip)
|
||||||
|
sysInfo := &SystemInfo{
|
||||||
|
NeType: neInfo.NeType,
|
||||||
|
NeId: neInfo.NeId,
|
||||||
|
HostName: systemState.HostName,
|
||||||
|
OsInfo: systemState.OsInfo,
|
||||||
|
DbInfo: systemState.DbInfo,
|
||||||
|
Version: systemState.Version,
|
||||||
|
IpAddr: neInfo.Ip,
|
||||||
|
Port: systemState.Port,
|
||||||
|
CPUs: systemState.HardwareInfo.CPUs,
|
||||||
|
TotalMem: systemState.HardwareInfo.Memory,
|
||||||
|
PvFlag: neInfo.PvFlag,
|
||||||
|
Status: NeStatusEnumToStr(neInfo.Status),
|
||||||
|
}
|
||||||
|
result, err = global.ToMap(*sysInfo, "json")
|
||||||
|
// neItem := strings.ToUpper(neType) + "/" + neId
|
||||||
|
// result[neItem] = sysInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, result)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
|
||||||
|
var response Response
|
||||||
|
response.Data = data
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get system state from NF/NFs
|
||||||
|
func GetAllSysinfoFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetAllSysinfoFromNF processing... ")
|
||||||
|
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
var neList []dborm.NeInfo
|
||||||
|
_, err = dborm.XormGetAllNeInfo(&neList)
|
||||||
|
omcNeTypeLower := "omc"
|
||||||
|
if config.GetYamlConfig().OMC.NeType != "" {
|
||||||
|
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ne := range neList {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
|
||||||
|
log.Debug("ne: ", ne)
|
||||||
|
//if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) {
|
||||||
|
if strings.ToLower(ne.NeType) != omcNeTypeLower {
|
||||||
|
// hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
|
||||||
|
// requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
// hostUri, strings.ToLower(ne.NeType))
|
||||||
|
var requestURI2NF string
|
||||||
|
if config.GetYamlConfig().OMC.TestMode == true && strings.ToLower(ne.NeType) != "udm" {
|
||||||
|
var udmNEs []dborm.NeInfo
|
||||||
|
err := dborm.XormGetNeInfoByNeType("UDM", &udmNEs)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get system state from NF is failed:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(udmNEs) > 0 {
|
||||||
|
udmNe := udmNEs[0]
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", udmNe.Ip, udmNe.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(udmNe.NeType))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
|
||||||
|
requestURI2NF = fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, strings.ToLower(ne.NeType))
|
||||||
|
}
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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)
|
||||||
|
// errorMessage := services.ErrorMessage{
|
||||||
|
// ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused",
|
||||||
|
// }
|
||||||
|
// //result["error"] = errorMessage
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
systemState := &SysState{}
|
||||||
|
_ = json.Unmarshal(resp.Body(), &systemState)
|
||||||
|
hostName := "5gc"
|
||||||
|
if systemState.HostName != "" {
|
||||||
|
hostName = systemState.HostName
|
||||||
|
}
|
||||||
|
osInfo := "Linux 5gc 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux"
|
||||||
|
if systemState.OsInfo != "" {
|
||||||
|
osInfo = systemState.OsInfo
|
||||||
|
}
|
||||||
|
dbInfo := "adb v1.0.1"
|
||||||
|
if systemState.OsInfo != "" {
|
||||||
|
dbInfo = systemState.DbInfo
|
||||||
|
}
|
||||||
|
port, _ := strconv.Atoi(ne.Port)
|
||||||
|
cpus := 4
|
||||||
|
if systemState.HardwareInfo.CPUs != 0 {
|
||||||
|
cpus = systemState.HardwareInfo.CPUs
|
||||||
|
}
|
||||||
|
totalMem := 34029125632
|
||||||
|
if systemState.HardwareInfo.Memory != 0 {
|
||||||
|
totalMem = systemState.HardwareInfo.Memory
|
||||||
|
}
|
||||||
|
sysInfo := &SystemInfo{
|
||||||
|
NeType: ne.NeType,
|
||||||
|
NeId: ne.NeId,
|
||||||
|
HostName: hostName,
|
||||||
|
OsInfo: osInfo,
|
||||||
|
DbInfo: dbInfo,
|
||||||
|
Version: systemState.Version,
|
||||||
|
IpAddr: ne.Ip,
|
||||||
|
Port: uint16(port),
|
||||||
|
CPUs: cpus,
|
||||||
|
TotalMem: totalMem,
|
||||||
|
PvFlag: ne.PvFlag,
|
||||||
|
Status: NeStatusEnumToStr(ne.Status),
|
||||||
|
}
|
||||||
|
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
|
||||||
|
// result[neItem] = sysInfo
|
||||||
|
result, err = global.ToMap(*sysInfo, "json")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port, _ := strconv.Atoi(ne.Port)
|
||||||
|
systemState := GetEMSState(ne.Ip)
|
||||||
|
sysInfo := &SystemInfo{
|
||||||
|
NeType: ne.NeType,
|
||||||
|
NeId: ne.NeId,
|
||||||
|
HostName: systemState.HostName,
|
||||||
|
OsInfo: systemState.OsInfo,
|
||||||
|
DbInfo: systemState.DbInfo,
|
||||||
|
Version: systemState.Version,
|
||||||
|
IpAddr: ne.Ip,
|
||||||
|
Port: (uint16(port)),
|
||||||
|
CPUs: systemState.HardwareInfo.CPUs,
|
||||||
|
TotalMem: systemState.HardwareInfo.Memory,
|
||||||
|
PvFlag: ne.PvFlag,
|
||||||
|
Status: NeStatusEnumToStr(ne.Status),
|
||||||
|
}
|
||||||
|
// neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
|
||||||
|
// result[neItem] = sysInfo
|
||||||
|
result, err = global.ToMap(*sysInfo, "json")
|
||||||
|
}
|
||||||
|
|
||||||
|
data = append(data, result)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var response Response
|
||||||
|
response.Data = data
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get system state from NF/NFs
|
||||||
|
func GetStateFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetStateFromNF processing... ")
|
||||||
|
|
||||||
|
data := make([]map[string]interface{}, 0)
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
neType := vars["elementTypeValue"]
|
||||||
|
|
||||||
|
var neList []dborm.NeInfo
|
||||||
|
if neType == "" {
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
switch strings.ToLower(neType) {
|
||||||
|
case "all":
|
||||||
|
// query all NFs
|
||||||
|
// create rest client
|
||||||
|
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
|
||||||
|
getNeInfoPattern := fmt.Sprintf(config.UriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info",
|
||||||
|
config.GetYamlConfig().Database.Name)
|
||||||
|
getNeInfoURI := restHostPort + getNeInfoPattern + "?WHERE=status='0'"
|
||||||
|
log.Debug("getNeInfoPattern:", getNeInfoPattern)
|
||||||
|
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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(getNeInfoURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get ne_info from DB is failed:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neList, _ = dborm.XormParseResult(resp.Body())
|
||||||
|
default:
|
||||||
|
restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port)
|
||||||
|
getNeInfoPattern := fmt.Sprintf(config.UriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info",
|
||||||
|
config.GetYamlConfig().Database.Name)
|
||||||
|
getNeInfoURI := restHostPort + getNeInfoPattern
|
||||||
|
neId := services.GetUriParamString(r, "ne_id", ",", true, false)
|
||||||
|
if neId == "" {
|
||||||
|
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%s'", neType)
|
||||||
|
} else {
|
||||||
|
getNeInfoURI = getNeInfoURI + fmt.Sprintf("?WHERE=status='0'+and+ne_type='%v'+and+ne_id+in+%v", neType, neId)
|
||||||
|
}
|
||||||
|
log.Debug("getNeInfoURI:", getNeInfoURI)
|
||||||
|
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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(getNeInfoURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Get ne_info from DB is failed:", err)
|
||||||
|
services.ResponseInternalServerError500NFConnectRefused(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neList, _ = dborm.XormParseResult(resp.Body())
|
||||||
|
}
|
||||||
|
omcNeTypeLower := "omc"
|
||||||
|
if config.GetYamlConfig().OMC.NeType != "" {
|
||||||
|
omcNeTypeLower = strings.ToLower(config.GetYamlConfig().OMC.NeType)
|
||||||
|
}
|
||||||
|
for _, ne := range neList {
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
log.Debugf("r.RemoteAddr: %s omcNeTypeLower: %s", r.RemoteAddr, omcNeTypeLower)
|
||||||
|
log.Debug("ne: ", ne)
|
||||||
|
//if strings.ToLower(ne.NeType) != omcNeTypeLower || !strings.Contains(r.RemoteAddr, ne.Ip) {
|
||||||
|
if strings.ToLower(ne.NeType) != omcNeTypeLower {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", ne.Ip, ne.Port)
|
||||||
|
requestURI2NF := fmt.Sprintf("%s/api/rest/systemManagement/v1/elementType/%s/objectType/systemState",
|
||||||
|
hostUri, ne.NeType)
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
result["ipAddress"] = ne.Ip
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
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)
|
||||||
|
errorMessage := services.ErrorMessage{
|
||||||
|
ErrorCode: "1", ErrorInfo: "Internal server error, NF connnect refused",
|
||||||
|
}
|
||||||
|
result["error"] = errorMessage
|
||||||
|
} else {
|
||||||
|
systemState := make(map[string]interface{})
|
||||||
|
_ = json.Unmarshal(resp.Body(), &systemState)
|
||||||
|
result["systemState"] = systemState
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result["ipAddress"] = ne.Ip
|
||||||
|
emsState := GetEMSState(ne.Ip)
|
||||||
|
result["systemState"] = emsState
|
||||||
|
}
|
||||||
|
neItem := strings.ToUpper(ne.NeType) + "/" + ne.NeId
|
||||||
|
mapState := make(map[string]interface{})
|
||||||
|
mapState[neItem] = result
|
||||||
|
|
||||||
|
data = append(data, mapState)
|
||||||
|
log.Trace("data:", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var response Response
|
||||||
|
response.Data = data
|
||||||
|
services.ResponseWithJson(w, http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEMSState(ip string) *SysState {
|
||||||
|
log.Debug("GetEMSState processing... ")
|
||||||
|
|
||||||
|
sysInfo := new(SysInfo)
|
||||||
|
err := GetSysInfo(sysInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to GetSysInfo:", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuUsage := &CpuUsage{
|
||||||
|
NfCpuUsage: sysInfo.MyCpuPercent,
|
||||||
|
SysCpuUsage: sysInfo.SysCpuPercent,
|
||||||
|
}
|
||||||
|
|
||||||
|
memUsage := &MemUsage{
|
||||||
|
TotalMem: sysInfo.SysTotalRam,
|
||||||
|
NfUsedMem: sysInfo.MyUsedRam,
|
||||||
|
SysMemUsage: sysInfo.SysRamUsedPercent,
|
||||||
|
}
|
||||||
|
|
||||||
|
diskSpace := &DiskSpace{
|
||||||
|
PartitionNum: sysInfo.PartitionNum,
|
||||||
|
PartitionInfo: sysInfo.PartitionInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
version := "16.1.1"
|
||||||
|
if global.Version != "" {
|
||||||
|
version = global.Version
|
||||||
|
}
|
||||||
|
hostName, _ := os.Hostname()
|
||||||
|
emsState := &SysState{
|
||||||
|
HostName: hostName,
|
||||||
|
OsInfo: getUnameStr(),
|
||||||
|
DbInfo: "mysql Ver 15.1 Distrib 10.3.35-MariaDB, for Linux (aarch64) using readline 5.1",
|
||||||
|
IpAddr: []string{ip},
|
||||||
|
Port: 3030,
|
||||||
|
Version: version,
|
||||||
|
Capability: 9999999,
|
||||||
|
SerialNum: config.GetYamlConfig().OMC.Sn,
|
||||||
|
ExpiryDate: "-",
|
||||||
|
HardwareInfo: HardwareInfo{CPUs: getCpuNumber(), Memory: getTotalMemory()},
|
||||||
|
CpuUsage: *cpuUsage,
|
||||||
|
MemUsage: *memUsage,
|
||||||
|
DiskSpace: *diskSpace,
|
||||||
|
}
|
||||||
|
|
||||||
|
//getSystemInfo()
|
||||||
|
return emsState
|
||||||
|
}
|
||||||
243
features/state/state_linux.go
Normal file
243
features/state/state_linux.go
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
"github.com/shirou/gopsutil/process"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SysInfo struct {
|
||||||
|
SysCpuPercent uint16 // x%
|
||||||
|
MyCpuPercent uint16 // x%, CPU percent of current proccess
|
||||||
|
|
||||||
|
SysTotalRam uint32 // KB
|
||||||
|
MyUsedRam uint32 // RAM usage of current proccess, KB
|
||||||
|
SysRamUsedPercent uint16 // x%
|
||||||
|
|
||||||
|
PartitionNum byte
|
||||||
|
PartitionInfo []PartitionInfo // usage of each partition
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_PARTITION_NUM byte = 32
|
||||||
|
|
||||||
|
func GetSysStat() ([]byte, int) {
|
||||||
|
// Get sys info
|
||||||
|
var sysInfo SysInfo
|
||||||
|
err := GetSysInfo(&sysInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//log.Tracef("current sys info: %v", sysInfo)
|
||||||
|
|
||||||
|
// build ems buffer
|
||||||
|
var data []byte = make([]byte, 1024)
|
||||||
|
var len int
|
||||||
|
var i byte
|
||||||
|
binary.BigEndian.PutUint16(data[0:], sysInfo.MyCpuPercent) //x% * 100
|
||||||
|
binary.BigEndian.PutUint16(data[2:], sysInfo.SysCpuPercent) //x% * 100
|
||||||
|
binary.BigEndian.PutUint32(data[4:], sysInfo.SysTotalRam) // KB
|
||||||
|
binary.BigEndian.PutUint32(data[8:], sysInfo.MyUsedRam) // KB
|
||||||
|
binary.BigEndian.PutUint16(data[12:], sysInfo.SysRamUsedPercent) //x% * 100
|
||||||
|
data[14] = sysInfo.PartitionNum
|
||||||
|
for i = 0; i < sysInfo.PartitionNum; i++ {
|
||||||
|
binary.BigEndian.PutUint32(data[15+8*(i):], sysInfo.PartitionInfo[i].Total) // MB
|
||||||
|
binary.BigEndian.PutUint32(data[15+8*(i)+4:], sysInfo.PartitionInfo[i].Used) // MB
|
||||||
|
}
|
||||||
|
len = int(15 + 8*sysInfo.PartitionNum)
|
||||||
|
|
||||||
|
//log.Tracef("current sys stat buf: %v, len: %d", data, len)
|
||||||
|
|
||||||
|
return data, len
|
||||||
|
}
|
||||||
|
|
||||||
|
var pProc *process.Process = nil
|
||||||
|
|
||||||
|
func GetSYsCpuPercent() float64 {
|
||||||
|
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
|
||||||
|
if err != nil {
|
||||||
|
return 0.0
|
||||||
|
} else {
|
||||||
|
return totalPercent[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSysInfo(sysInfo *SysInfo) error {
|
||||||
|
// sys cpu percent
|
||||||
|
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
|
||||||
|
if err != nil {
|
||||||
|
sysInfo.SysCpuPercent = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.SysCpuPercent = uint16(totalPercent[0] * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pProc == nil {
|
||||||
|
checkPid := os.Getpid()
|
||||||
|
pProc, err = process.NewProcess(int32(checkPid))
|
||||||
|
if err != nil {
|
||||||
|
log.Tracef("get process info error %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// self cpu percent
|
||||||
|
percent, err := pProc.Percent(0) //(2*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
log.Tracef("get process cpu percent error %v", err)
|
||||||
|
sysInfo.MyCpuPercent = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.MyCpuPercent = uint16(percent * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// self RAM(KB)
|
||||||
|
myRam, err := pProc.MemoryInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Tracef("get self memory info error %v", err)
|
||||||
|
sysInfo.MyUsedRam = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.MyUsedRam = uint32(myRam.RSS / 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
// system RAM(KB)
|
||||||
|
sysRam, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
log.Tracef("gett sys memory info error %v", err)
|
||||||
|
sysInfo.SysTotalRam = 0
|
||||||
|
sysInfo.SysRamUsedPercent = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.SysTotalRam = uint32(sysRam.Total / 1024)
|
||||||
|
sysInfo.SysRamUsedPercent = uint16(sysRam.UsedPercent * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// partition usage
|
||||||
|
GetPartitions(sysInfo)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProcess() process.Process {
|
||||||
|
checkPid := os.Getpid()
|
||||||
|
ret, _ := process.NewProcess(int32(checkPid))
|
||||||
|
return *ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSystemCpuInfo() {
|
||||||
|
physicalCnt, _ := cpu.Counts(false)
|
||||||
|
logicalCnt, _ := cpu.Counts(true)
|
||||||
|
log.Tracef("physical count:%d logical count:%d", physicalCnt, logicalCnt)
|
||||||
|
|
||||||
|
totalPercent, _ := cpu.Percent(3*time.Second, false) // per cpu is false
|
||||||
|
perPercents, _ := cpu.Percent(3*time.Second, true) // per cpu is true
|
||||||
|
log.Tracef("total percent:%v per percents:%v", totalPercent, perPercents)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProcessCpuPercent() {
|
||||||
|
p := getProcess()
|
||||||
|
percent, err := p.Percent(0)
|
||||||
|
if err != nil {
|
||||||
|
log.Tracef("error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
numcpu := runtime.NumCPU()
|
||||||
|
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
|
||||||
|
if percent < 0.0 {
|
||||||
|
log.Tracef("Err CPU Percent of Process: %f, CPU num: %d", percent, numcpu)
|
||||||
|
} else {
|
||||||
|
log.Tracef("get process CPU percent: %f, CPU num: %d", percent, numcpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProcessMemoryInfo() {
|
||||||
|
p := getProcess()
|
||||||
|
|
||||||
|
v, err := p.MemoryInfo()
|
||||||
|
if err != nil {
|
||||||
|
log.Tracef("getting memory info error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Tracef("get process memory info %v", v)
|
||||||
|
|
||||||
|
info, _ := mem.VirtualMemory()
|
||||||
|
fmt.Println(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPartitions(sysInfo *SysInfo) {
|
||||||
|
sysInfo.PartitionNum = 0
|
||||||
|
//sysInfo.PartitionInfo = make([]PartitionInfo, MAX_PARTITION_NUM, MAX_PARTITION_NUM)
|
||||||
|
infos, _ := disk.Partitions(true)
|
||||||
|
for _, info := range infos {
|
||||||
|
GetOnePartitionUsage(info.Mountpoint, sysInfo)
|
||||||
|
if sysInfo.PartitionNum >= MAX_PARTITION_NUM {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOnePartitionUsage(path string, sysInfo *SysInfo) int {
|
||||||
|
info, err := disk.Usage(path)
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Total <= 0 { // info.Used/(1024 * 1024)MB
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var partition PartitionInfo
|
||||||
|
partition.Total = uint32(info.Total / 1024 / 1024)
|
||||||
|
partition.Used = uint32(info.Used / 1024 / 1024)
|
||||||
|
sysInfo.PartitionInfo = append(sysInfo.PartitionInfo, partition)
|
||||||
|
sysInfo.PartitionNum++
|
||||||
|
|
||||||
|
/*data, err := json.MarshalIndent(info, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(data))*/
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOS() string {
|
||||||
|
var osname string
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
osname = "GNU/Linux"
|
||||||
|
}
|
||||||
|
return osname
|
||||||
|
}
|
||||||
|
|
||||||
|
func utsnameToString(unameArray [65]int8) string {
|
||||||
|
var byteString [65]byte
|
||||||
|
var indexLength int
|
||||||
|
for ; unameArray[indexLength] != 0 && indexLength < 65; indexLength++ {
|
||||||
|
byteString[indexLength] = uint8(unameArray[indexLength])
|
||||||
|
}
|
||||||
|
return string(byteString[:indexLength])
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUnameStr() string {
|
||||||
|
var utsname = syscall.Utsname{}
|
||||||
|
err := syscall.Uname(&utsname)
|
||||||
|
if err == nil {
|
||||||
|
name := utsnameToString(utsname.Sysname)
|
||||||
|
node := utsnameToString(utsname.Nodename)
|
||||||
|
release := utsnameToString(utsname.Release)
|
||||||
|
version := utsnameToString(utsname.Version)
|
||||||
|
machine := utsnameToString(utsname.Machine)
|
||||||
|
//domain:= utsnameToString(utsname.Domainname)
|
||||||
|
osName := getOS()
|
||||||
|
return fmt.Sprintf("%s %s %s %s %s %s", name, node,
|
||||||
|
release, version, machine, osName)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
231
features/state/state_windows.go
Normal file
231
features/state/state_windows.go
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
"github.com/shirou/gopsutil/process"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SysInfo struct {
|
||||||
|
SysCpuPercent uint16 // x%
|
||||||
|
MyCpuPercent uint16 // x%, CPU percent of current proccess
|
||||||
|
|
||||||
|
SysTotalRam uint32 // KB
|
||||||
|
MyUsedRam uint32 // RAM usage of current proccess, KB
|
||||||
|
SysRamUsedPercent uint16 // x%
|
||||||
|
|
||||||
|
PartitionNum byte
|
||||||
|
PartitionInfo []PartitionInfo // usage of each partition
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_PARTITION_NUM byte = 32
|
||||||
|
|
||||||
|
func GetSysStat() ([]byte, int) {
|
||||||
|
// Get sys info
|
||||||
|
var sysInfo SysInfo
|
||||||
|
err := GetSysInfo(&sysInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//fmt.Printf("current sys info: %v", sysInfo)
|
||||||
|
|
||||||
|
// build ems buffer
|
||||||
|
var data []byte = make([]byte, 1024)
|
||||||
|
var len int
|
||||||
|
var i byte
|
||||||
|
binary.BigEndian.PutUint16(data[0:], sysInfo.MyCpuPercent) //x% * 100
|
||||||
|
binary.BigEndian.PutUint16(data[2:], sysInfo.SysCpuPercent) //x% * 100
|
||||||
|
binary.BigEndian.PutUint32(data[4:], sysInfo.SysTotalRam) // KB
|
||||||
|
binary.BigEndian.PutUint32(data[8:], sysInfo.MyUsedRam) // KB
|
||||||
|
binary.BigEndian.PutUint16(data[12:], sysInfo.SysRamUsedPercent) //x% * 100
|
||||||
|
data[14] = sysInfo.PartitionNum
|
||||||
|
for i = 0; i < sysInfo.PartitionNum; i++ {
|
||||||
|
binary.BigEndian.PutUint32(data[15+8*(i):], sysInfo.PartitionInfo[i].Total) // MB
|
||||||
|
binary.BigEndian.PutUint32(data[15+8*(i)+4:], sysInfo.PartitionInfo[i].Used) // MB
|
||||||
|
}
|
||||||
|
len = int(15 + 8*sysInfo.PartitionNum)
|
||||||
|
|
||||||
|
//fmt.Printf("current sys stat buf: %v, len: %d", data, len)
|
||||||
|
|
||||||
|
return data, len
|
||||||
|
}
|
||||||
|
|
||||||
|
var pProc *process.Process = nil
|
||||||
|
|
||||||
|
func GetSYsCpuPercent() float64 {
|
||||||
|
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
|
||||||
|
if err != nil {
|
||||||
|
return 0.0
|
||||||
|
} else {
|
||||||
|
return totalPercent[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSysInfo(sysInfo *SysInfo) error {
|
||||||
|
// sys cpu percent
|
||||||
|
totalPercent, err := cpu.Percent(0, false) //(2*time.Second, false)
|
||||||
|
if err != nil {
|
||||||
|
sysInfo.SysCpuPercent = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.SysCpuPercent = uint16(totalPercent[0] * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pProc == nil {
|
||||||
|
checkPid := os.Getpid()
|
||||||
|
pProc, err = process.NewProcess(int32(checkPid))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("get process info error %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// self cpu percent
|
||||||
|
percent, err := pProc.Percent(0) //(2*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("get process cpu percent error %v", err)
|
||||||
|
sysInfo.MyCpuPercent = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.MyCpuPercent = uint16(percent * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// self RAM(KB)
|
||||||
|
myRam, err := pProc.MemoryInfo()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("get self memory info error %v", err)
|
||||||
|
sysInfo.MyUsedRam = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.MyUsedRam = uint32(myRam.RSS / 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
// system RAM(KB)
|
||||||
|
sysRam, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("gett sys memory info error %v", err)
|
||||||
|
sysInfo.SysTotalRam = 0
|
||||||
|
sysInfo.SysRamUsedPercent = 0
|
||||||
|
} else {
|
||||||
|
sysInfo.SysTotalRam = uint32(sysRam.Total / 1024)
|
||||||
|
sysInfo.SysRamUsedPercent = uint16(sysRam.UsedPercent * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// partition usage
|
||||||
|
GetPartitions(sysInfo)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProcess() process.Process {
|
||||||
|
checkPid := os.Getpid()
|
||||||
|
ret, _ := process.NewProcess(int32(checkPid))
|
||||||
|
return *ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSystemCpuInfo() {
|
||||||
|
physicalCnt, _ := cpu.Counts(false)
|
||||||
|
logicalCnt, _ := cpu.Counts(true)
|
||||||
|
fmt.Printf("physical count:%d logical count:%d\n", physicalCnt, logicalCnt)
|
||||||
|
|
||||||
|
totalPercent, _ := cpu.Percent(3*time.Second, false) // per cpu is false
|
||||||
|
perPercents, _ := cpu.Percent(3*time.Second, true) // per cpu is true
|
||||||
|
fmt.Printf("total percent:%v per percents:%v\n", totalPercent, perPercents)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProcessCpuPercent() {
|
||||||
|
p := getProcess()
|
||||||
|
percent, err := p.Percent(0)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
numcpu := runtime.NumCPU()
|
||||||
|
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
|
||||||
|
if percent < 0.0 {
|
||||||
|
fmt.Printf("Err CPU Percent of Process: %f, CPU num: %d", percent, numcpu)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("get process CPU percent: %f, CPU num: %d", percent, numcpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProcessMemoryInfo() {
|
||||||
|
p := getProcess()
|
||||||
|
|
||||||
|
v, err := p.MemoryInfo()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("getting memory info error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("get process memory info %v\n", v)
|
||||||
|
|
||||||
|
info, _ := mem.VirtualMemory()
|
||||||
|
fmt.Println(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPartitions(sysInfo *SysInfo) {
|
||||||
|
sysInfo.PartitionNum = 0
|
||||||
|
//sysInfo.PartitionInfo = make([]PartitionInfo, MAX_PARTITION_NUM, MAX_PARTITION_NUM)
|
||||||
|
infos, _ := disk.Partitions(true)
|
||||||
|
for _, info := range infos {
|
||||||
|
GetOnePartitionUsage(info.Mountpoint, sysInfo)
|
||||||
|
if sysInfo.PartitionNum >= MAX_PARTITION_NUM {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOnePartitionUsage(path string, sysInfo *SysInfo) int {
|
||||||
|
info, err := disk.Usage(path)
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Total <= 0 { // info.Used/(1024 * 1024)MB
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var partition PartitionInfo
|
||||||
|
partition.Total = uint32(info.Total / 1024 / 1024)
|
||||||
|
partition.Used = uint32(info.Used / 1024 / 1024)
|
||||||
|
sysInfo.PartitionInfo = append(sysInfo.PartitionInfo, partition)
|
||||||
|
sysInfo.PartitionNum++
|
||||||
|
|
||||||
|
/*data, err := json.MarshalIndent(info, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(data))*/
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOS() string {
|
||||||
|
var osname string
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
osname = "GNU/Linux"
|
||||||
|
}
|
||||||
|
return osname
|
||||||
|
}
|
||||||
|
|
||||||
|
func utsnameToString(unameArray [65]int8) string {
|
||||||
|
var byteString [65]byte
|
||||||
|
var indexLength int
|
||||||
|
for ; unameArray[indexLength] != 0 && indexLength < 65; indexLength++ {
|
||||||
|
byteString[indexLength] = uint8(unameArray[indexLength])
|
||||||
|
}
|
||||||
|
return string(byteString[:indexLength])
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUnameStr() string {
|
||||||
|
osInfo, _ := syscall.GetVersion()
|
||||||
|
|
||||||
|
return fmt.Sprintf("Widnows %d", osInfo)
|
||||||
|
}
|
||||||
74
features/state/sysinfo.go
Normal file
74
features/state/sysinfo.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"github.com/shirou/gopsutil/cpu"
|
||||||
|
"github.com/shirou/gopsutil/disk"
|
||||||
|
"github.com/shirou/gopsutil/host"
|
||||||
|
"github.com/shirou/gopsutil/mem"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSystemInfo() {
|
||||||
|
// 获取主机信息
|
||||||
|
hostInfo, err := host.Info()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get host info: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Tracef("Host info: %+v", hostInfo)
|
||||||
|
|
||||||
|
// 获取CPU信息
|
||||||
|
cpuInfo, err := cpu.Info()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get CPU info: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Tracef("CPU info: %+v", cpuInfo)
|
||||||
|
|
||||||
|
// 获取内存信息
|
||||||
|
memInfo, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get memory info: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Tracef("Memory info: %+v", memInfo)
|
||||||
|
|
||||||
|
// 获取磁盘分区信息
|
||||||
|
diskPartitions, err := disk.Partitions(true)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get disk partitions: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Tracef("Disk partitions: %+v", diskPartitions)
|
||||||
|
for _, partition := range diskPartitions {
|
||||||
|
// 获取每个磁盘分区的使用情况
|
||||||
|
usage, err := disk.Usage(partition.Mountpoint)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get disk usage for %s: %v", partition.Mountpoint, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Tracef("%s usage: %+v", partition.Mountpoint, usage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCpuNumber() int {
|
||||||
|
// 获取CPU信息
|
||||||
|
cpuInfo, err := cpu.Info()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get CPU info: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
log.Tracef("CPU info: %+v", cpuInfo)
|
||||||
|
return len(cpuInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTotalMemory() int {
|
||||||
|
// 获取内存信息
|
||||||
|
memInfo, err := mem.VirtualMemory()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get memory info: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
log.Tracef("Memory info: %+v", memInfo)
|
||||||
|
return int(memInfo.Total)
|
||||||
|
}
|
||||||
230
features/sys_config/api_sys_config.go
Normal file
230
features/sys_config/api_sys_config.go
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
package sysconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_config/model"
|
||||||
|
"ems.agt/features/sys_config/service"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/midware"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 参数配置信息接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 SysConfigApi 结构体
|
||||||
|
var apis = &SysConfigApi{
|
||||||
|
sysConfigService: service.NewServiceSysConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/configs",
|
||||||
|
Handler: apis.List,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/config/{configId}",
|
||||||
|
Handler: apis.Info,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/config",
|
||||||
|
Handler: apis.Add,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/config",
|
||||||
|
Handler: apis.Edit,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "DELETE",
|
||||||
|
Pattern: "/config/{configIds}",
|
||||||
|
Handler: apis.Remove,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/config/refreshCache",
|
||||||
|
Handler: apis.RefreshCache,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/config/configKey/{configKey}",
|
||||||
|
Handler: apis.ConfigKey,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/configManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置信息
|
||||||
|
//
|
||||||
|
// PATH /configManage
|
||||||
|
type SysConfigApi struct {
|
||||||
|
// 参数配置服务
|
||||||
|
sysConfigService *service.ServiceSysConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置列表
|
||||||
|
//
|
||||||
|
// GET /list
|
||||||
|
func (s *SysConfigApi) List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
querys := ctx.QueryMap(r)
|
||||||
|
data := s.sysConfigService.SelectConfigPage(querys)
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置信息
|
||||||
|
//
|
||||||
|
// GET /:configId
|
||||||
|
func (s *SysConfigApi) Info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
configId := ctx.Param(r, "configId")
|
||||||
|
if configId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := s.sysConfigService.SelectConfigById(configId)
|
||||||
|
if data.ConfigID == configId {
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置新增
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysConfigApi) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysConfig
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.ConfigID != "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查属性值唯一
|
||||||
|
uniqueConfigKey := s.sysConfigService.CheckUniqueConfigKey(body.ConfigKey, "")
|
||||||
|
if !uniqueConfigKey {
|
||||||
|
msg := fmt.Sprintf("参数配置新增【%s】失败,参数键名已存在", body.ConfigKey)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.CreateBy = ctx.LoginUserToUserName(r)
|
||||||
|
insertId := s.sysConfigService.InsertConfig(body)
|
||||||
|
if insertId != "" {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置修改
|
||||||
|
//
|
||||||
|
// PUT /
|
||||||
|
func (s *SysConfigApi) Edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysConfig
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.ConfigID == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查属性值唯一
|
||||||
|
uniqueConfigKey := s.sysConfigService.CheckUniqueConfigKey(body.ConfigKey, body.ConfigID)
|
||||||
|
if !uniqueConfigKey {
|
||||||
|
msg := fmt.Sprintf("参数配置修改【%s】失败,参数键名已存在", body.ConfigKey)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在
|
||||||
|
config := s.sysConfigService.SelectConfigById(body.ConfigID)
|
||||||
|
if config.ConfigID != body.ConfigID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问参数配置数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.UpdateBy = ctx.LoginUserToUserName(r)
|
||||||
|
rows := s.sysConfigService.UpdateConfig(body)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置删除
|
||||||
|
//
|
||||||
|
// DELETE /:configIds
|
||||||
|
func (s *SysConfigApi) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
configIds := ctx.Param(r, "configIds")
|
||||||
|
if configIds == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 处理字符转id数组后去重
|
||||||
|
ids := strings.Split(configIds, ",")
|
||||||
|
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||||
|
if len(uniqueIDs) <= 0 {
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows, err := s.sysConfigService.DeleteConfigByIds(uniqueIDs)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("删除成功:%d", rows)
|
||||||
|
ctx.JSON(w, 200, result.OkMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置刷新缓存
|
||||||
|
//
|
||||||
|
// PUT /refreshCache
|
||||||
|
func (s *SysConfigApi) RefreshCache(w http.ResponseWriter, r *http.Request) {
|
||||||
|
s.sysConfigService.ResetConfigCache()
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参数配置根据参数键名
|
||||||
|
//
|
||||||
|
// GET /configKey/:configKey
|
||||||
|
func (s *SysConfigApi) ConfigKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
configKey := ctx.Param(r, "configKey")
|
||||||
|
if configKey == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := s.sysConfigService.SelectConfigValueByKey(configKey)
|
||||||
|
if key != "" {
|
||||||
|
ctx.JSON(w, 200, result.OkData(key))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
25
features/sys_config/model/sys_config.go
Normal file
25
features/sys_config/model/sys_config.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// 参数配置对象 sys_config
|
||||||
|
type SysConfig struct {
|
||||||
|
// 参数主键
|
||||||
|
ConfigID string `json:"configId"`
|
||||||
|
// 参数名称
|
||||||
|
ConfigName string `json:"configName" binding:"required"`
|
||||||
|
// 参数键名
|
||||||
|
ConfigKey string `json:"configKey" binding:"required"`
|
||||||
|
// 参数键值
|
||||||
|
ConfigValue string `json:"configValue" binding:"required"`
|
||||||
|
// 系统内置(Y是 N否)
|
||||||
|
ConfigType string `json:"configType"`
|
||||||
|
// 创建者
|
||||||
|
CreateBy string `json:"createBy"`
|
||||||
|
// 创建时间
|
||||||
|
CreateTime int64 `json:"createTime"`
|
||||||
|
// 更新者
|
||||||
|
UpdateBy string `json:"updateBy"`
|
||||||
|
// 更新时间
|
||||||
|
UpdateTime int64 `json:"updateTime"`
|
||||||
|
// 备注
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
336
features/sys_config/service/repo_sys_config.go
Normal file
336
features/sys_config/service/repo_sys_config.go
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_config/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/date"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysConfig 结构体
|
||||||
|
var NewRepoSysConfig = &RepoSysConfig{
|
||||||
|
selectSql: `select
|
||||||
|
config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark
|
||||||
|
from sys_config`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"config_id": "ConfigID",
|
||||||
|
"config_name": "ConfigName",
|
||||||
|
"config_key": "ConfigKey",
|
||||||
|
"config_value": "ConfigValue",
|
||||||
|
"config_type": "ConfigType",
|
||||||
|
"remark": "Remark",
|
||||||
|
"create_by": "CreateBy",
|
||||||
|
"create_time": "CreateTime",
|
||||||
|
"update_by": "UpdateBy",
|
||||||
|
"update_time": "UpdateTime",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSysConfig 参数配置表 数据层处理
|
||||||
|
type RepoSysConfig struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoSysConfig) convertResultRows(rows []map[string]any) []model.SysConfig {
|
||||||
|
arr := make([]model.SysConfig, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
sysConfig := model.SysConfig{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysConfig, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, sysConfig)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataPage 分页查询参数配置列表数据
|
||||||
|
func (r *RepoSysConfig) SelectConfigPage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["configName"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "config_name like concat(?, '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["configType"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "config_type = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["configKey"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "config_key like concat(?, '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
beginTime, ok := query["beginTime"]
|
||||||
|
if !ok {
|
||||||
|
beginTime, ok = query["params[beginTime]"]
|
||||||
|
}
|
||||||
|
if ok && beginTime != "" {
|
||||||
|
conditions = append(conditions, "create_time >= ?")
|
||||||
|
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, beginDate.UnixMilli())
|
||||||
|
}
|
||||||
|
endTime, ok := query["endTime"]
|
||||||
|
if !ok {
|
||||||
|
endTime, ok = query["params[endTime]"]
|
||||||
|
}
|
||||||
|
if ok && endTime != "" {
|
||||||
|
conditions = append(conditions, "create_time <= ?")
|
||||||
|
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, endDate.UnixMilli())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := "select count(1) as 'total' from sys_config"
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": []model.SysConfig{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.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 {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectConfigList 查询参数配置列表
|
||||||
|
func (r *RepoSysConfig) SelectConfigList(sysConfig model.SysConfig) []model.SysConfig {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysConfig.ConfigName != "" {
|
||||||
|
conditions = append(conditions, "config_name like concat(?, '%')")
|
||||||
|
params = append(params, sysConfig.ConfigName)
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigType != "" {
|
||||||
|
conditions = append(conditions, "config_type = ?")
|
||||||
|
params = append(params, sysConfig.ConfigType)
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigKey != "" {
|
||||||
|
conditions = append(conditions, "config_key like concat(?, '%')")
|
||||||
|
params = append(params, sysConfig.ConfigKey)
|
||||||
|
}
|
||||||
|
if sysConfig.CreateTime > 0 {
|
||||||
|
conditions = append(conditions, "create_time >= ?")
|
||||||
|
params = append(params, sysConfig.CreateTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectConfigValueByKey 通过参数键名查询参数键值
|
||||||
|
func (r *RepoSysConfig) SelectConfigValueByKey(configKey string) string {
|
||||||
|
querySql := "select config_value as 'str' from sys_config where config_key = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{configKey})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectConfigByIds 通过配置ID查询参数配置信息
|
||||||
|
func (r *RepoSysConfig) SelectConfigByIds(configIds []string) []model.SysConfig {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(configIds))
|
||||||
|
querySql := r.selectSql + " where config_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(configIds)
|
||||||
|
results, err := datasource.RawDB("", querySql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysConfig{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueConfig 校验配置参数是否唯一
|
||||||
|
func (r *RepoSysConfig) CheckUniqueConfig(sysConfig model.SysConfig) string {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysConfig.ConfigKey != "" {
|
||||||
|
conditions = append(conditions, "config_key = ?")
|
||||||
|
params = append(params, sysConfig.ConfigKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := "select config_id as 'str' from sys_config " + whereSql + " limit 1"
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertConfig 新增参数配置
|
||||||
|
func (r *RepoSysConfig) InsertConfig(sysConfig model.SysConfig) string {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysConfig.ConfigName != "" {
|
||||||
|
params["config_name"] = sysConfig.ConfigName
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigKey != "" {
|
||||||
|
params["config_key"] = sysConfig.ConfigKey
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigValue != "" {
|
||||||
|
params["config_value"] = sysConfig.ConfigValue
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigType != "" {
|
||||||
|
params["config_type"] = sysConfig.ConfigType
|
||||||
|
}
|
||||||
|
if sysConfig.Remark != "" {
|
||||||
|
params["remark"] = sysConfig.Remark
|
||||||
|
}
|
||||||
|
if sysConfig.CreateBy != "" {
|
||||||
|
params["create_by"] = sysConfig.CreateBy
|
||||||
|
params["create_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
|
||||||
|
sql := "insert into sys_config (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||||
|
|
||||||
|
// 执行插入
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(insertId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateConfig 修改参数配置
|
||||||
|
func (r *RepoSysConfig) UpdateConfig(sysConfig model.SysConfig) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysConfig.ConfigName != "" {
|
||||||
|
params["config_name"] = sysConfig.ConfigName
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigKey != "" {
|
||||||
|
params["config_key"] = sysConfig.ConfigKey
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigValue != "" {
|
||||||
|
params["config_value"] = sysConfig.ConfigValue
|
||||||
|
}
|
||||||
|
if sysConfig.ConfigType != "" {
|
||||||
|
params["config_type"] = sysConfig.ConfigType
|
||||||
|
}
|
||||||
|
if sysConfig.Remark != "" {
|
||||||
|
params["remark"] = sysConfig.Remark
|
||||||
|
}
|
||||||
|
if sysConfig.UpdateBy != "" {
|
||||||
|
params["update_by"] = sysConfig.UpdateBy
|
||||||
|
params["update_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, values := datasource.KeyValueByUpdate(params)
|
||||||
|
sql := "update sys_config set " + strings.Join(keys, ",") + " where config_id = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
values = append(values, sysConfig.ConfigID)
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteConfigByIds 批量删除参数配置信息
|
||||||
|
func (r *RepoSysConfig) DeleteConfigByIds(configIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(configIds))
|
||||||
|
sql := "delete from sys_config where config_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(configIds)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
155
features/sys_config/service/service_sys_config.go
Normal file
155
features/sys_config/service/service_sys_config.go
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_config/model"
|
||||||
|
"ems.agt/lib/core/cache"
|
||||||
|
"ems.agt/lib/core/constants/cachekey"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceSysConfig 结构体
|
||||||
|
var NewServiceSysConfig = &ServiceSysConfig{
|
||||||
|
sysConfigRepository: NewRepoSysConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceSysConfig 参数配置 服务层处理
|
||||||
|
type ServiceSysConfig struct {
|
||||||
|
// 参数配置表
|
||||||
|
sysConfigRepository *RepoSysConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataPage 分页查询参数配置列表数据
|
||||||
|
func (r *ServiceSysConfig) SelectConfigPage(query map[string]any) map[string]any {
|
||||||
|
return r.sysConfigRepository.SelectConfigPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectConfigList 查询参数配置列表
|
||||||
|
func (r *ServiceSysConfig) SelectConfigList(sysConfig model.SysConfig) []model.SysConfig {
|
||||||
|
return r.sysConfigRepository.SelectConfigList(sysConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectConfigValueByKey 通过参数键名查询参数键值
|
||||||
|
func (r *ServiceSysConfig) SelectConfigValueByKey(configKey string) string {
|
||||||
|
cacheKey := r.getCacheKey(configKey)
|
||||||
|
// 从缓存中读取
|
||||||
|
cacheValue, ok := cache.GetLocal(cacheKey)
|
||||||
|
if cacheValue != nil && ok {
|
||||||
|
return cacheValue.(string)
|
||||||
|
}
|
||||||
|
// 无缓存时读取数据放入缓存中
|
||||||
|
configValue := r.sysConfigRepository.SelectConfigValueByKey(configKey)
|
||||||
|
if configValue != "" {
|
||||||
|
cache.SetLocal(cacheKey, configValue)
|
||||||
|
return configValue
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectConfigById 通过配置ID查询参数配置信息
|
||||||
|
func (r *ServiceSysConfig) SelectConfigById(configId string) model.SysConfig {
|
||||||
|
if configId == "" {
|
||||||
|
return model.SysConfig{}
|
||||||
|
}
|
||||||
|
configs := r.sysConfigRepository.SelectConfigByIds([]string{configId})
|
||||||
|
if len(configs) > 0 {
|
||||||
|
return configs[0]
|
||||||
|
}
|
||||||
|
return model.SysConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueConfigKey 校验参数键名是否唯一
|
||||||
|
func (r *ServiceSysConfig) CheckUniqueConfigKey(configKey, configId string) bool {
|
||||||
|
uniqueId := r.sysConfigRepository.CheckUniqueConfig(model.SysConfig{
|
||||||
|
ConfigKey: configKey,
|
||||||
|
})
|
||||||
|
if uniqueId == configId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertConfig 新增参数配置
|
||||||
|
func (r *ServiceSysConfig) InsertConfig(sysConfig model.SysConfig) string {
|
||||||
|
configId := r.sysConfigRepository.InsertConfig(sysConfig)
|
||||||
|
if configId != "" {
|
||||||
|
r.loadingConfigCache(sysConfig.ConfigKey)
|
||||||
|
}
|
||||||
|
return configId
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateConfig 修改参数配置
|
||||||
|
func (r *ServiceSysConfig) UpdateConfig(sysConfig model.SysConfig) int64 {
|
||||||
|
rows := r.sysConfigRepository.UpdateConfig(sysConfig)
|
||||||
|
if rows > 0 {
|
||||||
|
r.loadingConfigCache(sysConfig.ConfigKey)
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteConfigByIds 批量删除参数配置信息
|
||||||
|
func (r *ServiceSysConfig) DeleteConfigByIds(configIds []string) (int64, error) {
|
||||||
|
// 检查是否存在
|
||||||
|
configs := r.sysConfigRepository.SelectConfigByIds(configIds)
|
||||||
|
if len(configs) <= 0 {
|
||||||
|
return 0, errors.New("没有权限访问参数配置数据!")
|
||||||
|
}
|
||||||
|
for _, config := range configs {
|
||||||
|
// 检查是否为内置参数
|
||||||
|
if config.ConfigType == "Y" {
|
||||||
|
return 0, errors.New(config.ConfigID + " 配置参数属于内置参数,禁止删除!")
|
||||||
|
}
|
||||||
|
// 清除缓存
|
||||||
|
r.clearConfigCache(config.ConfigKey)
|
||||||
|
}
|
||||||
|
if len(configs) == len(configIds) {
|
||||||
|
rows := r.sysConfigRepository.DeleteConfigByIds(configIds)
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("删除参数配置信息失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetConfigCache 重置参数缓存数据
|
||||||
|
func (r *ServiceSysConfig) ResetConfigCache() {
|
||||||
|
r.clearConfigCache("*")
|
||||||
|
r.loadingConfigCache("*")
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCacheKey 组装缓存key
|
||||||
|
func (r *ServiceSysConfig) getCacheKey(configKey string) string {
|
||||||
|
return cachekey.SYS_CONFIG_KEY + configKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadingConfigCache 加载参数缓存数据
|
||||||
|
func (r *ServiceSysConfig) loadingConfigCache(configKey string) {
|
||||||
|
// 查询全部参数
|
||||||
|
if configKey == "*" {
|
||||||
|
sysConfigs := r.SelectConfigList(model.SysConfig{})
|
||||||
|
for _, v := range sysConfigs {
|
||||||
|
key := r.getCacheKey(v.ConfigKey)
|
||||||
|
cache.DeleteLocal(key)
|
||||||
|
cache.SetLocal(key, v.ConfigValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 指定参数
|
||||||
|
if configKey != "" {
|
||||||
|
cacheValue := r.sysConfigRepository.SelectConfigValueByKey(configKey)
|
||||||
|
if cacheValue != "" {
|
||||||
|
key := r.getCacheKey(configKey)
|
||||||
|
cache.DeleteLocal(key)
|
||||||
|
cache.SetLocal(key, cacheValue)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearConfigCache 清空参数缓存数据
|
||||||
|
func (r *ServiceSysConfig) clearConfigCache(configKey string) bool {
|
||||||
|
key := r.getCacheKey(configKey)
|
||||||
|
keys := cache.GetLocalKeys(key)
|
||||||
|
for _, v := range keys {
|
||||||
|
cache.DeleteLocal(v)
|
||||||
|
}
|
||||||
|
return len(keys) > 0
|
||||||
|
}
|
||||||
247
features/sys_dict_data/api_sys_dict_data.go
Normal file
247
features/sys_dict_data/api_sys_dict_data.go
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
package sysdictdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_dict_data/model"
|
||||||
|
sysDictDataService "ems.agt/features/sys_dict_data/service"
|
||||||
|
sysDictTypeService "ems.agt/features/sys_dict_type/service"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/midware"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 字典类型对应的字典数据信息接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 SysDictDataApi 结构体
|
||||||
|
var apis = &SysDictDataApi{
|
||||||
|
sysDictDataService: sysDictDataService.NewServiceSysDictData,
|
||||||
|
sysDictTypeService: sysDictTypeService.NewServiceSysDictType,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/dictDatas",
|
||||||
|
Handler: apis.List,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/dictData/{dictCode}",
|
||||||
|
Handler: apis.Info,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/dictData",
|
||||||
|
Handler: apis.Add,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/dictData",
|
||||||
|
Handler: apis.Edit,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "DELETE",
|
||||||
|
Pattern: "/dictData/{dictCodes}",
|
||||||
|
Handler: apis.Remove,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/dictData/type/{dictType}",
|
||||||
|
Handler: apis.DictType,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/dictDataManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型对应的字典数据信息
|
||||||
|
//
|
||||||
|
// PATH /dictDataManage
|
||||||
|
type SysDictDataApi struct {
|
||||||
|
// 字典数据服务
|
||||||
|
sysDictDataService *sysDictDataService.ServiceSysDictData
|
||||||
|
// 字典类型服务
|
||||||
|
sysDictTypeService *sysDictTypeService.ServiceSysDictType
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典数据列表
|
||||||
|
//
|
||||||
|
// GET /list
|
||||||
|
func (s *SysDictDataApi) List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
querys := ctx.QueryMap(r)
|
||||||
|
data := s.sysDictDataService.SelectDictDataPage(querys)
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典数据详情
|
||||||
|
//
|
||||||
|
// GET /:dictCode
|
||||||
|
func (s *SysDictDataApi) Info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dictCode := ctx.Param(r, "dictCode")
|
||||||
|
if dictCode == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := s.sysDictDataService.SelectDictDataByCode(dictCode)
|
||||||
|
if data.DictCode == dictCode {
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典数据新增
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysDictDataApi) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysDictData
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.DictCode != "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典类型是否存在
|
||||||
|
sysDictType := s.sysDictTypeService.SelectDictTypeByType(body.DictType)
|
||||||
|
if sysDictType.DictType != body.DictType {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问字典类型数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典标签唯一
|
||||||
|
uniqueDictLabel := s.sysDictDataService.CheckUniqueDictLabel(body.DictType, body.DictLabel, "")
|
||||||
|
if !uniqueDictLabel {
|
||||||
|
msg := fmt.Sprintf("数据新增【%s】失败,该字典类型下标签名已存在", body.DictLabel)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典键值唯一
|
||||||
|
uniqueDictValue := s.sysDictDataService.CheckUniqueDictValue(body.DictType, body.DictValue, "")
|
||||||
|
if !uniqueDictValue {
|
||||||
|
msg := fmt.Sprintf("数据新增【%s】失败,该字典类型下标签值已存在", body.DictValue)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.CreateBy = ctx.LoginUserToUserName(r)
|
||||||
|
insertId := s.sysDictDataService.InsertDictData(body)
|
||||||
|
if insertId != "" {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型修改
|
||||||
|
//
|
||||||
|
// PUT /
|
||||||
|
func (s *SysDictDataApi) Edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysDictData
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.DictCode == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典类型是否存在
|
||||||
|
sysDictType := s.sysDictTypeService.SelectDictTypeByType(body.DictType)
|
||||||
|
if sysDictType.DictType != body.DictType {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问字典类型数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典编码是否存在
|
||||||
|
SysDictDataApi := s.sysDictDataService.SelectDictDataByCode(body.DictCode)
|
||||||
|
if SysDictDataApi.DictCode != body.DictCode {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问字典编码数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典标签唯一
|
||||||
|
uniqueDictLabel := s.sysDictDataService.CheckUniqueDictLabel(body.DictType, body.DictLabel, body.DictCode)
|
||||||
|
if !uniqueDictLabel {
|
||||||
|
msg := fmt.Sprintf("数据修改【%s】失败,该字典类型下标签名已存在", body.DictLabel)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典键值唯一
|
||||||
|
uniqueDictValue := s.sysDictDataService.CheckUniqueDictValue(body.DictType, body.DictValue, body.DictCode)
|
||||||
|
if !uniqueDictValue {
|
||||||
|
msg := fmt.Sprintf("数据修改【%s】失败,该字典类型下标签值已存在", body.DictValue)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.UpdateBy = ctx.LoginUserToUserName(r)
|
||||||
|
rows := s.sysDictDataService.UpdateDictData(body)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典数据删除
|
||||||
|
//
|
||||||
|
// DELETE /:dictCodes
|
||||||
|
func (s *SysDictDataApi) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dictCodes := ctx.Param(r, "dictCodes")
|
||||||
|
if dictCodes == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 处理字符转id数组后去重
|
||||||
|
ids := strings.Split(dictCodes, ",")
|
||||||
|
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||||
|
if len(uniqueIDs) <= 0 {
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows, err := s.sysDictDataService.DeleteDictDataByCodes(uniqueIDs)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("删除成功:%d", rows)
|
||||||
|
ctx.JSON(w, 200, result.OkMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典数据列表(指定字典类型)
|
||||||
|
//
|
||||||
|
// GET /type/:dictType
|
||||||
|
func (s *SysDictDataApi) DictType(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dictType := ctx.Param(r, "dictType")
|
||||||
|
if dictType == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := s.sysDictDataService.SelectDictDataByType(dictType)
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
}
|
||||||
31
features/sys_dict_data/model/sys_dict_data.go
Normal file
31
features/sys_dict_data/model/sys_dict_data.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// SysDictData 字典数据对象 sys_dict_data
|
||||||
|
type SysDictData struct {
|
||||||
|
// 字典编码
|
||||||
|
DictCode string `json:"dictCode"`
|
||||||
|
// 字典排序
|
||||||
|
DictSort int `json:"dictSort"`
|
||||||
|
// 字典标签
|
||||||
|
DictLabel string `json:"dictLabel" binding:"required"`
|
||||||
|
// 字典键值
|
||||||
|
DictValue string `json:"dictValue" binding:"required"`
|
||||||
|
// 字典类型
|
||||||
|
DictType string `json:"dictType" binding:"required"`
|
||||||
|
// 样式属性(样式扩展)
|
||||||
|
TagClass string `json:"tagClass"`
|
||||||
|
// 标签类型(预设颜色)
|
||||||
|
TagType string `json:"tagType"`
|
||||||
|
// 状态(0停用 1正常)
|
||||||
|
Status string `json:"status"`
|
||||||
|
// 创建者
|
||||||
|
CreateBy string `json:"createBy"`
|
||||||
|
// 创建时间
|
||||||
|
CreateTime int64 `json:"createTime"`
|
||||||
|
// 更新者
|
||||||
|
UpdateBy string `json:"updateBy"`
|
||||||
|
// 更新时间
|
||||||
|
UpdateTime int64 `json:"updateTime"`
|
||||||
|
// 备注
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
369
features/sys_dict_data/repo/repo_sys_dict_data.go
Normal file
369
features/sys_dict_data/repo/repo_sys_dict_data.go
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_dict_data/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysDictData 结构体
|
||||||
|
var NewRepoSysDictData = &RepoSysDictData{
|
||||||
|
selectSql: `select
|
||||||
|
dict_code, dict_sort, dict_label, dict_value, dict_type, tag_class, tag_type, status, create_by, create_time, remark
|
||||||
|
from sys_dict_data`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"dict_code": "DictCode",
|
||||||
|
"dict_sort": "DictSort",
|
||||||
|
"dict_label": "DictLabel",
|
||||||
|
"dict_value": "DictValue",
|
||||||
|
"dict_type": "DictType",
|
||||||
|
"tag_class": "TagClass",
|
||||||
|
"tag_type": "TagType",
|
||||||
|
"status": "Status",
|
||||||
|
"remark": "Remark",
|
||||||
|
"create_by": "CreateBy",
|
||||||
|
"create_time": "CreateTime",
|
||||||
|
"update_by": "UpdateBy",
|
||||||
|
"update_time": "UpdateTime",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSysDictData 字典类型数据表 数据层处理
|
||||||
|
type RepoSysDictData struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoSysDictData) convertResultRows(rows []map[string]any) []model.SysDictData {
|
||||||
|
arr := make([]model.SysDictData, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
sysDictData := model.SysDictData{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysDictData, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, sysDictData)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataPage 根据条件分页查询字典数据
|
||||||
|
func (r *RepoSysDictData) SelectDictDataPage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["dictType"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "dict_type = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["dictLabel"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "dict_label like concat(?, '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["status"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "status = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := "select count(1) as 'total' from sys_dict_data"
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": []model.SysDictData{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
|
||||||
|
pageSql := " order by dict_sort asc limit ?,? "
|
||||||
|
params = append(params, pageNum*pageSize)
|
||||||
|
params = append(params, pageSize)
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql + pageSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataList 根据条件查询字典数据
|
||||||
|
func (r *RepoSysDictData) SelectDictDataList(sysDictData model.SysDictData) []model.SysDictData {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysDictData.DictLabel != "" {
|
||||||
|
conditions = append(conditions, "dict_label like concat(?, '%')")
|
||||||
|
params = append(params, sysDictData.DictLabel)
|
||||||
|
}
|
||||||
|
if sysDictData.DictType != "" {
|
||||||
|
conditions = append(conditions, "dict_type = ?")
|
||||||
|
params = append(params, sysDictData.DictType)
|
||||||
|
}
|
||||||
|
if sysDictData.Status != "" {
|
||||||
|
conditions = append(conditions, "status = ?")
|
||||||
|
params = append(params, sysDictData.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
orderSql := " order by dict_sort asc "
|
||||||
|
querySql := r.selectSql + whereSql + orderSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysDictData{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataByCodes 根据字典数据编码查询信息
|
||||||
|
func (r *RepoSysDictData) SelectDictDataByCodes(dictCodes []string) []model.SysDictData {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(dictCodes))
|
||||||
|
querySql := r.selectSql + " where dict_code in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(dictCodes)
|
||||||
|
results, err := datasource.RawDB("", querySql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysDictData{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountDictDataByType 查询字典数据
|
||||||
|
func (r *RepoSysDictData) CountDictDataByType(dictType string) int64 {
|
||||||
|
querySql := "select count(1) as 'total' from sys_dict_data where dict_type = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{dictType})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return parse.Number(results[0]["total"])
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueDictData 校验字典数据是否唯一
|
||||||
|
func (r *RepoSysDictData) CheckUniqueDictData(sysDictData model.SysDictData) string {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysDictData.DictType != "" {
|
||||||
|
conditions = append(conditions, "dict_type = ?")
|
||||||
|
params = append(params, sysDictData.DictType)
|
||||||
|
}
|
||||||
|
if sysDictData.DictLabel != "" {
|
||||||
|
conditions = append(conditions, "dict_label = ?")
|
||||||
|
params = append(params, sysDictData.DictLabel)
|
||||||
|
}
|
||||||
|
if sysDictData.DictValue != "" {
|
||||||
|
conditions = append(conditions, "dict_value = ?")
|
||||||
|
params = append(params, sysDictData.DictValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := "select dict_code as 'str' from sys_dict_data " + whereSql + " limit 1"
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDictDataByCodes 批量删除字典数据信息
|
||||||
|
func (r *RepoSysDictData) DeleteDictDataByCodes(dictCodes []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(dictCodes))
|
||||||
|
sql := "delete from sys_dict_data where dict_code in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(dictCodes)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertDictData 新增字典数据信息
|
||||||
|
func (r *RepoSysDictData) InsertDictData(sysDictData model.SysDictData) string {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysDictData.DictSort > 0 {
|
||||||
|
params["dict_sort"] = sysDictData.DictSort
|
||||||
|
}
|
||||||
|
if sysDictData.DictLabel != "" {
|
||||||
|
params["dict_label"] = sysDictData.DictLabel
|
||||||
|
}
|
||||||
|
if sysDictData.DictValue != "" {
|
||||||
|
params["dict_value"] = sysDictData.DictValue
|
||||||
|
}
|
||||||
|
if sysDictData.DictType != "" {
|
||||||
|
params["dict_type"] = sysDictData.DictType
|
||||||
|
}
|
||||||
|
if sysDictData.TagClass != "" {
|
||||||
|
params["tag_class"] = sysDictData.TagClass
|
||||||
|
}
|
||||||
|
if sysDictData.TagType != "" {
|
||||||
|
params["tag_type"] = sysDictData.TagType
|
||||||
|
}
|
||||||
|
if sysDictData.Status != "" {
|
||||||
|
params["status"] = sysDictData.Status
|
||||||
|
}
|
||||||
|
if sysDictData.Remark != "" {
|
||||||
|
params["remark"] = sysDictData.Remark
|
||||||
|
}
|
||||||
|
if sysDictData.CreateBy != "" {
|
||||||
|
params["create_by"] = sysDictData.CreateBy
|
||||||
|
params["create_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
|
||||||
|
sql := "insert into sys_dict_data (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||||
|
|
||||||
|
// 执行插入
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(insertId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDictData 修改字典数据信息
|
||||||
|
func (r *RepoSysDictData) UpdateDictData(sysDictData model.SysDictData) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysDictData.DictSort > 0 {
|
||||||
|
params["dict_sort"] = sysDictData.DictSort
|
||||||
|
}
|
||||||
|
if sysDictData.DictLabel != "" {
|
||||||
|
params["dict_label"] = sysDictData.DictLabel
|
||||||
|
}
|
||||||
|
if sysDictData.DictValue != "" {
|
||||||
|
params["dict_value"] = sysDictData.DictValue
|
||||||
|
}
|
||||||
|
if sysDictData.DictType != "" {
|
||||||
|
params["dict_type"] = sysDictData.DictType
|
||||||
|
}
|
||||||
|
if sysDictData.TagClass != "" {
|
||||||
|
params["tag_class"] = sysDictData.TagClass
|
||||||
|
}
|
||||||
|
if sysDictData.TagType != "" {
|
||||||
|
params["tag_type"] = sysDictData.TagType
|
||||||
|
}
|
||||||
|
if sysDictData.Status != "" {
|
||||||
|
params["status"] = sysDictData.Status
|
||||||
|
}
|
||||||
|
if sysDictData.Remark != "" {
|
||||||
|
params["remark"] = sysDictData.Remark
|
||||||
|
}
|
||||||
|
if sysDictData.UpdateBy != "" {
|
||||||
|
params["update_by"] = sysDictData.UpdateBy
|
||||||
|
params["update_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, values := datasource.KeyValueByUpdate(params)
|
||||||
|
sql := "update sys_dict_data set " + strings.Join(keys, ",") + " where dict_code = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
values = append(values, sysDictData.DictCode)
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDictDataType 同步修改字典类型
|
||||||
|
func (r *RepoSysDictData) UpdateDictDataType(oldDictType string, newDictType string) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make([]any, 0)
|
||||||
|
if oldDictType == "" || newDictType == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
params = append(params, newDictType)
|
||||||
|
params = append(params, oldDictType)
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
sql := "update sys_dict_data set dict_type = ? where dict_type = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
results, err := datasource.ExecDB("", sql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
111
features/sys_dict_data/service/service_sys_dict_data.go
Normal file
111
features/sys_dict_data/service/service_sys_dict_data.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_dict_data/model"
|
||||||
|
"ems.agt/features/sys_dict_data/repo"
|
||||||
|
sysDictTypeService "ems.agt/features/sys_dict_type/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceSysDictData 结构体
|
||||||
|
var NewServiceSysDictData = &ServiceSysDictData{
|
||||||
|
sysDictDataRepository: *repo.NewRepoSysDictData,
|
||||||
|
sysDictTypeService: *sysDictTypeService.NewServiceSysDictType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceSysDictData 字典类型数据 服务层处理
|
||||||
|
type ServiceSysDictData struct {
|
||||||
|
// 字典数据服务
|
||||||
|
sysDictDataRepository repo.RepoSysDictData
|
||||||
|
// 字典类型服务
|
||||||
|
sysDictTypeService sysDictTypeService.ServiceSysDictType
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataPage 根据条件分页查询字典数据
|
||||||
|
func (r *ServiceSysDictData) SelectDictDataPage(query map[string]any) map[string]any {
|
||||||
|
return r.sysDictDataRepository.SelectDictDataPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataList 根据条件查询字典数据
|
||||||
|
func (r *ServiceSysDictData) SelectDictDataList(sysDictData model.SysDictData) []model.SysDictData {
|
||||||
|
return r.sysDictDataRepository.SelectDictDataList(sysDictData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataByCode 根据字典数据编码查询信息
|
||||||
|
func (r *ServiceSysDictData) SelectDictDataByCode(dictCode string) model.SysDictData {
|
||||||
|
if dictCode == "" {
|
||||||
|
return model.SysDictData{}
|
||||||
|
}
|
||||||
|
dictCodes := r.sysDictDataRepository.SelectDictDataByCodes([]string{dictCode})
|
||||||
|
if len(dictCodes) > 0 {
|
||||||
|
return dictCodes[0]
|
||||||
|
}
|
||||||
|
return model.SysDictData{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictDataByType 根据字典类型查询信息
|
||||||
|
func (r *ServiceSysDictData) SelectDictDataByType(dictType string) []model.SysDictData {
|
||||||
|
return r.sysDictTypeService.DictDataCache(dictType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueDictLabel 校验字典标签是否唯一
|
||||||
|
func (r *ServiceSysDictData) CheckUniqueDictLabel(dictType, dictLabel, dictCode string) bool {
|
||||||
|
uniqueId := r.sysDictDataRepository.CheckUniqueDictData(model.SysDictData{
|
||||||
|
DictType: dictType,
|
||||||
|
DictLabel: dictLabel,
|
||||||
|
})
|
||||||
|
if uniqueId == dictCode {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueDictValue 校验字典键值是否唯一
|
||||||
|
func (r *ServiceSysDictData) CheckUniqueDictValue(dictType, dictValue, dictCode string) bool {
|
||||||
|
uniqueId := r.sysDictDataRepository.CheckUniqueDictData(model.SysDictData{
|
||||||
|
DictType: dictType,
|
||||||
|
DictValue: dictValue,
|
||||||
|
})
|
||||||
|
if uniqueId == dictCode {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDictDataByCodes 批量删除字典数据信息
|
||||||
|
func (r *ServiceSysDictData) DeleteDictDataByCodes(dictCodes []string) (int64, error) {
|
||||||
|
// 检查是否存在
|
||||||
|
dictDatas := r.sysDictDataRepository.SelectDictDataByCodes(dictCodes)
|
||||||
|
if len(dictDatas) <= 0 {
|
||||||
|
return 0, errors.New("没有权限访问字典编码数据!")
|
||||||
|
}
|
||||||
|
if len(dictDatas) == len(dictCodes) {
|
||||||
|
for _, v := range dictDatas {
|
||||||
|
// 刷新缓存
|
||||||
|
r.sysDictTypeService.ClearDictCache(v.DictType)
|
||||||
|
r.sysDictTypeService.LoadingDictCache(v.DictType)
|
||||||
|
}
|
||||||
|
rows := r.sysDictDataRepository.DeleteDictDataByCodes(dictCodes)
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("删除字典数据信息失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertDictData 新增字典数据信息
|
||||||
|
func (r *ServiceSysDictData) InsertDictData(sysDictData model.SysDictData) string {
|
||||||
|
insertId := r.sysDictDataRepository.InsertDictData(sysDictData)
|
||||||
|
if insertId != "" {
|
||||||
|
r.sysDictTypeService.LoadingDictCache(sysDictData.DictType)
|
||||||
|
}
|
||||||
|
return insertId
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDictData 修改字典数据信息
|
||||||
|
func (r *ServiceSysDictData) UpdateDictData(sysDictData model.SysDictData) int64 {
|
||||||
|
rows := r.sysDictDataRepository.UpdateDictData(sysDictData)
|
||||||
|
if rows > 0 {
|
||||||
|
r.sysDictTypeService.LoadingDictCache(sysDictData.DictType)
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
253
features/sys_dict_type/api_sys_dict_type.go
Normal file
253
features/sys_dict_type/api_sys_dict_type.go
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
package sysdicttype
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_dict_type/model"
|
||||||
|
sysDictTypeService "ems.agt/features/sys_dict_type/service"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/midware"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 字典类型信息接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 SysDictTypeApi 结构体
|
||||||
|
var apis = &SysDictTypeApi{
|
||||||
|
sysDictTypeService: *sysDictTypeService.NewServiceSysDictType,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/dictTypes",
|
||||||
|
Handler: apis.List,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/dictType/{dictId}",
|
||||||
|
Handler: apis.Info,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/dictType",
|
||||||
|
Handler: apis.Add,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/dictType",
|
||||||
|
Handler: apis.Edit,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "DELETE",
|
||||||
|
Pattern: "/dictType/{dictIds}",
|
||||||
|
Handler: apis.Remove,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/dictType/refreshCache",
|
||||||
|
Handler: apis.RefreshCache,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/dictTypes/optionselect",
|
||||||
|
Handler: apis.DictOptionselect,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/dictTypegManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型信息
|
||||||
|
//
|
||||||
|
// PATH /dictTypegManage
|
||||||
|
type SysDictTypeApi struct {
|
||||||
|
// 字典类型服务
|
||||||
|
sysDictTypeService sysDictTypeService.ServiceSysDictType
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型列表
|
||||||
|
//
|
||||||
|
// GET /list
|
||||||
|
func (s *SysDictTypeApi) List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
querys := ctx.QueryMap(r)
|
||||||
|
data := s.sysDictTypeService.SelectDictTypePage(querys)
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型信息
|
||||||
|
//
|
||||||
|
// GET /:dictId
|
||||||
|
func (s *SysDictTypeApi) Info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dictId := ctx.Param(r, "dictId")
|
||||||
|
if dictId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := s.sysDictTypeService.SelectDictTypeByID(dictId)
|
||||||
|
if data.DictID == dictId {
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型新增
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysDictTypeApi) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysDictType
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.DictID != "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典名称唯一
|
||||||
|
uniqueDictName := s.sysDictTypeService.CheckUniqueDictName(body.DictName, "")
|
||||||
|
if !uniqueDictName {
|
||||||
|
msg := fmt.Sprintf("字典新增【%s】失败,字典名称已存在", body.DictName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典类型唯一
|
||||||
|
uniqueDictType := s.sysDictTypeService.CheckUniqueDictType(body.DictType, "")
|
||||||
|
if !uniqueDictType {
|
||||||
|
msg := fmt.Sprintf("字典新增【%s】失败,字典类型已存在", body.DictType)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.CreateBy = ctx.LoginUserToUserName(r)
|
||||||
|
insertId := s.sysDictTypeService.InsertDictType(body)
|
||||||
|
if insertId != "" {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型修改
|
||||||
|
//
|
||||||
|
// PUT /
|
||||||
|
func (s *SysDictTypeApi) Edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysDictType
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.DictID == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数据是否存在
|
||||||
|
dictInfo := s.sysDictTypeService.SelectDictTypeByID(body.DictID)
|
||||||
|
if dictInfo.DictID != body.DictID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问字典类型数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典名称唯一
|
||||||
|
uniqueDictName := s.sysDictTypeService.CheckUniqueDictName(body.DictName, body.DictID)
|
||||||
|
if !uniqueDictName {
|
||||||
|
msg := fmt.Sprintf("字典修改【%s】失败,字典名称已存在", body.DictName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字典类型唯一
|
||||||
|
uniqueDictType := s.sysDictTypeService.CheckUniqueDictType(body.DictType, body.DictID)
|
||||||
|
if !uniqueDictType {
|
||||||
|
msg := fmt.Sprintf("字典修改【%s】失败,字典类型已存在", body.DictType)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.UpdateBy = ctx.LoginUserToUserName(r)
|
||||||
|
rows := s.sysDictTypeService.UpdateDictType(body)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型删除
|
||||||
|
//
|
||||||
|
// DELETE /:dictIds
|
||||||
|
func (s *SysDictTypeApi) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dictIds := ctx.Param(r, "dictIds")
|
||||||
|
if dictIds == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 处理字符转id数组后去重
|
||||||
|
ids := strings.Split(dictIds, ",")
|
||||||
|
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||||
|
if len(uniqueIDs) <= 0 {
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows, err := s.sysDictTypeService.DeleteDictTypeByIDs(uniqueIDs)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("删除成功:%d", rows)
|
||||||
|
ctx.JSON(w, 200, result.OkMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型刷新缓存
|
||||||
|
//
|
||||||
|
// PUT /refreshCache
|
||||||
|
func (s *SysDictTypeApi) RefreshCache(w http.ResponseWriter, r *http.Request) {
|
||||||
|
s.sysDictTypeService.ResetDictCache()
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字典类型选择框列表
|
||||||
|
//
|
||||||
|
// GET /getDictOptionselect
|
||||||
|
func (s *SysDictTypeApi) DictOptionselect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
data := s.sysDictTypeService.SelectDictTypeList(model.SysDictType{
|
||||||
|
Status: "1",
|
||||||
|
})
|
||||||
|
|
||||||
|
type labelValue struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据组
|
||||||
|
arr := []labelValue{}
|
||||||
|
for _, v := range data {
|
||||||
|
arr = append(arr, labelValue{
|
||||||
|
Label: v.DictName,
|
||||||
|
Value: v.DictType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.OkData(arr))
|
||||||
|
}
|
||||||
23
features/sys_dict_type/model/sys_dict_type.go
Normal file
23
features/sys_dict_type/model/sys_dict_type.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// SysDictType 字典类型对象 sys_dict_type
|
||||||
|
type SysDictType struct {
|
||||||
|
// 字典主键
|
||||||
|
DictID string `json:"dictId"`
|
||||||
|
// 字典名称
|
||||||
|
DictName string `json:"dictName" binding:"required"`
|
||||||
|
// 字典类型
|
||||||
|
DictType string `json:"dictType" binding:"required"`
|
||||||
|
// 状态(0停用 1正常)
|
||||||
|
Status string `json:"status"`
|
||||||
|
// 创建者
|
||||||
|
CreateBy string `json:"createBy"`
|
||||||
|
// 创建时间
|
||||||
|
CreateTime int64 `json:"createTime"`
|
||||||
|
// 更新者
|
||||||
|
UpdateBy string `json:"updateBy"`
|
||||||
|
// 更新时间
|
||||||
|
UpdateTime int64 `json:"updateTime"`
|
||||||
|
// 备注
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
}
|
||||||
330
features/sys_dict_type/repo/repo_sys_dict_type.go
Normal file
330
features/sys_dict_type/repo/repo_sys_dict_type.go
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_dict_type/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/date"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysDictType 结构体
|
||||||
|
var NewRepoSysDictType = &RepoSysDictType{
|
||||||
|
selectSql: `select
|
||||||
|
dict_id, dict_name, dict_type, status, create_by, create_time, remark
|
||||||
|
from sys_dict_type`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"dict_id": "DictID",
|
||||||
|
"dict_name": "DictName",
|
||||||
|
"dict_type": "DictType",
|
||||||
|
"remark": "Remark",
|
||||||
|
"status": "Status",
|
||||||
|
"create_by": "CreateBy",
|
||||||
|
"create_time": "CreateTime",
|
||||||
|
"update_by": "UpdateBy",
|
||||||
|
"update_time": "UpdateTime",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSysDictType 字典类型表 数据层处理
|
||||||
|
type RepoSysDictType struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoSysDictType) convertResultRows(rows []map[string]any) []model.SysDictType {
|
||||||
|
arr := make([]model.SysDictType, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
sysDictType := model.SysDictType{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysDictType, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, sysDictType)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypePage 根据条件分页查询字典类型
|
||||||
|
func (r *RepoSysDictType) SelectDictTypePage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["dictName"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "dict_name like concat(?, '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["dictType"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "dict_type like concat(?, '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["status"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "status = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
beginTime, ok := query["beginTime"]
|
||||||
|
if !ok {
|
||||||
|
beginTime, ok = query["params[beginTime]"]
|
||||||
|
}
|
||||||
|
if ok && beginTime != "" {
|
||||||
|
conditions = append(conditions, "create_time >= ?")
|
||||||
|
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, beginDate.UnixMilli())
|
||||||
|
}
|
||||||
|
endTime, ok := query["endTime"]
|
||||||
|
if !ok {
|
||||||
|
endTime, ok = query["params[endTime]"]
|
||||||
|
}
|
||||||
|
if ok && endTime != "" {
|
||||||
|
conditions = append(conditions, "create_time <= ?")
|
||||||
|
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, endDate.UnixMilli())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := "select count(1) as 'total' from sys_dict_type"
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": []model.SysDictType{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.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 {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypeList 根据条件查询字典类型
|
||||||
|
func (r *RepoSysDictType) SelectDictTypeList(sysDictType model.SysDictType) []model.SysDictType {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysDictType.DictName != "" {
|
||||||
|
conditions = append(conditions, "dict_name like concat(?, '%')")
|
||||||
|
params = append(params, sysDictType.DictName)
|
||||||
|
}
|
||||||
|
if sysDictType.DictType != "" {
|
||||||
|
conditions = append(conditions, "dict_type like concat(?, '%')")
|
||||||
|
params = append(params, sysDictType.DictType)
|
||||||
|
}
|
||||||
|
if sysDictType.Status != "" {
|
||||||
|
conditions = append(conditions, "status = ?")
|
||||||
|
params = append(params, sysDictType.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysDictType{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypeByIDs 根据字典类型ID查询信息
|
||||||
|
func (r *RepoSysDictType) SelectDictTypeByIDs(dictIDs []string) []model.SysDictType {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(dictIDs))
|
||||||
|
querySql := r.selectSql + " where dict_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(dictIDs)
|
||||||
|
results, err := datasource.RawDB("", querySql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysDictType{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypeByType 根据字典类型查询信息
|
||||||
|
func (r *RepoSysDictType) SelectDictTypeByType(dictType string) model.SysDictType {
|
||||||
|
querySql := r.selectSql + " where dict_type = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{dictType})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return model.SysDictType{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
if len(rows) > 0 {
|
||||||
|
return rows[0]
|
||||||
|
}
|
||||||
|
return model.SysDictType{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueDictType 校验字典是否唯一
|
||||||
|
func (r *RepoSysDictType) CheckUniqueDictType(sysDictType model.SysDictType) string {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysDictType.DictName != "" {
|
||||||
|
conditions = append(conditions, "dict_name = ?")
|
||||||
|
params = append(params, sysDictType.DictName)
|
||||||
|
}
|
||||||
|
if sysDictType.DictType != "" {
|
||||||
|
conditions = append(conditions, "dict_type = ?")
|
||||||
|
params = append(params, sysDictType.DictType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := "select dict_id as 'str' from sys_dict_type " + whereSql + " limit 1"
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertDictType 新增字典类型信息
|
||||||
|
func (r *RepoSysDictType) InsertDictType(sysDictType model.SysDictType) string {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysDictType.DictName != "" {
|
||||||
|
params["dict_name"] = sysDictType.DictName
|
||||||
|
}
|
||||||
|
if sysDictType.DictType != "" {
|
||||||
|
params["dict_type"] = sysDictType.DictType
|
||||||
|
}
|
||||||
|
if sysDictType.Status != "" {
|
||||||
|
params["status"] = sysDictType.Status
|
||||||
|
}
|
||||||
|
if sysDictType.Remark != "" {
|
||||||
|
params["remark"] = sysDictType.Remark
|
||||||
|
}
|
||||||
|
if sysDictType.CreateBy != "" {
|
||||||
|
params["create_by"] = sysDictType.CreateBy
|
||||||
|
params["create_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
|
||||||
|
sql := "insert into sys_dict_type (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||||
|
|
||||||
|
// 执行插入
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(insertId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDictType 修改字典类型信息
|
||||||
|
func (r *RepoSysDictType) UpdateDictType(sysDictType model.SysDictType) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysDictType.DictName != "" {
|
||||||
|
params["dict_name"] = sysDictType.DictName
|
||||||
|
}
|
||||||
|
if sysDictType.DictType != "" {
|
||||||
|
params["dict_type"] = sysDictType.DictType
|
||||||
|
}
|
||||||
|
if sysDictType.Status != "" {
|
||||||
|
params["status"] = sysDictType.Status
|
||||||
|
}
|
||||||
|
if sysDictType.Remark != "" {
|
||||||
|
params["remark"] = sysDictType.Remark
|
||||||
|
}
|
||||||
|
if sysDictType.UpdateBy != "" {
|
||||||
|
params["update_by"] = sysDictType.UpdateBy
|
||||||
|
params["update_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, values := datasource.KeyValueByUpdate(params)
|
||||||
|
sql := "update sys_dict_type set " + strings.Join(keys, ",") + " where dict_id = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
values = append(values, sysDictType.DictID)
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDictTypeByIDs 批量删除字典类型信息
|
||||||
|
func (r *RepoSysDictType) DeleteDictTypeByIDs(dictIDs []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(dictIDs))
|
||||||
|
sql := "delete from sys_dict_type where dict_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(dictIDs)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
211
features/sys_dict_type/service/service_sys_dict_type.go
Normal file
211
features/sys_dict_type/service/service_sys_dict_type.go
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sysDictDataModel "ems.agt/features/sys_dict_data/model"
|
||||||
|
sysDictDataRepo "ems.agt/features/sys_dict_data/repo"
|
||||||
|
sysDictTypeModel "ems.agt/features/sys_dict_type/model"
|
||||||
|
"ems.agt/features/sys_dict_type/repo"
|
||||||
|
"ems.agt/lib/core/cache"
|
||||||
|
"ems.agt/lib/core/constants/cachekey"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceSysDictType 结构体
|
||||||
|
var NewServiceSysDictType = &ServiceSysDictType{
|
||||||
|
sysDictTypeRepository: *repo.NewRepoSysDictType,
|
||||||
|
sysDictDataRepository: *sysDictDataRepo.NewRepoSysDictData,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceSysDictType 字典类型 服务层处理
|
||||||
|
type ServiceSysDictType struct {
|
||||||
|
// 字典类型服务
|
||||||
|
sysDictTypeRepository repo.RepoSysDictType
|
||||||
|
// 字典数据服务
|
||||||
|
sysDictDataRepository sysDictDataRepo.RepoSysDictData
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypePage 根据条件分页查询字典类型
|
||||||
|
func (r *ServiceSysDictType) SelectDictTypePage(query map[string]any) map[string]any {
|
||||||
|
return r.sysDictTypeRepository.SelectDictTypePage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypeList 根据条件查询字典类型
|
||||||
|
func (r *ServiceSysDictType) SelectDictTypeList(sysDictType sysDictTypeModel.SysDictType) []sysDictTypeModel.SysDictType {
|
||||||
|
return r.sysDictTypeRepository.SelectDictTypeList(sysDictType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypeByID 根据字典类型ID查询信息
|
||||||
|
func (r *ServiceSysDictType) SelectDictTypeByID(dictID string) sysDictTypeModel.SysDictType {
|
||||||
|
if dictID == "" {
|
||||||
|
return sysDictTypeModel.SysDictType{}
|
||||||
|
}
|
||||||
|
dictTypes := r.sysDictTypeRepository.SelectDictTypeByIDs([]string{dictID})
|
||||||
|
if len(dictTypes) > 0 {
|
||||||
|
return dictTypes[0]
|
||||||
|
}
|
||||||
|
return sysDictTypeModel.SysDictType{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectDictTypeByType 根据字典类型查询信息
|
||||||
|
func (r *ServiceSysDictType) SelectDictTypeByType(dictType string) sysDictTypeModel.SysDictType {
|
||||||
|
return r.sysDictTypeRepository.SelectDictTypeByType(dictType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueDictName 校验字典名称是否唯一
|
||||||
|
func (r *ServiceSysDictType) CheckUniqueDictName(dictName, dictID string) bool {
|
||||||
|
uniqueId := r.sysDictTypeRepository.CheckUniqueDictType(sysDictTypeModel.SysDictType{
|
||||||
|
DictName: dictName,
|
||||||
|
})
|
||||||
|
if uniqueId == dictID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueDictType 校验字典类型是否唯一
|
||||||
|
func (r *ServiceSysDictType) CheckUniqueDictType(dictType, dictID string) bool {
|
||||||
|
uniqueId := r.sysDictTypeRepository.CheckUniqueDictType(sysDictTypeModel.SysDictType{
|
||||||
|
DictType: dictType,
|
||||||
|
})
|
||||||
|
if uniqueId == dictID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertDictType 新增字典类型信息
|
||||||
|
func (r *ServiceSysDictType) InsertDictType(sysDictType sysDictTypeModel.SysDictType) string {
|
||||||
|
insertId := r.sysDictTypeRepository.InsertDictType(sysDictType)
|
||||||
|
if insertId != "" {
|
||||||
|
r.LoadingDictCache(sysDictType.DictType)
|
||||||
|
}
|
||||||
|
return insertId
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDictType 修改字典类型信息
|
||||||
|
func (r *ServiceSysDictType) UpdateDictType(sysDictType sysDictTypeModel.SysDictType) int64 {
|
||||||
|
data := r.sysDictTypeRepository.SelectDictTypeByIDs([]string{sysDictType.DictID})
|
||||||
|
if len(data) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// 修改字典类型key时同步更新其字典数据的类型key
|
||||||
|
oldDictType := data[0].DictType
|
||||||
|
rows := r.sysDictTypeRepository.UpdateDictType(sysDictType)
|
||||||
|
if rows > 0 && oldDictType != "" && oldDictType != sysDictType.DictType {
|
||||||
|
r.sysDictDataRepository.UpdateDictDataType(oldDictType, sysDictType.DictType)
|
||||||
|
}
|
||||||
|
// 刷新缓存
|
||||||
|
r.ClearDictCache(oldDictType)
|
||||||
|
r.LoadingDictCache(sysDictType.DictType)
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteDictTypeByIDs 批量删除字典类型信息
|
||||||
|
func (r *ServiceSysDictType) DeleteDictTypeByIDs(dictIDs []string) (int64, error) {
|
||||||
|
// 检查是否存在
|
||||||
|
dictTypes := r.sysDictTypeRepository.SelectDictTypeByIDs(dictIDs)
|
||||||
|
if len(dictTypes) <= 0 {
|
||||||
|
return 0, errors.New("没有权限访问字典类型数据!")
|
||||||
|
}
|
||||||
|
for _, v := range dictTypes {
|
||||||
|
// 字典类型下级含有数据
|
||||||
|
useCount := r.sysDictDataRepository.CountDictDataByType(v.DictType)
|
||||||
|
if useCount > 0 {
|
||||||
|
msg := fmt.Sprintf("【%s】存在字典数据,不能删除", v.DictName)
|
||||||
|
return 0, errors.New(msg)
|
||||||
|
}
|
||||||
|
// 清除缓存
|
||||||
|
r.ClearDictCache(v.DictType)
|
||||||
|
}
|
||||||
|
if len(dictTypes) == len(dictIDs) {
|
||||||
|
rows := r.sysDictTypeRepository.DeleteDictTypeByIDs(dictIDs)
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("删除字典数据信息失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetDictCache 重置字典缓存数据
|
||||||
|
func (r *ServiceSysDictType) ResetDictCache() {
|
||||||
|
r.ClearDictCache("*")
|
||||||
|
r.LoadingDictCache("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCacheKey 组装缓存key
|
||||||
|
func (r *ServiceSysDictType) getDictCache(dictType string) string {
|
||||||
|
return cachekey.SYS_DICT_KEY + dictType
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadingDictCache 加载字典缓存数据
|
||||||
|
func (r *ServiceSysDictType) LoadingDictCache(dictType string) {
|
||||||
|
sysDictData := sysDictDataModel.SysDictData{
|
||||||
|
Status: "1",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指定字典类型
|
||||||
|
if dictType != "" {
|
||||||
|
sysDictData.DictType = dictType
|
||||||
|
// 删除缓存
|
||||||
|
key := r.getDictCache(dictType)
|
||||||
|
cache.DeleteLocal(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
sysDictDataList := r.sysDictDataRepository.SelectDictDataList(sysDictData)
|
||||||
|
if len(sysDictDataList) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将字典数据按类型分组
|
||||||
|
m := make(map[string][]sysDictDataModel.SysDictData, 0)
|
||||||
|
for _, v := range sysDictDataList {
|
||||||
|
key := v.DictType
|
||||||
|
if item, ok := m[key]; ok {
|
||||||
|
m[key] = append(item, v)
|
||||||
|
} else {
|
||||||
|
m[key] = []sysDictDataModel.SysDictData{v}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 放入缓存
|
||||||
|
for k, v := range m {
|
||||||
|
key := r.getDictCache(k)
|
||||||
|
values, _ := json.Marshal(v)
|
||||||
|
cache.SetLocal(key, string(values))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearDictCache 清空字典缓存数据
|
||||||
|
func (r *ServiceSysDictType) ClearDictCache(dictType string) bool {
|
||||||
|
key := r.getDictCache(dictType)
|
||||||
|
keys := cache.GetLocalKeys(key)
|
||||||
|
for _, v := range keys {
|
||||||
|
cache.DeleteLocal(v)
|
||||||
|
}
|
||||||
|
return len(keys) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// DictDataCache 获取字典数据缓存数据
|
||||||
|
func (r *ServiceSysDictType) DictDataCache(dictType string) []sysDictDataModel.SysDictData {
|
||||||
|
data := []sysDictDataModel.SysDictData{}
|
||||||
|
key := r.getDictCache(dictType)
|
||||||
|
jsonAny, ok := cache.GetLocal(key)
|
||||||
|
if jsonAny != nil && ok {
|
||||||
|
err := json.Unmarshal([]byte(jsonAny.(string)), &data)
|
||||||
|
if err != nil {
|
||||||
|
data = []sysDictDataModel.SysDictData{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = r.sysDictDataRepository.SelectDictDataList(sysDictDataModel.SysDictData{
|
||||||
|
Status: "1",
|
||||||
|
DictType: dictType,
|
||||||
|
})
|
||||||
|
if len(data) > 0 {
|
||||||
|
cache.DeleteLocal(key)
|
||||||
|
values, _ := json.Marshal(data)
|
||||||
|
cache.SetLocal(key, string(values))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
354
features/sys_menu/api_sys_menu.go
Normal file
354
features/sys_menu/api_sys_menu.go
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
package sysmenu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_menu/consts"
|
||||||
|
"ems.agt/features/sys_menu/model"
|
||||||
|
"ems.agt/features/sys_menu/service"
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/utils/regular"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/midware"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 菜单接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 SysMenuApi 结构体
|
||||||
|
var apis = &SysMenuApi{
|
||||||
|
sysMenuService: service.NewServiceSysMenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/menus",
|
||||||
|
Handler: apis.List,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/menu/{menuId}",
|
||||||
|
Handler: apis.Info,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/menu",
|
||||||
|
Handler: apis.Add,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/menu",
|
||||||
|
Handler: apis.Edit,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "DELETE",
|
||||||
|
Pattern: "/menu/{menuId}",
|
||||||
|
Handler: apis.Remove,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/menus/treeSelect",
|
||||||
|
Handler: apis.TreeSelect,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/menu/roleMenuTreeSelect/{roleId}",
|
||||||
|
Handler: apis.RoleMenuTreeSelect,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/menuManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 实例化控制层 SysMenuApi 结构体
|
||||||
|
// var NewSysMenu = &SysMenuApi{
|
||||||
|
// sysMenuService: NewServiceSysMenu,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 菜单信息
|
||||||
|
//
|
||||||
|
// PATH /menuManage
|
||||||
|
type SysMenuApi struct {
|
||||||
|
// 菜单服务
|
||||||
|
sysMenuService *service.ServiceSysMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单列表
|
||||||
|
//
|
||||||
|
// GET /list
|
||||||
|
func (s *SysMenuApi) List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
query := model.SysMenu{}
|
||||||
|
if v := ctx.GetQuery(r, "menuName"); v != "" {
|
||||||
|
query.MenuName = v
|
||||||
|
}
|
||||||
|
if v := ctx.GetQuery(r, "status"); v != "" {
|
||||||
|
query.Status = v
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := ctx.LoginUserToUserID(r)
|
||||||
|
if conf.IsAdmin(userId) {
|
||||||
|
userId = "*"
|
||||||
|
}
|
||||||
|
data := s.sysMenuService.SelectMenuList(query, userId)
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单信息
|
||||||
|
//
|
||||||
|
// GET /:menuId
|
||||||
|
func (s *SysMenuApi) Info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
menuId := ctx.Param(r, "menuId")
|
||||||
|
if menuId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := s.sysMenuService.SelectMenuById(menuId)
|
||||||
|
if data.MenuID == menuId {
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单新增
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysMenuApi) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysMenu
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.MenuID != "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 目录和菜单检查地址唯一
|
||||||
|
if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType {
|
||||||
|
uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, "")
|
||||||
|
if !uniqueNenuPath {
|
||||||
|
msg := fmt.Sprintf("菜单新增【%s】失败,菜单路由地址已存在", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查名称唯一
|
||||||
|
uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, "")
|
||||||
|
if !uniqueNenuName {
|
||||||
|
msg := fmt.Sprintf("菜单新增【%s】失败,菜单名称已存在", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 外链菜单需要符合网站http(s)开头
|
||||||
|
if body.IsFrame == "0" && !regular.ValidHttp(body.Path) {
|
||||||
|
msg := fmt.Sprintf("菜单新增【%s】失败,非内部地址必须以http(s)://开头", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.CreateBy = ctx.LoginUserToUserName(r)
|
||||||
|
insertId := s.sysMenuService.InsertMenu(body)
|
||||||
|
if insertId != "" {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单修改
|
||||||
|
//
|
||||||
|
// PUT /
|
||||||
|
func (s *SysMenuApi) Edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysMenu
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.MenuID == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上级菜单不能选自己
|
||||||
|
if body.MenuID == body.ParentID {
|
||||||
|
msg := fmt.Sprintf("菜单修改【%s】失败,上级菜单不能选择自己", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数据是否存在
|
||||||
|
menuInfo := s.sysMenuService.SelectMenuById(body.MenuID)
|
||||||
|
if menuInfo.MenuID != body.MenuID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问菜单数据"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 父级ID不为0是要检查
|
||||||
|
if body.ParentID != "0" {
|
||||||
|
menuParent := s.sysMenuService.SelectMenuById(body.ParentID)
|
||||||
|
if menuParent.MenuID != body.ParentID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问菜单数据"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 禁用菜单时检查父菜单是否使用
|
||||||
|
if body.Status == "1" && menuParent.Status == "0" {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("父菜单未启用!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 目录和菜单检查地址唯一
|
||||||
|
if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType {
|
||||||
|
uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.MenuID)
|
||||||
|
if !uniqueNenuPath {
|
||||||
|
msg := fmt.Sprintf("菜单修改【%s】失败,菜单路由地址已存在", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查名称唯一
|
||||||
|
uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, body.MenuID)
|
||||||
|
if !uniqueNenuName {
|
||||||
|
msg := fmt.Sprintf("菜单修改【%s】失败,菜单名称已存在", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 外链菜单需要符合网站http(s)开头
|
||||||
|
if body.IsFrame == "0" && !regular.ValidHttp(body.Path) {
|
||||||
|
msg := fmt.Sprintf("菜单修改【%s】失败,非内部地址必须以http(s)://开头", body.MenuName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用菜单时检查子菜单是否使用
|
||||||
|
if body.Status == "0" {
|
||||||
|
hasStatus := s.sysMenuService.HasChildByMenuIdAndStatus(body.MenuID, "1")
|
||||||
|
if hasStatus > 0 {
|
||||||
|
msg := fmt.Sprintf("不允许禁用,存在使用子菜单数:%d", hasStatus)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.UpdateBy = ctx.LoginUserToUserName(r)
|
||||||
|
rows := s.sysMenuService.UpdateMenu(body)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单删除
|
||||||
|
//
|
||||||
|
// DELETE /:menuId
|
||||||
|
func (s *SysMenuApi) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
menuId := ctx.Param(r, "menuId")
|
||||||
|
if menuId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数据是否存在
|
||||||
|
menu := s.sysMenuService.SelectMenuById(menuId)
|
||||||
|
if menu.MenuID != menuId {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问菜单数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在子菜单
|
||||||
|
hasChild := s.sysMenuService.HasChildByMenuIdAndStatus(menuId, "")
|
||||||
|
if hasChild > 0 {
|
||||||
|
msg := fmt.Sprintf("不允许删除,存在子菜单数:%d", hasChild)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否分配给角色
|
||||||
|
existRole := s.sysMenuService.CheckMenuExistRole(menuId)
|
||||||
|
if existRole > 0 {
|
||||||
|
msg := fmt.Sprintf("不允许删除,菜单已分配给角色数:%d", existRole)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := s.sysMenuService.DeleteMenuById(menuId)
|
||||||
|
if rows > 0 {
|
||||||
|
msg := fmt.Sprintf("删除成功:%d", rows)
|
||||||
|
ctx.JSON(w, 200, result.OkMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单树结构列表
|
||||||
|
//
|
||||||
|
// GET /treeSelect
|
||||||
|
func (s *SysMenuApi) TreeSelect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
query := model.SysMenu{}
|
||||||
|
if v := ctx.GetQuery(r, "menuName"); v != "" {
|
||||||
|
query.MenuName = v
|
||||||
|
}
|
||||||
|
if v := ctx.GetQuery(r, "status"); v != "" {
|
||||||
|
query.Status = v
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := ctx.LoginUserToUserID(r)
|
||||||
|
if conf.IsAdmin(userId) {
|
||||||
|
userId = "*"
|
||||||
|
}
|
||||||
|
data := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId)
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单树结构列表(指定角色)
|
||||||
|
//
|
||||||
|
// GET /roleMenuTreeSelect/:roleId
|
||||||
|
func (s *SysMenuApi) RoleMenuTreeSelect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
roleId := ctx.Param(r, "roleId")
|
||||||
|
if roleId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
query := model.SysMenu{}
|
||||||
|
if v := ctx.GetQuery(r, "menuName"); v != "" {
|
||||||
|
query.MenuName = v
|
||||||
|
}
|
||||||
|
if v := ctx.GetQuery(r, "status"); v != "" {
|
||||||
|
query.Status = v
|
||||||
|
}
|
||||||
|
|
||||||
|
userId := ctx.LoginUserToUserID(r)
|
||||||
|
if conf.IsAdmin(userId) {
|
||||||
|
userId = "*"
|
||||||
|
}
|
||||||
|
menuTreeSelect := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId)
|
||||||
|
checkedKeys := s.sysMenuService.SelectMenuListByRoleId(roleId)
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"menus": menuTreeSelect,
|
||||||
|
"checkedKeys": checkedKeys,
|
||||||
|
}))
|
||||||
|
}
|
||||||
24
features/sys_menu/consts/consts_menu.go
Normal file
24
features/sys_menu/consts/consts_menu.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package consts
|
||||||
|
|
||||||
|
// 系统菜单常量信息
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 组件布局类型-基础布局组件标识
|
||||||
|
COMPONENT_LAYOUT_BASIC = "BasicLayout"
|
||||||
|
// 组件布局类型-空白布局组件标识
|
||||||
|
COMPONENT_LAYOUT_BLANK = "BlankLayout"
|
||||||
|
// 组件布局类型-内链接布局组件标识
|
||||||
|
COMPONENT_LAYOUT_LINK = "LinkLayout"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 菜单类型-目录
|
||||||
|
TYPE_DIR = "D"
|
||||||
|
// 菜单类型-菜单
|
||||||
|
TYPE_MENU = "M"
|
||||||
|
// 菜单类型-按钮
|
||||||
|
TYPE_BUTTON = "B"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 菜单内嵌地址标识-带/前缀
|
||||||
|
const PATH_INLINE = "/inline"
|
||||||
46
features/sys_menu/model/sys_menu.go
Normal file
46
features/sys_menu/model/sys_menu.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// SysMenu 菜单权限对象 sys_menu
|
||||||
|
type SysMenu struct {
|
||||||
|
// 菜单ID
|
||||||
|
MenuID string `json:"menuId"`
|
||||||
|
// 菜单名称
|
||||||
|
MenuName string `json:"menuName" binding:"required"`
|
||||||
|
// 父菜单ID 默认0
|
||||||
|
ParentID string `json:"parentId" binding:"required"`
|
||||||
|
// 显示顺序
|
||||||
|
MenuSort int `json:"menuSort"`
|
||||||
|
// 路由地址
|
||||||
|
Path string `json:"path"`
|
||||||
|
// 组件路径
|
||||||
|
Component string `json:"component"`
|
||||||
|
// 是否内部跳转(0否 1是)
|
||||||
|
IsFrame string `json:"isFrame"`
|
||||||
|
// 是否缓存(0不缓存 1缓存)
|
||||||
|
IsCache string `json:"isCache"`
|
||||||
|
// 菜单类型(D目录 M菜单 B按钮)
|
||||||
|
MenuType string `json:"menuType" binding:"required"`
|
||||||
|
// 是否显示(0隐藏 1显示)
|
||||||
|
Visible string `json:"visible"`
|
||||||
|
// 菜单状态(0停用 1正常)
|
||||||
|
Status string `json:"status"`
|
||||||
|
// 权限标识
|
||||||
|
Perms string `json:"perms"`
|
||||||
|
// 菜单图标(#无图标)
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
// 创建者
|
||||||
|
CreateBy string `json:"createBy"`
|
||||||
|
// 创建时间
|
||||||
|
CreateTime int64 `json:"createTime"`
|
||||||
|
// 更新者
|
||||||
|
UpdateBy string `json:"updateBy"`
|
||||||
|
// 更新时间
|
||||||
|
UpdateTime int64 `json:"updateTime"`
|
||||||
|
// 备注
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
|
||||||
|
// ====== 非数据库字段属性 ======
|
||||||
|
|
||||||
|
// 子菜单
|
||||||
|
Children []SysMenu `json:"children,omitempty"`
|
||||||
|
}
|
||||||
475
features/sys_menu/service/repo_sys_menu.go
Normal file
475
features/sys_menu/service/repo_sys_menu.go
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_menu/consts"
|
||||||
|
"ems.agt/features/sys_menu/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysMenu 结构体
|
||||||
|
var NewRepoSysMenu = &RepoSysMenu{
|
||||||
|
selectSql: `select
|
||||||
|
m.menu_id, m.menu_name, m.parent_id, m.menu_sort, m.path, m.component, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, ifnull(m.perms,'') as perms, m.icon, m.create_time, m.remark
|
||||||
|
from sys_menu m`,
|
||||||
|
|
||||||
|
selectSqlByUser: `select distinct
|
||||||
|
m.menu_id, m.menu_name, m.parent_id, m.menu_sort, m.path, m.component, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, ifnull(m.perms,'') as perms, m.icon, m.create_time, m.remark
|
||||||
|
from sys_menu m
|
||||||
|
left join sys_role_menu rm on m.menu_id = rm.menu_id
|
||||||
|
left join sys_user_role ur on rm.role_id = ur.role_id
|
||||||
|
left join sys_role ro on ur.role_id = ro.role_id`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"menu_id": "MenuID",
|
||||||
|
"menu_name": "MenuName",
|
||||||
|
"parent_name": "ParentName",
|
||||||
|
"parent_id": "ParentID",
|
||||||
|
"path": "Path",
|
||||||
|
"menu_sort": "MenuSort",
|
||||||
|
"component": "Component",
|
||||||
|
"is_frame": "IsFrame",
|
||||||
|
"is_cache": "IsCache",
|
||||||
|
"menu_type": "MenuType",
|
||||||
|
"visible": "Visible",
|
||||||
|
"status": "Status",
|
||||||
|
"perms": "Perms",
|
||||||
|
"icon": "Icon",
|
||||||
|
"create_by": "CreateBy",
|
||||||
|
"create_time": "CreateTime",
|
||||||
|
"update_by": "UpdateBy",
|
||||||
|
"update_time": "UpdateTime",
|
||||||
|
"remark": "Remark",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSysMenu 菜单表 数据层处理
|
||||||
|
type RepoSysMenu struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 查询视图用户对象SQL
|
||||||
|
selectSqlByUser string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoSysMenu) convertResultRows(rows []map[string]any) []model.SysMenu {
|
||||||
|
arr := make([]model.SysMenu, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
sysMenu := model.SysMenu{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysMenu, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, sysMenu)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuList 查询系统菜单列表
|
||||||
|
func (r *RepoSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysMenu.MenuName != "" {
|
||||||
|
conditions = append(conditions, "m.menu_name like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, sysMenu.MenuName)
|
||||||
|
}
|
||||||
|
if sysMenu.Visible != "" {
|
||||||
|
conditions = append(conditions, "m.visible = ?")
|
||||||
|
params = append(params, sysMenu.Visible)
|
||||||
|
}
|
||||||
|
if sysMenu.Status != "" {
|
||||||
|
conditions = append(conditions, "m.status = ?")
|
||||||
|
params = append(params, sysMenu.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fromSql := r.selectSql
|
||||||
|
|
||||||
|
// 个人菜单
|
||||||
|
if userId != "*" {
|
||||||
|
fromSql = r.selectSqlByUser
|
||||||
|
conditions = append(conditions, "ur.user_id = ?")
|
||||||
|
params = append(params, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
orderSql := " order by m.parent_id, m.menu_sort"
|
||||||
|
querySql := fromSql + whereSql + orderSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysMenu{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuPermsByUserId 根据用户ID查询权限
|
||||||
|
func (r *RepoSysMenu) SelectMenuPermsByUserId(userId string) []string {
|
||||||
|
querySql := `select distinct m.perms as 'str' from sys_menu m
|
||||||
|
left join sys_role_menu rm on m.menu_id = rm.menu_id
|
||||||
|
left join sys_user_role ur on rm.role_id = ur.role_id
|
||||||
|
left join sys_role r on r.role_id = ur.role_id
|
||||||
|
where m.status = '1' and m.perms != '' and r.status = '1' and ur.user_id = ? `
|
||||||
|
|
||||||
|
// 查询结果
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{userId})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取结果
|
||||||
|
rows := make([]string, 0)
|
||||||
|
for _, m := range results {
|
||||||
|
rows = append(rows, fmt.Sprintf("%v", m["str"]))
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuTreeByUserId 根据用户ID查询菜单
|
||||||
|
func (r *RepoSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu {
|
||||||
|
var params []any
|
||||||
|
var querySql string
|
||||||
|
|
||||||
|
if userId == "*" {
|
||||||
|
// 管理员全部菜单
|
||||||
|
querySql = r.selectSql + ` where
|
||||||
|
m.menu_type in (?,?) and m.status = '1'
|
||||||
|
order by m.parent_id, m.menu_sort`
|
||||||
|
params = append(params, consts.TYPE_DIR)
|
||||||
|
params = append(params, consts.TYPE_MENU)
|
||||||
|
} else {
|
||||||
|
// 用户ID权限
|
||||||
|
querySql = r.selectSqlByUser + ` where
|
||||||
|
m.menu_type in (?, ?) and m.status = '1'
|
||||||
|
and ur.user_id = ? and ro.status = '1'
|
||||||
|
order by m.parent_id, m.menu_sort`
|
||||||
|
params = append(params, consts.TYPE_DIR)
|
||||||
|
params = append(params, consts.TYPE_MENU)
|
||||||
|
params = append(params, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询结果
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysMenu{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuListByRoleId 根据角色ID查询菜单树信息
|
||||||
|
func (r *RepoSysMenu) SelectMenuListByRoleId(roleId string, menuCheckStrictly bool) []string {
|
||||||
|
querySql := `select m.menu_id as 'str' from sys_menu m
|
||||||
|
left join sys_role_menu rm on m.menu_id = rm.menu_id
|
||||||
|
where rm.role_id = ? `
|
||||||
|
var params []any
|
||||||
|
params = append(params, roleId)
|
||||||
|
// 展开
|
||||||
|
if menuCheckStrictly {
|
||||||
|
querySql += ` and m.menu_id not in
|
||||||
|
(select m.parent_id from sys_menu m
|
||||||
|
inner join sys_role_menu rm on m.menu_id = rm.menu_id
|
||||||
|
and rm.role_id = ?) `
|
||||||
|
params = append(params, roleId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询结果
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(results) > 0 {
|
||||||
|
ids := make([]string, 0)
|
||||||
|
for _, v := range results {
|
||||||
|
ids = append(ids, fmt.Sprintf("%v", v["str"]))
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuByIds 根据菜单ID查询信息
|
||||||
|
func (r *RepoSysMenu) SelectMenuByIds(menuIds []string) []model.SysMenu {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(menuIds))
|
||||||
|
querySql := r.selectSql + " where m.menu_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(menuIds)
|
||||||
|
results, err := datasource.RawDB("", querySql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysMenu{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态
|
||||||
|
func (r *RepoSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 {
|
||||||
|
querySql := "select count(1) as 'total' from sys_menu where parent_id = ?"
|
||||||
|
params := []any{menuId}
|
||||||
|
|
||||||
|
// 菜单状态
|
||||||
|
if status != "" {
|
||||||
|
querySql += " and status = ?"
|
||||||
|
params = append(params, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return parse.Number(results[0]["total"])
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertMenu 新增菜单信息
|
||||||
|
func (r *RepoSysMenu) InsertMenu(sysMenu model.SysMenu) string {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysMenu.MenuID != "" {
|
||||||
|
params["menu_id"] = sysMenu.MenuID
|
||||||
|
}
|
||||||
|
if sysMenu.ParentID != "" {
|
||||||
|
params["parent_id"] = sysMenu.ParentID
|
||||||
|
}
|
||||||
|
if sysMenu.MenuName != "" {
|
||||||
|
params["menu_name"] = sysMenu.MenuName
|
||||||
|
}
|
||||||
|
if sysMenu.MenuSort > 0 {
|
||||||
|
params["menu_sort"] = sysMenu.MenuSort
|
||||||
|
}
|
||||||
|
if sysMenu.Path != "" {
|
||||||
|
params["path"] = sysMenu.Path
|
||||||
|
}
|
||||||
|
if sysMenu.Component != "" {
|
||||||
|
params["component"] = sysMenu.Component
|
||||||
|
}
|
||||||
|
if sysMenu.IsFrame != "" {
|
||||||
|
params["is_frame"] = sysMenu.IsFrame
|
||||||
|
}
|
||||||
|
if sysMenu.IsCache != "" {
|
||||||
|
params["is_cache"] = sysMenu.IsCache
|
||||||
|
}
|
||||||
|
if sysMenu.MenuType != "" {
|
||||||
|
params["menu_type"] = sysMenu.MenuType
|
||||||
|
}
|
||||||
|
if sysMenu.Visible != "" {
|
||||||
|
params["visible"] = sysMenu.Visible
|
||||||
|
}
|
||||||
|
if sysMenu.Status != "" {
|
||||||
|
params["status"] = sysMenu.Status
|
||||||
|
}
|
||||||
|
if sysMenu.Perms != "" {
|
||||||
|
params["perms"] = sysMenu.Perms
|
||||||
|
}
|
||||||
|
if sysMenu.Icon != "" {
|
||||||
|
params["icon"] = sysMenu.Icon
|
||||||
|
} else {
|
||||||
|
params["icon"] = "#"
|
||||||
|
}
|
||||||
|
if sysMenu.Remark != "" {
|
||||||
|
params["remark"] = sysMenu.Remark
|
||||||
|
}
|
||||||
|
if sysMenu.CreateBy != "" {
|
||||||
|
params["create_by"] = sysMenu.CreateBy
|
||||||
|
params["create_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据菜单类型重置参数
|
||||||
|
if sysMenu.MenuType == consts.TYPE_BUTTON {
|
||||||
|
params["component"] = ""
|
||||||
|
params["path"] = ""
|
||||||
|
params["icon"] = "#"
|
||||||
|
params["is_cache"] = "1"
|
||||||
|
params["is_frame"] = "1"
|
||||||
|
params["visible"] = "1"
|
||||||
|
params["status"] = "1"
|
||||||
|
}
|
||||||
|
if sysMenu.MenuType == consts.TYPE_DIR {
|
||||||
|
params["component"] = ""
|
||||||
|
params["perms"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
|
||||||
|
sql := "insert into sys_menu (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||||
|
|
||||||
|
// 执行插入
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(insertId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMenu 修改菜单信息
|
||||||
|
func (r *RepoSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysMenu.MenuID != "" {
|
||||||
|
params["menu_id"] = sysMenu.MenuID
|
||||||
|
}
|
||||||
|
if sysMenu.ParentID != "" {
|
||||||
|
params["parent_id"] = sysMenu.ParentID
|
||||||
|
}
|
||||||
|
if sysMenu.MenuName != "" {
|
||||||
|
params["menu_name"] = sysMenu.MenuName
|
||||||
|
}
|
||||||
|
if sysMenu.MenuSort > 0 {
|
||||||
|
params["menu_sort"] = sysMenu.MenuSort
|
||||||
|
}
|
||||||
|
if sysMenu.Path != "" {
|
||||||
|
params["path"] = sysMenu.Path
|
||||||
|
}
|
||||||
|
if sysMenu.Component != "" {
|
||||||
|
params["component"] = sysMenu.Component
|
||||||
|
}
|
||||||
|
if sysMenu.IsFrame != "" {
|
||||||
|
params["is_frame"] = sysMenu.IsFrame
|
||||||
|
}
|
||||||
|
if sysMenu.IsCache != "" {
|
||||||
|
params["is_cache"] = sysMenu.IsCache
|
||||||
|
}
|
||||||
|
if sysMenu.MenuType != "" {
|
||||||
|
params["menu_type"] = sysMenu.MenuType
|
||||||
|
}
|
||||||
|
if sysMenu.Visible != "" {
|
||||||
|
params["visible"] = sysMenu.Visible
|
||||||
|
}
|
||||||
|
if sysMenu.Status != "" {
|
||||||
|
params["status"] = sysMenu.Status
|
||||||
|
}
|
||||||
|
if sysMenu.Perms != "" {
|
||||||
|
params["perms"] = sysMenu.Perms
|
||||||
|
}
|
||||||
|
if sysMenu.Icon != "" {
|
||||||
|
params["icon"] = sysMenu.Icon
|
||||||
|
} else {
|
||||||
|
params["icon"] = "#"
|
||||||
|
}
|
||||||
|
if sysMenu.Remark != "" {
|
||||||
|
params["remark"] = sysMenu.Remark
|
||||||
|
}
|
||||||
|
if sysMenu.UpdateBy != "" {
|
||||||
|
params["update_by"] = sysMenu.UpdateBy
|
||||||
|
params["update_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据菜单类型重置参数
|
||||||
|
if sysMenu.MenuType == consts.TYPE_BUTTON {
|
||||||
|
params["component"] = ""
|
||||||
|
params["path"] = ""
|
||||||
|
params["icon"] = "#"
|
||||||
|
params["is_cache"] = "1"
|
||||||
|
params["is_frame"] = "1"
|
||||||
|
params["visible"] = "1"
|
||||||
|
params["status"] = "1"
|
||||||
|
}
|
||||||
|
if sysMenu.MenuType == consts.TYPE_DIR {
|
||||||
|
params["component"] = ""
|
||||||
|
params["perms"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, values := datasource.KeyValueByUpdate(params)
|
||||||
|
sql := "update sys_menu set " + strings.Join(keys, ",") + " where menu_id = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
values = append(values, sysMenu.MenuID)
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMenuById 删除菜单管理信息
|
||||||
|
func (r *RepoSysMenu) DeleteMenuById(menuId string) int64 {
|
||||||
|
sql := "delete from sys_menu where menu_id = ?"
|
||||||
|
results, err := datasource.ExecDB("", sql, []any{menuId})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueMenu 校验菜单是否唯一
|
||||||
|
func (r *RepoSysMenu) CheckUniqueMenu(sysMenu model.SysMenu) string {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysMenu.MenuName != "" {
|
||||||
|
conditions = append(conditions, "menu_name = ?")
|
||||||
|
params = append(params, sysMenu.MenuName)
|
||||||
|
}
|
||||||
|
if sysMenu.ParentID != "" {
|
||||||
|
conditions = append(conditions, "parent_id = ?")
|
||||||
|
params = append(params, sysMenu.ParentID)
|
||||||
|
}
|
||||||
|
if sysMenu.Path != "" {
|
||||||
|
conditions = append(conditions, "path = ?")
|
||||||
|
params = append(params, sysMenu.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
if whereSql == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := "select menu_id as 'str' from sys_menu " + whereSql + " limit 1"
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
398
features/sys_menu/service/service_sys_menu.go
Normal file
398
features/sys_menu/service/service_sys_menu.go
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_menu/consts"
|
||||||
|
"ems.agt/features/sys_menu/model"
|
||||||
|
sysRoleService "ems.agt/features/sys_role/service"
|
||||||
|
sysrolemenu "ems.agt/features/sys_role_menu"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/utils/regular"
|
||||||
|
"ems.agt/lib/core/vo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceSysMenu 结构体
|
||||||
|
var NewServiceSysMenu = &ServiceSysMenu{
|
||||||
|
sysMenuRepository: NewRepoSysMenu,
|
||||||
|
sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu,
|
||||||
|
sysRoleRepository: sysRoleService.NewRepoSysRole,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceSysMenu 菜单 服务层处理
|
||||||
|
type ServiceSysMenu struct {
|
||||||
|
// 菜单服务
|
||||||
|
sysMenuRepository *RepoSysMenu
|
||||||
|
// 角色与菜单关联服务
|
||||||
|
sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu
|
||||||
|
// 角色服务
|
||||||
|
sysRoleRepository *sysRoleService.RepoSysRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuList 查询系统菜单列表
|
||||||
|
func (r *ServiceSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu {
|
||||||
|
return r.sysMenuRepository.SelectMenuList(sysMenu, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuPermsByUserId 根据用户ID查询权限
|
||||||
|
func (r *ServiceSysMenu) SelectMenuPermsByUserId(userId string) []string {
|
||||||
|
return r.sysMenuRepository.SelectMenuPermsByUserId(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuTreeByUserId 根据用户ID查询菜单
|
||||||
|
func (r *ServiceSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu {
|
||||||
|
sysMenus := r.sysMenuRepository.SelectMenuTreeByUserId(userId)
|
||||||
|
return r.parseDataToTree(sysMenus)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息
|
||||||
|
func (r *ServiceSysMenu) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect {
|
||||||
|
sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId)
|
||||||
|
menus := r.parseDataToTree(sysMenus)
|
||||||
|
tree := make([]vo.TreeSelect, 0)
|
||||||
|
for _, menu := range menus {
|
||||||
|
tree = append(tree, sysMenuTreeSelect(menu))
|
||||||
|
}
|
||||||
|
return tree
|
||||||
|
}
|
||||||
|
|
||||||
|
// sysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象
|
||||||
|
func sysMenuTreeSelect(sysMenu model.SysMenu) vo.TreeSelect {
|
||||||
|
t := vo.TreeSelect{}
|
||||||
|
t.ID = sysMenu.MenuID
|
||||||
|
t.Label = sysMenu.MenuName
|
||||||
|
t.Title = sysMenu.MenuName
|
||||||
|
|
||||||
|
if len(sysMenu.Children) > 0 {
|
||||||
|
for _, menu := range sysMenu.Children {
|
||||||
|
child := sysMenuTreeSelect(menu)
|
||||||
|
t.Children = append(t.Children, child)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Children = []vo.TreeSelect{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuListByRoleId 根据角色ID查询菜单树信息 TODO
|
||||||
|
func (r *ServiceSysMenu) SelectMenuListByRoleId(roleId string) []string {
|
||||||
|
roles := r.sysRoleRepository.SelectRoleByIds([]string{roleId})
|
||||||
|
if len(roles) > 0 {
|
||||||
|
role := roles[0]
|
||||||
|
if role.RoleID == roleId {
|
||||||
|
return r.sysMenuRepository.SelectMenuListByRoleId(
|
||||||
|
role.RoleID,
|
||||||
|
role.MenuCheckStrictly == "1",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMenuById 根据菜单ID查询信息
|
||||||
|
func (r *ServiceSysMenu) SelectMenuById(menuId string) model.SysMenu {
|
||||||
|
if menuId == "" {
|
||||||
|
return model.SysMenu{}
|
||||||
|
}
|
||||||
|
menus := r.sysMenuRepository.SelectMenuByIds([]string{menuId})
|
||||||
|
if len(menus) > 0 {
|
||||||
|
return menus[0]
|
||||||
|
}
|
||||||
|
return model.SysMenu{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态
|
||||||
|
func (r *ServiceSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 {
|
||||||
|
return r.sysMenuRepository.HasChildByMenuIdAndStatus(menuId, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckMenuExistRole 查询菜单是否存在角色
|
||||||
|
func (r *ServiceSysMenu) CheckMenuExistRole(menuId string) int64 {
|
||||||
|
return r.sysRoleMenuRepository.CheckMenuExistRole(menuId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertMenu 新增菜单信息
|
||||||
|
func (r *ServiceSysMenu) InsertMenu(sysMenu model.SysMenu) string {
|
||||||
|
return r.sysMenuRepository.InsertMenu(sysMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMenu 修改菜单信息
|
||||||
|
func (r *ServiceSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 {
|
||||||
|
return r.sysMenuRepository.UpdateMenu(sysMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMenuById 删除菜单管理信息
|
||||||
|
func (r *ServiceSysMenu) DeleteMenuById(menuId string) int64 {
|
||||||
|
// 删除菜单与角色关联
|
||||||
|
r.sysRoleMenuRepository.DeleteMenuRole([]string{menuId})
|
||||||
|
return r.sysMenuRepository.DeleteMenuById(menuId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueMenuName 校验菜单名称是否唯一
|
||||||
|
func (r *ServiceSysMenu) CheckUniqueMenuName(menuName, parentId, menuId string) bool {
|
||||||
|
uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{
|
||||||
|
MenuName: menuName,
|
||||||
|
ParentID: parentId,
|
||||||
|
})
|
||||||
|
if uniqueId == menuId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueMenuPath 校验路由地址是否唯一(针对目录和菜单)
|
||||||
|
func (r *ServiceSysMenu) CheckUniqueMenuPath(path, menuId string) bool {
|
||||||
|
uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
if uniqueId == menuId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildRouteMenus 构建前端路由所需要的菜单
|
||||||
|
func (r *ServiceSysMenu) BuildRouteMenus(sysMenus []model.SysMenu, prefix string) []vo.Router {
|
||||||
|
routers := []vo.Router{}
|
||||||
|
for _, item := range sysMenus {
|
||||||
|
router := vo.Router{}
|
||||||
|
router.Name = r.getRouteName(item)
|
||||||
|
router.Path = r.getRouterPath(item)
|
||||||
|
router.Component = r.getComponent(item)
|
||||||
|
router.Meta = r.getRouteMeta(item)
|
||||||
|
|
||||||
|
// 子项菜单 目录类型 非路径链接
|
||||||
|
cMenus := item.Children
|
||||||
|
if len(cMenus) > 0 && item.MenuType == consts.TYPE_DIR && !regular.ValidHttp(item.Path) {
|
||||||
|
// 获取重定向地址
|
||||||
|
redirectPrefix, redirectPath := r.getRouteRedirect(
|
||||||
|
cMenus,
|
||||||
|
router.Path,
|
||||||
|
prefix,
|
||||||
|
)
|
||||||
|
router.Redirect = redirectPath
|
||||||
|
// 子菜单进入递归
|
||||||
|
router.Children = r.BuildRouteMenus(cMenus, redirectPrefix)
|
||||||
|
} else if item.ParentID == "0" && item.IsFrame == "1" && item.MenuType == consts.TYPE_MENU {
|
||||||
|
// 父菜单 内部跳转 菜单类型
|
||||||
|
menuPath := "/" + item.MenuID
|
||||||
|
childPath := menuPath + r.getRouterPath(item)
|
||||||
|
children := vo.Router{
|
||||||
|
Name: r.getRouteName(item),
|
||||||
|
Path: childPath,
|
||||||
|
Component: item.Component,
|
||||||
|
Meta: r.getRouteMeta(item),
|
||||||
|
}
|
||||||
|
router.Meta.HideChildInMenu = true
|
||||||
|
router.Children = append(router.Children, children)
|
||||||
|
router.Name = item.MenuID
|
||||||
|
router.Path = menuPath
|
||||||
|
router.Redirect = childPath
|
||||||
|
router.Component = consts.COMPONENT_LAYOUT_BASIC
|
||||||
|
} else if item.ParentID == "0" && item.IsFrame == "1" && regular.ValidHttp(item.Path) {
|
||||||
|
// 父菜单 内部跳转 路径链接
|
||||||
|
menuPath := "/" + item.MenuID
|
||||||
|
childPath := menuPath + r.getRouterPath(item)
|
||||||
|
children := vo.Router{
|
||||||
|
Name: r.getRouteName(item),
|
||||||
|
Path: childPath,
|
||||||
|
Component: consts.COMPONENT_LAYOUT_LINK,
|
||||||
|
Meta: r.getRouteMeta(item),
|
||||||
|
}
|
||||||
|
router.Meta.HideChildInMenu = true
|
||||||
|
router.Children = append(router.Children, children)
|
||||||
|
router.Name = item.MenuID
|
||||||
|
router.Path = menuPath
|
||||||
|
router.Redirect = childPath
|
||||||
|
router.Component = consts.COMPONENT_LAYOUT_BASIC
|
||||||
|
}
|
||||||
|
|
||||||
|
routers = append(routers, router)
|
||||||
|
}
|
||||||
|
return routers
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRouteName 获取路由名称 路径英文首字母大写
|
||||||
|
func (r *ServiceSysMenu) getRouteName(sysMenu model.SysMenu) string {
|
||||||
|
routerName := parse.FirstUpper(sysMenu.Path)
|
||||||
|
// 路径链接
|
||||||
|
if regular.ValidHttp(sysMenu.Path) {
|
||||||
|
return routerName[:5] + "Link" + sysMenu.MenuID
|
||||||
|
}
|
||||||
|
return routerName
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRouterPath 获取路由地址
|
||||||
|
func (r *ServiceSysMenu) getRouterPath(sysMenu model.SysMenu) string {
|
||||||
|
routerPath := sysMenu.Path
|
||||||
|
|
||||||
|
// 显式路径
|
||||||
|
if routerPath == "" || strings.HasPrefix(routerPath, "/") {
|
||||||
|
return routerPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路径链接 内部跳转
|
||||||
|
if regular.ValidHttp(routerPath) && sysMenu.IsFrame == "1" {
|
||||||
|
routerPath = regular.Replace(routerPath, `/^http(s)?:\/\/+/`, "")
|
||||||
|
routerPath = base64.StdEncoding.EncodeToString([]byte(routerPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 父菜单 内部跳转
|
||||||
|
if sysMenu.ParentID == "0" && sysMenu.IsFrame == "1" {
|
||||||
|
routerPath = "/" + routerPath
|
||||||
|
}
|
||||||
|
|
||||||
|
return routerPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// getComponent 获取组件信息
|
||||||
|
func (r *ServiceSysMenu) getComponent(sysMenu model.SysMenu) string {
|
||||||
|
// 内部跳转 路径链接
|
||||||
|
if sysMenu.IsFrame == "1" && regular.ValidHttp(sysMenu.Path) {
|
||||||
|
return consts.COMPONENT_LAYOUT_LINK
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非父菜单 目录类型
|
||||||
|
if sysMenu.ParentID != "0" && sysMenu.MenuType == consts.TYPE_DIR {
|
||||||
|
return consts.COMPONENT_LAYOUT_BLANK
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件路径 内部跳转 菜单类型
|
||||||
|
if sysMenu.Component != "" && sysMenu.IsFrame == "1" && sysMenu.MenuType == consts.TYPE_MENU {
|
||||||
|
// 父菜单套外层布局
|
||||||
|
if sysMenu.ParentID == "0" {
|
||||||
|
return consts.COMPONENT_LAYOUT_BASIC
|
||||||
|
}
|
||||||
|
return sysMenu.Component
|
||||||
|
}
|
||||||
|
|
||||||
|
return consts.COMPONENT_LAYOUT_BASIC
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRouteMeta 获取路由元信息
|
||||||
|
func (r *ServiceSysMenu) getRouteMeta(sysMenu model.SysMenu) vo.RouterMeta {
|
||||||
|
meta := vo.RouterMeta{}
|
||||||
|
if sysMenu.Icon == "#" {
|
||||||
|
meta.Icon = ""
|
||||||
|
} else {
|
||||||
|
meta.Icon = sysMenu.Icon
|
||||||
|
}
|
||||||
|
meta.Title = sysMenu.MenuName
|
||||||
|
meta.HideChildInMenu = false
|
||||||
|
meta.HideInMenu = sysMenu.Visible == "0"
|
||||||
|
meta.Cache = sysMenu.IsCache == "1"
|
||||||
|
meta.Target = ""
|
||||||
|
|
||||||
|
// 路径链接 非内部跳转
|
||||||
|
if regular.ValidHttp(sysMenu.Path) && sysMenu.IsFrame == "0" {
|
||||||
|
meta.Target = "_blank"
|
||||||
|
}
|
||||||
|
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRouteRedirect 获取路由重定向地址(针对目录)
|
||||||
|
//
|
||||||
|
// cMenus 子菜单数组
|
||||||
|
// routerPath 当前菜单路径
|
||||||
|
// prefix 菜单重定向路径前缀
|
||||||
|
func (r *ServiceSysMenu) getRouteRedirect(cMenus []model.SysMenu, routerPath string, prefix string) (string, string) {
|
||||||
|
redirectPath := ""
|
||||||
|
|
||||||
|
// 重定向为首个显示并启用的子菜单
|
||||||
|
var firstChild *model.SysMenu
|
||||||
|
for _, item := range cMenus {
|
||||||
|
if item.IsFrame == "1" && item.Visible == "1" {
|
||||||
|
firstChild = &item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查内嵌隐藏菜单是否可做重定向
|
||||||
|
if firstChild == nil {
|
||||||
|
for _, item := range cMenus {
|
||||||
|
if item.IsFrame == "1" && item.Visible == "1" && strings.Contains(item.Path, consts.PATH_INLINE) {
|
||||||
|
firstChild = &item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if firstChild != nil {
|
||||||
|
firstChildPath := r.getRouterPath(*firstChild)
|
||||||
|
if strings.HasPrefix(firstChildPath, "/") {
|
||||||
|
redirectPath = firstChildPath
|
||||||
|
} else {
|
||||||
|
// 拼接追加路径
|
||||||
|
if !strings.HasPrefix(routerPath, "/") {
|
||||||
|
prefix += "/"
|
||||||
|
}
|
||||||
|
prefix = prefix + routerPath
|
||||||
|
redirectPath = prefix + "/" + firstChildPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix, redirectPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseDataToTree 将数据解析为树结构,构建前端所需要下拉树结构
|
||||||
|
func (r *ServiceSysMenu) parseDataToTree(sysMenus []model.SysMenu) []model.SysMenu {
|
||||||
|
// 节点分组
|
||||||
|
nodesMap := make(map[string][]model.SysMenu)
|
||||||
|
// 节点id
|
||||||
|
treeIds := []string{}
|
||||||
|
// 树节点
|
||||||
|
tree := []model.SysMenu{}
|
||||||
|
|
||||||
|
for _, item := range sysMenus {
|
||||||
|
parentID := item.ParentID
|
||||||
|
// 分组
|
||||||
|
mapItem, ok := nodesMap[parentID]
|
||||||
|
if !ok {
|
||||||
|
mapItem = []model.SysMenu{}
|
||||||
|
}
|
||||||
|
mapItem = append(mapItem, item)
|
||||||
|
nodesMap[parentID] = mapItem
|
||||||
|
// 记录节点ID
|
||||||
|
treeIds = append(treeIds, item.MenuID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range nodesMap {
|
||||||
|
// 选择不是节点ID的作为树节点
|
||||||
|
found := false
|
||||||
|
for _, id := range treeIds {
|
||||||
|
if id == key {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
tree = append(tree, value...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, node := range tree {
|
||||||
|
iN := r.parseDataToTreeComponet(node, &nodesMap)
|
||||||
|
tree[i] = iN
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseDataToTreeComponet 递归函数处理子节点
|
||||||
|
func (r *ServiceSysMenu) parseDataToTreeComponet(node model.SysMenu, nodesMap *map[string][]model.SysMenu) model.SysMenu {
|
||||||
|
id := node.MenuID
|
||||||
|
children, ok := (*nodesMap)[id]
|
||||||
|
if ok {
|
||||||
|
node.Children = children
|
||||||
|
}
|
||||||
|
if len(node.Children) > 0 {
|
||||||
|
for i, child := range node.Children {
|
||||||
|
icN := r.parseDataToTreeComponet(child, nodesMap)
|
||||||
|
node.Children[i] = icN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
368
features/sys_role/api_sys_role.go
Normal file
368
features/sys_role/api_sys_role.go
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
package sysrole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_role/model"
|
||||||
|
"ems.agt/features/sys_role/service"
|
||||||
|
userService "ems.agt/features/sys_user/service"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/midware"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 角色接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 SysRoleApi 结构体
|
||||||
|
var apis = &SysRoleApi{
|
||||||
|
sysRoleService: service.NewServiceSysRole,
|
||||||
|
sysUserService: userService.NewServiceSysUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/roles",
|
||||||
|
Handler: apis.List,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/role/{roleId}",
|
||||||
|
Handler: apis.Info,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/role",
|
||||||
|
Handler: apis.Add,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/role",
|
||||||
|
Handler: apis.Edit,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "DELETE",
|
||||||
|
Pattern: "/role/{roleIds}",
|
||||||
|
Handler: apis.Remove,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/role/changeStatus",
|
||||||
|
Handler: apis.Status,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/role/authUser/allocatedList",
|
||||||
|
Handler: apis.AuthUserAllocatedList,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/role/authUser/checked",
|
||||||
|
Handler: apis.AuthUserChecked,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/roleManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 实例化控制层 SysRoleApi 结构体
|
||||||
|
// var NewSysRole = &SysRoleApi{
|
||||||
|
// sysRoleService: sysrole.NewServiceSysRole,
|
||||||
|
// sysUserService: sysuser.NewServiceSysUser,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 角色信息
|
||||||
|
//
|
||||||
|
// PATH /roleManage
|
||||||
|
type SysRoleApi struct {
|
||||||
|
// 角色服务
|
||||||
|
sysRoleService *service.ServiceSysRole
|
||||||
|
// 用户服务
|
||||||
|
sysUserService *userService.ServiceSysUser
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色列表
|
||||||
|
//
|
||||||
|
// GET /list
|
||||||
|
func (s *SysRoleApi) List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
querys := ctx.QueryMap(r)
|
||||||
|
data := s.sysRoleService.SelectRolePage(querys)
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色信息详情
|
||||||
|
//
|
||||||
|
// GET /:roleId
|
||||||
|
func (s *SysRoleApi) Info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
roleId := ctx.Param(r, "roleId")
|
||||||
|
if roleId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := s.sysRoleService.SelectRoleById(roleId)
|
||||||
|
if data.RoleID == roleId {
|
||||||
|
ctx.JSON(w, 200, result.OkData(data))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色信息新增
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysRoleApi) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysRole
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.RoleID != "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断角色名称是否唯一
|
||||||
|
uniqueRoleName := s.sysRoleService.CheckUniqueRoleName(body.RoleName, "")
|
||||||
|
if !uniqueRoleName {
|
||||||
|
msg := fmt.Sprintf("角色新增【%s】失败,角色名称已存在", body.RoleName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断角色键值是否唯一
|
||||||
|
uniqueRoleKey := s.sysRoleService.CheckUniqueRoleKey(body.RoleKey, "")
|
||||||
|
if !uniqueRoleKey {
|
||||||
|
msg := fmt.Sprintf("角色新增【%s】失败,角色键值已存在", body.RoleName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.CreateBy = ctx.LoginUserToUserName(r)
|
||||||
|
insertId := s.sysRoleService.InsertRole(body)
|
||||||
|
if insertId != "" {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色信息修改
|
||||||
|
//
|
||||||
|
// PUT /
|
||||||
|
func (s *SysRoleApi) Edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body model.SysRole
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.RoleID == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否管理员角色
|
||||||
|
if body.RoleID == "1" {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员角色"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在
|
||||||
|
role := s.sysRoleService.SelectRoleById(body.RoleID)
|
||||||
|
if role.RoleID != body.RoleID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问角色数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断角色名称是否唯一
|
||||||
|
uniqueRoleName := s.sysRoleService.CheckUniqueRoleName(body.RoleName, body.RoleID)
|
||||||
|
if !uniqueRoleName {
|
||||||
|
msg := fmt.Sprintf("角色修改【%s】失败,角色名称已存在", body.RoleName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断角色键值是否唯一
|
||||||
|
uniqueRoleKey := s.sysRoleService.CheckUniqueRoleKey(body.RoleKey, body.RoleID)
|
||||||
|
if !uniqueRoleKey {
|
||||||
|
msg := fmt.Sprintf("角色修改【%s】失败,角色键值已存在", body.RoleName)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.UpdateBy = ctx.LoginUserToUserName(r)
|
||||||
|
rows := s.sysRoleService.UpdateRole(body)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色信息删除
|
||||||
|
//
|
||||||
|
// DELETE /:roleIds
|
||||||
|
func (s *SysRoleApi) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
roleIds := ctx.Param(r, "roleIds")
|
||||||
|
if roleIds == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 处理字符转id数组后去重
|
||||||
|
ids := strings.Split(roleIds, ",")
|
||||||
|
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||||
|
if len(uniqueIDs) <= 0 {
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查是否管理员角色
|
||||||
|
for _, id := range uniqueIDs {
|
||||||
|
if id == "1" {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员角色"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rows, err := s.sysRoleService.DeleteRoleByIds(uniqueIDs)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("删除成功:%d", rows)
|
||||||
|
ctx.JSON(w, 200, result.OkMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色状态变更
|
||||||
|
//
|
||||||
|
// PUT /changeStatus
|
||||||
|
func (s *SysRoleApi) Status(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
// 角色ID
|
||||||
|
RoleID string `json:"roleId" binding:"required"`
|
||||||
|
// 状态
|
||||||
|
Status string `json:"status" binding:"required"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否管理员角色
|
||||||
|
if body.RoleID == "1" {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员角色"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在
|
||||||
|
role := s.sysRoleService.SelectRoleById(body.RoleID)
|
||||||
|
if role.RoleID != body.RoleID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问角色数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 与旧值相等不变更
|
||||||
|
if role.Status == body.Status {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("变更状态与旧值相等!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新状态不刷新缓存
|
||||||
|
userName := ctx.LoginUserToUserName(r)
|
||||||
|
SysRoleApi := model.SysRole{
|
||||||
|
RoleID: body.RoleID,
|
||||||
|
Status: body.Status,
|
||||||
|
UpdateBy: userName,
|
||||||
|
}
|
||||||
|
rows := s.sysRoleService.UpdateRole(SysRoleApi)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色分配用户列表
|
||||||
|
//
|
||||||
|
// GET /authUser/allocatedList
|
||||||
|
func (s *SysRoleApi) AuthUserAllocatedList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
querys := ctx.QueryMap(r)
|
||||||
|
roleId, ok := querys["roleId"]
|
||||||
|
if !ok || roleId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在
|
||||||
|
role := s.sysRoleService.SelectRoleById(roleId.(string))
|
||||||
|
if role.RoleID != roleId {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问角色数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := s.sysUserService.SelectAllocatedPage(querys)
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色分配选择授权
|
||||||
|
//
|
||||||
|
// PUT /authUser/checked
|
||||||
|
func (s *SysRoleApi) AuthUserChecked(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
// 角色ID
|
||||||
|
RoleID string `json:"roleId" binding:"required"`
|
||||||
|
// 用户ID组
|
||||||
|
UserIDs string `json:"userIds" binding:"required"`
|
||||||
|
// 选择操作 添加true 取消false
|
||||||
|
Checked bool `json:"checked"`
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理字符转id数组后去重
|
||||||
|
ids := strings.Split(body.UserIDs, ",")
|
||||||
|
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||||
|
if len(uniqueIDs) <= 0 {
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在
|
||||||
|
role := s.sysRoleService.SelectRoleById(body.RoleID)
|
||||||
|
if role.RoleID != body.RoleID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问角色数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var rows int64
|
||||||
|
if body.Checked {
|
||||||
|
rows = s.sysRoleService.InsertAuthUsers(body.RoleID, uniqueIDs)
|
||||||
|
} else {
|
||||||
|
rows = s.sysRoleService.DeleteAuthUsers(body.RoleID, uniqueIDs)
|
||||||
|
}
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
38
features/sys_role/model/sys_role.go
Normal file
38
features/sys_role/model/sys_role.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// SysRole 角色对象 sys_role
|
||||||
|
type SysRole struct {
|
||||||
|
// 角色ID
|
||||||
|
RoleID string `json:"roleId"`
|
||||||
|
// 角色名称
|
||||||
|
RoleName string `json:"roleName" binding:"required"`
|
||||||
|
// 角色键值
|
||||||
|
RoleKey string `json:"roleKey" binding:"required"`
|
||||||
|
// 显示顺序
|
||||||
|
RoleSort int `json:"roleSort"`
|
||||||
|
// 菜单树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示)
|
||||||
|
MenuCheckStrictly string `json:"menuCheckStrictly"`
|
||||||
|
// 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示)
|
||||||
|
DeptCheckStrictly string `json:"deptCheckStrictly"`
|
||||||
|
// 角色状态(0停用 1正常)
|
||||||
|
Status string `json:"status"`
|
||||||
|
// 删除标志(0代表存在 1代表删除)
|
||||||
|
DelFlag string `json:"delFlag"`
|
||||||
|
// 创建者
|
||||||
|
CreateBy string `json:"createBy"`
|
||||||
|
// 创建时间
|
||||||
|
CreateTime int64 `json:"createTime"`
|
||||||
|
// 更新者
|
||||||
|
UpdateBy string `json:"updateBy"`
|
||||||
|
// 更新时间
|
||||||
|
UpdateTime int64 `json:"updateTime"`
|
||||||
|
// 备注
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
|
||||||
|
// ====== 非数据库字段属性 ======
|
||||||
|
|
||||||
|
// 菜单组
|
||||||
|
MenuIds []string `json:"menuIds,omitempty"`
|
||||||
|
// 部门组(数据权限)
|
||||||
|
DeptIds []string `json:"deptIds,omitempty"`
|
||||||
|
}
|
||||||
362
features/sys_role/service/repo_sys_role.go
Normal file
362
features/sys_role/service/repo_sys_role.go
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_role/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/date"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysRole 结构体
|
||||||
|
var NewRepoSysRole = &RepoSysRole{
|
||||||
|
selectSql: `select distinct
|
||||||
|
r.role_id, r.role_name, r.role_key, r.role_sort, r.menu_check_strictly,
|
||||||
|
r.dept_check_strictly, r.status, r.del_flag, r.create_time, r.remark
|
||||||
|
from sys_role r
|
||||||
|
left join sys_user_role ur on ur.role_id = r.role_id
|
||||||
|
left join user u on u.id = ur.user_id`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"role_id": "RoleID",
|
||||||
|
"role_name": "RoleName",
|
||||||
|
"role_key": "RoleKey",
|
||||||
|
"role_sort": "RoleSort",
|
||||||
|
"menu_check_strictly": "MenuCheckStrictly",
|
||||||
|
"dept_check_strictly": "DeptCheckStrictly",
|
||||||
|
"status": "Status",
|
||||||
|
"del_flag": "DelFlag",
|
||||||
|
"create_by": "CreateBy",
|
||||||
|
"create_time": "CreateTime",
|
||||||
|
"update_by": "UpdateBy",
|
||||||
|
"update_time": "UpdateTime",
|
||||||
|
"remark": "Remark",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSysRole 角色表 数据层处理
|
||||||
|
type RepoSysRole struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoSysRole) convertResultRows(rows []map[string]any) []model.SysRole {
|
||||||
|
arr := make([]model.SysRole, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
sysRole := model.SysRole{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysRole, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, sysRole)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRolePage 根据条件分页查询角色数据
|
||||||
|
func (r *RepoSysRole) SelectRolePage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["roleId"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "r.role_id = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["roleName"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "r.role_name like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["roleKey"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "r.role_key like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["status"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "r.status = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
beginTime, ok := query["beginTime"]
|
||||||
|
if !ok {
|
||||||
|
beginTime, ok = query["params[beginTime]"]
|
||||||
|
}
|
||||||
|
if ok && beginTime != "" {
|
||||||
|
conditions = append(conditions, "r.create_time >= ?")
|
||||||
|
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, beginDate.UnixMilli())
|
||||||
|
}
|
||||||
|
endTime, ok := query["endTime"]
|
||||||
|
if !ok {
|
||||||
|
endTime, ok = query["params[endTime]"]
|
||||||
|
}
|
||||||
|
if ok && endTime != "" {
|
||||||
|
conditions = append(conditions, "r.create_time <= ?")
|
||||||
|
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, endDate.UnixMilli())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := " where r.del_flag = '0' "
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " and " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := `select count(distinct r.role_id) as 'total' from sys_role r
|
||||||
|
left join sys_user_role ur on ur.role_id = r.role_id
|
||||||
|
left join user u on u.id = ur.user_id`
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": []model.SysRole{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
|
||||||
|
pageSql := " order by r.role_sort asc limit ?,? "
|
||||||
|
params = append(params, pageNum*pageSize)
|
||||||
|
params = append(params, pageSize)
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql + pageSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRoleList 根据条件查询角色数据
|
||||||
|
func (r *RepoSysRole) SelectRoleList(sysRole model.SysRole) []model.SysRole {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysRole.RoleID != "" {
|
||||||
|
conditions = append(conditions, "r.role_id = ?")
|
||||||
|
params = append(params, sysRole.RoleID)
|
||||||
|
}
|
||||||
|
if sysRole.RoleKey != "" {
|
||||||
|
conditions = append(conditions, "r.role_key like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, sysRole.RoleKey)
|
||||||
|
}
|
||||||
|
if sysRole.RoleName != "" {
|
||||||
|
conditions = append(conditions, "r.role_name like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, sysRole.RoleName)
|
||||||
|
}
|
||||||
|
if sysRole.Status != "" {
|
||||||
|
conditions = append(conditions, "r.status = ?")
|
||||||
|
params = append(params, sysRole.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := " where r.del_flag = '0' "
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " and " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
orderSql := " order by r.role_sort"
|
||||||
|
querySql := r.selectSql + whereSql + orderSql
|
||||||
|
rows, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysRole{}
|
||||||
|
}
|
||||||
|
return r.convertResultRows(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRoleListByUserId 根据用户ID获取角色选择框列表
|
||||||
|
func (r *RepoSysRole) SelectRoleListByUserId(userId string) []model.SysRole {
|
||||||
|
querySql := r.selectSql + " where r.del_flag = '0' and ur.user_id = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{userId})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysRole{}
|
||||||
|
}
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRoleByIds 通过角色ID查询角色
|
||||||
|
func (r *RepoSysRole) SelectRoleByIds(roleIds []string) []model.SysRole {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(roleIds))
|
||||||
|
querySql := r.selectSql + " where r.role_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(roleIds)
|
||||||
|
results, err := datasource.RawDB("", querySql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []model.SysRole{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRole 修改角色信息
|
||||||
|
func (r *RepoSysRole) UpdateRole(sysRole model.SysRole) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysRole.RoleName != "" {
|
||||||
|
params["role_name"] = sysRole.RoleName
|
||||||
|
}
|
||||||
|
if sysRole.RoleKey != "" {
|
||||||
|
params["role_key"] = sysRole.RoleKey
|
||||||
|
}
|
||||||
|
if sysRole.RoleSort > 0 {
|
||||||
|
params["role_sort"] = sysRole.RoleSort
|
||||||
|
}
|
||||||
|
if sysRole.MenuCheckStrictly != "" {
|
||||||
|
params["menu_check_strictly"] = sysRole.MenuCheckStrictly
|
||||||
|
}
|
||||||
|
if sysRole.DeptCheckStrictly != "" {
|
||||||
|
params["dept_check_strictly"] = sysRole.DeptCheckStrictly
|
||||||
|
}
|
||||||
|
if sysRole.Status != "" {
|
||||||
|
params["status"] = sysRole.Status
|
||||||
|
}
|
||||||
|
if sysRole.Remark != "" {
|
||||||
|
params["remark"] = sysRole.Remark
|
||||||
|
}
|
||||||
|
if sysRole.UpdateBy != "" {
|
||||||
|
params["update_by"] = sysRole.UpdateBy
|
||||||
|
params["update_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, values := datasource.KeyValueByUpdate(params)
|
||||||
|
sql := "update sys_role set " + strings.Join(keys, ",") + " where role_id = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
values = append(values, sysRole.RoleID)
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertRole 新增角色信息
|
||||||
|
func (r *RepoSysRole) InsertRole(sysRole model.SysRole) string {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysRole.RoleID != "" {
|
||||||
|
params["role_id"] = sysRole.RoleID
|
||||||
|
}
|
||||||
|
if sysRole.RoleName != "" {
|
||||||
|
params["role_name"] = sysRole.RoleName
|
||||||
|
}
|
||||||
|
if sysRole.RoleKey != "" {
|
||||||
|
params["role_key"] = sysRole.RoleKey
|
||||||
|
}
|
||||||
|
if sysRole.RoleSort > 0 {
|
||||||
|
params["role_sort"] = sysRole.RoleSort
|
||||||
|
}
|
||||||
|
if sysRole.MenuCheckStrictly != "" {
|
||||||
|
params["menu_check_strictly"] = sysRole.MenuCheckStrictly
|
||||||
|
}
|
||||||
|
if sysRole.DeptCheckStrictly != "" {
|
||||||
|
params["dept_check_strictly"] = sysRole.DeptCheckStrictly
|
||||||
|
}
|
||||||
|
if sysRole.Status != "" {
|
||||||
|
params["status"] = sysRole.Status
|
||||||
|
}
|
||||||
|
if sysRole.Remark != "" {
|
||||||
|
params["remark"] = sysRole.Remark
|
||||||
|
}
|
||||||
|
if sysRole.CreateBy != "" {
|
||||||
|
params["create_by"] = sysRole.CreateBy
|
||||||
|
params["create_time"] = time.Now().UnixMilli()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
|
||||||
|
sql := "insert into sys_role (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||||
|
|
||||||
|
// 执行插入
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(insertId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRoleByIds 批量删除角色信息
|
||||||
|
func (r *RepoSysRole) DeleteRoleByIds(roleIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(roleIds))
|
||||||
|
sql := "update sys_role set del_flag = '1' where role_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(roleIds)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueRole 校验角色是否唯一
|
||||||
|
func (r *RepoSysRole) CheckUniqueRole(sysRole model.SysRole) string {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysRole.RoleName != "" {
|
||||||
|
conditions = append(conditions, "r.role_name = ?")
|
||||||
|
params = append(params, sysRole.RoleName)
|
||||||
|
}
|
||||||
|
if sysRole.RoleKey != "" {
|
||||||
|
conditions = append(conditions, "r.role_key = ?")
|
||||||
|
params = append(params, sysRole.RoleKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := "select role_id as 'str' from sys_role r " + whereSql + " and r.del_flag = '0' limit 1"
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
165
features/sys_role/service/service_sys_role.go
Normal file
165
features/sys_role/service/service_sys_role.go
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"ems.agt/features/sys_role/model"
|
||||||
|
sysrolemenu "ems.agt/features/sys_role_menu"
|
||||||
|
sysuserrole "ems.agt/features/sys_user_role"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceSysRole 结构体
|
||||||
|
var NewServiceSysRole = &ServiceSysRole{
|
||||||
|
sysRoleRepository: NewRepoSysRole,
|
||||||
|
sysUserRoleRepository: sysuserrole.NewRepoSysUserRole,
|
||||||
|
sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceSysRole 角色 服务层处理
|
||||||
|
type ServiceSysRole struct {
|
||||||
|
// 角色服务
|
||||||
|
sysRoleRepository *RepoSysRole
|
||||||
|
// 用户与角色关联服务
|
||||||
|
sysUserRoleRepository *sysuserrole.RepoSysUserRole
|
||||||
|
// 角色与菜单关联服务
|
||||||
|
sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRolePage 根据条件分页查询角色数据
|
||||||
|
func (r *ServiceSysRole) SelectRolePage(query map[string]any) map[string]any {
|
||||||
|
return r.sysRoleRepository.SelectRolePage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRoleList 根据条件查询角色数据
|
||||||
|
func (r *ServiceSysRole) SelectRoleList(sysRole model.SysRole) []model.SysRole {
|
||||||
|
return r.sysRoleRepository.SelectRoleList(sysRole)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRoleListByUserId 根据用户ID获取角色选择框列表
|
||||||
|
func (r *ServiceSysRole) SelectRoleListByUserId(userId string) []model.SysRole {
|
||||||
|
return r.sysRoleRepository.SelectRoleListByUserId(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRoleById 通过角色ID查询角色
|
||||||
|
func (r *ServiceSysRole) SelectRoleById(roleId string) model.SysRole {
|
||||||
|
if roleId == "" {
|
||||||
|
return model.SysRole{}
|
||||||
|
}
|
||||||
|
posts := r.sysRoleRepository.SelectRoleByIds([]string{roleId})
|
||||||
|
if len(posts) > 0 {
|
||||||
|
return posts[0]
|
||||||
|
}
|
||||||
|
return model.SysRole{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRole 修改角色信息
|
||||||
|
func (r *ServiceSysRole) UpdateRole(sysRole model.SysRole) int64 {
|
||||||
|
rows := r.sysRoleRepository.UpdateRole(sysRole)
|
||||||
|
if rows > 0 {
|
||||||
|
// 删除角色与菜单关联
|
||||||
|
r.sysRoleMenuRepository.DeleteRoleMenu([]string{sysRole.RoleID})
|
||||||
|
if len(sysRole.MenuIds) > 0 {
|
||||||
|
r.insertRoleMenu(sysRole.RoleID, sysRole.MenuIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertRole 新增角色信息
|
||||||
|
func (r *ServiceSysRole) InsertRole(sysRole model.SysRole) string {
|
||||||
|
insertId := r.sysRoleRepository.InsertRole(sysRole)
|
||||||
|
if insertId != "" && len(sysRole.MenuIds) > 0 {
|
||||||
|
r.insertRoleMenu(insertId, sysRole.MenuIds)
|
||||||
|
}
|
||||||
|
return insertId
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertRoleMenu 新增角色菜单信息
|
||||||
|
func (r *ServiceSysRole) insertRoleMenu(roleId string, menuIds []string) int64 {
|
||||||
|
if roleId == "" || len(menuIds) <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sysRoleMenus := []sysrolemenu.SysRoleMenu{}
|
||||||
|
for _, menuId := range menuIds {
|
||||||
|
if menuId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sysRoleMenus = append(sysRoleMenus, sysrolemenu.NewSysRoleMenu(roleId, menuId))
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.sysRoleMenuRepository.BatchRoleMenu(sysRoleMenus)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRoleByIds 批量删除角色信息
|
||||||
|
func (r *ServiceSysRole) DeleteRoleByIds(roleIds []string) (int64, error) {
|
||||||
|
// 检查是否存在
|
||||||
|
roles := r.sysRoleRepository.SelectRoleByIds(roleIds)
|
||||||
|
if len(roles) <= 0 {
|
||||||
|
return 0, errors.New("没有权限访问角色数据!")
|
||||||
|
}
|
||||||
|
for _, role := range roles {
|
||||||
|
// 检查是否为已删除
|
||||||
|
if role.DelFlag == "1" {
|
||||||
|
return 0, errors.New(role.RoleID + " 角色信息已经删除!")
|
||||||
|
}
|
||||||
|
// 检查分配用户
|
||||||
|
userCount := r.sysUserRoleRepository.CountUserRoleByRoleId(role.RoleID)
|
||||||
|
if userCount > 0 {
|
||||||
|
msg := fmt.Sprintf("【%s】已分配给用户,不能删除", role.RoleName)
|
||||||
|
return 0, errors.New(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(roles) == len(roleIds) {
|
||||||
|
// 删除角色与菜单关联
|
||||||
|
r.sysRoleMenuRepository.DeleteRoleMenu(roleIds)
|
||||||
|
rows := r.sysRoleRepository.DeleteRoleByIds(roleIds)
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("删除角色信息失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueRoleName 校验角色名称是否唯一
|
||||||
|
func (r *ServiceSysRole) CheckUniqueRoleName(roleName, roleId string) bool {
|
||||||
|
uniqueId := r.sysRoleRepository.CheckUniqueRole(model.SysRole{
|
||||||
|
RoleName: roleName,
|
||||||
|
})
|
||||||
|
if uniqueId == roleId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueRoleKey 校验角色权限是否唯一
|
||||||
|
func (r *ServiceSysRole) CheckUniqueRoleKey(roleKey, roleId string) bool {
|
||||||
|
uniqueId := r.sysRoleRepository.CheckUniqueRole(model.SysRole{
|
||||||
|
RoleKey: roleKey,
|
||||||
|
})
|
||||||
|
if uniqueId == roleId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAuthUsers 批量取消授权用户角色
|
||||||
|
func (r *ServiceSysRole) DeleteAuthUsers(roleId string, userIds []string) int64 {
|
||||||
|
return r.sysUserRoleRepository.DeleteUserRoleByRoleId(roleId, userIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertAuthUsers 批量新增授权用户角色
|
||||||
|
func (r *ServiceSysRole) InsertAuthUsers(roleId string, userIds []string) int64 {
|
||||||
|
if roleId == "" || len(userIds) <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sysUserRoles := []sysuserrole.SysUserRole{}
|
||||||
|
for _, userId := range userIds {
|
||||||
|
if userId == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sysUserRoles = append(sysUserRoles, sysuserrole.NewSysUserRole(userId, roleId))
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.sysUserRoleRepository.BatchUserRole(sysUserRoles)
|
||||||
|
}
|
||||||
15
features/sys_role_menu/model_sys_role_menu.go
Normal file
15
features/sys_role_menu/model_sys_role_menu.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package sysrolemenu
|
||||||
|
|
||||||
|
// SysRoleMenu 角色和菜单关联对象 sys_role_menu
|
||||||
|
type SysRoleMenu struct {
|
||||||
|
RoleID string `json:"roleId"` // 角色ID
|
||||||
|
MenuID string `json:"menuId"` // 菜单ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSysRoleMenu 创建角色和菜单关联对象的构造函数
|
||||||
|
func NewSysRoleMenu(roleID string, menuID string) SysRoleMenu {
|
||||||
|
return SysRoleMenu{
|
||||||
|
RoleID: roleID,
|
||||||
|
MenuID: menuID,
|
||||||
|
}
|
||||||
|
}
|
||||||
86
features/sys_role_menu/repo_sys_role_menu.go
Normal file
86
features/sys_role_menu/repo_sys_role_menu.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package sysrolemenu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysRoleMenu 结构体
|
||||||
|
var NewRepoSysRoleMenu = &RepoSysRoleMenu{}
|
||||||
|
|
||||||
|
// RepoSysRoleMenu 角色与菜单关联表 数据层处理
|
||||||
|
type RepoSysRoleMenu struct{}
|
||||||
|
|
||||||
|
// CheckMenuExistRole 查询菜单分配给角色使用数量
|
||||||
|
func (r *RepoSysRoleMenu) CheckMenuExistRole(menuId string) int64 {
|
||||||
|
querySql := "select count(1) as 'total' from sys_role_menu where menu_id = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{menuId})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return parse.Number(results[0]["total"])
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRoleMenu 批量删除角色和菜单关联
|
||||||
|
func (r *RepoSysRoleMenu) DeleteRoleMenu(roleIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(roleIds))
|
||||||
|
sql := "delete from sys_role_menu where role_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(roleIds)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMenuRole 批量删除菜单和角色关联
|
||||||
|
func (r *RepoSysRoleMenu) DeleteMenuRole(menuIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(menuIds))
|
||||||
|
sql := "delete from sys_role_menu where menu_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(menuIds)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchRoleMenu 批量新增角色菜单信息
|
||||||
|
func (r *RepoSysRoleMenu) BatchRoleMenu(sysRoleMenus []SysRoleMenu) int64 {
|
||||||
|
keyValues := make([]string, 0)
|
||||||
|
for _, item := range sysRoleMenus {
|
||||||
|
keyValues = append(keyValues, fmt.Sprintf("(%s,%s)", item.RoleID, item.MenuID))
|
||||||
|
}
|
||||||
|
sql := "insert into sys_role_menu(role_id, menu_id) values " + strings.Join(keyValues, ",")
|
||||||
|
results, err := datasource.ExecDB("", sql, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return insertId
|
||||||
|
}
|
||||||
323
features/sys_user/api_sys_user.go
Normal file
323
features/sys_user/api_sys_user.go
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
package sysuser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
sysRoleModel "ems.agt/features/sys_role/model"
|
||||||
|
sysRoleService "ems.agt/features/sys_role/service"
|
||||||
|
sysUserModel "ems.agt/features/sys_user/model"
|
||||||
|
"ems.agt/features/sys_user/service"
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/midware"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 用户接口添加到路由
|
||||||
|
func Routers() []services.RouterItem {
|
||||||
|
// 实例化控制层 SysUserApi 结构体
|
||||||
|
var apis = &SysUserApi{
|
||||||
|
sysUserService: service.NewServiceSysUser,
|
||||||
|
sysRoleService: sysRoleService.NewServiceSysRole,
|
||||||
|
}
|
||||||
|
|
||||||
|
rs := [...]services.RouterItem{
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/users",
|
||||||
|
Handler: apis.List,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "GET",
|
||||||
|
Pattern: "/user/{userId}",
|
||||||
|
Handler: apis.Info,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "POST",
|
||||||
|
Pattern: "/user",
|
||||||
|
Handler: apis.Add,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "PUT",
|
||||||
|
Pattern: "/user",
|
||||||
|
Handler: apis.Edit,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: "DELETE",
|
||||||
|
Pattern: "/user/{userIds}",
|
||||||
|
Handler: apis.Remove,
|
||||||
|
Middleware: midware.Authorize(nil),
|
||||||
|
},
|
||||||
|
// 添加更多的 Router 对象...
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成两组前缀路由
|
||||||
|
rsPrefix := []services.RouterItem{}
|
||||||
|
for _, v := range rs {
|
||||||
|
path := "/userManage/{apiVersion}" + v.Pattern
|
||||||
|
// 固定前缀
|
||||||
|
v.Pattern = config.DefaultUriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
// 可配置
|
||||||
|
v.Pattern = config.UriPrefix + path
|
||||||
|
rsPrefix = append(rsPrefix, v)
|
||||||
|
}
|
||||||
|
return rsPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 实例化控制层 SysUserApi 结构体
|
||||||
|
// var NewSysUser = &SysUserApi{
|
||||||
|
// sysUserService: service.NewSysUserImpl,
|
||||||
|
// sysRoleService: service.NewSysRoleImpl,
|
||||||
|
// sysPostService: service.NewSysPostImpl,
|
||||||
|
// sysDictDataService: service.NewSysDictDataImpl,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
//
|
||||||
|
// PATH /system/user
|
||||||
|
type SysUserApi struct {
|
||||||
|
// 用户服务
|
||||||
|
sysUserService *service.ServiceSysUser
|
||||||
|
// 角色服务
|
||||||
|
sysRoleService *sysRoleService.ServiceSysRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息列表
|
||||||
|
//
|
||||||
|
// GET /list
|
||||||
|
func (s *SysUserApi) List(w http.ResponseWriter, r *http.Request) {
|
||||||
|
querys := ctx.QueryMap(r)
|
||||||
|
data := s.sysUserService.SelectUserPage(querys)
|
||||||
|
ctx.JSON(w, 200, result.Ok(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息详情
|
||||||
|
//
|
||||||
|
// GET /:userId
|
||||||
|
func (s *SysUserApi) Info(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userId := ctx.Param(r, "userId")
|
||||||
|
if userId == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 查询系统角色列表
|
||||||
|
roles := s.sysRoleService.SelectRoleList(sysRoleModel.SysRole{})
|
||||||
|
|
||||||
|
// 不是系统指定管理员需要排除其角色
|
||||||
|
if !conf.IsAdmin(userId) {
|
||||||
|
rolesFilter := make([]sysRoleModel.SysRole, 0)
|
||||||
|
for _, r := range roles {
|
||||||
|
if r.RoleID != "1" {
|
||||||
|
rolesFilter = append(rolesFilter, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roles = rolesFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增用户时,用户ID为0
|
||||||
|
if userId == "0" {
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"user": map[string]any{},
|
||||||
|
"roleIds": []string{},
|
||||||
|
"roles": roles,
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查用户是否存在
|
||||||
|
user := s.sysUserService.SelectUserById(userId)
|
||||||
|
if user.Id != userId {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问用户数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色ID组
|
||||||
|
roleIds := make([]string, 0)
|
||||||
|
for _, r := range user.Roles {
|
||||||
|
roleIds = append(roleIds, r.RoleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"user": user,
|
||||||
|
"roleIds": roleIds,
|
||||||
|
"roles": roles,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息新增
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysUserApi) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body sysUserModel.SysUser
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.Id != "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查用户登录账号是否唯一
|
||||||
|
uniqueUserName := s.sysUserService.CheckUniqueUserName(body.AccountId, "")
|
||||||
|
if !uniqueUserName {
|
||||||
|
msg := fmt.Sprintf("新增用户【%s】失败,登录账号已存在", body.AccountId)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
insertId := s.sysUserService.InsertUser(body)
|
||||||
|
if insertId != "" {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息修改
|
||||||
|
//
|
||||||
|
// POST /
|
||||||
|
func (s *SysUserApi) Edit(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body sysUserModel.SysUser
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.Id == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否管理员用户
|
||||||
|
// if conf.IsAdmin(body.Id) {
|
||||||
|
// ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员用户"))
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
user := s.sysUserService.SelectUserById(body.Id)
|
||||||
|
if user.Id != body.Id {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问用户数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查用户登录账号是否唯一
|
||||||
|
uniqueUserName := s.sysUserService.CheckUniqueUserName(body.AccountId, body.Id)
|
||||||
|
if !uniqueUserName {
|
||||||
|
msg := fmt.Sprintf("修改用户【%s】失败,登录账号已存在", body.AccountId)
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(msg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body.AccountId = "" // 忽略修改登录用户名称
|
||||||
|
// body.Password = "" // 忽略修改密码
|
||||||
|
rows := s.sysUserService.UpdateUserAndRolePost(body)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息删除
|
||||||
|
//
|
||||||
|
// DELETE /:userIds
|
||||||
|
func (s *SysUserApi) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userIds := ctx.Param(r, "userIds")
|
||||||
|
if userIds == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 处理字符转id数组后去重
|
||||||
|
ids := strings.Split(userIds, ",")
|
||||||
|
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||||
|
if len(uniqueIDs) <= 0 {
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rows, err := s.sysUserService.DeleteUserByIds(uniqueIDs)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("删除成功:%d", rows)
|
||||||
|
ctx.JSON(w, 200, result.OkMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户重置密码
|
||||||
|
//
|
||||||
|
// PUT /resetPwd
|
||||||
|
func (s *SysUserApi) ResetPwd(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
UserID string `json:"userId" binding:"required"`
|
||||||
|
Password string `json:"password" binding:"required"`
|
||||||
|
}
|
||||||
|
if err := ctx.ShouldBindJSON(r, &body); err != nil {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否管理员用户
|
||||||
|
if conf.IsAdmin(body.UserID) {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员用户"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user := s.sysUserService.SelectUserById(body.UserID)
|
||||||
|
if user.Id != body.UserID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问用户数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SysUserApi := sysUserModel.SysUser{
|
||||||
|
Id: body.UserID,
|
||||||
|
Password: body.Password,
|
||||||
|
}
|
||||||
|
rows := s.sysUserService.UpdateUser(SysUserApi)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户状态修改
|
||||||
|
//
|
||||||
|
// PUT /changeStatus
|
||||||
|
func (s *SysUserApi) Status(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
UserID string `json:"userId" binding:"required"`
|
||||||
|
Status string `json:"status" binding:"required"`
|
||||||
|
}
|
||||||
|
if err := ctx.ShouldBindJSON(r, &body); err != nil {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否存在
|
||||||
|
user := s.sysUserService.SelectUserById(body.UserID)
|
||||||
|
if user.Id != body.UserID {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("没有权限访问用户数据!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 与旧值相等不变更
|
||||||
|
if user.Status == body.Status {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("变更状态与旧值相等!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SysUserApi := sysUserModel.SysUser{
|
||||||
|
Id: body.UserID,
|
||||||
|
Status: body.Status,
|
||||||
|
}
|
||||||
|
rows := s.sysUserService.UpdateUser(SysUserApi)
|
||||||
|
if rows > 0 {
|
||||||
|
ctx.JSON(w, 200, result.Ok(nil))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.Err(nil))
|
||||||
|
}
|
||||||
42
features/sys_user/model/sys_user.go
Normal file
42
features/sys_user/model/sys_user.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "ems.agt/features/sys_role/model"
|
||||||
|
|
||||||
|
type SysUser struct {
|
||||||
|
Id string `json:"id" xorm:"pk 'id' autoincr"`
|
||||||
|
AccountId string `json:"accountId" xorm:"account_id"`
|
||||||
|
Name string `json:"name" xorm:"name"`
|
||||||
|
Sn string `json:"sn"`
|
||||||
|
Gender string `json:"gender"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
TelephoneNumber string `json:"telephoneNumber" xorm:"telephone_number"`
|
||||||
|
Mobile string `json:"mobile"`
|
||||||
|
Email string `json:"email" xorm:"email"`
|
||||||
|
StartTime string `json:"startTime" xorm:"start_time"`
|
||||||
|
EndTime string `json:"endTime" xorm:"end_time"`
|
||||||
|
IdCardNumber string `json:"idCardNumber"`
|
||||||
|
EmployeeNumber string `json:"employeeNumber"`
|
||||||
|
Organize string `json:"organize"`
|
||||||
|
EmployeeType string `json:"employeeType"`
|
||||||
|
SupporterCorpName string `json:"supporterCorpName"`
|
||||||
|
RealName string `json:"realName" xorm:"real_name"`
|
||||||
|
Password string `json:"password" xorm:"-"`
|
||||||
|
PasswordSha512 string `json:"-" xorm:"-"`
|
||||||
|
ChangePasswordFlag int `json:"changePasswordFlag"`
|
||||||
|
PasswordExpiration string `json:"passwordExpiration" xorm:"password_expiration"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
UserExpiration string `json:"userExpiration" xorm:"user_expiration"`
|
||||||
|
GroupName string `json:"groupName" xorm:"group_name"`
|
||||||
|
Profile string `json:"-" xorm:"profile"`
|
||||||
|
Phone string `json:"phone" xorm:"phone"`
|
||||||
|
CreateTime string `json:"createTime" xorm:"create_time"`
|
||||||
|
UpdateTime string `json:"updateTime" xorm:"update_time"`
|
||||||
|
Unit string `json:"unit" xorm:"unit"`
|
||||||
|
|
||||||
|
// 角色对象组
|
||||||
|
Roles []model.SysRole `json:"roles"`
|
||||||
|
// 角色ID - 参数提交绑定
|
||||||
|
RoleID string `json:"roleId,omitempty"`
|
||||||
|
// 角色组 - 参数提交绑定
|
||||||
|
RoleIDs []string `json:"roleIds,omitempty"`
|
||||||
|
}
|
||||||
578
features/sys_user/service/repo_sys_user.go
Normal file
578
features/sys_user/service/repo_sys_user.go
Normal file
@@ -0,0 +1,578 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sysRoleModel "ems.agt/features/sys_role/model"
|
||||||
|
sysUserModel "ems.agt/features/sys_user/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/crypto"
|
||||||
|
"ems.agt/lib/core/utils/date"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysUser 结构体
|
||||||
|
var NewRepoSysUser = &RepoSysUser{
|
||||||
|
selectSql: `select u.id,
|
||||||
|
u.account_id, u.name, u.sn, u.gender, u.description, u.telephone_number, u.mobile, u.email,
|
||||||
|
u.start_time, u.end_time, u.id_card_number, u.employee_number,
|
||||||
|
u.organize, u.employee_type, u.supporter_corp_name, u.real_name, u.password, u.password_sha512,
|
||||||
|
u.change_password_flag,u.password_expiration, u.status, u.user_expiration, u.group_name,
|
||||||
|
u.profile, u.phone, u.create_time, u.update_time, u.unit,
|
||||||
|
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
|
||||||
|
from user u
|
||||||
|
left join sys_user_role ur on u.id = ur.user_id
|
||||||
|
left join sys_role r on r.role_id = ur.role_id`,
|
||||||
|
|
||||||
|
sysUserMap: map[string]string{
|
||||||
|
"id": "Id",
|
||||||
|
"account_id": "AccountId",
|
||||||
|
"name": "Name",
|
||||||
|
"sn": "Sn",
|
||||||
|
"gender": "Gender",
|
||||||
|
"description": "Description",
|
||||||
|
"telephone_number": "TelephoneNumber",
|
||||||
|
"mobile": "Mobile",
|
||||||
|
"email": "Email",
|
||||||
|
"start_time": "StartTime",
|
||||||
|
"end_time": "EndTime",
|
||||||
|
"id_card_number": "IdCardNumber",
|
||||||
|
"employee_number": "EmployeeNumber",
|
||||||
|
"organize": "Organize",
|
||||||
|
"employee_type": "EmployeeType",
|
||||||
|
"supporter_corp_name": "SupporterCorpName",
|
||||||
|
"real_name": "RealName",
|
||||||
|
"password": "Password",
|
||||||
|
"password_sha512": "PasswordSha512",
|
||||||
|
"change_password_flag": "ChangePasswordFlag",
|
||||||
|
"password_expiration": "PasswordExpiration",
|
||||||
|
"status": "Status",
|
||||||
|
"user_expiration": "UserExpiration",
|
||||||
|
"group_name": "GroupName",
|
||||||
|
"profile": "Profile",
|
||||||
|
"phone": "Phone",
|
||||||
|
"create_time": "CreateTime",
|
||||||
|
"update_time": "UpdateTime",
|
||||||
|
"unit": "Unit",
|
||||||
|
},
|
||||||
|
|
||||||
|
sysRoleMap: map[string]string{
|
||||||
|
"role_id": "RoleID",
|
||||||
|
"role_name": "RoleName",
|
||||||
|
"role_key": "RoleKey",
|
||||||
|
"role_sort": "RoleSort",
|
||||||
|
"data_scope": "DataScope",
|
||||||
|
"role_status": "Status",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoSysUser 用户表 数据层处理
|
||||||
|
type RepoSysUser struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 用户信息实体映射
|
||||||
|
sysUserMap map[string]string
|
||||||
|
// 用户角色实体映射 一对多
|
||||||
|
sysRoleMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoSysUser) convertResultRows(rows []map[string]any) []sysUserModel.SysUser {
|
||||||
|
arr := make([]sysUserModel.SysUser, 0)
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
sysUser := sysUserModel.SysUser{}
|
||||||
|
sysRole := sysRoleModel.SysRole{}
|
||||||
|
sysUser.Roles = []sysRoleModel.SysRole{}
|
||||||
|
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.sysUserMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysUser, keyMapper, value)
|
||||||
|
}
|
||||||
|
if keyMapper, ok := r.sysRoleMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&sysRole, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sysRole.RoleKey != "" {
|
||||||
|
sysUser.Roles = append(sysUser.Roles, sysRole)
|
||||||
|
}
|
||||||
|
|
||||||
|
one := true
|
||||||
|
for i, a := range arr {
|
||||||
|
if a.Id == sysUser.Id {
|
||||||
|
arrUser := &arr[i]
|
||||||
|
arrUser.Roles = append(arrUser.Roles, sysUser.Roles...)
|
||||||
|
one = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if one {
|
||||||
|
arr = append(arr, sysUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserPage 根据条件分页查询用户列表
|
||||||
|
func (r *RepoSysUser) SelectUserPage(query map[string]any) map[string]any {
|
||||||
|
selectUserSql := `select u.id,
|
||||||
|
u.account_id, u.name, u.sn, u.gender, u.description, u.telephone_number, u.mobile, u.email,
|
||||||
|
u.start_time, u.end_time, u.id_card_number, u.employee_number,
|
||||||
|
u.organize, u.employee_type, u.supporter_corp_name, u.real_name,
|
||||||
|
u.change_password_flag,u.password_expiration, u.status, u.user_expiration, u.group_name,
|
||||||
|
u.profile, u.phone, u.create_time, u.update_time, u.unit
|
||||||
|
from user u`
|
||||||
|
selectUserTotalSql := `select count(distinct u.id) as 'total' from user u`
|
||||||
|
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["accountId"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.account_id = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["name"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.name concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["status"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.status = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["phonenumber"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.phonenumber like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
beginTime, ok := query["beginTime"]
|
||||||
|
if !ok {
|
||||||
|
beginTime, ok = query["params[beginTime]"]
|
||||||
|
}
|
||||||
|
if ok && beginTime != "" {
|
||||||
|
conditions = append(conditions, "u.login_date >= ?")
|
||||||
|
beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, beginDate.UnixMilli())
|
||||||
|
}
|
||||||
|
endTime, ok := query["endTime"]
|
||||||
|
if !ok {
|
||||||
|
endTime, ok = query["params[endTime]"]
|
||||||
|
}
|
||||||
|
if ok && endTime != "" {
|
||||||
|
conditions = append(conditions, "u.login_date <= ?")
|
||||||
|
endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD)
|
||||||
|
params = append(params, endDate.UnixMilli())
|
||||||
|
}
|
||||||
|
if v, ok := query["deptId"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "(u.dept_id = ? or u.dept_id in ( select t.dept_id from sys_dept t where find_in_set(?, ancestors) ))")
|
||||||
|
params = append(params, v)
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := selectUserTotalSql + whereSql
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": []sysUserModel.SysUser{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
|
||||||
|
pageSql := " limit ?,? "
|
||||||
|
params = append(params, pageNum*pageSize)
|
||||||
|
params = append(params, pageSize)
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := selectUserSql + whereSql + pageSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectAllocatedPage 根据条件分页查询分配用户角色列表
|
||||||
|
func (r *RepoSysUser) SelectAllocatedPage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["name"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.name like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["phone"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.phone like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["status"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "u.status = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
// 分配角色用户
|
||||||
|
if allocated, ok := query["allocated"]; ok && allocated != "" {
|
||||||
|
if roleId, ok := query["roleId"]; ok && roleId != "" {
|
||||||
|
if parse.Boolean(allocated) {
|
||||||
|
conditions = append(conditions, "r.role_id = ?")
|
||||||
|
params = append(params, roleId)
|
||||||
|
} else {
|
||||||
|
conditions = append(conditions, `(r.role_id != ? or r.role_id IS NULL)
|
||||||
|
and u.id not in (
|
||||||
|
select u.id from user u
|
||||||
|
inner join sys_user_role ur on u.id = ur.user_id
|
||||||
|
and ur.role_id = ?
|
||||||
|
)`)
|
||||||
|
params = append(params, roleId)
|
||||||
|
params = append(params, roleId)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := `select count(distinct u.id) as 'total' from user u
|
||||||
|
left join sys_user_role ur on u.id = ur.user_id
|
||||||
|
left join sys_role r on r.role_id = ur.role_id`
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": []sysUserModel.SysUser{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
|
||||||
|
pageSql := " limit ?,? "
|
||||||
|
params = append(params, pageNum*pageSize)
|
||||||
|
params = append(params, pageSize)
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := `select distinct
|
||||||
|
u.id, u.account_id, u.name, u.gender, u.email,
|
||||||
|
u.phone, u.status, u.create_time, u.real_name
|
||||||
|
from user u
|
||||||
|
left join sys_user_role ur on u.id = ur.user_id
|
||||||
|
left join sys_role r on r.role_id = ur.role_id`
|
||||||
|
querySql = querySql + whereSql + pageSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
return map[string]any{
|
||||||
|
"total": total,
|
||||||
|
"rows": rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserList 根据条件查询用户列表
|
||||||
|
func (r *RepoSysUser) SelectUserList(sysUser sysUserModel.SysUser, dataScopeSQL string) []sysUserModel.SysUser {
|
||||||
|
selectUserSql := `select
|
||||||
|
u.id, u.account_id, u.name, u.real_name, u.email, u.gender, u.phone, u.create_time, u.status, u.description
|
||||||
|
from user u`
|
||||||
|
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysUser.AccountId != "" {
|
||||||
|
conditions = append(conditions, "u.account_id = ?")
|
||||||
|
params = append(params, sysUser.AccountId)
|
||||||
|
}
|
||||||
|
if sysUser.Name != "" {
|
||||||
|
conditions = append(conditions, "u.name like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, sysUser.Name)
|
||||||
|
}
|
||||||
|
if sysUser.Status != "" {
|
||||||
|
conditions = append(conditions, "u.status = ?")
|
||||||
|
params = append(params, sysUser.Status)
|
||||||
|
}
|
||||||
|
if sysUser.Phone != "" {
|
||||||
|
conditions = append(conditions, "u.phone like concat('%', concat(?, '%'))")
|
||||||
|
params = append(params, sysUser.Phone)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := selectUserSql + whereSql + dataScopeSQL
|
||||||
|
rows, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
return r.convertResultRows(rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserByIds 通过用户ID查询用户
|
||||||
|
func (r *RepoSysUser) SelectUserByIds(userIds []string) []sysUserModel.SysUser {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
|
||||||
|
querySql := r.selectSql + " where u.id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(userIds)
|
||||||
|
results, err := datasource.RawDB("", querySql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return []sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserByUserName 通过用户登录账号查询用户
|
||||||
|
func (r *RepoSysUser) SelectUserByUserName(userName string) sysUserModel.SysUser {
|
||||||
|
querySql := r.selectSql + " where u.name = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{userName})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
// 转换实体
|
||||||
|
rows := r.convertResultRows(results)
|
||||||
|
if len(rows) > 0 {
|
||||||
|
return rows[0]
|
||||||
|
}
|
||||||
|
return sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertUser 新增用户信息
|
||||||
|
func (r *RepoSysUser) InsertUser(sysUser sysUserModel.SysUser) string {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysUser.AccountId != "" {
|
||||||
|
params["account_id"] = sysUser.AccountId
|
||||||
|
}
|
||||||
|
if sysUser.Name != "" {
|
||||||
|
params["name"] = sysUser.Name
|
||||||
|
}
|
||||||
|
if sysUser.Sn != "" {
|
||||||
|
params["sn"] = sysUser.Sn
|
||||||
|
} else {
|
||||||
|
params["sn"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.RealName != "" {
|
||||||
|
params["real_name"] = sysUser.RealName
|
||||||
|
} else {
|
||||||
|
params["real_name"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.Gender != "" {
|
||||||
|
params["gender"] = sysUser.Gender
|
||||||
|
}
|
||||||
|
if sysUser.Email != "" {
|
||||||
|
params["email"] = sysUser.Email
|
||||||
|
} else {
|
||||||
|
params["email"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.Phone != "" {
|
||||||
|
params["phone"] = sysUser.Phone
|
||||||
|
} else {
|
||||||
|
params["phone"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.Unit != "" {
|
||||||
|
params["unit"] = sysUser.Unit
|
||||||
|
} else {
|
||||||
|
params["unit"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if sysUser.Organize != "" {
|
||||||
|
params["organize"] = sysUser.Organize
|
||||||
|
}
|
||||||
|
if sysUser.Password != "" {
|
||||||
|
password := crypto.BcryptHash(sysUser.Password)
|
||||||
|
params["password"] = password
|
||||||
|
}
|
||||||
|
if sysUser.Status != "" {
|
||||||
|
params["status"] = sysUser.Status
|
||||||
|
}
|
||||||
|
if sysUser.PasswordExpiration != "" {
|
||||||
|
params["password_expiration"] = sysUser.PasswordExpiration
|
||||||
|
}
|
||||||
|
if sysUser.UserExpiration != "" {
|
||||||
|
params["user_expiration"] = sysUser.UserExpiration
|
||||||
|
}
|
||||||
|
if sysUser.GroupName != "" {
|
||||||
|
params["group_name"] = sysUser.GroupName
|
||||||
|
}
|
||||||
|
params["create_time"] = time.Now()
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params)
|
||||||
|
sql := "insert into user (" + strings.Join(keys, ",") + ")values(" + placeholder + ")"
|
||||||
|
|
||||||
|
// 执行插入
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
insertId, err := results.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("insert row : %v", err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprint(insertId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUser 修改用户信息
|
||||||
|
func (r *RepoSysUser) UpdateUser(sysUser sysUserModel.SysUser) int64 {
|
||||||
|
// 参数拼接
|
||||||
|
params := make(map[string]any)
|
||||||
|
if sysUser.Name != "" {
|
||||||
|
params["name"] = sysUser.Name
|
||||||
|
}
|
||||||
|
if sysUser.Sn != "" {
|
||||||
|
params["sn"] = sysUser.Sn
|
||||||
|
} else {
|
||||||
|
params["sn"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.RealName != "" {
|
||||||
|
params["real_name"] = sysUser.RealName
|
||||||
|
} else {
|
||||||
|
params["real_name"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.Gender != "" {
|
||||||
|
params["gender"] = sysUser.Gender
|
||||||
|
}
|
||||||
|
if sysUser.Email != "" {
|
||||||
|
params["email"] = sysUser.Email
|
||||||
|
} else {
|
||||||
|
params["email"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.Phone != "" {
|
||||||
|
params["phone"] = sysUser.Phone
|
||||||
|
} else {
|
||||||
|
params["phone"] = ""
|
||||||
|
}
|
||||||
|
if sysUser.Unit != "" {
|
||||||
|
params["unit"] = sysUser.Unit
|
||||||
|
} else {
|
||||||
|
params["unit"] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if sysUser.Organize != "" {
|
||||||
|
params["organize"] = sysUser.Organize
|
||||||
|
}
|
||||||
|
if sysUser.Password != "" {
|
||||||
|
password := crypto.BcryptHash(sysUser.Password)
|
||||||
|
params["password"] = password
|
||||||
|
}
|
||||||
|
if sysUser.Status != "" {
|
||||||
|
params["status"] = sysUser.Status
|
||||||
|
}
|
||||||
|
if sysUser.PasswordExpiration != "" {
|
||||||
|
params["password_expiration"] = sysUser.PasswordExpiration
|
||||||
|
}
|
||||||
|
if sysUser.UserExpiration != "" {
|
||||||
|
params["user_expiration"] = sysUser.UserExpiration
|
||||||
|
}
|
||||||
|
if sysUser.GroupName != "" {
|
||||||
|
params["group_name"] = sysUser.GroupName
|
||||||
|
}
|
||||||
|
params["update_time"] = time.Now()
|
||||||
|
|
||||||
|
// 构建执行语句
|
||||||
|
keys, values := datasource.KeyValueByUpdate(params)
|
||||||
|
sql := "update user set " + strings.Join(keys, ",") + " where id = ?"
|
||||||
|
|
||||||
|
// 执行更新
|
||||||
|
values = append(values, sysUser.Id)
|
||||||
|
results, err := datasource.ExecDB("", sql, values)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update row : %v", err.Error())
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("update err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserByIds 批量删除用户信息
|
||||||
|
func (r *RepoSysUser) DeleteUserByIds(userIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
|
||||||
|
sql := "delete from user where id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(userIds)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueUser 校验用户信息是否唯一
|
||||||
|
func (r *RepoSysUser) CheckUniqueUser(sysUser sysUserModel.SysUser) string {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if sysUser.Name != "" {
|
||||||
|
conditions = append(conditions, "name = ?")
|
||||||
|
params = append(params, sysUser.Name)
|
||||||
|
}
|
||||||
|
if sysUser.AccountId != "" {
|
||||||
|
conditions = append(conditions, "account_id = ?")
|
||||||
|
params = append(params, sysUser.AccountId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := "select id as 'str' from user " + whereSql + " limit 1"
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err %v", err)
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return fmt.Sprintf("%v", results[0]["str"])
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
150
features/sys_user/service/service_sys_user.go
Normal file
150
features/sys_user/service/service_sys_user.go
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sysUserModel "ems.agt/features/sys_user/model"
|
||||||
|
sysuserrole "ems.agt/features/sys_user_role"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceSysUser 结构体
|
||||||
|
var NewServiceSysUser = &ServiceSysUser{
|
||||||
|
sysUserRepository: NewRepoSysUser,
|
||||||
|
sysUserRoleRepository: sysuserrole.NewRepoSysUserRole,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceSysUser 用户 服务层处理
|
||||||
|
type ServiceSysUser struct {
|
||||||
|
// 用户服务
|
||||||
|
sysUserRepository *RepoSysUser
|
||||||
|
// 用户与角色服务
|
||||||
|
sysUserRoleRepository *sysuserrole.RepoSysUserRole
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserPage 根据条件分页查询用户列表
|
||||||
|
func (r *ServiceSysUser) SelectUserPage(query map[string]any) map[string]any {
|
||||||
|
return r.sysUserRepository.SelectUserPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserList 根据条件查询用户列表
|
||||||
|
func (r *ServiceSysUser) SelectUserList(sysUser sysUserModel.SysUser) []sysUserModel.SysUser {
|
||||||
|
return []sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectAllocatedPage 根据条件分页查询分配用户角色列表
|
||||||
|
func (r *ServiceSysUser) SelectAllocatedPage(query map[string]any) map[string]any {
|
||||||
|
return r.sysUserRepository.SelectAllocatedPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserByUserName 通过用户名查询用户
|
||||||
|
func (r *ServiceSysUser) SelectUserByUserName(userName string) sysUserModel.SysUser {
|
||||||
|
return r.sysUserRepository.SelectUserByUserName(userName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectUserById 通过用户ID查询用户
|
||||||
|
func (r *ServiceSysUser) SelectUserById(userId string) sysUserModel.SysUser {
|
||||||
|
if userId == "" {
|
||||||
|
return sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
users := r.sysUserRepository.SelectUserByIds([]string{userId})
|
||||||
|
if len(users) > 0 {
|
||||||
|
return users[0]
|
||||||
|
}
|
||||||
|
return sysUserModel.SysUser{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertUser 新增用户信息
|
||||||
|
func (r *ServiceSysUser) InsertUser(sysUser sysUserModel.SysUser) string {
|
||||||
|
// 新增用户信息
|
||||||
|
insertId := r.sysUserRepository.InsertUser(sysUser)
|
||||||
|
if insertId != "" {
|
||||||
|
// 新增用户角色信息
|
||||||
|
r.insertUserRole(insertId, sysUser.RoleIDs)
|
||||||
|
}
|
||||||
|
return insertId
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertUserRole 新增用户角色信息
|
||||||
|
func (r *ServiceSysUser) insertUserRole(userId string, roleIds []string) int64 {
|
||||||
|
if userId == "" || len(roleIds) <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
sysUserRoles := []sysuserrole.SysUserRole{}
|
||||||
|
for _, roleId := range roleIds {
|
||||||
|
// 管理员角色禁止操作,只能通过配置指定用户ID分配
|
||||||
|
if roleId == "" || roleId == "1" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sysUserRoles = append(sysUserRoles, sysuserrole.NewSysUserRole(userId, roleId))
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.sysUserRoleRepository.BatchUserRole(sysUserRoles)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUser 修改用户信息
|
||||||
|
func (r *ServiceSysUser) UpdateUser(sysUser sysUserModel.SysUser) int64 {
|
||||||
|
return r.sysUserRepository.UpdateUser(sysUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserAndRolePost 修改用户信息同时更新角色和岗位
|
||||||
|
func (r *ServiceSysUser) UpdateUserAndRolePost(sysUser sysUserModel.SysUser) int64 {
|
||||||
|
userId := fmt.Sprint(sysUser.Id)
|
||||||
|
// 删除用户与角色关联
|
||||||
|
r.sysUserRoleRepository.DeleteUserRole([]string{userId})
|
||||||
|
// 新增用户角色信息
|
||||||
|
r.insertUserRole(userId, sysUser.RoleIDs)
|
||||||
|
return r.sysUserRepository.UpdateUser(sysUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserByIds 批量删除用户信息
|
||||||
|
func (r *ServiceSysUser) DeleteUserByIds(userIds []string) (int64, error) {
|
||||||
|
// 检查是否存在
|
||||||
|
users := r.sysUserRepository.SelectUserByIds(userIds)
|
||||||
|
if len(users) <= 0 {
|
||||||
|
return 0, errors.New("没有权限访问用户数据!")
|
||||||
|
}
|
||||||
|
if len(users) == len(userIds) {
|
||||||
|
// 删除用户与角色关联
|
||||||
|
r.sysUserRoleRepository.DeleteUserRole(userIds)
|
||||||
|
// ... 注意其他userId进行关联的表
|
||||||
|
// 删除用户
|
||||||
|
rows := r.sysUserRepository.DeleteUserByIds(userIds)
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("删除用户信息失败!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueUserName 校验用户名称是否唯一
|
||||||
|
func (r *ServiceSysUser) CheckUniqueUserName(accountId, userId string) bool {
|
||||||
|
uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{
|
||||||
|
AccountId: accountId,
|
||||||
|
})
|
||||||
|
if uniqueId == userId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniquePhone 校验手机号码是否唯一
|
||||||
|
func (r *ServiceSysUser) CheckUniquePhone(phonenumber, userId string) bool {
|
||||||
|
uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{
|
||||||
|
Phone: phonenumber,
|
||||||
|
})
|
||||||
|
if uniqueId == userId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUniqueEmail 校验email是否唯一
|
||||||
|
func (r *ServiceSysUser) CheckUniqueEmail(email, userId string) bool {
|
||||||
|
uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{
|
||||||
|
Email: email,
|
||||||
|
})
|
||||||
|
if uniqueId == userId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return uniqueId == ""
|
||||||
|
}
|
||||||
15
features/sys_user_role/model_sys_user_role.go
Normal file
15
features/sys_user_role/model_sys_user_role.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package sysuserrole
|
||||||
|
|
||||||
|
// SysUserRole 用户和角色关联对象 sys_user_role
|
||||||
|
type SysUserRole struct {
|
||||||
|
UserID string `json:"userId"` // 用户ID
|
||||||
|
RoleID string `json:"roleId"` // 角色ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSysUserRole 创建用户和角色关联对象的构造函数
|
||||||
|
func NewSysUserRole(userID string, roleID string) SysUserRole {
|
||||||
|
return SysUserRole{
|
||||||
|
UserID: userID,
|
||||||
|
RoleID: roleID,
|
||||||
|
}
|
||||||
|
}
|
||||||
87
features/sys_user_role/repo_sys_user_role.go
Normal file
87
features/sys_user_role/repo_sys_user_role.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package sysuserrole
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoSysUserRole 结构体
|
||||||
|
var NewRepoSysUserRole = &RepoSysUserRole{}
|
||||||
|
|
||||||
|
// RepoSysUserRole 用户与角色关联表 数据层处理
|
||||||
|
type RepoSysUserRole struct{}
|
||||||
|
|
||||||
|
// CountUserRoleByRoleId 通过角色ID查询角色使用数量
|
||||||
|
func (r *RepoSysUserRole) CountUserRoleByRoleId(roleId string) int64 {
|
||||||
|
querySql := "select count(1) as total from sys_user_role where role_id = ?"
|
||||||
|
results, err := datasource.RawDB("", querySql, []any{roleId})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
return parse.Number(results[0]["total"])
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchUserRole 批量新增用户角色信息
|
||||||
|
func (r *RepoSysUserRole) BatchUserRole(sysUserRoles []SysUserRole) int64 {
|
||||||
|
keyValues := make([]string, 0)
|
||||||
|
for _, item := range sysUserRoles {
|
||||||
|
keyValues = append(keyValues, fmt.Sprintf("(%s,%s)", item.UserID, item.RoleID))
|
||||||
|
}
|
||||||
|
sql := "insert into sys_user_role(user_id, role_id) values " + strings.Join(keyValues, ",")
|
||||||
|
results, err := datasource.ExecDB("", sql, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserRole 批量删除用户和角色关联
|
||||||
|
func (r *RepoSysUserRole) DeleteUserRole(userIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
|
||||||
|
sql := "delete from sys_user_role where user_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(userIds)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUserRoleByRoleId 批量取消授权用户角色
|
||||||
|
func (r *RepoSysUserRole) DeleteUserRoleByRoleId(roleId string, userIds []string) int64 {
|
||||||
|
placeholder := datasource.KeyPlaceholderByQuery(len(userIds))
|
||||||
|
sql := "delete from sys_user_role where role_id= ? and user_id in (" + placeholder + ")"
|
||||||
|
parameters := datasource.ConvertIdsSlice(userIds)
|
||||||
|
parameters = append([]any{roleId}, parameters...)
|
||||||
|
results, err := datasource.ExecDB("", sql, parameters)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
affected, err := results.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("delete err => %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return affected
|
||||||
|
}
|
||||||
272
features/trace/tcpdump.go
Normal file
272
features/trace/tcpdump.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
package trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/cmd"
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/core/file"
|
||||||
|
"ems.agt/lib/core/utils/ctx"
|
||||||
|
"ems.agt/lib/core/vo/result"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriTcpdumpTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask"
|
||||||
|
CustomUriTcpdumpTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" // decode message api
|
||||||
|
|
||||||
|
UriTcpdumpPcapDownload = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload"
|
||||||
|
CustomUriTcpdumpPcapDownload = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" // decode message api
|
||||||
|
|
||||||
|
UriTcpdumpNeUPFTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask"
|
||||||
|
CustomUriTcpdumpNeUPFTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" // decode message api
|
||||||
|
)
|
||||||
|
|
||||||
|
// NeInfo 网元信息
|
||||||
|
func NeInfo(neType, neId string) (*dborm.NeInfo, error) {
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("dborm.XormGetNeInfo is failed:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if neInfo == nil || neInfo.Ip == "" {
|
||||||
|
return nil, fmt.Errorf("not ne_info or not IP")
|
||||||
|
}
|
||||||
|
return neInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TcpdumpNeTask 网元发送执行 pcap
|
||||||
|
func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
NeType string `json:"neType"` // 网元类型
|
||||||
|
NeId string `json:"neId"` // 网元ID
|
||||||
|
Timeout int `json:"timeout"` // 超时时间
|
||||||
|
Cmd string `json:"cmd"` // 命令
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.NeType == "" || body.NeId == "" || body.Timeout < 5 || body.Cmd == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo, err := NeInfo(body.NeType, body.NeId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli())
|
||||||
|
fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli())
|
||||||
|
writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127
|
||||||
|
cmdStr := fmt.Sprintf("cd /tmp \ntimeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName)
|
||||||
|
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
|
||||||
|
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"cmd": cmdStr,
|
||||||
|
"msg": msg,
|
||||||
|
"fileName": filePcapName,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TcpdumpPcapDownload 网元抓包pcap文件下载
|
||||||
|
func TcpdumpPcapDownload(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
NeType string `json:"neType"` // 网元类型
|
||||||
|
NeId string `json:"neId"` // 网元ID
|
||||||
|
FileName string `json:"fileName"` // 文件名
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.NeType == "" || body.NeId == "" || body.FileName == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo, err := NeInfo(body.NeType, body.NeId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nePath := fmt.Sprintf("/tmp/%s", body.FileName)
|
||||||
|
localPath := fmt.Sprintf("%s/tcpdump/pcap/%s", conf.Get("ne.omcdir"), body.FileName)
|
||||||
|
err = file.FileSCPNeToLocal(neInfo.Ip, nePath, localPath)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.FileAttachment(w, r, localPath, body.FileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TcpdumpNeUPFTask 网元UPF发送执行 pcap
|
||||||
|
func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var body struct {
|
||||||
|
NeType string `json:"neType"` // 网元类型
|
||||||
|
NeId string `json:"neId"` // 网元ID
|
||||||
|
Cmd string `json:"cmd"` // 命令
|
||||||
|
RunType string `json:"runType"` // 执行开始start还是停止stop
|
||||||
|
}
|
||||||
|
err := ctx.ShouldBindJSON(r, &body)
|
||||||
|
if err != nil || body.NeType != "UPF" || body.NeId == "" || body.Cmd == "" {
|
||||||
|
ctx.JSON(w, 400, result.CodeMsg(400, "参数错误"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
neInfo, err := NeInfo(body.NeType, body.NeId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始
|
||||||
|
if body.RunType == "start" {
|
||||||
|
// 创建TCP连接
|
||||||
|
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002))
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
|
||||||
|
cmdStr := fmt.Sprintf("pcap dispatch trace on max 100000 file %s", filePcapName)
|
||||||
|
|
||||||
|
fmt.Fprintln(conn, cmdStr)
|
||||||
|
|
||||||
|
// 读取内容
|
||||||
|
time.Sleep(time.Duration(200) * time.Millisecond)
|
||||||
|
buf := make([]byte, 1024*8)
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
} else {
|
||||||
|
str := string(buf[0:n])
|
||||||
|
s := strings.Index(str, "pcap dispatch trace:")
|
||||||
|
if s != -1 {
|
||||||
|
e := strings.Index(str, "\r\nupfd1#")
|
||||||
|
str = str[s:e]
|
||||||
|
} else {
|
||||||
|
str = fmt.Sprintf("Executed, please stop before proceeding %d", n)
|
||||||
|
}
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"cmd": cmdStr,
|
||||||
|
"msg": str,
|
||||||
|
"fileName": filePcapName,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 停止
|
||||||
|
if body.RunType == "stop" {
|
||||||
|
// 创建TCP连接
|
||||||
|
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002))
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
|
||||||
|
cmdStr := "pcap dispatch trace off"
|
||||||
|
|
||||||
|
fmt.Fprintln(conn, cmdStr)
|
||||||
|
|
||||||
|
// 读取内容
|
||||||
|
time.Sleep(time.Duration(200) * time.Millisecond)
|
||||||
|
buf := make([]byte, 1024*8)
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
} else {
|
||||||
|
str := string(buf[0:n])
|
||||||
|
s := strings.Index(str, "pcap dispatch trace:")
|
||||||
|
if s == -1 {
|
||||||
|
s = strings.Index(str, "Write ")
|
||||||
|
}
|
||||||
|
if s != -1 {
|
||||||
|
e := strings.Index(str, "\r\nupfd1#")
|
||||||
|
str = str[s:e]
|
||||||
|
} else {
|
||||||
|
str = "No stoppable found"
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"cmd": cmdStr,
|
||||||
|
"msg": str,
|
||||||
|
"fileName": filePcapName,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始 -脚本
|
||||||
|
if body.RunType == "start2" {
|
||||||
|
fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
|
||||||
|
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
|
||||||
|
// 复制文件到网元上
|
||||||
|
err := file.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp")
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127
|
||||||
|
cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace on max 100000 file %s' %s ", fileLogName, writeLog)
|
||||||
|
|
||||||
|
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
|
||||||
|
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
} else {
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"cmd": cmdStr,
|
||||||
|
"msg": msg,
|
||||||
|
"fileName": filePcapName,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 停止 -脚本
|
||||||
|
if body.RunType == "stop2" {
|
||||||
|
fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId)
|
||||||
|
filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId)
|
||||||
|
// cmdStr := "cd /tmp \nexpect /tmp/cat.sh "
|
||||||
|
err := file.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\restagent\\backup\\upf_pcap", "/tmp")
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127
|
||||||
|
cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace off' %s ", writeLog)
|
||||||
|
|
||||||
|
usernameNe := conf.Get("ne.user").(string) // 网元统一用户
|
||||||
|
sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip)
|
||||||
|
msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg(err.Error()))
|
||||||
|
} else {
|
||||||
|
ctx.JSON(w, 200, result.OkData(map[string]any{
|
||||||
|
"cmd": cmdStr,
|
||||||
|
"msg": msg,
|
||||||
|
"fileName": filePcapName,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(w, 200, result.ErrMsg("runType is start or stop"))
|
||||||
|
}
|
||||||
437
features/trace/trace.go
Normal file
437
features/trace/trace.go
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
package trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/run"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriTraceTaskV1 = config.DefaultUriPrefix + "/traceManagement/v1/subscriptions"
|
||||||
|
UriTraceTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/subscriptions"
|
||||||
|
UriTraceRawMsg = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/rawMessage/{id}"
|
||||||
|
UriTraceDecMsg = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/decMessage/{id}" // decode message api
|
||||||
|
|
||||||
|
CustomUriTraceTaskV1 = config.UriPrefix + "/traceManagement/v1/subscriptions"
|
||||||
|
CustomUriTraceTask = config.UriPrefix + "/traceManagement/{apiVersion}/subscriptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TraceTask struct {
|
||||||
|
Id int `json:"id" xorm:"pk 'id' autoincr"`
|
||||||
|
TraceType string `json:"traceType"`
|
||||||
|
StartTime string `json:"startTime"`
|
||||||
|
EndTime string `json:"endTime"`
|
||||||
|
Imsi string `json:"imsi"`
|
||||||
|
Msisdn string `json:"msisdn"`
|
||||||
|
SrcIp string `json:"srcIp"`
|
||||||
|
DstIp string `json:"dstIp"`
|
||||||
|
SignalPort int16 `json:"signalPort"`
|
||||||
|
NeType string `json:"neType"`
|
||||||
|
NeId string `json:"neId"`
|
||||||
|
UeIp string `json:"ueIp"`
|
||||||
|
Interfaces []string `json:"interfaces"`
|
||||||
|
NotifyUrl string `json:"notifyUrl" xorm:"-"`
|
||||||
|
Status string `json:"-" xorm:"status"`
|
||||||
|
SuccNEs []string `json:"-" xorm:"succ_nes"`
|
||||||
|
FailNEs []string `json:"-" xorm:"fail_nes"`
|
||||||
|
AccountID string `json:"accountId" xorm:"account_id"`
|
||||||
|
Comment string `json:"comment" xorm:"comment"`
|
||||||
|
UpdateTime string `json:"-" xorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = resty.New()
|
||||||
|
|
||||||
|
/*
|
||||||
|
func init() {
|
||||||
|
client.SetTimeout(3 * time.Second)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Post trace task to NF/NFs
|
||||||
|
func PostTraceTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PostTraceTaskToNF processing... ")
|
||||||
|
|
||||||
|
//vars := mux.Vars(r)
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, int64(config.GetYamlConfig().Params.UriMaxLen)))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("body:", string(body))
|
||||||
|
|
||||||
|
traceTask := new(TraceTask)
|
||||||
|
_ = json.Unmarshal(body, traceTask)
|
||||||
|
log.Debug("traceTask:", traceTask)
|
||||||
|
|
||||||
|
var neTypes []string
|
||||||
|
// do not set device
|
||||||
|
if traceTask.NeType == "" {
|
||||||
|
// query neType by interface
|
||||||
|
if len(traceTask.Interfaces) > 0 {
|
||||||
|
err := dborm.XormGetSingleColStringArrayByIn("trace_info", "ne_type", "interface", traceTask.Interfaces, &neTypes)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetSingleCol:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
neTypes = []string{"AMF", "SMF", "UDM", "AUSF", "UPF"}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
neTypes = append(neTypes, traceTask.NeType)
|
||||||
|
}
|
||||||
|
log.Debug("neTypes:", neTypes)
|
||||||
|
|
||||||
|
traceTask.Status = "Inactive"
|
||||||
|
_, err = dborm.XormInsertTableOne("trace_task", traceTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormInsertTableOne:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
traceTask.NotifyUrl = config.GetYamlConfig().OMC.GtpUri
|
||||||
|
log.Trace("traceTask:", traceTask)
|
||||||
|
|
||||||
|
for _, neType := range neTypes {
|
||||||
|
var neInfos []dborm.NeInfo
|
||||||
|
if traceTask.NeId == "" {
|
||||||
|
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, traceTask.NeId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neInfos = append(neInfos, *neInfo)
|
||||||
|
}
|
||||||
|
for _, neInfo := range neInfos {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
requestURI2NF := fmt.Sprintf("%s%s", hostUri, UriTraceTaskV1)
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
body, _ := json.Marshal(traceTask)
|
||||||
|
log.Debug("body:", string(body))
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Post(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Post:", err)
|
||||||
|
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
|
||||||
|
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
|
||||||
|
} else {
|
||||||
|
switch resp.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
succNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
|
||||||
|
traceTask.SuccNEs = append(traceTask.SuccNEs, succNE)
|
||||||
|
default:
|
||||||
|
log.Warnf("Post return code:%d, message:%s", resp.StatusCode(), string(resp.Body()))
|
||||||
|
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
|
||||||
|
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(traceTask.SuccNEs) > 0 {
|
||||||
|
traceTask.Status = "Active"
|
||||||
|
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormUpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
} else {
|
||||||
|
traceTask.Status = "Failed"
|
||||||
|
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormUpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = global.ErrTraceFailedDistributeToNEs
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutTraceTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("PutTraceTaskToNF processing... ")
|
||||||
|
|
||||||
|
//vars := mux.Vars(r)
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(io.LimitReader(r.Body, int64(config.GetYamlConfig().Params.UriMaxLen)))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("io.ReadAll is failed:", err)
|
||||||
|
services.ResponseNotFound404UriNotExist(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
traceTask := new(TraceTask)
|
||||||
|
_ = json.Unmarshal(body, traceTask)
|
||||||
|
|
||||||
|
traceTask.NotifyUrl = config.GetYamlConfig().OMC.GtpUri
|
||||||
|
log.Debug("traceTask:", traceTask)
|
||||||
|
|
||||||
|
var neTypes []string
|
||||||
|
// do not set device
|
||||||
|
if traceTask.NeType == "" {
|
||||||
|
// query neType by interface
|
||||||
|
if len(traceTask.Interfaces) > 0 {
|
||||||
|
err := dborm.XormGetSingleColStringArrayByIn("trace_info", "ne_type", "interface", traceTask.Interfaces, &neTypes)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetSingleColStringArrayByIn:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
neTypes = []string{"AMF", "SMF", "UDM", "AUSF", "UPF"}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
neTypes = append(neTypes, traceTask.NeType)
|
||||||
|
}
|
||||||
|
log.Debug("neTypes:", neTypes)
|
||||||
|
|
||||||
|
for _, neType := range neTypes {
|
||||||
|
var neInfos []dborm.NeInfo
|
||||||
|
if traceTask.NeId == "" {
|
||||||
|
err := dborm.XormGetNeInfoByNeType(neType, &neInfos)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, traceTask.NeId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfoByNeType:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
neInfos = append(neInfos, *neInfo)
|
||||||
|
}
|
||||||
|
for _, neInfo := range neInfos {
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
requestURI2NF := fmt.Sprintf("%s%s", hostUri, UriTraceTaskV1)
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
body, _ := json.Marshal(traceTask)
|
||||||
|
log.Debug("body:", string(body))
|
||||||
|
resp, err := client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
SetBody(body).
|
||||||
|
Put(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Put:", err)
|
||||||
|
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
|
||||||
|
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
|
||||||
|
} else {
|
||||||
|
switch resp.StatusCode() {
|
||||||
|
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||||
|
succNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
|
||||||
|
traceTask.SuccNEs = append(traceTask.SuccNEs, succNE)
|
||||||
|
default:
|
||||||
|
log.Warn("Post return code:%d, message:%s", resp.StatusCode(), string(resp.Body()))
|
||||||
|
failNE := fmt.Sprintf("%s.%s", neInfo.NeType, neInfo.NeId)
|
||||||
|
traceTask.FailNEs = append(traceTask.FailNEs, failNE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(traceTask.SuccNEs) > 0 {
|
||||||
|
traceTask.Status = "Active"
|
||||||
|
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormUpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
} else {
|
||||||
|
traceTask.Status = "Failed"
|
||||||
|
_, err = dborm.XormUpdateTableById(traceTask.Id, "trace_task", traceTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormUpdateTableById:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = global.ErrTraceFailedDistributeToNEs
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTraceTaskToNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("DeleteTraceTaskToNF processing... ")
|
||||||
|
|
||||||
|
token, err := services.CheckFrontValidRequest(w, r)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Request error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("AccessToken:", token)
|
||||||
|
|
||||||
|
vars := r.URL.Query()
|
||||||
|
ids, ok := vars["id"]
|
||||||
|
if !ok || len(ids) == 0 {
|
||||||
|
err = global.ErrTraceNotCarriedTaskID
|
||||||
|
log.Error(err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("ids:", ids)
|
||||||
|
|
||||||
|
for _, id := range ids {
|
||||||
|
log.Debug("id:", id)
|
||||||
|
|
||||||
|
var succNes []string
|
||||||
|
err = dborm.XormGetColStringArrayByWhere("trace_task", "succ_nes", fmt.Sprintf("id=%s", id), &succNes)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetSingleColStringArrayByWhere:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Debug("succNes:", succNes)
|
||||||
|
nes := new([]string)
|
||||||
|
if len(succNes) > 0 {
|
||||||
|
_ = json.Unmarshal([]byte(succNes[0]), nes)
|
||||||
|
}
|
||||||
|
log.Debug("nes:", nes)
|
||||||
|
|
||||||
|
for _, ne := range *nes {
|
||||||
|
i := strings.Index(ne, ".")
|
||||||
|
neType := ne[0:i]
|
||||||
|
neId := ne[i+1:]
|
||||||
|
log.Debugf("ne:%s neType:%s neId:%s", ne, neType, neId)
|
||||||
|
neInfo, err := dborm.XormGetNeInfo(neType, neId)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetNeInfo:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
|
||||||
|
requestURI2NF := fmt.Sprintf("%s%s?id=%s", hostUri, UriTraceTaskV1, id)
|
||||||
|
log.Debug("requestURI2NF:", requestURI2NF)
|
||||||
|
|
||||||
|
_, err = client.R().
|
||||||
|
EnableTrace().
|
||||||
|
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||||
|
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||||
|
Delete(requestURI2NF)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to Delete:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dborm.XormDeleteDataByWhere(fmt.Sprintf("id=%s", id), "trace_task")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormDeleteDataByWhere:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
services.ResponseStatusOK204NoContent(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRawMessage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("GetRawMessage processing... ")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRawMsg2Html(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Debug("ParseRawMsg2Html processing... ")
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
idStr := vars["id"]
|
||||||
|
id, _ := strconv.Atoi(idStr)
|
||||||
|
|
||||||
|
traceData, err := dborm.XormGetTraceData(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to dborm.XormGetTraceRawMsg:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Trace("traceData:", traceData)
|
||||||
|
filePath := traceData.DecMsg
|
||||||
|
if traceData.DecMsg == "" {
|
||||||
|
htmlFile := fmt.Sprintf("traceDecMessage-%d-%d.html", traceData.TaskID, traceData.ID)
|
||||||
|
filePath = config.GetYamlConfig().OMC.FrontTraceDir + "/" + htmlFile
|
||||||
|
command := fmt.Sprintf("/usr/local/omc/bin/data2html -f %s -t %d -i N%d -d %x", filePath, traceData.Timestamp, traceData.IfType, traceData.RawMsg)
|
||||||
|
out, err := run.ExecCmd(command, "/")
|
||||||
|
log.Tracef("Exec output: %v", string(out))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to ipdate2html:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
exist, err := global.FilePathExists(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to stat:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !exist {
|
||||||
|
err = errors.New(string(strings.ReplaceAll(string(out), "\n", "")))
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
traceData.DecMsg = filePath
|
||||||
|
_, err = dborm.XormUpdateTraceData(id, traceData)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Faile to XormUpdateTraceData:", err)
|
||||||
|
services.ResponseInternalServerError500ProcessError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
services.ResponseHtmlContent(w, http.StatusOK, filePath)
|
||||||
|
}
|
||||||
1209
features/udm_user/api_udm_user.go
Normal file
1209
features/udm_user/api_udm_user.go
Normal file
File diff suppressed because it is too large
Load Diff
13
features/udm_user/model/udm_auth_user.go
Normal file
13
features/udm_user/model/udm_auth_user.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// UdmAuthUser UDM鉴权用户
|
||||||
|
type UdmAuthUser struct {
|
||||||
|
ID string `json:"id" xorm:"pk 'id' autoincr"`
|
||||||
|
Imsi string `json:"imsi" xorm:"imsi"` // SIM卡号
|
||||||
|
Amf string `json:"amf" xorm:"amf"` // ANF
|
||||||
|
Status string `json:"status" xorm:"status"` // 状态
|
||||||
|
Ki string `json:"ki" xorm:"ki"` // ki
|
||||||
|
AlgoIndex string `json:"algoIndex" xorm:"algo_index"` //
|
||||||
|
Opc string `json:"opc" xorm:"opc"`
|
||||||
|
NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统
|
||||||
|
}
|
||||||
29
features/udm_user/model/udm_sub_user.go
Normal file
29
features/udm_user/model/udm_sub_user.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// UdmSubUser UDM签约用户
|
||||||
|
type UdmSubUser struct {
|
||||||
|
ID string `json:"id" xorm:"pk 'id' autoincr"`
|
||||||
|
Msisdn string `json:"msisdn" xorm:"msisdn"` // 相当手机号
|
||||||
|
Imsi string `json:"imsi" xorm:"imsi"` // SIM卡号
|
||||||
|
Ambr string `json:"ambr" xorm:"ambr"`
|
||||||
|
Nssai string `json:"nssai" xorm:"nssai"`
|
||||||
|
Rat string `json:"rat" xorm:"rat"`
|
||||||
|
Arfb string `json:"arfb" xorm:"arfb"`
|
||||||
|
Sar string `json:"sar" xorm:"sar"`
|
||||||
|
Cn string `json:"cn" xorm:"cn"`
|
||||||
|
SmData string `json:"smData" xorm:"sm_data"`
|
||||||
|
SmfSel string `json:"smfSel" xorm:"smf_sel"`
|
||||||
|
EpsDat string `json:"epsDat" xorm:"eps_dat"`
|
||||||
|
NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统
|
||||||
|
|
||||||
|
EpsFlag string `json:"epsFlag" xorm:"eps_flag"`
|
||||||
|
EpsOdb string `json:"epsOdb" xorm:"eps_odb"`
|
||||||
|
HplmnOdb string `json:"hplmnOdb" xorm:"hplmn_odb"`
|
||||||
|
Ard string `json:"ard" xorm:"ard"`
|
||||||
|
Epstpl string `json:"epstpl" xorm:"epstpl"`
|
||||||
|
ContextId string `json:"contextId" xorm:"context_id"`
|
||||||
|
ApnContext string `json:"apnContext" xorm:"apn_context"`
|
||||||
|
StaticIp string `json:"staticIp" xorm:"static_ip"`
|
||||||
|
|
||||||
|
SubNum string `json:"subNum,omitempty" xorm:"-"` // 批量数
|
||||||
|
}
|
||||||
274
features/udm_user/repo/repo_udm_auth_user.go
Normal file
274
features/udm_user/repo/repo_udm_auth_user.go
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/udm_user/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoUdmAuthUser 结构体
|
||||||
|
var NewRepoUdmAuthUser = &RepoUdmAuthUser{
|
||||||
|
selectSql: `select
|
||||||
|
id, imsi, amf, status, ki, algo_index, opc, ne_id
|
||||||
|
from u_auth_user`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"id": "ID",
|
||||||
|
"imsi": "Imsi",
|
||||||
|
"amf": "Amf",
|
||||||
|
"status": "Status",
|
||||||
|
"ki": "Ki",
|
||||||
|
"algo_index": "AlgoIndex",
|
||||||
|
"opc": "Opc",
|
||||||
|
"ne_id": "NeID",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoUdmAuthUser UDM鉴权用户 数据层处理
|
||||||
|
type RepoUdmAuthUser struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoUdmAuthUser) convertResultRows(rows []map[string]any) []model.UdmAuthUser {
|
||||||
|
arr := make([]model.UdmAuthUser, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
UdmUser := model.UdmAuthUser{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&UdmUser, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, UdmUser)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectPage 根据条件分页查询
|
||||||
|
func (r *RepoUdmAuthUser) SelectPage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["imsi"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["neId"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "ne_id = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
result := map[string]any{
|
||||||
|
"total": 0,
|
||||||
|
"rows": []model.UdmAuthUser{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := "select count(1) as 'total' from u_auth_user"
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
result["total"] = total
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
|
||||||
|
pageSql := " limit ?,? "
|
||||||
|
params = append(params, pageNum*pageSize)
|
||||||
|
params = append(params, pageSize)
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
sortSql := ""
|
||||||
|
if v, ok := query["sortField"]; ok && v != "" {
|
||||||
|
if v == "imsi" {
|
||||||
|
sortSql += " order by imsi "
|
||||||
|
}
|
||||||
|
if v, ok := query["sortOrder"]; ok && v != nil {
|
||||||
|
if v == "desc" {
|
||||||
|
sortSql += " desc "
|
||||||
|
} else {
|
||||||
|
sortSql += " asc "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql + sortSql + pageSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
result["rows"] = r.convertResultRows(results)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectList 根据实体查询
|
||||||
|
func (r *RepoUdmAuthUser) SelectList(auth model.UdmAuthUser) []model.UdmAuthUser {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if auth.Imsi != "" {
|
||||||
|
conditions = append(conditions, "imsi = ?")
|
||||||
|
params = append(params, auth.Imsi)
|
||||||
|
}
|
||||||
|
if auth.NeID != "" {
|
||||||
|
conditions = append(conditions, "ne_id = ?")
|
||||||
|
params = append(params, auth.NeID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearAndInsert 清空ne_id后新增实体
|
||||||
|
func (r *RepoUdmAuthUser) ClearAndInsert(neID string, authArr []model.UdmAuthUser) int64 {
|
||||||
|
var num int64 = 0
|
||||||
|
|
||||||
|
// 清空指定ne_id
|
||||||
|
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil)
|
||||||
|
// _, err := datasource.ExecDB("", "DELETE FROM u_auth_user WHERE ne_id = ?", []any{neID})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("TRUNCATE err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n := len(authArr)
|
||||||
|
batchSize := 2000
|
||||||
|
for i := 0; i < n; i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > n {
|
||||||
|
end = n
|
||||||
|
}
|
||||||
|
batch := authArr[i:end]
|
||||||
|
|
||||||
|
// 调用 InsertMulti 函数将批量数据插入数据库
|
||||||
|
results, err := datasource.DefaultDB().Table("u_auth_user").InsertMulti(batch)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
num += results
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 新增实体
|
||||||
|
func (r *RepoUdmAuthUser) Insert(authUser model.UdmAuthUser) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("u_auth_user").Insert(authUser)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Insert err => %v", err)
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 批量添加
|
||||||
|
func (r *RepoUdmAuthUser) Inserts(authUsers []model.UdmAuthUser) int64 {
|
||||||
|
var num int64
|
||||||
|
n := len(authUsers)
|
||||||
|
batchSize := 2000
|
||||||
|
for i := 0; i < n; i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > n {
|
||||||
|
end = n
|
||||||
|
}
|
||||||
|
batch := authUsers[i:end]
|
||||||
|
|
||||||
|
// 调用 InsertMulti 函数将批量数据插入数据库
|
||||||
|
results, err := datasource.DefaultDB().Table("u_auth_user").InsertMulti(batch)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
num += results
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改更新
|
||||||
|
func (r *RepoUdmAuthUser) Update(neID string, authUser model.UdmAuthUser) int64 {
|
||||||
|
// 查询先
|
||||||
|
var user model.UdmAuthUser
|
||||||
|
has, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", authUser.Imsi, neID).Get(&user)
|
||||||
|
if !has || err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if authUser.Ki != "" && authUser.Ki != user.Ki {
|
||||||
|
user.Ki = authUser.Ki
|
||||||
|
}
|
||||||
|
if authUser.Amf != "" && authUser.Amf != user.Amf {
|
||||||
|
user.Amf = authUser.Amf
|
||||||
|
}
|
||||||
|
if authUser.AlgoIndex != "" && authUser.AlgoIndex != user.AlgoIndex {
|
||||||
|
user.AlgoIndex = authUser.AlgoIndex
|
||||||
|
}
|
||||||
|
if authUser.Opc != "" && authUser.Opc != user.Opc {
|
||||||
|
user.Opc = authUser.Opc
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", user.Imsi, user.NeID).Update(user)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除实体
|
||||||
|
func (r *RepoUdmAuthUser) Delete(neID, imsi string) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", imsi, neID).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除范围实体
|
||||||
|
func (r *RepoUdmAuthUser) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi >= ? and imsi <= ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
438
features/udm_user/repo/repo_udm_sub_user.go
Normal file
438
features/udm_user/repo/repo_udm_sub_user.go
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/udm_user/model"
|
||||||
|
"ems.agt/lib/core/datasource"
|
||||||
|
"ems.agt/lib/core/utils/parse"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 RepoUdmSubUser 结构体
|
||||||
|
var NewRepoUdmSubUser = &RepoUdmSubUser{
|
||||||
|
selectSql: `select
|
||||||
|
id, msisdn, imsi, ambr, nssai, rat, arfb, sar, cn, sm_data, smf_sel, eps_dat, ne_id, eps_flag, eps_odb, hplmn_odb, ard, epstpl, context_id, apn_context, static_ip
|
||||||
|
from u_sub_user`,
|
||||||
|
|
||||||
|
resultMap: map[string]string{
|
||||||
|
"id": "ID",
|
||||||
|
"msisdn": "Msisdn",
|
||||||
|
"imsi": "Imsi",
|
||||||
|
"ambr": "Ambr",
|
||||||
|
"nssai": "Nssai",
|
||||||
|
"rat": "Rat",
|
||||||
|
"arfb": "Arfb",
|
||||||
|
"sar": "Sar",
|
||||||
|
"cn": "Cn",
|
||||||
|
"sm_data": "SmData",
|
||||||
|
"smf_sel": "SmfSel",
|
||||||
|
"eps_dat": "EpsDat",
|
||||||
|
"ne_id": "NeID",
|
||||||
|
"eps_flag": "EpsFlag",
|
||||||
|
"eps_odb": "EpsOdb",
|
||||||
|
"hplmn_odb": "HplmnOdb",
|
||||||
|
"ard": "Ard",
|
||||||
|
"epstpl": "Epstpl",
|
||||||
|
"context_id": "ContextId",
|
||||||
|
"apn_context": "ApnContext",
|
||||||
|
"static_ip": "StaticIp",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RepoUdmSubUser UDM签约用户 数据层处理
|
||||||
|
type RepoUdmSubUser struct {
|
||||||
|
// 查询视图对象SQL
|
||||||
|
selectSql string
|
||||||
|
// 结果字段与实体映射
|
||||||
|
resultMap map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertResultRows 将结果记录转实体结果组
|
||||||
|
func (r *RepoUdmSubUser) convertResultRows(rows []map[string]any) []model.UdmSubUser {
|
||||||
|
arr := make([]model.UdmSubUser, 0)
|
||||||
|
for _, row := range rows {
|
||||||
|
UdmUser := model.UdmSubUser{}
|
||||||
|
for key, value := range row {
|
||||||
|
if keyMapper, ok := r.resultMap[key]; ok {
|
||||||
|
datasource.SetFieldValue(&UdmUser, keyMapper, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr = append(arr, UdmUser)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectPage 根据条件分页查询字典类型
|
||||||
|
func (r *RepoUdmSubUser) SelectPage(query map[string]any) map[string]any {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if v, ok := query["msisdn"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["imsi"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
if v, ok := query["neId"]; ok && v != "" {
|
||||||
|
conditions = append(conditions, "ne_id = ?")
|
||||||
|
params = append(params, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
result := map[string]any{
|
||||||
|
"total": 0,
|
||||||
|
"rows": []model.UdmAuthUser{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数量 长度为0直接返回
|
||||||
|
totalSql := "select count(1) as 'total' from u_sub_user"
|
||||||
|
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("total err => %v", err)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
total := parse.Number(totalRows[0]["total"])
|
||||||
|
if total == 0 {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
result["total"] = total
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"])
|
||||||
|
pageSql := " limit ?,? "
|
||||||
|
params = append(params, pageNum*pageSize)
|
||||||
|
params = append(params, pageSize)
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
sortSql := ""
|
||||||
|
if v, ok := query["sortField"]; ok && v != "" {
|
||||||
|
if v == "imsi" {
|
||||||
|
sortSql += " order by imsi "
|
||||||
|
}
|
||||||
|
if v, ok := query["sortOrder"]; ok && v != nil {
|
||||||
|
if v == "desc" {
|
||||||
|
sortSql += " desc "
|
||||||
|
} else {
|
||||||
|
sortSql += " asc "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql + sortSql + pageSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
result["rows"] = r.convertResultRows(results)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectList 根据实体查询
|
||||||
|
func (r *RepoUdmSubUser) SelectList(auth model.UdmSubUser) []model.UdmSubUser {
|
||||||
|
// 查询条件拼接
|
||||||
|
var conditions []string
|
||||||
|
var params []any
|
||||||
|
if auth.Imsi != "" {
|
||||||
|
conditions = append(conditions, "imsi = ?")
|
||||||
|
params = append(params, auth.Imsi)
|
||||||
|
}
|
||||||
|
if auth.NeID != "" {
|
||||||
|
conditions = append(conditions, "ne_id = ?")
|
||||||
|
params = append(params, auth.NeID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
whereSql := ""
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
whereSql += " where " + strings.Join(conditions, " and ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询数据
|
||||||
|
querySql := r.selectSql + whereSql
|
||||||
|
results, err := datasource.RawDB("", querySql, params)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("query err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换实体
|
||||||
|
return r.convertResultRows(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearAndInsert 清空ne_id后新增实体
|
||||||
|
func (r *RepoUdmSubUser) ClearAndInsert(neID string, subArr []model.UdmSubUser) int64 {
|
||||||
|
var num int64 = 0
|
||||||
|
|
||||||
|
// 清空指定ne_id
|
||||||
|
_, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil)
|
||||||
|
// _, err := datasource.ExecDB("", "DELETE FROM u_sub_user WHERE ne_id = ?", []any{neID})
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("TRUNCATE err => %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n := len(subArr)
|
||||||
|
batchSize := 2000
|
||||||
|
for i := 0; i < n; i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > n {
|
||||||
|
end = n
|
||||||
|
}
|
||||||
|
batch := subArr[i:end]
|
||||||
|
|
||||||
|
// 调用 InsertMulti 函数将批量数据插入数据库
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").InsertMulti(batch)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
num += results
|
||||||
|
}
|
||||||
|
|
||||||
|
// for _, u := range subArr {
|
||||||
|
// u.NeID = neID
|
||||||
|
// results, err := datasource.DefaultDB().Table("u_sub_user").Insert(u)
|
||||||
|
// if err != nil {
|
||||||
|
// return num
|
||||||
|
// }
|
||||||
|
// num += results
|
||||||
|
// }
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 新增实体
|
||||||
|
func (r *RepoUdmSubUser) Insert(subUser model.UdmSubUser) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Insert(subUser)
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 批量添加
|
||||||
|
func (r *RepoUdmSubUser) Inserts(subUser []model.UdmSubUser) int64 {
|
||||||
|
var num int64
|
||||||
|
n := len(subUser)
|
||||||
|
batchSize := 2000
|
||||||
|
for i := 0; i < n; i += batchSize {
|
||||||
|
end := i + batchSize
|
||||||
|
if end > n {
|
||||||
|
end = n
|
||||||
|
}
|
||||||
|
batch := subUser[i:end]
|
||||||
|
|
||||||
|
// 调用 InsertMulti 函数将批量数据插入数据库
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").InsertMulti(batch)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
num += results
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert4G 批量添加4G用户
|
||||||
|
func (r *RepoUdmSubUser) Insert4G(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
var insertNum int64
|
||||||
|
|
||||||
|
imsiV, err := strconv.Atoi(subUser.Imsi)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
numV, err := strconv.Atoi(subUser.SubNum)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
subUser.NeID = neID
|
||||||
|
for i := 0; i < numV; i++ {
|
||||||
|
subUser.Imsi = fmt.Sprint(imsiV + i)
|
||||||
|
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Insert(subUser)
|
||||||
|
if err == nil {
|
||||||
|
insertNum += results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update 修改更新
|
||||||
|
func (r *RepoUdmSubUser) Update(neID string, authUser model.UdmSubUser) int64 {
|
||||||
|
// 查询先
|
||||||
|
var user model.UdmSubUser
|
||||||
|
has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", authUser.Imsi, neID).Get(&user)
|
||||||
|
if !has || err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if authUser.Msisdn != "" && authUser.Msisdn != user.Msisdn {
|
||||||
|
user.Msisdn = authUser.Msisdn
|
||||||
|
}
|
||||||
|
if authUser.Ambr != "" && authUser.Ambr != user.Ambr {
|
||||||
|
user.Ambr = authUser.Ambr
|
||||||
|
}
|
||||||
|
if authUser.Arfb != "" && authUser.Arfb != user.Arfb {
|
||||||
|
user.Arfb = authUser.Arfb
|
||||||
|
}
|
||||||
|
if authUser.Sar != "" && authUser.Sar != user.Sar {
|
||||||
|
user.Sar = authUser.Sar
|
||||||
|
}
|
||||||
|
if authUser.Rat != "" && authUser.Rat != user.Rat {
|
||||||
|
user.Rat = authUser.Rat
|
||||||
|
}
|
||||||
|
if authUser.Cn != "" && authUser.Cn != user.Cn {
|
||||||
|
user.Cn = authUser.Cn
|
||||||
|
}
|
||||||
|
if authUser.SmfSel != "" && authUser.SmfSel != user.SmfSel {
|
||||||
|
user.SmfSel = authUser.SmfSel
|
||||||
|
}
|
||||||
|
if authUser.SmData != "" && authUser.SmData != user.SmData {
|
||||||
|
user.SmData = authUser.SmData
|
||||||
|
}
|
||||||
|
if authUser.EpsDat != "" && authUser.EpsDat != user.EpsDat {
|
||||||
|
user.EpsDat = authUser.EpsDat
|
||||||
|
}
|
||||||
|
if authUser.EpsFlag != "" && authUser.EpsFlag != user.EpsFlag {
|
||||||
|
user.EpsFlag = authUser.EpsFlag
|
||||||
|
}
|
||||||
|
if authUser.EpsOdb != "" && authUser.EpsDat != user.EpsDat {
|
||||||
|
user.EpsOdb = authUser.EpsOdb
|
||||||
|
}
|
||||||
|
if authUser.HplmnOdb != "" && authUser.HplmnOdb != user.HplmnOdb {
|
||||||
|
user.HplmnOdb = authUser.HplmnOdb
|
||||||
|
}
|
||||||
|
if authUser.Epstpl != "" && authUser.Epstpl != user.Epstpl {
|
||||||
|
user.Epstpl = authUser.Epstpl
|
||||||
|
}
|
||||||
|
if authUser.Ard != "" && authUser.Ard != user.Ard {
|
||||||
|
user.Ard = authUser.Ard
|
||||||
|
}
|
||||||
|
if authUser.ContextId != "" && authUser.ContextId != user.ContextId {
|
||||||
|
user.ContextId = authUser.ContextId
|
||||||
|
}
|
||||||
|
if authUser.ApnContext != "" && authUser.ApnContext != user.ApnContext {
|
||||||
|
user.ApnContext = authUser.ApnContext
|
||||||
|
}
|
||||||
|
if authUser.StaticIp != "" && authUser.StaticIp != user.StaticIp {
|
||||||
|
user.StaticIp = authUser.StaticIp
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", user.Imsi, user.NeID).Update(user)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update4GIP 批量修改4G IP
|
||||||
|
func (r *RepoUdmSubUser) Update4GIP(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
var insertNum int64
|
||||||
|
|
||||||
|
imsiV, err := strconv.Atoi(subUser.Imsi)
|
||||||
|
if err != nil || subUser.StaticIp == "" {
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
numV, err := strconv.Atoi(subUser.SubNum)
|
||||||
|
if err != nil {
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < numV; i++ {
|
||||||
|
subUser.Imsi = fmt.Sprint(imsiV + i)
|
||||||
|
|
||||||
|
// 查询先
|
||||||
|
var user model.UdmSubUser
|
||||||
|
has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).Get(&user)
|
||||||
|
if has && err == nil {
|
||||||
|
// IP会自动递增
|
||||||
|
parts := strings.Split(subUser.StaticIp, ".")
|
||||||
|
lastPart := parts[3]
|
||||||
|
lastNum, _ := strconv.Atoi(lastPart)
|
||||||
|
lastNum += i
|
||||||
|
newLastPart := strconv.Itoa(lastNum)
|
||||||
|
parts[3] = newLastPart
|
||||||
|
newIP := strings.Join(parts, ".")
|
||||||
|
user.StaticIp = newIP
|
||||||
|
// 更新
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Update(user)
|
||||||
|
if err == nil {
|
||||||
|
insertNum += results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSmData 批量修改sm-data
|
||||||
|
func (r *RepoUdmSubUser) UpdateSmData(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
var insertNum int64
|
||||||
|
|
||||||
|
imsiV, err := strconv.Atoi(subUser.Imsi)
|
||||||
|
if err != nil || subUser.StaticIp == "" {
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
numV, err := strconv.Atoi(subUser.SubNum)
|
||||||
|
if err != nil {
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < numV; i++ {
|
||||||
|
subUser.Imsi = fmt.Sprint(imsiV + i)
|
||||||
|
|
||||||
|
// 查询先
|
||||||
|
var user model.UdmSubUser
|
||||||
|
has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).Get(&user)
|
||||||
|
if has && err == nil {
|
||||||
|
// IP会自动递增,需提前规划好DNN对应的IP;如dnn不需要绑定IP则不带此字段名
|
||||||
|
// parts := strings.Split(subUser.SmData, "&")
|
||||||
|
user.SmData = subUser.SmData
|
||||||
|
// 更新
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Update(user)
|
||||||
|
if err == nil {
|
||||||
|
insertNum += results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insertNum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除实体
|
||||||
|
func (r *RepoUdmSubUser) Delete(neID, imsi string) int64 {
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", imsi, neID).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除范围实体
|
||||||
|
func (r *RepoUdmSubUser) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi >= ? and imsi <= ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete()
|
||||||
|
if err != nil {
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
108
features/udm_user/service/service_redis_data.go
Normal file
108
features/udm_user/service/service_redis_data.go
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/udm_user/model"
|
||||||
|
"ems.agt/lib/core/redis"
|
||||||
|
)
|
||||||
|
|
||||||
|
// phoneImsiList 获取所有imsi
|
||||||
|
// func phoneImsiList() map[string]string {
|
||||||
|
// phoneAndImsiArr := make(map[string]string, 0)
|
||||||
|
// phoneKeys, err := redis.GetKeys("udmuser", "1*********")
|
||||||
|
// if err != nil {
|
||||||
|
// return phoneAndImsiArr
|
||||||
|
// }
|
||||||
|
// for _, phone := range phoneKeys {
|
||||||
|
// imsi, err := redis.Get("udmuser", phone)
|
||||||
|
// if err != nil {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// phoneAndImsiArr[phone] = imsi
|
||||||
|
// }
|
||||||
|
// return phoneAndImsiArr
|
||||||
|
// }
|
||||||
|
|
||||||
|
// redisUdmAuthUserList UDM鉴权用户
|
||||||
|
func redisUdmAuthUserList() []model.UdmAuthUser {
|
||||||
|
user := []model.UdmAuthUser{}
|
||||||
|
ausfArr, err := redis.GetKeys("udmuser", "ausf:*")
|
||||||
|
if err != nil {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
for _, key := range ausfArr {
|
||||||
|
m, err := redis.GetHash("udmuser", key)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
status := "0"
|
||||||
|
if _, ok := m["auth_success"]; ok {
|
||||||
|
status = "1"
|
||||||
|
}
|
||||||
|
amf := ""
|
||||||
|
if v, ok := m["amf"]; ok {
|
||||||
|
amf = strings.Replace(v, "\r\n", "", 1)
|
||||||
|
}
|
||||||
|
a := model.UdmAuthUser{
|
||||||
|
Imsi: key[5:],
|
||||||
|
Amf: amf,
|
||||||
|
Status: status,
|
||||||
|
Ki: m["ki"],
|
||||||
|
AlgoIndex: m["algo"],
|
||||||
|
Opc: m["opc"],
|
||||||
|
}
|
||||||
|
user = append(user, a)
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
// redisUdmSubUserList UDM签约用户
|
||||||
|
func redisUdmSubUserList() []model.UdmSubUser {
|
||||||
|
user := []model.UdmSubUser{}
|
||||||
|
udmsdArr, err := redis.GetKeys("udmuser", "udm-sd:*")
|
||||||
|
if err != nil {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
for _, key := range udmsdArr {
|
||||||
|
m, err := redis.GetHash("udmuser", key)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
a := model.UdmSubUser{
|
||||||
|
Imsi: key[7:],
|
||||||
|
Msisdn: strings.TrimPrefix(m["gpsi"], "86"),
|
||||||
|
SmfSel: m["smf-sel"],
|
||||||
|
SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
a.EpsDat = v
|
||||||
|
arr := strings.Split(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]
|
||||||
|
a.StaticIp = arr[8]
|
||||||
|
}
|
||||||
|
|
||||||
|
user = append(user, a)
|
||||||
|
}
|
||||||
|
return user
|
||||||
|
}
|
||||||
143
features/udm_user/service/service_udm_auth_user.go
Normal file
143
features/udm_user/service/service_udm_auth_user.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"ems.agt/features/udm_user/model"
|
||||||
|
"ems.agt/features/udm_user/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceUdmAuthUser 结构体
|
||||||
|
var NewServiceUdmAuthUser = &ServiceUdmAuthUser{
|
||||||
|
repoAuthUser: *repo.NewRepoUdmAuthUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceUdmAuthUser UDM鉴权用户 服务层处理
|
||||||
|
type ServiceUdmAuthUser struct {
|
||||||
|
repoAuthUser repo.RepoUdmAuthUser
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save UDM鉴权用户-获取全部保存数据库
|
||||||
|
func (r *ServiceUdmAuthUser) Save(neID string) int64 {
|
||||||
|
var num int64 = 0
|
||||||
|
authArr := redisUdmAuthUserList()
|
||||||
|
// 有数据才清空
|
||||||
|
if len(authArr) == 0 {
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
go r.repoAuthUser.ClearAndInsert(neID, authArr)
|
||||||
|
return int64(len(authArr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page UDM签约用户-分页查询数据库
|
||||||
|
func (r *ServiceUdmAuthUser) Page(query map[string]any) map[string]any {
|
||||||
|
return r.repoAuthUser.SelectPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List UDM签约用户-查询数据库
|
||||||
|
func (r *ServiceUdmAuthUser) List(authUser model.UdmAuthUser) []model.UdmAuthUser {
|
||||||
|
return r.repoAuthUser.SelectList(authUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM鉴权用户-新增单个
|
||||||
|
// imsi长度15,ki长度32,opc长度0或者32
|
||||||
|
func (r *ServiceUdmAuthUser) Insert(neID string, authUser model.UdmAuthUser) int64 {
|
||||||
|
authUser.NeID = neID
|
||||||
|
authUser.Status = "1"
|
||||||
|
return r.repoAuthUser.Insert(authUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM鉴权用户-批量添加
|
||||||
|
func (r *ServiceUdmAuthUser) Inserts(neID string, authUser model.UdmAuthUser, num string) int64 {
|
||||||
|
var arr []model.UdmAuthUser
|
||||||
|
|
||||||
|
imsiVlen := len(authUser.Imsi)
|
||||||
|
imsiV, err := strconv.Atoi(authUser.Imsi)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
numV, err := strconv.Atoi(num)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
authUser.NeID = neID
|
||||||
|
authUser.Status = "1"
|
||||||
|
for i := 0; i < numV; i++ {
|
||||||
|
imsi := fmt.Sprint(imsiV + i)
|
||||||
|
if len(imsi) < imsiVlen {
|
||||||
|
imsi = fmt.Sprintf("%0*s", imsiVlen, imsi)
|
||||||
|
}
|
||||||
|
authUser.Imsi = imsi
|
||||||
|
arr = append(arr, authUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.repoAuthUser.Inserts(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertCSV UDM鉴权用户-批量添加
|
||||||
|
func (r *ServiceUdmAuthUser) InsertCSV(neID string, data []map[string]string) int64 {
|
||||||
|
var arr []model.UdmAuthUser
|
||||||
|
for _, v := range data {
|
||||||
|
var authUser model.UdmAuthUser
|
||||||
|
authUser.NeID = neID
|
||||||
|
authUser.Status = "1"
|
||||||
|
if s, ok := v["imsi"]; ok {
|
||||||
|
authUser.Imsi = s
|
||||||
|
}
|
||||||
|
if s, ok := v["ki"]; ok {
|
||||||
|
authUser.Ki = s
|
||||||
|
}
|
||||||
|
if s, ok := v["amf"]; ok {
|
||||||
|
authUser.Amf = s
|
||||||
|
}
|
||||||
|
if s, ok := v["algo"]; ok {
|
||||||
|
authUser.AlgoIndex = s
|
||||||
|
}
|
||||||
|
if s, ok := v["opc"]; ok {
|
||||||
|
authUser.Opc = s
|
||||||
|
}
|
||||||
|
arr = append(arr, authUser)
|
||||||
|
}
|
||||||
|
return r.repoAuthUser.Inserts(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertTxt UDM鉴权用户-批量添加
|
||||||
|
func (r *ServiceUdmAuthUser) InsertTxt(neID string, data [][]string) int64 {
|
||||||
|
var arr []model.UdmAuthUser
|
||||||
|
for _, v := range data {
|
||||||
|
if len(v) < 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var authUser model.UdmAuthUser
|
||||||
|
authUser.NeID = neID
|
||||||
|
authUser.Status = "1"
|
||||||
|
authUser.Imsi = v[0]
|
||||||
|
authUser.Ki = v[1]
|
||||||
|
authUser.AlgoIndex = v[2]
|
||||||
|
authUser.Amf = v[3]
|
||||||
|
if len(v) == 5 {
|
||||||
|
authUser.Opc = v[4]
|
||||||
|
}
|
||||||
|
arr = append(arr, authUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.repoAuthUser.Inserts(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM鉴权用户-修改更新
|
||||||
|
func (r *ServiceUdmAuthUser) Update(neID string, authUser model.UdmAuthUser) int64 {
|
||||||
|
return r.repoAuthUser.Update(neID, authUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM鉴权用户-删除单个
|
||||||
|
func (r *ServiceUdmAuthUser) Delete(neID, imsi string) int64 {
|
||||||
|
return r.repoAuthUser.Delete(neID, imsi)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM鉴权用户-删除范围
|
||||||
|
func (r *ServiceUdmAuthUser) Deletes(neID, imsi, num string) int64 {
|
||||||
|
return r.repoAuthUser.Deletes(neID, imsi, num)
|
||||||
|
}
|
||||||
201
features/udm_user/service/service_udm_sub_user.go
Normal file
201
features/udm_user/service/service_udm_sub_user.go
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/features/udm_user/model"
|
||||||
|
"ems.agt/features/udm_user/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 ServiceUdmSubUser 结构体
|
||||||
|
var NewServiceUdmSubUser = &ServiceUdmSubUser{
|
||||||
|
repoSunUser: *repo.NewRepoUdmSubUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceUdmSubUser UDM签约用户 服务层处理
|
||||||
|
type ServiceUdmSubUser struct {
|
||||||
|
repoSunUser repo.RepoUdmSubUser
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save UDM签约用户-获取全部保存数据库
|
||||||
|
func (r *ServiceUdmSubUser) Save(neID string) int64 {
|
||||||
|
var num int64 = 0
|
||||||
|
subArr := redisUdmSubUserList()
|
||||||
|
// 有数据才清空
|
||||||
|
if len(subArr) == 0 {
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
go r.repoSunUser.ClearAndInsert(neID, subArr)
|
||||||
|
return int64(len(subArr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page UDM签约用户-分页查询数据库
|
||||||
|
func (r *ServiceUdmSubUser) Page(query map[string]any) map[string]any {
|
||||||
|
return r.repoSunUser.SelectPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List UDM签约用户-查询数据库
|
||||||
|
func (r *ServiceUdmSubUser) List(subUser model.UdmSubUser) []model.UdmSubUser {
|
||||||
|
return r.repoSunUser.SelectList(subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM签约用户-新增单个
|
||||||
|
// imsi长度15,ki长度32,opc长度0或者32
|
||||||
|
func (r *ServiceUdmSubUser) Insert(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
subUser.NeID = neID
|
||||||
|
return r.repoSunUser.Insert(subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM签约用户-批量添加
|
||||||
|
func (r *ServiceUdmSubUser) Inserts(neID string, subUser model.UdmSubUser, num string) int64 {
|
||||||
|
var arr []model.UdmSubUser
|
||||||
|
|
||||||
|
imsiVlen := len(subUser.Imsi)
|
||||||
|
imsiV, err := strconv.Atoi(subUser.Imsi)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
msisdnVlen := len(subUser.Msisdn)
|
||||||
|
msisdnV, err := strconv.Atoi(subUser.Msisdn)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
numV, err := strconv.Atoi(num)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
subUser.NeID = neID
|
||||||
|
for i := 0; i < numV; i++ {
|
||||||
|
msisdn := fmt.Sprint(msisdnV + i)
|
||||||
|
if len(msisdn) < msisdnVlen {
|
||||||
|
msisdn = fmt.Sprintf("%0*s", msisdnVlen, msisdn)
|
||||||
|
}
|
||||||
|
subUser.Msisdn = msisdn
|
||||||
|
|
||||||
|
imsi := fmt.Sprint(imsiV + i)
|
||||||
|
if len(imsi) < imsiVlen {
|
||||||
|
imsi = fmt.Sprintf("%0*s", imsiVlen, imsi)
|
||||||
|
}
|
||||||
|
subUser.Imsi = imsi
|
||||||
|
|
||||||
|
// IP会自动递增
|
||||||
|
if subUser.StaticIp != "" {
|
||||||
|
parts := strings.Split(subUser.StaticIp, ".")
|
||||||
|
lastPart := parts[3]
|
||||||
|
lastNum, _ := strconv.Atoi(lastPart)
|
||||||
|
lastNum += i
|
||||||
|
newLastPart := strconv.Itoa(lastNum)
|
||||||
|
parts[3] = newLastPart
|
||||||
|
newIP := strings.Join(parts, ".")
|
||||||
|
subUser.StaticIp = newIP
|
||||||
|
}
|
||||||
|
arr = append(arr, subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.repoSunUser.Inserts(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertCSV UDM签约用户-批量添加
|
||||||
|
func (r *ServiceUdmSubUser) InsertCSV(neID string, data []map[string]string) int64 {
|
||||||
|
var arr []model.UdmSubUser
|
||||||
|
for _, v := range data {
|
||||||
|
var subUser model.UdmSubUser
|
||||||
|
subUser.NeID = neID
|
||||||
|
if s, ok := v["imsi"]; ok {
|
||||||
|
subUser.Imsi = s
|
||||||
|
}
|
||||||
|
if s, ok := v["msisdn"]; ok {
|
||||||
|
subUser.Msisdn = s
|
||||||
|
}
|
||||||
|
if s, ok := v["ambr"]; ok {
|
||||||
|
subUser.Ambr = s
|
||||||
|
}
|
||||||
|
if s, ok := v["nssai"]; ok {
|
||||||
|
subUser.Nssai = s
|
||||||
|
}
|
||||||
|
if s, ok := v["arfb"]; ok {
|
||||||
|
subUser.Arfb = s
|
||||||
|
}
|
||||||
|
if s, ok := v["sar"]; ok {
|
||||||
|
subUser.Sar = s
|
||||||
|
}
|
||||||
|
if s, ok := v["rat"]; ok {
|
||||||
|
subUser.Rat = s
|
||||||
|
}
|
||||||
|
if s, ok := v["cn"]; ok {
|
||||||
|
subUser.Cn = s
|
||||||
|
}
|
||||||
|
if s, ok := v["smf_sel"]; ok {
|
||||||
|
subUser.SmfSel = s
|
||||||
|
}
|
||||||
|
if s, ok := v["sm_data"]; ok {
|
||||||
|
subUser.SmData = s
|
||||||
|
}
|
||||||
|
if s, ok := v["eps_dat"]; ok {
|
||||||
|
subUser.EpsDat = s
|
||||||
|
}
|
||||||
|
arr = append(arr, subUser)
|
||||||
|
}
|
||||||
|
return r.repoSunUser.Inserts(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertTxt UDM签约用户-批量添加
|
||||||
|
func (r *ServiceUdmSubUser) InsertTxt(neID string, data [][]string) int64 {
|
||||||
|
var arr []model.UdmSubUser
|
||||||
|
for _, v := range data {
|
||||||
|
if len(v) < 10 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var subUser model.UdmSubUser
|
||||||
|
subUser.NeID = neID
|
||||||
|
subUser.Imsi = v[0]
|
||||||
|
subUser.Msisdn = v[1]
|
||||||
|
subUser.Ambr = v[2]
|
||||||
|
subUser.Nssai = v[3]
|
||||||
|
subUser.Arfb = v[4]
|
||||||
|
subUser.Sar = v[5]
|
||||||
|
subUser.Rat = v[6]
|
||||||
|
subUser.Cn = v[7]
|
||||||
|
subUser.SmfSel = v[8]
|
||||||
|
subUser.SmData = v[9]
|
||||||
|
if len(v) == 11 {
|
||||||
|
subUser.EpsDat = v[10]
|
||||||
|
}
|
||||||
|
arr = append(arr, subUser)
|
||||||
|
}
|
||||||
|
return r.repoSunUser.Inserts(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM签约用户-批量添加4G用户
|
||||||
|
func (r *ServiceUdmSubUser) Insert4G(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
return r.repoSunUser.Insert4G(neID, subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM签约用户-修改更新
|
||||||
|
func (r *ServiceUdmSubUser) Update(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
return r.repoSunUser.Update(neID, subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update4GIP UDM签约用户-批量修改4G IP
|
||||||
|
func (r *ServiceUdmSubUser) Update4GIP(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
return r.repoSunUser.Update4GIP(neID, subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update4GIP UDM签约用户-批量修改sm-data
|
||||||
|
func (r *ServiceUdmSubUser) UpdateSmData(neID string, subUser model.UdmSubUser) int64 {
|
||||||
|
return r.repoSunUser.UpdateSmData(neID, subUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM签约用户-删除单个
|
||||||
|
func (r *ServiceUdmSubUser) Delete(neID, imsi string) int64 {
|
||||||
|
return r.repoSunUser.Delete(neID, imsi)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert UDM签约用户-删除范围
|
||||||
|
func (r *ServiceUdmSubUser) Deletes(neID, imsi, num string) int64 {
|
||||||
|
return r.repoSunUser.Deletes(neID, imsi, num)
|
||||||
|
}
|
||||||
272
features/ue/ue.go
Normal file
272
features/ue/ue.go
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
package ue
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
"ems.agt/lib/global"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"ems.agt/lib/services"
|
||||||
|
"ems.agt/restagent/config"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AmfNBInfo AMF的NodeB信息
|
||||||
|
type AmfNBInfo struct {
|
||||||
|
ID string `json:"id"` //NodeB ID
|
||||||
|
Name string `json:"name"` // NodeB name
|
||||||
|
Address string `json:"address"` // 基站地址
|
||||||
|
UENum int `jons:"ueNum"` // UE数量
|
||||||
|
}
|
||||||
|
|
||||||
|
// SmfUENum SMF在线用户数
|
||||||
|
type SmfUENum struct {
|
||||||
|
UENum int `json:"ueNum"` // 当前在线用户数
|
||||||
|
}
|
||||||
|
|
||||||
|
// SmfUEInfo SMF在线用户信息
|
||||||
|
type SmfUEInfo struct {
|
||||||
|
IMSI string `json:"imsi"`
|
||||||
|
MSISDN string `json:"msisdn"`
|
||||||
|
RatType string `json:"ratType"`
|
||||||
|
PduSessionInfo []struct {
|
||||||
|
PduSessionID int `json:"pduSessionID"`
|
||||||
|
IPv4 string `json:"ipv4"`
|
||||||
|
IPv6 string `json:"ipv6"`
|
||||||
|
Dnn string `json:"dnn"`
|
||||||
|
Tai string `json:"tai"`
|
||||||
|
SstSD string `json:"sstSD"`
|
||||||
|
UpfN3IP string `json:"upfN3IP"`
|
||||||
|
RanN3IP string `json:"ranN3IP"`
|
||||||
|
Activetime string `json:"activeTime"`
|
||||||
|
} `json:"pduSessionInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImsUEInfo IMS在线用户信息
|
||||||
|
type ImsUEInfo struct {
|
||||||
|
IMSI string `json:"imsi"`
|
||||||
|
MSISDN string `json:"msisdn"`
|
||||||
|
IMPU string `json:"impu"`
|
||||||
|
Barring int `json:"barring"`
|
||||||
|
RegState int `json:"regState"`
|
||||||
|
Activetime string `json:"activeTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
UriNBInfo = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbInfo"
|
||||||
|
UriUEInfo = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueInfo"
|
||||||
|
UriUENum = config.DefaultUriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueNum"
|
||||||
|
|
||||||
|
CustomUriNBInfo = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/nbInfo"
|
||||||
|
CustomUriUEInfo = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueInfo"
|
||||||
|
CustomUriUENum = config.UriPrefix + "/ueManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/ueNum"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client = resty.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
/*
|
||||||
|
client.
|
||||||
|
SetTimeout(10 * time.Second).
|
||||||
|
SetRetryCount(1).
|
||||||
|
SetRetryWaitTime(1 * time.Second).
|
||||||
|
SetRetryMaxWaitTime(2 * time.Second).
|
||||||
|
SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||||||
|
return 0, errors.New("quota exceeded")
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
client.SetTimeout(3 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get UEInfo from NF/NFs
|
||||||
|
func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("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 {
|
||||||
|
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, 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
|
||||||
|
}
|
||||||
|
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{"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.DataResponse
|
||||||
|
_ = json.Unmarshal(resp.Body(), &response)
|
||||||
|
services.ResponseWithJson(w, resp.StatusCode(), response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get UEInfo from SMF
|
||||||
|
func GetUENumFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("GetUENumFromNF 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 {
|
||||||
|
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, 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
|
||||||
|
}
|
||||||
|
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{"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.DataResponse
|
||||||
|
_ = json.Unmarshal(resp.Body(), &response)
|
||||||
|
services.ResponseWithJson(w, resp.StatusCode(), response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get UEInfo from NF/NFs
|
||||||
|
func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Info("GetNBInfoFromNF 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 {
|
||||||
|
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, 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
|
||||||
|
}
|
||||||
|
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{"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.DataResponse
|
||||||
|
_ = json.Unmarshal(resp.Body(), &response)
|
||||||
|
services.ResponseWithJson(w, resp.StatusCode(), response)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
75
go.mod
Normal file
75
go.mod
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
module ems.agt
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
|
github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f
|
||||||
|
github.com/go-resty/resty/v2 v2.7.0
|
||||||
|
github.com/go-sql-driver/mysql v1.7.1
|
||||||
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
github.com/gosnmp/gosnmp v1.35.0
|
||||||
|
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
|
github.com/redis/go-redis/v9 v9.1.0
|
||||||
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
|
github.com/shirou/gopsutil/v3 v3.23.7
|
||||||
|
github.com/spf13/afero v1.9.5
|
||||||
|
github.com/spf13/viper v1.16.0
|
||||||
|
golang.org/x/crypto v0.12.0
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
xorm.io/xorm v1.3.2
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
|
github.com/onsi/gomega v1.21.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
|
||||||
|
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mojocn/base64Captcha v1.3.5
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||||
|
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||||
|
github.com/spf13/cast v1.5.1 // indirect
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/subosito/gotenv v1.4.2 // indirect
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||||
|
github.com/tebeka/strftime v0.1.5 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
|
golang.org/x/image v0.5.0 // indirect
|
||||||
|
golang.org/x/net v0.10.0 // indirect
|
||||||
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
|
golang.org/x/text v0.12.0 // indirect
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect
|
||||||
|
)
|
||||||
64
lib/aes/aes.go
Normal file
64
lib/aes/aes.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package aes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"encoding/base64"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AesEncrypt(orig string, key string) string {
|
||||||
|
// 转成字节数组
|
||||||
|
origData := []byte(orig)
|
||||||
|
k := []byte(key)
|
||||||
|
|
||||||
|
// 分组秘钥
|
||||||
|
block, _ := aes.NewCipher(k)
|
||||||
|
// 获取秘钥块的长度
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
// 补全码
|
||||||
|
origData = PKCS7Padding(origData, blockSize)
|
||||||
|
// 加密模式
|
||||||
|
blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
|
||||||
|
// 创建数组
|
||||||
|
cryted := make([]byte, len(origData))
|
||||||
|
// 加密
|
||||||
|
blockMode.CryptBlocks(cryted, origData)
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(cryted)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func AesDecrypt(cryted string, key string) string {
|
||||||
|
// 转成字节数组
|
||||||
|
crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
|
||||||
|
k := []byte(key)
|
||||||
|
|
||||||
|
// 分组秘钥
|
||||||
|
block, _ := aes.NewCipher(k)
|
||||||
|
// 获取秘钥块的长度
|
||||||
|
blockSize := block.BlockSize()
|
||||||
|
// 加密模式
|
||||||
|
blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
|
||||||
|
// 创建数组
|
||||||
|
orig := make([]byte, len(crytedByte))
|
||||||
|
// 解密
|
||||||
|
blockMode.CryptBlocks(orig, crytedByte)
|
||||||
|
// 去补全码
|
||||||
|
orig = PKCS7UnPadding(orig)
|
||||||
|
return string(orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 补码
|
||||||
|
func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
|
||||||
|
padding := blocksize - len(ciphertext)%blocksize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去码
|
||||||
|
func PKCS7UnPadding(origData []byte) []byte {
|
||||||
|
length := len(origData)
|
||||||
|
unpadding := int(origData[length-1])
|
||||||
|
return origData[:(length - unpadding)]
|
||||||
|
}
|
||||||
54
lib/core/account/account.go
Normal file
54
lib/core/account/account.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package account
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sysMenuService "ems.agt/features/sys_menu/service"
|
||||||
|
sysRoleService "ems.agt/features/sys_role/service"
|
||||||
|
"ems.agt/lib/core/cache"
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/core/vo"
|
||||||
|
"ems.agt/lib/dborm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 登录缓存用户信息
|
||||||
|
func CacheLoginUser(user *dborm.User) {
|
||||||
|
// 过期时间
|
||||||
|
expiresStr, err := dborm.XormGetConfigValue("Security", "sessionExpires")
|
||||||
|
if err != nil {
|
||||||
|
expiresStr = "18000"
|
||||||
|
}
|
||||||
|
expiresValue, _ := strconv.Atoi(expiresStr)
|
||||||
|
expireTime := time.Duration(expiresValue) * time.Second
|
||||||
|
|
||||||
|
nowTime := time.Now().UnixMilli()
|
||||||
|
|
||||||
|
// 登录用户
|
||||||
|
loginUser := vo.LoginUser{
|
||||||
|
UserID: fmt.Sprint(user.Id),
|
||||||
|
UserName: user.Name,
|
||||||
|
ExpireTime: nowTime + expireTime.Milliseconds(),
|
||||||
|
LoginTime: nowTime,
|
||||||
|
User: *user,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否管理员
|
||||||
|
if conf.IsAdmin(loginUser.UserID) {
|
||||||
|
loginUser.Permissions = []string{"*:*:*"}
|
||||||
|
} else {
|
||||||
|
// 获取权限标识
|
||||||
|
loginUser.Permissions = sysMenuService.NewRepoSysMenu.SelectMenuPermsByUserId(loginUser.UserID)
|
||||||
|
// 获取角色信息
|
||||||
|
loginUser.User.Roles = sysRoleService.NewRepoSysRole.SelectRoleListByUserId(loginUser.UserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存时间
|
||||||
|
cache.SetLocalTTL(user.AccountId, loginUser, time.Duration(expireTime))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除缓存用户信息
|
||||||
|
func ClearLoginUser(accountId string) {
|
||||||
|
cache.DeleteLocalTTL(accountId)
|
||||||
|
}
|
||||||
56
lib/core/cache/lcoal.go
vendored
Normal file
56
lib/core/cache/lcoal.go
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 创建一个全局的不过期缓存对象
|
||||||
|
var cNoExpiration = cache.New(cache.NoExpiration, cache.NoExpiration)
|
||||||
|
|
||||||
|
// 将数据放入缓存,并设置永不过期
|
||||||
|
func SetLocal(key string, value any) {
|
||||||
|
cNoExpiration.Set(key, value, cache.NoExpiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从缓存中获取数据
|
||||||
|
func GetLocal(key string) (any, bool) {
|
||||||
|
return cNoExpiration.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从缓存中删除数据
|
||||||
|
func DeleteLocal(key string) {
|
||||||
|
cNoExpiration.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取指定前缀的所有键
|
||||||
|
func GetLocalKeys(prefix string) []string {
|
||||||
|
prefix = strings.TrimSuffix(prefix, "*")
|
||||||
|
var keys []string
|
||||||
|
for key := range cNoExpiration.Items() {
|
||||||
|
if strings.HasPrefix(key, prefix) {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个全局的过期缓存对象
|
||||||
|
var cTTL = cache.New(6*time.Hour, 12*time.Hour)
|
||||||
|
|
||||||
|
// 设置具有过期时间的缓存项
|
||||||
|
func SetLocalTTL(key string, value any, expiration time.Duration) {
|
||||||
|
cTTL.Set(key, value, expiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从缓存中获取数据
|
||||||
|
func GetLocalTTL(key string) (any, bool) {
|
||||||
|
return cTTL.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从缓存中删除数据
|
||||||
|
func DeleteLocalTTL(key string) {
|
||||||
|
cTTL.Delete(key)
|
||||||
|
}
|
||||||
201
lib/core/cmd/cmd.go
Normal file
201
lib/core/cmd/cmd.go
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Exec(cmdStr string) (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.Command("bash", "-c", cmdStr)
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return "", fmt.Errorf("errCmdTimeout %v", err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errMsg := ""
|
||||||
|
if len(stderr.String()) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
|
||||||
|
}
|
||||||
|
if len(stdout.String()) != 0 {
|
||||||
|
if len(errMsg) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
|
||||||
|
} else {
|
||||||
|
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errMsg, err
|
||||||
|
}
|
||||||
|
return stdout.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecWithTimeOut(cmdStr string, timeout time.Duration) (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.Command("bash", "-c", cmdStr)
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return "", fmt.Errorf("errCmdTimeout %v", err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errMsg := ""
|
||||||
|
if len(stderr.String()) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
|
||||||
|
}
|
||||||
|
if len(stdout.String()) != 0 {
|
||||||
|
if len(errMsg) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
|
||||||
|
} else {
|
||||||
|
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errMsg, err
|
||||||
|
}
|
||||||
|
return stdout.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecCronjobWithTimeOut(cmdStr string, workdir string, timeout time.Duration) (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.Command("bash", "-c", cmdStr)
|
||||||
|
cmd.Dir = workdir
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return "", fmt.Errorf("errCmdTimeout %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
errMsg := ""
|
||||||
|
if len(stderr.String()) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("stderr:\n %s", stderr.String())
|
||||||
|
}
|
||||||
|
if len(stdout.String()) != 0 {
|
||||||
|
if len(errMsg) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("%s \n\n; stdout:\n %s", errMsg, stdout.String())
|
||||||
|
} else {
|
||||||
|
errMsg = fmt.Sprintf("stdout:\n %s", stdout.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errMsg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execf(cmdStr string, a ...interface{}) (string, error) {
|
||||||
|
cmd := exec.Command("bash", "-c", fmt.Sprintf(cmdStr, a...))
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
errMsg := ""
|
||||||
|
if len(stderr.String()) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
|
||||||
|
}
|
||||||
|
if len(stdout.String()) != 0 {
|
||||||
|
if len(errMsg) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
|
||||||
|
} else {
|
||||||
|
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errMsg, err
|
||||||
|
}
|
||||||
|
return stdout.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecWithCheck(name string, a ...string) (string, error) {
|
||||||
|
cmd := exec.Command(name, a...)
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
errMsg := ""
|
||||||
|
if len(stderr.String()) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
|
||||||
|
}
|
||||||
|
if len(stdout.String()) != 0 {
|
||||||
|
if len(errMsg) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
|
||||||
|
} else {
|
||||||
|
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errMsg, err
|
||||||
|
}
|
||||||
|
return stdout.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecScript(scriptPath, workDir string) (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
cmd := exec.Command("bash", scriptPath)
|
||||||
|
cmd.Dir = workDir
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
return "", fmt.Errorf("errCmdTimeout %v", err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errMsg := ""
|
||||||
|
if len(stderr.String()) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("stderr: %s", stderr.String())
|
||||||
|
}
|
||||||
|
if len(stdout.String()) != 0 {
|
||||||
|
if len(errMsg) != 0 {
|
||||||
|
errMsg = fmt.Sprintf("%s; stdout: %s", errMsg, stdout.String())
|
||||||
|
} else {
|
||||||
|
errMsg = fmt.Sprintf("stdout: %s", stdout.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errMsg, err
|
||||||
|
}
|
||||||
|
return stdout.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckIllegal(args ...string) bool {
|
||||||
|
if args == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, arg := range args {
|
||||||
|
if strings.Contains(arg, "&") || strings.Contains(arg, "|") || strings.Contains(arg, ";") ||
|
||||||
|
strings.Contains(arg, "$") || strings.Contains(arg, "'") || strings.Contains(arg, "`") ||
|
||||||
|
strings.Contains(arg, "(") || strings.Contains(arg, ")") || strings.Contains(arg, "\"") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func HasNoPasswordSudo() bool {
|
||||||
|
cmd2 := exec.Command("sudo", "-n", "ls")
|
||||||
|
err2 := cmd2.Run()
|
||||||
|
return err2 == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SudoHandleCmd() string {
|
||||||
|
cmd := exec.Command("sudo", "-n", "ls")
|
||||||
|
if err := cmd.Run(); err == nil {
|
||||||
|
return "sudo "
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func Which(name string) bool {
|
||||||
|
_, err := exec.LookPath(name)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
52
lib/core/conf/conf.go
Normal file
52
lib/core/conf/conf.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package conf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 配置文件读取
|
||||||
|
func InitConfig(configFile string) {
|
||||||
|
// 设置配置文件路径
|
||||||
|
viper.SetConfigFile(configFile)
|
||||||
|
|
||||||
|
// 读取配置文件
|
||||||
|
err := viper.ReadInConfig()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("读取配置文件失败: %v \n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录程序开始运行的时间点
|
||||||
|
viper.Set("runTime", time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunTime 程序开始运行的时间
|
||||||
|
func RunTime() time.Time {
|
||||||
|
return viper.GetTime("runTime")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取配置信息
|
||||||
|
//
|
||||||
|
// Get("framework.name")
|
||||||
|
func Get(key string) any {
|
||||||
|
return viper.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAdmin 用户是否为管理员
|
||||||
|
func IsAdmin(userID string) bool {
|
||||||
|
if userID == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 从本地配置获取user信息
|
||||||
|
// admins := Get("user.adminList").([]any)
|
||||||
|
admins := []string{"1", "2", "3"}
|
||||||
|
for _, s := range admins {
|
||||||
|
if s == userID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
24
lib/core/constants/cachekey/cachekey.go
Normal file
24
lib/core/constants/cachekey/cachekey.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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:"
|
||||||
49
lib/core/datasource/datasource.go
Normal file
49
lib/core/datasource/datasource.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package datasource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"ems.agt/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
|
||||||
|
}
|
||||||
135
lib/core/datasource/repo.go
Normal file
135
lib/core/datasource/repo.go
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
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 {
|
||||||
|
if num > 5000 {
|
||||||
|
num = 5000
|
||||||
|
}
|
||||||
|
num = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示记录数
|
||||||
|
pageSizeStr := fmt.Sprintf("%v", pageSize)
|
||||||
|
size := 10
|
||||||
|
if v, err := strconv.Atoi(pageSizeStr); err == nil && v > 0 {
|
||||||
|
if size < 0 {
|
||||||
|
size = 10
|
||||||
|
} else if size > 1000 {
|
||||||
|
size = 1000
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
88
lib/core/file/csv.go
Normal file
88
lib/core/file/csv.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/csv"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 写入CSV文件,需要转换数据
|
||||||
|
// 例如:
|
||||||
|
// data := [][]string{}
|
||||||
|
// data = append(data, []string{"姓名", "年龄", "城市"})
|
||||||
|
// data = append(data, []string{"1", "2", "3"})
|
||||||
|
// err := file.WriterCSVFile(data, filePath)
|
||||||
|
func WriterCSVFile(data [][]string, filePath string) error {
|
||||||
|
// 获取文件所在的目录路径
|
||||||
|
dirPath := filepath.Dir(filePath)
|
||||||
|
|
||||||
|
// 确保文件夹路径存在
|
||||||
|
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("创建文件夹失败 CreateFile %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建或打开文件
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 创建CSV编写器
|
||||||
|
writer := csv.NewWriter(file)
|
||||||
|
defer writer.Flush()
|
||||||
|
|
||||||
|
// 写入数据
|
||||||
|
for _, row := range data {
|
||||||
|
writer.Write(row)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取CSV文件,转换map数据
|
||||||
|
func ReadCSVFile(filePath string) []map[string]string {
|
||||||
|
// 创建 map 存储 CSV 数据
|
||||||
|
arr := make([]map[string]string, 0)
|
||||||
|
|
||||||
|
// 打开 CSV 文件
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("无法打开 CSV 文件:", err)
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 创建 CSV Reader
|
||||||
|
reader := csv.NewReader(file)
|
||||||
|
|
||||||
|
// 读取 CSV 头部行
|
||||||
|
header, err := reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("无法读取 CSV 头部行:", err)
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 CSV 数据行
|
||||||
|
for {
|
||||||
|
// 读取一行数据
|
||||||
|
record, err := reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
// 到达文件末尾或遇到错误时退出循环
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 CSV 数据插入到 map 中
|
||||||
|
data := make(map[string]string)
|
||||||
|
for i, value := range record {
|
||||||
|
key := strings.ToLower(header[i])
|
||||||
|
data[key] = value
|
||||||
|
}
|
||||||
|
arr = append(arr, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
49
lib/core/file/ssh.go
Normal file
49
lib/core/file/ssh.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 网元NE 文件复制到远程文件
|
||||||
|
func FileSCPLocalToNe(neIp, localPath, nePath string) error {
|
||||||
|
usernameNe := conf.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)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("FileSCPLocalToNe %s", string(out))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 网元NE 远程文件复制到本地文件
|
||||||
|
func FileSCPNeToLocal(neIp, nePath, localPath string) error {
|
||||||
|
// 获取文件所在的目录路径
|
||||||
|
dirPath := filepath.Dir(localPath)
|
||||||
|
|
||||||
|
// 确保文件夹路径存在
|
||||||
|
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("创建文件夹失败 CreateFile %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
usernameNe := conf.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)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("FileSCPNeToLocal %s", string(out))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
79
lib/core/file/txt.go
Normal file
79
lib/core/file/txt.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 写入Txt文件用,号分割 需要转换数据
|
||||||
|
// 例如:
|
||||||
|
// data := [][]string{}
|
||||||
|
// data = append(data, []string{"姓名", "年龄", "城市"})
|
||||||
|
// data = append(data, []string{"1", "2", "3"})
|
||||||
|
// err := file.WriterCSVFile(data, filePath)
|
||||||
|
func WriterTxtFile(data [][]string, filePath string) error {
|
||||||
|
// 获取文件所在的目录路径
|
||||||
|
dirPath := filepath.Dir(filePath)
|
||||||
|
|
||||||
|
// 确保文件夹路径存在
|
||||||
|
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("创建文件夹失败 CreateFile %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建或打开文件
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 创建一个 Writer 对象,用于将数据写入文件
|
||||||
|
writer := bufio.NewWriter(file)
|
||||||
|
for _, row := range data {
|
||||||
|
line := strings.Join(row, ",")
|
||||||
|
fmt.Fprintln(writer, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将缓冲区中的数据刷新到文件中
|
||||||
|
err = writer.Flush()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("刷新缓冲区时发生错误:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取Txt文件,用,号分割 转换数组数据
|
||||||
|
func ReadTxtFile(filePath string) [][]string {
|
||||||
|
// 创建 map 存储 CSV 数据
|
||||||
|
arr := make([][]string, 0)
|
||||||
|
|
||||||
|
// 打开文本文件
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("无法打开文件:", err)
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 创建一个 Scanner 对象,用于逐行读取文件内容
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
if scanner.Err() != nil {
|
||||||
|
log.Fatal("读取文件时出错:", scanner.Err())
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
fields := strings.Split(line, ",")
|
||||||
|
arr = append(arr, fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
88
lib/core/mml_client/mml_client.go
Normal file
88
lib/core/mml_client/mml_client.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package mmlclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/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)
|
||||||
|
|
||||||
|
// 发送后等待
|
||||||
|
sleepTime := conf.Get("mml.sleep").(int)
|
||||||
|
awaitTime := time.Duration(sleepTime) * time.Millisecond
|
||||||
|
time.Sleep(awaitTime)
|
||||||
|
|
||||||
|
// 读取内容
|
||||||
|
buf := make([]byte, 1024*8)
|
||||||
|
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*8)
|
||||||
|
n, err := c.reader.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
return "", fmt.Errorf("server closed the connection")
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(buf[0:n]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 封装Close函数,用于关闭TCP连接
|
||||||
|
func (c *MMLClient) Close() error {
|
||||||
|
return c.conn.Close()
|
||||||
|
}
|
||||||
104
lib/core/mml_client/send.go
Normal file
104
lib/core/mml_client/send.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
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("创建MMLClient实例失败:%v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
// 发送数据
|
||||||
|
err = client.Send(msg)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("发送数据失败:%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收数据
|
||||||
|
data, err := client.Receive()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("接收数据失败:%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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 截断
|
||||||
|
index := strings.Index(str, "\n")
|
||||||
|
if index != -1 {
|
||||||
|
str = str[:index]
|
||||||
|
str = strings.ToLower(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命令成功
|
||||||
|
if strings.Contains(str, "ok") || strings.Contains(str, "OK") {
|
||||||
|
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.Split(item, "=")
|
||||||
|
} else if strings.Contains(item, ":") {
|
||||||
|
// 按照分隔符":"进行拆分键值对
|
||||||
|
pair = strings.Split(item, ":")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pair) == 2 {
|
||||||
|
// 将键值对存入map中
|
||||||
|
m[pair[0]] = pair[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
358
lib/core/redis/redis.go
Normal file
358
lib/core/redis/redis.go
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"ems.agt/lib/core/conf"
|
||||||
|
"ems.agt/lib/log"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Redis连接实例
|
||||||
|
var rdbMap = make(map[string]*redis.Client)
|
||||||
|
|
||||||
|
// 声明定义限流脚本命令
|
||||||
|
var rateLimitCommand = redis.NewScript(`
|
||||||
|
local key = KEYS[1]
|
||||||
|
local time = tonumber(ARGV[1])
|
||||||
|
local count = tonumber(ARGV[2])
|
||||||
|
local current = redis.call('get', key);
|
||||||
|
if current and tonumber(current) >= count then
|
||||||
|
return tonumber(current);
|
||||||
|
end
|
||||||
|
current = redis.call('incr', key)
|
||||||
|
if tonumber(current) == 1 then
|
||||||
|
redis.call('expire', key, time)
|
||||||
|
end
|
||||||
|
return tonumber(current);`)
|
||||||
|
|
||||||
|
// 连接Redis实例
|
||||||
|
func Connect() {
|
||||||
|
ctx := context.Background()
|
||||||
|
// 读取数据源配置
|
||||||
|
datasource := conf.Get("redis.dataSource").(map[string]any)
|
||||||
|
for k, v := range datasource {
|
||||||
|
client := v.(map[string]any)
|
||||||
|
// 创建连接
|
||||||
|
address := fmt.Sprintf("%s:%d", client["host"], client["port"])
|
||||||
|
rdb := redis.NewClient(&redis.Options{
|
||||||
|
Addr: address,
|
||||||
|
Password: client["password"].(string),
|
||||||
|
DB: client["db"].(int),
|
||||||
|
})
|
||||||
|
// 测试数据库连接
|
||||||
|
pong, err := rdb.Ping(ctx).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed error ping redis %s %d is %v", client["host"], client["db"], err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Infof("redis %s %d %s connection is successful.", client["host"], client["db"], pong)
|
||||||
|
rdbMap[k] = rdb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭Redis实例
|
||||||
|
func Close() {
|
||||||
|
for _, rdb := range rdbMap {
|
||||||
|
if err := rdb.Close(); err != nil {
|
||||||
|
log.Errorf("fatal error db close: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取默认实例
|
||||||
|
func DefaultRDB() *redis.Client {
|
||||||
|
source := conf.Get("redis.defaultDataSourceName").(string)
|
||||||
|
return rdbMap[source]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取实例
|
||||||
|
func RDB(source string) *redis.Client {
|
||||||
|
return rdbMap[source]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info 获取redis服务信息
|
||||||
|
func Info(source string) map[string]map[string]string {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
info, err := rdb.Info(ctx).Result()
|
||||||
|
if err != nil {
|
||||||
|
return map[string]map[string]string{}
|
||||||
|
}
|
||||||
|
infoObj := make(map[string]map[string]string)
|
||||||
|
lines := strings.Split(info, "\r\n")
|
||||||
|
label := ""
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.Contains(line, "#") {
|
||||||
|
label = strings.Fields(line)[len(strings.Fields(line))-1]
|
||||||
|
label = strings.ToLower(label)
|
||||||
|
infoObj[label] = make(map[string]string)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kvArr := strings.Split(line, ":")
|
||||||
|
if len(kvArr) >= 2 {
|
||||||
|
key := strings.TrimSpace(kvArr[0])
|
||||||
|
value := strings.TrimSpace(kvArr[len(kvArr)-1])
|
||||||
|
infoObj[label][key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return infoObj
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeySize 获取redis当前连接可用键Key总数信息
|
||||||
|
func KeySize(source string) int64 {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
size, err := rdb.DBSize(ctx).Result()
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandStats 获取redis命令状态信息
|
||||||
|
func CommandStats(source string) []map[string]string {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
commandstats, err := rdb.Info(ctx, "commandstats").Result()
|
||||||
|
if err != nil {
|
||||||
|
return []map[string]string{}
|
||||||
|
}
|
||||||
|
statsObjArr := make([]map[string]string, 0)
|
||||||
|
lines := strings.Split(commandstats, "\r\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if !strings.HasPrefix(line, "cmdstat_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kvArr := strings.Split(line, ":")
|
||||||
|
key := kvArr[0]
|
||||||
|
valueStr := kvArr[len(kvArr)-1]
|
||||||
|
statsObj := make(map[string]string)
|
||||||
|
statsObj["name"] = key[8:]
|
||||||
|
statsObj["value"] = valueStr[6:strings.Index(valueStr, ",usec=")]
|
||||||
|
statsObjArr = append(statsObjArr, statsObj)
|
||||||
|
}
|
||||||
|
return statsObjArr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取键的剩余有效时间(秒)
|
||||||
|
func GetExpire(source string, key string) (float64, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ttl, err := rdb.TTL(ctx, key).Result()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return ttl.Seconds(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得缓存数据的key列表
|
||||||
|
func GetKeys(source string, pattern string) ([]string, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化变量
|
||||||
|
var keys []string
|
||||||
|
var cursor uint64 = 0
|
||||||
|
ctx := context.Background()
|
||||||
|
// 循环遍历获取匹配的键
|
||||||
|
for {
|
||||||
|
// 使用 SCAN 命令获取匹配的键
|
||||||
|
batchKeys, nextCursor, err := rdb.Scan(ctx, cursor, pattern, 100).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to scan keys: %v", err)
|
||||||
|
return keys, err
|
||||||
|
}
|
||||||
|
cursor = nextCursor
|
||||||
|
keys = append(keys, batchKeys...)
|
||||||
|
// 当 cursor 为 0,表示遍历完成
|
||||||
|
if cursor == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量获得缓存数据
|
||||||
|
func GetBatch(source string, keys []string) ([]any, error) {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return []any{}, fmt.Errorf("not keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取缓存数据
|
||||||
|
result, err := rdb.MGet(context.Background(), keys...).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get batch data: %v", err)
|
||||||
|
return []any{}, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得缓存数据
|
||||||
|
func Get(source, key string) (string, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
value, err := rdb.Get(ctx, key).Result()
|
||||||
|
if err == redis.Nil || err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得缓存数据Hash
|
||||||
|
func GetHash(source, key string) (map[string]string, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
value, err := rdb.HGetAll(ctx, key).Result()
|
||||||
|
if err == redis.Nil || err != nil {
|
||||||
|
return map[string]string{}, err
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否存在
|
||||||
|
func Has(source string, keys ...string) (bool, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
exists, err := rdb.Exists(ctx, keys...).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return exists >= 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置缓存数据
|
||||||
|
func Set(source, key string, value any) (bool, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
err := rdb.Set(ctx, key, value, 0).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("redis lua script err %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置缓存数据与过期时间
|
||||||
|
func SetByExpire(source, key string, value any, expiration time.Duration) (bool, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
err := rdb.Set(ctx, key, value, expiration).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("redis lua script err %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除单个
|
||||||
|
func Del(source string, key string) (bool, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
err := rdb.Del(ctx, key).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("redis lua script err %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除多个
|
||||||
|
func DelKeys(source string, keys []string) (bool, error) {
|
||||||
|
if len(keys) == 0 {
|
||||||
|
return false, fmt.Errorf("no keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
err := rdb.Del(ctx, keys...).Err()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("redis lua script err %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限流查询并记录
|
||||||
|
func RateLimit(source, limitKey string, time, count int64) (int64, error) {
|
||||||
|
// 数据源
|
||||||
|
rdb := DefaultRDB()
|
||||||
|
if source != "" {
|
||||||
|
rdb = RDB(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
result, err := rateLimitCommand.Run(ctx, rdb, []string{limitKey}, time, count).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("redis lua script err %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return result.(int64), err
|
||||||
|
}
|
||||||
20
lib/core/utils/crypto/crypto.go
Normal file
20
lib/core/utils/crypto/crypto.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BcryptHash Bcrypt密码加密
|
||||||
|
func BcryptHash(originStr string) string {
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(originStr), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BcryptCompare Bcrypt密码匹配检查
|
||||||
|
func BcryptCompare(originStr, hashStr string) bool {
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(hashStr), []byte(originStr))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user