aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/olebedev/go-duktape.v3/timers.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/olebedev/go-duktape.v3/timers.go')
-rw-r--r--vendor/gopkg.in/olebedev/go-duktape.v3/timers.go136
1 files changed, 136 insertions, 0 deletions
diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/timers.go b/vendor/gopkg.in/olebedev/go-duktape.v3/timers.go
new file mode 100644
index 000000000..e12ee1f2e
--- /dev/null
+++ b/vendor/gopkg.in/olebedev/go-duktape.v3/timers.go
@@ -0,0 +1,136 @@
+package duktape
+
+import (
+ "errors"
+ "fmt"
+ "time"
+)
+
+// DefineTimers defines `setTimeout`, `clearTimeout`, `setInterval`,
+// `clearInterval` into global context.
+func (d *Context) PushTimers() error {
+ d.PushGlobalStash()
+ // check if timers already exists
+ if !d.HasPropString(-1, "timers") {
+ d.PushObject()
+ d.PutPropString(-2, "timers") // stash -> [ timers:{} ]
+ d.Pop()
+
+ d.PushGlobalGoFunction("setTimeout", setTimeout)
+ d.PushGlobalGoFunction("setInterval", setInterval)
+ d.PushGlobalGoFunction("clearTimeout", clearTimeout)
+ d.PushGlobalGoFunction("clearInterval", clearTimeout)
+ return nil
+ } else {
+ d.Pop()
+ return errors.New("Timers are already defined")
+ }
+}
+
+func (d *Context) FlushTimers() {
+ d.PushGlobalStash()
+ d.PushObject()
+ d.PutPropString(-2, "timers") // stash -> [ timers:{} ]
+ d.Pop()
+}
+
+func setTimeout(c *Context) int {
+ id := c.pushTimer(0)
+ timeout := c.ToNumber(1)
+ if timeout < 1 {
+ timeout = 1
+ }
+ go func(id float64) {
+ <-time.After(time.Duration(timeout) * time.Millisecond)
+ c.Lock()
+ defer c.Unlock()
+ if c.duk_context == nil {
+ fmt.Println("[duktape] Warning!\nsetTimeout invokes callback after the context was destroyed.")
+ return
+ }
+
+ // check if timer still exists
+ c.putTimer(id)
+ if c.GetType(-1).IsObject() {
+ c.Pcall(0 /* nargs */)
+ }
+ c.dropTimer(id)
+ }(id)
+ c.PushNumber(id)
+ return 1
+}
+
+func clearTimeout(c *Context) int {
+ if c.GetType(0).IsNumber() {
+ c.dropTimer(c.GetNumber(0))
+ c.Pop()
+ }
+ return 0
+}
+
+func setInterval(c *Context) int {
+ id := c.pushTimer(0)
+ timeout := c.ToNumber(1)
+ if timeout < 1 {
+ timeout = 1
+ }
+ go func(id float64) {
+ ticker := time.NewTicker(time.Duration(timeout) * time.Millisecond)
+ for _ = range ticker.C {
+ c.Lock()
+ // check if duktape context exists
+ if c.duk_context == nil {
+ c.dropTimer(id)
+ c.Pop()
+ ticker.Stop()
+ fmt.Println("[duktape] Warning!\nsetInterval invokes callback after the context was destroyed.")
+ c.Unlock()
+ continue
+ }
+
+ // check if timer still exists
+ c.putTimer(id)
+ if c.GetType(-1).IsObject() {
+ c.Pcall(0 /* nargs */)
+ c.Pop()
+ } else {
+ c.dropTimer(id)
+ c.Pop()
+ ticker.Stop()
+ }
+ c.Unlock()
+ }
+ }(id)
+ c.PushNumber(id)
+ return 1
+}
+
+func (d *Context) pushTimer(index int) float64 {
+ id := d.timerIndex.get()
+
+ d.PushGlobalStash()
+ d.GetPropString(-1, "timers")
+ d.PushNumber(id)
+ d.Dup(index)
+ d.PutProp(-3)
+ d.Pop2()
+
+ return id
+}
+
+func (d *Context) dropTimer(id float64) {
+ d.PushGlobalStash()
+ d.GetPropString(-1, "timers")
+ d.PushNumber(id)
+ d.DelProp(-2)
+ d.Pop2()
+}
+
+func (d *Context) putTimer(id float64) {
+ d.PushGlobalStash() // stash -> [ ..., timers: { <id>: { func: true } } ]
+ d.GetPropString(-1, "timers") // stash -> [ ..., timers: { <id>: { func: true } } }, { <id>: { func: true } ]
+ d.PushNumber(id)
+ d.GetProp(-2) // stash -> [ ..., timers: { <id>: { func: true } } }, { <id>: { func: true }, { func: true } ]
+ d.Replace(-3)
+ d.Pop()
+}