lkcp9_updater.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright © 2015 Daniel Fu <daniel820313@gmail.com>.
  2. // Copyright © 2019 Loki 'l0k18' Verloren <stalker.loki@protonmail.ch>.
  3. // Copyright © 2020 Gridfinity, LLC. <admin@gridfinity.com>.
  4. // Copyright © 2020 Jeffrey H. Johnson <jeff@gridfinity.com>.
  5. //
  6. // All rights reserved.
  7. //
  8. // All use of this code is governed by the MIT license.
  9. // The complete license is available in the LICENSE file.
  10. package lkcp9 // import "go.gridfinity.dev/lkcp9"
  11. import (
  12. "container/heap"
  13. "sync"
  14. "time"
  15. )
  16. var updater updateHeap
  17. func init() {
  18. updater.init()
  19. go updater.updateTask()
  20. }
  21. type entry struct {
  22. ts time.Time
  23. s *UDPSession
  24. }
  25. type updateHeap struct {
  26. entries []entry
  27. mu sync.Mutex
  28. chWakeUp chan struct{}
  29. }
  30. func (
  31. h *updateHeap,
  32. ) Len() int {
  33. return len(
  34. h.entries,
  35. )
  36. }
  37. func (
  38. h *updateHeap,
  39. ) Less(
  40. i,
  41. j int,
  42. ) bool {
  43. return h.entries[i].ts.Before(
  44. h.entries[j].ts,
  45. )
  46. }
  47. func (
  48. h *updateHeap,
  49. ) Swap(
  50. i,
  51. j int,
  52. ) {
  53. h.entries[i], h.entries[j] = h.entries[j], h.entries[i]
  54. h.entries[i].s.updaterIdx = i
  55. h.entries[j].s.updaterIdx = j
  56. }
  57. func (
  58. h *updateHeap,
  59. ) Push(
  60. x interface{},
  61. ) {
  62. h.entries = append(
  63. h.entries,
  64. x.(entry),
  65. )
  66. n := len(h.entries)
  67. h.entries[n-1].s.updaterIdx = n - 1
  68. }
  69. func (
  70. h *updateHeap,
  71. ) Pop() interface{} {
  72. n := len(
  73. h.entries,
  74. )
  75. x := h.entries[n-1]
  76. h.entries[n-1].s.updaterIdx = -1
  77. h.entries[n-1] = entry{}
  78. h.entries = h.entries[0 : n-1]
  79. return x
  80. }
  81. func (
  82. h *updateHeap,
  83. ) init() {
  84. h.chWakeUp = make(
  85. chan struct{},
  86. 1,
  87. )
  88. }
  89. func (
  90. h *updateHeap,
  91. ) addSession(
  92. s *UDPSession,
  93. ) {
  94. h.mu.Lock()
  95. heap.Push(
  96. h,
  97. entry{
  98. time.Now(),
  99. s,
  100. },
  101. )
  102. h.mu.Unlock()
  103. h.wakeup()
  104. }
  105. func (
  106. h *updateHeap,
  107. ) removeSession(
  108. s *UDPSession,
  109. ) {
  110. h.mu.Lock()
  111. if s.updaterIdx != -1 {
  112. heap.Remove(
  113. h,
  114. s.updaterIdx,
  115. )
  116. }
  117. h.mu.Unlock()
  118. }
  119. func (
  120. h *updateHeap,
  121. ) wakeup() {
  122. select {
  123. case h.chWakeUp <- struct{}{}:
  124. default:
  125. }
  126. }
  127. func (
  128. h *updateHeap,
  129. ) updateTask() {
  130. timer := time.NewTimer(0)
  131. for {
  132. select {
  133. case <-timer.C:
  134. case <-h.chWakeUp:
  135. }
  136. h.mu.Lock()
  137. hlen := h.Len()
  138. for i := 0; i < hlen; i++ {
  139. entry := &h.entries[0]
  140. if !time.Now().Before(entry.ts) {
  141. interval := entry.s.update()
  142. entry.ts = time.Now().Add(
  143. interval,
  144. )
  145. heap.Fix(
  146. h,
  147. 0,
  148. )
  149. } else {
  150. break
  151. }
  152. }
  153. if hlen > 0 {
  154. timer.Reset(
  155. h.entries[0].ts.Sub(
  156. time.Now(),
  157. ),
  158. )
  159. }
  160. h.mu.Unlock()
  161. }
  162. }