add: 提交

This commit is contained in:
lichang
2023-08-14 17:02:50 +08:00
parent 897d45d443
commit 5ac2e981ea
163 changed files with 29466 additions and 0 deletions

64
lib/aes/aes.go Normal file
View 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)]
}

92
lib/cache/badger_db/badger_db.go vendored Normal file
View File

@@ -0,0 +1,92 @@
package badger_db
import (
"fmt"
"time"
"github.com/dgraph-io/badger/v4"
"github.com/pkg/errors"
)
type Cache struct {
db *badger.DB
}
func NewCacheDB(db *badger.DB) *Cache {
return &Cache{
db: db,
}
}
func (c *Cache) SetNX(key string, value interface{}) error {
err := c.db.Update(func(txn *badger.Txn) error {
_, err := txn.Get([]byte(key))
if errors.Is(err, badger.ErrKeyNotFound) {
v := []byte(fmt.Sprintf("%v", value))
return txn.Set([]byte(key), v)
}
return err
})
return err
}
func (c *Cache) Set(key string, value interface{}) error {
err := c.db.Update(func(txn *badger.Txn) error {
v := []byte(fmt.Sprintf("%v", value))
return txn.Set([]byte(key), v)
})
return err
}
func (c *Cache) Del(key string) error {
err := c.db.Update(func(txn *badger.Txn) error {
return txn.Delete([]byte(key))
})
return err
}
func (c *Cache) Clean() error {
return c.db.DropAll()
}
func (c *Cache) Get(key string) ([]byte, error) {
var result []byte
err := c.db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte(key))
if err != nil {
return err
}
err = item.Value(func(val []byte) error {
result = append([]byte{}, val...)
return nil
})
return err
})
return result, err
}
func (c *Cache) SetWithTTL(key string, value interface{}, duration time.Duration) error {
err := c.db.Update(func(txn *badger.Txn) error {
v := []byte(fmt.Sprintf("%v", value))
e := badger.NewEntry([]byte(key), v).WithTTL(duration)
return txn.SetEntry(e)
})
return err
}
func (c *Cache) PrefixScanKey(prefixStr string) ([]string, error) {
var res []string
err := c.db.View(func(txn *badger.Txn) error {
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
prefix := []byte(prefixStr)
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
k := item.Key()
res = append(res, string(k))
return nil
}
return nil
})
return res, err
}

55
lib/cache/cache.go vendored Normal file
View File

@@ -0,0 +1,55 @@
package cache
import (
"time"
"ems.agt/lib/cache/badger_db"
"ems.agt/lib/log"
"github.com/dgraph-io/badger/v4"
)
var CACHE *badger_db.Cache
func Init() {
options := badger.Options{
Dir: "tmp/badger",
ValueDir: "tmp/badger",
ValueLogFileSize: 64 << 20,
ValueLogMaxEntries: 10 << 20,
VLogPercentile: 0.1,
MemTableSize: 32 << 20,
BaseTableSize: 2 << 20,
BaseLevelSize: 10 << 20,
TableSizeMultiplier: 2,
LevelSizeMultiplier: 10,
MaxLevels: 7,
NumGoroutines: 4,
MetricsEnabled: true,
NumCompactors: 2,
NumLevelZeroTables: 5,
NumLevelZeroTablesStall: 15,
NumMemtables: 1,
BloomFalsePositive: 0.01,
BlockSize: 2 * 1024,
SyncWrites: false,
NumVersionsToKeep: 1,
CompactL0OnClose: false,
VerifyValueChecksum: false,
BlockCacheSize: 32 << 20,
IndexCacheSize: 0,
ZSTDCompressionLevel: 1,
EncryptionKey: []byte{},
EncryptionKeyRotationDuration: 10 * 24 * time.Hour, // Default 10 days.
DetectConflicts: true,
NamespaceOffset: -1,
}
cache, err := badger.Open(options)
if err != nil {
log.Errorf("failed to badger init cache:", err)
}
CACHE = badger_db.NewCacheDB(cache)
log.Info("init cache successfully")
}

1412
lib/dborm/dborm.go Normal file

File diff suppressed because it is too large Load Diff

120
lib/file/file.go Normal file
View File

@@ -0,0 +1,120 @@
package file
import (
"encoding/json"
"fmt"
"io"
"net"
"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/gorilla/mux"
)
const (
//经过测试linux下延时需要大于100ms
TIME_DELAY_AFTER_WRITE = 200
)
type Response struct {
Data []string `json:"data"`
}
type MMLRequest struct {
MML []string `json:"mml"`
}
func GetFile(w http.ResponseWriter, r *http.Request) {
log.Debug("PostMMLToNF processing... ")
vars := mux.Vars(r)
neType := vars["elementTypeValue"]
params := r.URL.Query()
neId := params["ne_id"]
log.Debug("neType:", neType, "neId", neId)
neInfo := new(dborm.NeInfo)
var err error
if len(neId) == 0 {
log.Error("ne_id NOT FOUND")
services.ResponseBadRequest400WrongParamValue(w)
return
}
neInfo, err = dborm.XormGetNeInfo(neType, neId[0])
if err != nil {
log.Error("dborm.XormGetNeInfo is failed:", err)
services.ResponseInternalServerError500DatabaseOperationFailed(w)
return
}
var buf [8192]byte
var n int
var mmlResult []string
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)
}

58
lib/global/global.go Normal file
View File

@@ -0,0 +1,58 @@
package global
import "errors"
// 跨package引用的首字母大写
const (
RequestBodyMaxLen = 2000000
ApiVersionV1 = "v1"
ApiVersionV2 = "v2"
LineBreak = "\n"
)
const (
DateTime = "2006-01-02 15:04:05"
DateData = "20060102150405"
DateHour = "2006010215"
)
const (
MaxInt32Number = 2147483647
)
const (
MaxLimitData = 1000
)
var (
Version string
BuildTime string
GoVer string
)
var (
ErrParamsNotAdapted = errors.New("the number of params is not adapted")
// PM module error message
ErrPMNotFoundData = errors.New("not found PM data")
// CM module error message
ErrCMNotFoundTargetNE = errors.New("not found target NE")
ErrCMCannotDeleteActiveNE = errors.New("can not delete an active NE")
ErrCMInvalidBackupFile = errors.New("invalid backup file")
ErrCMNotMatchMD5File = errors.New("md5 not match between file and url")
ErrCMNotMatchSignFile = errors.New("digests signatures not match in the file")
ErrCMExistSoftwareFile = errors.New("exist the same software package file")
ErrCMNotFoundTargetSoftware = errors.New("not found the target software package")
ErrCMNotFoundTargetNeVersion = errors.New("not found the target NE version")
ErrCMNotFoundRollbackNeVersion = errors.New("not found the rollback NE version")
ErrCMNotFoundTargetBackupFile = errors.New("not found the target NE backup")
// TRACE module error message
ErrTraceFailedDistributeToNEs = errors.New("failed to distribute trace task to target NEs")
ErrTraceNotCarriedTaskID = errors.New("not carried task id in request url")
// MML module error define
ErrMmlInvalidCommandFormat = errors.New("invalid mml command format")
)

479
lib/global/kits.go Normal file
View File

