package hosts import ( "github.com/miekg/dns" "time" ) type HostMap map[string][]Host type Host struct { Type uint16 `json:"type"` TTL time.Duration `json:"ttl"` Values []string `json:"values"` } func (h *Host) TypeString() string { return dns.TypeToString[h.Type] } type ProviderList struct { providers []Provider } // Provider is an interface specifying a host source // Each source should support AT LEAST List and Get, but can support Writer as well type Provider interface { List() (HostMap, error) Get(queryType uint16, domain string) (*Host, error) } // Writer is an interface to modify hosts. // Examples of this include Redis, Bolt, MySQL, etc. type Writer interface { Set(domain string, host *Host) error Delete(domain string) error } type ProviderWriter interface { Provider Writer } func NewHosts(providers []Provider) *ProviderList { return &ProviderList{providers} } // List returns all results, merged into one HostMap func (h *ProviderList) List() (HostMap, error) { hostMap := make(HostMap) for _, provider := range h.providers { hosts, err := provider.List() if err != nil { continue } for k, v := range hosts { if existing, ok := hostMap[k]; ok { existing = append(existing, v...) hostMap[k] = existing } else { hostMap[k] = v } } } return hostMap, nil } // Get Matches values to providers, loping each in order func (h *ProviderList) Get(queryType uint16, domain string) (*Host, error) { var host *Host var err error for _, provider := range h.providers { host, err = provider.Get(queryType, domain) if host != nil { break } } return host, err } // Set invokes each provider, setting the host on the first one to return a nil error func (h *ProviderList) Set(domain string, host *Host) (err error) { for _, provider := range h.providers { if writer, ok := provider.(Writer); ok { err = writer.Set(domain, host) if err == nil { return } } } err = errUnsupportedOperation return } // Delete invokes each provider, removing the host on the first one to return a nil error func (h *ProviderList) Delete(domain string) (err error) { for _, provider := range h.providers { if writer, ok := provider.(Writer); ok { err = writer.Delete(domain) if err == nil { return } } } err = errUnsupportedOperation return }