You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
3.4 KiB
190 lines
3.4 KiB
package jsruntime
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"fmt"
|
|
"github.com/dop251/goja"
|
|
"github.com/go-errors/errors"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/url"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type JsRuntime struct {
|
|
MainSrc string
|
|
UseFileName string
|
|
UseSrc string
|
|
ExtFileDir string
|
|
Relys Relys
|
|
TimeoutSec int64
|
|
runtime *goja.Runtime
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
type Rely struct {
|
|
Src string
|
|
}
|
|
|
|
type Relys []Rely
|
|
|
|
type RunMode int
|
|
|
|
const (
|
|
ModeSync RunMode = 1
|
|
//ModeAsync RunMode = 2
|
|
)
|
|
|
|
func NewJsRuntime(mainScript string, useFileName string, extFileDir string, rels Relys, mode RunMode) (jr *JsRuntime, err error) {
|
|
|
|
jr = &JsRuntime{
|
|
MainSrc: mainScript,
|
|
Relys: rels,
|
|
UseFileName: useFileName,
|
|
ExtFileDir: extFileDir,
|
|
TimeoutSec: 30,
|
|
}
|
|
|
|
jr.runtime = goja.New()
|
|
|
|
jr.EnableTimeoutFunc()
|
|
|
|
jr.EnableIntervalFun()
|
|
|
|
jr.EnableRequestFunc()
|
|
|
|
jr.EnableConsoleFun()
|
|
|
|
jr.SetVariable("GoRunCodeByFile", func(filePath string) {
|
|
code, err := ioutil.ReadFile(filepath.Join(jr.ExtFileDir, filePath))
|
|
if err != nil {
|
|
log.Println("GoRunCodeByFile Read Error:", err)
|
|
}
|
|
err = jr.RunCode(string(code))
|
|
if err != nil {
|
|
log.Println("GoRunCodeByFile Run Error:", err)
|
|
}
|
|
})
|
|
err = jr.InitJsCode()
|
|
if err != nil {
|
|
log.Println("InitJsCode", err)
|
|
}
|
|
|
|
return jr, nil
|
|
}
|
|
|
|
func (jr *JsRuntime) InitJsCode() error {
|
|
|
|
for e := range jr.Relys {
|
|
//start := time.Now().UnixNano()
|
|
err := jr.RunCode(jr.Relys[e].Src)
|
|
//end := time.Now().UnixNano()
|
|
|
|
//log.Println(e, "加载时间:", end-start)
|
|
if err != nil {
|
|
log.Println("initjscode", err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
useSrc, _ := ioutil.ReadFile(jr.UseFileName)
|
|
jr.UseSrc = string(useSrc)
|
|
go func() {
|
|
for {
|
|
useSrc, _ := ioutil.ReadFile(jr.UseFileName)
|
|
jr.UseSrc = string(useSrc)
|
|
time.Sleep(time.Second * 2)
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (jr *JsRuntime) SetVariable(name string, value interface{}) {
|
|
jr.runtime.Set(name, value)
|
|
}
|
|
|
|
var codeMap sync.Map
|
|
|
|
func (jr *JsRuntime) md5(data string) string {
|
|
return fmt.Sprintf("%x", md5.Sum([]byte(data)))
|
|
}
|
|
|
|
func (jr *JsRuntime) RunCode(code string) error {
|
|
id := jr.md5(code)
|
|
var p interface{}
|
|
var ok bool
|
|
p, ok = codeMap.Load(id)
|
|
if !ok {
|
|
pro, err := goja.Compile("", code, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
codeMap.Store(id, pro)
|
|
p = pro
|
|
}
|
|
program := p.(*goja.Program)
|
|
|
|
_, err := jr.runtime.RunProgram(program)
|
|
return err
|
|
}
|
|
|
|
func (jr *JsRuntime) Render(filePath, href, tplSrc string, cb func(data string)) (err error) {
|
|
jr.mutex.Lock()
|
|
defer jr.mutex.Unlock()
|
|
|
|
runtime := jr.runtime
|
|
timeoutSec := jr.TimeoutSec
|
|
useSrc := jr.UseSrc
|
|
mainSrc := jr.MainSrc
|
|
isLock := true
|
|
go func() {
|
|
time.Sleep(time.Duration(timeoutSec) * time.Second)
|
|
if isLock {
|
|
log.Println("timeout")
|
|
runtime.Interrupt("timeout")
|
|
runtime.ClearInterrupt()
|
|
}
|
|
}()
|
|
defer func() {
|
|
isLock = false
|
|
}()
|
|
|
|
if useSrc != "" {
|
|
err = jr.RunCode(useSrc)
|
|
if err != nil {
|
|
return errors.New(err.Error() + "1")
|
|
}
|
|
}
|
|
|
|
url, err := url.Parse(href)
|
|
if err != nil {
|
|
return errors.New(err.Error() + "2")
|
|
}
|
|
|
|
url2, err := url.Parse(strings.Replace(filePath, `\`, "/", -1))
|
|
if err != nil {
|
|
return errors.New(err.Error() + "3")
|
|
}
|
|
|
|
runtime.Set("GoHtmlSrc", tplSrc)
|
|
|
|
runtime.Set("GoHref", href)
|
|
|
|
runtime.Set("GoQuery", url.Query().Encode())
|
|
|
|
runtime.Set("GoPath", url2.Path)
|
|
|
|
runtime.Set("GoReturn", func(data string) {
|
|
cb(data)
|
|
})
|
|
err = jr.RunCode(mainSrc)
|
|
if err != nil {
|
|
return errors.New(err.Error() + "4")
|
|
}
|
|
|
|
return
|
|
}
|