diff --git a/config/api.go b/config/api.go index 8fe13cd..121d668 100644 --- a/config/api.go +++ b/config/api.go @@ -5,33 +5,25 @@ import "time" var config *Config func GetString(key string) string { - return config.Viper.GetString(key) + return config.GetString(key) } func GetInt(key string) int { - return config.Viper.GetInt(key) + return config.GetInt(key) } func GetBool(key string) bool { - return config.Viper.GetBool(key) + return config.GetBool(key) } func GetTime(key string) time.Time { - return config.Viper.GetTime(key) + return config.GetTime(key) } func GetFloat64(key string) float64 { - return config.Viper.GetFloat64(key) -} - -func GetDuration(key string) time.Duration { - return config.Viper.GetDuration(key) + return config.GetFloat64(key) } func UnmarshalKey(key string, rawVal interface{}) { - config.Viper.UnmarshalKey(key, &rawVal) -} - -func WithConfig(c *Config) { - config = c + config.UnmarshalKey(key, &rawVal) } diff --git a/config/config.go b/config/config.go index 5333b02..429483f 100644 --- a/config/config.go +++ b/config/config.go @@ -2,48 +2,73 @@ package config import ( "strings" + "time" +) - "github.com/spf13/viper" +var ( + vendor Properties ) type Config struct { //key: scheme, value: url protocols map[string]string - - Viper *viper.Viper } func New() *Config { - return &Config{ + config = &Config{ protocols: make(map[string]string), - Viper: viper.New(), } + return config } func (c *Config) Init() error { //初始化Contrib for key, value := range c.protocols { //初始化Contrib - configsourceBuilders[key].Init(value, c) + configsourceBuilders[key].Init(value) } return nil } -func (c *Config) ParseArgument() *Config { - return c -} - func (c *Config) AddProtocol(protocol string) *Config { - c.protocols[strings.Split(protocol, "://")[0]] = strings.Split(protocol, "://")[1] + c.protocols[strings.Split(protocol, "://")[0]] = protocol return c } func (c *Config) ReadConfig() error { for scheme, _ := range c.protocols { - err := configsourceBuilders[scheme].Read(c) + err := configsourceBuilders[scheme].Read() if err != nil { return err } } return nil } + +func WithVendor(v Properties) { + vendor = v +} + +func (c *Config) GetString(key string) string { + return vendor.GetString(key) +} + +func (c *Config) UnmarshalKey(key string, rawVal interface{}) error { + return vendor.UnmarshalKey(key, rawVal) +} + +func (c *Config) GetInt(key string) int { + return vendor.GetInt(key) +} + +func (c *Config) GetBool(key string) bool { + return vendor.GetBool(key) +} + +func (c *Config) GetTime(key string) time.Time { + return vendor.GetTime(key) +} + +func (c *Config) GetFloat64(key string) float64 { + return vendor.GetFloat64(key) +} diff --git a/config/configsource.go b/config/configsource.go index 6fbd5ec..9867071 100644 --- a/config/configsource.go +++ b/config/configsource.go @@ -5,8 +5,8 @@ var ( ) type ConfigSource interface { - Read(config *Config) error - Init(protocol string, config *Config) error + Read() error + Init(protocol string) error } func Register(scheme string, creator ConfigSource) { diff --git a/config/contrib/env/env.go b/config/contrib/env/env.go deleted file mode 100644 index b499938..0000000 --- a/config/contrib/env/env.go +++ /dev/null @@ -1,36 +0,0 @@ -package env - -import ( - "strings" - - "github.com/NetEase-Media/easy-ngo/config" -) - -const EnvConfigSourceName = "env" - -type EnvConfigSource struct { - envPrefix string - bindEnv []string -} - -func New() *EnvConfigSource { - return &EnvConfigSource{ - bindEnv: make([]string, 0), - } -} - -func (e *EnvConfigSource) Init(protocol string, config *config.Config) error { - kvs := strings.Split(protocol, ";") - for _, kv := range kvs { - if strings.HasPrefix(kv, "prefix=") { - e.envPrefix = strings.TrimPrefix(kv, "prefix=") - } - } - config.Viper.AutomaticEnv() - config.Viper.SetEnvPrefix(e.envPrefix) - return nil -} - -func (e *EnvConfigSource) Read(config *config.Config) error { - return nil -} diff --git a/config/contrib/env/register.go b/config/contrib/env/register.go deleted file mode 100644 index bdf0d1b..0000000 --- a/config/contrib/env/register.go +++ /dev/null @@ -1,7 +0,0 @@ -package env - -import "github.com/NetEase-Media/easy-ngo/config" - -func init() { - config.Register(EnvConfigSourceName, New()) -} diff --git a/config/contrib/file/file.go b/config/contrib/file/file.go deleted file mode 100644 index 4aeef4b..0000000 --- a/config/contrib/file/file.go +++ /dev/null @@ -1,44 +0,0 @@ -package file - -import ( - "strings" - - "github.com/NetEase-Media/easy-ngo/config" -) - -const FileConfigSourceName = "file" - -type FileConfigSource struct { - name string - fileType string - path []string -} - -func New() *FileConfigSource { - return &FileConfigSource{ - path: make([]string, 0), - } -} - -func (e *FileConfigSource) Init(protocol string, config *config.Config) error { - kvs := strings.Split(protocol, ";") - for _, kv := range kvs { - if strings.HasPrefix(kv, "name=") { - e.name = strings.TrimPrefix(kv, "name=") - } else if strings.HasPrefix(kv, "type=") { - e.fileType = strings.TrimPrefix(kv, "type=") - } else if strings.HasPrefix(kv, "path=") { - e.path = strings.Split(strings.TrimPrefix(kv, "path="), ",") - } - } - config.Viper.SetConfigName(e.name) - config.Viper.SetConfigType(e.fileType) - for _, p := range e.path { - config.Viper.AddConfigPath(p) - } - return nil -} - -func (e *FileConfigSource) Read(config *config.Config) error { - return config.Viper.ReadInConfig() -} diff --git a/config/contrib/file/register.go b/config/contrib/file/register.go deleted file mode 100644 index 7fcaa08..0000000 --- a/config/contrib/file/register.go +++ /dev/null @@ -1,7 +0,0 @@ -package file - -import "github.com/NetEase-Media/easy-ngo/config" - -func init() { - config.Register(FileConfigSourceName, New()) -} diff --git a/config/contrib/xviper/register.go b/config/contrib/xviper/register.go new file mode 100644 index 0000000..530a4e8 --- /dev/null +++ b/config/contrib/xviper/register.go @@ -0,0 +1,16 @@ +package xviper + +import "github.com/NetEase-Media/easy-ngo/config" + +const ( + EnvConfigSourceName = "env" + FileConfigSourceName = "file" +) + +var xviper = New() + +func init() { + config.Register(FileConfigSourceName, xviper) + config.Register(EnvConfigSourceName, xviper) + config.WithVendor(xviper) +} diff --git a/config/contrib/xviper/xviper.go b/config/contrib/xviper/xviper.go new file mode 100644 index 0000000..9568071 --- /dev/null +++ b/config/contrib/xviper/xviper.go @@ -0,0 +1,83 @@ +package xviper + +import ( + "strings" + "time" + + "github.com/spf13/viper" +) + +type XViper struct { + viper *viper.Viper +} + +func New() *XViper { + return &XViper{ + viper: viper.New(), + } +} + +func (xviper *XViper) Init(protocol string) error { + scheme := protocol[:strings.Index(protocol, "://")] + switch scheme { + case "env": + initEnv(protocol[strings.Index(protocol, "://")+3:]) + case "file": + initFile(protocol[strings.Index(protocol, "://")+3:]) + } + return nil +} + +func initEnv(protocol string) { + kvs := strings.Split(protocol, ";") + for _, kv := range kvs { + if strings.HasPrefix(kv, "prefix=") { + xviper.viper.SetEnvPrefix(strings.TrimPrefix(kv, "prefix=")) + } + } + xviper.viper.AutomaticEnv() +} + +func initFile(protocol string) { + kvs := strings.Split(protocol, ";") + for _, kv := range kvs { + if strings.HasPrefix(kv, "name=") { + xviper.viper.SetConfigName(strings.TrimPrefix(kv, "name=")) + } else if strings.HasPrefix(kv, "type=") { + xviper.viper.SetConfigType(strings.TrimPrefix(kv, "type=")) + } else if strings.HasPrefix(kv, "path=") { + paths := strings.Split(strings.TrimPrefix(kv, "path="), ",") + for _, path := range paths { + xviper.viper.AddConfigPath(path) + } + } + } +} + +func (xviper *XViper) Read() error { + return xviper.viper.ReadInConfig() +} + +func (xviper *XViper) GetString(key string) string { + return xviper.viper.GetString(key) +} + +func (xviper *XViper) UnmarshalKey(key string, rawVal interface{}) error { + return xviper.viper.UnmarshalKey(key, rawVal) +} + +func (xviper *XViper) GetInt(key string) int { + return xviper.viper.GetInt(key) +} + +func (xviper *XViper) GetBool(key string) bool { + return xviper.viper.GetBool(key) +} + +func (xviper *XViper) GetTime(key string) time.Time { + return xviper.viper.GetTime(key) +} + +func (xviper *XViper) GetFloat64(key string) float64 { + return xviper.viper.GetFloat64(key) +} diff --git a/config/go.mod b/config/go.mod index a46991e..1dd7cc2 100644 --- a/config/go.mod +++ b/config/go.mod @@ -4,6 +4,11 @@ go 1.18 require github.com/spf13/viper v1.16.0 +require ( + github.com/google/go-cmp v0.5.9 // indirect + github.com/pkg/errors v0.9.1 // indirect +) + require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -19,4 +24,5 @@ require ( golang.org/x/text v0.9.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools v2.2.0+incompatible ) diff --git a/config/go.sum b/config/go.sum index f30f202..767fb2d 100644 --- a/config/go.sum +++ b/config/go.sum @@ -98,6 +98,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -137,6 +138,7 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -469,6 +471,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/config/properties.go b/config/properties.go new file mode 100644 index 0000000..0e7cf68 --- /dev/null +++ b/config/properties.go @@ -0,0 +1,12 @@ +package config + +import "time" + +type Properties interface { + GetString(key string) string + GetInt(key string) int + GetBool(key string) bool + GetTime(key string) time.Time + GetFloat64(key string) float64 + UnmarshalKey(key string, rawVal interface{}) error +} diff --git a/config/test/env_test.go b/config/test/env_test.go deleted file mode 100644 index 58031e1..0000000 --- a/config/test/env_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package test - -import ( - "os" - "testing" - - "github.com/NetEase-Media/easy-ngo/config" - _ "github.com/NetEase-Media/easy-ngo/config/contrib/env" - "github.com/go-playground/assert/v2" -) - -func TestEnv(t *testing.T) { - os.Setenv("APP_NAME", "easy-ngo") - os.Setenv("APP_VERSION", "v1.0.0") - c := config.New() - c.AddProtocol("env://prefix=APP") - c.Init() - config.WithConfig(c) - assert.Equal(t, config.GetString("name"), "easy-ngo") - assert.Equal(t, config.GetString("version"), "v1.0.0") -} diff --git a/config/test/file_test.go b/config/test/file_test.go deleted file mode 100644 index b94135b..0000000 --- a/config/test/file_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package test - -import ( - "testing" - - "github.com/NetEase-Media/easy-ngo/config" - "github.com/go-playground/assert/v2" - - _ "github.com/NetEase-Media/easy-ngo/config/contrib/file" -) - -type App struct { - Name string `mapstructure:"name"` - Version string `mapstructure:"version"` - Port int `mapstructure:"port"` -} - -func TestYaml(t *testing.T) { - c := config.New() - c.AddProtocol("file://type=yaml;path=./;name=test1") - c.Init() - c.ReadConfig() - config.WithConfig(c) - assert.Equal(t, config.GetString("app.name"), "test") - assert.Equal(t, config.GetString("app.version"), "v1.0.0") - assert.Equal(t, config.GetInt("app.port"), 8080) -} - -func TestToml(t *testing.T) { - c := config.New() - c.AddProtocol("file://type=toml;path=./;name=test2") - c.Init() - c.ReadConfig() - config.WithConfig(c) - assert.Equal(t, config.GetString("app.name"), "test") - assert.Equal(t, config.GetString("app.version"), "v1.0.0") - assert.Equal(t, config.GetInt("app.port"), 8080) -} - -func TestStruct(t *testing.T) { - c := config.New() - c.AddProtocol("file://type=toml;path=./;name=test2") - c.Init() - c.ReadConfig() - config.WithConfig(c) - app := &App{} - config.UnmarshalKey("app", app) - assert.Equal(t, app.Name, "test") - assert.Equal(t, app.Version, "v1.0.0") - assert.Equal(t, app.Port, 8080) -} diff --git a/config/test/xviper_test.go b/config/test/xviper_test.go new file mode 100644 index 0000000..d3b16bf --- /dev/null +++ b/config/test/xviper_test.go @@ -0,0 +1,36 @@ +package test + +import ( + "os" + "testing" + + "github.com/NetEase-Media/easy-ngo/config" + _ "github.com/NetEase-Media/easy-ngo/config/contrib/xviper" + "gotest.tools/assert" +) + +type App struct { + Name string `mapstructure:"name"` + Version string `mapstructure:"version"` + Port int `mapstructure:"port"` +} + +func TestXViper(t *testing.T) { + os.Setenv("APP_NAME", "easy-ngo") + os.Setenv("APP_VERSION", "v1.0.0") + os.Setenv("APP_PORT", "8080") + c := config.New() + c.AddProtocol("env://prefix=APP") + c.AddProtocol("file://type=toml;path=./;name=test2") + c.Init() + c.ReadConfig() + assert.Equal(t, "v1.0.0", "v1.0.0") + assert.Equal(t, config.GetString("name"), "easy-ngo") + assert.Equal(t, config.GetString("version"), "v1.0.0") + assert.Equal(t, config.GetInt("port"), 8080) + app := &App{} + config.UnmarshalKey("app", app) + assert.Equal(t, app.Name, "test") + assert.Equal(t, app.Version, "v1.0.0") + assert.Equal(t, app.Port, 8080) +}