@@ -0,0 +1,479 @@
package global
import (
"bytes"
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
"time"
)
const (
IsIPv4 = "IPv4"
IsIPv6 = "IPv6"
NonIP = "NonIp"
)
type em struct{}
func GetPkgName() string {
return reflect.TypeOf(em{}).PkgPath()
}
// interface{} change to map[string]interface{}
// interface{} data is []interface{}
func ListToMap(list interface{}, key string) map[string]interface{} {
res := make(map[string]interface{})
arr := ToSlice(list)
for _, row := range arr {
immutable := reflect.ValueOf(row)
val := immutable.FieldByName(key).String()
res[val] = row
}
return res
}
// interface{} change to []interface{}
func ToSlice(arr interface{}) []interface{} {
ret := make([]interface{}, 0)
v := reflect.ValueOf(arr)
if v.Kind() != reflect.Slice {
ret = append(ret, arr)
return ret
}
l := v.Len()
for i := 0; i < l; i++ {
ret = append(ret, v.Index(i).Interface())
}
return ret
}
var TodoList []Todo
type Todo struct {
Id int64
Item string
}
// JSON序列化方式
func jsonStructToMap(TodoList Todo) (map[string]interface{}, error) {
// 结构体转json
strRet, err := json.Marshal(TodoList)
if err != nil {
return nil, err
}
// json转map
var mRet map[string]interface{}
err1 := json.Unmarshal(strRet, &mRet)
if err1 != nil {
return nil, err1
}
return mRet, nil
}
func IsContain(item string, items []string) bool {
for _, e := range items {
if e == item {
return true
}
}
return false
}
func IsContainP(item string, items *[]string, size int) bool {
for i := 0; i < size; i++ {
if (*items)[i] == item {
return true
}
}
return false
}
// 将字符串 分割成 字符串数组
// @s分割符
func SplitString(str string, s string) []string {
sa := strings.Split(str, s)
return sa
}
//  合并字符串数组
func MergeStringArr(a, b []string) []string {
var arr []string
for _, i := range a {
arr = append(arr, i)
}
for _, j := range b {
arr = append(arr, j)
}
return arr
}
// 数组去重
func UniqueStringArr(m []string) []string {
d := make([]string, 0)
tempMap := make(map[string]bool, len(m))
for _, v := range m { // 以值作为键名
if tempMap[v] == false {
tempMap[v] = true
d = append(d, v)
}
}
return d
}
//  合并整型数组
func MergeArr(a, b []int) []int {
var arr []int
for _, i := range a {
arr = append(arr, i)
}
for _, j := range b {
arr = append(arr, j)
}
return arr
}
// 数组去重
func UniqueArr(m []int) []int {
d := make([]int, 0)
tempMap := make(map[int]bool, len(m))
for _, v := range m { // 以值作为键名
if tempMap[v] == false {
tempMap[v] = true
d = append(d, v)
}
}
return d
}
// 升序
func AscArr(e []int) []int {
sort.Ints(e[:])
return e
}
// 降序
func DescArr(e []int) []int {
sort.Sort(sort.Reverse(sort.IntSlice(e)))
return e
}
func MatchRmUID(p string, s string) bool {
match, _ := regexp.MatchString(p, s)
return match
}
type OrderedMap struct {
Order []string
Map map[string]interface{}
}
func (om *OrderedMap) UnmarshalJson(b []byte) error {
json.Unmarshal(b, &om.Map)
index := make(map[string]int)
for key := range om.Map {
om.Order = append(om.Order, key)
esc, _ := json.Marshal(key) //Escape the key
index[key] = bytes.Index(b, esc)
}
sort.Slice(om.Order, func(i, j int) bool { return index[om.Order[i]] < index[om.Order[j]] })
return nil
}
func (om OrderedMap) MarshalJson() ([]byte, error) {
var b []byte
buf := bytes.NewBuffer(b)
buf.WriteRune('{')
l := len(om.Order)
for i, key := range om.Order {
km, err := json.Marshal(key)
if err != nil {
return nil, err
}
buf.Write(km)
buf.WriteRune(':')
vm, err := json.Marshal(om.Map[key])
if err != nil {
return nil, err
}
buf.Write(vm)
if i != l-1 {
buf.WriteRune(',')
}
fmt.Println(buf.String())
}
buf.WriteRune('}')
fmt.Println(buf.String())
return buf.Bytes(), nil
}
func GetBodyCopy(r *http.Request) (*bytes.Buffer, error) {
// If r.bodyBuf present, return the copy
// if r.bodyBuf != nil {
// return bytes.NewBuffer(r.bodyBuf.Bytes()), nil
// }
// Maybe body is `io.Reader`.
// Note: Resty user have to watchout for large body size of `io.Reader`
if r.Body != nil {
b, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
// Restore the Body
// close(r.Body)
r.Body = io.NopCloser(bytes.NewReader(b))
// Return the Body bytes
return bytes.NewBuffer(b), nil
}
return nil, nil
}
func UnmarshalBody(r *http.Request, v *interface{}, maxLen int64) error {
body, err := io.ReadAll(io.LimitReader(r.Body, maxLen))
if err != nil {
return err
}
return json.Unmarshal(body, v)
}
func SetNotifyUrl(ip string, port uint16, uri string) string {
return fmt.Sprintf("http://%s:%d%s", ip, port, uri)
}
func GetIps() (ips []string, err error) {
interfaceAddr, err := net.InterfaceAddrs()
if err != nil {
return ips, err
}
for _, address := range interfaceAddr {
ipNet, isVailIpNet := address.(*net.IPNet)
// 检查ip地址判断是否回环地址
if isVailIpNet && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ips = append(ips, ipNet.IP.String())
}
}
}
return ips, nil
}
func GetCurrentTimeSliceIndexByPeriod(t time.Time, period int) int {
index := int((t.Hour()*60+t.Minute())/period) - 1
if index < 0 {
return int(24*60/period) - 1
}
return index
}
var (
cst *time.Location
)
// RFC3339ToDateTime convert rfc3339 value to china standard time layout
func RFC3339ToDateTime(value string) (string, error) {
ts, err := time.Parse(time.RFC3339, value)
if err != nil {
return "", err
}
return ts.In(cst).Format("2006-01-02 15:04:05"), nil
}
// CreateTimeDir 根据当前时间格式来创建文件夹
func CreateTimeDir(fmt string, path string) string {
folderName := time.Now().Format(fmt)
folderPath := filepath.Join(path, folderName)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
// 必须分成两步:先创建文件夹、再修改权限
os.Mkdir(folderPath, 0664) //0644也可以os.ModePerm
os.Chmod(folderPath, 0664)
}
return folderPath
}
// CreateDir 根据传入的目录名和路径来创建文件夹
func CreateDir(folderName string, path string) string {
folderPath := filepath.Join(path, folderName)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
// 必须分成两步:先创建文件夹、再修改权限
os.Mkdir(folderPath, 0664) //0644也可以os.ModePerm
os.Chmod(folderPath, 0664)
}
return folderPath
}
func GetFmtTimeString(srcFmt string, timeString string, dstFmt string) string {
t, _ := time.ParseInLocation(srcFmt, timeString, time.Local)
return t.Format(dstFmt)
}
func GetFileMD5Sum(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
md5 := md5.New()
_, err = io.Copy(md5, file)
if err != nil {
return "", err
}
md5str := hex.EncodeToString(md5.Sum(nil))
return md5str, nil
}
// PathExists check path is exist or no
func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil { //文件或者目录存在
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
func GetDayDuration(d1, d2 string) int64 {
a, _ := time.Parse("2006-01-02", d1)
b, _ := time.Parse("2006-01-02", d2)
d := a.Sub(b)
return (int64)(d.Hours() / 24)
}
func GetSecondsSinceDatetime(datetimeStr string) (int64, error) {
loc1, _ := time.LoadLocation("Local")
// 解析日期时间字符串为时间对象
datetime, err := time.ParseInLocation(time.DateTime, datetimeStr, loc1)
if err != nil {
return 0, err
}
// 计算时间差
duration := time.Since(datetime)
// 获取时间差的秒数
seconds := int64(duration.Seconds())
return seconds, nil
}
// 0: invalid ip
// 4: IPv4
// 6: IPv6
func ParseIP(s string) (net.IP, int) {
ip := net.ParseIP(s)
if ip == nil {
return nil, 0
}
for i := 0; i < len(s); i++ {
switch s[i] {
case '.':
return ip, 4
case ':':
return ip, 6
}
}
return nil, 0
}
func BytesCombine1(pBytes ...[]byte) []byte {
return bytes.Join(pBytes, []byte(""))
}
func BytesCombine(pBytes ...[]byte) []byte {
length := len(pBytes)
s := make([][]byte, length)
for index := 0; index < length; index++ {
s[index] = pBytes[index]
}
sep := []byte("")
return bytes.Join(s, sep)
}
func ParseIPAddr(ip string) string {
ipAddr := net.ParseIP(ip)
if ipAddr != nil {
if ipAddr.To4() != nil {
return IsIPv4
} else {
return IsIPv6
}
}
return NonIP
}
func CombineHostUri(ip string, port string) string {
var hostUri string = ""
ipType := ParseIPAddr(ip)
if ipType == IsIPv4 {
hostUri = fmt.Sprintf("http://%s:%v", ip, port)
} else {
hostUri = fmt.Sprintf("http://[%s]:%v", ip, port)
}
return hostUri
}
func StructToMap(obj interface{}) map[string]interface{} {
objValue := reflect.ValueOf(obj)
objType := objValue.Type()
m := make(map[string]interface{})
for i := 0; i < objValue.NumField(); i++ {
field := objValue.Field(i)
fieldName := objType.Field(i).Name
m[fieldName] = field.Interface()
}
return m
}
// ToMap 结构体转为Map[string]interface{}
func ToMap(in interface{}, tagName string) (map[string]interface{}, error) {
out := make(map[string]interface{})
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct { // 非结构体返回错误提示
return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
}
t := v.Type()
// 遍历结构体字段
// 指定tagName值为map中key;字段值为map中value
for i := 0; i < v.NumField(); i++ {
fi := t.Field(i)
if tagValue := fi.Tag.Get(tagName); tagValue != "" {
out[tagValue] = v.Field(i).Interface()
}
}
return out, nil
}

337
lib/log/logger.go Normal file
View File

@@ -0,0 +1,337 @@
// logger for omc/ems
package log
import (
"fmt"
"io"
"log"
)
// LogLevel defines a log level
type LogLevel int
// enum all LogLevels
const (
// following level also match syslog.Priority value
LOG_TRACE LogLevel = iota
LOG_DEBUG
LOG_INFO
LOG_WARN
LOG_ERROR
LOG_FATAL
LOG_OFF
LOG_NODEF
)
// default log options
const (
DEFAULT_LOG_PREFIX = "omc"
DEFAULT_LOG_FLAG = log.Lshortfile | log.Ldate | log.Lmicroseconds
DEFAULT_LOG_LEVEL = LOG_DEBUG
DEFAULT_CALL_DEPTH = 3
)
// Logger is a logger interface
type Logger interface {
Fatal(v ...interface{})
Fatalf(format string, v ...interface{})
Error(v ...interface{})
Errorf(format string, v ...interface{})
Warn(v ...interface{})
Warnf(format string, v ...interface{})
Info(v ...interface{})
Infof(format string, v ...interface{})
Debug(v ...interface{})
Debugf(format string, v ...interface{})
Trace(v ...interface{})
Tracef(format string, v ...interface{})
Level() LogLevel
LevelString() string
SetLevel(l LogLevel)
}
var _ Logger = DiscardLogger{}
// DiscardLogger don't log implementation for ILogger
type DiscardLogger struct{}
// Trace empty implementation
func (DiscardLogger) Trace(v ...interface{}) {}
// Tracef empty implementation
func (DiscardLogger) Tracef(format string, v ...interface{}) {}
// Debug empty implementation
func (DiscardLogger) Debug(v ...interface{}) {}
// Debugf empty implementation
func (DiscardLogger) Debugf(format string, v ...interface{}) {}
// Info empty implementation
func (DiscardLogger) Info(v ...interface{}) {}
// Infof empty implementation
func (DiscardLogger) Infof(format string, v ...interface{}) {}
// Warn empty implementation
func (DiscardLogger) Warn(v ...interface{}) {}
// Warnf empty implementation
func (DiscardLogger) Warnf(format string, v ...interface{}) {}
// Error empty implementation
func (DiscardLogger) Error(v ...interface{}) {}
// Errorf empty implementation
func (DiscardLogger) Errorf(format string, v ...interface{}) {}
// Fatal empty implementation
func (DiscardLogger) Fatal(v ...interface{}) {}
// Fatalf empty implementation
func (DiscardLogger) Fatalf(format string, v ...interface{}) {}
// Level empty implementation
func (DiscardLogger) Level() LogLevel {
return LOG_NODEF
}
// Level empty implementation
func (DiscardLogger) LevelString() string {
return ""
}
// SetLevel empty implementation
func (DiscardLogger) SetLevel(l LogLevel) {}
// EmsLogger is the default implment of ILogger
type EmsLogger struct {
TRACE *log.Logger
DEBUG *log.Logger
INFO *log.Logger
WARN *log.Logger
ERROR *log.Logger
FATAL *log.Logger
level LogLevel
levelString []string
depth int
}
var _ Logger = &EmsLogger{}
// NewEmsLogger use a special io.Writer as logger output
func NewEmsLogger(out io.Writer) *EmsLogger {
return NewEmsLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG)
}
// NewEmsLogger2 let you customrize your logger prefix and flag
func NewEmsLogger2(out io.Writer, prefix string, flag int) *EmsLogger {
return NewEmsLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL)
}
// NewEmsLogger3 let you customrize your logger prefix and flag and logLevel
func NewEmsLogger3(out io.Writer, prefix string, flag int, l LogLevel) *EmsLogger {
return &EmsLogger{
TRACE: log.New(out, fmt.Sprintf("[%s] [trace] ", prefix), flag),
DEBUG: log.New(out, fmt.Sprintf("[%s] [debug] ", prefix), flag),
INFO: log.New(out, fmt.Sprintf("[%s] [info ] ", prefix), flag),
WARN: log.New(out, fmt.Sprintf("[%s] [warn ] ", prefix), flag),
ERROR: log.New(out, fmt.Sprintf("[%s] [error] ", prefix), flag),
FATAL: log.New(out, fmt.Sprintf("[%s] [fatal] ", prefix), flag),
level: l,
levelString: []string{"trace", "debug", "info", "warn", "error", "fatal"},
depth: DEFAULT_CALL_DEPTH,
}
}
// Trace implement ILogger
func (s *EmsLogger) Trace(v ...interface{}) {
if s.level <= LOG_TRACE {
_ = s.TRACE.Output(s.depth, fmt.Sprintln(v...))
}
}
// Tracef implement ILogger
func (s *EmsLogger) Tracef(format string, v ...interface{}) {
if s.level <= LOG_TRACE {
_ = s.TRACE.Output(s.depth, fmt.Sprintf(format, v...))
}
}
// Debug implement ILogger
func (s *EmsLogger) Debug(v ...interface{}) {
if s.level <= LOG_DEBUG {
_ = s.DEBUG.Output(s.depth, fmt.Sprintln(v...))
}
}
// Debugf implement ILogger
func (s *EmsLogger) Debugf(format string, v ...interface{}) {
if s.level <= LOG_DEBUG {
_ = s.DEBUG.Output(s.depth, fmt.Sprintf(format, v...))
}
}
// Info implement ILogger
func (s *EmsLogger) Info(v ...interface{}) {
if s.level <= LOG_INFO {
_ = s.INFO.Output(s.depth, fmt.Sprintln(v...))
}
}
// Infof implement ILogger
func (s *EmsLogger) Infof(format string, v ...interface{}) {
if s.level <= LOG_INFO {
_ = s.INFO.Output(s.depth, fmt.Sprintf(format, v...))
}
}
// Warn implement ILogger
func (s *EmsLogger) Warn(v ...interface{}) {
if s.level <= LOG_WARN {
_ = s.WARN.Output(s.depth, fmt.Sprintln(v...))
}
}
// Warnf implement ILogger
func (s *EmsLogger) Warnf(format string, v ...interface{}) {
if s.level <= LOG_WARN {
_ = s.WARN.Output(s.depth, fmt.Sprintf(format, v...))
}
}
// Error implement ILogger
func (s *EmsLogger) Error(v ...interface{}) {
if s.level <= LOG_ERROR {
_ = s.ERROR.Output(s.depth, fmt.Sprintln(v...))
}
}
// Errorf implement ILogger
func (s *EmsLogger) Errorf(format string, v ...interface{}) {
if s.level <= LOG_ERROR {
_ = s.ERROR.Output(s.depth, fmt.Sprintf(format, v...))
}
}
// Warn implement ILogger
func (s *EmsLogger) Fatal(v ...interface{}) {
if s.level <= LOG_FATAL {
_ = s.FATAL.Output(s.depth, fmt.Sprintln(v...))
}
}
// Warnf implement ILogger
func (s *EmsLogger) Fatalf(format string, v ...interface{}) {
if s.level <= LOG_FATAL {
_ = s.FATAL.Output(s.depth, fmt.Sprintf(format, v...))
}
}
// Level implement ILogger
func (s *EmsLogger) Level() LogLevel {
return s.level
}
// Level implement ILogger
func (s *EmsLogger) LevelString() string {
return s.levelString[s.level]
}
// SetLevel implement ILogger
func (s *EmsLogger) SetLevel(l LogLevel) {
s.level = l
}
var Elogger Logger
func InitLogger(logFile string, period int, count int, prefix string, logLevel LogLevel) {
/*
logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
if err != nil {
panic(err)
}
*/
logWriter := getLogWriter(logFile, period, count)
Elogger = NewEmsLogger3(logWriter, prefix, DEFAULT_LOG_FLAG, logLevel)
fmt.Printf("logFile=%s, period=%d, count=%d, prefix=%s, logLevel=%s\n", logFile, period, count, prefix, GetLevelString())
}
// Trace implement ILogger
func Trace(v ...interface{}) {
Elogger.Trace(v...)
}
// Tracef implement ILogger
func Tracef(format string, v ...interface{}) {
Elogger.Tracef(format, v...)
}
// Debug implement ILogger
func Debug(v ...interface{}) {
Elogger.Debug(v...)
}
// Debugf implement ILogger
func Debugf(format string, v ...interface{}) {
Elogger.Debugf(format, v...)
}
// Info implement ILogger
func Info(v ...interface{}) {
Elogger.Info(v...)
}
// Infof implement ILogger
func Infof(format string, v ...interface{}) {
Elogger.Infof(format, v...)
}
// Warn implement ILogger
func Warn(v ...interface{}) {
Elogger.Warn(v...)
}
// Warnf implement ILogger
func Warnf(format string, v ...interface{}) {
Elogger.Warnf(format, v...)
}
// Error implement ILogger
func Error(v ...interface{}) {
Elogger.Error(v...)
}
// Errorf implement ILogger
func Errorf(format string, v ...interface{}) {
Elogger.Errorf(format, v...)
}
// Warn implement ILogger
func Fatal(v ...interface{}) {
Elogger.Fatal(v...)
}
// Warnf implement ILogger
func Fatalf(format string, v ...interface{}) {
Elogger.Fatalf(format, v...)
}
// Level implement ILogger
func GetLevel() LogLevel {
return Elogger.Level()
}
// Level implement ILogger
func GetLevelString() string {
return Elogger.LevelString()
}
// SetLevel implement ILogger
func SetLevel(l LogLevel) {
Elogger.SetLevel(l)
}

71
lib/log/partition.go Normal file
View File

