| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- package signal
- import (
- "context"
- "sync"
- "sync/atomic"
- "time"
- "github.com/xtls/xray-core/common"
- "github.com/xtls/xray-core/common/task"
- )
- type ActivityUpdater interface {
- Update()
- }
- type ActivityTimer struct {
- mu sync.RWMutex
- updated chan struct{}
- checkTask *task.Periodic
- onTimeout func()
- consumed atomic.Bool
- once sync.Once
- }
- func (t *ActivityTimer) Update() {
- select {
- case t.updated <- struct{}{}:
- default:
- }
- }
- func (t *ActivityTimer) check() error {
- select {
- case <-t.updated:
- default:
- t.finish()
- }
- return nil
- }
- func (t *ActivityTimer) finish() {
- t.once.Do(func() {
- t.consumed.Store(true)
- t.mu.Lock()
- defer t.mu.Unlock()
- common.CloseIfExists(t.checkTask)
- t.onTimeout()
- })
- }
- func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
- if t.consumed.Load() {
- return
- }
- if timeout == 0 {
- t.finish()
- return
- }
- t.mu.Lock()
- defer t.mu.Unlock()
- // double check, just in case
- if t.consumed.Load() {
- return
- }
- newCheckTask := &task.Periodic{
- Interval: timeout,
- Execute: t.check,
- }
- common.CloseIfExists(t.checkTask)
- t.checkTask = newCheckTask
- t.Update()
- common.Must(newCheckTask.Start())
- }
- func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
- timer := &ActivityTimer{
- updated: make(chan struct{}, 1),
- onTimeout: cancel,
- }
- timer.SetTimeout(timeout)
- return timer
- }
|