zitadel/internal/actions/actions.go

113 lines
2.1 KiB
Go
Raw Normal View History

package actions
import (
"errors"
"time"
"github.com/dop251/goja"
"github.com/dop251/goja_nodejs/console"
"github.com/dop251/goja_nodejs/require"
"github.com/zitadel/logging"
)
var ErrHalt = errors.New("interrupt")
type jsAction func(*Context, *API) error
func Run(ctx *Context, api *API, script, name string, timeout time.Duration, allowedToFail bool) error {
if timeout <= 0 || timeout > 20 {
timeout = 20 * time.Second
}
prepareTimeout := timeout
if prepareTimeout > 5 {
prepareTimeout = 5 * time.Second
}
vm, err := prepareRun(script, prepareTimeout)
if err != nil {
return err
}
var fn jsAction
jsFn := vm.Get(name)
if jsFn == nil {
return errors.New("function not found")
}
err = vm.ExportTo(jsFn, &fn)
if err != nil {
return err
}
t := setInterrupt(vm, timeout)
defer func() {
t.Stop()
}()
errCh := make(chan error)
go func() {
defer func() {
r := recover()
if r != nil && !allowedToFail {
err, ok := r.(error)
if !ok {
e, ok := r.(string)
if ok {
err = errors.New(e)
}
}
errCh <- err
return
}
}()
err = fn(ctx, api)
if err != nil && !allowedToFail {
errCh <- err
return
}
errCh <- nil
}()
return <-errCh
}
func newRuntime() *goja.Runtime {
vm := goja.New()
printer := console.PrinterFunc(func(s string) {
logging.Log("ACTIONS-dfgg2").Debug(s)
})
registry := new(require.Registry)
registry.Enable(vm)
registry.RegisterNativeModule("console", console.RequireWithPrinter(printer))
console.Enable(vm)
return vm
}
func prepareRun(script string, timeout time.Duration) (*goja.Runtime, error) {
vm := newRuntime()
t := setInterrupt(vm, timeout)
defer func() {
t.Stop()
}()
errCh := make(chan error)
go func() {
defer func() {
r := recover()
if r != nil {
errCh <- r.(error)
return
}
}()
_, err := vm.RunString(script)
if err != nil {
errCh <- err
return
}
errCh <- nil
}()
return vm, <-errCh
}
func setInterrupt(vm *goja.Runtime, timeout time.Duration) *time.Timer {
vm.ClearInterrupt()
return time.AfterFunc(timeout, func() {
vm.Interrupt(ErrHalt)
})
}