gitee.com/h79/goutils@v1.22.10/dao/redis/adapter.go (about) 1 package redis 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 commonoption "gitee.com/h79/goutils/common/option" 8 "gitee.com/h79/goutils/common/result" 9 commontls "gitee.com/h79/goutils/common/tls" 10 "gitee.com/h79/goutils/dao/config" 11 "gitee.com/h79/goutils/dao/option" 12 daotls "gitee.com/h79/goutils/dao/util" 13 "github.com/go-redis/redis/v8" 14 "go.uber.org/zap" 15 "strings" 16 "time" 17 ) 18 19 var _ Redis = (*Adapter)(nil) 20 21 type Adapter struct { 22 client *redis.Client 23 sentinel *redis.SentinelClient 24 cluster *redis.ClusterClient 25 name string 26 } 27 28 var DefaultTlsFunc = func(cnf *config.RedisConfig) (*tls.Config, error) { 29 if strings.EqualFold(cnf.Tls.Key, "false") { 30 return nil, result.RErrNotSupport 31 } 32 if strings.EqualFold(cnf.Tls.Key, "true") { 33 return &tls.Config{}, nil 34 } 35 if strings.EqualFold(cnf.Tls.Key, "skip-verify") || 36 strings.EqualFold(cnf.Tls.Key, "preferred") { 37 return &tls.Config{InsecureSkipVerify: true}, nil 38 } 39 cert, rootCertPool, err := commontls.GetCertificate(&cnf.Tls) 40 if err != nil { 41 return nil, err 42 } 43 return &tls.Config{ 44 RootCAs: rootCertPool, 45 Certificates: []tls.Certificate{cert}, 46 }, nil 47 } 48 49 func WithTlsOption(f func(cnf *config.RedisConfig) (*tls.Config, error)) commonoption.Option { 50 return tlsFunc(f) 51 } 52 53 type tlsFunc func(cnf *config.RedisConfig) (*tls.Config, error) 54 55 func (t tlsFunc) String() string { 56 return "redis:tls" 57 } 58 func (t tlsFunc) Type() int { return option.TypeRedisTls } 59 func (t tlsFunc) Value() interface{} { return t } 60 61 func tlsFuncExist(opts ...commonoption.Option) tlsFunc { 62 if r, ok := commonoption.Exist(option.TypeRedisTls, opts...); ok { 63 return r.Value().(tlsFunc) 64 } 65 return nil 66 } 67 68 func UseTls(cnf *config.RedisConfig, opts ...commonoption.Option) (*tls.Config, error) { 69 fn := tlsFuncExist(opts...) 70 if fn == nil { 71 fn = DefaultTlsFunc 72 } 73 return fn(cnf) 74 } 75 76 func NewAdapter(name string, cfg *config.RedisConfig, sentinelCfg *config.RedisConfig, clusterCfg *config.RedisConfig, opts ...commonoption.Option) (*Adapter, error) { 77 cli, err := newClient(cfg) 78 if err != nil { 79 return nil, err 80 } 81 sentinel, err := newSentinelClient(sentinelCfg) 82 if err != nil { 83 zap.L().Warn("Redis: newSentinelClient", zap.Error(err)) 84 } 85 cluster, err := newClusterClient(clusterCfg) 86 if err != nil { 87 zap.L().Warn("Redis: newClusterClient", zap.Error(err)) 88 } 89 return &Adapter{client: cli, sentinel: sentinel, cluster: cluster, name: name}, nil 90 } 91 92 func newClient(cfg *config.RedisConfig, opts ...commonoption.Option) (*redis.Client, error) { 93 if len(cfg.Host) == 0 || len(cfg.Host[0]) <= 0 { 94 return nil, result.RErrParam 95 } 96 tlsCfn, _ := UseTls(cfg, opts...) 97 cli := redis.NewClient(&redis.Options{ 98 Network: "tcp", 99 Addr: cfg.Host[0], 100 Username: cfg.User, 101 Password: cfg.Pwd, // no password set 102 DB: cfg.DB, // use default DB 103 DialTimeout: cfg.DialTimeout * time.Second, 104 ReadTimeout: cfg.ReadTimeout * time.Second, 105 WriteTimeout: cfg.WriteTimeout * time.Second, 106 IdleTimeout: cfg.IdleTimeout * time.Minute, 107 TLSConfig: tlsCfn, 108 }) 109 110 ctx := context.Background() 111 if _, err := cli.Ping(ctx).Result(); err != nil { 112 daotls.Alarm(result.ErrRdsPingInternal, "", fmt.Sprintf("master redis ping(%s)", cfg.Host), err) 113 } 114 return cli, nil 115 } 116 117 func newSentinelClient(cfg *config.RedisConfig, opts ...commonoption.Option) (*redis.SentinelClient, error) { 118 if len(cfg.Host) == 0 || len(cfg.Host[0]) <= 0 { 119 return nil, result.RErrParam 120 } 121 tlsCfn, _ := UseTls(cfg, opts...) 122 cli := redis.NewSentinelClient(&redis.Options{ 123 Network: "tcp", 124 Addr: cfg.Host[0], 125 Username: cfg.User, 126 Password: cfg.Pwd, // no password set 127 DB: cfg.DB, // use default DB 128 DialTimeout: cfg.DialTimeout * time.Second, 129 ReadTimeout: cfg.ReadTimeout * time.Second, 130 WriteTimeout: cfg.WriteTimeout * time.Second, 131 IdleTimeout: cfg.IdleTimeout * time.Minute, 132 TLSConfig: tlsCfn, 133 }) 134 135 ctx := context.Background() 136 if _, err := cli.Ping(ctx).Result(); err != nil { 137 daotls.Alarm(result.ErrRdsPingInternal, "", fmt.Sprintf("sentinel redis ping(%s)", cfg.Host), err) 138 } 139 return cli, nil 140 } 141 142 func newClusterClient(cfg *config.RedisConfig, opts ...commonoption.Option) (*redis.ClusterClient, error) { 143 if len(cfg.Host) == 0 || len(cfg.Host[0]) <= 0 { 144 return nil, result.RErrParam 145 } 146 tlsCfn, _ := UseTls(cfg, opts...) 147 cli := redis.NewClusterClient(&redis.ClusterOptions{ 148 Addrs: cfg.Host, 149 Username: cfg.User, 150 Password: cfg.Pwd, // no password set 151 DialTimeout: cfg.DialTimeout * time.Second, 152 ReadTimeout: cfg.ReadTimeout * time.Second, 153 WriteTimeout: cfg.WriteTimeout * time.Second, 154 IdleTimeout: cfg.IdleTimeout * time.Minute, 155 TLSConfig: tlsCfn, 156 }) 157 158 ctx := context.Background() 159 if _, err := cli.Ping(ctx).Result(); err != nil { 160 daotls.Alarm(result.ErrRdsPingInternal, "", fmt.Sprintf("cluster redis ping(%s)", cfg.Host), err) 161 } 162 return cli, nil 163 } 164 165 func (a *Adapter) Rds() *redis.Client { 166 return a.client 167 } 168 169 func (a *Adapter) Sentinel() *redis.SentinelClient { 170 return a.sentinel 171 } 172 173 func (a *Adapter) Cluster() *redis.ClusterClient { 174 return a.cluster 175 } 176 177 func (a *Adapter) Name() string { 178 return a.name 179 }