func NewClient(cfg *Config) (*Client, error) {
	var c = &Client{
		cfg: cfg,
	}
	switch cfg.DeployType {
	case TypeSingle:
		c.Cmdable = redis.NewClient(&redis.Options{
			Addr:               cfg.ForSingle.Addr,
			Password:           cfg.Password,
			MaxRetries:         cfg.MaxRetries,
			MaxRetryBackoff:    time.Duration(cfg.ForSingle.MaxRetryBackoff) * time.Second,
			DialTimeout:        time.Duration(cfg.DialTimeout) * time.Second,
			ReadTimeout:        time.Duration(cfg.ReadTimeout) * time.Second,
			WriteTimeout:       time.Duration(cfg.WriteTimeout) * time.Second,
			PoolSize:           cfg.PoolSizePerNode,
			PoolTimeout:        time.Duration(cfg.PoolTimeout) * time.Second,
			IdleTimeout:        time.Duration(cfg.IdleTimeout) * time.Second,
			IdleCheckFrequency: time.Duration(cfg.IdleCheckFrequency) * time.Second,
		})
	case TypeCluster:
		c.Cmdable = redis.NewClusterClient(&redis.ClusterOptions{
			Addrs:              cfg.ForCluster.Addrs,
			MaxRedirects:       cfg.ForCluster.MaxRedirects,
			ReadOnly:           cfg.ReadOnly,
			RouteByLatency:     cfg.ForCluster.RouteByLatency,
			Password:           cfg.Password,
			MaxRetries:         cfg.MaxRetries,
			DialTimeout:        time.Duration(cfg.DialTimeout) * time.Second,
			ReadTimeout:        time.Duration(cfg.ReadTimeout) * time.Second,
			WriteTimeout:       time.Duration(cfg.WriteTimeout) * time.Second,
			PoolSize:           cfg.PoolSizePerNode,
			PoolTimeout:        time.Duration(cfg.PoolTimeout) * time.Second,
			IdleTimeout:        time.Duration(cfg.IdleTimeout) * time.Second,
			IdleCheckFrequency: time.Duration(cfg.IdleCheckFrequency) * time.Second,
		})
	default:
		return nil, fmt.Errorf("redis.Config.DeployType: optional enumeration list: %s, %s", TypeSingle, TypeCluster)
	}
	if _, err := c.Ping().Result(); err != nil {
		return nil, err
	}
	return c, nil
}
NewClient creates a redis(cluster) client from yaml config, and pings the client.
package redis
import (
	"fmt"
	"time"
	"github.com/go-redis/redis/v7"
	"github.com/henrylee2cn/cfgo"
)
type (
	Config struct {
		DeployType string `yaml:"deploy_type"`
		ForSingle SingleConfig `yaml:"for_single"`
		ForCluster ClusterConfig `yaml:"for_cluster"`
		Password string `yaml:"password,omitempty"`
		MaxRetries int `yaml:"max_retries,omitempty"`
		DialTimeout int64 `yaml:"dial_timeout,omitempty"`
		ReadTimeout int64 `yaml:"read_timeout,omitempty"`
		WriteTimeout int64 `yaml:"write_timeout,omitempty"`
		PoolSizePerNode int `yaml:"pool_size_per_node"`
		PoolTimeout int64 `yaml:"pool_timeout,omitempty"`
		IdleTimeout int64 `yaml:"idle_timeout"`
		IdleCheckFrequency int64 `yaml:"idle_check_frequency,omitempty"`
		ReadOnly bool `yaml:"read_only,omitempty"`
		init bool
	}
	SingleConfig struct {
		Addr string `yaml:"addr"`
		MaxRetryBackoff int64 `yaml:"max_retry_backoff,omitempty"`
	}
	ClusterConfig struct {
		Addrs []string `yaml:"addrs"`
		MaxRedirects int `yaml:"max_redirects,omitempty"`
		RouteByLatency bool `yaml:"route_by_latency,omitempty"`
	}
)
const (
	TypeSingle  = "single"
	TypeCluster = "cluster"
)
func (cfg *Config) Reload(bind cfgo.BindFunc) error {
	if cfg.init {
		return nil
	}
	err := bind()
	if err != nil {
		return err
	}
	cfg.init = true
	if cfg.DeployType != TypeSingle && cfg.DeployType != TypeCluster {
		return fmt.Errorf("redis config: deploy_type optional enumeration list: %s, %s", TypeSingle, TypeCluster)
	}
	return nil
}
func ReadConfig(configSection string) (*Config, error) {
	var cfg = NewConfig()
	var err error
	if cfgo.IsReg(configSection) {
		err = cfgo.BindSection(configSection, cfg)
	} else {
		err = cfgo.Reg(configSection, cfg)
	}
	return cfg, err
}
func NewConfig() *Config {
	return &Config{
		DeployType: TypeSingle,
		ForSingle:  SingleConfig{Addr: "127.0.0.1:6379"},
	}
}
type (
	Client struct {
		cfg *Config
		Cmdable
	}
	Cmdable interface {
		redis.Cmdable
		Subscribe(channels ...string) *redis.PubSub
	}
	PubSub             = redis.PubSub
	Message            = redis.Message
	GeoLocation        = redis.GeoLocation
	GeoRadiusQuery     = redis.GeoRadiusQuery
	ZRangeBy           = redis.ZRangeBy
	Z                  = redis.Z
	Pipeliner          = redis.Pipeliner
	RedisCmdable       = redis.Cmdable
	SliceCmd           = redis.SliceCmd
	StatusCmd          = redis.StatusCmd
	Cmder              = redis.Cmder
	IntCmd             = redis.IntCmd
	DurationCmd        = redis.DurationCmd
	BoolCmd            = redis.BoolCmd
	StringCmd          = redis.StringCmd
	FloatCmd           = redis.FloatCmd
	StringSliceCmd     = redis.StringSliceCmd
	BoolSliceCmd       = redis.BoolSliceCmd
	StringStringMapCmd = redis.StringStringMapCmd
	StringIntMapCmd    = redis.StringIntMapCmd
	ZSliceCmd          = redis.ZSliceCmd
	ScanCmd            = redis.ScanCmd
	ClusterSlotsCmd    = redis.ClusterSlotsCmd
)