@@ -0,0 +1,71 @@
package log
import (
"io"
"time"
rotatelogs "github.com/lestrrat/go-file-rotatelogs"
)
type WriteSyncer interface {
io.Writer
Sync() error
}
// 得到LogWriter
func getLogWriter(filePath string, period, count int) WriteSyncer {
warnIoWriter := getWriter(filePath, period, count)
return addSync(warnIoWriter)
}
// 日志文件切割
func getWriter(filename string, period, count int) io.Writer {
// 保存日志count天每period小时分割一次日志
duration := time.Hour * time.Duration(period)
var logfile string
if period >= 24 {
logfile = filename + "-%Y%m%d"
} else {
logfile = filename + "-%Y%m%d%H"
}
hook, err := rotatelogs.New(
logfile,
rotatelogs.WithLinkName(filename),
// rotatelogs.WithMaxAge(duration),
rotatelogs.WithRotationCount(count),
rotatelogs.WithRotationTime(duration),
rotatelogs.WithLocation(time.Local),
)
//保存日志30天每1分钟分割一次日志
/*
hook, err := rotatelogs.New(
filename+"_%Y%m%d%H%M.log",
rotatelogs.WithLinkName(filename),
rotatelogs.WithMaxAge(time.Hour*24*30),
rotatelogs.WithRotationTime(time.Minute*1),
)
*/
if err != nil {
panic(err)
}
return hook
}
func addSync(w io.Writer) WriteSyncer {
switch w := w.(type) {
case WriteSyncer:
return w
default:
return writerWrapper{w}
}
}
type writerWrapper struct {
io.Writer
}
func (w writerWrapper) Sync() error {
return nil
}

89
lib/log/syslogger.go.bak Normal file
View File

@@ -0,0 +1,89 @@
//go:build !windows && !nacl && !plan9
// +build !windows,!nacl,!plan9
package log
import (
"fmt"
"log/syslog"
)
var _ Logger = &SyslogLogger{}
// SyslogLogger will be depricated
type SyslogLogger struct {
w *syslog.Writer
}
// NewSyslogLogger implements Logger
func NewSyslogLogger(w *syslog.Writer) *SyslogLogger {
return &SyslogLogger{w: w}
}
// Trace log content as Trace
func (s *SyslogLogger) Trace(v ...interface{}) {
_ = s.w.Trace(fmt.Sprint(v...))
}
// Tracef log content as Trace and format
func (s *SyslogLogger) Tracef(format string, v ...interface{}) {
_ = s.w.Trace(fmt.Sprintf(format, v...))
}
// Debug log content as Debug
func (s *SyslogLogger) Debug(v ...interface{}) {
_ = s.w.Debug(fmt.Sprint(v...))
}
// Debugf log content as Debug and format
func (s *SyslogLogger) Debugf(format string, v ...interface{}) {
_ = s.w.Debug(fmt.Sprintf(format, v...))
}
// Error log content as Error
func (s *SyslogLogger) Error(v ...interface{}) {
_ = s.w.Err(fmt.Sprint(v...))
}
// Errorf log content as Errorf and format
func (s *SyslogLogger) Errorf(format string, v ...interface{}) {
_ = s.w.Err(fmt.Sprintf(format, v...))
}
// Info log content as Info
func (s *SyslogLogger) Info(v ...interface{}) {
_ = s.w.Info(fmt.Sprint(v...))
}
// Infof log content as Infof and format
func (s *SyslogLogger) Infof(format string, v ...interface{}) {
_ = s.w.Info(fmt.Sprintf(format, v...))
}
// Warn log content as Warn
func (s *SyslogLogger) Warn(v ...interface{}) {
_ = s.w.Warn(fmt.Sprint(v...))
}
// Warnf log content as Warnf and format
func (s *SyslogLogger) Warnf(format string, v ...interface{}) {
_ = s.w.Warn(fmt.Sprintf(format, v...))
}
// Fatal log content as Fatal
func (s *SyslogLogger) Fatal(v ...interface{}) {
_ = s.w.Fatal(fmt.Sprint(v...))
}
// Fatalf log content as Fatalf and format
func (s *SyslogLogger) Fatalf(format string, v ...interface{}) {
_ = s.w.Fatal(fmt.Sprintf(format, v...))
}
// Level shows log level
func (s *SyslogLogger) Level() LogLevel {
return LOG_NODEF
}
// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created
func (s *SyslogLogger) SetLevel(l LogLevel) {}

30
lib/midware/midhandle.go Normal file
View File

@@ -0,0 +1,30 @@
package midware
import (
"net/http"
"ems.agt/lib/log"
)
func LoggerTraceMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do stuff here
log.Trace("Http Trace Info:")
log.Trace(" From Host:", r.RemoteAddr)
log.Trace(" To Host:", r.Host)
log.Debug(" RequestUri:", r.RequestURI)
log.Trace(" Method:", r.Method)
log.Trace(" Proto:", r.Proto)
log.Trace(" ContentLength:", r.ContentLength)
log.Trace(" User-Agent:", r.Header.Get("User-Agent"))
log.Trace(" Content-Type:", r.Header.Get("Content-Type"))
log.Trace(" AccessToken:", r.Header.Get("AccessToken"))
log.Trace("Trace End=====")
//body, _ := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
// nop-close to ready r.Body !!!
//r.Body = ioutil.NopCloser(bytes.NewReader(body))
//log.Trace("Body:", string(body))
// Call the next handler, which can be another middleware in the chain, or the final handler.
next.ServeHTTP(w, r)
})
}

900
lib/mmlp/parse.go Normal file
View File

