From e0f6cc555343a7a3d1c6acd847c2be4163daea49 Mon Sep 17 00:00:00 2001 From: Peter Grlica Date: Wed, 11 Aug 2021 17:20:39 +0200 Subject: [PATCH] Added jsenv support to workflows --- automation/automation/jsenv_handler.gen.go | 175 +++++++++++++++++++++ automation/automation/jsenv_handler.go | 73 +++++++++ automation/automation/jsenv_handler.yaml | 25 +++ automation/service/registry.go | 5 +- automation/service/service.go | 1 + 5 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 automation/automation/jsenv_handler.gen.go create mode 100644 automation/automation/jsenv_handler.go create mode 100644 automation/automation/jsenv_handler.yaml diff --git a/automation/automation/jsenv_handler.gen.go b/automation/automation/jsenv_handler.gen.go new file mode 100644 index 000000000..d3ce621f6 --- /dev/null +++ b/automation/automation/jsenv_handler.gen.go @@ -0,0 +1,175 @@ +package automation + +// This file is auto-generated. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// Definitions file that controls how this file is generated: +// automation/automation/jsenv_handler.yaml + +import ( + "context" + atypes "github.com/cortezaproject/corteza-server/automation/types" + "github.com/cortezaproject/corteza-server/pkg/expr" + "github.com/cortezaproject/corteza-server/pkg/wfexec" + "io" +) + +var _ wfexec.ExecResponse + +type ( + jsenvHandlerRegistry interface { + AddFunctions(ff ...*atypes.Function) + Type(ref string) expr.Type + } +) + +func (h jsenvHandler) register() { + h.reg.AddFunctions( + h.Execute(), + ) +} + +type ( + jsenvExecuteArgs struct { + hasScope bool + Scope interface{} + scopeAny interface{} + scopeString string + scopeStream io.Reader + + hasSource bool + Source string + } + + jsenvExecuteResults struct { + ResultString string + ResultInt int64 + ResultAny interface{} + } +) + +func (a jsenvExecuteArgs) GetScope() (bool, interface{}, string, io.Reader) { + return a.hasScope, a.scopeAny, a.scopeString, a.scopeStream +} + +// Execute function Process arbitrary data in jsenv +// +// expects implementation of execute function: +// func (h jsenvHandler) execute(ctx context.Context, args *jsenvExecuteArgs) (results *jsenvExecuteResults, err error) { +// return +// } +func (h jsenvHandler) Execute() *atypes.Function { + return &atypes.Function{ + Ref: "jsenvExecute", + Kind: "function", + Labels: map[string]string(nil), + Meta: &atypes.FunctionMeta{ + Short: "Process arbitrary data in jsenv", + }, + + Parameters: []*atypes.Param{ + { + Name: "scope", + Types: []string{"Any", "String", "Reader"}, Required: true, + }, + { + Name: "source", + Types: []string{"String"}, Required: true, + }, + }, + + Results: []*atypes.Param{ + + { + Name: "resultString", + Types: []string{"String"}, + }, + + { + Name: "resultInt", + Types: []string{"Integer"}, + }, + + { + Name: "resultAny", + Types: []string{"Any"}, + }, + }, + + Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) { + var ( + args = &jsenvExecuteArgs{ + hasScope: in.Has("scope"), + hasSource: in.Has("source"), + } + ) + + if err = in.Decode(args); err != nil { + return + } + + // Converting Scope argument + if args.hasScope { + aux := expr.Must(expr.Select(in, "scope")) + switch aux.Type() { + case h.reg.Type("Any").Type(): + args.scopeAny = aux.Get().(interface{}) + case h.reg.Type("String").Type(): + args.scopeString = aux.Get().(string) + case h.reg.Type("Reader").Type(): + args.scopeStream = aux.Get().(io.Reader) + } + } + + var results *jsenvExecuteResults + if results, err = h.execute(ctx, args); err != nil { + return + } + + out = &expr.Vars{} + + { + // converting results.ResultString (string) to String + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("String").Cast(results.ResultString); err != nil { + return + } else if err = expr.Assign(out, "resultString", tval); err != nil { + return + } + } + + { + // converting results.ResultInt (int64) to Integer + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("Integer").Cast(results.ResultInt); err != nil { + return + } else if err = expr.Assign(out, "resultInt", tval); err != nil { + return + } + } + + { + // converting results.ResultAny (interface{}) to Any + var ( + tval expr.TypedValue + ) + + if tval, err = h.reg.Type("Any").Cast(results.ResultAny); err != nil { + return + } else if err = expr.Assign(out, "resultAny", tval); err != nil { + return + } + } + + return + }, + } +} diff --git a/automation/automation/jsenv_handler.go b/automation/automation/jsenv_handler.go new file mode 100644 index 000000000..0e1feb8a2 --- /dev/null +++ b/automation/automation/jsenv_handler.go @@ -0,0 +1,73 @@ +package automation + +import ( + "context" + "fmt" + + "github.com/cortezaproject/corteza-server/pkg/jsenv" +) + +type ( + jsenvHandler struct { + reg queueHandlerRegistry + } +) + +func JsenvHandler(reg queueHandlerRegistry) *jsenvHandler { + h := &jsenvHandler{ + reg: reg, + } + + h.register() + return h +} + +func (h jsenvHandler) execute(ctx context.Context, args *jsenvExecuteArgs) (res *jsenvExecuteResults, err error) { + res = &jsenvExecuteResults{} + + if !args.hasSource { + err = fmt.Errorf("could not process payload, function missing") + return + } + + if !args.hasScope { + err = fmt.Errorf("could not process payload, scope missing") + return + } + + // call jsenv, feed it function and expect a result + tr := jsenv.NewTransformer(jsenv.LoaderJS, jsenv.TargetNoop) + vm := jsenv.New(tr) + + fn, err := vm.RegisterFunction(args.Source) + + if err != nil { + err = fmt.Errorf("could not register jsenv function: %s", err) + return + } + + out, err := fn.Exec(vm.New(args.scopeString)) + + if err != nil { + err = fmt.Errorf("could not exec jsenv function: %s", err) + return + } + + switch vv := out.(type) { + + // this one should go out once the ResultAny + // is mainly used + case uint64, int64: + res.ResultInt = int64(vv.(uint64)) + + // this one should go out once the ResultAny + // is mainly used + case string: + res.ResultString = string(vv) + + default: + res.ResultAny = vv + } + + return +} diff --git a/automation/automation/jsenv_handler.yaml b/automation/automation/jsenv_handler.yaml new file mode 100644 index 000000000..1c622a50b --- /dev/null +++ b/automation/automation/jsenv_handler.yaml @@ -0,0 +1,25 @@ +imports: + - io + +functions: + execute: + meta: + short: Process arbitrary data in jsenv + params: + scope: + required: true + types: + - { wf: Any } + - { wf: String, suffix: String } + - { wf: Reader, suffix: Stream } + source: + required: true + types: + - { wf: String } + results: + resultString: + wf: String + resultInt: + wf: Integer + resultAny: + wf: Any diff --git a/automation/service/registry.go b/automation/service/registry.go index 922be0fd3..938ad88e0 100644 --- a/automation/service/registry.go +++ b/automation/service/registry.go @@ -1,10 +1,11 @@ package service import ( - "github.com/cortezaproject/corteza-server/automation/types" - "github.com/cortezaproject/corteza-server/pkg/expr" "sort" "sync" + + "github.com/cortezaproject/corteza-server/automation/types" + "github.com/cortezaproject/corteza-server/pkg/expr" ) type ( diff --git a/automation/service/service.go b/automation/service/service.go index be6a1f957..f60a41569 100644 --- a/automation/service/service.go +++ b/automation/service/service.go @@ -120,6 +120,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, ws websock automation.HttpRequestHandler(Registry()) automation.LogHandler(Registry()) automation.QueueHandler(Registry()) + automation.JsenvHandler(Registry()) automation.LoopHandler(Registry(), DefaultWorkflow.parser) automation.CorredorHandler(Registry(), corredor.Service()) automation.EmailHandler(Registry())