2024-06-17 14:18:39 +08:00
|
|
|
|
package utils
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2024-09-30 17:58:30 +08:00
|
|
|
|
"crypto/hmac"
|
2024-06-17 14:18:39 +08:00
|
|
|
|
"crypto/md5"
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"crypto/sha512"
|
2024-08-29 22:21:12 +08:00
|
|
|
|
"encoding/csv"
|
2024-06-17 14:18:39 +08:00
|
|
|
|
"encoding/hex"
|
|
|
|
|
"fmt"
|
2024-08-21 14:30:20 +08:00
|
|
|
|
"github.com/ZZMarquis/gm/sm4"
|
2024-06-17 14:18:39 +08:00
|
|
|
|
"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"
|
2024-06-19 18:32:34 +08:00
|
|
|
|
"sync/atomic"
|
2024-06-17 14:18:39 +08:00
|
|
|
|
"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)
|
2024-08-29 22:21:12 +08:00
|
|
|
|
var datetime = time.Now().Format(time.DateTime)
|
2024-06-17 14:18:39 +08:00
|
|
|
|
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())
|
2024-10-22 14:25:40 +08:00
|
|
|
|
randomPart := fmt.Sprintf("%06d", mrand.Intn(100000))
|
2024-06-17 14:18:39 +08:00
|
|
|
|
|
|
|
|
|
// 添加固定前缀
|
2024-10-22 14:25:40 +08:00
|
|
|
|
//prefix := "SN"
|
|
|
|
|
prefix := ""
|
2024-06-17 14:18:39 +08:00
|
|
|
|
|
|
|
|
|
// 最终的订单号由前缀、日期和随机数部分组成
|
|
|
|
|
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 {
|
2024-06-25 13:51:22 +08:00
|
|
|
|
Id string
|
|
|
|
|
CustNo string
|
2024-06-17 14:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GeneratorJwtToken(user User) string {
|
|
|
|
|
// 定义一个用于签名的密钥
|
|
|
|
|
secretKey := []byte(config.GetConf().Jwt.SecretKey)
|
|
|
|
|
|
|
|
|
|
// 创建一个MapClaims对象,用于存放自定义的声明信息
|
|
|
|
|
claims := jwt.MapClaims{
|
2024-06-25 13:51:22 +08:00
|
|
|
|
"id": user.Id,
|
|
|
|
|
"custNo": user.CustNo,
|
|
|
|
|
"exp": time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间为24小时后
|
2024-06-17 14:18:39 +08:00
|
|
|
|
}
|
|
|
|
|
// 使用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 {
|
2024-06-25 13:51:22 +08:00
|
|
|
|
Id string
|
|
|
|
|
CustNo string
|
2024-06-17 14:18:39 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
2024-06-19 18:32:34 +08:00
|
|
|
|
|
|
|
|
|
// 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<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
|
|
|
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
|
|
|
|
)
|
|
|
|
|
var letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
var src = mrand.NewSource(time.Now().UnixNano())
|
|
|
|
|
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)
|
|
|
|
|
}
|
2024-06-25 10:12:48 +08:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
2024-08-21 14:30:20 +08:00
|
|
|
|
|
|
|
|
|
func Sm4Decrpt(data []byte) ([]byte, error) {
|
|
|
|
|
var iv = "UISwD9fW6cFh9SNS"
|
|
|
|
|
data, err := sm4.CBCDecrypt([]byte(config.GetConf().SmFourKey), []byte(iv), data)
|
|
|
|
|
return data, err
|
|
|
|
|
}
|
2024-08-29 22:21:12 +08:00
|
|
|
|
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()
|
|
|
|
|
}
|
2024-09-30 17:58:30 +08:00
|
|
|
|
|
|
|
|
|
func HmacSha256To16(key string, data string) string {
|
|
|
|
|
mac := hmac.New(sha256.New, []byte(key))
|
|
|
|
|
_, _ = mac.Write([]byte(data))
|
|
|
|
|
encode := mac.Sum(nil)
|
|
|
|
|
|
|
|
|
|
return hex.EncodeToString(encode)
|
|
|
|
|
}
|