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 }