status-go/geth/jail/internal/timers/timers.go

132 lines
2.5 KiB
Go

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"
)
var minDelay = map[bool]int64{
true: 10,
false: 4,
}
func Define(vm *vm.VM, l *loop.Loop) error {
if v, err := vm.Get("setTimeout"); err != nil {
return err
} else if !v.IsUndefined() {
return nil
}
newTimer := func(interval bool) func(call otto.FunctionCall) otto.Value {
return func(call otto.FunctionCall) otto.Value {
delay, _ := call.Argument(1).ToInteger()
if delay < minDelay[interval] {
delay = minDelay[interval]
}
t := &timerTask{
duration: time.Duration(delay) * time.Millisecond,
call: call,
interval: interval,
}
l.Add(t)
t.timer = time.AfterFunc(t.duration, func() {
l.Ready(t)
})
value, err := call.Otto.ToValue(t)
if err != nil {
panic(err)
}
return value
}
}
vm.Set("setTimeout", newTimer(false))
vm.Set("setInterval", newTimer(true))
vm.Set("setImmediate", func(call otto.FunctionCall) otto.Value {
t := &timerTask{
duration: time.Millisecond,
call: call,
}
l.Add(t)
t.timer = time.AfterFunc(t.duration, func() {
l.Ready(t)
})
value, err := call.Otto.ToValue(t)
if err != nil {
panic(err)
}
return value
})
clearTimeout := func(call otto.FunctionCall) otto.Value {
v, _ := call.Argument(0).Export()
if t, ok := v.(*timerTask); ok {
t.stopped = true
t.timer.Stop()
l.Remove(t)
}
return otto.UndefinedValue()
}
vm.Set("clearTimeout", clearTimeout)
vm.Set("clearInterval", clearTimeout)
vm.Set("clearImmediate", clearTimeout)
return nil
}
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)
l.Add(t)
}
return nil
}
func (t *timerTask) Cancel() {
t.timer.Stop()
}