|
@@ -0,0 +1,221 @@
|
|
|
+package cache
|
|
|
+
|
|
|
+import (
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/go-redis/redis"
|
|
|
+)
|
|
|
+
|
|
|
+// RedisConfig config
|
|
|
+type RedisConfig struct {
|
|
|
+ Addr string
|
|
|
+ Password string
|
|
|
+ DialTimeout time.Duration
|
|
|
+ ReadTimeout time.Duration
|
|
|
+ WriteTimeout time.Duration
|
|
|
+ PoolTimeout time.Duration
|
|
|
+ PoolSize int
|
|
|
+}
|
|
|
+
|
|
|
+// RedisClusterConfig redis cluster configure
|
|
|
+type RedisClusterConfig struct {
|
|
|
+ // A seed list of host:port addresses of cluster nodes.
|
|
|
+ Addrs []string
|
|
|
+
|
|
|
+ // The maximum number of retries before giving up. Command is retried
|
|
|
+ // on network errors and MOVED/ASK redirects.
|
|
|
+ // Default is 16.
|
|
|
+ MaxRedirects int
|
|
|
+
|
|
|
+ // Enables read-only commands on slave nodes.
|
|
|
+ ReadOnly bool
|
|
|
+ // Allows routing read-only commands to the closest master or slave node.
|
|
|
+ RouteByLatency bool
|
|
|
+
|
|
|
+ //OnConnect func(*Conn) error
|
|
|
+
|
|
|
+ MaxRetries int
|
|
|
+ MinRetryBackoff time.Duration
|
|
|
+ MaxRetryBackoff time.Duration
|
|
|
+ Password string
|
|
|
+
|
|
|
+ DialTimeout time.Duration
|
|
|
+ ReadTimeout time.Duration
|
|
|
+ WriteTimeout time.Duration
|
|
|
+
|
|
|
+ // PoolSize applies per cluster node and not for the whole cluster.
|
|
|
+ PoolSize int
|
|
|
+ PoolTimeout time.Duration
|
|
|
+ IdleTimeout time.Duration
|
|
|
+ IdleCheckFrequency time.Duration
|
|
|
+}
|
|
|
+
|
|
|
+var (
|
|
|
+ redisConfig RedisConfig
|
|
|
+ redisClusterConfig RedisClusterConfig
|
|
|
+ once sync.Once
|
|
|
+ cache *RedisCache
|
|
|
+ isCluster bool
|
|
|
+)
|
|
|
+
|
|
|
+// RedisCache define
|
|
|
+type RedisCache struct {
|
|
|
+ c *redis.Client
|
|
|
+ cc *redis.ClusterClient
|
|
|
+}
|
|
|
+
|
|
|
+// SetRedisConfig set
|
|
|
+func SetRedisConfig(cfg RedisConfig) {
|
|
|
+ redisConfig = cfg
|
|
|
+}
|
|
|
+
|
|
|
+// SetRedisClusterConfig set
|
|
|
+func SetRedisClusterConfig(cfg RedisClusterConfig) {
|
|
|
+ redisClusterConfig = cfg
|
|
|
+}
|
|
|
+
|
|
|
+// NewRedisCache new RedisCache object
|
|
|
+func NewRedisCache() *RedisCache {
|
|
|
+ client := redis.NewClient(&redis.Options{
|
|
|
+ Addr: redisConfig.Addr,
|
|
|
+ Password: redisConfig.Password,
|
|
|
+ DialTimeout: redisConfig.DialTimeout,
|
|
|
+ ReadTimeout: redisConfig.ReadTimeout,
|
|
|
+ WriteTimeout: redisConfig.WriteTimeout,
|
|
|
+ PoolSize: redisConfig.PoolSize,
|
|
|
+ PoolTimeout: redisConfig.PoolTimeout,
|
|
|
+ })
|
|
|
+
|
|
|
+ client.Ping().Result()
|
|
|
+ return &RedisCache{c: client}
|
|
|
+}
|
|
|
+
|
|
|
+// NewRedisClusterCache new RedisCluster object
|
|
|
+func NewRedisClusterCache() *RedisCache {
|
|
|
+ var config redis.ClusterOptions
|
|
|
+
|
|
|
+ config.Addrs = redisClusterConfig.Addrs
|
|
|
+ config.Password = redisClusterConfig.Password
|
|
|
+
|
|
|
+ config.DialTimeout = redisClusterConfig.DialTimeout
|
|
|
+ config.ReadTimeout = redisClusterConfig.ReadTimeout
|
|
|
+ config.WriteTimeout = redisClusterConfig.WriteTimeout
|
|
|
+
|
|
|
+ config.PoolSize = redisClusterConfig.PoolSize
|
|
|
+ config.PoolTimeout = redisClusterConfig.PoolTimeout
|
|
|
+ config.IdleTimeout = redisClusterConfig.IdleTimeout
|
|
|
+ config.IdleCheckFrequency = redisClusterConfig.IdleCheckFrequency
|
|
|
+
|
|
|
+ client := redis.NewClusterClient(&config)
|
|
|
+
|
|
|
+ client.Ping()
|
|
|
+ return &RedisCache{cc: client}
|
|
|
+}
|
|
|
+
|
|
|
+// Get get value from cache
|
|
|
+func (c RedisCache) Get(key string) (string, error) {
|
|
|
+ if c.cc != nil {
|
|
|
+ return c.cc.Get(key).Result()
|
|
|
+ }
|
|
|
+ return c.c.Get(key).Result()
|
|
|
+}
|
|
|
+
|
|
|
+// Set set key-value to cache
|
|
|
+func (c RedisCache) Set(key, value string, expiration time.Duration) error {
|
|
|
+ if c.cc != nil {
|
|
|
+ return c.cc.Set(key, value, expiration).Err()
|
|
|
+ }
|
|
|
+ return c.c.Set(key, value, expiration).Err()
|
|
|
+}
|
|
|
+
|
|
|
+// Del Del value from cache
|
|
|
+func (c RedisCache) Del(key string) (int64, error) {
|
|
|
+ if c.cc != nil {
|
|
|
+ return c.cc.Del(key).Result()
|
|
|
+ }
|
|
|
+ return c.c.Del(key).Result()
|
|
|
+}
|
|
|
+
|
|
|
+// Subscribe subscribe message
|
|
|
+func (c RedisCache) Subscribe(channels string, cb func(channel string, message string, err error)) {
|
|
|
+ pubsub := &redis.PubSub{}
|
|
|
+ if c.cc != nil {
|
|
|
+ pubsub = c.cc.Subscribe(channels)
|
|
|
+ } else {
|
|
|
+ pubsub = c.c.Subscribe(channels)
|
|
|
+ }
|
|
|
+ defer pubsub.Close()
|
|
|
+
|
|
|
+ var (
|
|
|
+ msg *redis.Message
|
|
|
+ err error
|
|
|
+ )
|
|
|
+ msg, err = pubsub.ReceiveMessage()
|
|
|
+ for err == nil {
|
|
|
+ cb(msg.Channel, msg.Payload, nil)
|
|
|
+ msg, err = pubsub.ReceiveMessage()
|
|
|
+ }
|
|
|
+
|
|
|
+ cb("", "", err)
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// Publish publish message
|
|
|
+func (c RedisCache) Publish(channel, message string) error {
|
|
|
+ return c.c.Publish(channel, message).Err()
|
|
|
+}
|
|
|
+
|
|
|
+// PublishCluster publish message
|
|
|
+func (c RedisCache) PublishCluster(channel, message string) error {
|
|
|
+ return c.cc.Publish(channel, message).Err()
|
|
|
+}
|
|
|
+
|
|
|
+func connect() (*RedisCache, error) {
|
|
|
+ if cache != nil {
|
|
|
+ return cache, nil
|
|
|
+ }
|
|
|
+ //*
|
|
|
+ var err error
|
|
|
+ once.Do(func() {
|
|
|
+ isCluster = false
|
|
|
+ if len(redisConfig.Addr) > 0 {
|
|
|
+ cache = NewRedisCache()
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(redisClusterConfig.Addrs) > 0 {
|
|
|
+ cache = NewRedisClusterCache()
|
|
|
+ isCluster = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ //*/
|
|
|
+ return cache, err
|
|
|
+}
|
|
|
+
|
|
|
+// Get key from cache
|
|
|
+func Get(key string) (string, error) {
|
|
|
+ c, err := connect()
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+ return c.Get(key)
|
|
|
+}
|
|
|
+
|
|
|
+// Set key-value to cache
|
|
|
+func Set(key, value string, expiration time.Duration) error {
|
|
|
+ c, err := connect()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return c.Set(key, value, expiration)
|
|
|
+}
|
|
|
+
|
|
|
+// Del delete key from cache
|
|
|
+func Del(key string) (int64, error) {
|
|
|
+ c, err := connect()
|
|
|
+ if err != nil {
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ return c.Del(key)
|
|
|
+}
|