You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1056 lines
22 KiB
Go

4 weeks ago
package Common
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
4 days ago
"runtime"
4 weeks ago
"net"
"os"
"os/exec"
"path"
"reflect"
"strconv"
"strings"
"time"
log "github.com/sirupsen/logrus"
// "github.com/faiface/beep/speaker"
// log "github.com/sirupsen/logrus"
)
// 截取字符串 start 起点下标 length 需要截取的长度
func Substr(str string, start int, length int) string {
defer func() {
if r := recover(); r != nil {
log.Error("Substr:", r)
}
}()
rs := []rune(str)
rl := len(rs)
end := 0
if start < 0 {
start = rl - 1 + start
}
end = start + length
if start > end {
start, end = end, start
}
if start < 0 {
start = 0
}
if start > rl {
start = rl
}
if end < 0 {
end = 0
}
if end > rl {
end = rl
}
return string(rs[start:end])
}
// insertSlice 插入
func InsertSlice(index int, newstr []byte, src []byte) (ns []byte) {
defer func() {
if r := recover(); r != nil {
log.Error("InsertSlice:", r)
}
}()
ns = append(ns, src[:index]...) // 切片后加..., 相当于拆包成单个元素
ns = append(ns, newstr...)
ns = append(ns, src[index+len(newstr):]...)
return
}
func InsertToSlice(index int, newstr []byte, src []byte) (ns []byte) {
defer func() {
if r := recover(); r != nil {
log.Error("InsertToSlice:", r)
}
}()
ns = append(ns, src[:index]...) // 切片后加..., 相当于拆包成单个元素
ns = append(ns, newstr...)
ns = append(ns, src[index:]...)
return
}
func ContainCS(list []string, key string) bool {
defer func() {
if r := recover(); r != nil {
log.Error("ContainCS:", r)
}
}()
for _, item := range list {
if item == key {
return true
}
}
return false
}
func Contain(obj interface{}, target interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("Contain:", r)
}
}()
targetValue := reflect.ValueOf(target)
switch reflect.TypeOf(target).Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < targetValue.Len(); i++ {
if targetValue.Index(i).Interface() == obj {
return true
}
}
case reflect.Map:
if targetValue.MapIndex(reflect.ValueOf(obj)).IsValid() {
return true
}
}
return false
}
// RemoveElementToint32 移除数组内的指定元素
func RemoveElementStrings(list []string, value string) []string {
defer func() {
if r := recover(); r != nil {
log.Error("RemoveElementStrings:", r)
}
}()
var result = make([]string, 0)
index := 0
endIndex := len(list) - 1
for i, s := range list {
if s == value {
result = append(result, list[index:i]...)
index = i + 1
} else if i == endIndex {
result = append(result, list[index:endIndex+1]...)
}
}
return result
}
// Strval 获取变量的字符串值
// 浮点型 3.0将会转换成字符串3, "3"
// 非数值或字符类型的变量将会被转换成JSON格式字符串
func Strval(value interface{}) string {
defer func() {
if r := recover(); r != nil {
log.Error("Strval:", r)
}
}()
var key string
if value == nil {
return key
}
switch value.(type) {
case float64:
ft := value.(float64)
key = strconv.FormatFloat(ft, 'f', -1, 64)
case float32:
ft := value.(float32)
key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
case int:
it := value.(int)
key = strconv.Itoa(it)
case uint:
it := value.(uint)
key = strconv.Itoa(int(it))
case int8:
it := value.(int8)
key = strconv.Itoa(int(it))
case uint8:
it := value.(uint8)
key = strconv.Itoa(int(it))
case int16:
it := value.(int16)
key = strconv.Itoa(int(it))
case uint16:
it := value.(uint16)
key = strconv.Itoa(int(it))
case int32:
it := value.(int32)
key = strconv.Itoa(int(it))
case uint32:
it := value.(uint32)
key = strconv.Itoa(int(it))
case int64:
it := value.(int64)
key = strconv.FormatInt(it, 10)
case uint64:
it := value.(uint64)
key = strconv.FormatUint(it, 10)
case string:
key = value.(string)
case []byte:
key = string(value.([]byte))
default:
newValue, _ := json.Marshal(value)
key = string(newValue)
}
return key
}
// MD5加密
func GetAuthKey(token string) (key string) {
defer func() {
if r := recover(); r != nil {
log.Error("GetAuthKey:", r)
}
}()
token = token
md5Ctx := md5.New()
md5Ctx.Write([]byte(token))
data := md5Ctx.Sum(nil)
return hex.EncodeToString(data)
}
/**
*@tips l.ibreoffice
* libreoffice6.2 invisible --convert-to pdf csDoc.doc --outdir /home/[]
*
* @function pdfhtml
* @param command:libreofficed()winsoffice linuxlibreoffice6.2
* fileSrcPath:
* fileOutDir:
* converterTypepdf/html
* @return fileOutPath error
*/
func FuncDocs2Pdf(command string, fileSrcPath string, fileOutDir string, converterType string) (fileOutPath string, error error) {
defer func() {
if r := recover(); r != nil {
log.Error("FuncDocs2Pdf:", r)
}
}()
//校验fileSrcPath
srcFile, erByOpenSrcFile := os.Open(fileSrcPath)
if erByOpenSrcFile != nil && os.IsNotExist(erByOpenSrcFile) {
return "", erByOpenSrcFile
}
//如文件输出目录fileOutDir不存在则自动创建
outFileDir, erByOpenFileOutDir := os.Open(fileOutDir)
if erByOpenFileOutDir != nil && os.IsNotExist(erByOpenFileOutDir) {
erByCreateFileOutDir := os.MkdirAll(fileOutDir, os.ModePerm)
if erByCreateFileOutDir != nil {
fmt.Println("File ouput dir create error.....", erByCreateFileOutDir.Error())
return "", erByCreateFileOutDir
}
}
//关闭流
defer func() {
_ = srcFile.Close()
_ = outFileDir.Close()
}()
//convert
cmd := exec.Command(command, "--invisible", "--language=zh-CN", "--convert-to", converterType,
fileSrcPath, "--outdir", fileOutDir)
byteByStat, errByCmdStart := cmd.Output()
//命令调用转换失败
if errByCmdStart != nil {
return "", errByCmdStart
}
//success
fileOutPath = fileOutDir + "/" + strings.Split(path.Base(fileSrcPath), ".")[0]
if converterType == "html" {
fileOutPath += ".html"
} else {
fileOutPath += ".pdf"
}
fmt.Println("文件转换成功...", string(byteByStat))
return fileOutPath, nil
}
// 中文转拼音函数
func ToPinYin(words string) string {
defer func() {
if r := recover(); r != nil {
log.Error("ToPinYin:", r)
}
}()
//fmt.Println("words",words)
var name string
flag := 0
for _, n := range words {
flag++
//fmt.Println("n:",strings.Replace(string(n)," ","",-1))
if (strings.Compare(strings.Replace(string(n), " ", "", -1), "覃") == 0) && (flag == 1) {
name += firstNamePin(string(n))
flag = 0
} else if (strings.Compare(strings.Replace(string(n), " ", "", -1), "区") == 0) && (flag == 1) {
name += firstNamePin(string(n))
flag = 0
} else if (strings.Compare(strings.Replace(string(n), " ", "", -1), "牟") == 0) && (flag == 1) {
name += firstNamePin(string(n))
flag = 0
} else if (strings.Compare(strings.Replace(string(n), " ", "", -1), "单") == 0) && (flag == 1) {
name += firstNamePin(string(n))
flag = 0
} else {
// str, err := pinyin.New(string(n)).Split("").Mode(pinyin.InitialsInCapitals).Convert()
// if err != nil {
// fmt.Println("转换拼音异常...")
// } else {
// name += str
// }
}
}
return name
}
// 多音字解决方法,尤其是姓氏
func firstNamePin(name string) string {
defer func() {
if r := recover(); r != nil {
log.Error("firstNamePin:", r)
}
}()
var n string
//fmt.Println("name:",name)
n = ""
if strings.Compare(name, "覃") == 0 {
n = "Qin"
} else if strings.Compare(name, "区") == 0 {
n = "Ou"
} else if strings.Compare(name, "牟") == 0 {
n = "Mu"
} else if strings.Compare(name, "单") == 0 {
n = "Shan"
}
return n
}
func DeleteFile(Path string) (total int64, err error) {
defer func() {
if r := recover(); r != nil {
log.Error("DeleteFile:", r)
}
}()
if Path != "" {
err = os.Remove(Path) //删除文件
if err != nil {
//如果删除失败则输出 file remove Error!
fmt.Println("file remove Error!")
//输出错误详细信息
fmt.Printf("%s", err)
return 0, err
}
return 1, nil
}
return 2, nil
}
func PathExists(path string) (bool, error) {
defer func() {
if r := recover(); r != nil {
log.Error("PathExists:", r)
}
}()
_, err := os.Stat(path)
if err != nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, nil
}
/**
* true false
*/
func CheckFileIsExists(filename string) bool {
defer func() {
if r := recover(); r != nil {
log.Error("CheckFileIsExists:", r)
}
}()
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
/*
*
*/
func IsDirs(fileAddr string) bool {
defer func() {
if r := recover(); r != nil {
log.Error("IsDirs:", r)
}
}()
s, err := os.Stat(fileAddr)
if err != nil {
log.Println(err)
return false
}
return s.IsDir()
}
/*
goAndroid
*/
// func JpushGoSend(tags []string, aliasPhone []string, context string, state, jpushState int) error {
// //state区分推送方式 jpushState :区分推送消息的类别;
// //构建要推送的平台: jpushclient.Platform
// var pf jpushclient.Platform
// pf.Add(jpushclient.ANDROID)
// //构建接收听众: jpushclient.Audience
// var ad jpushclient.Audience
// if state == JpushTag {
// //推送 通知公告
// if tags[0] == AdminLevelOne {
// //极光推送 - 所有
// //一级管理员发布,所有人员接收
// ad.All()
// } else {
// //极光推送 - tag
// //二级或者三级管理员发布下属app人员接收
// ad.SetTag(tags)
// }
// } else {
// //极光推送 - 别名 用app用户的登录手机号当作别名
// ad.SetAlias(aliasPhone)
// }
// //构建通知 jpushclient.Notice或者消息 jpushclient.Message
// //Notice
// var notice jpushclient.Notice
// notice.SetAlert("alert_test")
// if jpushState == JpushStateNotice {
// //推送通知公告
// notice.SetAndroidNotice(&jpushclient.AndroidNotice{Title: "通知公告", Alert: context})
// } else {
// //推送新单
// notice.SetAndroidNotice(&jpushclient.AndroidNotice{Title: "新派xx单", Alert: context})
// }
// //构建jpushclient.PayLoad
// payload := jpushclient.NewPushPayLoad()
// payload.SetPlatform(&pf)
// payload.SetAudience(&ad)
// payload.SetNotice(&notice)
// bytes, _ := payload.ToBytes()
// fmt.Printf("%s\r\n", string(bytes))
// //构建PushClient发出推送
// c := jpushclient.NewPushClient(masterSecret, appKey)
// r, err := c.Send(bytes)
// if err != nil {
// fmt.Printf("err:%s", err.Error())
// return err
// } else {
// fmt.Printf("ok:%s", r)
// }
// return nil
// }
func intToChinese(num int) string {
defer func() {
if r := recover(); r != nil {
log.Error("intToChinese:", r)
}
}()
chineseNums := []string{"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}
chineseUnits := []string{"", "十", "百", "千"}
chineseBigUnits := []string{"", "万", "亿", "万亿"} // 可根据需求扩展更大的单位
var result strings.Builder
zero := true // 是否需要补零
unit := 0 // 当前的单位
for num > 0 {
n := num % 10
if n > 0 {
if zero {
result.WriteString(chineseNums[0]) // 如果需要补零,则先补零
}
result.WriteString(chineseNums[n])
result.WriteString(chineseUnits[unit])
zero = false
} else {
zero = true
}
unit++
if unit == 4 { // 单位循环
unit = 0
result.WriteString(chineseBigUnits[unit])
}
num /= 10
}
return reverseString(result.String())
}
// 反转字符串
func reverseString(s string) string {
defer func() {
if r := recover(); r != nil {
log.Error("reverseString:", r)
}
}()
r := []rune(s)
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
func MapsAreEqual(map1, map2 map[string]interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("MapsAreEqual:", r)
}
}()
// 检查长度是否相等
if len(map1) != len(map2) {
return false
}
// 遍历 map1 的键值对
for key, value := range map1 {
// 检查 map2 中是否存在相同的键
if value2, ok := map2[key]; ok {
// 递归比较值
if !valuesAreEqual(value, value2) {
return false
}
} else {
// map2 中不存在相同的键
return false
}
}
return true
}
func valuesAreEqual(value1, value2 interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("valuesAreEqual:", r)
}
}()
// 判断类型是否相同
if reflect.TypeOf(value1) != reflect.TypeOf(value2) {
return false
}
// 对不同类型的值进行比较
switch value1 := value1.(type) {
case map[string]interface{}:
return MapsAreEqual(value1, value2.(map[string]interface{}))
case []interface{}:
return slicesAreEqual(value1, value2.([]interface{}))
case []map[string]interface{}:
return slicesmapAreEqual(value1, value2.([]map[string]interface{}))
case int, int32, int64, uint, uint32, uint64, float32, float64, string, bool, time.Time:
// 基本类型直接比较值
return value1 == value2
default:
return structValuesAreEqual(value1, value2)
}
}
func structValuesAreEqual(value1, value2 interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("structValuesAreEqual:", r)
}
}()
// 获取 value1 和 value2 的反射值
v1 := reflect.ValueOf(value1)
v2 := reflect.ValueOf(value2)
// 判断类型是否相同
if v1.Type() != v2.Type() {
return false
}
// 遍历结构体的字段
for i := 0; i < v1.NumField(); i++ {
// 获取字段的反射值和名称
field1 := v1.Field(i)
field2 := v2.Field(i)
name := v1.Type().Field(i).Name
// 递归比较属性值
if !valuesAreEqual(field1.Interface(), field2.Interface()) {
fmt.Printf("%s: %v != %v\n", name, field1.Interface(), field2.Interface())
return false
}
}
return true
}
func slicesmapAreEqual(slice1, slice2 []map[string]interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("slicesmapAreEqual:", r)
}
}()
// 检查长度是否相等
if len(slice1) != len(slice2) {
return false
}
// 递归比较每个元素
for i := 0; i < len(slice1); i++ {
if !valuesAreEqual(slice1[i], slice2[i]) {
return false
}
}
return true
}
func slicesAreEqual(slice1, slice2 []interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("slicesAreEqual:", r)
}
}()
// 检查长度是否相等
if len(slice1) != len(slice2) {
return false
}
// 递归比较每个元素
for i := 0; i < len(slice1); i++ {
if !valuesAreEqual(slice1[i], slice2[i]) {
return false
}
}
return true
}
// IsNullOrEmpty 检查字符串是否为空或为nil
func IsNullOrEmpty(s *string) bool {
defer func() {
if r := recover(); r != nil {
log.Error("IsNullOrEmpty:", r)
}
}()
if s == nil || *s == "" {
return true
}
return false
}
func Contains(slice []interface{}, item interface{}) bool {
defer func() {
if r := recover(); r != nil {
log.Error("Contains:", r)
}
}()
for _, sliceItem := range slice {
if sliceItem == item {
return true
}
}
return false
}
func CreateMutiDir(filePath string) error {
defer func() {
if r := recover(); r != nil {
log.Error("CreateMutiDir:", r)
}
}()
if !isExist(filePath) {
err := os.MkdirAll(filePath, os.ModePerm)
if err != nil {
fmt.Println("创建文件夹失败,error info:", err)
return err
}
return err
}
return nil
}
// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
defer func() {
if r := recover(); r != nil {
log.Error("isExist:", r)
}
}()
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func IsExist(path string) bool {
defer func() {
if r := recover(); r != nil {
log.Error("IsExist:", r)
}
}()
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func StructToMap(obj interface{}) map[string]interface{} {
defer func() {
if r := recover(); r != nil {
log.Error("StructToMap:", r)
}
}()
objValue := reflect.ValueOf(obj)
if objValue.Kind() == reflect.Ptr {
objValue = objValue.Elem()
}
if objValue.Kind() != reflect.Struct {
panic("传入的不是结构体类型")
}
objType := objValue.Type()
result := make(map[string]interface{})
for i := 0; i < objValue.NumField(); i++ {
field := objValue.Field(i)
fieldName := objType.Field(i).Name
result[fieldName] = field.Interface()
}
return result
}
func GetLocalIP() string {
defer func() {
if r := recover(); r != nil {
log.Error("GetLocalIP:", r)
}
}()
var IPAddress string = "127.0.0.1"
netInterfaces, err := net.Interfaces()
if err != nil {
fmt.Println("net.Interfaces failed, err:", err.Error())
return IPAddress
}
for i := 0; i < len(netInterfaces); i++ {
if (netInterfaces[i].Flags & net.FlagUp) != 0 {
addrs, _ := netInterfaces[i].Addrs()
for _, address := range addrs {
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
IPAddress = ipnet.IP.String()
return IPAddress
}
}
}
}
}
return IPAddress
}
func Md5func(filePath string) string {
defer func() {
if r := recover(); r != nil {
log.Error("Md5func:", r)
}
}()
// 打开文件
file, err := os.Open(filePath)
if err != nil {
fmt.Println("无法打开文件:", err)
return ""
}
defer file.Close()
// 创建一个 MD5 的哈希对象
hash := md5.New()
// 将文件内容拷贝到哈希对象中
if _, err := io.Copy(hash, file); err != nil {
fmt.Println("无法读取文件内容:", err)
return ""
}
// 计算 MD5 哈希值
hashInBytes := hash.Sum(nil)
// 将字节转换为十六进制表示
md5Hash := hex.EncodeToString(hashInBytes)
fmt.Printf("文件 %s 的MD5哈希值为: %s\n", filePath, md5Hash)
return md5Hash
}
func PlayMusic(musicPath string) error {
defer func() {
if r := recover(); r != nil {
log.Error("PlayMusic:", r)
}
}()
// 打开wav文件
f, err := os.Open(musicPath)
if err != nil {
// log.Fatal(err) Fatal报错直接退出程序
log.Println(err)
return err
}
defer f.Close()
// 解码wav文件
// streamer, format, err := wav.Decode(f)
// if err != nil {
// log.Println(err)
// return err
// }
// 初始化音频驱动
// err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
// if err != nil {
// log.Println(err)
// return err
// }
// 异步播放音频
// go func() {
// done := make(chan bool)
// speaker.Play(beep.Seq(streamer, beep.Callback(func() {
// done <- true
// })))
// // 等待音频播放完成
// <-done
// }()
// 播放音频
// done := make(chan bool)
// speaker.Play(beep.Seq(streamer, beep.Callback(func() {
// done <- true
// })))
// fmt.Println("Playing audio...")
// // 等待音频播放完成
// <-done
// 等待一段时间确保音频播放完毕
// time.Sleep(time.Duration(streamer.Len()) / time.Duration(format.SampleRate))
// time.Sleep(5 * time.Second)
return nil
}
// func PlayMusics(musicPath string) error {
// // 打开wav文件
// f, err := os.Open(musicPath)
// if err != nil {
// log.Println(err)
// return err
// }
// defer f.Close()
// // 解码wav文件
// streamer, format, err := wav.Decode(f)
// if err != nil {
// log.Println(err)
// return err
// }
// // 初始化音频驱动
// err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
// if err != nil {
// log.Println(err)
// return err
// }
// // 播放音频
// done := make(chan struct{})
// // 启动一个新的goroutine来播放音频
// go func() {
// defer func() {
// if err := recover(); err != nil {
// log.WithFields(log.Fields{
// "function": "PlayMusics",
// "error": err,
// }).Error("PlayMusics")
// // log.Printf("OpenDevice: %v", err) // 记录错误信息到日志
// fmt.Println("PlayMusics:", err) // 打印错误信息
// }
// }()
// defer close(done)
// // 使用非阻塞方式播放
// speaker.Play(streamer)
// }()
// fmt.Println("Playing audio...")
// // 等待足够长的时间确保音频播放完毕
// time.Sleep(5 * time.Second)
// // 等待音频播放完成
// <-done
// return nil
// }
// FormatTime 将时间字符串格式化为 HH:MM 格式
func FormatTime(timeStr string) string {
defer func() {
if r := recover(); r != nil {
log.Error("FormatTime:", r)
}
}()
// 按照冒号分割小时和分钟
parts := strings.Split(timeStr, ":")
if len(parts) != 2 {
return timeStr // 返回原始字符串如果格式不对
}
// 将小时和分钟转换为整数
hours, err1 := strconv.Atoi(parts[0])
minutes, err2 := strconv.Atoi(parts[1])
if err1 != nil || err2 != nil {
return timeStr // 返回原始字符串如果转换失败
}
// 格式化小时和分钟为两位数字
return fmt.Sprintf("%02d:%02d", hours, minutes)
}
func FormatTimes(now time.Time, format string) string {
// 替换常见的日期时间格式标记
format = strings.ReplaceAll(format, "YYYY", "2006")
format = strings.ReplaceAll(format, "YY", "06")
// 特殊处理带中文的月和日
if strings.Contains(format, "月") {
format = strings.ReplaceAll(format, "MM", "1")
} else {
format = strings.ReplaceAll(format, "MM", "01")
}
if strings.Contains(format, "日") {
format = strings.ReplaceAll(format, "DD", "2")
} else {
format = strings.ReplaceAll(format, "DD", "02")
}
format = strings.ReplaceAll(format, "HH", "15")
format = strings.ReplaceAll(format, "mm", "04")
format = strings.ReplaceAll(format, "ss", "05")
return now.Format(format)
}
func GetAvailableEndpoint() string {
primaryIP := LoadConfig().SeverData.ServerIP
backupIP := LoadConfig().SeverData.BackUpServerIP // 替换为实际备选IP
4 days ago
if IsIPReachable(primaryIP, "9800") {
return primaryIP
}
4 days ago
if IsIPReachable(backupIP, "9800") {
return backupIP
}
return ""
}
4 days ago
func IsIPReachable(ip string, port string) bool {
4 days ago
var cmd *exec.Cmd
// cmd := exec.Command("ping", "-c", "1", "-W", "1", ip)
timeout := 100 // 毫秒
if runtime.GOOS == "windows" {
cmd = exec.Command("ping", "-n", "1", "-w", strconv.Itoa(timeout), ip)
} else {
cmd = exec.Command("ping", "-c", "1", "-W", strconv.Itoa(timeout/1000), ip)
}
4 days ago
if err := cmd.Run(); err == nil {
return true
}
4 days ago
return false
}