timer.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package signal
  2. import (
  3. "context"
  4. "time"
  5. )
  6. type ActivityUpdater interface {
  7. Update()
  8. }
  9. type ActivityTimer struct {
  10. updated chan struct{}
  11. timeout chan time.Duration
  12. closing chan struct{}
  13. }
  14. func (t *ActivityTimer) Update() {
  15. select {
  16. case t.updated <- struct{}{}:
  17. default:
  18. }
  19. }
  20. func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
  21. select {
  22. case <-t.closing:
  23. case t.timeout <- timeout:
  24. }
  25. }
  26. func (t *ActivityTimer) run(ctx context.Context, cancel context.CancelFunc) {
  27. defer func() {
  28. cancel()
  29. close(t.closing)
  30. }()
  31. timeout := <-t.timeout
  32. if timeout == 0 {
  33. return
  34. }
  35. ticker := time.NewTicker(timeout)
  36. defer func() {
  37. ticker.Stop()
  38. }()
  39. for {
  40. select {
  41. case <-ticker.C:
  42. case <-ctx.Done():
  43. return
  44. case timeout := <-t.timeout:
  45. if timeout == 0 {
  46. return
  47. }
  48. ticker.Stop()
  49. ticker = time.NewTicker(timeout)
  50. continue
  51. }
  52. select {
  53. case <-t.updated:
  54. // Updated keep waiting.
  55. default:
  56. return
  57. }
  58. }
  59. }
  60. func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
  61. timer := &ActivityTimer{
  62. timeout: make(chan time.Duration, 1),
  63. updated: make(chan struct{}, 1),
  64. closing: make(chan struct{}),
  65. }
  66. timer.timeout <- timeout
  67. go timer.run(ctx, cancel)
  68. return timer
  69. }