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