package bot import ( "context" "log/slog" "os" "os/signal" "slices" "syscall" "gitea.mrixs.me/Mrixs/yamusic-bot/internal/admin" "gitea.mrixs.me/Mrixs/yamusic-bot/internal/config" "gitea.mrixs.me/Mrixs/yamusic-bot/internal/interfaces" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) // App - главное приложение бота. type App struct { cfg *config.Config api *tgbotapi.BotAPI storage interfaces.TrackStorage adminHandler *admin.Handler inlineHandler *InlineHandler } // NewApp создает новый экземпляр приложения. func NewApp(cfg *config.Config, api *tgbotapi.BotAPI, storage interfaces.TrackStorage, adminHandler *admin.Handler, inlineHandler *InlineHandler) *App { return &App{ cfg: cfg, api: api, storage: storage, adminHandler: adminHandler, inlineHandler: inlineHandler, } } // Run запускает основной цикл бота. func (a *App) Run(ctx context.Context) { ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) defer cancel() u := tgbotapi.NewUpdate(0) u.Timeout = 60 updates := a.api.GetUpdatesChan(u) slog.Info("Bot is running and waiting for updates...") for { select { case update := <-updates: a.handleUpdate(ctx, update) case <-ctx.Done(): slog.Info("Shutting down...") a.api.StopReceivingUpdates() if err := a.storage.Close(); err != nil { slog.Error("Failed to close storage", "error", err) } return } } } func (a *App) handleUpdate(ctx context.Context, update tgbotapi.Update) { if update.InlineQuery != nil { go a.inlineHandler.HandleInlineQuery(ctx, update.InlineQuery) } else if update.Message != nil && update.Message.IsCommand() { if a.isAdmin(update.Message.From.ID) { go a.adminHandler.HandleCommand(ctx, update.Message) } else { slog.Warn("Unauthorized command attempt", "user_id", update.Message.From.ID) } } } func (a *App) isAdmin(userID int64) bool { return slices.Contains(a.cfg.TelegramAdminIDs, userID) }