diff options
Diffstat (limited to 'vendor/gopkg.in/olebedev/go-duktape.v3/timers.go')
-rw-r--r-- | vendor/gopkg.in/olebedev/go-duktape.v3/timers.go | 136 |
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() +} |