initial Go port of streamrip

This commit is contained in:
2026-04-19 21:11:38 +02:00
commit 97e8b758b3
32 changed files with 7008 additions and 0 deletions

View 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
}
}

View 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")
}
}