Clash.Meta/common/singledo/singledo.go

55 lines
876 B
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
last int64
wait int64
call *call
result *Result
}
type Result struct {
Val interface{}
Err error
}
func (s *Single) Do(fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
s.mux.Lock()
now := time.Now().Unix()
if now < s.last+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()
s.call = nil
s.result = &Result{call.val, call.err}
s.last = now
return call.val, call.err, false
}
func NewSingle(wait time.Duration) *Single {
return &Single{wait: int64(wait)}
}