Additionally, this change clean ups and improves organization of `geth/jail/internal/timers` package.
This commit is contained in:
parent
83415ea4c8
commit
7ab6a062ec
|
@ -0,0 +1,54 @@
|
||||||
|
package timers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/robertkrimen/otto"
|
||||||
|
"github.com/status-im/status-go/geth/jail/internal/loop"
|
||||||
|
"github.com/status-im/status-go/geth/jail/internal/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type timerTask struct {
|
||||||
|
id int64
|
||||||
|
timer *time.Timer
|
||||||
|
duration time.Duration
|
||||||
|
interval bool
|
||||||
|
call otto.FunctionCall
|
||||||
|
stopped bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *timerTask) SetID(id int64) { t.id = id }
|
||||||
|
func (t *timerTask) GetID() int64 { return t.id }
|
||||||
|
|
||||||
|
func (t *timerTask) Execute(vm *vm.VM, l *loop.Loop) error {
|
||||||
|
arguments := t.getArguments()
|
||||||
|
if _, err := vm.Call(`Function.call.call`, nil, arguments...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(t.interval && !t.stopped) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
t.timer.Reset(t.duration)
|
||||||
|
return l.Add(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *timerTask) Cancel() {
|
||||||
|
t.timer.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *timerTask) getArguments() (arguments []interface{}) {
|
||||||
|
arguments = make([]interface{}, 1)
|
||||||
|
if len(t.call.ArgumentList) > 2 {
|
||||||
|
tmp := t.call.ArgumentList[2:]
|
||||||
|
arguments = make([]interface{}, 2+len(tmp))
|
||||||
|
|
||||||
|
for i, value := range tmp {
|
||||||
|
arguments[i+2] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arguments[0] = t.call.ArgumentList[0]
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -9,12 +9,7 @@ import (
|
||||||
"github.com/status-im/status-go/geth/jail/internal/vm"
|
"github.com/status-im/status-go/geth/jail/internal/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
var minDelay = map[bool]int64{
|
// Define jail timers
|
||||||
true: 10,
|
|
||||||
false: 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
//Define jail timers
|
|
||||||
func Define(vm *vm.VM, l *loop.Loop) error {
|
func Define(vm *vm.VM, l *loop.Loop) error {
|
||||||
if v, err := vm.Get("setTimeout"); err != nil {
|
if v, err := vm.Get("setTimeout"); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -22,19 +17,46 @@ func Define(vm *vm.VM, l *loop.Loop) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newTimer := func(interval bool) func(call otto.FunctionCall) otto.Value {
|
timeHandlers := map[string]func(call otto.FunctionCall) otto.Value{
|
||||||
return func(call otto.FunctionCall) otto.Value {
|
"setInterval": newTimerHandler(l, true),
|
||||||
|
"setTimeout": newTimerHandler(l, false),
|
||||||
|
"setImmediate": newImmediateTimerHandler(l),
|
||||||
|
"clearTimeout": newClearTimeoutHandler(l),
|
||||||
|
"clearInterval": newClearTimeoutHandler(l),
|
||||||
|
"clearImmediate": newClearTimeoutHandler(l),
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, handler := range timeHandlers {
|
||||||
|
if err := vm.Set(k, handler); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDelayWithMin(call otto.FunctionCall, interval bool) int64 {
|
||||||
|
var minDelay = map[bool]int64{
|
||||||
|
true: 10,
|
||||||
|
false: 4,
|
||||||
|
}
|
||||||
|
|
||||||
delay, _ := call.Argument(1).ToInteger()
|
delay, _ := call.Argument(1).ToInteger()
|
||||||
if delay < minDelay[interval] {
|
if delay < minDelay[interval] {
|
||||||
delay = minDelay[interval]
|
return minDelay[interval]
|
||||||
}
|
}
|
||||||
|
return delay
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTimerHandler(l *loop.Loop, interval bool) func(call otto.FunctionCall) otto.Value {
|
||||||
|
return func(call otto.FunctionCall) otto.Value {
|
||||||
|
delay := getDelayWithMin(call, interval)
|
||||||
|
|
||||||
t := &timerTask{
|
t := &timerTask{
|
||||||
duration: time.Duration(delay) * time.Millisecond,
|
duration: time.Duration(delay) * time.Millisecond,
|
||||||
call: call,
|
call: call,
|
||||||
interval: interval,
|
interval: interval,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If err is non-nil, then the loop is closed and should not
|
// If err is non-nil, then the loop is closed and should not
|
||||||
// be used anymore.
|
// be used anymore.
|
||||||
if err := l.Add(t); err != nil {
|
if err := l.Add(t); err != nil {
|
||||||
|
@ -52,19 +74,10 @@ func Define(vm *vm.VM, l *loop.Loop) error {
|
||||||
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := vm.Set("setTimeout", newTimer(false))
|
func newImmediateTimerHandler(l *loop.Loop) func(call otto.FunctionCall) otto.Value {
|
||||||
if err != nil {
|
return func(call otto.FunctionCall) otto.Value {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = vm.Set("setInterval", newTimer(true))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = vm.Set("setImmediate", func(call otto.FunctionCall) otto.Value {
|
|
||||||
t := &timerTask{
|
t := &timerTask{
|
||||||
duration: time.Millisecond,
|
duration: time.Millisecond,
|
||||||
call: call,
|
call: call,
|
||||||
|
@ -81,17 +94,16 @@ func Define(vm *vm.VM, l *loop.Loop) error {
|
||||||
})
|
})
|
||||||
|
|
||||||
value, setImmediateErr := call.Otto.ToValue(t)
|
value, setImmediateErr := call.Otto.ToValue(t)
|
||||||
if err != nil {
|
if setImmediateErr != nil {
|
||||||
panic(setImmediateErr)
|
panic(setImmediateErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return value
|
return value
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clearTimeout := func(call otto.FunctionCall) otto.Value {
|
func newClearTimeoutHandler(l *loop.Loop) func(call otto.FunctionCall) otto.Value {
|
||||||
|
return func(call otto.FunctionCall) otto.Value {
|
||||||
v, _ := call.Argument(0).Export()
|
v, _ := call.Argument(0).Export()
|
||||||
if t, ok := v.(*timerTask); ok {
|
if t, ok := v.(*timerTask); ok {
|
||||||
t.stopped = true
|
t.stopped = true
|
||||||
|
@ -101,62 +113,4 @@ func Define(vm *vm.VM, l *loop.Loop) error {
|
||||||
|
|
||||||
return otto.UndefinedValue()
|
return otto.UndefinedValue()
|
||||||
}
|
}
|
||||||
err = vm.Set("clearTimeout", clearTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = vm.Set("clearInterval", clearTimeout)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = vm.Set("clearImmediate", clearTimeout)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type timerTask struct {
|
|
||||||
id int64
|
|
||||||
timer *time.Timer
|
|
||||||
duration time.Duration
|
|
||||||
interval bool
|
|
||||||
call otto.FunctionCall
|
|
||||||
stopped bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *timerTask) SetID(id int64) { t.id = id }
|
|
||||||
func (t *timerTask) GetID() int64 { return t.id }
|
|
||||||
|
|
||||||
func (t *timerTask) Execute(vm *vm.VM, l *loop.Loop) error {
|
|
||||||
var arguments []interface{}
|
|
||||||
|
|
||||||
if len(t.call.ArgumentList) > 2 {
|
|
||||||
tmp := t.call.ArgumentList[2:]
|
|
||||||
arguments = make([]interface{}, 2+len(tmp))
|
|
||||||
|
|
||||||
for i, value := range tmp {
|
|
||||||
arguments[i+2] = value
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arguments = make([]interface{}, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
arguments[0] = t.call.ArgumentList[0]
|
|
||||||
|
|
||||||
if _, err := vm.Call(`Function.call.call`, nil, arguments...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.interval && !t.stopped {
|
|
||||||
t.timer.Reset(t.duration)
|
|
||||||
if err := l.Add(t); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *timerTask) Cancel() {
|
|
||||||
t.timer.Stop()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,29 @@ func (s *TimersSuite) TestClearIntervalImmediately() {
|
||||||
<-time.After(100 * time.Millisecond)
|
<-time.After(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimersSuite) TestImmediateTimer() {
|
||||||
|
err := s.vm.Set("__done", func() {
|
||||||
|
s.ch <- struct{}{}
|
||||||
|
})
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
err = s.loop.Eval(`
|
||||||
|
var v = setImmediate(function() {
|
||||||
|
__done();
|
||||||
|
});
|
||||||
|
`)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-s.ch:
|
||||||
|
value, err := s.vm.Get("v")
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(value)
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
s.Fail("test timed out")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type TimersSuite struct {
|
type TimersSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue