Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

idletimer.go 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright (c) 2017 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "fmt"
  6. "sync"
  7. "time"
  8. "github.com/oragono/oragono/irc/caps"
  9. )
  10. const (
  11. // RegisterTimeout is how long clients have to register before we disconnect them
  12. RegisterTimeout = time.Minute
  13. // IdleTimeout is how long without traffic before a registered client is considered idle.
  14. IdleTimeout = time.Minute + time.Second*30
  15. // IdleTimeoutWithResumeCap is how long without traffic before a registered client is considered idle, when they have the resume capability.
  16. IdleTimeoutWithResumeCap = time.Minute*2 + time.Second*30
  17. // QuitTimeout is how long without traffic before an idle client is disconnected
  18. QuitTimeout = time.Minute
  19. )
  20. // client idleness state machine
  21. type TimerState uint
  22. const (
  23. TimerUnregistered TimerState = iota // client is unregistered
  24. TimerActive // client is actively sending commands
  25. TimerIdle // client is idle, we sent PING and are waiting for PONG
  26. TimerDead // client was terminated
  27. )
  28. type IdleTimer struct {
  29. sync.Mutex // tier 1
  30. // immutable after construction
  31. registerTimeout time.Duration
  32. idleTimeout time.Duration
  33. idleTimeoutWithResume time.Duration
  34. quitTimeout time.Duration
  35. client *Client
  36. // mutable
  37. state TimerState
  38. timer *time.Timer
  39. }
  40. // NewIdleTimer sets up a new IdleTimer using constant timeouts.
  41. func NewIdleTimer(client *Client) *IdleTimer {
  42. it := IdleTimer{
  43. registerTimeout: RegisterTimeout,
  44. idleTimeout: IdleTimeout,
  45. idleTimeoutWithResume: IdleTimeoutWithResumeCap,
  46. quitTimeout: QuitTimeout,
  47. client: client,
  48. }
  49. return &it
  50. }
  51. // Start starts counting idle time; if there is no activity from the client,
  52. // it will eventually be stopped.
  53. func (it *IdleTimer) Start() {
  54. it.Lock()
  55. defer it.Unlock()
  56. it.state = TimerUnregistered
  57. it.resetTimeout()
  58. }
  59. func (it *IdleTimer) Touch() {
  60. // ignore touches from unregistered clients
  61. if !it.client.Registered() {
  62. return
  63. }
  64. it.Lock()
  65. defer it.Unlock()
  66. // a touch transitions TimerUnregistered or TimerIdle into TimerActive
  67. if it.state != TimerDead {
  68. it.state = TimerActive
  69. it.resetTimeout()
  70. }
  71. }
  72. func (it *IdleTimer) processTimeout() {
  73. var previousState TimerState
  74. func() {
  75. it.Lock()
  76. defer it.Unlock()
  77. previousState = it.state
  78. // TimerActive transitions to TimerIdle, all others to TimerDead
  79. if it.state == TimerActive {
  80. // send them a ping, give them time to respond
  81. it.state = TimerIdle
  82. it.resetTimeout()
  83. } else {
  84. it.state = TimerDead
  85. }
  86. }()
  87. if previousState == TimerActive {
  88. it.client.Ping()
  89. } else {
  90. it.client.Quit(it.quitMessage(previousState))
  91. it.client.destroy(false)
  92. }
  93. }
  94. // Stop stops counting idle time.
  95. func (it *IdleTimer) Stop() {
  96. it.Lock()
  97. defer it.Unlock()
  98. it.state = TimerDead
  99. it.resetTimeout()
  100. }
  101. func (it *IdleTimer) resetTimeout() {
  102. if it.timer != nil {
  103. it.timer.Stop()
  104. }
  105. var nextTimeout time.Duration
  106. switch it.state {
  107. case TimerUnregistered:
  108. nextTimeout = it.registerTimeout
  109. case TimerActive:
  110. // if they have the resume cap, wait longer before pinging them out
  111. // to give them a chance to resume their connection
  112. if it.client.capabilities.Has(caps.Resume) {
  113. nextTimeout = it.idleTimeoutWithResume
  114. } else {
  115. nextTimeout = it.idleTimeout
  116. }
  117. case TimerIdle:
  118. nextTimeout = it.quitTimeout
  119. case TimerDead:
  120. return
  121. }
  122. it.timer = time.AfterFunc(nextTimeout, it.processTimeout)
  123. }
  124. func (it *IdleTimer) quitMessage(state TimerState) string {
  125. switch state {
  126. case TimerUnregistered:
  127. return fmt.Sprintf("Registration timeout: %v", it.registerTimeout)
  128. case TimerIdle:
  129. // how many seconds before registered clients are timed out (IdleTimeout plus QuitTimeout).
  130. return fmt.Sprintf("Ping timeout: %v", (it.idleTimeout + it.quitTimeout))
  131. default:
  132. // shouldn't happen
  133. return ""
  134. }
  135. }