package discord import ( "errors" "fmt" "log" "os" "os/signal" "ticket-pimp/client/discord/router" "ticket-pimp/internal/controller" "ticket-pimp/internal/domain" "github.com/bwmarrin/discordgo" ) func initBotWith(token string) *discordgo.Session { discord, err := discordgo.New("Bot " + token) if err != nil { log.Fatalf("unable to create discord session: %v", err) } return discord } type DiscordOptions struct { Config *domain.Config Controller *controller.WorkflowController } func checkPrivateMessaging(s *discordgo.Session, i *discordgo.InteractionCreate) error { // Моментальный ответ для избежания столкновения с протуханием токена initialResponse := discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Flags: discordgo.MessageFlagsEphemeral, Content: "👩‍🍳 Cooking your query..", }, } s.InteractionRespond(i.Interaction, &initialResponse) dchan, err := s.Channel(i.ChannelID) if err != nil { return err } if dchan.Type == discordgo.ChannelTypeDM { s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: "Yo, fella! I'm not working in private!", }, }) return errors.New("no private messages! lol") } return nil } func Run(conf domain.Config, opts DiscordOptions) error { token := conf.Discord.Token s := initBotWith(token) router := router.InitRouter(*opts.Controller, &conf.Discord, &conf.Telegram) commandHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){} for _, handler := range router.Commands { commandHandlers[handler.Command.Name] = handler.Handler } componentsHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ "task_start": router.Components[0].Handler, "task_close": router.Components[0].Handler, } s.AddHandler(router.ListenPosts) s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) { err := checkPrivateMessaging(s, i) if err != nil { return } switch i.Type { case discordgo.InteractionApplicationCommand: if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok { h(s, i) } case discordgo.InteractionMessageComponent: if h, ok := componentsHandlers[i.MessageComponentData().CustomID]; ok { h(s, i) } } }) if err := s.Open(); err != nil { return fmt.Errorf("cannot open the session: %v", err) } // UPDATE FORUM IF NEEDED: forum, err := s.Channel(conf.Discord.IsTaskForum) if err != nil { log.Print(err) } tagsAvailable := []discordgo.ForumTag{ { Name: "В работе", Moderated: true, EmojiName: "👩‍🍳", }, { Name: "Готово", Moderated: true, EmojiName: "✅", }, } dchan, err := s.ChannelEditComplex(forum.ID, &discordgo.ChannelEdit{ AvailableTags: &tagsAvailable, }) if err != nil { log.Fatal(err) } log.Printf("Channel %s with ID %s propagated by tags:", dchan.Name, dchan.ID) for _, t := range dchan.AvailableTags { log.Printf("N: %s, ID: %s", t.Name, t.ID) } log.Println("Adding commands...") var cmds []*discordgo.ApplicationCommand var logString []string for _, h := range router.Commands { cmd, err := s.ApplicationCommandCreate(s.State.User.ID, "", &h.Command) if err != nil { log.Panicf("Cannot create '%v' command: %v", h.Command.Name, err) } cmds = append(cmds, cmd) logString = append(logString, cmd.Name) } log.Println("Following commands added:") log.Println(logString) defer s.Close() stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt) <-stop log.Println("Graceful shutdown") log.Println("Removing commands...") for _, h := range cmds { err := s.ApplicationCommandDelete(s.State.User.ID, "", h.ID) if err != nil { log.Panicf("Cannot delete '%v' command: %v", h.Name, err) } } return nil }