Plugins: allow chaining of input/output plugins (#7836)
This commit is contained in:
parent
370b15aaca
commit
cba97832db
16 changed files with 582 additions and 199 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/provider/javascript"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/robertkrimen/otto"
|
||||
|
|
@ -10,17 +12,21 @@ import (
|
|||
type Javascript struct {
|
||||
vm *otto.Otto
|
||||
script string
|
||||
in []inputTransformation
|
||||
out []outputTransformation
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Add("js", NewJavascriptProviderFromConfig)
|
||||
}
|
||||
|
||||
// NewJavascriptProviderFromConfig creates a HTTP provider
|
||||
func NewJavascriptProviderFromConfig(other map[string]interface{}) (IntProvider, error) {
|
||||
// NewJavascriptProviderFromConfig creates a Javascript provider
|
||||
func NewJavascriptProviderFromConfig(other map[string]interface{}) (Provider, error) {
|
||||
var cc struct {
|
||||
VM string
|
||||
Script string
|
||||
In []transformationConfig
|
||||
Out []transformationConfig
|
||||
}
|
||||
|
||||
if err := util.DecodeOther(other, &cc); err != nil {
|
||||
|
|
@ -32,9 +38,21 @@ func NewJavascriptProviderFromConfig(other map[string]interface{}) (IntProvider,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
in, err := configureInputs(cc.In)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out, err := configureOutputs(cc.Out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := &Javascript{
|
||||
vm: vm,
|
||||
script: cc.Script,
|
||||
in: in,
|
||||
out: out,
|
||||
}
|
||||
|
||||
return p, nil
|
||||
|
|
@ -42,92 +60,140 @@ func NewJavascriptProviderFromConfig(other map[string]interface{}) (IntProvider,
|
|||
|
||||
// FloatGetter parses float from request
|
||||
func (p *Javascript) FloatGetter() func() (float64, error) {
|
||||
return func() (res float64, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToFloat()
|
||||
return func() (float64, error) {
|
||||
v, err := p.handleGetter()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return res, err
|
||||
vv, ok := v.(float64)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("not a float: %s", v)
|
||||
}
|
||||
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// IntGetter parses int64 from request
|
||||
func (p *Javascript) IntGetter() func() (int64, error) {
|
||||
return func() (res int64, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToInteger()
|
||||
return func() (int64, error) {
|
||||
v, err := p.handleGetter()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return res, err
|
||||
vv, ok := v.(int64)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("not a int: %s", v)
|
||||
}
|
||||
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringGetter sends string request
|
||||
// StringGetter parses string from request
|
||||
func (p *Javascript) StringGetter() func() (string, error) {
|
||||
return func() (res string, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToString()
|
||||
return func() (string, error) {
|
||||
v, err := p.handleGetter()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res, err
|
||||
vv, ok := v.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("not a string: %s", v)
|
||||
}
|
||||
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// BoolGetter parses bool from request
|
||||
func (p *Javascript) BoolGetter() func() (bool, error) {
|
||||
return func() (res bool, err error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err == nil {
|
||||
res, err = v.ToBoolean()
|
||||
return func() (bool, error) {
|
||||
v, err := p.handleGetter()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return res, err
|
||||
vv, ok := v.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("not a bool: %s", v)
|
||||
}
|
||||
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Javascript) setParam(param string, val interface{}) error {
|
||||
err := p.vm.Set(param, val)
|
||||
if err == nil {
|
||||
err = p.vm.Set("param", param)
|
||||
func (p *Javascript) handleGetter() (any, error) {
|
||||
if err := transformInputs(p.in, p.setParam); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err == nil {
|
||||
err = p.vm.Set("val", val)
|
||||
|
||||
v, err := p.evaluate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return err
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (p *Javascript) handleSetter(param string, val any) error {
|
||||
if err := p.setParam(param, val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := p.evaluate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return transformOutputs(p.out, v)
|
||||
}
|
||||
|
||||
func (p *Javascript) evaluate() (any, error) {
|
||||
v, err := p.vm.Eval(p.script)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vv, err := v.Export()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return normalizeValue(vv)
|
||||
}
|
||||
|
||||
func (p *Javascript) setParam(param string, val any) error {
|
||||
return p.vm.Set(param, val)
|
||||
}
|
||||
|
||||
// IntSetter sends int request
|
||||
func (p *Javascript) IntSetter(param string) func(int64) error {
|
||||
return func(val int64) error {
|
||||
err := p.setParam(param, val)
|
||||
if err == nil {
|
||||
_, err = p.vm.Eval(p.script)
|
||||
}
|
||||
return err
|
||||
return p.handleSetter(param, val)
|
||||
}
|
||||
}
|
||||
|
||||
// FloatSetter sends float request
|
||||
func (p *Javascript) FloatSetter(param string) func(float64) error {
|
||||
return func(val float64) error {
|
||||
return p.handleSetter(param, val)
|
||||
}
|
||||
}
|
||||
|
||||
// StringSetter sends string request
|
||||
func (p *Javascript) StringSetter(param string) func(string) error {
|
||||
return func(val string) error {
|
||||
err := p.setParam(param, val)
|
||||
if err == nil {
|
||||
_, err = p.vm.Eval(p.script)
|
||||
}
|
||||
return err
|
||||
return p.handleSetter(param, val)
|
||||
}
|
||||
}
|
||||
|
||||
// BoolSetter sends bool request
|
||||
func (p *Javascript) BoolSetter(param string) func(bool) error {
|
||||
return func(val bool) error {
|
||||
err := p.setParam(param, val)
|
||||
if err == nil {
|
||||
_, err = p.vm.Eval(p.script)
|
||||
}
|
||||
return err
|
||||
return p.handleSetter(param, val)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue