timer.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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. }
  38. if t.checkTask != nil {
  39. t.checkTask.Close() // nolint: errcheck
  40. t.checkTask = nil
  41. }
  42. }
  43. func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
  44. if timeout == 0 {
  45. t.finish()
  46. return
  47. }
  48. t.Lock()
  49. if t.checkTask != nil {
  50. t.checkTask.Close() // nolint: errcheck
  51. }
  52. t.checkTask = &task.Periodic{
  53. Interval: timeout,
  54. Execute: t.check,
  55. }
  56. t.Unlock()
  57. t.Update()
  58. common.Must(t.checkTask.Start())
  59. }
  60. func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
  61. timer := &ActivityTimer{
  62. updated: make(chan struct{}, 1),
  63. onTimeout: cancel,
  64. }
  65. timer.SetTimeout(timeout)
  66. return timer
  67. }