github.com/charlienet/go-mixed@v0.3.7/cache/redis.go (about)

     1  package cache
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"time"
     8  
     9  	"github.com/charlienet/go-mixed/bytesconv"
    10  	"github.com/charlienet/go-mixed/json"
    11  	"github.com/charlienet/go-mixed/rand"
    12  	"github.com/go-redis/redis/v8"
    13  )
    14  
    15  const redisEmptyObject = "redis object not exist"
    16  
    17  type RedisConfig struct {
    18  	Prefix string // key perfix
    19  	Addrs  []string
    20  
    21  	// Database to be selected after connecting to the server.
    22  	// Only single-node and failover clients.
    23  	DB int
    24  
    25  	Username        string
    26  	Password        string
    27  	MaxRetries      int
    28  	MinRetryBackoff time.Duration
    29  	MaxRetryBackoff time.Duration
    30  
    31  	DialTimeout  time.Duration
    32  	ReadTimeout  time.Duration
    33  	WriteTimeout time.Duration
    34  }
    35  
    36  type redisClient struct {
    37  	client     redis.UniversalClient
    38  	emptyStamp string // 空对象标识,每个实例隔离
    39  	prefix     string // 缓存键前缀
    40  }
    41  
    42  func NewRedis(c RedisConfig) *redisClient {
    43  	client := redis.NewUniversalClient(&redis.UniversalOptions{
    44  		Addrs:    c.Addrs,
    45  		DB:       c.DB,
    46  		Username: c.Username,
    47  		Password: c.Password,
    48  	})
    49  
    50  	return &redisClient{
    51  		emptyStamp: fmt.Sprintf("redis-empty-%d-%s", time.Now().Unix(), rand.Hex.Generate(6)),
    52  		prefix:     c.Prefix,
    53  		client:     client,
    54  	}
    55  }
    56  
    57  func (c *redisClient) Get(key string, out any) error {
    58  	val, err := c.client.Get(context.Background(), c.getKey(key)).Result()
    59  	if errors.Is(err, redis.Nil) {
    60  		return ErrNotFound
    61  	}
    62  
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	// redis 保存键为空值时返回键不存在错误
    68  	if val == redisEmptyObject {
    69  		return ErrNotFound
    70  	}
    71  
    72  	return json.Unmarshal(bytesconv.StringToBytes(val), out)
    73  }
    74  
    75  func (c *redisClient) Set(key string, value any, expiration time.Duration) error {
    76  	j, _ := json.Marshal(value)
    77  	return c.client.Set(context.Background(), c.getKey(key), j, expiration).Err()
    78  }
    79  
    80  func (c *redisClient) Exist(key string) (bool, error) {
    81  	val, err := c.client.Exists(context.Background(), c.getKey(key)).Result()
    82  	return val > 0, err
    83  }
    84  
    85  func (c *redisClient) Delete(key ...string) error {
    86  	keys := make([]string, 0, len(key))
    87  	for _, k := range key {
    88  		keys = append(keys, c.getKey(k))
    89  	}
    90  
    91  	_ , err := c.client.Del(context.Background(), keys...).Result()
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  func (c *redisClient) Ping() error {
   100  	_, err := c.client.Ping(context.Background()).Result()
   101  	return err
   102  }
   103  
   104  func (c *redisClient) getKey(key string) string {
   105  	if c.prefix != "" {
   106  		return c.prefix + ":" + key
   107  	}
   108  
   109  	return key
   110  }