2023-11-08 21:53:07 +08:00

196 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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