678 lines
14 KiB
Go
678 lines
14 KiB
Go
package global
|
||
|
||
import (
|
||
"archive/zip"
|
||
"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.MkdirAll(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
|
||
}
|
||
|
||
// PathExists check path is exist or no
|
||
func FilePathExists(filePath string) (bool, error) {
|
||
_, err := os.Stat(filePath)
|
||
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
|
||
}
|
||
|
||
func ZipOneFile(srcFile, dstZip string, pathFlag bool) error {
|
||
zipFile, err := os.Create(dstZip)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer zipFile.Close()
|
||
|
||
zipWriter := zip.NewWriter(zipFile)
|
||
defer zipWriter.Close()
|
||
|
||
fileToCompress, err := os.Open(srcFile)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer fileToCompress.Close()
|
||
|
||
var fileInZip io.Writer
|
||
if pathFlag {
|
||
fileInZip, err = zipWriter.Create(srcFile)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
} else {
|
||
// 获取文件的基本名称
|
||
fileName := filepath.Base(fileToCompress.Name())
|
||
fileInZip, err = zipWriter.Create(fileName)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
_, err = io.Copy(fileInZip, fileToCompress)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func ZipDirectoryFile(srcDir, dstZip string) error {
|
||
// Create a new zip file
|
||
zipfileWriter, err := os.Create(dstZip)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer zipfileWriter.Close()
|
||
|
||
// Create a new zip archive
|
||
zipWriter := zip.NewWriter(zipfileWriter)
|
||
defer zipWriter.Close()
|
||
|
||
// Walk through the directory and add files to the zip archive
|
||
err = filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// Create a new file header for the current file
|
||
header, err := zip.FileInfoHeader(info)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// Set the name of the file within the zip archive
|
||
header.Name = filepath.Join(filepath.Base(srcDir), path[len(srcDir):])
|
||
|
||
// If the current file is a directory, skip it
|
||
if info.IsDir() {
|
||
return nil
|
||
}
|
||
|
||
// Create a new file in the zip archive
|
||
fileWriter, err := zipWriter.CreateHeader(header)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// Open the current file
|
||
file, err := os.Open(path)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer file.Close()
|
||
|
||
// Copy the contents of the current file to the zip archive
|
||
_, err = io.Copy(fileWriter, file)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
})
|
||
|
||
return err
|
||
}
|
||
|
||
// 判断软件包是rpm或者deb, 1:rpm, 2:deb, 0:unknown format
|
||
func JudgeRpmOrDebPackage(filePath string) (int, error) {
|
||
var fileType int = 0
|
||
file, err := os.Open(filePath)
|
||
if err != nil {
|
||
return fileType, err
|
||
}
|
||
defer file.Close()
|
||
|
||
// Read the first 6 bytes of the file
|
||
header := make([]byte, 6)
|
||
_, err = file.Read(header)
|
||
if err != nil {
|
||
return fileType, err
|
||
}
|
||
|
||
// Check the magic numbers to determine the package format
|
||
if string(header) == "!<arch>" {
|
||
fileType = 1
|
||
} else if string(header) == "!<arch\n" || string(header) == "!<arch\r" {
|
||
fileType = 2
|
||
} else {
|
||
fileType = 0
|
||
}
|
||
|
||
return fileType, nil
|
||
}
|
||
|
||
func isRpmPackage(file *os.File) bool {
|
||
// RPM packages start with the magic number "EDABEEDB"
|
||
magic := []byte{0xED, 0xAB, 0xEE, 0xDB}
|
||
buffer := make([]byte, len(magic))
|
||
|
||
_, err := file.Read(buffer)
|
||
if err != nil && err != io.EOF {
|
||
return false
|
||
}
|
||
|
||
return string(buffer) == string(magic)
|
||
}
|
||
|
||
func isDebPackage(file *os.File) bool {
|
||
// DEB packages start with the magic number "!<arch>\n"
|
||
magic := []byte("!<arch>\n")
|
||
buffer := make([]byte, len(magic))
|
||
|
||
_, err := file.Read(buffer)
|
||
if err != nil && err != io.EOF {
|
||
return false
|
||
}
|
||
|
||
return string(buffer) == string(magic)
|
||
}
|
||
|
||
func CheckRpmOrDebPackage(filePath string) (int, error) {
|
||
var fileType int = 0
|
||
file, err := os.Open(filePath)
|
||
if err != nil {
|
||
return fileType, err
|
||
}
|
||
defer file.Close()
|
||
|
||
isRpm := isRpmPackage(file)
|
||
isDeb := isDebPackage(file)
|
||
|
||
if isRpm {
|
||
fileType = 1
|
||
} else if isDeb {
|
||
fileType = 2
|
||
} else {
|
||
fileType = 0
|
||
}
|
||
|
||
return fileType, nil
|
||
}
|
||
|
||
func IsRpmOrDebPackage(filePath string) int {
|
||
var fileType int = 0
|
||
|
||
if strings.Contains(filePath, ".rpm") {
|
||
fileType = 1
|
||
} else if strings.Contains(filePath, ".deb") {
|
||
fileType = 2
|
||
} else {
|
||
fileType = 0
|
||
}
|
||
|
||
return fileType
|
||
}
|