Overhaul the commands, again
--- a/discord/commands.go Mon Apr 08 18:55:23 2019 -0700
+++ b/discord/commands.go Mon Apr 08 22:52:18 2019 -0500
@@ -4,51 +4,34 @@
- "github.com/alecthomas/kong"
"github.com/bwmarrin/discordgo"
- log "github.com/sirupsen/logrus"
+ "github.com/iancoleman/orderedmap"
- UptimeCommand uptimeCommand `kong:"cmd,name='uptime'"`
- StatusCommand statusCommand `kong:"cmd,name='status'"`
- SetChannelCommand setChannelCommand `kong:"cmd,name='setchannel'"`
+type Command interface { + Run(args []string, c *DiscordClient, m *discordgo.MessageCreate) (interface{}, error) -func (c *DiscordClient) messageHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
- // ignore messages for ourselves
- if m.Author.ID == s.State.User.ID {
+ commands = orderedmap.New() - if !strings.HasPrefix(m.Content, c.mentionString) {
+ commands.Set("set-channel", &commandSetChannel{}) + commands.Set("status", &commandStatus{}) + commands.Set("uptime", &commandUptime{}) +func (c *DiscordClient) processCommand(args []string, m *discordgo.MessageCreate) (interface{}, error) { + return nil, fmt.Errorf("no command specified")
- parser, err := kong.New(
- kong.Exit(func(int) {}),
- c.sendChannel(m.ChannelID, "failed to parse command")
- log.Warnf("error creating parser: %v", err)
+ name := strings.ToLower(args[0]) + if cmd, found := commands.Get(name); found { + return cmd.(Command).Run(args[1:], c, m) - args := strings.Split(m.Content, " ")[1:]
- ctx, err := parser.Parse(args)
- c.sendChannel(m.ChannelID, "failed to parse command")
- log.Warnf("error parsing command: %#v : %v", args, err)
- c.sendChannel(m.ChannelID, fmt.Sprintf("%v", err))
- log.Debugf("finished running command: '%v'", err)
+ return "", fmt.Errorf("unknown command '%s'", args[0]) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/discord/messages.go Mon Apr 08 22:52:18 2019 -0500
@@ -0,0 +1,40 @@
+ "github.com/bwmarrin/discordgo" + log "github.com/sirupsen/logrus" +var splitRegex = regexp.MustCompile(`\s+`) +func (c *DiscordClient) messageHandler(s *discordgo.Session, m *discordgo.MessageCreate) { + // ignore messages for ourselves + if m.Author.ID == s.State.User.ID { + if !strings.HasPrefix(m.Content, c.mentionString) { + args := splitRegex.Split(m.Content, -1)[1:] + output, err := c.processCommand(args, m) + log.Warnf("error processing %#v: %v", m.Content, err) + output = fmt.Sprintf("error: %v", err) + c.sendChannel(m.ChannelID, output.(string)) + case *discordgo.MessageEmbed: + c.client.ChannelMessageSendEmbed(m.ChannelID, output.(*discordgo.MessageEmbed)) --- a/discord/presence.go Mon Apr 08 18:55:23 2019 -0700
+++ b/discord/presence.go Mon Apr 08 22:52:18 2019 -0500
@@ -44,35 +44,39 @@
func (c *DiscordClient) sendPresenceChannel(channelID string, presence presence.Presence) error {
_, err := c.client.ChannelMessageSendEmbed(
- &discordgo.MessageEmbed{
- Image: &discordgo.MessageEmbedImage{
- URL: presence.ProfileImageURL,
- Author: &discordgo.MessageEmbedAuthor{
- Name: fmt.Sprintf("%s is now live", presence.Username),
- Thumbnail: &discordgo.MessageEmbedThumbnail{
- URL: presence.ThumbnailURL,
- Fields: []*discordgo.MessageEmbedField{
- &discordgo.MessageEmbedField{
- &discordgo.MessageEmbedField{
- Value: humanize.Comma(presence.Viewers),
- &discordgo.MessageEmbedField{
- Value: presence.Language,
+ presenceEmbed(presence), +func presenceEmbed(presence presence.Presence) *discordgo.MessageEmbed { + return &discordgo.MessageEmbed{ + Image: &discordgo.MessageEmbedImage{ + URL: presence.ProfileImageURL, + Author: &discordgo.MessageEmbedAuthor{ + Name: fmt.Sprintf("%s is now live", presence.Username), + Thumbnail: &discordgo.MessageEmbedThumbnail{ + URL: presence.ThumbnailURL, + Fields: []*discordgo.MessageEmbedField{ + &discordgo.MessageEmbedField{ + &discordgo.MessageEmbedField{ + Value: humanize.Comma(presence.Viewers), + &discordgo.MessageEmbedField{ + Value: presence.Language, --- a/discord/set_channel_command.go Mon Apr 08 18:55:23 2019 -0700
+++ b/discord/set_channel_command.go Mon Apr 08 22:52:18 2019 -0500
@@ -6,15 +6,14 @@
"github.com/bwmarrin/discordgo"
-type setChannelCommand struct {
- //Channel string `kong:"required,name='channel'"`
+type commandSetChannel struct{} +func (cmd *commandSetChannel) Help() string { + return "sets the channel to send automatic announcements to" -func (cmd *setChannelCommand) Run(c *DiscordClient, m *discordgo.MessageCreate) error {
+func (cmd *commandSetChannel) Run(args []string, c *DiscordClient, m *discordgo.MessageCreate) (interface{}, error) { c.db.SetChannel(m.GuildID, m.ChannelID)
- fmt.Sprintf("Set <#%s> as the announcement channel", m.ChannelID),
+ return fmt.Sprintf("Set <#%s> as the announcement channel", m.ChannelID), nil --- a/discord/status_command.go Mon Apr 08 18:55:23 2019 -0700
+++ b/discord/status_command.go Mon Apr 08 22:52:18 2019 -0500
@@ -5,21 +5,27 @@
"github.com/bwmarrin/discordgo"
- log "github.com/sirupsen/logrus"
"bitbucket.org/TheToyz/nowdead/presence"
-type statusCommand struct {
- Target string `kong:"arg,required,name='target'"`
+type commandStatus struct{} +func (cmd *commandStatus) Help() string { + return "get the streaming status of a target" -func (cmd *statusCommand) Run(c *DiscordClient, m *discordgo.MessageCreate) error {
- log.Debug("running status command")
+func (cmd *commandStatus) Run(args []string, c *DiscordClient, m *discordgo.MessageCreate) (interface{}, error) { - if strings.HasPrefix(cmd.Target, "<@") {
- mentionID := cmd.Target[2 : len(cmd.Target)-1]
+ return nil, fmt.Errorf("invalid target") + if strings.HasPrefix(target, "<@") { + mentionID := target[2 : len(target)-1] for _, mentioned := range m.Mentions {
if mentioned.ID == mentionID {
@@ -28,18 +34,18 @@
if p != nil && p.Game != nil && p.Game.Type == discordgo.GameTypeStreaming {
- return fmt.Errorf("%s is not streaming", cmd.Target)
+ return nil, fmt.Errorf("%s is not streaming", target) - uri = "https://twitch.tv/" + cmd.Target
+ uri = "https://twitch.tv/" + target presence, err := presence.GetPresence(uri)
- return c.sendPresenceChannel(m.ChannelID, presence)
+ return presenceEmbed(presence), nil --- a/discord/uptime_command.go Mon Apr 08 18:55:23 2019 -0700
+++ b/discord/uptime_command.go Mon Apr 08 22:52:18 2019 -0500
@@ -7,11 +7,12 @@
"github.com/dustin/go-humanize"
-type uptimeCommand struct{}
+type commandUptime struct{} -func (cmd *uptimeCommand) Run(c *DiscordClient, m *discordgo.MessageCreate) error {
- fmt.Sprintf("Started %s", humanize.Time(c.started)),
+func (cmd *commandUptime) Help() string { + return "the amount of time the bot has been running" +func (cmd *commandUptime) Run(args []string, c *DiscordClient, m *discordgo.MessageCreate) (interface{}, error) { + return fmt.Sprintf("Started %s", humanize.Time(c.started)), nil --- a/go.mod Mon Apr 08 18:55:23 2019 -0700
+++ b/go.mod Mon Apr 08 22:52:18 2019 -0500
@@ -10,6 +10,7 @@
github.com/bwmarrin/discordgo v0.19.0
github.com/dustin/go-humanize v1.0.0
github.com/go-redis/redis v6.15.2+incompatible
+ github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 github.com/nicklaw5/helix v0.5.1
github.com/nicksnyder/go-i18n v1.10.0 // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
--- a/go.sum Mon Apr 08 18:55:23 2019 -0700
+++ b/go.sum Mon Apr 08 22:52:18 2019 -0500
@@ -36,6 +36,8 @@
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= +github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=