diff --git a/bot/bot.go b/bot/bot.go new file mode 100644 index 0000000..36d0e83 --- /dev/null +++ b/bot/bot.go @@ -0,0 +1,47 @@ +package bot + +import "github.com/bwmarrin/discordgo" + +type Bot struct { + Session *discordgo.Session + Config Config +} + +func NewBot(s *discordgo.Session, config Config) *Bot { + return &Bot{Session: s, Config: config} +} + +func (b *Bot) RegisterCommands() { + AddCommand(&Command{ + Name: "coin", + Func: b.CoinCommand(), + }) + AddCommand(&Command{ + Name: "deal", + Func: b.DealCommand(), + NArgs: 1, + }) + AddCommand(&Command{ + Name: "ping", + Func: b.PingCommand(), + }) + AddCommand(&Command{ + Name: "roll", + Func: b.RollCommand(), + NArgs: 1, + }) + AddCommand(&Command{ + Name: "time", + Func: b.TimeCommand(), + NArgs: 1, + }) + AddCommand(&Command{ + Name: "version", + Func: b.VersionCommand(), + }) + AddCommand(&Command{ + Name: "weather", + Func: b.WeatherCommand(), + NArgs: 1, + }) +} diff --git a/bot/coin.go b/bot/coin.go new file mode 100644 index 0000000..e5550fd --- /dev/null +++ b/bot/coin.go @@ -0,0 +1,31 @@ +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 index be3db97..7485279 100644 --- a/bot/command.go +++ b/bot/command.go @@ -18,13 +18,13 @@ type ( } Command struct { - Name string - Config Config - Func func(cmd *Command, args []string) error - NArgs int - Session *discordgo.Session - Message *discordgo.MessageCreate + Name string + Config Config + Func CommandFunc + NArgs int } + + CommandFunc func(args []string, m *discordgo.MessageCreate) error ) func init() { @@ -55,7 +55,7 @@ func GetCommand(name string) (*Command, bool) { return cmd, ok } -func NewCommandHandler(config Config) func(s *discordgo.Session, m *discordgo.MessageCreate) { +func NewCommandHandler(bot *Bot) func(s *discordgo.Session, m *discordgo.MessageCreate) { return func(s *discordgo.Session, m *discordgo.MessageCreate) { var cmd *Command @@ -63,24 +63,21 @@ func NewCommandHandler(config Config) func(s *discordgo.Session, m *discordgo.Me return } - if !lib.HasCommand(m.Content, config.Prefix) { + if !lib.HasCommand(m.Content, bot.Config.Prefix) { return } - cmdName, arg := lib.SplitCommandAndArg(m.Content, config.Prefix) + cmdName, arg := lib.SplitCommandAndArg(m.Content, bot.Config.Prefix) cmd, ok := GetCommand(cmdName) args := lib.SplitArgs(arg, cmd.NArgs) if ok { - cmd.Config = config - cmd.Name = cmdName - cmd.Session = s - cmd.Message = m + cmd.Config = bot.Config log.Debugf("command: %v, args: %v, nargs: %d", cmd.Name, args, len(args)) - cmd.Func(cmd, args) + cmd.Func(args, m) return } diff --git a/bot/commands/coin.go b/bot/commands/coin.go deleted file mode 100644 index a9bcb2f..0000000 --- a/bot/commands/coin.go +++ /dev/null @@ -1,29 +0,0 @@ -package commands - -import ( - "git.kill0.net/chill9/beepboop/bot" - "git.kill0.net/chill9/beepboop/lib" -) - -type Coin bool - -func (c *Coin) Flip() bool { - *c = Coin(lib.Itob(lib.RandInt(0, 1))) - return bool(*c) -} - -func CoinCommand(cmd *bot.Command, args []string) error { - var ( - c Coin - msg string - ) - - if c.Flip() { - msg = "heads" - } else { - msg = "tails" - } - - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, msg) - return nil -} diff --git a/bot/commands/ping.go b/bot/commands/ping.go deleted file mode 100644 index c0aaf8c..0000000 --- a/bot/commands/ping.go +++ /dev/null @@ -1,10 +0,0 @@ -package commands - -import ( - "git.kill0.net/chill9/beepboop/bot" -) - -func PingCommand(cmd *bot.Command, args []string) error { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, "pong") - return nil -} diff --git a/bot/commands/time.go b/bot/commands/time.go deleted file mode 100644 index e51d8be..0000000 --- a/bot/commands/time.go +++ /dev/null @@ -1,34 +0,0 @@ -package commands - -import ( - "fmt" - "time" - - "git.kill0.net/chill9/beepboop/bot" - log "github.com/sirupsen/logrus" -) - -func TimeCommand(cmd *bot.Command, args []string) 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) - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, err.Error()) - return nil - } - t = now.In(loc) - } else { - t = now - } - - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, fmt.Sprint(t)) - return nil -} diff --git a/bot/commands/version.go b/bot/commands/version.go deleted file mode 100644 index 70c81fb..0000000 --- a/bot/commands/version.go +++ /dev/null @@ -1,23 +0,0 @@ -package commands - -import ( - "fmt" - "runtime" - - "git.kill0.net/chill9/beepboop/bot" -) - -const ( - SourceURI = "https://git.kill0.net/chill9/bb" -) - -func VersionCommand(cmd *bot.Command, args []string) error { - cmd.Session.ChannelMessageSend(cmd.Message.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/commands/weather.go b/bot/commands/weather.go deleted file mode 100644 index 72ce022..0000000 --- a/bot/commands/weather.go +++ /dev/null @@ -1,67 +0,0 @@ -package commands - -import ( - "fmt" - - "git.kill0.net/chill9/beepboop/bot" - "git.kill0.net/chill9/beepboop/lib/weather" - - log "github.com/sirupsen/logrus" -) - -type WeatherHandler struct { - Config bot.Config - Name string -} - -func NewWeatherHandler(s string) *WeatherHandler { - return &WeatherHandler{Name: s} -} - -func (h *WeatherHandler) SetConfig(config bot.Config) { - h.Config = config -} - -func WeatherCommand(cmd *bot.Command, args []string) error { - var ( - err error - loc string - w weather.Weather - ) - - if len(args) != 1 { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, "help: `!weather ,,`") - return nil - } - - loc = args[0] - - if cmd.Config.OpenWeatherMapToken == "" { - log.Error("OpenWeather token is not set") - return nil - } - - wc := weather.NewClient(cmd.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) - - cmd.Session.ChannelMessageSend(cmd.Message.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/bot/commands/deal.go b/bot/deal.go similarity index 59% rename from bot/commands/deal.go rename to bot/deal.go index 503534b..dc68211 100644 --- a/bot/commands/deal.go +++ b/bot/deal.go @@ -1,4 +1,4 @@ -package commands +package bot import ( "errors" @@ -7,16 +7,11 @@ import ( "strconv" "strings" - "git.kill0.net/chill9/beepboop/bot" + "github.com/bwmarrin/discordgo" log "github.com/sirupsen/logrus" ) type ( - DealHandler struct { - config bot.Config - Name string - } - Card string Deck [52]Card @@ -50,31 +45,33 @@ func (d *Deck) Deal(n int) ([]Card, error) { return hand, err } -func DealCommand(cmd *bot.Command, args []string) error { - rand.Shuffle(len(deck), func(i, j int) { - deck[i], deck[j] = deck[j], deck[i] - }) +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] + }) - log.Debugf("%+v", deck) + log.Debugf("%+v", deck) - if len(args) != 1 { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, fmt.Sprintf("help: `!%s `", cmd.Name)) + 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, " ")) 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 { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, fmt.Sprintf("error: %s\n", err)) - return nil - } - - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, JoinCards(hand, " ")) - return nil } func JoinCards(h []Card, sep string) string { diff --git a/bot/commands/dice.go b/bot/dice.go similarity index 68% rename from bot/commands/dice.go rename to bot/dice.go index 79af4e7..9b9d437 100644 --- a/bot/commands/dice.go +++ b/bot/dice.go @@ -1,4 +1,4 @@ -package commands +package bot import ( "errors" @@ -7,9 +7,9 @@ import ( "strconv" "strings" - "git.kill0.net/chill9/beepboop/bot" "git.kill0.net/chill9/beepboop/lib" + "github.com/bwmarrin/discordgo" log "github.com/sirupsen/logrus" ) @@ -78,26 +78,28 @@ func (r *Roll) RollDice() { } } -func RollCommand(cmd *bot.Command, args []string) error { - var ( - err error - msg, roll string - r *Roll - ) +func (b *Bot) RollCommand() CommandFunc { + return func(args []string, 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 { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, err.Error()) + 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) return nil } - - r.RollDice() - log.Debugf("rolled dice: %+v", r) - - msg = fmt.Sprintf("🎲 %s = %d", lib.JoinInt(r.Rolls, " + "), r.Sum) - - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, msg) - return nil } diff --git a/bot/ping.go b/bot/ping.go new file mode 100644 index 0000000..f0c7608 --- /dev/null +++ b/bot/ping.go @@ -0,0 +1,12 @@ +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/commands/roulette.go b/bot/roulette.go similarity index 61% rename from bot/commands/roulette.go rename to bot/roulette.go index c4ab9cc..c5360a7 100644 --- a/bot/commands/roulette.go +++ b/bot/roulette.go @@ -1,9 +1,9 @@ -package commands +package bot import ( - "git.kill0.net/chill9/beepboop/bot" "git.kill0.net/chill9/beepboop/lib" + "github.com/bwmarrin/discordgo" log "github.com/sirupsen/logrus" ) @@ -66,17 +66,19 @@ func (g *Gun) IsEmpty() bool { return true } -func RouletteCommand(cmd *bot.Command, args []string) error { - if gun.IsEmpty() { - gun.Load(Bullets) - log.Debugf("reloading gun: %+v\n", gun) - } +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() { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, GunFireMessage) - } else { - cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, GunClickMessage) + 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 } - return nil } diff --git a/bot/time.go b/bot/time.go new file mode 100644 index 0000000..405d3eb --- /dev/null +++ b/bot/time.go @@ -0,0 +1,36 @@ +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 new file mode 100644 index 0000000..4713fc2 --- /dev/null +++ b/bot/version.go @@ -0,0 +1,25 @@ +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 new file mode 100644 index 0000000..0575e01 --- /dev/null +++ b/bot/weather.go @@ -0,0 +1,56 @@ +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/cmd/bb/main.go b/cmd/bb/main.go index 78b4f27..d6b29e4 100644 --- a/cmd/bb/main.go +++ b/cmd/bb/main.go @@ -11,7 +11,6 @@ import ( "syscall" "git.kill0.net/chill9/beepboop/bot" - "git.kill0.net/chill9/beepboop/bot/commands" "git.kill0.net/chill9/beepboop/bot/handler" "git.kill0.net/chill9/beepboop/lib" @@ -29,41 +28,6 @@ var ( } ) -func init() { - bot.AddCommand(&bot.Command{ - Name: "coin", - Func: commands.CoinCommand, - }) - bot.AddCommand(&bot.Command{ - Name: "deal", - Func: commands.DealCommand, - NArgs: 1, - }) - bot.AddCommand(&bot.Command{ - Name: "ping", - Func: commands.PingCommand, - }) - bot.AddCommand(&bot.Command{ - Name: "roll", - Func: commands.RollCommand, - NArgs: 1, - }) - bot.AddCommand(&bot.Command{ - Name: "time", - Func: commands.TimeCommand, - NArgs: 1, - }) - bot.AddCommand(&bot.Command{ - Name: "version", - Func: commands.VersionCommand, - }) - bot.AddCommand(&bot.Command{ - Name: "weather", - Func: commands.WeatherCommand, - NArgs: 1, - }) -} - func main() { setupConfig() @@ -83,7 +47,10 @@ func main() { dg.AddHandler(h.Handle) } - dg.AddHandler(bot.NewCommandHandler(C)) + b := bot.NewBot(dg, C) + b.RegisterCommands() + + dg.AddHandler(bot.NewCommandHandler(b)) dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsDirectMessages