Files
daohangye/service/lib/cache/redis.go
T
2023-11-08 21:53:07 +08:00

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
}
}
}