mirror of
				https://github.com/cloudreve/cloudreve.git
				synced 2025-10-31 08:39:10 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			242 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package cache
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/gob"
 | |
| 	"github.com/cloudreve/Cloudreve/v4/pkg/logging"
 | |
| 	"strconv"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/gomodule/redigo/redis"
 | |
| )
 | |
| 
 | |
| // RedisStore redis存储驱动
 | |
| type RedisStore struct {
 | |
| 	pool *redis.Pool
 | |
| }
 | |
| 
 | |
| type item struct {
 | |
| 	Value interface{}
 | |
| }
 | |
| 
 | |
| func serializer(value any) ([]byte, error) {
 | |
| 	var buffer bytes.Buffer
 | |
| 	enc := gob.NewEncoder(&buffer)
 | |
| 	storeValue := item{
 | |
| 		Value: value,
 | |
| 	}
 | |
| 	err := enc.Encode(storeValue)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return buffer.Bytes(), nil
 | |
| }
 | |
| 
 | |
| func deserializer(value []byte) (any, error) {
 | |
| 	var res item
 | |
| 	buffer := bytes.NewReader(value)
 | |
| 	dec := gob.NewDecoder(buffer)
 | |
| 	err := dec.Decode(&res)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return res.Value, nil
 | |
| }
 | |
| 
 | |
| // NewRedisStore 创建新的redis存储
 | |
| func NewRedisStore(l logging.Logger, size int, network, address, user, password, database string) *RedisStore {
 | |
| 	return &RedisStore{
 | |
| 		pool: &redis.Pool{
 | |
| 			MaxIdle:     size,
 | |
| 			IdleTimeout: 240 * time.Second,
 | |
| 			TestOnBorrow: func(c redis.Conn, t time.Time) error {
 | |
| 				_, err := c.Do("PING")
 | |
| 				return err
 | |
| 			},
 | |
| 			Dial: func() (redis.Conn, error) {
 | |
| 				db, err := strconv.Atoi(database)
 | |
| 				if err != nil {
 | |
| 					return nil, err
 | |
| 				}
 | |
| 
 | |
| 				c, err := redis.Dial(
 | |
| 					network,
 | |
| 					address,
 | |
| 					redis.DialDatabase(db),
 | |
| 					redis.DialPassword(password),
 | |
| 					redis.DialUsername(user),
 | |
| 				)
 | |
| 				if err != nil {
 | |
| 					l.Panic("Failed to create Redis connection: %s", err)
 | |
| 				}
 | |
| 				return c, nil
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Set 存储值
 | |
| func (store *RedisStore) Set(key string, value any, ttl int) error {
 | |
| 	rc := store.pool.Get()
 | |
| 	defer rc.Close()
 | |
| 
 | |
| 	serialized, err := serializer(value)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if rc.Err() != nil {
 | |
| 		return rc.Err()
 | |
| 	}
 | |
| 
 | |
| 	if ttl > 0 {
 | |
| 		_, err = rc.Do("SETEX", key, ttl, serialized)
 | |
| 	} else {
 | |
| 		_, err = rc.Do("SET", key, serialized)
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| 
 | |
| }
 | |
| 
 | |
| // Get 取值
 | |
| func (store *RedisStore) Get(key string) (any, bool) {
 | |
| 	rc := store.pool.Get()
 | |
| 	defer rc.Close()
 | |
| 	if rc.Err() != nil {
 | |
| 		return nil, false
 | |
| 	}
 | |
| 
 | |
| 	v, err := redis.Bytes(rc.Do("GET", key))
 | |
| 	if err != nil || v == nil {
 | |
| 		return nil, false
 | |
| 	}
 | |
| 
 | |
| 	finalValue, err := deserializer(v)
 | |
| 	if err != nil {
 | |
| 		return nil, false
 | |
| 	}
 | |
| 
 | |
| 	return finalValue, true
 | |
| 
 | |
| }
 | |
| 
 | |
| // Gets 批量取值
 | |
| func (store *RedisStore) Gets(keys []string, prefix string) (map[string]any, []string) {
 | |
| 	rc := store.pool.Get()
 | |
| 	defer rc.Close()
 | |
| 	if rc.Err() != nil {
 | |
| 		return nil, keys
 | |
| 	}
 | |
| 
 | |
| 	var queryKeys = make([]string, len(keys))
 | |
| 	for key, value := range keys {
 | |
| 		queryKeys[key] = prefix + value
 | |
| 	}
 | |
| 
 | |
| 	v, err := redis.ByteSlices(rc.Do("MGET", redis.Args{}.AddFlat(queryKeys)...))
 | |
| 	if err != nil {
 | |
| 		return nil, keys
 | |
| 	}
 | |
| 
 | |
| 	var res = make(map[string]any)
 | |
| 	var missed = make([]string, 0, len(keys))
 | |
| 
 | |
| 	for key, value := range v {
 | |
| 		decoded, err := deserializer(value)
 | |
| 		if err != nil || decoded == nil {
 | |
| 			missed = append(missed, keys[key])
 | |
| 		} else {
 | |
| 			res[keys[key]] = decoded
 | |
| 		}
 | |
| 	}
 | |
| 	// 解码所得值
 | |
| 	return res, missed
 | |
| }
 | |
| 
 | |
| // Sets 批量设置值
 | |
| func (store *RedisStore) Sets(values map[string]any, prefix string) error {
 | |
| 	rc := store.pool.Get()
 | |
| 	defer rc.Close()
 | |
| 	if rc.Err() != nil {
 | |
| 		return rc.Err()
 | |
| 	}
 | |
| 	var setValues = make(map[string]any)
 | |
| 
 | |
| 	// 编码待设置值
 | |
| 	for key, value := range values {
 | |
| 		serialized, err := serializer(value)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		setValues[prefix+key] = serialized
 | |
| 	}
 | |
| 
 | |
| 	_, err := rc.Do("MSET", redis.Args{}.AddFlat(setValues)...)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| 
 | |
| }
 | |
| 
 | |
| // Delete 批量删除给定的键
 | |
| func (store *RedisStore) Delete(prefix string, keys ...string) error {
 | |
| 	rc := store.pool.Get()
 | |
| 	defer rc.Close()
 | |
| 	if rc.Err() != nil {
 | |
| 		return rc.Err()
 | |
| 	}
 | |
| 
 | |
| 	// 处理前缀
 | |
| 	for i := 0; i < len(keys); i++ {
 | |
| 		keys[i] = prefix + keys[i]
 | |
| 	}
 | |
| 
 | |
| 	// No key is presented, delete all keys with given prefix
 | |
| 	if len(keys) == 0 {
 | |
| 		// Fetch all key with given prefix
 | |
| 		allPrefixKeys, err := redis.Strings(rc.Do("KEYS", prefix+"*"))
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		keys = allPrefixKeys
 | |
| 	}
 | |
| 
 | |
| 	if len(keys) > 0 {
 | |
| 		_, err := rc.Do("DEL", redis.Args{}.AddFlat(keys)...)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // DeleteAll 批量所有键
 | |
| func (store *RedisStore) DeleteAll() error {
 | |
| 	rc := store.pool.Get()
 | |
| 	defer rc.Close()
 | |
| 	if rc.Err() != nil {
 | |
| 		return rc.Err()
 | |
| 	}
 | |
| 
 | |
| 	_, err := rc.Do("FLUSHDB")
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // Persist Dummy implementation
 | |
| func (store *RedisStore) Persist(path string) error {
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Restore dummy implementation
 | |
| func (store *RedisStore) Restore(path string) error {
 | |
| 	return nil
 | |
| }
 | 
