From 39fec05ff493f9136fddc187e60e00e5efd35275 Mon Sep 17 00:00:00 2001 From: Ryan Cavicchioni Date: Sat, 24 Sep 2022 21:43:10 -0500 Subject: [PATCH] Refactored handlers and command handlers --- bot/bot.go | 122 ++++++++++++++++++++++++++--------- bot/coin.go | 31 --------- bot/command.go | 91 -------------------------- bot/ping.go | 12 ---- bot/reaction.go | 52 --------------- bot/rps.go | 36 ----------- bot/rpsls.go | 36 ----------- bot/time.go | 36 ----------- bot/version.go | 25 ------- bot/weather.go | 56 ---------------- command/coin.go | 29 +++++++++ command/commands.go | 11 ++++ {bot => command}/deal.go | 46 +++++++------ {bot => command}/dice.go | 40 ++++++------ command/ping.go | 10 +++ {bot => command}/roulette.go | 28 ++++---- command/router.go | 34 ++++++++++ command/rps.go | 34 ++++++++++ command/rpsls.go | 34 ++++++++++ command/time.go | 34 ++++++++++ command/version.go | 23 +++++++ command/weather.go | 54 ++++++++++++++++ handler/command.go | 1 + handler/handlers.go | 15 +++++ handler/reaction.go | 50 ++++++++++++++ 25 files changed, 474 insertions(+), 466 deletions(-) delete mode 100644 bot/coin.go delete mode 100644 bot/command.go delete mode 100644 bot/ping.go delete mode 100644 bot/reaction.go delete mode 100644 bot/rps.go delete mode 100644 bot/rpsls.go delete mode 100644 bot/time.go delete mode 100644 bot/version.go delete mode 100644 bot/weather.go create mode 100644 command/coin.go create mode 100644 command/commands.go rename {bot => command}/deal.go (62%) rename {bot => command}/dice.go (70%) create mode 100644 command/ping.go rename {bot => command}/roulette.go (63%) create mode 100644 command/router.go create mode 100644 command/rps.go create mode 100644 command/rpsls.go create mode 100644 command/time.go create mode 100644 command/version.go create mode 100644 command/weather.go create mode 100644 handler/command.go create mode 100644 handler/handlers.go create mode 100644 handler/reaction.go diff --git a/bot/bot.go b/bot/bot.go index d17d42d..9b515bc 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -7,7 +7,9 @@ import ( "os/signal" "syscall" + "git.kill0.net/chill9/beepboop/command" "git.kill0.net/chill9/beepboop/config" + "git.kill0.net/chill9/beepboop/handler" "git.kill0.net/chill9/beepboop/lib" "github.com/bwmarrin/discordgo" log "github.com/sirupsen/logrus" @@ -19,10 +21,19 @@ var C *config.Config type ( Bot struct { - Session *discordgo.Session - Config *config.Config + config *config.Config + session *discordgo.Session + commands map[string]*Command } + Command struct { + Name string + Func CommandFunc + NArgs int + } + + CommandFunc func(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error + MessageHandler func(s *discordgo.Session, m *discordgo.MessageCreate) ) @@ -33,60 +44,110 @@ func init() { viper.BindPFlags(pflag.CommandLine) } -func NewBot(s *discordgo.Session, config *config.Config) *Bot { - return &Bot{Session: s, Config: config} +func NewBot(config *config.Config, s *discordgo.Session) *Bot { + return &Bot{ + session: s, + commands: make(map[string]*Command), + } } -func (b *Bot) RegisterCommands() { - AddCommand(&Command{ +func (b *Bot) AddHandler(handler interface{}) func() { + return b.session.AddHandler(handler) +} + +func (b *Bot) AddCommand(cmd *Command) { + b.commands[cmd.Name] = cmd +} + +func (b *Bot) GetCommand(name string) (*Command, bool) { + cmd, ok := b.commands[name] + return cmd, ok +} + +func (b *Bot) CommandHandler(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == s.State.User.ID { + return + } + + if !lib.HasCommand(m.Content, b.config.Prefix) { + return + } + + cmdName, arg := lib.SplitCommandAndArg(m.Content, b.config.Prefix) + + cmd, ok := b.GetCommand(cmdName) + if !ok { + return + } + + args := lib.SplitArgs(arg, cmd.NArgs) + + if ok { + log.Debugf("command: %v, args: %v, nargs: %d", cmd.Name, args, len(args)) + if err := cmd.Func(args, s, m); err != nil { + log.Errorf("failed to execute command: %s", err) + } + + return + } + + log.Warnf("unknown command: %v, args: %v, nargs: %d", cmdName, args, len(args)) + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("unknown command: %s", cmdName)) +} + +func (b *Bot) Init(h *handler.Handlers, ch *command.Handlers) { + // Register handlers + b.AddHandler(h.Reaction) + + // Register commands + b.AddCommand(&Command{ Name: "coin", - Func: b.CoinCommand(), + Func: ch.Coin, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "deal", - Func: b.DealCommand(), + Func: ch.Deal, NArgs: 1, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "ping", - Func: b.PingCommand(), + Func: ch.Ping, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "roll", - Func: b.RollCommand(), + Func: ch.Roll, NArgs: 1, }) - AddCommand(&Command{ + b.AddCommand(&Command{ + Name: "roulette", + Func: ch.Roulette, + }) + b.AddCommand(&Command{ Name: "rps", - Func: b.RpsCommand(), + Func: ch.Rps, NArgs: 1, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "rpsls", - Func: b.RpslsCommand(), + Func: ch.Rpsls, NArgs: 1, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "time", - Func: b.TimeCommand(), + Func: ch.Time, NArgs: 1, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "version", - Func: b.VersionCommand(), + Func: ch.Version, }) - AddCommand(&Command{ + b.AddCommand(&Command{ Name: "weather", - Func: b.WeatherCommand(), + Func: ch.Weather, NArgs: 1, }) } -func (b *Bot) RegisterHandlers() { - b.Session.AddHandler(b.CommandHandler()) - b.Session.AddHandler(b.ReactionHandler()) -} - func Run() error { initConfig() go reloadConfig() @@ -104,9 +165,8 @@ func Run() error { return fmt.Errorf("error creating discord session: %v", err) } - b := NewBot(dg, C) - b.RegisterHandlers() - b.RegisterCommands() + b := NewBot(C, dg) + b.Init(handler.NewHandlers(C), command.NewHandlers(C)) dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsDirectMessages diff --git a/bot/coin.go b/bot/coin.go deleted file mode 100644 index e5550fd..0000000 --- a/bot/coin.go +++ /dev/null @@ -1,31 +0,0 @@ -package bot - -import ( - "git.kill0.net/chill9/beepboop/lib" - "github.com/bwmarrin/discordgo" -) - -type Coin bool - -func (c *Coin) Flip() bool { - *c = Coin(lib.Itob(lib.RandInt(0, 1))) - return bool(*c) -} - -func (b *Bot) CoinCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - var ( - c Coin - msg string - ) - - if c.Flip() { - msg = "heads" - } else { - msg = "tails" - } - - b.Session.ChannelMessageSend(m.ChannelID, msg) - return nil - } -} diff --git a/bot/command.go b/bot/command.go deleted file mode 100644 index 7ea1831..0000000 --- a/bot/command.go +++ /dev/null @@ -1,91 +0,0 @@ -package bot - -import ( - "fmt" - - "git.kill0.net/chill9/beepboop/config" - "git.kill0.net/chill9/beepboop/lib" - "github.com/bwmarrin/discordgo" - log "github.com/sirupsen/logrus" -) - -var ( - DefaultCommander *Commander -) - -type ( - Commander struct { - commands map[string]*Command - } - - Command struct { - Name string - Config *config.Config - Func CommandFunc - NArgs int - } - - CommandFunc func(args []string, m *discordgo.MessageCreate) error -) - -func init() { - DefaultCommander = NewCommander() -} - -func NewCommander() *Commander { - cmdr := new(Commander) - cmdr.commands = make(map[string]*Command) - return cmdr -} - -func (cmdr *Commander) AddCommand(cmd *Command) { - cmdr.commands[cmd.Name] = cmd -} - -func (cmdr *Commander) GetCommand(name string) (*Command, bool) { - cmd, ok := cmdr.commands[name] - return cmd, ok -} - -func AddCommand(cmd *Command) { - DefaultCommander.AddCommand(cmd) -} - -func GetCommand(name string) (*Command, bool) { - cmd, ok := DefaultCommander.GetCommand(name) - return cmd, ok -} - -func (b *Bot) CommandHandler() func(*discordgo.Session, *discordgo.MessageCreate) { - return func(s *discordgo.Session, m *discordgo.MessageCreate) { - var cmd *Command - - if m.Author.ID == s.State.User.ID { - return - } - - if !lib.HasCommand(m.Content, b.Config.Prefix) { - return - } - - cmdName, arg := lib.SplitCommandAndArg(m.Content, b.Config.Prefix) - - cmd, ok := GetCommand(cmdName) - - args := lib.SplitArgs(arg, cmd.NArgs) - - if ok { - cmd.Config = b.Config - - log.Debugf("command: %v, args: %v, nargs: %d", cmd.Name, args, len(args)) - if err := cmd.Func(args, m); err != nil { - log.Errorf("failed to execute command: %s", err) - } - - return - } - - log.Warnf("unknown command: %v, args: %v, nargs: %d", cmdName, args, len(args)) - s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("unknown command: %s", cmdName)) - } -} diff --git a/bot/ping.go b/bot/ping.go deleted file mode 100644 index f0c7608..0000000 --- a/bot/ping.go +++ /dev/null @@ -1,12 +0,0 @@ -package bot - -import ( - "github.com/bwmarrin/discordgo" -) - -func (b *Bot) PingCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - b.Session.ChannelMessageSend(m.ChannelID, "pong") - return nil - } -} diff --git a/bot/reaction.go b/bot/reaction.go deleted file mode 100644 index efefe55..0000000 --- a/bot/reaction.go +++ /dev/null @@ -1,52 +0,0 @@ -package bot - -import ( - "math/rand" - "strings" - - "git.kill0.net/chill9/beepboop/lib" - - "github.com/bwmarrin/discordgo" - log "github.com/sirupsen/logrus" -) - -func (b *Bot) ReactionHandler() func(*discordgo.Session, *discordgo.MessageCreate) { - return func(s *discordgo.Session, m *discordgo.MessageCreate) { - if m.Author.ID == s.State.User.ID { - return - } - - emojis := b.Config.Handler.Reaction.Emojis - channels := b.Config.Handler.Reaction.Channels - - if len(emojis) == 0 { - log.Warning("emoji list is empty") - return - } - - channel, err := s.Channel(m.ChannelID) - if err != nil { - log.Fatalf("unable to get channel name: %v", err) - } - - if len(channels) > 0 && !lib.Contains(channels, channel.Name) { - return - } - - for _, a := range m.Attachments { - if strings.HasPrefix(a.ContentType, "image/") { - for i := 1; i <= lib.RandInt(1, len(emojis)); i++ { - r := emojis[rand.Intn(len(emojis))] - s.MessageReactionAdd(m.ChannelID, m.ID, r) - } - } - } - - for range m.Embeds { - for i := 1; i <= lib.RandInt(1, len(emojis)); i++ { - r := emojis[rand.Intn(len(emojis))] - s.MessageReactionAdd(m.ChannelID, m.ID, r) - } - } - } -} diff --git a/bot/rps.go b/bot/rps.go deleted file mode 100644 index 706de07..0000000 --- a/bot/rps.go +++ /dev/null @@ -1,36 +0,0 @@ -package bot - -import ( - "strings" - - "git.kill0.net/chill9/beepboop/lib/rps" - "github.com/bwmarrin/discordgo" -) - -func (b *Bot) RpsCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - if len(args) != 1 { - b.Session.ChannelMessageSend( - m.ChannelID, "help: `!rps (rock | paper | scissors)`", - ) - return nil - } - - pc := strings.ToLower(args[0]) // player's choice - - g := rps.NewGame(rps.RulesRps, rps.EmojiMapRps) - - bc := g.Rand() // bot's choice - - s, err := g.Play(bc, pc) - if _, ok := err.(rps.InvalidChoiceError); ok { - b.Session.ChannelMessageSend( - m.ChannelID, "help: `!rps (rock | paper | scissors)`", - ) - } - - b.Session.ChannelMessageSend(m.ChannelID, s) - - return nil - } -} diff --git a/bot/rpsls.go b/bot/rpsls.go deleted file mode 100644 index 2d46bd7..0000000 --- a/bot/rpsls.go +++ /dev/null @@ -1,36 +0,0 @@ -package bot - -import ( - "strings" - - "git.kill0.net/chill9/beepboop/lib/rps" - "github.com/bwmarrin/discordgo" -) - -func (b *Bot) RpslsCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - if len(args) != 1 { - b.Session.ChannelMessageSend( - m.ChannelID, "help: `!rps (rock | paper | scissors | lizard | spock)`", - ) - return nil - } - - pc := strings.ToLower(args[0]) // player's choice - - g := rps.NewGame(rps.RulesRpsls, rps.EmojiMapRpsls) - - bc := g.Rand() // bot's choice - - s, err := g.Play(bc, pc) - if _, ok := err.(rps.InvalidChoiceError); ok { - b.Session.ChannelMessageSend( - m.ChannelID, "help: `!rps (rock | paper | scissors | lizard | spock)`", - ) - } - - b.Session.ChannelMessageSend(m.ChannelID, s) - - return nil - } -} diff --git a/bot/time.go b/bot/time.go deleted file mode 100644 index 405d3eb..0000000 --- a/bot/time.go +++ /dev/null @@ -1,36 +0,0 @@ -package bot - -import ( - "fmt" - "time" - - "github.com/bwmarrin/discordgo" - log "github.com/sirupsen/logrus" -) - -func (b *Bot) TimeCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - var ( - t time.Time - tz string - ) - - now := time.Now() - - if len(args) == 1 { - tz = args[0] - loc, err := time.LoadLocation(tz) - if err != nil { - log.Warnf("failed to load location: %s", err) - b.Session.ChannelMessageSend(m.ChannelID, err.Error()) - return nil - } - t = now.In(loc) - } else { - t = now - } - - b.Session.ChannelMessageSend(m.ChannelID, fmt.Sprint(t)) - return nil - } -} diff --git a/bot/version.go b/bot/version.go deleted file mode 100644 index 4713fc2..0000000 --- a/bot/version.go +++ /dev/null @@ -1,25 +0,0 @@ -package bot - -import ( - "fmt" - "runtime" - - "github.com/bwmarrin/discordgo" -) - -const ( - SourceURI = "https://git.kill0.net/chill9/bb" -) - -func (b *Bot) VersionCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - b.Session.ChannelMessageSend(m.ChannelID, fmt.Sprintf( - "go version: %s\nplatform: %s\nos: %s\nsource: %s\n", - runtime.Version(), - runtime.GOARCH, - runtime.GOOS, - SourceURI, - )) - return nil - } -} diff --git a/bot/weather.go b/bot/weather.go deleted file mode 100644 index 0575e01..0000000 --- a/bot/weather.go +++ /dev/null @@ -1,56 +0,0 @@ -package bot - -import ( - "fmt" - - "git.kill0.net/chill9/beepboop/lib/weather" - - "github.com/bwmarrin/discordgo" - log "github.com/sirupsen/logrus" -) - -func (b *Bot) WeatherCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - var ( - err error - loc string - w weather.Weather - ) - - if len(args) != 1 { - b.Session.ChannelMessageSend(m.ChannelID, "help: `!weather ,,`") - return nil - } - - loc = args[0] - - if b.Config.OpenWeatherMapToken == "" { - log.Error("OpenWeather token is not set") - return nil - } - - wc := weather.NewClient(b.Config.OpenWeatherMapToken) - - log.Debugf("weather requested for '%s'", loc) - - w, err = wc.Get(loc) - if err != nil { - log.Errorf("weather client error: %v", err) - return nil - } - - log.Debugf("weather returned for '%s': %+v", loc, w) - - b.Session.ChannelMessageSend(m.ChannelID, fmt.Sprintf( - "%s (%.1f, %.1f) — C:%.1f F:%.1f K:%.1f", - loc, - w.Coord.Lat, - w.Coord.Lon, - w.Main.Temp.Celcius(), - w.Main.Temp.Fahrenheit(), - w.Main.Temp.Kelvin(), - )) - - return nil - } -} diff --git a/command/coin.go b/command/coin.go new file mode 100644 index 0000000..088f10f --- /dev/null +++ b/command/coin.go @@ -0,0 +1,29 @@ +package command + +import ( + "git.kill0.net/chill9/beepboop/lib" + "github.com/bwmarrin/discordgo" +) + +type Coin bool + +func (c *Coin) Flip() bool { + *c = Coin(lib.Itob(lib.RandInt(0, 1))) + return bool(*c) +} + +func (h *Handlers) Coin(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + var ( + c Coin + msg string + ) + + if c.Flip() { + msg = "heads" + } else { + msg = "tails" + } + + s.ChannelMessageSend(m.ChannelID, msg) + return nil +} diff --git a/command/commands.go b/command/commands.go new file mode 100644 index 0000000..2b08a50 --- /dev/null +++ b/command/commands.go @@ -0,0 +1,11 @@ +package command + +import "git.kill0.net/chill9/beepboop/config" + +type Handlers struct { + config *config.Config +} + +func NewHandlers(config *config.Config) *Handlers { + return &Handlers{config: config} +} diff --git a/bot/deal.go b/command/deal.go similarity index 62% rename from bot/deal.go rename to command/deal.go index 7f46c5c..3c40650 100644 --- a/bot/deal.go +++ b/command/deal.go @@ -1,4 +1,4 @@ -package bot +package command import ( "errors" @@ -45,33 +45,31 @@ func (d *Deck) Deal(n int) ([]Card, error) { return hand, err } -func (b *Bot) DealCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - rand.Shuffle(len(deck), func(i, j int) { - deck[i], deck[j] = deck[j], deck[i] - }) +func (h *Handlers) Deal(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + rand.Shuffle(len(deck), func(i, j int) { + deck[i], deck[j] = deck[j], deck[i] + }) - log.Debugf("%+v", deck) + log.Debugf("%+v", deck) - if len(args) != 1 { - b.Session.ChannelMessageSend(m.ChannelID, "help: `!deal `") - return nil - } - - n, err := strconv.Atoi(args[0]) - if err != nil { - log.Errorf("failed to convert string to int: %s", err) - } - - hand, err := deck.Deal(n) - if err != nil { - b.Session.ChannelMessageSend(m.ChannelID, fmt.Sprintf("error: %s\n", err)) - return nil - } - - b.Session.ChannelMessageSend(m.ChannelID, JoinCards(hand, " ")) + if len(args) != 1 { + s.ChannelMessageSend(m.ChannelID, "help: `!deal `") return nil } + + n, err := strconv.Atoi(args[0]) + if err != nil { + log.Errorf("failed to convert string to int: %s", err) + } + + hand, err := deck.Deal(n) + if err != nil { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("error: %s\n", err)) + return nil + } + + s.ChannelMessageSend(m.ChannelID, JoinCards(hand, " ")) + return nil } func JoinCards(h []Card, sep string) string { diff --git a/bot/dice.go b/command/dice.go similarity index 70% rename from bot/dice.go rename to command/dice.go index 9b9d437..7113edf 100644 --- a/bot/dice.go +++ b/command/dice.go @@ -1,4 +1,4 @@ -package bot +package command import ( "errors" @@ -78,28 +78,26 @@ func (r *Roll) RollDice() { } } -func (b *Bot) RollCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - var ( - err error - msg, roll string - r *Roll - ) +func (h *Handlers) Roll(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + var ( + err error + msg, roll string + r *Roll + ) - roll = args[0] + roll = args[0] - r, err = ParseRoll(roll) - if err != nil { - b.Session.ChannelMessageSend(m.ChannelID, err.Error()) - return nil - } - - r.RollDice() - log.Debugf("rolled dice: %+v", r) - - msg = fmt.Sprintf("🎲 %s = %d", lib.JoinInt(r.Rolls, " + "), r.Sum) - - b.Session.ChannelMessageSend(m.ChannelID, msg) + r, err = ParseRoll(roll) + if err != nil { + s.ChannelMessageSend(m.ChannelID, err.Error()) return nil } + + r.RollDice() + log.Debugf("rolled dice: %+v", r) + + msg = fmt.Sprintf("🎲 %s = %d", lib.JoinInt(r.Rolls, " + "), r.Sum) + + s.ChannelMessageSend(m.ChannelID, msg) + return nil } diff --git a/command/ping.go b/command/ping.go new file mode 100644 index 0000000..36b42f3 --- /dev/null +++ b/command/ping.go @@ -0,0 +1,10 @@ +package command + +import ( + "github.com/bwmarrin/discordgo" +) + +func (h *Handlers) Ping(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + s.ChannelMessageSend(m.ChannelID, "pong") + return nil +} diff --git a/bot/roulette.go b/command/roulette.go similarity index 63% rename from bot/roulette.go rename to command/roulette.go index f418b43..ad047cc 100644 --- a/bot/roulette.go +++ b/command/roulette.go @@ -1,4 +1,4 @@ -package bot +package command import ( "git.kill0.net/chill9/beepboop/lib" @@ -66,19 +66,17 @@ func (g *Gun) IsEmpty() bool { return true } -func (b *Bot) RouletteCommand() CommandFunc { - return func(args []string, m *discordgo.MessageCreate) error { - if gun.IsEmpty() { - gun.Load(Bullets) - log.Debugf("reloading gun: %+v\n", gun) - } - - log.Debugf("firing gun: %+v\n", gun) - if gun.Fire() { - b.Session.ChannelMessageSend(m.ChannelID, GunFireMessage) - } else { - b.Session.ChannelMessageSend(m.ChannelID, GunClickMessage) - } - return nil +func (h *Handlers) Roulette(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + if gun.IsEmpty() { + gun.Load(Bullets) + log.Debugf("reloading gun: %+v\n", gun) } + + log.Debugf("firing gun: %+v\n", gun) + if gun.Fire() { + s.ChannelMessageSend(m.ChannelID, GunFireMessage) + } else { + s.ChannelMessageSend(m.ChannelID, GunClickMessage) + } + return nil } diff --git a/command/router.go b/command/router.go new file mode 100644 index 0000000..7397e09 --- /dev/null +++ b/command/router.go @@ -0,0 +1,34 @@ +package command + +import ( + "github.com/bwmarrin/discordgo" +) + +type ( + Router struct { + commands map[string]*Command + } + + Command struct { + Name string + Func CommandFunc + NArgs int + } + + CommandFunc func(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error +) + +func NewRouter() *Router { + r := new(Router) + r.commands = make(map[string]*Command) + return r +} + +func (r *Router) AddCommand(cmd *Command) { + r.commands[cmd.Name] = cmd +} + +func (r *Router) GetCommand(name string) (*Command, bool) { + cmd, ok := r.commands[name] + return cmd, ok +} diff --git a/command/rps.go b/command/rps.go new file mode 100644 index 0000000..ce88ba7 --- /dev/null +++ b/command/rps.go @@ -0,0 +1,34 @@ +package command + +import ( + "strings" + + "git.kill0.net/chill9/beepboop/lib/rps" + "github.com/bwmarrin/discordgo" +) + +func (h *Handlers) Rps(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + if len(args) != 1 { + s.ChannelMessageSend( + m.ChannelID, "help: `!rps (rock | paper | scissors)`", + ) + return nil + } + + pc := strings.ToLower(args[0]) // player's choice + + g := rps.NewGame(rps.RulesRps, rps.EmojiMapRps) + + bc := g.Rand() // bot's choice + + out, err := g.Play(bc, pc) + if _, ok := err.(rps.InvalidChoiceError); ok { + s.ChannelMessageSend( + m.ChannelID, "help: `!rps (rock | paper | scissors)`", + ) + } + + s.ChannelMessageSend(m.ChannelID, out) + + return nil +} diff --git a/command/rpsls.go b/command/rpsls.go new file mode 100644 index 0000000..c500c5e --- /dev/null +++ b/command/rpsls.go @@ -0,0 +1,34 @@ +package command + +import ( + "strings" + + "git.kill0.net/chill9/beepboop/lib/rps" + "github.com/bwmarrin/discordgo" +) + +func (h *Handlers) Rpsls(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + if len(args) != 1 { + s.ChannelMessageSend( + m.ChannelID, "help: `!rps (rock | paper | scissors | lizard | spock)`", + ) + return nil + } + + pc := strings.ToLower(args[0]) // player's choice + + g := rps.NewGame(rps.RulesRpsls, rps.EmojiMapRpsls) + + bc := g.Rand() // bot's choice + + out, err := g.Play(bc, pc) + if _, ok := err.(rps.InvalidChoiceError); ok { + s.ChannelMessageSend( + m.ChannelID, "help: `!rps (rock | paper | scissors | lizard | spock)`", + ) + } + + s.ChannelMessageSend(m.ChannelID, out) + + return nil +} diff --git a/command/time.go b/command/time.go new file mode 100644 index 0000000..7b1748c --- /dev/null +++ b/command/time.go @@ -0,0 +1,34 @@ +package command + +import ( + "fmt" + "time" + + "github.com/bwmarrin/discordgo" + log "github.com/sirupsen/logrus" +) + +func (h *Handlers) Time(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + var ( + t time.Time + tz string + ) + + now := time.Now() + + if len(args) == 1 { + tz = args[0] + loc, err := time.LoadLocation(tz) + if err != nil { + log.Warnf("failed to load location: %s", err) + s.ChannelMessageSend(m.ChannelID, err.Error()) + return nil + } + t = now.In(loc) + } else { + t = now + } + + s.ChannelMessageSend(m.ChannelID, fmt.Sprint(t)) + return nil +} diff --git a/command/version.go b/command/version.go new file mode 100644 index 0000000..e5d9143 --- /dev/null +++ b/command/version.go @@ -0,0 +1,23 @@ +package command + +import ( + "fmt" + "runtime" + + "github.com/bwmarrin/discordgo" +) + +const ( + SourceURI = "https://git.kill0.net/chill9/bb" +) + +func (h *Handlers) Version(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf( + "go version: %s\nplatform: %s\nos: %s\nsource: %s\n", + runtime.Version(), + runtime.GOARCH, + runtime.GOOS, + SourceURI, + )) + return nil +} diff --git a/command/weather.go b/command/weather.go new file mode 100644 index 0000000..61801c0 --- /dev/null +++ b/command/weather.go @@ -0,0 +1,54 @@ +package command + +import ( + "fmt" + + "git.kill0.net/chill9/beepboop/lib/weather" + + "github.com/bwmarrin/discordgo" + log "github.com/sirupsen/logrus" +) + +func (h *Handlers) Weather(args []string, s *discordgo.Session, m *discordgo.MessageCreate) error { + var ( + err error + loc string + w weather.Weather + ) + + if len(args) != 1 { + s.ChannelMessageSend(m.ChannelID, "help: `!weather ,,`") + return nil + } + + loc = args[0] + + if h.config.OpenWeatherMapToken == "" { + log.Error("OpenWeather token is not set") + return nil + } + + wc := weather.NewClient(h.config.OpenWeatherMapToken) + + log.Debugf("weather requested for '%s'", loc) + + w, err = wc.Get(loc) + if err != nil { + log.Errorf("weather client error: %v", err) + return nil + } + + log.Debugf("weather returned for '%s': %+v", loc, w) + + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf( + "%s (%.1f, %.1f) — C:%.1f F:%.1f K:%.1f", + loc, + w.Coord.Lat, + w.Coord.Lon, + w.Main.Temp.Celcius(), + w.Main.Temp.Fahrenheit(), + w.Main.Temp.Kelvin(), + )) + + return nil +} diff --git a/handler/command.go b/handler/command.go new file mode 100644 index 0000000..abeebd1 --- /dev/null +++ b/handler/command.go @@ -0,0 +1 @@ +package handler diff --git a/handler/handlers.go b/handler/handlers.go new file mode 100644 index 0000000..2b45cab --- /dev/null +++ b/handler/handlers.go @@ -0,0 +1,15 @@ +package handler + +import ( + "git.kill0.net/chill9/beepboop/config" +) + +type Handlers struct { + config *config.Config +} + +func NewHandlers(config *config.Config) *Handlers { + return &Handlers{ + config: config, + } +} diff --git a/handler/reaction.go b/handler/reaction.go new file mode 100644 index 0000000..4884066 --- /dev/null +++ b/handler/reaction.go @@ -0,0 +1,50 @@ +package handler + +import ( + "math/rand" + "strings" + + "git.kill0.net/chill9/beepboop/lib" + + "github.com/bwmarrin/discordgo" + log "github.com/sirupsen/logrus" +) + +func (h *Handlers) Reaction(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == s.State.User.ID { + return + } + + emojis := h.config.Handler.Reaction.Emojis + channels := h.config.Handler.Reaction.Channels + + if len(emojis) == 0 { + log.Warning("emoji list is empty") + return + } + + channel, err := s.Channel(m.ChannelID) + if err != nil { + log.Fatalf("unable to get channel name: %v", err) + } + + if len(channels) > 0 && !lib.Contains(channels, channel.Name) { + return + } + + for _, a := range m.Attachments { + if strings.HasPrefix(a.ContentType, "image/") { + for i := 1; i <= lib.RandInt(1, len(emojis)); i++ { + r := emojis[rand.Intn(len(emojis))] + s.MessageReactionAdd(m.ChannelID, m.ID, r) + } + } + } + + for range m.Embeds { + for i := 1; i <= lib.RandInt(1, len(emojis)); i++ { + r := emojis[rand.Intn(len(emojis))] + s.MessageReactionAdd(m.ChannelID, m.ID, r) + } + } +}