273 lines
7.0 KiB
Go
273 lines
7.0 KiB
Go
package utils
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"net"
|
||
"reflect"
|
||
"sort"
|
||
"strconv"
|
||
"strings"
|
||
"sync/atomic"
|
||
"time"
|
||
|
||
"gitee.com/red-future---jilin-g/common/beans"
|
||
"github.com/gogf/gf/v2/database/gredis"
|
||
"github.com/gogf/gf/v2/errors/gcode"
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
"github.com/tiger1103/gfast-token/gftoken"
|
||
)
|
||
|
||
// ValidStructPtr 验证是否为结构体指针
|
||
func ValidStructPtr(req any) (err error) {
|
||
//验证请求参数必须为指针
|
||
var (
|
||
reflectValue reflect.Value
|
||
reflectKind reflect.Kind
|
||
)
|
||
if v, ok := req.(reflect.Value); ok {
|
||
reflectValue = v
|
||
} else {
|
||
reflectValue = reflect.ValueOf(req)
|
||
}
|
||
|
||
reflectKind = reflectValue.Kind()
|
||
if reflectKind != reflect.Ptr {
|
||
err = gerror.NewCode(gcode.CodeInvalidParameter, `the parameter "req" for function Find should type of *struct/*[]struct`)
|
||
}
|
||
return
|
||
}
|
||
|
||
// GetMonthToday 获取N个月前的某日
|
||
func GetMonthToday(t time.Time, month int) time.Time {
|
||
// today
|
||
fmt.Printf("today: [%s]\n", t)
|
||
// 判断天数范围 小于等于28天的计算,覆盖大多数情况
|
||
if t.Day() <= 28 {
|
||
return t.AddDate(0, -month, 0)
|
||
}
|
||
// 月份的天数数组
|
||
monthDay := [13]int{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||
// 计算目标所在日期
|
||
target := t.AddDate(0, 0, 1-t.Day()).AddDate(0, -month, 0)
|
||
// 计算当月最大天数
|
||
targetDay := monthDay[target.Month()]
|
||
// 计算闰年
|
||
if target.Month() == time.February && (target.Year()%400 == 0 || (target.Year()%100 != 0 && target.Year()%4 == 0)) {
|
||
targetDay++
|
||
}
|
||
if t.Day() > targetDay {
|
||
return target.AddDate(0, 0, targetDay-1)
|
||
}
|
||
return target.AddDate(0, 0, t.Day()-1)
|
||
}
|
||
|
||
func GetUserInfo(ctx context.Context) (user beans.User, err error) {
|
||
r := g.RequestFromCtx(ctx)
|
||
if r != nil {
|
||
redisAddr := g.Cfg().MustGet(ctx, "redis.default.address").String()
|
||
gft := gftoken.NewGfToken(
|
||
gftoken.WithCacheKey("gfToken:"),
|
||
gftoken.WithTimeout(20),
|
||
gftoken.WithMaxRefresh(10),
|
||
gftoken.WithMultiLogin(true),
|
||
//gftoken.WithExcludePaths(g.SliceStr{"/excludeDemo"}),
|
||
gftoken.WithGRedisConfig(&gredis.Config{
|
||
Address: redisAddr,
|
||
Db: 1,
|
||
}))
|
||
// 解析 token
|
||
data, err := gft.ParseToken(g.RequestFromCtx(ctx))
|
||
if err != nil {
|
||
return user, gerror.Wrap(err, "token 解析失败")
|
||
}
|
||
|
||
// 检查 data 是否为 nil
|
||
if data == nil {
|
||
return user, gerror.New("token 数据为空")
|
||
}
|
||
|
||
// 检查 data.Data 是否为 nil
|
||
if data.Data == nil {
|
||
return user, gerror.New("用户信息为空")
|
||
}
|
||
|
||
dataMap := gconv.Map(data.Data)
|
||
user.UserName = dataMap["userName"]
|
||
user.TenantId = dataMap["tenantId"]
|
||
} else {
|
||
user.TenantId = ctx.Value("tenantId")
|
||
user.UserName = ctx.Value("userName")
|
||
fmt.Println("user.UserName==================", user.UserName)
|
||
}
|
||
if user.TenantId == nil {
|
||
return user, gerror.New("租户信息为空")
|
||
}
|
||
return
|
||
}
|
||
|
||
func OrderMap(m map[string]interface{}) map[string]interface{} {
|
||
// 提取所有key
|
||
keys := make([]string, 0, len(m))
|
||
for k := range m {
|
||
keys = append(keys, k)
|
||
}
|
||
|
||
// 使用标准排序算法对key进行排序
|
||
// 使用strings.Sort确保排序结果永远一致
|
||
sort.Strings(keys)
|
||
|
||
// 创建有序map
|
||
orderedMap := make(map[string]interface{}, len(m))
|
||
for _, k := range keys {
|
||
orderedMap[k] = m[k]
|
||
}
|
||
|
||
return orderedMap
|
||
}
|
||
|
||
// ParseIntSlice 解析整数切片 - 通用字符串处理工具
|
||
func ParseIntSlice(str string) []int {
|
||
parts := strings.Split(str, ",")
|
||
result := make([]int, 0, len(parts))
|
||
for _, part := range parts {
|
||
if val, err := strconv.Atoi(strings.TrimSpace(part)); err == nil {
|
||
result = append(result, val)
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
// ParseStrings 解析字符串切片 - 通用字符串处理工具
|
||
func ParseStrings(str string) []string {
|
||
if str == "" {
|
||
return nil
|
||
}
|
||
parts := strings.Split(str, ",")
|
||
result := make([]string, 0, len(parts))
|
||
for _, part := range parts {
|
||
if trimmed := strings.TrimSpace(part); trimmed != "" {
|
||
result = append(result, trimmed)
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
// FilterServiceNames 过滤服务名 - 通用映射处理工具
|
||
func FilterServiceNames(services map[string]interface{}, excludeKeys ...string) []string {
|
||
excludeMap := make(map[string]bool)
|
||
for _, key := range excludeKeys {
|
||
excludeMap[key] = true
|
||
}
|
||
result := make([]string, 0, len(services))
|
||
for key := range services {
|
||
if !excludeMap[key] {
|
||
result = append(result, key)
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
// FormatUnixTime 格式化Unix时间戳 - 通用时间处理工具
|
||
func FormatUnixTime(timestamp int64) string {
|
||
if timestamp <= 0 {
|
||
return ""
|
||
}
|
||
return time.Unix(timestamp, 0).Format("2006-01-02 15:04:05")
|
||
}
|
||
|
||
// ParseDurationWithDefault 解析持续时间,失败时使用默认值 - 通用时间处理工具
|
||
func ParseDurationWithDefault(ctx context.Context, durationStr, defaultStr, fieldName string) (time.Duration, string) {
|
||
durationParsed, err := time.ParseDuration(durationStr)
|
||
if err != nil {
|
||
// 这里不能直接使用g.Log(),因为这是utils包,没有直接的日志访问
|
||
// 调用方应该处理日志
|
||
// g.Log().Warningf(ctx, "解析%s失败: %s, 使用默认值 %s, error: %v", fieldName, durationStr, defaultStr, err)
|
||
durationParsed, _ = time.ParseDuration(defaultStr)
|
||
return durationParsed, defaultStr
|
||
}
|
||
return durationParsed, durationStr
|
||
}
|
||
|
||
// AtomicUpdateMin 原子更新最小值 - 通用数值处理工具
|
||
func AtomicUpdateMin(minValue *atomic.Int64, newValue int64) {
|
||
for {
|
||
currentMin := minValue.Load()
|
||
if newValue >= currentMin {
|
||
break
|
||
}
|
||
if minValue.CompareAndSwap(currentMin, newValue) {
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
// AtomicUpdateMax 原子更新最大值 - 通用数值处理工具
|
||
func AtomicUpdateMax(maxValue *atomic.Int64, newValue int64) {
|
||
for {
|
||
currentMax := maxValue.Load()
|
||
if newValue <= currentMax {
|
||
break
|
||
}
|
||
if maxValue.CompareAndSwap(currentMax, newValue) {
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
// ParseCIDRs 解析CIDR列表 - 通用网络处理工具
|
||
func ParseCIDRs(strs []string) ([]*net.IPNet, error) {
|
||
nets := make([]*net.IPNet, 0, len(strs))
|
||
for _, s := range strs {
|
||
if s == "*" {
|
||
if _, ipv4Net, err := net.ParseCIDR("0.0.0.0/0"); err == nil {
|
||
nets = append(nets, ipv4Net)
|
||
}
|
||
if _, ipv6Net, err := net.ParseCIDR("::/0"); err == nil {
|
||
nets = append(nets, ipv6Net)
|
||
}
|
||
continue
|
||
}
|
||
if _, ipNet, err := net.ParseCIDR(s); err == nil {
|
||
nets = append(nets, ipNet)
|
||
}
|
||
}
|
||
return nets, nil
|
||
}
|
||
|
||
// UrlDecode 简单的URL解码 - 通用编码解码工具
|
||
func UrlDecode(s string) string {
|
||
result := make([]byte, 0, len(s))
|
||
|
||
for i := 0; i < len(s); i++ {
|
||
if s[i] == '%' && i+2 < len(s) {
|
||
if high := HexDigit(s[i+1]); high != 0xFF {
|
||
if low := HexDigit(s[i+2]); low != 0xFF {
|
||
result = append(result, (high<<4)|low)
|
||
i += 2
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
result = append(result, s[i])
|
||
}
|
||
|
||
return string(result)
|
||
}
|
||
|
||
// HexDigit 十六进制字符转数字 - 通用编码解码工具
|
||
func HexDigit(c byte) byte {
|
||
switch {
|
||
case '0' <= c && c <= '9':
|
||
return c - '0'
|
||
case 'a' <= c && c <= 'f':
|
||
return c - 'a' + 10
|
||
case 'A' <= c && c <= 'F':
|
||
return c - 'A' + 10
|
||
default:
|
||
return 0xFF
|
||
}
|
||
}
|