2023-11-02 21:51:30 +08:00
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
2024-02-12 04:52:41 +08:00
|
|
|
"context"
|
2024-07-26 23:52:33 +08:00
|
|
|
"sync"
|
2024-02-12 04:52:41 +08:00
|
|
|
"time"
|
2023-11-02 21:51:30 +08:00
|
|
|
|
|
|
|
"github.com/coocood/freecache"
|
2024-07-26 23:50:26 +08:00
|
|
|
"github.com/redis/go-redis/v9"
|
2024-08-31 23:50:17 +08:00
|
|
|
"github.com/tgdrive/teldrive/internal/config"
|
2024-07-26 23:50:26 +08:00
|
|
|
"github.com/vmihailenco/msgpack/v5"
|
2023-11-02 21:51:30 +08:00
|
|
|
)
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
type Cacher interface {
|
|
|
|
Get(key string, value interface{}) error
|
|
|
|
Set(key string, value interface{}, expiration time.Duration) error
|
|
|
|
Delete(keys ...string) error
|
2023-11-02 21:51:30 +08:00
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
type MemoryCache struct {
|
|
|
|
cache *freecache.Cache
|
|
|
|
prefix string
|
2024-07-26 23:52:33 +08:00
|
|
|
mu sync.RWMutex
|
2024-07-26 23:50:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewCache(ctx context.Context, conf *config.Config) Cacher {
|
|
|
|
var cacher Cacher
|
2024-09-10 15:30:47 +08:00
|
|
|
if conf.Cache.RedisAddr == "" {
|
2024-07-26 23:50:26 +08:00
|
|
|
cacher = NewMemoryCache(conf.Cache.MaxSize)
|
2024-09-10 15:30:47 +08:00
|
|
|
} else {
|
2024-07-26 23:50:26 +08:00
|
|
|
cacher = NewRedisCache(ctx, redis.NewClient(&redis.Options{
|
|
|
|
Addr: conf.Cache.RedisAddr,
|
|
|
|
Password: conf.Cache.RedisPass,
|
|
|
|
}))
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
2024-07-26 23:50:26 +08:00
|
|
|
return cacher
|
|
|
|
}
|
2023-11-02 21:51:30 +08:00
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func NewMemoryCache(size int) *MemoryCache {
|
|
|
|
return &MemoryCache{
|
|
|
|
cache: freecache.NewCache(size),
|
|
|
|
prefix: "teldrive:",
|
|
|
|
}
|
|
|
|
}
|
2023-11-02 21:51:30 +08:00
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func (m *MemoryCache) Get(key string, value interface{}) error {
|
2024-07-26 23:52:33 +08:00
|
|
|
m.mu.RLock()
|
|
|
|
defer m.mu.RUnlock()
|
2024-07-26 23:50:26 +08:00
|
|
|
key = m.prefix + key
|
|
|
|
data, err := m.cache.Get([]byte(key))
|
2023-11-02 21:51:30 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-07-26 23:50:26 +08:00
|
|
|
return msgpack.Unmarshal(data, value)
|
2023-11-02 21:51:30 +08:00
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func (m *MemoryCache) Set(key string, value interface{}, expiration time.Duration) error {
|
2024-07-26 23:52:33 +08:00
|
|
|
m.mu.RLock()
|
|
|
|
defer m.mu.RUnlock()
|
2024-07-26 23:50:26 +08:00
|
|
|
key = m.prefix + key
|
|
|
|
data, err := msgpack.Marshal(value)
|
2023-11-02 21:51:30 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-07-26 23:50:26 +08:00
|
|
|
return m.cache.Set([]byte(key), data, int(expiration.Seconds()))
|
2023-11-02 21:51:30 +08:00
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func (m *MemoryCache) Delete(keys ...string) error {
|
2024-07-26 23:52:33 +08:00
|
|
|
m.mu.RLock()
|
|
|
|
defer m.mu.RUnlock()
|
2024-07-26 23:50:26 +08:00
|
|
|
for _, key := range keys {
|
|
|
|
m.cache.Del([]byte(m.prefix + key))
|
|
|
|
}
|
2023-11-02 21:51:30 +08:00
|
|
|
return nil
|
|
|
|
}
|
2024-02-12 04:52:41 +08:00
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
type RedisCache struct {
|
|
|
|
client *redis.Client
|
|
|
|
ctx context.Context
|
|
|
|
prefix string
|
2024-07-26 23:52:33 +08:00
|
|
|
mu sync.RWMutex
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func NewRedisCache(ctx context.Context, client *redis.Client) *RedisCache {
|
|
|
|
return &RedisCache{
|
|
|
|
client: client,
|
|
|
|
prefix: "teldrive:",
|
|
|
|
ctx: ctx,
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func (r *RedisCache) Get(key string, value interface{}) error {
|
2024-07-26 23:52:33 +08:00
|
|
|
r.mu.RLock()
|
|
|
|
defer r.mu.RUnlock()
|
2024-07-26 23:50:26 +08:00
|
|
|
key = r.prefix + key
|
|
|
|
data, err := r.client.Get(r.ctx, key).Bytes()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return msgpack.Unmarshal(data, value)
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func (r *RedisCache) Set(key string, value interface{}, expiration time.Duration) error {
|
2024-07-26 23:52:33 +08:00
|
|
|
r.mu.RLock()
|
|
|
|
defer r.mu.RUnlock()
|
2024-07-26 23:50:26 +08:00
|
|
|
key = r.prefix + key
|
|
|
|
data, err := msgpack.Marshal(value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
2024-07-26 23:50:26 +08:00
|
|
|
return r.client.Set(r.ctx, key, data, expiration).Err()
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
|
|
|
|
2024-07-26 23:50:26 +08:00
|
|
|
func (r *RedisCache) Delete(keys ...string) error {
|
2024-07-26 23:52:33 +08:00
|
|
|
r.mu.RLock()
|
|
|
|
defer r.mu.RUnlock()
|
2024-07-26 23:50:26 +08:00
|
|
|
for i := range keys {
|
|
|
|
keys[i] = r.prefix + keys[i]
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|
2024-07-26 23:50:26 +08:00
|
|
|
return r.client.Del(r.ctx, keys...).Err()
|
2024-02-12 04:52:41 +08:00
|
|
|
}
|