Move optional provider params to separate option functions
This commit is contained in:
parent
e019112489
commit
b47914d80f
4 changed files with 115 additions and 86 deletions
|
|
@ -67,9 +67,9 @@ func NewDiscovergyFromConfig(other map[string]interface{}) (api.Meter, error) {
|
|||
}
|
||||
|
||||
uri := fmt.Sprintf("%s/last_reading?meterId=%s", discovergyAPI, meterID)
|
||||
power, err := provider.NewHTTP(log, http.MethodGet, uri, nil, "", false, "", ".values.power", 0.001*cc.Scale, 0)
|
||||
power, err := provider.NewHTTP(log, http.MethodGet, uri, false, 0.001*cc.Scale, 0).WithAuth("basic", cc.User, cc.Password)
|
||||
if err == nil {
|
||||
_, err = power.WithAuth("basic", cc.User, cc.Password)
|
||||
_, err = power.WithJq(".values.power")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -64,46 +64,45 @@ func NewHTTPProviderFromConfig(other map[string]interface{}) (IntProvider, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
log := util.NewLogger("http")
|
||||
|
||||
http, err := NewHTTP(log,
|
||||
http := NewHTTP(
|
||||
util.NewLogger("http"),
|
||||
cc.Method,
|
||||
cc.URI,
|
||||
cc.Headers,
|
||||
cc.Body,
|
||||
cc.Insecure,
|
||||
cc.Regex,
|
||||
cc.Jq,
|
||||
cc.Scale,
|
||||
cc.Cache,
|
||||
)
|
||||
).WithHeaders(cc.Headers).WithBody(cc.Body)
|
||||
http.Client.Timeout = cc.Timeout
|
||||
|
||||
var err error
|
||||
if err == nil && cc.Regex != "" {
|
||||
_, err = http.WithRegex(cc.Regex)
|
||||
}
|
||||
|
||||
if err == nil && cc.Jq != "" {
|
||||
_, err = http.WithJq(cc.Jq)
|
||||
}
|
||||
|
||||
if err == nil && cc.Auth.Type != "" {
|
||||
_, err = http.WithAuth(cc.Auth.Type, cc.Auth.User, cc.Auth.Password)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
http.Client.Timeout = cc.Timeout
|
||||
}
|
||||
|
||||
return http, err
|
||||
}
|
||||
|
||||
// NewHTTP create HTTP provider
|
||||
func NewHTTP(log *util.Logger, method, uri string, headers map[string]string, body string, insecure bool, regex, jq string, scale float64, cache time.Duration) (*HTTP, error) {
|
||||
func NewHTTP(log *util.Logger, method, uri string, insecure bool, scale float64, cache time.Duration) *HTTP {
|
||||
url := util.DefaultScheme(uri, "http")
|
||||
if url != uri {
|
||||
log.WARN.Printf("missing scheme for %s, assuming http", uri)
|
||||
}
|
||||
|
||||
p := &HTTP{
|
||||
Helper: request.NewHelper(log),
|
||||
url: url,
|
||||
method: method,
|
||||
headers: headers,
|
||||
body: body,
|
||||
scale: scale,
|
||||
cache: cache,
|
||||
Helper: request.NewHelper(log),
|
||||
url: url,
|
||||
method: method,
|
||||
scale: scale,
|
||||
cache: cache,
|
||||
}
|
||||
|
||||
// ignore the self signed certificate
|
||||
|
|
@ -111,24 +110,42 @@ func NewHTTP(log *util.Logger, method, uri string, headers map[string]string, bo
|
|||
p.Client.Transport = request.NewTripper(log, request.InsecureTransport())
|
||||
}
|
||||
|
||||
if regex != "" {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regex '%s': %w", re, err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
p.re = re
|
||||
// WithBody adds request body
|
||||
func (p *HTTP) WithBody(body string) *HTTP {
|
||||
p.body = body
|
||||
return p
|
||||
}
|
||||
|
||||
// WithHeaders adds request headers
|
||||
func (p *HTTP) WithHeaders(headers map[string]string) *HTTP {
|
||||
p.headers = headers
|
||||
return p
|
||||
}
|
||||
|
||||
// WithRegex adds a regex query applied to the mqtt listener payload
|
||||
func (p *HTTP) WithRegex(regex string) (*HTTP, error) {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regex '%s': %w", re, err)
|
||||
}
|
||||
|
||||
if jq != "" {
|
||||
op, err := gojq.Parse(jq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid jq query '%s': %w", jq, err)
|
||||
}
|
||||
p.re = re
|
||||
|
||||
p.jq = op
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// WithJq adds a jq query applied to the mqtt listener payload
|
||||
func (p *HTTP) WithJq(jq string) (*HTTP, error) {
|
||||
op, err := gojq.Parse(jq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid jq query '%s': %w", jq, err)
|
||||
}
|
||||
|
||||
p.jq = op
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,16 +53,14 @@ func NewMqttFromConfig(other map[string]interface{}) (IntProvider, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
m := NewMqtt(log, client, cc.Topic, cc.Scale, cc.Timeout)
|
||||
m := NewMqtt(log, client, cc.Topic, cc.Scale, cc.Timeout).WithPayload(cc.Payload)
|
||||
|
||||
if cc.Payload != "" {
|
||||
m = m.WithPayload(cc.Payload)
|
||||
}
|
||||
if cc.Regex != "" {
|
||||
if m, err = m.WithRegex(cc.Regex); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if cc.Jq != "" {
|
||||
if m, err = m.WithJq(cc.Jq); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -54,12 +54,22 @@ func NewScriptProviderFromConfig(other map[string]interface{}) (IntProvider, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return NewScriptProvider(cc.Cmd, cc.Timeout, cc.Regex, cc.Jq, cc.Scale, cc.Cache)
|
||||
p, err := NewScriptProvider(cc.Cmd, cc.Timeout, cc.Scale, cc.Cache)
|
||||
|
||||
if err == nil && cc.Regex != "" {
|
||||
_, err = p.WithRegex(cc.Regex)
|
||||
}
|
||||
|
||||
if err == nil && cc.Jq != "" {
|
||||
_, err = p.WithJq(cc.Jq)
|
||||
}
|
||||
|
||||
return p, err
|
||||
}
|
||||
|
||||
// NewScriptProvider creates a script provider.
|
||||
// Script execution is aborted after given timeout.
|
||||
func NewScriptProvider(script string, timeout time.Duration, regex, jq string, scale float64, cache time.Duration) (*Script, error) {
|
||||
func NewScriptProvider(script string, timeout time.Duration, scale float64, cache time.Duration) (*Script, error) {
|
||||
s := &Script{
|
||||
log: util.NewLogger("script"),
|
||||
script: script,
|
||||
|
|
@ -68,34 +78,38 @@ func NewScriptProvider(script string, timeout time.Duration, regex, jq string, s
|
|||
cache: cache,
|
||||
}
|
||||
|
||||
if regex != "" {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regex '%s': %w", re, err)
|
||||
}
|
||||
|
||||
s.re = re
|
||||
}
|
||||
|
||||
if jq != "" {
|
||||
op, err := gojq.Parse(jq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid jq query '%s': %w", jq, err)
|
||||
}
|
||||
|
||||
s.jq = op
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (e *Script) exec(script string) (string, error) {
|
||||
func (p *Script) WithRegex(regex string) (*Script, error) {
|
||||
re, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regex '%s': %w", re, err)
|
||||
}
|
||||
|
||||
p.re = re
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *Script) WithJq(jq string) (*Script, error) {
|
||||
op, err := gojq.Parse(jq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid jq query '%s': %w", jq, err)
|
||||
}
|
||||
|
||||
p.jq = op
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *Script) exec(script string) (string, error) {
|
||||
args, err := shellquote.Split(script)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.timeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, args[0], args[1:]...)
|
||||
|
|
@ -110,44 +124,44 @@ func (e *Script) exec(script string) (string, error) {
|
|||
s = strings.TrimSpace(string(ee.Stderr))
|
||||
}
|
||||
|
||||
e.log.ERROR.Printf("%s: %s", strings.Join(args, " "), s)
|
||||
p.log.ERROR.Printf("%s: %s", strings.Join(args, " "), s)
|
||||
return "", err
|
||||
}
|
||||
|
||||
e.log.DEBUG.Printf("%s: %s", strings.Join(args, " "), s)
|
||||
p.log.DEBUG.Printf("%s: %s", strings.Join(args, " "), s)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// StringGetter returns string from exec result. Only STDOUT is considered.
|
||||
func (e *Script) StringGetter() func() (string, error) {
|
||||
func (p *Script) StringGetter() func() (string, error) {
|
||||
return func() (string, error) {
|
||||
if time.Since(e.updated) > e.cache {
|
||||
e.val, e.err = e.exec(e.script)
|
||||
e.updated = time.Now()
|
||||
if time.Since(p.updated) > p.cache {
|
||||
p.val, p.err = p.exec(p.script)
|
||||
p.updated = time.Now()
|
||||
|
||||
if e.err == nil && e.re != nil {
|
||||
m := e.re.FindStringSubmatch(e.val)
|
||||
if p.err == nil && p.re != nil {
|
||||
m := p.re.FindStringSubmatch(p.val)
|
||||
if len(m) > 1 {
|
||||
e.val = m[1] // first submatch
|
||||
p.val = m[1] // first submatch
|
||||
}
|
||||
}
|
||||
|
||||
if e.err == nil && e.jq != nil {
|
||||
if p.err == nil && p.jq != nil {
|
||||
var v interface{}
|
||||
if v, e.err = jq.Query(e.jq, []byte(e.val)); e.err == nil {
|
||||
e.val = fmt.Sprintf("%v", v)
|
||||
if v, p.err = jq.Query(p.jq, []byte(p.val)); p.err == nil {
|
||||
p.val = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return e.val, e.err
|
||||
return p.val, p.err
|
||||
}
|
||||
}
|
||||
|
||||
// FloatGetter parses float from exec result
|
||||
func (e *Script) FloatGetter() func() (float64, error) {
|
||||
g := e.StringGetter()
|
||||
func (p *Script) FloatGetter() func() (float64, error) {
|
||||
g := p.StringGetter()
|
||||
|
||||
return func() (float64, error) {
|
||||
s, err := g()
|
||||
|
|
@ -157,7 +171,7 @@ func (e *Script) FloatGetter() func() (float64, error) {
|
|||
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err == nil {
|
||||
f *= e.scale
|
||||
f *= p.scale
|
||||
}
|
||||
|
||||
return f, err
|
||||
|
|
@ -165,8 +179,8 @@ func (e *Script) FloatGetter() func() (float64, error) {
|
|||
}
|
||||
|
||||
// IntGetter parses int64 from exec result
|
||||
func (e *Script) IntGetter() func() (int64, error) {
|
||||
g := e.FloatGetter()
|
||||
func (p *Script) IntGetter() func() (int64, error) {
|
||||
g := p.FloatGetter()
|
||||
|
||||
return func() (int64, error) {
|
||||
f, err := g()
|
||||
|
|
@ -175,8 +189,8 @@ func (e *Script) IntGetter() func() (int64, error) {
|
|||
}
|
||||
|
||||
// BoolGetter parses bool from exec result. "on", "true" and 1 are considered truish.
|
||||
func (e *Script) BoolGetter() func() (bool, error) {
|
||||
g := e.StringGetter()
|
||||
func (p *Script) BoolGetter() func() (bool, error) {
|
||||
g := p.StringGetter()
|
||||
|
||||
return func() (bool, error) {
|
||||
s, err := g()
|
||||
|
|
@ -189,15 +203,15 @@ func (e *Script) BoolGetter() func() (bool, error) {
|
|||
}
|
||||
|
||||
// IntSetter invokes script with parameter replaced by int value
|
||||
func (e *Script) IntSetter(param string) func(int64) error {
|
||||
func (p *Script) IntSetter(param string) func(int64) error {
|
||||
// return func to access cached value
|
||||
return func(i int64) error {
|
||||
cmd, err := util.ReplaceFormatted(e.script, map[string]interface{}{
|
||||
cmd, err := util.ReplaceFormatted(p.script, map[string]interface{}{
|
||||
param: i,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
_, err = e.exec(cmd)
|
||||
_, err = p.exec(cmd)
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -205,15 +219,15 @@ func (e *Script) IntSetter(param string) func(int64) error {
|
|||
}
|
||||
|
||||
// BoolSetter invokes script with parameter replaced by bool value
|
||||
func (e *Script) BoolSetter(param string) func(bool) error {
|
||||
func (p *Script) BoolSetter(param string) func(bool) error {
|
||||
// return func to access cached value
|
||||
return func(b bool) error {
|
||||
cmd, err := util.ReplaceFormatted(e.script, map[string]interface{}{
|
||||
cmd, err := util.ReplaceFormatted(p.script, map[string]interface{}{
|
||||
param: b,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
_, err = e.exec(cmd)
|
||||
_, err = p.exec(cmd)
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue