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 }