throttle.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. package ircclient
  2. import (
  3. "log"
  4. "time"
  5. )
  6. // Track when the client last sent something
  7. type FloodTrack struct {
  8. Pos int // Index to store next item
  9. Size int // Max number of Track items
  10. Timeout int // Timeout in seconds
  11. Track []time.Time
  12. }
  13. // Initialize flood tracking
  14. func (F *FloodTrack) Init(size int, timeout int) {
  15. F.Size = size
  16. F.Timeout = timeout
  17. F.Track = make([]time.Time, size)
  18. }
  19. // Are we full?
  20. //
  21. // Expire records before checking.
  22. func (F *FloodTrack) Full() bool {
  23. if F.Pos > 0 {
  24. F.Expire()
  25. }
  26. return F.Pos == F.Size
  27. }
  28. // Expire Track records older then timeout
  29. func (F *FloodTrack) Expire() {
  30. var idx int
  31. ReCheck:
  32. for idx = 0; idx < F.Pos; idx++ {
  33. // log.Println(idx, time.Since(F.Track[idx]).Seconds())
  34. if time.Since(F.Track[idx]).Seconds() > float64(F.Timeout) {
  35. // Remove this from the list
  36. F.Pos--
  37. for pos := idx; pos < F.Pos; pos++ {
  38. F.Track[pos] = F.Track[pos+1]
  39. }
  40. goto ReCheck
  41. }
  42. }
  43. }
  44. // Save Now() into the tracker.
  45. func (F *FloodTrack) Save() {
  46. F.Track[F.Pos] = time.Now()
  47. F.Pos++
  48. }
  49. type ThrottleBuffer struct {
  50. buffer map[string][]string // Map of targets and strings to send
  51. targets []string // List of targets
  52. last int // Last index set
  53. Life_sucks bool // Is throttle active?
  54. }
  55. func (T *ThrottleBuffer) Init() {
  56. T.buffer = make(map[string][]string, 0)
  57. T.targets = make([]string, 0)
  58. T.last = 0
  59. }
  60. // Pop next available from buffer.
  61. //
  62. // If empty, remove from map and targets list. Adjust last if needed.
  63. func (T *ThrottleBuffer) pop() string {
  64. // Get next target
  65. var t string = T.targets[T.last]
  66. T.last++
  67. if T.last == len(T.targets) {
  68. // We're past the end, start over at the beginning.
  69. T.last = 0
  70. }
  71. var msg string = T.buffer[t][0]
  72. if len(T.buffer[t]) == 1 {
  73. // This is the last entry for this target.
  74. delete(T.buffer, t)
  75. if len(T.targets) == 1 {
  76. // This is the last entry
  77. T.targets = make([]string, 0)
  78. T.Life_sucks = false
  79. log.Println("Flood control off.")
  80. } else {
  81. // Remove t from targets
  82. for x := 0; x < len(T.targets); x++ {
  83. if T.targets[x] == t {
  84. T.targets = append(T.targets[:x], T.targets[x+1:]...)
  85. if x <= T.last {
  86. T.last--
  87. }
  88. break
  89. }
  90. }
  91. }
  92. } else {
  93. // Delete the first entry for t
  94. T.buffer[t] = append(T.buffer[t][:0], T.buffer[t][1:]...)
  95. }
  96. return msg
  97. }
  98. // Push item into the buffer, begin throttling.
  99. func (T *ThrottleBuffer) push(To string, Output string) {
  100. if len(T.targets) == 0 {
  101. T.Life_sucks = true
  102. T.last = 0
  103. log.Println("Flood control enabled.")
  104. }
  105. _, has := T.buffer[To]
  106. if !has {
  107. T.buffer[To] = make([]string, 0)
  108. T.targets = append(T.targets, To)
  109. }
  110. T.buffer[To] = append(T.buffer[To], Output)
  111. }
  112. // Delete target from buffer, if exists.
  113. //
  114. // If we're kicked from the channel we're sending to, or if the
  115. // nick we're sending to quits -- remove those from write queue.
  116. func (T *ThrottleBuffer) delete(To string) {
  117. _, has := T.buffer[To]
  118. if has {
  119. // Yes, the buffer has message(s) for To
  120. delete(T.buffer, To)
  121. if len(T.targets) == 1 {
  122. // Last entry
  123. T.targets = make([]string, 0)
  124. T.Life_sucks = false
  125. log.Println("Flood control off.")
  126. } else {
  127. // Remove To from targets
  128. for x := 0; x < len(T.targets); x++ {
  129. if T.targets[x] == To {
  130. T.targets = append(T.targets[:x], T.targets[x+1:]...)
  131. // Don't decrement if already at first item
  132. if (x <= T.last) && (T.last != 0) {
  133. T.last--
  134. }
  135. break
  136. }
  137. }
  138. }
  139. }
  140. }