github.com/imannamdari/v2ray-core/v5@v5.0.5/common/signal/timer.go (about)

     1  package signal
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/imannamdari/v2ray-core/v5/common"
     9  	"github.com/imannamdari/v2ray-core/v5/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  }