forked from robertkrimen/otto
-
Notifications
You must be signed in to change notification settings - Fork 0
/
timer.go
106 lines (91 loc) · 2.13 KB
/
timer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package otto
import (
"time"
)
type _timer struct {
timer *time.Timer
duration time.Duration
interval bool
call FunctionCall
}
func AddTimerToOtto(vm *Otto) error {
registry := map[*_timer]*_timer{}
ready := make(chan *_timer)
newTimer := func(call FunctionCall, interval bool) (*_timer, Value) {
wg := vm.newRoutine()
delay, _ := call.Argument(1).ToInteger()
if 0 >= delay {
delay = 1
}
timer := &_timer{
duration: time.Duration(delay) * time.Millisecond,
call: call,
interval: interval,
}
registry[timer] = timer
timer.timer = time.AfterFunc(timer.duration, func() {
wg.Done()
ready <- timer
})
value := vm.runtime.toValue(timer)
return timer, value
}
setTimeout := func(call FunctionCall) Value {
_, value := newTimer(call, false)
return value
}
vm.Set("setTimeout", setTimeout)
setInterval := func(call FunctionCall) Value {
_, value := newTimer(call, true)
return value
}
vm.Set("setInterval", setInterval)
clearTimeout := func(call FunctionCall) Value {
timer, _ := call.Argument(0).Export()
if timer, ok := timer.(*_timer); ok {
timer.timer.Stop()
delete(registry, timer)
}
return UndefinedValue()
}
vm.Set("clearTimeout", clearTimeout)
vm.Set("clearInterval", clearTimeout)
go func() {
for {
select {
case timer := <-ready:
var arguments []interface{}
if len(timer.call.ArgumentList) > 2 {
tmp := timer.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] = timer.call.ArgumentList[0]
_, err := vm.Call(`Function.call.call`, nil, arguments...)
if err != nil {
for _, timer := range registry {
timer.timer.Stop()
delete(registry, timer)
}
}
if timer.interval {
timer.timer.Reset(timer.duration)
} else {
delete(registry, timer)
}
// default:
// fmt.Println("timer.go: waiting...")
// Escape valve!
// If this isn't here, we deadlock...
}
if len(registry) == 0 {
break
}
}
}()
return nil
}