github.com/iikira/iikira-go-utils@v0.0.0-20230610031953-f2cb11cde33a/requester/rio/speeds/ratelimit.go (about)

     1  package speeds
     2  
     3  import (
     4  	"sync"
     5  	"sync/atomic"
     6  	"time"
     7  )
     8  
     9  type (
    10  	RateLimit struct {
    11  		MaxRate int64
    12  
    13  		count           int64
    14  		interval        time.Duration
    15  		ticker          *time.Ticker
    16  		muChan          chan struct{}
    17  		closeChan       chan struct{}
    18  		backServiceOnce sync.Once
    19  	}
    20  
    21  	// AddCountFunc func() (count int64)
    22  )
    23  
    24  func NewRateLimit(maxRate int64) *RateLimit {
    25  	return &RateLimit{
    26  		MaxRate: maxRate,
    27  	}
    28  }
    29  
    30  func (rl *RateLimit) SetInterval(i time.Duration) {
    31  	if i <= 0 {
    32  		i = 1 * time.Second
    33  	}
    34  	rl.interval = i
    35  	if rl.ticker != nil {
    36  		rl.ticker.Stop()
    37  		rl.ticker = time.NewTicker(i)
    38  	}
    39  }
    40  
    41  func (rl *RateLimit) Stop() {
    42  	if rl.ticker != nil {
    43  		rl.ticker.Stop()
    44  	}
    45  	if rl.closeChan != nil {
    46  		close(rl.closeChan)
    47  	}
    48  	return
    49  }
    50  
    51  func (rl *RateLimit) resetChan() {
    52  	if rl.muChan != nil {
    53  		close(rl.muChan)
    54  	}
    55  	rl.muChan = make(chan struct{})
    56  }
    57  
    58  func (rl *RateLimit) backService() {
    59  	if rl.interval <= 0 {
    60  		rl.interval = 1 * time.Second
    61  	}
    62  	rl.ticker = time.NewTicker(rl.interval)
    63  	rl.closeChan = make(chan struct{})
    64  	rl.resetChan()
    65  	go func() {
    66  		for {
    67  			select {
    68  			case <-rl.ticker.C:
    69  				rl.resetChan()
    70  				atomic.StoreInt64(&rl.count, 0)
    71  			case <-rl.closeChan:
    72  				return
    73  			}
    74  		}
    75  	}()
    76  }
    77  
    78  func (rl *RateLimit) Add(count int64) {
    79  	rl.backServiceOnce.Do(rl.backService)
    80  	for {
    81  		if atomic.LoadInt64(&rl.count) >= rl.MaxRate { // 超出最大限额
    82  			// 阻塞
    83  			<-rl.muChan
    84  			continue
    85  		}
    86  		atomic.AddInt64(&rl.count, count)
    87  		break
    88  	}
    89  }