Files
2026-11-08 03:46:11 +00:00

112 lines
3.0 KiB
Go

package telegram
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
"git.entityseven.com/rilaxik/pllist/internal/service"
accesstelegram "git.entityseven.com/rilaxik/pllist/internal/telegram/access"
itemtelegram "git.entityseven.com/rilaxik/pllist/internal/telegram/item"
"git.entityseven.com/rilaxik/pllist/internal/telegram/list"
"git.entityseven.com/rilaxik/pllist/internal/telegram/menu"
sharetelegram "git.entityseven.com/rilaxik/pllist/internal/telegram/share"
"git.entityseven.com/rilaxik/pllist/internal/telegram/shared"
)
const (
shutdownTimeout = 10 * time.Second
updateTimeout = 30 * time.Second
)
type Bot struct {
api *telego.Bot
handler *th.BotHandler
logger *slog.Logger
users *service.UserService
botAccess *service.BotAccessService
shares *service.ShareService
pending *service.PendingStore
sender *shared.Sender
pendingRouter *shared.PendingRouter
menu *menu.Handler
access *accesstelegram.Handler
list *list.Handler
item *itemtelegram.Handler
share *sharetelegram.Handler
locker *keyedLocker
}
func New(
api *telego.Bot,
updates <-chan telego.Update,
users *service.UserService,
lists *service.ListService,
items *service.ItemService,
shares *service.ShareService,
access *service.AccessService,
botAccess *service.BotAccessService,
pending *service.PendingStore,
logger *slog.Logger,
) (*Bot, error) {
if logger == nil {
logger = slog.Default()
}
sender := shared.NewSender(api)
itemHandler := itemtelegram.New(sender, items, access, pending)
bot := &Bot{
api: api,
logger: logger,
users: users,
botAccess: botAccess,
shares: shares,
pending: pending,
sender: sender,
pendingRouter: shared.NewPendingRouter(),
menu: menu.New(sender, pending, botAccess),
access: accesstelegram.New(sender, botAccess),
list: list.New(sender, lists, access, pending, itemHandler),
item: itemHandler,
share: sharetelegram.New(sender, shares, pending),
locker: newKeyedLocker(),
}
handler, err := th.NewBotHandler(api, updates, th.WithErrorHandler(bot.handleError))
if err != nil {
return nil, fmt.Errorf("create bot handler: %w", err)
}
bot.handler = handler
handler.Use(
th.PanicRecoveryHandler(func(recovered any) error {
return fmt.Errorf("panic: %v", recovered)
}),
th.Timeout(updateTimeout),
bot.answerCallback,
bot.serialize,
bot.privateOnly,
bot.requireAccess,
bot.withUser,
)
bot.register()
return bot, nil
}
func (b *Bot) Run() error {
if err := b.handler.Start(); err != nil {
return fmt.Errorf("start bot handler: %w", err)
}
stopCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := b.handler.StopWithContext(stopCtx); err != nil {
return fmt.Errorf("stop bot handler: %w", err)
}
return nil
}