From 759eb07e405f9fa3dc0a23e88c957bdcf1748236 Mon Sep 17 00:00:00 2001 From: Marc Egerton Date: Mon, 4 May 2020 23:03:11 +0100 Subject: [PATCH] Main/Features: Overhaul handling of commands. Since the bot has grown to do more than just usercolor roles, the switch statement for the user-requested command has grown a lot. In order to reduce code duplication and just look better, we'll use a map of command names that have handler functions we call instead. --- cmd/main.go | 26 ++--- features/handlers.go | 246 +++++++++--------------------------------- features/helpers.go | 7 +- features/usercolor.go | 8 +- 4 files changed, 70 insertions(+), 217 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index a5c3839..572dce8 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -3,7 +3,6 @@ package main import ( "encoding/json" "flag" - "fmt" "github.com/foxtrot/scuzzy/auth" "github.com/foxtrot/scuzzy/features" "github.com/foxtrot/scuzzy/models" @@ -45,34 +44,34 @@ func main() { flag.Parse() if len(Token) == 0 { - log.Fatal("Error: No Auth Token supplied.") + log.Fatal("[!] Error: No Auth Token supplied.") } if len(ConfigPath) == 0 { - log.Fatal("Error: No Config Path supplied.") + log.Fatal("[!] Error: No Config Path supplied.") } // Get Config err := getConfig() if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } // Instantiate Bot bot, err := discordgo.New("Bot " + Token) if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } // Open Connection err = bot.Open() if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } // Setup Auth Config.Guild, err = bot.Guild(Config.GuildID) if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } var a *auth.Auth a = auth.New(&Config, Config.Guild) @@ -85,10 +84,11 @@ func main() { } // Register Handlers - bot.AddHandler(f.OnMessageCreate) - bot.AddHandler(f.OnUserJoin) + f.RegisterHandlers() + bot.AddHandler(f.ProcessCommand) + bot.AddHandler(f.ProcessUserJoin) - fmt.Println("Bot Running.") + log.Printf("[*] Bot Running.\n") // Set Bot Status go func() { @@ -110,14 +110,14 @@ func main() { } err = bot.UpdateStatusComplex(usd) if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } // For some reason the bot's status will regularly disappear... for _ = range time.Tick(10 * time.Minute) { err := bot.UpdateStatusComplex(usd) if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } } }() @@ -129,6 +129,6 @@ func main() { err = bot.Close() if err != nil { - log.Fatal("Error: " + err.Error()) + log.Fatal("[!] Error: " + err.Error()) } } diff --git a/features/handlers.go b/features/handlers.go index 6f73551..c758992 100644 --- a/features/handlers.go +++ b/features/handlers.go @@ -6,222 +6,80 @@ import ( "strings" ) -func (f *Features) OnMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { - var err error +type commandHandler func(session *discordgo.Session, m *discordgo.MessageCreate) error +var commandHandlers = make(map[string]commandHandler) + +func (f *Features) RegisterCommand(name string, handlerFunc commandHandler) { + log.Printf("[*] Registering Command '%s'\n", name) + commandHandlers[name] = handlerFunc +} + +func (f *Features) RegisterHandlers() { + // Misc Commands + f.RegisterCommand("help", f.handleHelp) + f.RegisterCommand("info", f.handleInfo) + f.RegisterCommand("md", f.handleMarkdownInfo) + f.RegisterCommand("userinfo", f.handleUserInfo) + f.RegisterCommand("serverinfo", f.handleServerInfo) + f.RegisterCommand("no", f.handleCat) + + // User Settings + f.RegisterCommand("colors", f.handleUserColors) + f.RegisterCommand("color", f.handleUserColor) + + // Conversion Helpers + f.RegisterCommand("ctof", f.handleCtoF) + f.RegisterCommand("ftoc", f.handleFtoC) + f.RegisterCommand("metofe", f.handleMetersToFeet) + f.RegisterCommand("fetome", f.handleFeetToMeters) + f.RegisterCommand("cmtoin", f.handleCentimeterToInch) + f.RegisterCommand("intocm", f.handleInchToCentimeter) + + // Admin Commands + f.RegisterCommand("ping", f.handlePing) + f.RegisterCommand("status", f.handleSetStatus) + f.RegisterCommand("purge", f.handlePurgeChannel) +} + +func (f *Features) ProcessCommand(s *discordgo.Session, m *discordgo.MessageCreate) { cKey := f.Config.CommandKey - cName := strings.Split(m.Content, " ")[0] + cCmd := strings.Split(m.Content, " ")[0] // Ignore the bot itself if m.Author.ID == s.State.User.ID { return } + // Ignore anything not starting with the command prefix + if !strings.HasPrefix(cCmd, cKey) { + return + } + + // Ignore Direct Messages if m.Member == nil { - log.Printf("[*] User %s was ignored in direct message.\n", m.Author.Username) return } - if !strings.HasPrefix(cName, cKey) { - return - } + cName := strings.Split(cCmd, cKey)[1] - log.Printf("[*] User %s tried command: %s\n", m.Author.Username, cName) + if cmdFunc, ok := commandHandlers[cName]; ok { + log.Printf("[*] Running command %s (Requested by %s)\n", cName, m.Author.Username) - switch cName { - /* Misc Commands */ - case cKey + "help": - err = f.handleHelp(s, m) + err := cmdFunc(s, m) if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Help)", err.Error(), "error", m.Author) + log.Printf("[*] Command %s (Requested by %s) had error: '%s'\n", cName, m.Author.Username, err.Error()) + + eMsg := f.CreateDefinedEmbed("Error ("+cName+")", err.Error(), "error", m.Author) _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) if err != nil { - log.Fatal(err.Error()) + log.Fatal(err) } - return } - break - case cKey + "info": - err = f.handleInfo(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Info)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "ping": - err = f.handlePing(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Ping)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "no": - err = f.handleCat(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (No)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "md": - err = f.handleMarkdownInfo(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Markdown)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "ctof": - err = f.handleCtoF(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (CtoF)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "ftoc": - err = f.handleFtoC(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (FtoC)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "metofe": - err = f.handleMetersToFeet(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Meters to Feet)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "fetome": - err = f.handleFeetToMeters(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Feet to Meters)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "cmtoin": - err = f.handleCentimeterToInch(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Meters to Feet)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "intocm": - err = f.handleInchToCentimeter(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Feet to Meters)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "userinfo": - err = f.handleUserInfo(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (User Info)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "serverinfo": - err = f.handleServerInfo(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Server Info)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - /* Moderation */ - case cKey + "purge": - err = f.handlePurgeChannel(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Purge)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - /* Bot Control */ - case cKey + "status": - err = f.handleSetStatus(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Status)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - /* Role Colors */ - case cKey + "colors": - err = f.listUserColors(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Colors)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break - case cKey + "color": - err = f.setUserColor(s, m) - if err != nil { - eMsg := f.CreateDefinedEmbed("Error (Color)", err.Error(), "error", m.Author) - _, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg) - if err != nil { - log.Fatal(err.Error()) - } - return - } - break } } -func (f *Features) OnUserJoin(s *discordgo.Session, m *discordgo.GuildMemberAdd) { +func (f *Features) ProcessUserJoin(s *discordgo.Session, m *discordgo.GuildMemberAdd) { userChannel, err := s.UserChannelCreate(m.User.ID) if err != nil { log.Print("Error (User Join): " + err.Error()) diff --git a/features/helpers.go b/features/helpers.go index 2d78f1e..d355134 100644 --- a/features/helpers.go +++ b/features/helpers.go @@ -1,16 +1,11 @@ package features import ( - "fmt" - discordgo "github.com/bwmarrin/discord.go" + "github.com/bwmarrin/discord.go" "github.com/foxtrot/scuzzy/models" "time" ) -func (f *Features) PrintError(component string, error string) { - fmt.Printf("Error: %s: %s\n", component, error) -} - func (f *Features) CreateDefinedEmbed(title string, desc string, status string, user *discordgo.User) *discordgo.MessageEmbed { msgColor := 0x000000 diff --git a/features/usercolor.go b/features/usercolor.go index 4ec2449..c1d7059 100644 --- a/features/usercolor.go +++ b/features/usercolor.go @@ -6,7 +6,7 @@ import ( "strings" ) -func (f *Features) listUserColors(s *discordgo.Session, m *discordgo.MessageCreate) error { +func (f *Features) handleUserColors(s *discordgo.Session, m *discordgo.MessageCreate) error { if !f.Auth.CheckCommandRestrictions(m) { return errors.New("This command is not allowed in this channel.") } @@ -27,7 +27,7 @@ func (f *Features) listUserColors(s *discordgo.Session, m *discordgo.MessageCrea return nil } -func (f *Features) setUserColor(s *discordgo.Session, m *discordgo.MessageCreate) error { +func (f *Features) handleUserColor(s *discordgo.Session, m *discordgo.MessageCreate) error { var err error if !f.Auth.CheckCommandRestrictions(m) { @@ -38,7 +38,7 @@ func (f *Features) setUserColor(s *discordgo.Session, m *discordgo.MessageCreate userInput := strings.Split(m.Content, " ") if len(userInput) < 2 { - err = f.listUserColors(s, m) + err = f.handleUserColors(s, m) return err } roleColorName := userInput[1] @@ -51,7 +51,7 @@ func (f *Features) setUserColor(s *discordgo.Session, m *discordgo.MessageCreate } } if len(roleColorID) == 0 { - err = f.listUserColors(s, m) + err = f.handleUserColors(s, m) return err }