mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
internal/jsre: move runtime creation back into JSRE and clean up API
This commit is contained in:
parent
e230602627
commit
fd422db34f
3 changed files with 47 additions and 59 deletions
|
|
@ -20,12 +20,10 @@ import (
|
|||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
)
|
||||
|
||||
func TestCompleteKeywords(t *testing.T) {
|
||||
re := New("", os.Stdout, goja.New())
|
||||
re := New("", os.Stdout)
|
||||
re.Run(`
|
||||
function theClass() {
|
||||
this.foo = 3;
|
||||
|
|
|
|||
|
|
@ -36,14 +36,13 @@ var (
|
|||
Web3Js = deps.MustAsset("web3.js")
|
||||
)
|
||||
|
||||
/*
|
||||
JSRE is a generic JS runtime environment embedding the goja JS interpreter.
|
||||
It provides some helper functions to
|
||||
- load code from files
|
||||
- run code snippets
|
||||
- require libraries
|
||||
- bind native go objects
|
||||
*/
|
||||
// JSRE is a JS runtime environment embedding the goja interpreter.
|
||||
// It provides helper functions to load code from files, run code snippets
|
||||
// and bind native go objects to JS.
|
||||
//
|
||||
// The runtime runs all code on a dedicated event loop and does not expose the underlying
|
||||
// goja runtime directly. To use the runtime, call JSRE.Do. When binding a Go function,
|
||||
// use the Call type to gain access to the runtime.
|
||||
type JSRE struct {
|
||||
assetPath string
|
||||
output io.Writer
|
||||
|
|
@ -53,6 +52,12 @@ type JSRE struct {
|
|||
vm *goja.Runtime
|
||||
}
|
||||
|
||||
// Call is the argument type of Go functions which are callable from JS.
|
||||
type Call struct {
|
||||
goja.FunctionCall
|
||||
VM *goja.Runtime
|
||||
}
|
||||
|
||||
// jsTimer is a single timer instance with a callback function
|
||||
type jsTimer struct {
|
||||
timer *time.Timer
|
||||
|
|
@ -68,17 +73,17 @@ type evalReq struct {
|
|||
}
|
||||
|
||||
// runtime must be stopped with Stop() after use and cannot be used after stopping
|
||||
func New(assetPath string, output io.Writer, vm *goja.Runtime) *JSRE {
|
||||
func New(assetPath string, output io.Writer) *JSRE {
|
||||
re := &JSRE{
|
||||
assetPath: assetPath,
|
||||
output: output,
|
||||
closed: make(chan struct{}),
|
||||
evalQueue: make(chan *evalReq),
|
||||
stopEventLoop: make(chan bool),
|
||||
vm: vm,
|
||||
vm: goja.New(),
|
||||
}
|
||||
go re.runEventLoop()
|
||||
re.Set("loadScript", re.loadScript)
|
||||
re.Set("loadScript", MakeCallback(re.vm, re.loadScript))
|
||||
re.Set("inspect", re.prettyPrintJS)
|
||||
return re
|
||||
}
|
||||
|
|
@ -244,21 +249,7 @@ func (re *JSRE) Exec(file string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var script *goja.Program
|
||||
re.Do(func(vm *goja.Runtime) {
|
||||
script, err = goja.Compile(file, string(code), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = vm.RunProgram(script)
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Bind assigns value v to a variable in the JS environment
|
||||
// This method is deprecated, use Set.
|
||||
func (re *JSRE) Bind(name string, v interface{}) error {
|
||||
return re.Set(name, v)
|
||||
return re.Compile(file, string(code))
|
||||
}
|
||||
|
||||
// Run runs a piece of JS code.
|
||||
|
|
@ -267,40 +258,25 @@ func (re *JSRE) Run(code string) (v goja.Value, err error) {
|
|||
return v, err
|
||||
}
|
||||
|
||||
// Get returns the value of a variable in the JS environment.
|
||||
func (re *JSRE) Get(ns string) (v goja.Value) {
|
||||
re.Do(func(vm *goja.Runtime) { v = vm.Get(ns) })
|
||||
return v
|
||||
}
|
||||
|
||||
// Set assigns value v to a variable in the JS environment.
|
||||
func (re *JSRE) Set(ns string, v interface{}) (err error) {
|
||||
re.Do(func(vm *goja.Runtime) { vm.Set(ns, v) })
|
||||
return err
|
||||
}
|
||||
|
||||
// loadScript executes a JS script from inside the currently executing JS code.
|
||||
func (re *JSRE) loadScript(call goja.FunctionCall) goja.Value {
|
||||
file := call.Argument(0).ToString().String()
|
||||
file = common.AbsolutePath(re.assetPath, file)
|
||||
source, err := ioutil.ReadFile(file)
|
||||
// MakeCallback turns the given function into a function that's callable by JS.
|
||||
func MakeCallback(vm *goja.Runtime, fn func(Call) (goja.Value, error)) goja.Value {
|
||||
return vm.ToValue(func(call goja.FunctionCall) goja.Value {
|
||||
result, err := fn(Call{call, vm})
|
||||
if err != nil {
|
||||
// Panicking with a goja.Value arg will cause a JS exception
|
||||
// in the caller.
|
||||
panic(re.vm.ToValue(fmt.Sprintf("Could not read file %s: %v", file, err)))
|
||||
panic(vm.NewGoError(err))
|
||||
}
|
||||
value, err := compileAndRun(re.vm, file, string(source))
|
||||
if err != nil {
|
||||
panic(re.vm.ToValue(fmt.Sprintf("Error while compiling or running script: %v", err)))
|
||||
}
|
||||
return value
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
// Evaluate executes code and pretty prints the result to the specified output
|
||||
// stream.
|
||||
func (re *JSRE) Evaluate(code string, w io.Writer) error {
|
||||
var fail error
|
||||
|
||||
// Evaluate executes code and pretty prints the result to the specified output stream.
|
||||
func (re *JSRE) Evaluate(code string, w io.Writer) {
|
||||
re.Do(func(vm *goja.Runtime) {
|
||||
val, err := vm.RunString(code)
|
||||
if err != nil {
|
||||
|
|
@ -310,7 +286,6 @@ func (re *JSRE) Evaluate(code string, w io.Writer) error {
|
|||
}
|
||||
fmt.Fprintln(w)
|
||||
})
|
||||
return fail
|
||||
}
|
||||
|
||||
// Compile compiles and then runs a piece of JS code.
|
||||
|
|
@ -319,6 +294,21 @@ func (re *JSRE) Compile(filename string, src string) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
// loadScript loads and executes a JS file.
|
||||
func (re *JSRE) loadScript(call Call) (goja.Value, error) {
|
||||
file := call.Argument(0).ToString().String()
|
||||
file = common.AbsolutePath(re.assetPath, file)
|
||||
source, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Could not read file %s: %v", file, err)
|
||||
}
|
||||
value, err := compileAndRun(re.vm, file, string(source))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error while compiling or running script: %v", err)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func compileAndRun(vm *goja.Runtime, filename string, src string) (goja.Value, error) {
|
||||
script, err := goja.Compile(filename, src, false)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func newWithTestJS(t *testing.T, testjs string) (*JSRE, string) {
|
|||
t.Fatal("cannot create test.js:", err)
|
||||
}
|
||||
}
|
||||
jsre := New(dir, os.Stdout, goja.New())
|
||||
jsre := New(dir, os.Stdout)
|
||||
return jsre, dir
|
||||
}
|
||||
|
||||
|
|
@ -102,10 +102,10 @@ func TestNatto(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBind(t *testing.T) {
|
||||
jsre := New("", os.Stdout, goja.New())
|
||||
jsre := New("", os.Stdout)
|
||||
defer jsre.Stop(false)
|
||||
|
||||
jsre.Bind("no", &testNativeObjectBinding{vm: jsre.vm})
|
||||
jsre.Set("no", &testNativeObjectBinding{vm: jsre.vm})
|
||||
|
||||
_, err := jsre.Run(`no.TestMethod("testMsg")`)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue