Skip to content

Commit

Permalink
Merge pull request #55 from jehiah/config_handlers_55
Browse files Browse the repository at this point in the history
refactor config handling
  • Loading branch information
jehiah committed Jun 27, 2014
2 parents f4ae369 + b88d506 commit bfdab88
Showing 1 changed file with 101 additions and 46 deletions.
147 changes: 101 additions & 46 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ import (
"unsafe"
)

// Define handlers for setting config defaults, and setting config values from command line arguments or config files
type configHandler interface {
Handles(option string) bool
HandlesOption(c *Config, option string) bool
Set(c *Config, option string, value interface{}) error
Validate(c *Config) error
}

type defaultsHandler interface {
SetDefaults(c *Config) error
}

// Config is a struct of NSQ options
Expand All @@ -28,7 +34,9 @@ type configHandler interface {
//
// Use Set(key string, value interface{}) as an alternate way to set parameters
type Config struct {
initialized bool
initialized bool

// used to Initialize, Validate
configHandlers []configHandler

// Deadlines for network reads and writes
Expand Down Expand Up @@ -98,7 +106,7 @@ type Config struct {
// This must be used to initialize Config structs. Values can be set directly, or through Config.Set()
func NewConfig() *Config {
c := &Config{}
c.configHandlers = append(c.configHandlers, &tlsHandler{})
c.configHandlers = append(c.configHandlers, &structTagsConfig{}, &tlsConfig{})
c.initialized = true
if err := c.setDefaults(); err != nil {
panic(err.Error())
Expand Down Expand Up @@ -130,23 +138,78 @@ func (c *Config) Set(option string, value interface{}) error {
c.assertInitialized()

for _, h := range c.configHandlers {
if h.Handles(option) {
if h.HandlesOption(c, option) {
return h.Set(c, option, value)
}
}
return fmt.Errorf("invalid option %s", option)
}

func (c *Config) assertInitialized() {
if !c.initialized {
panic("Config{} must be created with NewConfig()")
}
}

// Validate checks that all values are within specified min/max ranges
func (c *Config) Validate() error {

c.assertInitialized()

for _, h := range c.configHandlers {
if err := h.Validate(c); err != nil {
return err
}
}
return nil

}

func (c *Config) setDefaults() error {
for _, h := range c.configHandlers {
hh, ok := h.(defaultsHandler)
if ok {
if err := hh.SetDefaults(c); err != nil {
return err
}
}
}

return nil
}

type structTagsConfig struct {
}

// Handle options that are listed in StructTags
func (h *structTagsConfig) HandlesOption(c *Config, option string) bool {
val := reflect.ValueOf(c).Elem()
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
opt := field.Tag.Get("opt")
if opt == option {
return true
}
}
return false
}

// Set values based on parameters in StructTags
func (h *structTagsConfig) Set(c *Config, option string, value interface{}) error {
val := reflect.ValueOf(c).Elem()
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
opt := field.Tag.Get("opt")
min := field.Tag.Get("min")
max := field.Tag.Get("max")

if option != opt {
continue
}

min := field.Tag.Get("min")
max := field.Tag.Get("max")

fieldVal := val.FieldByName(field.Name)
dest := unsafeValueOf(fieldVal)
coercedVal, err := coerce(value, field.Type)
Expand All @@ -171,21 +234,37 @@ func (c *Config) Set(option string, value interface{}) error {
dest.Set(coercedVal)
return nil
}

return fmt.Errorf("invalid option %s", option)
return fmt.Errorf("unknown option %s", option)
}

func (c *Config) assertInitialized() {
if !c.initialized {
panic("Config{} must be created with NewConfig()")
func (h *structTagsConfig) SetDefaults(c *Config) error {
val := reflect.ValueOf(c).Elem()
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
opt := field.Tag.Get("opt")
defaultVal := field.Tag.Get("default")
if defaultVal == "" || opt == "" {
continue
}

if err := c.Set(opt, defaultVal); err != nil {
return err
}
}
}

// Validate checks that all values are within specified min/max ranges
func (c *Config) Validate() error {
hostname, err := os.Hostname()
if err != nil {
log.Fatalf("ERROR: unable to get hostname %s", err.Error())
}

c.assertInitialized()
c.ClientID = strings.Split(hostname, ".")[0]
c.Hostname = hostname
c.UserAgent = fmt.Sprintf("go-nsq/%s", VERSION)
return nil
}

func (h *structTagsConfig) Validate(c *Config) error {
val := reflect.ValueOf(c).Elem()
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
Expand Down Expand Up @@ -222,45 +301,18 @@ func (c *Config) Validate() error {
return nil
}

func (c *Config) setDefaults() error {
val := reflect.ValueOf(c).Elem()
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
opt := field.Tag.Get("opt")
defaultVal := field.Tag.Get("default")
if defaultVal == "" || opt == "" {
continue
}

if err := c.Set(opt, defaultVal); err != nil {
return err
}
}

hostname, err := os.Hostname()
if err != nil {
log.Fatalf("ERROR: unable to get hostname %s", err.Error())
}

c.ClientID = strings.Split(hostname, ".")[0]
c.Hostname = hostname
c.UserAgent = fmt.Sprintf("go-nsq/%s", VERSION)

return nil
}

type tlsHandler struct {
// Parsing for higher order TLS settings
type tlsConfig struct {
}

func (t *tlsHandler) Handles(option string) bool {
func (t *tlsConfig) HandlesOption(c *Config, option string) bool {
switch option {
case "tls-root-ca-file", "tls-insecure-skip-verify":
return true
}
return false
}
func (t *tlsHandler) Set(c *Config, option string, value interface{}) error {
func (t *tlsConfig) Set(c *Config, option string, value interface{}) error {
if c.TlsConfig == nil {
c.TlsConfig = &tls.Config{}
}
Expand Down Expand Up @@ -295,6 +347,9 @@ func (t *tlsHandler) Set(c *Config, option string, value interface{}) error {
}
return fmt.Errorf("unknown option %s", option)
}
func (t *tlsConfig) Validate(c *Config) error {
return nil
}

// because Config contains private structs we can't use reflect.Value
// directly, instead we need to "unsafely" address the variable
Expand Down

0 comments on commit bfdab88

Please sign in to comment.