package redis import ( "fmt" "net/url" "strconv" "sync" "time" "apigo.cc/go/cast" "apigo.cc/go/crypto" "apigo.cc/go/log" "apigo.cc/go/safe" ) type Config struct { Host string Password string DB int MaxActive int MaxIdle int IdleTimeout time.Duration ConnectTimeout time.Duration ReadTimeout time.Duration WriteTimeout time.Duration LogSlow time.Duration logger *log.Logger pwd *safe.SafeBuf } var redisConfigs = make(map[string]*Config) var redisConfigsLock = sync.RWMutex{} var confAes, _ = crypto.NewAESGCMAndEraseKey([]byte("?GQ$0K0GgLdO=f+~L68PLm$uhKr4'=tV"), []byte("VFs7@sK61cj^f?HZ")) var keysOnce = sync.Once{} func SetEncryptKeys(key, iv []byte) { keysOnce.Do(func() { confAes.Close() confAes, _ = crypto.NewAESGCMAndEraseKey(key, iv) }) } func (conf *Config) ConfigureBy(setting string) { redisConfigsLock.Lock() redisConfigs[setting] = conf redisConfigsLock.Unlock() urlInfo, err := url.Parse(setting) if err != nil { conf.logger.Error(err.Error(), "url", setting) return } if urlInfo.Scheme != "redis" { conf.logger.Error("unsupported scheme", "url", setting) return } conf.Host = urlInfo.Host dbStr := urlInfo.Query().Get("database") if dbStr == "" && len(urlInfo.Path) > 1 { dbStr = urlInfo.Path[1:] } if len(dbStr) > 0 { db, err := strconv.Atoi(dbStr) if err != nil { conf.logger.Error(err.Error(), "url", setting) } if err == nil && db >= 0 && db <= 15 { conf.DB = db } } conf.Password, _ = urlInfo.User.Password() conf.LogSlow = cast.Duration(urlInfo.Query().Get("logSlow")) conf.MaxIdle = cast.Int(urlInfo.Query().Get("maxIdle")) conf.MaxActive = cast.Int(urlInfo.Query().Get("maxActive")) conf.ConnectTimeout = cast.Duration(urlInfo.Query().Get("connectTimeout")) conf.ReadTimeout = cast.Duration(urlInfo.Query().Get("readTimeout")) conf.WriteTimeout = cast.Duration(urlInfo.Query().Get("writeTimeout")) conf.IdleTimeout = cast.Duration(urlInfo.Query().Get("idleTimeout")) } func (conf *Config) Dsn() string { return fmt.Sprintf("redis://:****@%s/%d?timeout=%s&logSlow=%s", conf.Host, conf.DB, conf.ConnectTimeout, conf.LogSlow) } func parseByName(name string) *Config { // config name support Host:Port args := cast.Split(name, ":") db := 0 if len(args) > 1 { arg1, err := strconv.Atoi(args[1]) if err == nil && arg1 >= 0 && arg1 <= 15 { name = args[0] db = arg1 } } redisConfigsLock.RLock() conf := redisConfigs[name] redisConfigsLock.RUnlock() if conf == nil { conf = new(Config) redisConfigsLock.Lock() redisConfigs[name] = conf redisConfigsLock.Unlock() if len(args) > 1 { arg1, err := strconv.Atoi(args[1]) if err == nil && arg1 >= 0 && arg1 <= 15 { conf.DB = arg1 } else { conf.Host = args[0] + ":" + args[1] } } } for i := 2; i < len(args); i++ { arg2, err := strconv.Atoi(args[i]) if err == nil { if arg2 >= 0 && arg2 <= 15 { conf.DB = arg2 } else { conf.Password = args[i] } } else { conf.Password = args[i] } } if conf.DB == 0 && db > 0 && db <= 15 { conf.DB = db } return conf }