timer.go 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package signal
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "github.com/xtls/xray-core/common"
  7. "github.com/xtls/xray-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()
  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. checkTask := &task.Periodic{
  50. Interval: timeout,
  51. Execute: t.check,
  52. }
  53. t.Lock()
  54. if t.checkTask != nil {
  55. t.checkTask.Close()
  56. }
  57. t.checkTask = checkTask
  58. t.Unlock()
  59. t.Update()
  60. common.Must(checkTask.Start())
  61. }
  62. func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
  63. timer := &ActivityTimer{
  64. updated: make(chan struct{}, 1),
  65. onTimeout: cancel,
  66. }
  67. timer.SetTimeout(timeout)
  68. return timer
  69. }