// SPDX-FileCopyrightText: 2020 Ethel Morgan // // SPDX-License-Identifier: MIT package config import ( "encoding/json" "errors" "io/ioutil" "net/url" ) type ( Action struct { Name string Triggers []Trigger Outputs []Output } Trigger struct { URL *url.URL FormValues url.Values } OutputKind int Output struct { Kind OutputKind Name string URL *url.URL FormValues url.Values MQTT *url.URL Value string } Config struct { Actions map[string]Action } config struct { Actions map[string]struct { Triggers []struct { URL uurl `json:"url"` FormValues map[string]string `json:"formValues"` } `json:"triggers"` Outputs []struct { URL uurl `json:"url"` FormValues map[string]string `json:"formValues"` MQTT uurl `json:"mqtt"` Value string `json:"value"` } `json:"outputs"` } `json:"actions"` } uurl struct { *url.URL } ) const ( HTTPOutput OutputKind = iota MQTTOutput ) func ParseFile(path string) (*Config, error) { bytes, err := ioutil.ReadFile(path) if err != nil { return nil, err } raw := config{} if err := json.Unmarshal(bytes, &raw); err != nil { return nil, err } return configFromConfig(raw) } func configFromConfig(raw config) (*Config, error) { c := &Config{ Actions: map[string]Action{}, } for k, v := range raw.Actions { action := Action{ Name: k, } for _, rawTrigger := range v.Triggers { trigger := Trigger{ URL: rawTrigger.URL.URL, FormValues: urlValuesFromRawValues(rawTrigger.FormValues), } action.Triggers = append(action.Triggers, trigger) } for _, rawOutput := range v.Outputs { output := Output{ URL: rawOutput.URL.URL, FormValues: urlValuesFromRawValues(rawOutput.FormValues), MQTT: rawOutput.MQTT.URL, Value: rawOutput.Value, } switch { case output.URL != nil && output.MQTT == nil: output.Kind = HTTPOutput case output.URL == nil && output.MQTT != nil: output.Kind = MQTTOutput default: return nil, errors.New("outputs must be URL xor MQTT") } action.Outputs = append(action.Outputs, output) } c.Actions[k] = action } return c, nil } func (u uurl) MarshalText() ([]byte, error) { return []byte(u.String()), nil } func (u *uurl) UnmarshalText(raw []byte) error { uu, err := url.Parse(string(raw)) if err != nil { return err } u.URL = uu return nil } func urlValuesFromRawValues(raw map[string]string) url.Values { urlValues := map[string][]string{} for k, v := range raw { urlValues[k] = []string{v} } return urlValues }