2020-06-18 14:11:04 -04:00
|
|
|
package d2script
|
|
|
|
|
|
|
|
import (
|
2020-07-11 11:24:04 -04:00
|
|
|
"errors"
|
2020-06-18 14:11:04 -04:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2020-06-30 17:04:41 -04:00
|
|
|
"path/filepath"
|
2020-06-18 14:11:04 -04:00
|
|
|
|
|
|
|
"github.com/robertkrimen/otto"
|
|
|
|
_ "github.com/robertkrimen/otto/underscore" // This causes the runtime to support underscore.js
|
|
|
|
)
|
|
|
|
|
2020-06-30 17:04:41 -04:00
|
|
|
// ScriptEngine allows running JavaScript scripts
|
2020-06-18 14:11:04 -04:00
|
|
|
type ScriptEngine struct {
|
2020-07-11 11:24:04 -04:00
|
|
|
vm *otto.Otto
|
|
|
|
isEvalAllowed bool
|
2020-06-18 14:11:04 -04:00
|
|
|
}
|
|
|
|
|
2020-06-30 17:04:41 -04:00
|
|
|
// CreateScriptEngine creates the script engine and returns a pointer to it.
|
2020-06-18 14:11:04 -04:00
|
|
|
func CreateScriptEngine() *ScriptEngine {
|
2020-07-11 11:24:04 -04:00
|
|
|
vm := otto.New()
|
|
|
|
err := vm.Set("debugPrint", func(call otto.FunctionCall) otto.Value {
|
2020-06-18 14:11:04 -04:00
|
|
|
fmt.Printf("Script: %s\n", call.Argument(0).String())
|
|
|
|
return otto.Value{}
|
|
|
|
})
|
2020-07-23 12:56:50 -04:00
|
|
|
|
2020-06-30 17:04:41 -04:00
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("could not bind the 'debugPrint' to the given function in script engine")
|
|
|
|
}
|
2020-07-23 12:56:50 -04:00
|
|
|
|
2020-07-11 11:24:04 -04:00
|
|
|
return &ScriptEngine{
|
|
|
|
vm: vm,
|
|
|
|
isEvalAllowed: false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllowEval allows the evaluation of JS code.
|
|
|
|
func (s *ScriptEngine) AllowEval() {
|
|
|
|
s.isEvalAllowed = true
|
|
|
|
}
|
2020-06-18 14:11:04 -04:00
|
|
|
|
2020-07-23 12:56:50 -04:00
|
|
|
// DisallowEval disallows the evaluation of JS code.
|
2020-07-11 11:24:04 -04:00
|
|
|
func (s *ScriptEngine) DisallowEval() {
|
|
|
|
s.isEvalAllowed = false
|
2020-06-18 14:11:04 -04:00
|
|
|
}
|
|
|
|
|
2020-06-30 17:04:41 -04:00
|
|
|
// ToValue converts the given interface{} value to a otto.Value
|
2020-06-18 14:11:04 -04:00
|
|
|
func (s *ScriptEngine) ToValue(source interface{}) (otto.Value, error) {
|
|
|
|
return s.vm.ToValue(source)
|
|
|
|
}
|
|
|
|
|
2020-06-30 17:04:41 -04:00
|
|
|
// AddFunction adds the given function to the script engine with the given name.
|
2020-06-18 14:11:04 -04:00
|
|
|
func (s *ScriptEngine) AddFunction(name string, value interface{}) {
|
2020-06-30 17:04:41 -04:00
|
|
|
err := s.vm.Set(name, value)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("could not add the '%s' function to the script engine", name)
|
|
|
|
}
|
2020-06-18 14:11:04 -04:00
|
|
|
}
|
|
|
|
|
2020-06-30 17:04:41 -04:00
|
|
|
// RunScript runs the script file within the given path.
|
2020-06-18 14:11:04 -04:00
|
|
|
func (s *ScriptEngine) RunScript(fileName string) (*otto.Value, error) {
|
2020-06-30 17:04:41 -04:00
|
|
|
fileData, err := ioutil.ReadFile(filepath.Clean(fileName))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("could not read script file: %s\n", err.Error())
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-06-18 14:11:04 -04:00
|
|
|
val, err := s.vm.Run(string(fileData))
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("Error running script: %s\n", err.Error())
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-06-30 17:04:41 -04:00
|
|
|
|
2020-06-18 14:11:04 -04:00
|
|
|
return &val, nil
|
|
|
|
}
|
2020-07-11 11:24:04 -04:00
|
|
|
|
|
|
|
// Eval JS code.
|
|
|
|
func (s *ScriptEngine) Eval(code string) (string, error) {
|
|
|
|
if !s.isEvalAllowed {
|
|
|
|
return "", errors.New("disabled")
|
|
|
|
}
|
|
|
|
|
|
|
|
val, err := s.vm.Eval(code)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2020-07-23 12:56:50 -04:00
|
|
|
|
2020-07-11 11:24:04 -04:00
|
|
|
return val.String(), nil
|
|
|
|
}
|