package utils import ( "context" "crypto/md5" "crypto/rand" "crypto/sha256" "crypto/sha512" "encoding/csv" "encoding/hex" "fmt" "github.com/ZZMarquis/gm/sm4" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" "github.com/pkg/errors" "github.com/qit-team/snow-core/redis" "github.com/tjfoc/gmsm/sm2" "github.com/tjfoc/gmsm/x509" mrand "math/rand" "net" "os" "path/filepath" "qteam/app/constants/common" "qteam/config" "reflect" "regexp" "runtime" "strings" "sync/atomic" "time" "unicode" ) const ( CODE62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" codeLen = 20 ) func GetHostIp() string { conn, err := net.Dial("udp", "8.8.8.8:53") if err != nil { fmt.Println("get current host ip err: ", err) return "" } addr := conn.LocalAddr().(*net.UDPAddr) ip := strings.Split(addr.String(), ":")[0] return ip } func Log(c *gin.Context, name string, msg ...interface{}) { _, file, line, _ := runtime.Caller(1) var datetime = time.Now().Format(time.DateTime) fmt.Println(name, msg, file, line, datetime) } func GetRealKey(key string) string { return config.GetConf().ServiceName + ":" + key } // MD5加密 func SToMd5(data string) string { r := md5.Sum([]byte(data)) return hex.EncodeToString(r[:]) } /** * 编码 整数 为 base62 字符串 */ func Encode(number int64) string { if number == 0 { return "0" } result := make([]byte, 0) for number > 0 { round := number / codeLen remain := number % codeLen result = append(result, CODE62[remain]) number = round } return string(result) } // 生成用户touken func GeneratorToken(playerName string, playerId int) string { //去生成一个token返回给客户端 m5 := SToMd5(playerName + time.Now().String()) var pid = int64(playerId) bsCode := Encode(pid) tk := m5 + bsCode //将token放入redis _, err := redis.GetRedis(redis.SingletonMain).SetEX(context.Background(), GetRealKey(common.TOKEN_PRE+tk), playerId, time.Duration(3600)*time.Second).Result() if err != nil { Log(nil, "token", err) } return tk } // ExistFile 检查给定的文件是否存在 func ExistFile(dirPath string) (exist bool, err error) { // 使用filepath.Abs获取绝对路径,确保我们处理的是实际存在的路径 absPath, err := filepath.Abs(dirPath) if err != nil { return exist, fmt.Errorf("failed to get absolute path: %v", err) } // 使用os.Stat检查路径是否存在 _, err = os.Stat(absPath) if errors.Is(err, os.ErrNotExist) { return exist, nil } return true, err } // StrToTimeShanghai 字符串转时间 func StrToTimeShanghai(strTime string) (t time.Time, err error) { location, _ := time.LoadLocation("Asia/Shanghai") return time.ParseInLocation(time.DateTime, strTime, location) } func GenIncrementId(tableName string) (int, error) { var id, err = redis.GetRedis().Incr(context.Background(), GetRealKey(tableName)).Result() return int(id), err } // CheckOrCreateYmdDirectory 创建ymd目录 func CheckOrCreateYmdDirectory(dirPath string) (SavePath string, err error) { // 使用filepath.Abs获取绝对路径,确保我们处理的是实际存在的路径 now := time.Now() year := now.Year() month := now.Month() day := now.Day() savePath := filepath.Join("uploads", dirPath, fmt.Sprintf("%d", year), fmt.Sprintf("%d", month), fmt.Sprintf("%d", day)) absPath, err := filepath.Abs(savePath) if err != nil { return SavePath, fmt.Errorf("failed to get absolute path: %v", err) } // 使用os.Stat检查路径是否存在 info, err := os.Stat(absPath) if err != nil { if !os.IsNotExist(err) { return SavePath, fmt.Errorf("error checking directory: %v", err) } // 目录不存在,尝试创建 err = os.MkdirAll(absPath, 0755) // 0755是默认权限,可以按需调整 if err != nil { return SavePath, fmt.Errorf("failed to create directory: %v", err) } } else if !info.IsDir() { return SavePath, fmt.Errorf("%s exists but it's not a directory", absPath) } SavePath = absPath return SavePath, nil } // CheckOrCreateDirectory 检查给定的目录是否存在,如果不存在则创建它 func CheckOrCreateDirectory(dirPath string) error { // 使用filepath.Abs获取绝对路径,确保我们处理的是实际存在的路径 absPath, err := filepath.Abs(dirPath) if err != nil { return fmt.Errorf("failed to get absolute path: %v", err) } // 使用os.Stat检查路径是否存在 info, err := os.Stat(absPath) if err != nil { if !os.IsNotExist(err) { return fmt.Errorf("error checking directory: %v", err) } // 目录不存在,尝试创建 err = os.MkdirAll(absPath, 0755) // 0755是默认权限,可以按需调整 if err != nil { return fmt.Errorf("failed to create directory: %v", err) } } else if !info.IsDir() { return fmt.Errorf("%s exists but it's not a directory", absPath) } return nil } func ToSnakeCase(s string) string { ch, en := splitChineseEnglish(s) fmt.Println(ch, en) re := regexp.MustCompile("([a-z0-9])([A-Z])") snake := re.ReplaceAllString(en, "${1}_${2}") return strings.ToLower(snake) + ch } func splitChineseEnglish(input string) (chinese string, english string) { var index = findChineseStartIndex(input) return input[index:], input[0:index] } func findChineseStartIndex(input string) int { runes := []rune(input) for i, r := range runes { if unicode.Is(unicode.Han, r) { return i } } return -1 // 如果没有找到中文字符,返回-1 } func DownloadFileFromOss(url, savePath string) error { _, bucket, err := AliOssClient() if err != nil { return err } err = bucket.GetObjectToFileWithURL(url, savePath) return err } func EntityCopy(dst, src interface{}) { dstValue := reflect.ValueOf(dst).Elem() srcValue := reflect.ValueOf(src).Elem() for i := 0; i < srcValue.NumField(); i++ { srcField := srcValue.Field(i) srcName := srcValue.Type().Field(i).Name dstFieldByName := dstValue.FieldByName(srcName) if dstFieldByName.IsValid() { switch dstFieldByName.Kind() { case reflect.Ptr: switch srcField.Kind() { case reflect.Ptr: if srcField.IsNil() { dstFieldByName.Set(reflect.New(dstFieldByName.Type().Elem())) } else { dstFieldByName.Set(srcField) } default: dstFieldByName.Set(srcField.Addr()) } default: switch srcField.Kind() { case reflect.Ptr: if srcField.IsNil() { dstFieldByName.Set(reflect.Zero(dstFieldByName.Type())) } else { dstFieldByName.Set(srcField.Elem()) } default: if srcField.Type().Name() == "Time" { if (srcField.Interface().(time.Time).Unix()) < 1 { dstFieldByName.Set(reflect.ValueOf("")) } else { dstFieldByName.Set(reflect.ValueOf(srcField.Interface().(time.Time).Format("2006-01-02 15:04:05"))) } } else { dstFieldByName.Set(srcField) } } } } } } // AliOssClient 返回Oss客户链接 func AliOssClient() (client *oss.Client, Bucket *oss.Bucket, err error) { /* oss 的相关配置信息 */ bucketName := config.GetConf().AliOss.BucKet endpoint := config.GetConf().AliOss.EndPoint accessKeyId := config.GetConf().AliOss.AccessKey accessKeySecret := config.GetConf().AliOss.AccessKeySecret //domain := config.GetConf().AliOss.Domain //Dir := config.GetConf().AliOss.Dir //创建OSSClient实例 client, err = oss.New(endpoint, accessKeyId, accessKeySecret) if err != nil { return nil, nil, err } // 获取存储空间 Bucket, err = client.Bucket(bucketName) if err != nil { return nil, nil, err } return client, Bucket, nil } func GetSHA256HashCode(message []byte) string { //方法一: //创建一个基于SHA256算法的hash.Hash接口的对象 hash := sha256.New() //输入数据 hash.Write(message) //计算哈希值 bytes := hash.Sum(nil) //将字符串编码为16进制格式,返回字符串 hashCode := hex.EncodeToString(bytes) //返回哈希值 return hashCode //方法二: //bytes2:=sha256.Sum256(message)//计算哈希值,返回一个长度为32的数组 //hashcode2:=hex.EncodeToString(bytes2[:])//将数组转换成切片,转换成16进制,返回字符串 //return hashcode2 } func GetSHA512HashCode(message []byte) string { hash := sha512.New() hash.Write(message) bytes := hash.Sum(nil) hashCode := hex.EncodeToString(bytes) return hashCode } // SM2Encode sm2公钥加密 func SM2Encode(pubKey string, plaintext string, mode int) (string, error) { pubMen, err := x509.ReadPublicKeyFromHex(pubKey) if err != nil { return "", err } msg := []byte(plaintext) ciphertxt, err := sm2.Encrypt(pubMen, msg, rand.Reader, mode) if err != nil { return "", err } return hex.EncodeToString(ciphertxt), nil } // SM2Decode sm2私钥解密 func SM2Decode(privKey string, data string, mode int) (string, error) { priv, err := x509.ReadPrivateKeyFromHex(privKey) if err != nil { return "", err } ciphertext, err := hex.DecodeString(data) if err != nil { return "", err } plaintext, err := sm2.Decrypt(priv, []byte(ciphertext), mode) if err != nil { return "", err } return string(plaintext), nil } func GenerateOrderNumber() string { // 生成当前日期部分(例如:20231008) datePart := time.Now().Format("20060102150405") // 生成随机数部分(4位随机数) mrand.Seed(time.Now().UnixNano()) randomPart := fmt.Sprintf("%04d", mrand.Intn(10000)) // 添加固定前缀 prefix := "SN" // 最终的订单号由前缀、日期和随机数部分组成 orderNumber := fmt.Sprintf("%s%s%s", prefix, datePart, randomPart) return orderNumber } func IsNil(x interface{}) bool { if x == nil { return true } rv := reflect.ValueOf(x) return rv.Kind() == reflect.Ptr && rv.IsNil() } type User struct { Id string CustNo string } func GeneratorJwtToken(user User) string { // 定义一个用于签名的密钥 secretKey := []byte(config.GetConf().Jwt.SecretKey) // 创建一个MapClaims对象,用于存放自定义的声明信息 claims := jwt.MapClaims{ "id": user.Id, "custNo": user.CustNo, "exp": time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间为24小时后 } // 使用HS256算法创建一个Token对象 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // 使用密钥对Token进行签名,生成JWT字符串 tokenString, err := token.SignedString(secretKey) if err != nil { fmt.Println("Failed to create token:", err) return "" } return tokenString } type Claims struct { Id string CustNo string jwt.StandardClaims } func ParseToken(tokenString string) (*jwt.Token, *Claims, error) { Claims := &Claims{} token, err := jwt.ParseWithClaims(tokenString, Claims, func(token *jwt.Token) (i interface{}, err error) { return []byte(config.GetConf().Jwt.SecretKey), nil }) return token, Claims, err } // generateRequestNumber 生成一个全局唯一的请求流水号 func GenerateRequestNumber() string { // 时间戳部分,精确到毫秒 timestamp := time.Now().UnixNano() / int64(time.Millisecond) // 机器标识部分,可以是IP地址、主机名或者自定义的机器唯一标识 // 这里简单使用随机数模拟机器标识部分 machineID := mrand.Int63n(1000) // 序列号部分,使用原子操作保证线程安全的递增 var sequence uint32 atomic.AddUint32(&sequence, 1) // 生成随机字符串部分,增加复杂度和唯一性 randStr := RandomString(4) // 拼接各部分生成最终的请求流水号 return fmt.Sprintf("%d-%d-%d-%s", timestamp, machineID, sequence, randStr) } // randomString 生成指定长度的随机字符串 func RandomString(n int) string { const ( letterIdxBits = 6 // 6 bits to represent a letter index letterIdxMask = 1<= 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 RandomNumber(n int) (result string) { mrand.Seed(time.Now().UnixNano()) // 生成包含 10 位随机数字的字符串 for i := 0; i < n; i++ { digit := mrand.Intn(10) result += fmt.Sprintf("%d", digit) } return result } func Sm4Decrpt(data []byte) ([]byte, error) { var iv = "UISwD9fW6cFh9SNS" data, err := sm4.CBCDecrypt([]byte(config.GetConf().SmFourKey), []byte(iv), data) return data, err } func DownloadBill(xmlString string, key int) { f, _ := os.Create(fmt.Sprintf("./bills/对账单%s-%d.csv", time.Now().Format(time.DateOnly), key)) defer f.Close() w := csv.NewWriter(f) w.Write([]string{"交易缩写", "清算日期", "商户日期时间 ", "订单号", "平台流水号", "商户号", "终端号", "订单金额", "手续费", "响应码", "商户保留 1", "商户保留 2", "交易渠道", "费率类型", "交易通道", "成本手续费", "账户卡类型", "商户保留 3", "交易状态"}) var string = xmlString[strings.Index(xmlString, "CSER"):] data := string[0:strings.Index(string, "<")] rows := strings.Split(data, "\n") for _, v := range rows { var tp = "支付" if strings.Index(v, "SPR") > 0 { tp = "退款" } v = strings.Replace(v, "CSER", "", 1) v = strings.Replace(v, "CSPR", "", 1) row := strings.Split(v, "|+|") if len(row) == 19 { row[0] = tp row[18] = strings.Replace(row[18], "|-|", "", 1) row[2] = "'" + row[2] row[3] = "'" + row[3] row[4] = "'" + row[4] row[5] = "'" + row[5] fmt.Println(w.Write(row)) } else { fmt.Println(v) } } w.Flush() }