Clash.Meta/common/singledo/singledo.go

65 lines
1.0 KiB
Go
Raw Normal View History

package singledo
import (
"sync"
"time"
)
type call struct {
wg sync.WaitGroup
val interface{}
err error
}
type Single struct {
mux sync.Mutex
2019-12-10 16:26:15 +08:00
last time.Time
wait time.Duration
call *call
result *Result
}
type Result struct {
Val interface{}
Err error
}
2020-08-25 22:19:59 +08:00
// Do single.Do likes sync.singleFilght
//lint:ignore ST1008 it likes sync.singleFilght
func (s *Single) Do(fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
s.mux.Lock()
2019-12-10 16:26:15 +08:00
now := time.Now()
if now.Before(s.last.Add(s.wait)) {
s.mux.Unlock()
return s.result.Val, s.result.Err, true
}
if call := s.call; call != nil {
s.mux.Unlock()
call.wg.Wait()
return call.val, call.err, true
}
call := &call{}
call.wg.Add(1)
s.call = call
s.mux.Unlock()
call.val, call.err = fn()
2019-12-10 16:26:15 +08:00
call.wg.Done()
2020-07-18 20:56:13 +08:00
s.mux.Lock()
s.call = nil
s.result = &Result{call.val, call.err}
s.last = now
2020-07-18 20:56:13 +08:00
s.mux.Unlock()
return call.val, call.err, false
}
2020-04-30 20:13:27 +08:00
func (s *Single) Reset() {
s.last = time.Time{}
}
func NewSingle(wait time.Duration) *Single {
2019-12-10 16:26:15 +08:00
return &Single{wait: wait}
}