package config import ( "errors" "github.com/go-playground/validator" "github.com/imdario/mergo" confLoader "github.com/otakukaze/config-loader" ) type Config struct { Server Server `yaml:"server"` } type Server struct { Port int `yaml:"port" env:"SERVER_PORT" default:"10230" validate:"gte=1,lte=65535"` Secret string `yaml:"secret" env:"SERVER_SECRET" default:"lawsnote-rpi" validate:"required,min=1"` RelayPin int `yaml:"relay_pin" env:"SERVER_RELAY_PIN" validate:"required,gte=1,lte=255"` } func Load(cfgPath ...string) (*Config, error) { cfg := &Config{} // load config from env and default value if err := confLoader.Load(cfg, &confLoader.LoadOptions{FromEnv: true}); err != nil { return nil, err } validate := validator.New() if len(cfgPath) > 0 { for _, v := range cfgPath { fileOpts := &confLoader.ConfigFile{Type: confLoader.ConfigFileTypeYAML, Path: v} loadOpts := &confLoader.LoadOptions{ConfigFile: fileOpts, FromEnv: false} c := &Config{} if err := confLoader.Load(c, loadOpts); err != nil { return nil, err } // validate struct fields if err := validate.Struct(c); err != nil { return nil, err } // merge new config to prev config withOverride if err := mergo.Merge(&cfg, c, mergo.WithOverride); err != nil { return nil, err } } } if cfg.Server.RelayPin < 1 || cfg.Server.RelayPin > 255 { return nil, errors.New("gpio pin range wrong (1 <= x <= 255)") } if cfg.Server.Secret == "" { return nil, errors.New("secret empty") } return cfg, nil }