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 }