diff --git a/config/config.go b/config/config.go index da84c9a..4d21909 100644 --- a/config/config.go +++ b/config/config.go @@ -128,6 +128,8 @@ func (c *Cfg) GetUrlFile(name string) (jsonObj *gjson.Json, err error) { //} func (c *Cfg) GetApollo(name string, obj Load) (jsonObj *gjson.Json, err error) { + Item2Obj[name+".json"] = obj + // 接入阿波罗配置 ApolloCfg.NamespaceName = name + ".json" adapter, err := apollo.New(nil, *ApolloCfg) @@ -169,14 +171,6 @@ type CustomChangeListener struct { } func (c *CustomChangeListener) OnChange(changeEvent *storage.ChangeEvent) { - //write your code here - //fmt.Println(changeEvent.Changes) - //for key, value := range changeEvent.Changes { - // fmt.Println("change key : ", key, ", value :", value) - //} - //fmt.Println(changeEvent.Namespace) - //c.wg.Done() - g.Log().Debugf(nil, "当前Namespace变化了:%v", changeEvent.Namespace) filename := changeEvent.Namespace if obj, ok := Item2Obj[filename]; ok { diff --git a/tools/redis.go b/tools/redis.go new file mode 100644 index 0000000..8cd7ca2 --- /dev/null +++ b/tools/redis.go @@ -0,0 +1,81 @@ +package tools + +import ( + "github.com/gogf/gf/v2/database/gredis" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" +) + +var ( + Redis *redis +) + +type redis struct { +} + +func (r *redis) Load() { + g.Log().Debugf(gctx.New(), "初始化工具类") + if Redis == nil { + Redis = &redis{} + } + return +} + +func (r *redis) RedisScan(cacheKey string, _key ...string) (keys []string, err error) { + var cursor uint64 + key := "" + if len(_key) > 0 { + key = _key[0] + } + for { + var newKeys []string + cursor, newKeys, err = g.Redis(key).Scan(ctx, cursor, gredis.ScanOption{ + Match: cacheKey, + Count: 1000, + }) + if err != nil { + g.Log().Errorf(ctx, "Scan failed: %v", err) + break + } + keys = append(keys, newKeys...) + + if cursor == 0 { + break + } + } + return +} + +// redis 批量获取大量数据 +func (r *redis) RedisScanV2(cacheKey string, _func func([]string) error, _key ...string) error { + + //var keys []string + var err error + + var cursor uint64 + key := "" + if len(_key) > 0 { + key = _key[0] + } + for { + var newKeys []string + cursor, newKeys, err = g.Redis(key).Scan(ctx, cursor, gredis.ScanOption{ + Match: cacheKey, + Count: 1000, + }) + if err != nil { + g.Log().Errorf(ctx, "Scan failed: %v", err) + break + } + + if len(newKeys) > 0 { + err = _func(newKeys) + } + + //这个要放在最后 + if cursor == 0 { + break + } + } + return err +} diff --git a/tools/time.go b/tools/time.go new file mode 100644 index 0000000..43f076e --- /dev/null +++ b/tools/time.go @@ -0,0 +1,124 @@ +package tools + +import ( + "github.com/gogf/gf/v2/os/gtime" + "time" +) + +type timeMod struct { +} + +var Time *timeMod + +func (m *timeMod) Load() { + if Tools == nil { + Tools = &tools{} + } +} + +// 获取本周的开始时间 +func (m *timeMod) StartOfWeek(t time.Time) time.Time { + start := gtime.New().AddDate(0, 0, -int(t.Weekday()-1)).Time + start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()) + return start +} + +func (m *timeMod) StartOfWeekV2(t time.Time) time.Time { + start := t.AddDate(0, 0, -int(t.Weekday()-1)) + start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()) + return start +} + +func (m *timeMod) EndOfWeek(t time.Time) time.Time { + return m.StartOfWeek(t).AddDate(0, 0, 7).Add(-(time.Second * 1)) +} + +// 获取指定时间的0点时间戳 +func (m *timeMod) GetTimeDayZero(tm time.Time) time.Time { + duration := time.Hour*time.Duration(tm.Hour()) + time.Minute*time.Duration(tm.Minute()) + time.Second*time.Duration(tm.Second()) + return tm.Add(-duration) +} + +// GetWeekZero 获取指定时间周一零点的时间 +func (m *timeMod) GetWeekZero(now time.Time) time.Time { + timeUnix := m.GetTimeDayZero(now) + now = timeUnix + daysSinceMonday := int(now.Weekday() - time.Monday) + if daysSinceMonday < 0 { + daysSinceMonday += 7 + } + + currentMonday := now.AddDate(0, 0, -daysSinceMonday) + return currentMonday +} + +// 计算两个时间间隔了几天 +func (m *timeMod) GetDayPass(startTime time.Time, t ...time.Time) int { + // 获取时间的年、月、日 + year := startTime.Year() + month := startTime.Month() + day := startTime.Day() + // 构建一天的开始时间 + startTime = time.Date(year, month, day, 0, 0, 0, 0, startTime.Location()) + + //如果为空,使用当前时间 + endTime := time.Now() + if len(t) > 0 { + endTime = t[0] + } + //计算过去了多少天 + dayPass := int(endTime.Sub(startTime).Hours() / 24) + return dayPass +} + +// 获取下周一的时间 +func (m *timeMod) GetNextWeek(now time.Time) time.Time { + now = m.GetWeekZero(now) + timeUnix := now.UnixMilli() + (86400 * 7 * 1000) + nextMondayMidnight := time.UnixMilli(timeUnix) + return nextMondayMidnight +} + +// GetDayZeroTime 获取几天后的0点时间 +// +// @Description: +// @param currentTime 开始时间 +// @param day 多少天后 +// @return time.Time +func (m *timeMod) GetDayZeroTime(currentTime time.Time, day int) time.Time { + // 加上指定天数的时间 + threeDaysLater := currentTime.AddDate(0, 0, day) + // 调整时间为0点 + zeroTime := time.Date(threeDaysLater.Year(), threeDaysLater.Month(), threeDaysLater.Day(), 0, 0, 0, 0, threeDaysLater.Location()) + return zeroTime +} + +// GetEndTime 获取结束的时间 +// +// @Description: +// @receiver m +// @param startTime +// @param _day 多少天以后得实际那,当天时间为空 +// @return time.Time +func (m *timeMod) GetEndTime(startTime time.Time, _day ...int) time.Time { + var day = 0 + if len(_day) > 0 { + day = _day[0] + } + // 加上指定天数的时间 + threeDaysLater := startTime.AddDate(0, 0, day) + // 调整时间为0点 + zeroTime := time.Date(threeDaysLater.Year(), threeDaysLater.Month(), threeDaysLater.Day(), 23, 59, 59, 0, threeDaysLater.Location()) + return zeroTime +} + +// GetDailyTimeList 获取一个时间段里面每天开始的时间 +func (m *timeMod) GetDailyTimeList(time1 time.Time, time2 time.Time) (timeList []time.Time) { + day := m.GetDayPass(time1, time2) + timeList = make([]time.Time, day+1) + for i := 0; i <= day; i++ { + //PassDay := i - day + timeList[i] = m.GetDayZeroTime(time1, i) + } + return +} diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 0000000..5e978d0 --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,252 @@ +package tools + +import ( + bagV1 "game_server/api/bag/v1" + v1 "game_server/api/bag/v1" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/gtime" + "math" + "strconv" + "strings" + "time" +) + +var ( + ctx = gctx.New() + Tools *tools +) + +type Number interface { + int | int64 | int32 | int16 | uint64 | uint32 | uint16 | float32 | float64 +} + +//type Any interface { +// interface{} | string | int | int64 | int32 | int16 | uint64 | uint32 | uint16 | float32 | float64 +//} + +type toolsInterface interface { + Load() +} + +type tools struct { +} + +func init() { + g.Log().Debugf(gctx.New(), "初始化工具类") + + names := []toolsInterface{ + Tools, + } + for _, v := range names { + v.Load() + } + +} + +func (m *tools) Load() { + if Tools == nil { + Tools = &tools{} + } +} + +// 两个时间相隔多少天,需要考虑时区 +func (m *tools) GetDay(t1 *gtime.Time, t2 *gtime.Time) int { + if t2 == nil { + t2 = gtime.New(time.UnixMilli(0)) + } + return int(t1.Sub(t2).Hours() / 24) +} + +// 字符串转道具类型 +func (m *tools) Spilt2Item(str string) (result [][]int64) { + parts := strings.Split(str, "|") // 分割字符串 + + for i := 0; i < len(parts)-1; i += 2 { + num1, _ := strconv.ParseInt(parts[i], 10, 64) + num2, _ := strconv.ParseInt(parts[i+1], 10, 64) + + pair := []int64{num1, num2} + result = append(result, pair) + } + return +} + +// 切片换道具类型 +func (m *tools) Slice2Item(slice []int64) (res [][]int64) { + res = make([][]int64, 0) + for i := 0; i < len(slice)-1; i += 2 { + pair := []int64{slice[i], slice[i+1]} + res = append(res, pair) + } + return res +} + +// 道具格式转map +func (m *tools) Items2Map(items [][]int64) (list map[int64]int64) { + list = make(map[int64]int64) + for _, v := range items { + list[v[0]] = v[1] + } + return +} + +// 道具转Pb +func (m *tools) Items2Pb(items [][]int64) (list map[int64]*v1.Item) { + list = make(map[int64]*v1.Item) + for _, v := range items { + list[v[0]] = &v1.Item{ + Count: v[1], + } + } + return list +} + +// UpdateItems 格式化到items输出 +func (m *tools) UpdateItems(items [][]int64, updateItems [][]int64, IsDeduct ...bool) (data *bagV1.ItemUpdate) { + data = &bagV1.ItemUpdate{ + Items: make(map[int64]*bagV1.Item), + UpdateItems: make(map[int64]*bagV1.Item), + } + + for _, v := range items { + if _, ok := data.Items[v[0]]; ok { + //如果存在,追加数据 + data.Items[v[0]].Count += v[1] + } else { + //如果不存在,创建数据 + data.Items[v[0]] = &bagV1.Item{ + Count: v[1], + } + } + } + + for _, v := range updateItems { + //UpdateItems 只保存最新的值 + data.UpdateItems[v[0]] = &bagV1.Item{ + Count: v[1], + } + } + + //如果是强制转为负数 + if len(IsDeduct) > 0 && IsDeduct[0] { + for k, v := range data.Items { + data.Items[k].Count = -int64(math.Abs(float64(v.Count))) + } + } + + return +} + +// RemoveSlice 从切片中移除指定的值。 +// 参数: +// +// slice: 待操作的切片。 +// value: 需要移除的值。 +// +// 返回值: +// +// 移除指定值后的切片。 +// +// 该函数通过遍历切片,从后向前检查每个元素,如果找到与指定值相等的元素,则将其从切片中移除。 +// 这种从后向前的遍历方法可以避免因移除元素而导致的数组重新排列带来的额外计算。 +// RemoveSlice 删除切片中的某个值 +func RemoveSlice[t Number](slice []t, value t) []t { + // 从后向前遍历切片 + for i := len(slice) - 1; i >= 0; i-- { + // 检查当前元素是否等于需要移除的值 + if slice[i] == value { + // 如果相等,移除该元素 + // 使用append和切片操作符来实现移除操作,将i之前和i之后的元素合并到一起 + slice = append(slice[:i], slice[i+1:]...) + } + } + // 返回处理后的切片 + return slice +} + +// InArray 判断当前切片中是否拥有当前值 +// InArray[t Number] 支持的类型 +// +// @Description: +// @param value 需要查找的值 +// @param array 进行查找的切片 +// @return bool 返回是否存在 +func InArray[t Number](value t, array []t) bool { + for _, v := range array { + if v == value { + return true + } + } + return false +} + +// ExtractPage 根据给定的页码和每页大小,从项目切片中提取指定页的项目。 +// 它支持泛型,可以用于任何类型的切片。 +// 参数: +// +// items: 项目切片,代表所有待分页的项目。 +// page: 指定的页码,起始页码为1。 +// size: 每页的项目数量。 +// +// 返回值: +// +// 返回一个切片,包含指定页的项目。 +// +// 如果每页大小为0,将默认为1。如果项目切片为空,或指定页的项目数量少于每页大小,且页码大于0,则直接返回整个项目切片。 +// ExtractPage [t Any] +// +// @Description: +// @param items +// @param page +// @param size +// @return []t +func ExtractPage[t interface{}](items []t, page int, size int) []t { + // 如果每页大小为0,将其默认设置为1。 + // 如果每页大小为0,将其默认设置为1。 + if size == 0 { + size = 1 + } + // 如果项目切片为空,直接返回空切片。 + if len(items) == 0 { + return []t{} + } + //// 如果项目切片长度小于每页大小,并且页码大于0,返回整个项目切片。 + //if len(items) < size && page > 0 { + // //return items + //} + + // 计算起始索引和结束索引。 + // 根据页码和每页大小计算起始索引和结束索引。 + // 计算起始索引和结束索引。 + startIndex := (page - 1) * size + endIndex := startIndex + size + // 如果结束索引超出项目切片长度,调整结束索引为项目切片的长度。 + // 如果结束索引超出项目切片的长度,将其调整为项目切片的长度。 + if endIndex >= len(items) { // 确保不会超出切片范围 + endIndex = len(items) + } + + // 如果起始索引超出项目切片长度,返回空切片。 + if len(items) < startIndex || len(items) < endIndex { + return []t{} + } + + // 根据起始索引和结束索引从项目切片中提取指定页的项目,并返回。 + // 返回指定页的项目切片。 + + return items[startIndex:endIndex] +} + +// 这是一个用于反转切片的函数示例 +// reverseSlice[T comparable] +// +// @Description: +// @param s +// @return []T +func ReverseSlice[T comparable](s []T) []T { + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } + return s +}