package main import ( "os" "regexp" "strings" "time" "github.com/NicoNex/echotron/v3" "github.com/TelegramExchange/tgex-backend/tg_bot/backend" "github.com/TelegramExchange/tgex-backend/tg_bot/bot" "github.com/TelegramExchange/tgex-backend/tg_bot/screens" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) var botCommands = []echotron.BotCommand{ {Command: "start", Description: "Главное меню"}, {Command: "projects", Description: "Мои проекты"}, {Command: "placements", Description: "Размещения"}, {Command: "platform", Description: "Веб-платформа"}, {Command: "help", Description: "Помощь"}, } func main() { initLogger() botToken := mustEnv("TELEGRAM__TOKEN") backendClient := backend.New(backend.Config{ BaseURL: mustEnv("BACKEND__BASE_URL"), LoginURL: mustEnv("LOGIN_URL"), }) // Регистрируем команды бота в Telegram api := echotron.NewAPI(botToken) if me, err := api.GetMe(); err != nil { log.Error().Err(err).Msg("Failed to get bot profile") } else if me.Result != nil { bot.SetUsername(me.Result.Username) log.Info().Str("username", me.Result.Username).Msg("Telegram bot authorized") } if _, err := api.SetMyCommands(nil, botCommands...); err != nil { log.Error().Err(err).Msg("Failed to set bot commands") } else { log.Info().Msg("Bot commands registered successfully") } var commandRouter = func(command string) bot.State { createCreativeRe := regexp.MustCompile(`^/start project_(.+)_createcreative$`) switch { case command == "/start": return &screens.MainMenu{} case command == "/start login": return &screens.Login{} case command == "/projects": return &screens.MyProjects{BackState: &screens.MainMenu{}} case command == "/placements": return &screens.MyProjects{BackState: &screens.MainMenu{}, OpenPlacements: true} case command == "/platform": return &screens.PlatformLink{} case command == "/help": return &screens.Help{} case createCreativeRe.MatchString(command): projectID := createCreativeRe.FindStringSubmatch(command)[1] return &screens.AddCreativeStart{Ctx: &screens.AddCreativeCtx{ ProjectID: projectID, BackState: &screens.MainMenu{}, }} } panic("Unknown command: " + command) } var handleGlobalCallback = func(callbackData string) bot.State { id, ok := strings.CutPrefix(callbackData, "pending_channel:") if ok { return &screens.SelectWorkspace{ChannelID: id, BackState: &screens.MainMenu{}} } id, ok = strings.CutPrefix(callbackData, "workspace_invite_accept:") if ok { return &screens.AcceptWorkspaceInvite{InviteID: id} } return nil } newBot := func(chatID int64) echotron.Bot { return bot.NewBot(chatID, botToken, commandRouter, backendClient, handleGlobalCallback) } dsp := echotron.NewDispatcher(botToken, newBot) updateOpts := echotron.UpdateOptions{ AllowedUpdates: []echotron.UpdateType{ echotron.MessageUpdate, echotron.CallbackQueryUpdate, echotron.MyChatMemberUpdate, echotron.ChatMemberUpdate, echotron.UpdateType("chat_join_request"), }, } echotron.SetChatRequestLimit(0, 0) for { err := dsp.PollOptions(false, updateOpts) if err != nil { log.Error().Err(err).Msg("dsp.Poll failed, retrying in 5 seconds...") time.Sleep(5 * time.Second) continue } break } } func initLogger() { zerolog.TimeFieldFormat = time.RFC3339 level := zerolog.InfoLevel if parsedLevel, err := zerolog.ParseLevel(os.Getenv("LOGGER__LEVEL")); err == nil { level = parsedLevel } zerolog.SetGlobalLevel(level) log.Logger = zerolog.New(os.Stdout).With().Timestamp().Logger().Level(level) prettyConsole := os.Getenv("LOGGER__PRETTY_CONSOLE") if prettyConsole == "" { prettyConsole = "true" } if prettyConsole == "true" { log.Logger = zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05"}). With(). Timestamp(). Logger(). Level(level) } log.Info().Msg("Logger initialized") } func mustEnv(key string) string { v := os.Getenv(key) if v == "" { log.Fatal().Str("env", key).Msg("missing required environment variable") } return v }