@@ -0,0 +1,900 @@
package mmlp
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"net/http"
"regexp"
"strconv"
"strings"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"github.com/go-resty/resty/v2"
)
type Param struct {
Name string `json:"name"`
Value string `json:"value"`
}
type MmlCommand struct {
Operation string `json:"operation"`
Object string `json:"object"`
Params []Param `json:"params"`
PaList []string `json:"paList"`
AaList []string `json:"aaList"`
AaMap map[string]interface{} `json:"aaMap"`
NaMap map[string]interface{} `json:"naMap"`
AaUri []string `json:"aaUri"`
AaLoc []string `json:"aaLoc"` // for loc parameter
}
type MmlVar struct {
Version string `json:"version"`
Output string `json:"output"`
Limit int `json:"limit"`
User string `json:"user"`
SessionToken string `josn:"sessionToken"`
HttpUri string `json:"httpUri"`
UserAgent string `json:"userAgent"`
}
// func init() {
// OmcMmlVar = &MmlVar{
// Version: "16.1.1",
// Output: DefaultFormatType,
// Limit: 50,
// }
// }
// func SetOmcMmlVarOutput(output string) {
// OmcMmlVar.Output = output
// }
// func SetOmcMmlVarLimit(limit int) {
// OmcMmlVar.Limit = limit
// }
func splitByColon(str string) []string {
return splitBy(str, ':')
}
func splitByComma(str string) []string {
return splitBy(str, ',')
}
func splitBy(str string, sep rune) []string {
var result []string
var stack []string
var current []rune
var quotes, apoFlag bool = false, false
for _, c := range str {
if c == '{' || c == '[' || (c == '\'' && apoFlag == false) || (c == '"' && quotes == false) { // "'"
apoFlag = true
quotes = true
stack = append(stack, string(c))
} else if c == '}' || c == ']' || (c == '\'' && apoFlag == true) || (c == '"' && quotes == true) {
apoFlag = false
quotes = false
if len(stack) > 0 {
stack = stack[:len(stack)-1]
}
}
if c == sep && len(stack) == 0 {
result = append(result, string(current))
current = []rune{}
} else {
current = append(current, c)
}
}
result = append(result, string(current))
return result
}
func ParseMMLCommand(mmlStr string, mmlComms *[]MmlCommand) error {
log.Info("ParseMMLCommand processing ...")
log.Debug("mmlStr: ", mmlStr)
mc := new(MmlCommand)
reg := regexp.MustCompile(`\s*;\s*`)
mmls := reg.Split(mmlStr, -1)
for _, mml := range mmls {
log.Trace("mml:", mml)
if len(mml) == 0 {
continue
}
//reg := regexp.MustCompile(`\s*:\s*`)
//ms := reg.Split(mml, -1)
ms := splitByColon(mml)
if len(ms) < 1 || len(ms) > 2 {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
if len(ms) == 2 {
cmd := strings.Trim(ms[0], " ")
reg = regexp.MustCompile(`\s+`)
cs := reg.Split(cmd, -1)
//cs := strings.Split(cmd, " ")
if len(cs) == 2 {
mc.Operation = cs[0]
mc.Object = cs[1]
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
//reg = regexp.MustCompile(`\s*,\s*`)
//reg = regexp.MustCompile(`(?U)(?<!\{[^{}]*),(?![^{}]*\})|(?<!\"[^\"]*),(?![^\"]*\")|(?<!\[[^\[\]]*),(?![^\[\]]*\])`)
//reg = regexp.MustCompile(`,[^'"\(\)]+`)
//params := reg.Split(ms[1], -1)
params := splitByComma(strings.Trim(ms[1], " "))
//params := strings.Split(ms[1], ",")
for _, p := range params {
log.Trace("p:", p)
if p == "" {
continue
}
mc.PaList = append(mc.PaList, p)
reg = regexp.MustCompile(`\s*=\s*`)
pvs := reg.Split(p, -1)
log.Trace("pvs:", pvs)
if len(pvs) == 2 {
mc.Params = append(mc.Params, Param{Name: pvs[0], Value: pvs[1]})
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
}
} else if len(ms) == 1 {
cmd := ms[0]
reg = regexp.MustCompile(`\s+`)
cs := reg.Split(cmd, -1)
//cs := strings.Split(cmd, " ")
if len(cs) == 2 {
mc.Operation = cs[0]
mc.Object = cs[1]
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
} else {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
err := ParseMMLAlias(mc)
if err != nil {
err := global.ErrMmlInvalidCommandFormat
log.Error(err)
return err
}
*mmlComms = append(*mmlComms, *mc)
}
return nil
}
func ParseMMLAlias(mml *MmlCommand) error {
where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object)
mc, err := dborm.XormGetMmlCommand("mml_command", where)
if err != nil {
log.Error("Failed to XormGetMmlCommand: ", err)
return err
}
if mc == nil {
err := errors.New("Not found mml map")
log.Error(err)
return err
}
log.Debug("mml command: ", mc)
aaMap := make(map[string]interface{})
naMap := make(map[string]interface{})
for _, pn := range mml.Params {
log.Trace("pn: ", pn)
for _, param := range mc.ParamJson {
log.Trace("param: ", param)
var pv string
if pn.Name == param.Name {
if param.Apostr == "true" {
pv = fmt.Sprintf("'%v'", pn.Value)
} else {
pv = fmt.Sprintf("%v", pn.Value)
}
var aa, av string
if param.Alias != "" {
aa = fmt.Sprintf("%s=%v", param.Alias, pv)
av = fmt.Sprintf("%v", pv)
switch param.Type {
case "int":
aaMap[param.Alias] = pn.Value
naMap[param.Alias] = pn.Value
default:
aaMap[param.Alias] = pv
naMap[param.Alias] = fmt.Sprintf("%v", pn.Value)
}
} else {
aa = fmt.Sprintf("%s=%v", param.Name, pv)
av = fmt.Sprintf("%v", pv)
switch param.Type {
case "int":
aaMap[param.Name] = pn.Value
naMap[param.Name] = pn.Value
default:
aaMap[param.Name] = pv
naMap[param.Name] = fmt.Sprintf("%v", pn.Value)
}
}
if param.Loc == "" || param.Loc == "true" {
mml.AaLoc = append(mml.AaLoc, aa)
mml.AaUri = append(mml.AaUri, av)
}
//mml.AaMap = append(mml.AaMap, aaMap)
mml.AaList = append(mml.AaList, aa)
break
}
}
}
mml.AaMap = aaMap
mml.NaMap = naMap
log.Trace("mml.AaMap: ", mml.AaMap)
log.Trace("mml.NaMap: ", mml.NaMap)
log.Trace("mml.AaList: ", mml.AaList)
return nil
}
func ParseMMLParams(mmlComms *[]MmlCommand) error {
for _, mml := range *mmlComms {
where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object)
mc, err := dborm.XormGetMmlCommand("mml_command", where)
if err != nil {
log.Error("Failed to XormGetMmlCommand: ", err)
return err
}
if mc == nil {
err := errors.New("Not found mml map")
log.Error(err)
return err
}
log.Debug("mml command: ", mc)
for _, pn := range mml.Params {
log.Trace("pn: ", pn)
for _, param := range mc.ParamJson {
log.Trace("param: ", param)
var pv string
if pn.Name == param.Name {
if param.Apostr == "true" {
pv = fmt.Sprintf("'%v'", pn.Value)
} else {
pv = fmt.Sprintf("%v", pn.Value)
}
var aa string
aaMap := make(map[string]interface{})
if param.Alias != "" {
aa = fmt.Sprintf("%s=%v", param.Alias, pv)
switch param.Type {
case "int":
aaMap[param.Alias] = pn.Value
case "string":
aaMap[param.Alias] = pv
}
} else {
aa = fmt.Sprintf("%s=%v", param.Name, pv)
switch param.Type {
case "int":
aaMap[param.Name] = pn.Value
case "string":
aaMap[param.Name] = pv
}
}
//mml.AaMap = append(mml.AaMap, aaMap)
mml.AaList = append(mml.AaList, aa)
break
}
}
}
log.Trace("mml.AaMap: ", mml.AaMap)
log.Trace("mml.AaList: ", mml.AaList)
*mmlComms = append(*mmlComms, mml)
}
return nil
}
func parseRequestUri(httpUri string, mmlMap *dborm.MmlHttpMap, mml *MmlCommand) string {
requestURI := fmt.Sprintf("%s%s", httpUri, mmlMap.URI)
if mmlMap.ExtUri != "" && len(mml.AaUri) > 0 {
extUri := strings.Join(mml.AaUri, "/")
requestURI = requestURI + fmt.Sprintf(mmlMap.ExtUri, extUri)
}
if mmlMap.Params != "" {
params := strings.Join(mml.AaLoc, "+and+")
params = strings.ReplaceAll(params, " ", "+") // replace " " to "+"
log.Trace("params:", params)
if mmlMap.ParamTag == "SQL" && strings.TrimSpace(params) != "" {
params = "+where+" + params
}
requestURI = fmt.Sprintf("%s%s%s", requestURI, mmlMap.Params, params)
}
return requestURI
}
func TransMml2HttpReq(omcMmlVar *MmlVar, mml *MmlCommand) (*[]byte, error) {
log.Info("TransMml2HttpReq processing ...")
log.Debug("mml: ", mml)
where := fmt.Sprintf("operation='%s' AND object='%s'", mml.Operation, mml.Object)
mmlMap, err := dborm.XormGetMmlHttpMap("mml_http_map", where)
if err != nil {
log.Error("Failed to XormGetMmlHttpMap: ", err)
return ParseErrorOutput(err), err
}
if mmlMap == nil {
err := errors.New("Not found mml map")
log.Error(err)
return ParseErrorOutput(err), err
}
log.Trace("mmlMap: ", mmlMap)
if mmlMap.Output == "" {
mmlMap.Output = "{}"
}
outputJson := new(dborm.MmlOutput)
err = json.Unmarshal([]byte(mmlMap.Output), outputJson)
if err != nil {
log.Error("Failed to Unmarshal:", err)
return ParseErrorOutput(err), err
}
log.Trace("outputJson: ", outputJson)
inputJson := new(dborm.MmlInput)
log.Trace("mmlMap.Input: ", mmlMap.Input)
if mmlMap.Input == "" {
mmlMap.Input = "{}"
}
err = json.Unmarshal([]byte(mmlMap.Input), inputJson)
if err != nil {
log.Error("Failed to Unmarshal:", err)
return ParseErrorOutput(err), err
}
log.Trace("inputJson: ", inputJson)
var requestURI string
var output *[]byte
client := resty.New()
switch strings.ToLower(mmlMap.Method) {
case "get":
requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml)
log.Debugf("method: Get requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}).
SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Get(requestURI)
if err != nil {
log.Error("Failed to Get:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(omcMmlVar, outputJson, response)
}
case "post":
requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml)
body := ParseInputBody(inputJson, mml)
log.Debugf("method: Post requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}).
SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(*body).
Post(requestURI)
if err != nil {
log.Error("Failed to Post:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(omcMmlVar, outputJson, response)
}
case "put":
requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml)
body := ParseInputBody(inputJson, mml)
log.Debugf("method: Put requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}).
SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
SetBody(*body).
Put(requestURI)
if err != nil {
log.Error("Failed to Put:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(omcMmlVar, outputJson, response)
}
case "delete":
requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml)
log.Debugf("method: Delete requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}).
SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Delete(requestURI)
if err != nil {
log.Error("Failed to Delete:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(omcMmlVar, outputJson, response)
}
case "patch":
requestURI = parseRequestUri(omcMmlVar.HttpUri, mmlMap, mml)
log.Debugf("method: patch requestURI: %s", requestURI)
response, err := client.R().
EnableTrace().
SetHeaders(map[string]string{"accessToken": omcMmlVar.SessionToken}).
SetHeaders(map[string]string{"User-Agent": omcMmlVar.UserAgent}).
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
Patch(requestURI)
if err != nil {
log.Error("Failed to Patch:", err)
output = ParseErrorOutput(err)
} else {
output = ParseOutputResponse(omcMmlVar, outputJson, response)
}
default:
err := errors.New("not found mml command")
log.Error(err)
output = ParseErrorOutput(err)
}
return output, nil
}
const (
MaxMmlOutputBufferSize = 1000000
FormatTypeJson = "json"
FormatTypeTable = "table"
DefaultFormatType = FormatTypeTable
)
const (
RetCodeSucceeded = 0
RetCodeFailed = 0
)
func ParseInputBody(inputJson *dborm.MmlInput, mml *MmlCommand) *[]byte {
inputBody := make(map[string]interface{})
log.Trace("mml.NaMap:", mml.NaMap)
log.Trace("mml.AaMap:", mml.AaMap)
if strings.ToLower(inputJson.BodyFmt) == "putdb" {
for _, icol := range inputJson.Cols {
log.Trace("icol:", icol)
mml.NaMap[icol.Name] = icol.Value
}
inputBody[inputJson.BodyKey] = mml.NaMap
} else {
inputParams := make([]map[string]interface{}, 0)
inputParams = append(inputParams, mml.NaMap)
inputBody[inputJson.BodyKey] = inputParams
}
body, err := json.Marshal(inputBody)
if err != nil {
log.Error("Failed to marshal:", err)
}
log.Trace("inputBody:", inputBody)
log.Trace("body:", string(body))
return &body
}
func ParseOutputResponse(omcMmlVar *MmlVar, outputJson *dborm.MmlOutput, response *resty.Response) *[]byte {
var output []byte
var str bytes.Buffer
switch response.StatusCode() {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
if omcMmlVar.Output == FormatTypeJson {
code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status())
title := formatTitle(outputJson.Title)
json.Indent(&str, response.Body(), "", " ")
log.Trace(str.String())
output = global.BytesCombine1([]byte(code), []byte(title), str.Bytes(), []byte("\n"))
} else {
log.Trace("Body:", string(response.Body()))
mapDatas := make(map[string]interface{}, 0)
err := json.Unmarshal(response.Body(), &mapDatas)
if err != nil {
log.Error("Failed to json.Unmarshal:", err)
//output = *ParseErrorOutput(err)
output = *ParseErrorOutput(string(response.Body()))
return &output
}
log.Trace("mapDatas:", mapDatas)
switch strings.ToLower(outputJson.RetFmt) {
case "getdb":
if len(mapDatas) > 0 {
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.([]interface{})) > 0 {
table := (data.([]interface{}))[0]
log.Trace("table:", table)
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
title := formatTitle(outputJson.Title)
fmtResults := ParseTableOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults))
}
}
case "deletedb":
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.(map[string]interface{})) > 0 {
table := data.(map[string]interface{})
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
fmtResults := ParseDBOperOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(fmtResults))
}
case "postdb":
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.(map[string]interface{})) > 0 {
table := data.(map[string]interface{})
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
fmtResults := ParseDBOperOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(fmtResults))
}
case "putdb":
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.(map[string]interface{})) > 0 {
table := data.(map[string]interface{})
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
fmtResults := ParseDBOperOutput(outputJson, table)
output = global.BytesCombine1([]byte(code), []byte(fmtResults))
}
case "getnf":
if len(mapDatas) > 0 {
var data interface{}
for _, data = range mapDatas {
log.Trace("data:", data)
break
}
if len(data.([]interface{})) > 0 {
//table := (data.([]interface{}))[0]
//log.Trace("table:", table)
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
title := formatTitle(outputJson.Title)
fmtResults := ParseNFTableOutput(outputJson, data)
output = global.BytesCombine1([]byte(code), []byte(title), []byte(fmtResults))
}
}
default:
code := fmt.Sprintf(outputJson.RetMsg, RetCodeSucceeded)
output = global.BytesCombine1([]byte(code))
}
}
default:
if omcMmlVar.Output == FormatTypeJson {
code := fmt.Sprintf("StatusCode = %d status %s\n\n", response.StatusCode(), response.Status())
//title := formatTitle("Network Element Information")
json.Indent(&str, response.Body(), "", " ")
log.Trace(str.String())
output = global.BytesCombine1([]byte(code), str.Bytes(), []byte("\n"))
} else {
log.Trace("Body:", string(response.Body()))
mapResults := make(map[string]interface{}, 0)
err := json.Unmarshal(response.Body(), &mapResults)
if err != nil {
log.Error("Failed to json.Unmarshal:", err)
output = *ParseErrorOutput(string(response.Body()))
} else {
log.Trace("mapResults:", mapResults)
errResult := mapResults["error"]
log.Trace("errResult:", errResult)
if len(errResult.(map[string]interface{})) > 0 {
errCode, _ := strconv.Atoi(fmt.Sprintf("%v", errResult.(map[string]interface{})["errorCode"]))
errorInfo := errResult.(map[string]interface{})["errorInfo"]
output = []byte(fmt.Sprintf(outputJson.ErrMsg, errCode, errorInfo))
}
}
}
}
return &output
}
func ParseDBOperOutput(outputJson *dborm.MmlOutput, cols any) string {
var colOutput []dborm.ColOutput = outputJson.Cols
var value, retFmtCols string
if len(cols.(map[string]interface{})) > 0 {
if len(colOutput) > 0 {
coln := colOutput[0].Name
value = fmt.Sprintf("%v", cols.(map[string]interface{})[coln])
log.Tracef("coln:%s value:%s", coln, value)
retFmtCols = colOutput[0].Display + " = " + value + "\n\n"
}
}
return retFmtCols
}
func ParseNFTableOutput(outputJson *dborm.MmlOutput, cols any) string {
var colOutput []dborm.ColOutput
var fmtColName string
var colName []string
var spaceNum int = 1
var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left"
if outputJson.SepSpaceNum != 0 {
spaceNum = outputJson.SepSpaceNum
}
if outputJson.AlignmentM != "" {
alignmentM = outputJson.AlignmentM
}
if outputJson.AlignmentSN != "" {
alignmentSN = outputJson.AlignmentSN
}
if outputJson.AlignmentSV != "" {
alignmentSV = outputJson.AlignmentSV
}
maxLength := math.MinInt64
for _, coln := range outputJson.Cols {
log.Trace("coln:", coln)
if len(coln.Display) > maxLength {
maxLength = len(coln.Display)
}
if coln.Length < len(coln.Display) {
coln.Length = len(coln.Display)
}
colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display))
colOutput = append(colOutput, coln)
}
fmtColName = formatLineBySpace(&colName, spaceNum)
log.Trace("fmtColName:", fmtColName)
var retFmtCols string
var fmtColValues []string
var numberResult int
// for _, colnvs := range cols.([]interface{}) {
// log.Trace("colnvs:", colnvs)
// if colnvs == nil {
// break
// }
numberResult = len(cols.([]interface{}))
if numberResult == 1 && outputJson.SingleList == true {
colnv := cols.([]interface{})[0]
log.Trace("colnv:", colnv)
var fmtNV []string
for _, coln := range colOutput {
fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display)
log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName)
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value)
fmtNV = append(fmtNV, fmtName+": "+fmtValue)
}
fmtResults := strings.Join(fmtNV, "\n")
log.Tracef("fmtResults:\n%s", fmtResults)
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtResults + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
} else {
for i := 0; i < numberResult; i++ {
colnv := cols.([]interface{})[i]
log.Trace("colnv:", colnv)
var colValues []string
var newVal []string
for _, coln := range colOutput {
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
if len(coln.Alias) != 0 {
enumVal, _ := strconv.Atoi(value)
value = parseEnumAlias(&(coln.Alias), enumVal)
}
newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value))
}
colValues = append(colValues, formatLineBySpace(&newVal, spaceNum))
log.Trace("colValues:", colValues)
fmtColValues = append(fmtColValues, strings.Join(colValues, "\n"))
log.Trace("fmtColValues:", fmtColValues)
}
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
}
}
func ParseTableOutput(outputJson *dborm.MmlOutput, cols any) string {
var colOutput []dborm.ColOutput
var fmtColName string
var colName []string
var spaceNum int = 1
var alignmentM, alignmentSN, alignmentSV string = "Left", "Right", "Left"
if outputJson.SepSpaceNum != 0 {
spaceNum = outputJson.SepSpaceNum
}
if outputJson.AlignmentM != "" {
alignmentM = outputJson.AlignmentM
}
if outputJson.AlignmentSN != "" {
alignmentSN = outputJson.AlignmentSN
}
if outputJson.AlignmentSV != "" {
alignmentSV = outputJson.AlignmentSV
}
maxLength := math.MinInt64
for _, coln := range outputJson.Cols {
log.Trace("coln:", coln)
if len(coln.Display) > maxLength {
maxLength = len(coln.Display)
}
if coln.Length < len(coln.Display) {
coln.Length = len(coln.Display)
}
colName = append(colName, ParseAlignmentOutput(coln.Length, alignmentM, coln.Display))
colOutput = append(colOutput, coln)
}
fmtColName = formatLineBySpace(&colName, spaceNum)
log.Trace("fmtColName:", fmtColName)
var retFmtCols string
var fmtColValues []string
var numberResult int
for _, colnvs := range cols.(map[string]interface{}) {
log.Trace("colnvs:", colnvs)
if colnvs == nil {
break
}
numberResult = len(colnvs.([]interface{}))
if numberResult == 1 && outputJson.SingleList == true {
colnv := colnvs.([]interface{})[0]
log.Trace("colnv:", colnv)
var fmtNV []string
for _, coln := range colOutput {
fmtName := ParseAlignmentOutput(maxLength, alignmentSN, coln.Display)
log.Tracef("alignmentSN:%s fmtName:%s", alignmentSN, fmtName)
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
fmtValue := ParseAlignmentOutput(coln.Length, alignmentSV, value)
fmtNV = append(fmtNV, fmtName+": "+fmtValue)
}
fmtResults := strings.Join(fmtNV, "\n")
log.Tracef("fmtResults:\n%s", fmtResults)
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtResults + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
} else {
for i := 0; i < numberResult; i++ {
colnv := colnvs.([]interface{})[i]
log.Trace("colnv:", colnv)
var colValues []string
var newVal []string
for _, coln := range colOutput {
value := fmt.Sprintf("%v", colnv.(map[string]interface{})[coln.Name])
if len(coln.Alias) != 0 {
enumVal, _ := strconv.Atoi(value)
value = parseEnumAlias(&(coln.Alias), enumVal)
}
newVal = append(newVal, ParseAlignmentOutput(coln.Length, alignmentM, value))
}
colValues = append(colValues, formatLineBySpace(&newVal, spaceNum))
log.Trace("colValues:", colValues)
fmtColValues = append(fmtColValues, strings.Join(colValues, "\n"))
log.Trace("fmtColValues:", fmtColValues)
}
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtColName + "\n\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
}
}
fmtEnd := fmt.Sprintf(outputJson.End, numberResult)
retFmtCols = fmtColName + "\n" + strings.Join(fmtColValues, "\n") + "\n\n" + fmtEnd
log.Tracef("retFmtCols:\n%s", retFmtCols)
return retFmtCols
}
func parseEnumAlias(alias *[]string, enumVal int) string {
return (*alias)[enumVal]
}
func formatLineBySpace(strArray *[]string, spaceNum int) string {
space := strings.Repeat(" ", spaceNum)
return strings.Join(*strArray, space)
}
func ParseAlignmentOutput(length int, alignment string, str string) string {
spaceLen := length - len(str)
if spaceLen < 0 {
log.Warnf("len(str=%s)=%d more length=%d", str, len(str), length)
spaceLen = 0
}
var retStr string
switch alignment {
case "Left":
suffix := strings.Repeat(" ", spaceLen)
retStr = str + suffix
case "Right":
prefix := strings.Repeat(" ", spaceLen)
retStr = prefix + str
log.Tracef("retStr:%s", retStr)
case "Middle":
prefix := strings.Repeat(" ", int(math.Ceil(float64(spaceLen)/2)))
suffix := strings.Repeat(" ", int(math.Floor(float64(spaceLen)/2)))
retStr = prefix + str + suffix
}
log.Tracef("length=%d, spaceLne=%d, alignment=%s, str=%s, retStr=%s", length, spaceLen, alignment, str, retStr)
return retStr
}
func ParseErrorOutput(err any) *[]byte {
var output []byte
var formatType string = DefaultFormatType
if formatType == FormatTypeJson {
output = []byte(fmt.Sprintf("ErrorCode = 1 Error message: %v\n\n", err))
} else {
output = []byte(fmt.Sprintf("RetCode = -1 operation failed: %v\n\n", err))
}
return &output
}
func formatTitle(title string) string {
var builder strings.Builder
builder.WriteString(title)
builder.WriteString("\n")
for i := 0; i < len(title); i++ {
builder.WriteString("-")
}
builder.WriteString("\n")
return builder.String()
}
func formatTableOutput() {
}

