package config import ( "io" "os" "time" ) type ( Option interface { Extend(n Nurse) (Nurse, error) } OptionFunc func(n Nurse) (Nurse, error) ) func (f OptionFunc) Extend(n Nurse) (Nurse, error) { return f(n) } func New(opts ...Option) (*Nurse, error) { var ( inst Nurse err error ) for i := range opts { if inst, err = opts[i].Extend(inst); err != nil { return nil, err } } return &inst, nil } type Nurse struct { Servers map[string]Server Endpoints map[Route]EndpointSpec CheckTimeout time.Duration } // Merge merges the current Nurse instance with another one // giving the current instance precedence means no set value is overwritten func (n Nurse) Merge(other Nurse) Nurse { if n.CheckTimeout == 0 { n.CheckTimeout = other.CheckTimeout } for name, srv := range other.Servers { if _, ok := n.Servers[name]; !ok { n.Servers[name] = srv } } return n } func (n *Nurse) Unmarshal(reader io.ReadSeeker) error { providers := []func(io.Reader) configDecoder{ newYAMLDecoder, newJSONDecoder, } for i := range providers { if err := n.tryUnmarshal(reader, providers[i]); err == nil { return nil } } return nil } func (n *Nurse) ReadFromFile(configFilePath string) error { if file, err := os.Open(configFilePath); err != nil { return err } else { defer func() { _ = file.Close() }() return n.Unmarshal(file) } } func (n *Nurse) tryUnmarshal(seeker io.ReadSeeker, prov func(reader io.Reader) configDecoder) error { if _, err := seeker.Seek(0, 0); err != nil { return err } decoder := prov(seeker) return decoder.DecodeConfig(n) }