feat: initial commit

This commit is contained in:
2026-04-16 19:39:02 +02:00
commit 50d1686b1e
44 changed files with 2089 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
package telegram
import (
"context"
"fmt"
"log/slog"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
type BotGateway struct {
bot *tgbotapi.BotAPI
logger *slog.Logger
}
func NewBotGateway(bot *tgbotapi.BotAPI, logger *slog.Logger) *BotGateway {
return &BotGateway{bot: bot, logger: logger}
}
func (g *BotGateway) SendText(ctx context.Context, chatID int64, text string) error {
msg := tgbotapi.NewMessage(chatID, text)
msg.ParseMode = tgbotapi.ModeMarkdown
_, err := g.bot.Send(msg)
if err != nil {
return fmt.Errorf("telegram send text: %w", err)
}
return nil
}
func (g *BotGateway) SendTyping(ctx context.Context, chatID int64) error {
action := tgbotapi.NewChatAction(chatID, tgbotapi.ChatTyping)
_, err := g.bot.Request(action)
if err != nil {
g.logger.WarnContext(ctx, "failed to send typing action", "error", err, "chat_id", chatID)
}
return nil
}

View File

@@ -0,0 +1,48 @@
package telegram
import (
"context"
"fmt"
"io"
"net/http"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
type TelegramFileDownloader struct {
bot *tgbotapi.BotAPI
client *http.Client
}
func NewTelegramFileDownloader(bot *tgbotapi.BotAPI) *TelegramFileDownloader {
return &TelegramFileDownloader{
bot: bot,
client: &http.Client{},
}
}
func (d *TelegramFileDownloader) Download(ctx context.Context, fileID string) ([]byte, string, error) {
file, err := d.bot.GetFile(tgbotapi.FileConfig{FileID: fileID})
if err != nil {
return nil, "", fmt.Errorf("get file info: %w", err)
}
url := file.Link(d.bot.Token)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, "", fmt.Errorf("create download request: %w", err)
}
resp, err := d.client.Do(req)
if err != nil {
return nil, "", fmt.Errorf("download file: %w", err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, "", fmt.Errorf("read file body: %w", err)
}
return data, "audio/ogg", nil
}

View File

@@ -0,0 +1,50 @@
package telegram
import (
"context"
"log/slog"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
type UpdateHandler interface {
Handle(ctx context.Context, update tgbotapi.Update)
}
type UpdatePoller struct {
bot *tgbotapi.BotAPI
handler UpdateHandler
logger *slog.Logger
timeout int
}
func NewUpdatePoller(bot *tgbotapi.BotAPI, handler UpdateHandler, logger *slog.Logger) *UpdatePoller {
return &UpdatePoller{
bot: bot,
handler: handler,
logger: logger,
timeout: 60,
}
}
func (p *UpdatePoller) Start(ctx context.Context) error {
u := tgbotapi.NewUpdate(0)
u.Timeout = p.timeout
updates := p.bot.GetUpdatesChan(u)
p.logger.InfoContext(ctx, "update poller started")
for {
select {
case <-ctx.Done():
p.bot.StopReceivingUpdates()
p.logger.InfoContext(ctx, "update poller stopped")
return ctx.Err()
case update, ok := <-updates:
if !ok {
return nil
}
go p.handler.Handle(ctx, update)
}
}
}