github.com/igoogolx/clash@v1.19.8/common/singledo/singledo.go (about)

     1  package singledo
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  type call struct {
     9  	wg  sync.WaitGroup
    10  	val any
    11  	err error
    12  }
    13  
    14  type Single struct {
    15  	mux    sync.Mutex
    16  	last   time.Time
    17  	wait   time.Duration
    18  	call   *call
    19  	result *Result
    20  }
    21  
    22  type Result struct {
    23  	Val any
    24  	Err error
    25  }
    26  
    27  // Do single.Do likes sync.singleFlight
    28  func (s *Single) Do(fn func() (any, error)) (v any, err error, shared bool) {
    29  	s.mux.Lock()
    30  	now := time.Now()
    31  	if now.Before(s.last.Add(s.wait)) {
    32  		s.mux.Unlock()
    33  		return s.result.Val, s.result.Err, true
    34  	}
    35  
    36  	if call := s.call; call != nil {
    37  		s.mux.Unlock()
    38  		call.wg.Wait()
    39  		return call.val, call.err, true
    40  	}
    41  
    42  	call := &call{}
    43  	call.wg.Add(1)
    44  	s.call = call
    45  	s.mux.Unlock()
    46  	call.val, call.err = fn()
    47  	call.wg.Done()
    48  
    49  	s.mux.Lock()
    50  	s.call = nil
    51  	s.result = &Result{call.val, call.err}
    52  	s.last = now
    53  	s.mux.Unlock()
    54  	return call.val, call.err, false
    55  }
    56  
    57  func (s *Single) Reset() {
    58  	s.last = time.Time{}
    59  }
    60  
    61  func NewSingle(wait time.Duration) *Single {
    62  	return &Single{wait: wait}
    63  }