-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgoja.go
81 lines (70 loc) · 1.5 KB
/
goja.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package scripts
import (
"bytes"
"sync"
"time"
"github.com/dop251/goja"
"github.com/dop251/goja_nodejs/require"
)
type Script struct {
prog *goja.Program
}
func NewScript(source ...[]byte) (Script, error) {
prog, err := goja.Compile("script", string(bytes.Join(source, []byte("\n"))), false)
return Script{prog: prog}, err
}
type Engine struct {
pool *sync.Pool
}
func NewEngine(opts ...EngineOption) *Engine {
options := &engineOptions{
moduleLoader: NewStaticModuleLoader(),
}
for _, opt := range opts {
opt(options)
}
registry := require.NewRegistryWithLoader(options.moduleLoader.SourceLoader())
return &Engine{
pool: &sync.Pool{
New: func() any {
vm := goja.New()
registry.Enable(vm)
return vm
},
}}
}
func (m *Engine) Execute(s Script, arg any, opts ...ExecOption) (any, error) {
options := &execOptions{
arg: arg,
scriptTimeout: 1 * time.Second,
}
for _, o := range opts {
o(options)
}
vm := m.pool.Get().(*goja.Runtime)
vm.ClearInterrupt()
options.set(vm)
timer := time.AfterFunc(options.scriptTimeout, func() {
vm.Interrupt("execution timeout")
})
defer func() {
timer.Stop()
vm.ClearInterrupt()
options.reset(vm)
m.pool.Put(vm)
}()
res, err := vm.RunProgram(s.prog)
if err != nil {
return nil, castErr(err)
}
return res.Export(), nil
}
func castErr(err error) error {
if exception, ok := err.(*goja.Exception); ok {
val := exception.Value().Export()
if castedErr, ok := val.(error); ok {
return castedErr
}
}
return err
}