196 lines
4.7 KiB
Go
196 lines
4.7 KiB
Go
package cache
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"time"
|
||
|
||
redis "github.com/redis/go-redis/v9"
|
||
)
|
||
|
||
type RedisCacheStruct[T any] struct {
|
||
Redis *redis.Client
|
||
Ctx context.Context
|
||
HashKey string
|
||
Result T
|
||
DefaultExpiration time.Duration
|
||
CleanupInterval time.Duration
|
||
}
|
||
|
||
type RedisValue[T any] struct {
|
||
ExpirationTimeStamp int64
|
||
IsExpiration bool // 是否有过期时间 false // 不过期
|
||
Value T
|
||
}
|
||
|
||
// cache.New(5*time.Minute, 60*time.Second)
|
||
func NewRedisCache[T any](redisDb *redis.Client, hashKey string, defaultExpiration time.Duration, cleanupInterval time.Duration) *RedisCacheStruct[T] {
|
||
obj := RedisCacheStruct[T]{
|
||
Redis: redisDb,
|
||
Ctx: context.Background(),
|
||
HashKey: hashKey,
|
||
DefaultExpiration: defaultExpiration,
|
||
CleanupInterval: cleanupInterval,
|
||
}
|
||
|
||
// 创建定时器判断是否过期
|
||
if obj.CleanupInterval.Seconds() > 0 {
|
||
go obj.expirationVerification()
|
||
}
|
||
|
||
return &obj
|
||
}
|
||
|
||
func (r *RedisCacheStruct[T]) Set(k string, v T, d time.Duration) {
|
||
valueEncode := ""
|
||
value := RedisValue[T]{}
|
||
|
||
// 设置过期时间
|
||
if d.Seconds() > 0 {
|
||
value.IsExpiration = true
|
||
value.ExpirationTimeStamp = time.Now().Add(d).Unix()
|
||
} else {
|
||
value.IsExpiration = false // 不过期
|
||
}
|
||
|
||
value.Value = v
|
||
if j, e := json.Marshal(value); e == nil {
|
||
valueEncode = string(j)
|
||
}
|
||
|
||
r.Redis.HSet(r.Ctx, r.HashKey, k, valueEncode)
|
||
// second := d.Seconds()
|
||
// if second > 0 {
|
||
// // 设置过期时间
|
||
// err := r.Redis.Do(r.Ctx, "SETEX", r.HashKey+k, second, valueEncode).Err()
|
||
// fmt.Println("设置结果", err)
|
||
// } else {
|
||
// r.Redis.HSet(r.Ctx, r.HashKey, k, valueEncode)
|
||
// }
|
||
|
||
}
|
||
|
||
func (r *RedisCacheStruct[T]) Get(k string) (T, bool) {
|
||
var valueEncode []byte
|
||
value := RedisValue[T]{}
|
||
cmd := r.Redis.HGet(r.Ctx, r.HashKey, k)
|
||
if err := cmd.Scan(&valueEncode); err != nil {
|
||
// log.Println(err)
|
||
return r.Result, false
|
||
}
|
||
|
||
if err := json.Unmarshal(valueEncode, &value); err != nil {
|
||
// log.Println(err)
|
||
return r.Result, false
|
||
}
|
||
|
||
// 已过期,清理掉key
|
||
if value.IsExpiration && time.Now().Unix() > value.ExpirationTimeStamp {
|
||
r.Delete(k)
|
||
return r.Result, false
|
||
}
|
||
|
||
return value.Value, true
|
||
}
|
||
|
||
// 设置cache 无时间参数
|
||
func (r *RedisCacheStruct[T]) SetDefault(k string, v T) {
|
||
r.Set(k, v, r.DefaultExpiration)
|
||
}
|
||
|
||
// 设置并保持原始的过期时间
|
||
func (r *RedisCacheStruct[T]) SetKeepExpiration(k string, v T) {
|
||
var valueEncode []byte
|
||
value := RedisValue[T]{}
|
||
cmd := r.Redis.HGet(r.Ctx, r.HashKey, k)
|
||
if err := cmd.Scan(&valueEncode); err != nil {
|
||
// fmt.Println("使用默认的过期时间")
|
||
r.SetDefault(k, v)
|
||
return
|
||
}
|
||
|
||
if err := json.Unmarshal(valueEncode, &value); err != nil {
|
||
// fmt.Println("使用默认的过期时间")
|
||
r.SetDefault(k, v)
|
||
return
|
||
}
|
||
|
||
now := time.Now()
|
||
timeDiffer := value.ExpirationTimeStamp - now.Unix()
|
||
|
||
// 如果设置了过期时间并且过期时间大于现在将保留原始的过期时间
|
||
if value.IsExpiration && timeDiffer > 0 {
|
||
// fmt.Println("重新计算过期时间")
|
||
// fmt.Println("旧的过期时间", value.ExpirationTimeStamp)
|
||
// fmt.Println("时间限制差", timeDiffer)
|
||
// fmt.Println("新的过期时间", now.Unix()+timeDiffer)
|
||
r.Set(k, v, time.Second*time.Duration(timeDiffer))
|
||
} else {
|
||
// fmt.Println("使用默认的过期时间")
|
||
r.SetDefault(k, v)
|
||
}
|
||
}
|
||
|
||
// 删除 cache
|
||
func (r *RedisCacheStruct[T]) Delete(k string) {
|
||
r.Redis.HDel(r.Ctx, r.HashKey, k)
|
||
}
|
||
|
||
// Add() 加入缓存
|
||
// func (r *RedisCacheStruct[T]) Add(k string, v T, d time.Duration) {
|
||
// c.gocahce.Add(k, x, d)
|
||
// }
|
||
|
||
// IncrementInt() 对已存在的key 值自增n
|
||
// func (r *RedisCacheStruct[T]) IncrementInt(k string, n int) (num int, err error) {
|
||
// if err := r.Redis.HIncrBy(r.Ctx, r.HashKey, k, int64(n)).Err(); err != nil {
|
||
// return num, err
|
||
// }
|
||
|
||
// if v, ok := r.Get(k); ok {
|
||
// switch T {
|
||
// case int:
|
||
|
||
// }
|
||
// if vint, okint := v.(int); okint {
|
||
|
||
// }
|
||
// }
|
||
// return c.gocahce.IncrementInt(k, n)
|
||
// }
|
||
|
||
// ItemCount 获取已存在key的数量
|
||
func (r *RedisCacheStruct[T]) ItemCount() (int64, error) {
|
||
if count, err := r.Redis.HLen(r.Ctx, r.HashKey).Result(); err != nil {
|
||
return 0, err
|
||
} else {
|
||
return count, nil
|
||
}
|
||
}
|
||
|
||
// Flush 删除当前已存在的所有key
|
||
func (r *RedisCacheStruct[T]) Flush() {
|
||
r.Redis.Del(r.Ctx, r.HashKey)
|
||
}
|
||
|
||
// 定时清理过期验证
|
||
func (r *RedisCacheStruct[T]) expirationVerification() {
|
||
ticker := time.NewTicker(r.CleanupInterval)
|
||
|
||
for {
|
||
select {
|
||
case <-ticker.C:
|
||
if fields, err := r.Redis.HKeys(r.Ctx, r.HashKey).Result(); err == nil {
|
||
for _, v := range fields {
|
||
// r.Redis.HGet(r.Ctx, r.HashKey, v)
|
||
r.Get(v)
|
||
// fmt.Println("redis定时器", v)
|
||
}
|
||
}
|
||
// case <-j.stop:
|
||
// ticker.Stop()
|
||
// return
|
||
}
|
||
}
|
||
}
|