timer.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package signal
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "v2ray.com/core/common"
  7. "v2ray.com/core/common/task"
  8. )
  9. type ActivityUpdater interface {
  10. Update()
  11. }
  12. type ActivityTimer struct {
  13. sync.RWMutex
  14. updated chan struct{}
  15. checkTask *task.Periodic
  16. onTimeout func()
  17. }
  18. func (t *ActivityTimer) Update() {
  19. select {
  20. case t.updated <- struct{}{}:
  21. default:
  22. }
  23. }
  24. func (t *ActivityTimer) check() error {
  25. select {
  26. case <-t.updated:
  27. default:
  28. t.finish()
  29. }
  30. return nil
  31. }
  32. func (t *ActivityTimer) finish() {
  33. t.Lock()
  34. defer t.Unlock()
  35. if t.onTimeout != nil {
  36. t.onTimeout()
  37. t.onTimeout = nil
  38. }
  39. if t.checkTask != nil {
  40. t.checkTask.Close() // nolint: errcheck
  41. t.checkTask = nil
  42. }
  43. }
  44. func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
  45. if timeout == 0 {
  46. t.finish()
  47. return
  48. }
  49. t.Lock()
  50. if t.checkTask != nil {
  51. t.checkTask.Close() // nolint: errcheck
  52. }
  53. t.checkTask = &task.Periodic{
  54. Interval: timeout,
  55. Execute: t.check,
  56. }
  57. t.Unlock()
  58. t.Update()
  59. common.Must(t.checkTask.Start())
  60. }
  61. func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
  62. timer := &ActivityTimer{
  63. updated: make(chan struct{}, 1),
  64. onTimeout: cancel,
  65. }
  66. timer.SetTimeout(timeout)
  67. return timer
  68. }