OpenDiablo2/d2script/engine.go

90 lines
2.1 KiB
Go
Raw Normal View History

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