Files
yamusic-bot/internal/bot/telegram.go
Vladimir Zagainov 1852c5025e
All checks were successful
continuous-integration/drone/push Build is passing
add rate limiter to telegram
2025-06-24 12:40:42 +03:00

88 lines
3.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package bot
import (
"context"
"fmt"
"log/slog"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"golang.org/x/time/rate"
)
// TelegramClientAdapter адаптирует библиотеку tgbotapi под наш интерфейс interfaces.TelegramClient.
type TelegramClientAdapter struct {
api *tgbotapi.BotAPI
cacheChatID int64
fastLimiter *rate.Limiter // Для общих быстрых запросов
cacheLimiter *rate.Limiter // Для медленных запросов в кэш-канал
}
// NewTelegramClientAdapter создает новый адаптер.
func NewTelegramClientAdapter(api *tgbotapi.BotAPI, cacheChatID int64, fastLimiter, cacheLimiter *rate.Limiter) *TelegramClientAdapter {
return &TelegramClientAdapter{
api: api,
cacheChatID: cacheChatID,
fastLimiter: fastLimiter,
cacheLimiter: cacheLimiter,
}
}
// SendAudioToCacheChannel загружает аудиофайл в кэш-канал и возвращает его FileID.
// ИСПОЛЬЗУЕТ МЕДЛЕННЫЙ ЛИМИТЕР.
func (t *TelegramClientAdapter) SendAudioToCacheChannel(ctx context.Context, audioPath, title, performer string) (string, error) {
// Ждем, пока МЕДЛЕННЫЙ лимитер разрешит выполнить запрос
if err := t.cacheLimiter.Wait(ctx); err != nil {
return "", err
}
audio := tgbotapi.NewAudio(t.cacheChatID, tgbotapi.FilePath(audioPath))
audio.Title = title
audio.Performer = performer
msg, err := t.api.Send(audio)
if err != nil {
return "", fmt.Errorf("failed to send audio to cache channel: %w", err)
}
if msg.Audio == nil {
return "", fmt.Errorf("sent message does not contain audio")
}
slog.Debug("Audio sent to cache channel", "file_id", msg.Audio.FileID)
return msg.Audio.FileID, nil
}
// AnswerInlineQuery отвечает на inline-запрос.
// ИСПОЛЬЗУЕТ БЫСТРЫЙ ЛИМИТЕР.
func (t *TelegramClientAdapter) AnswerInlineQuery(ctx context.Context, queryID string, results []interface{}) error {
// Ждем, пока БЫСТРЫЙ лимитер разрешит выполнить запрос
if err := t.fastLimiter.Wait(ctx); err != nil {
return err
}
inlineConfig := tgbotapi.InlineConfig{
InlineQueryID: queryID,
Results: results,
CacheTime: 1,
}
if _, err := t.api.Request(inlineConfig); err != nil {
return fmt.Errorf("failed to answer inline query: %w", err)
}
return nil
}
// SendMessage отправляет текстовое сообщение.
// ИСПОЛЬЗУЕТ БЫСТРЫЙ ЛИМИТЕР.
func (t *TelegramClientAdapter) SendMessage(ctx context.Context, chatID int64, text string) error {
// Ждем, пока БЫСТРЫЙ лимитер разрешит выполнить запрос
if err := t.fastLimiter.Wait(ctx); err != nil {
return err
}
msg := tgbotapi.NewMessage(chatID, text)
if _, err := t.api.Send(msg); err != nil {
return fmt.Errorf("failed to send message: %w", err)
}
return nil
}