diff --git a/go.mod b/go.mod index e1ca600..a55a615 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/stretchr/testify v1.7.1 go.uber.org/zap v1.21.0 golang.org/x/net v0.0.0-20220526153639-5463443f8c37 - golang.org/x/time v0.0.0-20220411224347-583f2d630306 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index 99f1552..967dfe2 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= -golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/limiter/limiter.go b/limiter/limiter.go new file mode 100644 index 0000000..d941992 --- /dev/null +++ b/limiter/limiter.go @@ -0,0 +1,47 @@ +package limiter + +import ( + "sync" + "time" +) + +type Limiter interface { + Wait() +} + +type limiter struct { + tick time.Duration + count uint + entries []time.Time + index uint + mutex sync.Mutex +} + +func NewLimiter(tick time.Duration, count uint) Limiter { + l := limiter{ + tick: tick, + count: count, + index: 0, + } + l.entries = make([]time.Time, count) + before := time.Now().Add(-2 * tick) + for i, _ := range l.entries { + l.entries[i] = before + } + return &l +} +func (l *limiter) Wait() { + l.mutex.Lock() + defer l.mutex.Unlock() + last := &l.entries[l.index] + next := last.Add(l.tick) + now := time.Now() + if now.Before(next) { + time.Sleep(next.Sub(now)) + } + *last = time.Now() + l.index = l.index + 1 + if l.index == l.count { + l.index = 0 + } +} diff --git a/telegram/telegram.go b/telegram/telegram.go index 635a564..256e7b0 100644 --- a/telegram/telegram.go +++ b/telegram/telegram.go @@ -2,7 +2,6 @@ package telegram import ( "bytes" - "context" "encoding/json" "errors" "fmt" @@ -11,8 +10,8 @@ import ( "net/url" "time" + "go.balki.me/tss/limiter" "go.balki.me/tss/log" - "golang.org/x/time/rate" ) type TelegramSender interface { @@ -22,8 +21,8 @@ type TelegramSender interface { type telegramSender struct { client *http.Client authToken string - rateLimiterPerMin *rate.Limiter - rateLimiterPerSec *rate.Limiter + rateLimiterPerMin limiter.Limiter + rateLimiterPerSec limiter.Limiter } func (ts *telegramSender) SendLink(link, channel, rhash, title string) error { @@ -47,15 +46,8 @@ func (ts *telegramSender) SendLink(link, channel, rhash, title string) error { apiUrl := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", ts.authToken) - err = ts.rateLimiterPerMin.Wait(context.TODO()) - if err != nil { - return err - } - - err = ts.rateLimiterPerSec.Wait(context.TODO()) - if err != nil { - return err - } + ts.rateLimiterPerMin.Wait() + ts.rateLimiterPerSec.Wait() res, err := ts.client.Post(apiUrl, "application/json", bytes.NewReader(data)) if err != nil { @@ -79,9 +71,9 @@ func NewTelegramSender(transport http.RoundTripper, authToken string) TelegramSe client: &http.Client{Transport: transport}, authToken: authToken, // 20 requests per min with some buffer - rateLimiterPerMin: rate.NewLimiter(rate.Every(65*time.Second), 20), + rateLimiterPerMin: limiter.NewLimiter(65*time.Second, 20), // 1 msg per sec with some buffer - rateLimiterPerSec: rate.NewLimiter(rate.Every(1050*time.Millisecond), 1), + rateLimiterPerSec: limiter.NewLimiter(1050*time.Millisecond, 1), } }