179
lib/oauth/oauth.go Normal file
View File

@@ -0,0 +1,179 @@
package oauth
import (
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"math/rand"
"net/http"
"strings"
"time"
"ems.agt/lib/log"
"github.com/dgrijalva/jwt-go"
"golang.org/x/crypto/bcrypt"
)
// GenToken 生成Token值
func GenToken(mapClaims jwt.MapClaims) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, mapClaims)
var nowDate = time.Now()
var secret = fmt.Sprintf("%v%v", nowDate, "xxxx")
return token.SignedString([]byte(secret))
}
// GenerateToken 生成Token值
func GenerateToken(mapClaims jwt.MapClaims, key string) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, mapClaims)
return token.SignedString([]byte(key))
}
// ParseToken: "解析token"
func ParseToken(token string, secret string) (string, error) {
claim, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil {
return "", err
}
return claim.Claims.(jwt.MapClaims)["cmd"].(string), nil
}
func RandAccessToken(n int) (ret string) {
allString := "52661fbd-6b84-4fc2-aa1e-17879a5c6c9b"
ret = ""
for i := 0; i < n; i++ {
r := rand.Intn(len(allString))
ret = ret + allString[r:r+1]
}
return ret
}
const letterBytes = "abcdef0123456789"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
var src = rand.NewSource(time.Now().UnixNano())
func RandStringBytes(n int) string {
b := make([]byte, n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return string(b)
}
func GenRandToken() string {
return RandStringBytes(8) + "-" + RandStringBytes(4) + "-" +
RandStringBytes(4) + "-" + RandStringBytes(4) + "-" + RandStringBytes(12)
}
type OAuthBody struct {
GrantType string
UserName string
Value string
}
/*
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 GetTokenFromHttpRequest(r *http.Request) string {
for k, v := range r.Header {
log.Tracef("k:%s, v:%s", k, v)
if strings.ToLower(k) == "accesstoken" && len(v) != 0 {
log.Trace("AccessToken:", v[0])
return v[0]
}
}
return ""
}
// IsCarriedToken check token is carried
func IsCarriedToken(r *http.Request) (string, bool) {
token := GetTokenFromHttpRequest(r)
if token == "" {
return "", false
}
return token, true
}
// Bcrypt Encrypt 加密明文密码
func BcryptEncrypt(password string) (string, error) {
hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(hashedBytes), err
}
// Bcrypt Compare 密文校验
func BcryptCompare(hashedPassword, password string) error {
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}
// sha256 crypt
func GetSHA256HashCode(stringMessage string) string {
message := []byte(stringMessage) //字符串转化字节数组
//创建一个基于SHA256算法的hash.Hash接口的对象
hash := sha256.New() //sha-256加密
//输入数据
hash.Write(message)
//计算哈希值
bytes := hash.Sum(nil)
//将字符串编码为16进制格式,返回字符串
hashCode := hex.EncodeToString(bytes)
//返回哈希值
return hashCode
}
// sha512 crypt
func GetSHA512HashCode(stringMessage string) string {
message := []byte(stringMessage) //字符串转化字节数组
//创建一个基于SHA256算法的hash.Hash接口的对象
hash := sha512.New() //SHA-512加密
//输入数据
hash.Write(message)
//计算哈希值
bytes := hash.Sum(nil)
//将字符串编码为16进制格式,返回字符串
hashCode := hex.EncodeToString(bytes)
//返回哈希值
return hashCode
}

37
lib/pair/pair.go Normal file
View File

@@ -0,0 +1,37 @@
package pair
type Pair struct {
Key int
Value int
}
type PairList []Pair
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with index i
// must sort before the element with index j.
//
// If both Less(i, j) and Less(j, i) are false,
// then the elements at index i and j are considered equal.
// Sort may place equal elements in any order in the final result,
// while Stable preserves the original input order of equal elements.
//
// Less must describe a transitive ordering:
// - if both Less(i, j) and Less(j, k) are true, then Less(i, k) must be true as well.
// - if both Less(i, j) and Less(j, k) are false, then Less(i, k) must be false as well.
//
// Note that floating-point comparison (the < operator on float32 or float64 values)
// is not a transitive ordering when not-a-number (NaN) values are involved.
// See Float64Slice.Less for a correct implementation for floating-point values.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
func (p PairList) Len() int { return len(p) }
func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }
func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

252
lib/routes/routes.go Normal file
View File

@@ -0,0 +1,252 @@
package routes
import (
"net/http"
// "log"
"ems.agt/features/aaaa"
"ems.agt/features/cm"
"ems.agt/features/dbrest"
"ems.agt/features/file"
"ems.agt/features/fm"
"ems.agt/features/maintenance"
"ems.agt/features/mml"
"ems.agt/features/nbi"
"ems.agt/features/pm"
"ems.agt/features/security"
"ems.agt/features/state"
"ems.agt/features/trace"
"ems.agt/lib/midware"
"ems.agt/lib/services"
"github.com/gorilla/mux"
)
type Router struct {
Method string
Pattern string
Handler http.HandlerFunc
Middleware mux.MiddlewareFunc
}
var routers []Router
// var (
// commonUriPattern = config.UriPrefix + "/{apiCategory}/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
// getUriPattern = config.UriPrefix + "/resourceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/{objectTypeValue}"
// getStatePattern = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/systemState"
// // // database management rest pattern discard
// // XormGetDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/elementType/{databaseName}/objectType/{tableName}"
// // XormSelectDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/select/{databaseName}/{tableName}"
// // XormInsertDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/insert/{databaseName}/{tableName}"
// // XormUpdateDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/update/{databaseName}/{tableName}"
// // XormDeleteDataUri = config.UriPrefix + "/databaseManagement/{apiVersion}/delete/{databaseName}/{tableName}"
// // XormCommonUri = config.UriPrefix + "/databaseManagement/{apiVersion}/{databaseName}/{tableName}"
// // alarm management
// postAlarmPattern = config.UriPrefix + "/faultManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/alarms"
// // performance management
// postPerformancePattern = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}"
// measureTaskUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureTask"
// measureReportUri = config.UriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/measureReport"
// // parameter config management
// paramConfigUri = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/config/{paraName}"
// // NE info
// UriNeInfo = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo"
// )
func init() {
Register("POST", security.UriOauthToken, security.LoginFromOMC, nil)
Register("POST", security.UriOauthHandshake, security.HandshakeFromOMC, nil)
Register("DELETE", security.UriOauthToken, security.LogoutFromOMC, nil)
Register("OPTIONS", security.UriOauthToken, OptionsProc, nil)
Register("OPTIONS", security.UriOauthHandshake, OptionsProc, nil)
// System state
Register("GET", state.UriSysState, state.GetStateFromNF, nil)
Register("OPTIONS", state.UriSysState, OptionsProc, nil)
Register("GET", state.UriSysState2, state.GetStateFromNF, nil)
Register("OPTIONS", state.UriSysState, OptionsProc, nil)
Register("OPTIONS", state.UriSysState2, OptionsProc, nil)
Register("GET", state.UriSysInfoAll, state.GetAllSysinfoFromNF, nil)
Register("GET", state.UriSysInfoOne, state.GetOneSysinfoFromNF, nil)
Register("OPTIONS", state.UriSysInfoAll, OptionsProc, nil)
Register("OPTIONS", state.UriSysInfoOne, OptionsProc, nil)
Register("GET", state.UriLicenseInfoAll, state.GetAllLicenseInfoFromNF, nil)
Register("GET", state.UriLicenseInfoOne, state.GetOneLicenseInfoFromNF, nil)
Register("OPTIONS", state.UriLicenseInfoAll, OptionsProc, nil)
Register("OPTIONS", state.UriLicenseInfoOne, OptionsProc, nil)
// database management
Register("GET", dbrest.XormGetDataUri, dbrest.DatabaseGetData, nil)
Register("GET", dbrest.XormSelectDataUri, dbrest.DatabaseGetData, nil)
Register("POST", dbrest.XormInsertDataUri, dbrest.DatabaseInsertData, nil)
Register("PUT", dbrest.XormUpdateDataUri, dbrest.DatabaseUpdateData, nil)
Register("DELETE", dbrest.XormDeleteDataUri, dbrest.DatabaseDeleteData, nil)
// corss orgin domain
Register("OPTIONS", dbrest.XormGetDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormSelectDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormInsertDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormUpdateDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormDeleteDataUri, OptionsProc, nil)
Register("GET", dbrest.XormCommonUri, dbrest.DatabaseGetData, nil)
Register("POST", dbrest.XormCommonUri, dbrest.DatabaseInsertData, nil)
Register("PUT", dbrest.XormCommonUri, dbrest.DatabaseUpdateData, nil)
Register("DELETE", dbrest.XormCommonUri, dbrest.DatabaseDeleteData, nil)
Register("GET", dbrest.XormExtDataUri, dbrest.ExtDatabaseGetData, nil)
Register("POST", dbrest.XormExtDataUri, dbrest.ExtDatabaseInsertData, nil)
Register("PUT", dbrest.XormExtDataUri, dbrest.ExtDatabaseUpdateData, nil)
Register("DELETE", dbrest.XormExtDataUri, dbrest.ExtDatabaseDeleteData, nil)
// corss orgin domain
Register("OPTIONS", dbrest.XormInsertDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormUpdateDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormDeleteDataUri, OptionsProc, nil)
Register("OPTIONS", dbrest.XormCommonUri, OptionsProc, nil)
// alarm restful Register
Register("POST", fm.UriAlarms, fm.PostAlarmFromNF, nil)
Register("Get", fm.UriAlarms, fm.GetAlarmFromNF, nil)
Register("OPTIONS", fm.UriAlarms, OptionsProc, nil)
// performance restful Register
Register("POST", pm.PostPerformancePattern, pm.PostKPIReportFromNF, nil)
Register("POST", pm.MeasureTaskUri, pm.PostMeasureTaskToNF, nil)
Register("PUT", pm.MeasureTaskUri, pm.PutMeasureTaskToNF, nil)
Register("DELETE", pm.MeasureTaskUri, pm.DeleteMeasureTaskToNF, nil)
Register("PATCH", pm.MeasureTaskUri, pm.PatchMeasureTaskToNF, nil)
Register("POST", pm.MeasureReportUri, pm.PostMeasureReportFromNF, nil)
Register("POST", pm.MeasurementUri, pm.PostMeasurementFromNF, nil)
Register("GET", pm.MeasurementUri, pm.GetMeasurementFromNF, nil)
Register("OPTIONS", pm.MeasureTaskUri, OptionsProc, nil)
// parameter config management
Register("GET", cm.ParamConfigUri, cm.GetParamConfigFromNF, nil)
Register("POST", cm.ParamConfigUri, cm.PostParamConfigToNF, nil)
Register("PUT", cm.ParamConfigUri, cm.PutParamConfigToNF, nil)
Register("DELETE", cm.ParamConfigUri, cm.DeleteParamConfigToNF, nil)
Register("OPTIONS", cm.ParamConfigUri, OptionsProc, nil)
// Get/Create/Modify/Delete NE info
Register("GET", cm.UriNeInfo, cm.GetNeInfo, nil)
Register("POST", cm.UriNeInfo, cm.PostNeInfo, nil)
Register("PUT", cm.UriNeInfo, cm.PutNeInfo, nil)
Register("DELETE", cm.UriNeInfo, cm.DeleteNeInfo, nil)
Register("OPTIONS", cm.UriNeInfo, OptionsProc, nil)
// Post MML command to NF
Register("POST", mml.UriMML, mml.PostMMLToNF, nil)
Register("OPTIONS", mml.UriMML, OptionsProc, nil)
Register("POST", mml.UriOmMmlExt, mml.PostMMLToOMC, nil)
Register("OPTIONS", mml.UriOmMmlExt, OptionsProc, nil)
// Northbound Get NRM
Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil)
// Import/Export NF CM
Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil)
Register("POST", cm.NeCmUri, cm.ImportCmToNF, nil)
Register("OPTIONS", cm.NeCmUri, OptionsProc, nil)
Register("GET", cm.UriNeCmFile, cm.DownloadNeBackupFile, nil)
Register("DELETE", cm.UriNeCmFile, cm.DeleteNeBackupFile, nil)
Register("OPTIONS", cm.UriNeCmFile, OptionsProc, nil)
// Software management
Register("GET", cm.UriSoftware, cm.DownloadSoftwareFile, nil)
Register("POST", cm.UriSoftware, cm.UploadSoftwareFile, nil)
Register("DELETE", cm.UriSoftware, cm.DeleteSoftwareFile, nil)
Register("OPTIONS", cm.UriSoftware, OptionsProc, nil)
Register("POST", cm.UriSoftwareNE, cm.DistributeSoftwareToNF, nil)
Register("PUT", cm.UriSoftwareNE, cm.ActiveSoftwareToNF, nil)
Register("PATCH", cm.UriSoftwareNE, cm.RollBackSoftwareToNF, nil)
Register("OPTIONS", cm.UriSoftwareNE, OptionsProc, nil)
// License management
Register("GET", cm.LicenseUri, cm.ExportCmFromNF, nil)
Register("POST", cm.LicenseUri, cm.ImportCmToNF, nil)
Register("DELETE", cm.LicenseUri, cm.ImportCmToNF, nil)
Register("OPTIONS", cm.LicenseUri, OptionsProc, nil)
Register("POST", cm.NeLicenseUri, cm.ExportCmFromNF, nil)
Register("PUT", cm.NeLicenseUri, cm.ImportCmToNF, nil)
Register("PATCH", cm.NeLicenseUri, cm.ImportCmToNF, nil)
Register("OPTIONS", cm.NeLicenseUri, OptionsProc, nil)
// Trace management
Register("POST", trace.UriTraceTask, trace.PostTraceTaskToNF, nil)
Register("PUT", trace.UriTraceTask, trace.PutTraceTaskToNF, nil)
Register("DELETE", trace.UriTraceTask, trace.DeleteTraceTaskToNF, nil)
Register("OPTIONS", trace.UriTraceTask, OptionsProc, nil)
// file management
Register("POST", file.UriFile, file.UploadFile, nil)
Register("GET", file.UriFile, file.DownloadFile, nil)
Register("DELETE", file.UriFile, file.DeleteFile, nil)
Register("OPTIONS", file.UriFile, OptionsProc, nil)
// AAAA
Register("GET", aaaa.UriAAAASSO, aaaa.GetSSOFromAAAA, nil)
// 系统维护
Register("GET", maintenance.Uri, maintenance.List, nil)
Register("GET", maintenance.UriPref, maintenance.Pref, nil)
Register("GET", maintenance.UriPrefLog, maintenance.PrefLog, nil)
Register("GET", maintenance.UriSqlClient, maintenance.SqlClient, nil)
Register("GET", maintenance.UriTop, maintenance.Top, nil)
Register("PATCH", maintenance.UriTop, maintenance.TopOps, nil)
}
// To resolv rest POST/PUT/DELETE/PATCH cross domain
func OptionsProc(w http.ResponseWriter, r *http.Request) {
services.ResponseStatusOK200Null(w)
}
func NewRouter() *mux.Router {
r := mux.NewRouter()
// set custom handle for status 404/405
r.NotFoundHandler = services.CustomResponseNotFound404Handler()
r.MethodNotAllowedHandler = services.CustomResponseMethodNotAllowed405Handler()
r.Use(midware.LoggerTraceMiddleware)
for _, router := range routers {
r.Methods(router.Method).
Path(router.Pattern).
Handler(router.Handler)
if router.Middleware != nil {
r.Use(router.Middleware)
}
}
return r
}
func Register(method, pattern string, handler http.HandlerFunc, middleware mux.MiddlewareFunc) {
routers = append(routers, Router{method, pattern, handler, middleware})
}

356
lib/services/file.go Normal file
View File

@@ -0,0 +1,356 @@
package services
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"strconv"
"strings"
"ems.agt/lib/log"
)
const (
RootPath = "uploads/"
ChunkRootPath = "uploads_tmp/"
)
var (
// FilesMax 限制上传文件的大小为7 MB
FilesMax int64 = 32 << 20
// ValuesMax 限制POST字段内容的大小
ValuesMax int64 = 512
)
func GetPostFile(w http.ResponseWriter, r *http.Request) {
//获取文件流,第三个返回值是错误对象
file, header, _ := r.FormFile("file")
//读取文件流为[]byte
b, err := ioutil.ReadAll(file)
if err != nil {
log.Error("Failed to ReadAll:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
//把文件保存到指定位置
err = ioutil.WriteFile("./upload/test.zip", b, 0644)
if err != nil {
log.Error("Failed to WriteFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
//输出上传时文件名
log.Debug("filename:", header.Filename)
}
func GetUploadFile(w http.ResponseWriter, r *http.Request) {
log.Debug("GetUploadFile processing...")
file, err := os.Create("./test.zip")
if err != nil {
log.Error("Failed to Create:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
_, err = io.Copy(file, r.Body)
if err != nil {
log.Error("Failed to Copy:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
}
func GetUploadFormFile(w http.ResponseWriter, r *http.Request) {
// 设置最大的内存限制为32MB
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("file")
if err != nil {
log.Error("Failed to FormFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
defer file.Close()
log.Debug("Header:%v", handler.Header)
f, err := os.OpenFile("./"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
log.Error("Failed to OpenFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
defer f.Close()
_, err = io.Copy(f, file)
if err != nil {
log.Error("Failed to Copy:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("File uploaded successfully:", handler.Filename)
}
func HandleUploadFile(r *http.Request, path, newFileName string) (string, error) {
var filePath, fileName string
reader, err := r.MultipartReader()
if err != nil {
log.Error("Failed to MultipartReader:", err)
return "", err
}
for {
part, err := reader.NextPart()
if err == io.EOF {
break
} else if err != nil {
log.Error("Failed to NextPart:", err)
return "", err
}
log.Debugf("FileName=[%s], FormName=[%s]", part.FileName(), part.FormName())
if part.FileName() == "" { // this is FormData
data, _ := ioutil.ReadAll(part)
log.Debugf("FormData=[%s]", string(data))
} else { // This is FileData
if newFileName != "" {
fileName = newFileName
} else {
fileName = part.FileName()
}
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
log.Error("Failed to Mkdir:", err)
return "", err
}
filePath = path + "/" + fileName
file, err := os.Create(filePath)
if err != nil {
log.Error("Failed to Create:", err)
return "", err
}
defer file.Close()
_, err = io.Copy(file, part)
if err != nil {
log.Error("Failed to Copy:", err)
return "", err
}
}
}
return fileName, nil
}
func HandleUploadFormFile(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20)
//mForm := r.MultipartForm
for k, _ := range r.MultipartForm.File {
// k is the key of file part
file, fileHeader, err := r.FormFile(k)
if err != nil {
fmt.Println("inovke FormFile error:", err)
return
}
defer file.Close()
fmt.Printf("the uploaded file: name[%s], size[%d], header[%#v]\n",
fileHeader.Filename, fileHeader.Size, fileHeader.Header)
// store uploaded file into local path
localFileName := "./upload/" + fileHeader.Filename
out, err := os.Create(localFileName)
if err != nil {
fmt.Printf("failed to open the file %s for writing", localFileName)
return
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
fmt.Printf("copy file err:%s\n", err)
return
}
fmt.Printf("file %s uploaded ok\n", fileHeader.Filename)
}
}
func PostFileHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("PostFileHandler processing... ")
if !strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") {
// 不支持的 Content-Type 类型
fmt.Println("Invalid Content-Type: ", r.Header.Get("Content-Type"))
http.Error(w, " 不支持的 Content-Type 类型", http.StatusBadRequest)
return
}
// 整个请求的主体大小设置为7.5Mb
r.Body = http.MaxBytesReader(w, r.Body, FilesMax+ValuesMax)
reader, err := r.MultipartReader()
if err != nil {
fmt.Println(err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
for {
// A Part represents a single part in a multipart body.
part, err := reader.NextPart()
if err != nil {
if err == io.EOF {
break
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fileName := part.FileName()
formName := part.FormName()
var buf = &bytes.Buffer{}
// 非文件字段部分大小限制验证非文件字段go中filename会是空
if fileName == "" {
var limitError = "请求主体中非文件字段" + formName + "超出大小限制"
err = uploadSizeLimit(buf, part, ValuesMax, limitError)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
continue
}
// 文件字段部分大小限制验证
var limitError = "请求主体中文件字段" + fileName + "超出大小限制"
err = uploadSizeLimit(buf, part, FilesMax, limitError)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 文件创建部分
if err := uploadFileHandle(r.Header, fileName, buf); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 非逻辑内容,仅为测试使用
var chunkNumber = r.Header.Get("chunk-number")
if chunkNumber == "" {
http.Error(w, "文件"+fileName+"上传成功", http.StatusOK)
} else {
http.Error(w, "分片文件"+fileName+chunkNumber+"上传成功", http.StatusOK)
}
}
return
http.NotFound(w, r)
}
// 上传内容大小限制
func uploadSizeLimit(buf *bytes.Buffer, part *multipart.Part, maxLimit int64, limitError string) error {
n, err := io.CopyN(buf, part, maxLimit+1)
if err != nil && err != io.EOF {
fmt.Println("PostFileHandler:", err)
return err
}
maxLimit -= n
if maxLimit < 0 {
return errors.New(limitError)
}
return nil
}
// uploadFileHandle handle upload file
func uploadFileHandle(header http.Header, fileName string, buf *bytes.Buffer) error {
var chunkNumberStr = header.Get("chunk-number")
// 1.普通文件上传处理
if chunkNumberStr == "" {
//创建文件并写入文件内容
return createFile(RootPath+fileName, buf.Bytes())
}
// 2.分片文件上传处理
//2.1读取分片编号
chunkNumber, err := strconv.Atoi(chunkNumberStr)
if err != nil {
return err
}
//2.2创建分片文件并写入分片内容
if err := createFile(fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", chunkNumber), buf.Bytes()); err != nil {
return err
}
//2.3确认是否上传完毕
if header.Get("chunk-final") == "true" {
//2.4合并文件
if err := mergeChunkFiles(fileName); err != nil {
return err
}
//2.5删除分片
for i := 0; ; i++ {
chunFileName := fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", i)
err := os.Remove(chunFileName)
if err != nil {
if os.IsNotExist(err) {
break
}
return err
}
}
}
return nil
}
// 创建文件并写入内容
func createFile(fileName string, res []byte) error {
newFile, err := os.Create(fileName)
if err != nil {
return err
}
defer func() {
_ = newFile.Close()
}()
bufferedWriter := bufio.NewWriter(newFile)
_, err = bufferedWriter.Write(res)
if err != nil && err != io.EOF {
return err
}
return bufferedWriter.Flush()
}
// 合并分片文件
func mergeChunkFiles(fileName string) error {
var (
n int64
err error
)
finalFile, err := os.Create(RootPath + fileName)
if err != nil {
return err
}
defer finalFile.Close()
// 将分片内容写入最终文件
for i := 0; ; i++ {
chunFile, err := os.Open(fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", i))
if err != nil {
if os.IsNotExist(err) {
break
}
return err
}
n, err = io.Copy(finalFile, chunFile)
if err != nil {
return err
}
err = chunFile.Close()
if err != nil {
return err
}
if n < 1 {
break
}
}
return nil
}

45
lib/services/requset.go Normal file
View File

@@ -0,0 +1,45 @@
package services
import (
"encoding/json"
"io"
"net/http"
"strconv"
"ems.agt/lib/global"
)
// 读取json请求结构团体
func JSONBody(r *http.Request, args any) error {
body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
if err != nil {
return err
}
err = json.Unmarshal(body, args)
return err
}
// Get 查詢分頁值
func GetPageNumSize(r *http.Request) (int, int) {
pageNumStr := r.URL.Query().Get("pageNum")
num := 1
if v, err := strconv.Atoi(pageNumStr); err == nil && v > 0 {
if v >= 100 {
num = 100
} else {
num = v
}
}
pageSizeStr := r.URL.Query().Get("pageSize")
size := 0
if v, err := strconv.Atoi(pageSizeStr); err == nil && v > 0 {
if v >= 60 {
size = 60
} else {
size = v
}
}
return num, size
}

936
lib/services/services.go Normal file
View File

@@ -0,0 +1,936 @@
package services
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"os"
"path/filepath"
// "log"
"net/http"
"strconv"
"strings"
"ems.agt/lib/dborm"
"ems.agt/lib/global"
"ems.agt/lib/log"
"ems.agt/lib/oauth"
"ems.agt/restagent/config"
"github.com/gorilla/mux"
)
type NameValue struct {
Name string
Value string
}
type NameOid struct {
Name string
Oid string
}
type DataResponse struct {
Data interface{} `json:"data"`
}
type NullResponse struct {
nil interface{}
}
type ErrorResponse struct {
Error interface{} `json:"error"`
}
type ErrorMessage struct {
ErrorCode string `json:"errorCode"`
ErrorInfo string `json:"errorInfo"`
}
type SucceedOAuthResponse struct {
AccessToken string `json:"accessToken"`
Expires string `json:"expires"`
// Enum: "0": 不需要修改密码, "1": "FirstLogin",首次登录, "2": PasswordAboutToExpire, 密码即将过期
ChangePasswordFlag int `json:"changePasswordFlag"`
GroupName string `json:"groupName"`
}
type ServiceResponse struct {
}
func GetUriParamString(r *http.Request, paramName string, sep string, brackets bool, apostr bool) string {
vars := r.URL.Query()
s, ok := vars[paramName]
if !ok {
log.Infof("Parameter Name is not exist, %s", paramName)
return ""
}
if apostr {
for i := 0; i < len(s); i++ {
s[i] = "'" + s[i] + "'"
}
}
pn := strings.Join(s, sep)
if brackets {
pn = fmt.Sprintf("(%s)", pn)
}
return pn
}
func GetUriWhereString(r *http.Request) string {
return GetUriParamString(r, "WHERE", " and ", false, false)
}
func GetUriLocString(r *http.Request) string {
return GetUriParamString(r, "loc", " and ", false, false)
}
func GetUriPageLimitString(r *http.Request) string {
vars := r.URL.Query()
p, ok := vars["PAGE"]
if !ok {
log.Info("page param is not exist")
return ""
}
l, ok := vars["LIMIT"]
if !ok {
log.Info("limit param is not exist")
return ""
}
li, _ := strconv.Atoi(l[0])
pi, _ := strconv.Atoi(p[0])
ls := fmt.Sprintf("limit %d, %d", li*(pi-1), li)
log.Debug("Limit array:", ls)
return ls
}
func ExtGetUriPageLimitString(r *http.Request) string {
vars := r.URL.Query()
p, ok := vars["page"]
if !ok {
log.Info("page param is not exist")
p = append(p, "1")
}
l, ok := vars["limit"]
if !ok {
log.Info("limit param is not exist")
l = append(l, strconv.Itoa(global.MaxLimitData))
}
limit, _ := strconv.Atoi(l[0])
if limit > global.MaxLimitData {
limit = global.MaxLimitData
}
page, _ := strconv.Atoi(p[0])
limitStr := fmt.Sprintf("limit %d, %d", limit*(page-1), limit)
log.Debug("limitStr:", limitStr)
return limitStr
}
func IsJsonContentType(r *http.Request) bool {
if strings.Contains(r.Header.Get("Content-Type"), "application/json") {
return true
}
return false
}
func IsValidOAuthUri(r *http.Request) bool {
vars := mux.Vars(r)
apiVer := vars["apiVersion"] // 获取Uri
if apiVer != "v1" {
return false
}
return true
}
func IsVallidContentType(r *http.Request, checkFlag bool) bool {
log.Debug("IsVallidContentType processing ...")
/*
ctype := r.Header["Content-Type"]
log.Debug("ctype:", ctype)
if len(ctype) != 0 && !strings.Contains(ctype[0], "application/json") {
return false
}
*/
if strings.Contains(r.Header.Get("Content-Type"), "application/json") || checkFlag == false {
return true
}
return false
}
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.Info("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.Info("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(config.GetRmUIDRegexpFromConfig(), 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 GetParamsArrByName(paramName string, r *http.Request) []string {
vars := r.URL.Query()
pns, ok := vars[paramName]
if !ok {
log.Infof("%s is not exist", paramName)
return nil
}
var pnArr []string
for _, pn := range pns {
if pn != "" {
pnArr = global.MergeStringArr(pnArr, strings.Split(pn, `,`))
}
}
return pnArr
}
func GetOperationTypeFromHttpRequest(r *http.Request) string {
for k, v := range r.Header {
log.Tracef("k:%s, v:%s", k, v)
if strings.ToLower(k) == "operationtype" && len(v) != 0 {
log.Trace("OperationType:", v[0])
return v[0]
}
}
return ""
}
func CheckNorthboundValidRequest(w http.ResponseWriter, r *http.Request) (string, error) {
log.Debug("CheckNorthboundValidRequest processing... ")
var token string = ""
var err error
var ret bool
// 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())
ResponseRequestURITooLong414UriTooLong(w)
return token, err
}
// check media type(content type) only support "application/json"
// response 415-1
if !IsJsonContentType(r) {
log.Error("Invalid Content-Type")
ResponseUnsupportedMediaType415(w)
return token, err
}
// error processing ...
// 401-1 response
token, ret = oauth.IsCarriedToken(r)
if ret == false {
log.Error("AccessToken is not carried")
ResponseUnauthorized401AccessTokenNotCarried(w)
return token, err
}
// 401-2 response
if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false {
log.Error("AccessToken fails or does not exist")
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
_, err = dborm.XormUpdateSessionShakeTime(token)
if err != nil {
log.Error("Failed to update session table:", err)
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
}
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri is invalid")
ResponseNotFound404UriNotExist(w, r)
return token, err
}
// response 406-1
rmUIDValues := GetRmUIDArr(r)
if rmUIDValues == nil {
log.Error("missing parameter: rmUIDs")
ResponseNotAcceptable406MissingParam(w)
return token, err
}
// response 406-2
errorParams := CheckParameterName(r)
if errorParams != nil {
log.Error("parameter name error: ", errorParams)
ResponseNotAcceptable406ParamError(w, errorParams)
return token, err
}
// response 400-5
if len(rmUIDValues) == 0 {
log.Error("rmUIDs is wrong or NULL")
ResponseBadRequest400WrongParamValue(w)
return token, err
}
// response 414-1
if len(rmUIDValues) > config.GetYamlConfig().Params.RmUIDMaxNum {
log.Error("rmUID greater than", config.GetYamlConfig().Params.RmUIDMaxNum)
ResponseRequestURITooLong414NRMNumExceed(w, config.GetYamlConfig().Params.RmUIDMaxNum)
return token, err
}
return token, nil
}
func CheckCommonValidRequest(w http.ResponseWriter, r *http.Request) (string, error) {
log.Debug("CheckCommonValidRequest processing... ")
var token string = ""
var err error
var ret bool
// 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())
ResponseRequestURITooLong414UriTooLong(w)
return token, err
}
// check media type(content type) only support "application/json"
// response 415-1
if !IsJsonContentType(r) {
log.Error("Invalid Content-Type")
ResponseUnsupportedMediaType415(w)
return token, err
}
// error processing ...
// 401-1 response
token, ret = oauth.IsCarriedToken(r)
if ret == false {
log.Error("AccessToken is not carried")
ResponseUnauthorized401AccessTokenNotCarried(w)
return token, err
}
// 401-2 response
if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false {
log.Error("AccessToken fails or does not exist")
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
_, err = dborm.XormUpdateSessionShakeTime(token)
if err != nil {
log.Error("Failed to update session table:", err)
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
}
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
log.Error("Uri is invalid")
ResponseNotFound404UriNotExist(w, r)
return token, err
}
return token, nil
}
func IsLocalhost(host string) bool {
if strings.Contains(host, "127.0.0.1") || strings.Contains(host, "::1") {
return true
}
return false
}
func CheckFrontValidRequest(w http.ResponseWriter, r *http.Request) (string, error) {
log.Debug("CheckFrontValidRequest processing... ")
var token string = ""
var err error
var ret bool
// response 414-4 uri too long ? (optional)
// todo ... ?
if bytes.Count([]byte(r.RequestURI), nil) > config.GetUriMaxLenFromConfig() {
err = errors.New("Request Uri too long")
log.Errorf("Request Uri too long: bytes=%d, MaxLen=%d", bytes.Count([]byte(r.RequestURI), nil), config.GetUriMaxLenFromConfig())
ResponseRequestURITooLong414UriTooLong(w)
return token, err
}
/*
// check media type(content type) only support "application/json"
// response 415-1
if !IsVallidContentType(r) {
err := errors.New("Invalid Content-Type")
log.Error(err)
ResponseUnsupportedMediaType415(w)
return err
}
*/
// error processing ...
// 401-1 response
if config.GetYamlConfig().Auth.Token && IsLocalhost(r.RemoteAddr) == false {
token, ret = oauth.IsCarriedToken(r)
if ret == false {
err = errors.New("AccessToken is not carried")
log.Error(err)
ResponseUnauthorized401AccessTokenNotCarried(w)
return token, err
}
// 401-2 response
if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false {
err = errors.New("AccessToken fails or does not exist")
log.Error(err)
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
_, err = dborm.XormUpdateSessionShakeTime(token)
if err != nil {
log.Error("Failed to update session table:", err)
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
}
}
/*
// 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")
ResponseForbidden403NotPermission(w)
return
}
*/
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
err = errors.New("Uri is invalid")
log.Error(err)
ResponseNotFound404UriNotExist(w, r)
return token, err
}
return token, nil
}
func CheckExtValidRequest(w http.ResponseWriter, r *http.Request) (string, error) {
log.Debug("CheckExtValidRequest processing... ")
var token string = ""
var err error
var ret bool
// error processing ...
// 401-1 response
if config.GetYamlConfig().Auth.Token {
token, ret = oauth.IsCarriedToken(r)
if ret == false {
err = errors.New("AccessToken is not carried")
log.Error(err)
ResponseUnauthorized401AccessTokenNotCarried(w)
return token, err
}
// 401-2 response
if dborm.XormExistValidToken(token, config.GetExpiresFromConfig()) == false {
err = errors.New("AccessToken fails or does not exist")
log.Error(err)
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
if operType := GetOperationTypeFromHttpRequest(r); operType != "auto" {
_, err = dborm.XormUpdateSessionShakeTime(token)
if err != nil {
log.Error("Failed to update session table:", err)
ResponseUnauthorized401AccessTokenNotExist(w)
return token, err
}
}
}
vars := mux.Vars(r)
apiVer := vars["apiVersion"]
if apiVer != global.ApiVersionV1 {
err = errors.New("Uri is invalid")
log.Error(err)
ResponseNotFound404UriNotExist(w, r)
return token, err
}
return token, nil
}
func ResponseStatusOK200Login(w http.ResponseWriter, token string, user *dborm.User) {
var oAuthResponse SucceedOAuthResponse
oAuthResponse.AccessToken = token
oAuthResponse.Expires = strconv.Itoa((int)(config.GetExpiresFromConfig()))
oAuthResponse.ChangePasswordFlag = user.ChangePasswordFlag
oAuthResponse.GroupName = user.GroupName
ResponseWithJson(w, http.StatusOK, oAuthResponse)
}
func ResponseStatusOK200Null(w http.ResponseWriter) {
response := NullResponse{""}
ResponseWithJson(w, http.StatusOK, response)
}
func ResponseStatusOK204NoContent(w http.ResponseWriter) {
ResponseWithJson(w, http.StatusNoContent, "")
}
func ResponseRedirect(w http.ResponseWriter, redirectUrl string) {
w.Header().Set("Cache-Control", "must-revalidate, no-store")
w.Header().Set("Content-Type", " text/html;charset=UTF-8")
w.Header().Set("Location", redirectUrl) //跳转地址设置
w.WriteHeader(http.StatusTemporaryRedirect) //重定向!
}
func ResponseBadRequest400RmUIDsIsInvalid(w http.ResponseWriter, rmUIDs []string) {
errorMessage := ErrorMessage{"1", "rmUIDs is invalid:" + strings.Join(rmUIDs, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}
func ResponseBadRequest400DuplicateSubId(w http.ResponseWriter, SubIds string) {
errorMessage := ErrorMessage{"2", "Duplicate with resource subscription id:" + SubIds}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}
func ResponseBadRequest400DuplicateAlarmId(w http.ResponseWriter, AlarmIds string) {
errorMessage := ErrorMessage{"3", "Duplicate with alarm subscription id: " + AlarmIds}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}
func ResponseBadRequest400IncorrectLogin(w http.ResponseWriter) {
errorMessage := ErrorMessage{"4", "Incorrect username and password"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}
func ResponseBadRequest400WrongParamValue(w http.ResponseWriter) {
errorMessage := ErrorMessage{"5", "Wrong parameter value"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}
func ResponseBadRequest400CMCALoginError(w http.ResponseWriter) {
errorMessage := ErrorMessage{"6", "CMCA centralized authentication login error"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusBadRequest, errorResponse)
}
func ResponseBadRequest400InvalidJson(w http.ResponseWriter) {
errorMessage := ErrorMessage{"7", "Invalid json format"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusUnauthorized, errorResponse)
}
func ResponseUnauthorized401AccessTokenNotCarried(w http.ResponseWriter) {
errorMessage := ErrorMessage{"1", "AccessToken is not carried"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusUnauthorized, errorResponse)
}
func ResponseUnauthorized401AccessTokenNotExist(w http.ResponseWriter) {
errorMessage := ErrorMessage{"2", "AccessToken fails or does not exist"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusUnauthorized, errorResponse)
}
func ResponseForbidden403NotPermission(w http.ResponseWriter) {
errorMessage := ErrorMessage{"1", "Do not have the operation permissions"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusForbidden, errorResponse)
}
func ResponseForbidden403MultiLoginNotAllowed(w http.ResponseWriter) {
errorMessage := ErrorMessage{"2", "Multiple logins are not allowed"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusForbidden, errorResponse)
}
func ResponseNotFound404UriNotExist(w http.ResponseWriter, r *http.Request) {
errorMessage := ErrorMessage{"1", "The requested URI does not exist"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404UriNotExistExt(w http.ResponseWriter) {
errorMessage := ErrorMessage{"1", "The requested URI does not exist"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func CustomResponseNotFound404Handler() http.Handler {
return http.HandlerFunc(ResponseNotFound404UriNotExist)
}
func ResponseNotFound404NRMNotExist(w http.ResponseWriter, rmUIDs []string) {
errorMessage := ErrorMessage{"2", "rmUIDs does not exist: " + strings.Join(rmUIDs, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404PMNotExist(w http.ResponseWriter, rmUIDs []string) {
errorMessage := ErrorMessage{"3", "rmUIDs does not exist: " + strings.Join(rmUIDs, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404AlarmNotExist(w http.ResponseWriter, AlarmIds []string) {
errorMessage := ErrorMessage{"4", "AlarmIds does not exist: " + strings.Join(AlarmIds, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404GetSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
errorMessage := ErrorMessage{"5", "Subscription id does not exist: " + strings.Join(SubIds, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404DeleteSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
errorMessage := ErrorMessage{"6", "Subscription id does not exist: " + strings.Join(SubIds, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404GetAlarmSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
errorMessage := ErrorMessage{"7", "Subscription id does not exist: " + strings.Join(SubIds, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseNotFound404DeleteAlarmSubscriptionNotExist(w http.ResponseWriter, SubIds []string) {
errorMessage := ErrorMessage{"8", "Subscription id does not exist: " + strings.Join(SubIds, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotFound, errorResponse)
}
func ResponseMethodNotAllowed405(w http.ResponseWriter, r *http.Request) {
errorMessage := ErrorMessage{"1", "Method not allowed"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusMethodNotAllowed, errorResponse)
}
func CustomResponseMethodNotAllowed405Handler() http.Handler {
return http.HandlerFunc(ResponseMethodNotAllowed405)
}
func ResponseNotAcceptable406MissingParam(w http.ResponseWriter) {
errorMessage := ErrorMessage{"1", "Missing parameter: rmUIDs"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotAcceptable, errorResponse)
}
func ResponseNotAcceptable406ParamError(w http.ResponseWriter, errorParamsName []string) {
errorMessage := ErrorMessage{"2", "Parameter name error: " + strings.Join(errorParamsName, ",")}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotAcceptable, errorResponse)
}
func ResponseNotAcceptable406QuerySQLError(w http.ResponseWriter) {
errorMessage := ErrorMessage{"3", "Wrong or non-query SQL statement"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusNotAcceptable, errorResponse)
}
func ResponseRequestEntityTooLarge413SubscriptionExceed(w http.ResponseWriter, num int) {
errorMessage := ErrorMessage{"1", "The number of subscriptions greater than " + strconv.Itoa(num)}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusRequestEntityTooLarge, errorResponse)
}
func ResponseRequestEntityTooLarge413BodyToLarge(w http.ResponseWriter) {
errorMessage := ErrorMessage{"2", "The request entity too large"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusRequestEntityTooLarge, errorResponse)
}
func ResponseRequestURITooLong414NRMNumExceed(w http.ResponseWriter, num int) {
errorMessage := ErrorMessage{"1", "The number of NRM rmUIDs greater than " + strconv.Itoa(num)}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}
func ResponseRequestURITooLong414AlarmNumExceed(w http.ResponseWriter, num int) {
errorMessage := ErrorMessage{"2", "The number of alarmIds greater than " + strconv.Itoa(num)}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}
func ResponseRequestURITooLong414PMNumExceed(w http.ResponseWriter, num int) {
errorMessage := ErrorMessage{"3", "The number of PM rmUIDs greater than " + strconv.Itoa(num)}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}
func ResponseRequestURITooLong414UriTooLong(w http.ResponseWriter) {
errorMessage := ErrorMessage{"3", "Request URI too long"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusRequestURITooLong, errorResponse)
}
func ResponseUnsupportedMediaType415(w http.ResponseWriter) {
errorMessage := ErrorMessage{"1", "Unsupported media type"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusUnsupportedMediaType, errorResponse)
}
func ResponseInternalServerError500NFConnectRefused(w http.ResponseWriter) {
errorMessage := ErrorMessage{"1", "Internal server error, NF connnect refused"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusInternalServerError, errorResponse)
}
func ResponseInternalServerError500DatabaseOperationFailed(w http.ResponseWriter) {
errorMessage := ErrorMessage{"2", "Internal server error, database opration failed"}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusInternalServerError, errorResponse)
}
func ResponseInternalServerError500ProcessError(w http.ResponseWriter, err error) {
em := fmt.Sprintf("Internal server error: %v", err)
errorMessage := ErrorMessage{"3", em}
errorResponse := ErrorResponse{errorMessage}
ResponseWithJson(w, http.StatusInternalServerError, errorResponse)
}
func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) {
log.Trace("payload: ", payload)
response, _ := json.Marshal(payload)
SetResponseHeader(w)
w.WriteHeader(code)
w.Write(response)
log.Trace("Response Code:", code)
log.Trace("Response Body:", string(response))
}
func ResponseWithZip(w http.ResponseWriter, payload interface{}) {
response, _ := json.Marshal(payload)
SetResponseHeader(w)
w.WriteHeader(http.StatusOK)
w.Write(response)
log.Trace("Response Body:", string(response))
}
func TransportResponse(w http.ResponseWriter, code int, payload []byte) {
var tempBody, transBody interface{}
switch code {
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
json.Unmarshal(payload, &tempBody)
transBody = DataResponse{tempBody}
default:
json.Unmarshal(payload, &tempBody)
transBody = ErrorResponse{tempBody}
}
response, _ := json.Marshal(transBody)
log.Trace("transBody: ", transBody)
SetResponseHeader(w)
w.WriteHeader(code)
w.Write(response)
log.Trace("response: ", string(response))
}
func ResponseWithUnsortJson(w http.ResponseWriter, code int, payload map[string]interface{}) {
var om global.OrderedMap
om.Map = payload
response, _ := om.MarshalJson()
log.Trace("payload: ", payload)
SetResponseHeader(w)
w.WriteHeader(code)
w.Write(response)
log.Trace("response: ", string(response))
}
func ResponseErrorWithJson(w http.ResponseWriter, code int, nameValue interface{}) {
response := make(map[string]interface{})
response["error"] = nameValue
ResponseWithJson(w, code, response)
}
func SetCommonResponseHeader(w http.ResponseWriter) {
// To solve cross domain issue
w.Header().Set("Access-Control-Allow-Origin", "*")
// w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Methods", "*")
w.Header().Set("Access-Control-Allow-Headers", "*")
// w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
// w.Header().Set("Access-Control-Allow-Headers", "AccessToken")
w.Header().Set("Access-Control-Expose-Headers", "Access-Control-Allow-Headers, Token")
w.Header().Set("Access-Control-Allow-Credentials", "true")
}
func SetResponseHeader(w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
SetCommonResponseHeader(w)
}
// Creates a new file upload http request with optional extra params
func ResponseUploadFile(w http.ResponseWriter, code int, params map[string]string, paramName, path string) {
file, err := os.Open(path)
if err != nil {
log.Errorf("Failed to open: %v", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, filepath.Base(path))
if err != nil {
log.Error("Failed to CreateFormFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
_, err = io.Copy(part, file)
if err != nil {
log.Error("Failed to Copy:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
for key, val := range params {
_ = writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
log.Error("Failed to Close:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
SetCommonResponseHeader(w)
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(code)
w.Write(body.Bytes())
return
}
func ResponseFile(w http.ResponseWriter, code int, filePath string) {
fileBytes, err := os.ReadFile(filePath)
if err != nil {
log.Error("Failed to ReadFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
SetCommonResponseHeader(w)
w.Header().Set("Content-Type", "application/octet-stream")
w.WriteHeader(code)
w.Write(fileBytes)
return
}
func ResponseFileWithNameAndMD5(w http.ResponseWriter, code int, fileName, path, md5Sum string) {
filePath := path + "/" + fileName
fileBytes, err := ioutil.ReadFile(filePath)
if err != nil {
log.Error("Failed to ReadFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
SetCommonResponseHeader(w)
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("User-File", fileName)
w.Header().Set("MD5-Sum", md5Sum)
w.WriteHeader(code)
w.Write(fileBytes)
return
}

169
lib/session/session.go Normal file
View File

@@ -0,0 +1,169 @@
package session
import (
"crypto/rand"
"encoding/base64"
"errors"
"io"
"net/http"
"strconv"
"strings"
"sync"
"time"
"ems.agt/lib/log"
"ems.agt/lib/oauth"
"ems.agt/restagent/config"
)
// SessionMgr session manager
type SessManager struct {
name string
expires int64
lock sync.RWMutex
sessions map[string]*Session
}
// Session
type Session struct {
token string
time time.Time
permission []bool
values map[interface{}]interface{}
}
// NewSessionMgr create session manager
func NewSessManager(name string) *SessManager {
smgr := &SessManager{name: name, expires: (int64)(config.GetExpiresFromConfig()), sessions: make(map[string]*Session)}
go smgr.SessionGC()
return smgr
}
// NewSession create session
func (smgr *SessManager) NewSession(w http.ResponseWriter, r *http.Request, plist []bool) string {
smgr.lock.Lock()
defer smgr.lock.Unlock()
token := oauth.GenRandToken() // Generate new token to session ID
session := &Session{token: token, time: time.Now(), permission: plist, values: make(map[interface{}]interface{})}
smgr.sessions[token] = session
return token
}
// EndSession
func (smgr *SessManager) EndSession(w http.ResponseWriter, r *http.Request) {
token := smgr.GetTokenFromHttpRequest(r)
smgr.lock.Lock()
defer smgr.lock.Unlock()
delete(smgr.sessions, token)
}
// Handshake session, restart session
func (smgr *SessManager) ShakeSession(token string) bool {
smgr.lock.Lock()
defer smgr.lock.Unlock()
for _, s := range smgr.sessions {
if token == s.token {
log.Debug("session time:", s.time)
s.time = time.Now()
return true
}
}
return false
}
// EndSessionByID end the session by session ID
func (smgr *SessManager) DeleteSession(token string) {
smgr.lock.Lock()
defer smgr.lock.Unlock()
delete(smgr.sessions, token)
}
// SetSessionValue set value fo session
func (smgr *SessManager) SetSessionValue(token string, key interface{}, value interface{}) error {
smgr.lock.Lock()
defer smgr.lock.Unlock()
if session, ok := smgr.sessions[token]; ok {
session.values[key] = value
return nil
}
return errors.New("invalid session ID")
}
// GetSessionValue get value fo session
func (smgr *SessManager) GetSessionValue(token string, key interface{}) (interface{}, error) {
smgr.lock.RLock()
defer smgr.lock.RUnlock()
if session, ok := smgr.sessions[token]; ok {
if val, ok := session.values[key]; ok {
return val, nil
}
}
return nil, errors.New("invalid session ID")
}
func (smgr *SessManager) GetTokenFromHttpRequest(r *http.Request) string {
for k, v := range r.Header {
if strings.ToLower(k) == "accesstoken" && len(v) != 0 {
log.Debug("AccessToken:", v[0])
return v[0]
}
}
return ""
}
// IsValidToken check token is valid or not
func (smgr *SessManager) IsValidToken(token string) bool {
smgr.lock.Lock()
defer smgr.lock.Unlock()
if _, ok := smgr.sessions[token]; ok {
return true
}
return false
}
// IsCarriedToken check token is carried
func (smgr *SessManager) IsCarriedToken(r *http.Request) (string, bool) {
token := smgr.GetTokenFromHttpRequest(r)
if token == "" {
return "", false
}
return token, true
}
// GetPermissionFromSession get permission from session by token
func (smgr *SessManager) GetPermissionFromSession(token string) []bool {
if s, ok := smgr.sessions[token]; ok {
return s.permission
}
return nil
}
// SessionGC maintain session
func (smgr *SessManager) SessionGC() {
smgr.lock.Lock()
defer smgr.lock.Unlock()
for token, session := range smgr.sessions {
if session.time.Unix()+smgr.expires < time.Now().Unix() {
delete(smgr.sessions, token)
}
}
time.AfterFunc(time.Duration(smgr.expires)*time.Second, func() { smgr.SessionGC() })
}
// NewSessionID generate unique ID
func (smgr *SessManager) NewSessionID() string {
b := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
nano := time.Now().UnixNano()
return strconv.FormatInt(nano, 10)
}
return base64.URLEncoding.EncodeToString(b)
}

45
lib/websocket/client.go Normal file
View File

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

View File

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