Files
be.ems/lib/global/kits.go
2024-05-28 10:15:41 +08:00

729 lines
15 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
func GetSecondDuration(time1, time2 string) (int64, error) {
loc1, _ := time.LoadLocation("Local")
// 解析日期时间字符串为时间对象
t1, err := time.ParseInLocation(time.DateTime, time1, loc1)
if err != nil {
return 0, err
}
t2, err := time.ParseInLocation(time.DateTime, time2, loc1)
if err != nil {
return 0, err
}
// 计算时间差
duration := t2.Sub(t1)
// 获取时间差的秒数
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
}
func RecurseStructToMap(obj any) map[string]any {
out := make(map[string]any)
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// 递归函数,用于处理嵌套结构体
var recurse func(reflect.Value) any
recurse = func(value reflect.Value) any {
if value.Kind() == reflect.Struct {
nestedOut := make(map[string]any)
for i := 0; i < value.NumField(); i++ {
nestedOut[value.Type().Field(i).Name] = recurse(value.Field(i))
}
return nestedOut
} else if value.Kind() == reflect.Ptr {
return recurse(value.Elem())
}
return value.Interface()
}
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
out[t.Field(i).Name] = recurse(f)
}
return out
}