-
Notifications
You must be signed in to change notification settings - Fork 0
/
vm.go
127 lines (106 loc) · 2.47 KB
/
vm.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package js
import (
"sync"
"time"
"github.com/sohaha/zlsgo/zstring"
"github.com/sohaha/zlsgo/ztype"
"github.com/dop251/goja"
"github.com/dop251/goja/parser"
"github.com/dop251/goja_nodejs/require"
"github.com/sohaha/zlsgo/zcache"
"github.com/sohaha/zlsgo/zfile"
"github.com/sohaha/zlsgo/zlog"
)
type Option struct {
Args map[string]interface{}
Modules map[string]require.ModuleLoader
CustomVm func() *goja.Runtime
CompilerOptions ztype.Map
Dir string
Inject []byte
Timeout time.Duration
MaxPrograms uint
DisabledConsole bool
ParserSourceMaps bool
}
var log = zlog.New("[JS]")
func init() {
log.ResetFlags(zlog.BitLevel | zlog.BitTime)
}
func New(opt ...func(*Option)) *VM {
o := Option{
Dir: zfile.RealPath("."),
Timeout: time.Minute * 1,
MaxPrograms: 1 << 10,
}
for _, f := range opt {
f(&o)
}
for name := range o.Modules {
require.RegisterNativeModule(name, o.Modules[name])
}
timer := time.NewTimer(o.Timeout)
timer.Stop()
vm := &VM{
timer: timer,
option: o,
Programs: zcache.NewFast(func(co *zcache.Options) {
m := o.MaxPrograms / 10
if m > 1 {
co.Bucket = uint16(m)
co.Cap = 10
co.LRU2Cap = co.Bucket / 2
}
}),
runtime: sync.Pool{
New: func() interface{} {
var opts []require.Option
if o.Dir != "" {
opts = append(opts, require.WithLoader(sourceLoader(o.Dir)))
}
var vm *goja.Runtime
if o.CustomVm != nil {
vm = o.CustomVm()
} else {
vm = goja.New()
}
var parserOpts []parser.Option
if !o.ParserSourceMaps {
parserOpts = append(parserOpts, parser.WithDisableSourceMaps)
}
if len(parserOpts) > 0 {
vm.SetParserOptions(parserOpts...)
}
r := require.NewRegistry(opts...)
r.Enable(vm)
self := vm.GlobalObject()
vm.Set("self", self)
vm.Set("atob", func(code string) string {
raw, err := zstring.Base64DecodeString(code)
if err != nil {
panic(err)
}
return raw
})
vm.Set("btoa", func(code string) string {
return zstring.Base64EncodeString(code)
})
if !o.DisabledConsole {
clog := vm.NewObject()
clog.Set("log", log.Tips)
clog.Set("warn", log.Warn)
clog.Set("error", log.Error)
vm.Set("console", clog)
}
for k, v := range o.Args {
vm.Set(k, v)
}
if o.Inject != nil {
_, _ = vm.RunString(zstring.Bytes2String(o.Inject))
}
return vm
},
},
}
return vm
}