otto是golang的js虚拟机,基本支持正常的js代码,但re2或者es6这些现代化特性暂不支持。由于是虚拟机,因此需要限制脚本运行最长时间,从官网了解到限制的方法:
package main
import (
"errors"
"fmt"
"os"
"time"
"github.com/robertkrimen/otto"
)
var halt = errors.New("Stahp")
func main() {
runUnsafe(`var abc = [];`)
runUnsafe(`
while (true) {
// Loop forever
}`)
}
func runUnsafe(unsafe string) {
start := time.Now()
defer func() {
duration := time.Since(start)
if caught := recover(); caught != nil {
if caught == halt {
fmt.Fprintf(os.Stderr, "Some code took to long! Stopping after: %v\n", duration)
return
}
panic(caught) // Something else happened, repanic!
}
fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration)
}()
vm := otto.New()
vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking
go func() {
time.Sleep(2 * time.Second) // Stop after two seconds
vm.Interrupt <- func() {
panic(halt)
}
}()
vm.Run(unsafe) // Here be dragons (risky code)
}
这种方法对应超时的脚本不会产生问题,然而,如果这个脚本正常跑完了,那么推入Interrupt里的 东西就不会被拉出来,从而导致goroutine一直不被释放。
因此这种写法还需要增加一个容错处理,我修改之后如下:
...
// 增加一个额外的状态,如果otto没有自动拉出来,那么就在正常结束时我来处理
state := make(chan int,1)
state<-0
go func() {
if <-state==0 {
state<-2
time.Sleep(2 * time.Second) // Stop after two seconds
vm.Interrupt <- func() {
panic(halt)
}
}
}()
vm.Run(unsafe) // Here be dragons (risky code)
// 超过时间也会执行到这里,如果没有超过时间,那么取出的是0,否则取出的是2
if <-state==0{state<-1}
close(state)
...
相关文档
暂无
随便看看
畅言模块加载中