mirror of
https://git.sr.ht/~joren/streamrip-go
synced 2026-06-17 15:05:39 +02:00
initial Go port of streamrip
This commit is contained in:
54
internal/ratelimit/limiter.go
Normal file
54
internal/ratelimit/limiter.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Limiter struct {
|
||||
interval time.Duration
|
||||
|
||||
mu sync.Mutex
|
||||
next time.Time
|
||||
}
|
||||
|
||||
func New(requestsPerMinute int) *Limiter {
|
||||
if requestsPerMinute <= 0 {
|
||||
return &Limiter{}
|
||||
}
|
||||
return &Limiter{interval: time.Minute / time.Duration(requestsPerMinute)}
|
||||
}
|
||||
|
||||
func (l *Limiter) Wait(ctx context.Context) error {
|
||||
if l.interval <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
l.mu.Lock()
|
||||
now := time.Now()
|
||||
if l.next.IsZero() {
|
||||
l.next = now.Add(l.interval)
|
||||
l.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
wake := l.next
|
||||
if now.After(wake) {
|
||||
l.next = now.Add(l.interval)
|
||||
l.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
l.next = l.next.Add(l.interval)
|
||||
l.mu.Unlock()
|
||||
|
||||
timer := time.NewTimer(time.Until(wake))
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-timer.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
28
internal/ratelimit/limiter_test.go
Normal file
28
internal/ratelimit/limiter_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package ratelimit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLimiterDisabled(t *testing.T) {
|
||||
l := New(-1)
|
||||
if err := l.Wait(context.Background()); err != nil {
|
||||
t.Fatalf("Wait() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimiterContextCancel(t *testing.T) {
|
||||
l := New(1)
|
||||
if err := l.Wait(context.Background()); err != nil {
|
||||
t.Fatalf("first Wait() error = %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
if err := l.Wait(ctx); err == nil {
|
||||
t.Fatalf("expected context error")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user