timer.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package core
  5. import (
  6. "time"
  7. )
  8. // TimerManager manages multiple timers
  9. type TimerManager struct {
  10. nextID int // next timer id
  11. timers []timeout // list of timeouts
  12. }
  13. // TimerCallback is the type for timer callback functions
  14. type TimerCallback func(interface{})
  15. // Internal structure for each active timer
  16. type timeout struct {
  17. id int // timeout id
  18. expire time.Time // expiration time
  19. period time.Duration // period time
  20. cb TimerCallback // callback function
  21. arg interface{} // callback function argument
  22. }
  23. // NewTimerManager creates and returns a new timer manager
  24. func NewTimerManager() *TimerManager {
  25. tm := new(TimerManager)
  26. tm.Initialize()
  27. return tm
  28. }
  29. // Initialize initializes the timer manager.
  30. // It is normally used when the TimerManager is embedded in another type.
  31. func (tm *TimerManager) Initialize() {
  32. tm.nextID = 1
  33. tm.timers = make([]timeout, 0)
  34. }
  35. // SetTimeout sets a timeout with the specified duration and callback
  36. // The function returns the timeout id which can be used to cancel the timeout
  37. func (tm *TimerManager) SetTimeout(td time.Duration, arg interface{}, cb TimerCallback) int {
  38. return tm.setTimer(td, false, arg, cb)
  39. }
  40. // SetInterval sets a periodic timeout with the specified duration and callback
  41. // The function returns the timeout id which can be used to cancel the timeout
  42. func (tm *TimerManager) SetInterval(td time.Duration, arg interface{}, cb TimerCallback) int {
  43. return tm.setTimer(td, true, arg, cb)
  44. }
  45. // ClearTimeout clears the timeout specified by the id.
  46. // Returns true if the timeout is found.
  47. func (tm *TimerManager) ClearTimeout(id int) bool {
  48. for pos, t := range tm.timers {
  49. if t.id == id {
  50. copy(tm.timers[pos:], tm.timers[pos+1:])
  51. tm.timers[len(tm.timers)-1] = timeout{}
  52. tm.timers = tm.timers[:len(tm.timers)-1]
  53. return true
  54. }
  55. }
  56. return false
  57. }
  58. // ProcessTimers should be called periodically to process the timers
  59. func (tm *TimerManager) ProcessTimers() {
  60. now := time.Now()
  61. for pos, t := range tm.timers {
  62. // If empty entry, ignore
  63. if t.id == 0 {
  64. continue
  65. }
  66. // Checks if entry expired
  67. if now.After(t.expire) {
  68. if t.period == 0 {
  69. tm.timers[pos] = timeout{}
  70. } else {
  71. tm.timers[pos].expire = now.Add(t.period)
  72. }
  73. t.cb(t.arg)
  74. }
  75. }
  76. }
  77. // setTimer sets a new timer with the specified duration
  78. func (tm *TimerManager) setTimer(td time.Duration, periodic bool, arg interface{}, cb TimerCallback) int {
  79. // Creates timeout entry
  80. t := timeout{
  81. id: tm.nextID,
  82. expire: time.Now().Add(td),
  83. cb: cb,
  84. arg: arg,
  85. period: 0,
  86. }
  87. if periodic {
  88. t.period = td
  89. }
  90. tm.nextID++
  91. // Look for empty entry
  92. for pos, ct := range tm.timers {
  93. if ct.id == 0 {
  94. tm.timers[pos] = t
  95. return t.id
  96. }
  97. }
  98. // If no empty entry found, add to end of array
  99. tm.timers = append(tm.timers, t)
  100. return t.id
  101. }