timer.go 2.9 KB

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