Projeto bot pontos
This commit is contained in:
76
backend/internal/bot/runner.go
Normal file
76
backend/internal/bot/runner.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package bot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"botpontos/internal/adapters/telegram"
|
||||
)
|
||||
|
||||
// Runner faz o long polling do Telegram e responde cada mensagem.
|
||||
type Runner struct {
|
||||
client *telegram.Client
|
||||
router *Router
|
||||
log *slog.Logger
|
||||
pollTimeout int
|
||||
}
|
||||
|
||||
func NewRunner(client *telegram.Client, router *Router, log *slog.Logger, pollTimeout int) *Runner {
|
||||
return &Runner{client: client, router: router, log: log, pollTimeout: pollTimeout}
|
||||
}
|
||||
|
||||
// Run roda até o contexto ser cancelado. Erros de rede não derrubam o
|
||||
// worker: o loop espera alguns segundos e tenta de novo.
|
||||
func (r *Runner) Run(ctx context.Context) {
|
||||
var offset int64
|
||||
backoff := time.Second
|
||||
r.log.Info("bot do Telegram iniciado")
|
||||
for ctx.Err() == nil {
|
||||
updates, err := r.client.GetUpdates(ctx, offset, r.pollTimeout)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
r.log.Warn("falha no getUpdates do Telegram", "error", err, "retry_in", backoff.String())
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(backoff):
|
||||
}
|
||||
if backoff < 30*time.Second {
|
||||
backoff *= 2
|
||||
}
|
||||
continue
|
||||
}
|
||||
backoff = time.Second
|
||||
|
||||
for _, update := range updates {
|
||||
offset = update.UpdateID + 1
|
||||
msg := update.Message
|
||||
// Só conversas privadas: o bot trata dados pessoais de jornada.
|
||||
if msg == nil || msg.Text == "" || (msg.Chat.Type != "" && msg.Chat.Type != "private") {
|
||||
continue
|
||||
}
|
||||
r.handle(ctx, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Runner) handle(ctx context.Context, msg *telegram.Message) {
|
||||
defer func() {
|
||||
if v := recover(); v != nil {
|
||||
r.log.Error("panic ao tratar mensagem do Telegram", "panic", v)
|
||||
}
|
||||
}()
|
||||
handleCtx, cancel := context.WithTimeout(ctx, 45*time.Second)
|
||||
defer cancel()
|
||||
|
||||
reply := r.router.Handle(handleCtx, msg.Chat.ID, msg.From.Name(), msg.Text)
|
||||
if reply == "" {
|
||||
return
|
||||
}
|
||||
if _, err := r.client.Send(ctx, msg.Chat.ID, reply); err != nil {
|
||||
r.log.Warn("falha ao responder no Telegram", "error", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user