github.com/kelleygo/clashcore@v1.0.2/component/slowdown/slowdown.go (about)

     1  package slowdown
     2  
     3  import (
     4  	"context"
     5  	"sync/atomic"
     6  	"time"
     7  )
     8  
     9  type SlowDown struct {
    10  	errTimes atomic.Int64
    11  	backoff  Backoff
    12  }
    13  
    14  func (s *SlowDown) Wait(ctx context.Context) (err error) {
    15  	timer := time.NewTimer(s.backoff.Duration())
    16  	defer timer.Stop()
    17  	select {
    18  	case <-timer.C:
    19  	case <-ctx.Done():
    20  		err = ctx.Err()
    21  	}
    22  	return
    23  }
    24  
    25  func New() *SlowDown {
    26  	return &SlowDown{
    27  		backoff: Backoff{
    28  			Min:    10 * time.Millisecond,
    29  			Max:    1 * time.Second,
    30  			Factor: 2,
    31  			Jitter: true,
    32  		},
    33  	}
    34  }
    35  
    36  func Do[T any](s *SlowDown, ctx context.Context, fn func() (T, error)) (t T, err error) {
    37  	if s.errTimes.Load() > 10 {
    38  		err = s.Wait(ctx)
    39  		if err != nil {
    40  			return
    41  		}
    42  	}
    43  	t, err = fn()
    44  	if err != nil {
    45  		s.errTimes.Add(1)
    46  		return
    47  	}
    48  	s.errTimes.Store(0)
    49  	s.backoff.Reset()
    50  	return
    51  }