Compare commits

..

4 Commits

Author SHA1 Message Date
446ac616bf
Fix lint errors
All checks were successful
continuous-integration/drone/push Build is passing
2022-09-07 00:54:58 -05:00
e2032942ca
Add handlers to Bot struct 2022-09-07 00:29:28 -05:00
31cf6f6c9a
Move code out of main.go 2022-09-06 21:48:29 -05:00
5651df37ef
Move command functions under a bot struct 2022-09-06 21:33:59 -05:00
21 changed files with 445 additions and 456 deletions

4
.golangci.yml Normal file
View File

@ -0,0 +1,4 @@
---
linters:
disable:
- errcheck

147
bot/bot.go Normal file
View File

@ -0,0 +1,147 @@
package bot
import (
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"git.kill0.net/chill9/beepboop/lib"
"github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
var C Config
type (
Bot struct {
Session *discordgo.Session
Config Config
}
MessageHandler func(s *discordgo.Session, m *discordgo.MessageCreate)
)
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,
})
}
func (b *Bot) RegisterHandlers() {
b.Session.AddHandler(b.CommandHandler())
b.Session.AddHandler(b.ReactionHandler())
}
func Run() error {
setupConfig()
if err := lib.SeedMathRand(); err != nil {
log.Warn(err)
}
if C.DiscordToken == "" {
log.Fatalf("Discord token is not set")
}
dg, err := discordgo.New(fmt.Sprintf("Bot %s", C.DiscordToken))
if err != nil {
log.Fatalf("error creating Discord session: %v\n", err)
}
b := NewBot(dg, C)
b.RegisterHandlers()
b.RegisterCommands()
dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsDirectMessages
err = dg.Open()
if err != nil {
log.Fatalf("error opening connection: %v\n", err)
}
log.Info("The bot is now running. Press CTRL-C to exit.")
defer dg.Close()
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM)
<-sc
log.Info("Shutting down")
return nil
}
func setupConfig() {
var err error
C = NewConfig()
flag.Bool("debug", false, "enable debug logging")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
viper.SetEnvPrefix("BEEPBOOP")
viper.AutomaticEnv()
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err = viper.ReadInConfig()
viper.BindEnv("DEBUG")
viper.BindEnv("DISCORD_TOKEN")
viper.BindEnv("OPEN_WEATHER_MAP_TOKEN")
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
log.Fatalf("fatal error config file: %v", err)
}
err = viper.Unmarshal(&C)
if err != nil {
log.Fatalf("unable to decode into struct: %v", err)
}
if viper.GetBool("debug") {
log.SetLevel(log.DebugLevel)
}
}

31
bot/coin.go Normal file
View File

@ -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
}
}

View File

@ -20,11 +20,11 @@ type (
Command struct { Command struct {
Name string Name string
Config Config Config Config
Func func(cmd *Command, args []string) error Func CommandFunc
NArgs int NArgs int
Session *discordgo.Session
Message *discordgo.MessageCreate
} }
CommandFunc func(args []string, m *discordgo.MessageCreate) error
) )
func init() { func init() {
@ -55,7 +55,7 @@ func GetCommand(name string) (*Command, bool) {
return cmd, ok return cmd, ok
} }
func NewCommandHandler(config Config) func(s *discordgo.Session, m *discordgo.MessageCreate) { func (b *Bot) CommandHandler() func(*discordgo.Session, *discordgo.MessageCreate) {
return func(s *discordgo.Session, m *discordgo.MessageCreate) { return func(s *discordgo.Session, m *discordgo.MessageCreate) {
var cmd *Command var cmd *Command
@ -63,24 +63,23 @@ func NewCommandHandler(config Config) func(s *discordgo.Session, m *discordgo.Me
return return
} }
if !lib.HasCommand(m.Content, config.Prefix) { if !lib.HasCommand(m.Content, b.Config.Prefix) {
return return
} }
cmdName, arg := lib.SplitCommandAndArg(m.Content, config.Prefix) cmdName, arg := lib.SplitCommandAndArg(m.Content, b.Config.Prefix)
cmd, ok := GetCommand(cmdName) cmd, ok := GetCommand(cmdName)
args := lib.SplitArgs(arg, cmd.NArgs) args := lib.SplitArgs(arg, cmd.NArgs)
if ok { if ok {
cmd.Config = config cmd.Config = b.Config
cmd.Name = cmdName
cmd.Session = s
cmd.Message = m
log.Debugf("command: %v, args: %v, nargs: %d", cmd.Name, args, len(args)) log.Debugf("command: %v, args: %v, nargs: %d", cmd.Name, args, len(args))
cmd.Func(cmd, args) if err := cmd.Func(args, m); err != nil {
log.Errorf("failed to execute command: %s", err)
}
return return
} }

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 <CITY>,<STATE>,<COUNTRY>`")
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
}

View File

@ -1,4 +1,4 @@
package commands package bot
import ( import (
"errors" "errors"
@ -7,16 +7,11 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.kill0.net/chill9/beepboop/bot" "github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type ( type (
DealHandler struct {
config bot.Config
Name string
}
Card string Card string
Deck [52]Card Deck [52]Card
@ -50,7 +45,8 @@ func (d *Deck) Deal(n int) ([]Card, error) {
return hand, err return hand, err
} }
func DealCommand(cmd *bot.Command, args []string) error { func (b *Bot) DealCommand() CommandFunc {
return func(args []string, m *discordgo.MessageCreate) error {
rand.Shuffle(len(deck), func(i, j int) { rand.Shuffle(len(deck), func(i, j int) {
deck[i], deck[j] = deck[j], deck[i] deck[i], deck[j] = deck[j], deck[i]
}) })
@ -58,7 +54,7 @@ func DealCommand(cmd *bot.Command, args []string) error {
log.Debugf("%+v", deck) log.Debugf("%+v", deck)
if len(args) != 1 { if len(args) != 1 {
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, fmt.Sprintf("help: `!%s <n>`", cmd.Name)) b.Session.ChannelMessageSend(m.ChannelID, "help: `!deal <n>`")
return nil return nil
} }
@ -69,18 +65,17 @@ func DealCommand(cmd *bot.Command, args []string) error {
hand, err := deck.Deal(n) hand, err := deck.Deal(n)
if err != nil { if err != nil {
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, fmt.Sprintf("error: %s\n", err)) b.Session.ChannelMessageSend(m.ChannelID, fmt.Sprintf("error: %s\n", err))
return nil return nil
} }
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, JoinCards(hand, " ")) b.Session.ChannelMessageSend(m.ChannelID, JoinCards(hand, " "))
return nil return nil
} }
}
func JoinCards(h []Card, sep string) string { func JoinCards(h []Card, sep string) string {
var b []string b := make([]string, len(h))
b = make([]string, len(h))
for i, v := range h { for i, v := range h {
b[i] = string(v) b[i] = string(v)

View File

@ -1,4 +1,4 @@
package commands package bot
import ( import (
"errors" "errors"
@ -7,9 +7,9 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.kill0.net/chill9/beepboop/bot"
"git.kill0.net/chill9/beepboop/lib" "git.kill0.net/chill9/beepboop/lib"
"github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -78,7 +78,8 @@ func (r *Roll) RollDice() {
} }
} }
func RollCommand(cmd *bot.Command, args []string) error { func (b *Bot) RollCommand() CommandFunc {
return func(args []string, m *discordgo.MessageCreate) error {
var ( var (
err error err error
msg, roll string msg, roll string
@ -89,7 +90,7 @@ func RollCommand(cmd *bot.Command, args []string) error {
r, err = ParseRoll(roll) r, err = ParseRoll(roll)
if err != nil { if err != nil {
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, err.Error()) b.Session.ChannelMessageSend(m.ChannelID, err.Error())
return nil return nil
} }
@ -98,6 +99,7 @@ func RollCommand(cmd *bot.Command, args []string) error {
msg = fmt.Sprintf("🎲 %s = %d", lib.JoinInt(r.Rolls, " + "), r.Sum) msg = fmt.Sprintf("🎲 %s = %d", lib.JoinInt(r.Rolls, " + "), r.Sum)
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, msg) b.Session.ChannelMessageSend(m.ChannelID, msg)
return nil return nil
} }
}

View File

@ -1,65 +0,0 @@
package handler
import (
"math/rand"
"strings"
"git.kill0.net/chill9/beepboop/bot"
"git.kill0.net/chill9/beepboop/lib"
"github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus"
)
type (
ReactionHandler struct {
Config bot.Config
}
)
func NewReactionHandler() *ReactionHandler {
return new(ReactionHandler)
}
func (h *ReactionHandler) SetConfig(config bot.Config) {
h.Config = config
}
func (h *ReactionHandler) Handle(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)
}
}
}

View File

@ -1,10 +0,0 @@
package bot
import (
"github.com/bwmarrin/discordgo"
)
type MessageCreateHandler interface {
Handle(*discordgo.Session, *discordgo.MessageCreate)
SetConfig(Config)
}

12
bot/ping.go Normal file
View File

@ -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
}
}

52
bot/reaction.go Normal file
View File

@ -0,0 +1,52 @@
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)
}
}
}
}

View File

@ -1,9 +1,9 @@
package commands package bot
import ( import (
"git.kill0.net/chill9/beepboop/bot"
"git.kill0.net/chill9/beepboop/lib" "git.kill0.net/chill9/beepboop/lib"
"github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -36,7 +36,7 @@ func (g *Gun) Load(n int) {
g.N = 0 g.N = 0
for i := 1; i <= n; { for i := 1; i <= n; {
x := lib.RandInt(0, len(g.C)-1) x := lib.RandInt(0, len(g.C)-1)
if g.C[x] == false { if !g.C[x] {
g.C[x] = true g.C[x] = true
i++ i++
} else { } else {
@ -58,7 +58,7 @@ func (g *Gun) Fire() bool {
func (g *Gun) IsEmpty() bool { func (g *Gun) IsEmpty() bool {
for _, v := range g.C { for _, v := range g.C {
if v == true { if v {
return false return false
} }
} }
@ -66,7 +66,8 @@ func (g *Gun) IsEmpty() bool {
return true return true
} }
func RouletteCommand(cmd *bot.Command, args []string) error { func (b *Bot) RouletteCommand() CommandFunc {
return func(args []string, m *discordgo.MessageCreate) error {
if gun.IsEmpty() { if gun.IsEmpty() {
gun.Load(Bullets) gun.Load(Bullets)
log.Debugf("reloading gun: %+v\n", gun) log.Debugf("reloading gun: %+v\n", gun)
@ -74,9 +75,10 @@ func RouletteCommand(cmd *bot.Command, args []string) error {
log.Debugf("firing gun: %+v\n", gun) log.Debugf("firing gun: %+v\n", gun)
if gun.Fire() { if gun.Fire() {
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, GunFireMessage) b.Session.ChannelMessageSend(m.ChannelID, GunFireMessage)
} else { } else {
cmd.Session.ChannelMessageSend(cmd.Message.ChannelID, GunClickMessage) b.Session.ChannelMessageSend(m.ChannelID, GunClickMessage)
} }
return nil return nil
} }
}

36
bot/time.go Normal file
View File

@ -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
}
}

25
bot/version.go Normal file
View File

@ -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
}
}

56
bot/weather.go Normal file
View File

@ -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 <CITY>,<STATE>,<COUNTRY>`")
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
}
}

View File

@ -1,141 +1,13 @@
package main package main
import ( import (
"flag"
"fmt"
//"log"
"os" "os"
"os/signal"
"syscall"
"git.kill0.net/chill9/beepboop/bot" "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"
"github.com/bwmarrin/discordgo"
log "github.com/sirupsen/logrus"
"github.com/spf13/pflag"
"github.com/spf13/viper"
) )
var (
C bot.Config
handlers []bot.MessageCreateHandler = []bot.MessageCreateHandler{
handler.NewReactionHandler(),
}
)
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() { func main() {
setupConfig() if err := bot.Run(); err != nil {
os.Exit(1)
lib.SeedMathRand()
if C.DiscordToken == "" {
log.Fatalf("Discord token is not set")
}
dg, err := discordgo.New(fmt.Sprintf("Bot %s", C.DiscordToken))
if err != nil {
log.Fatalf("error creating Discord session: %v\n", err)
}
for _, h := range handlers {
h.SetConfig(C)
dg.AddHandler(h.Handle)
}
dg.AddHandler(bot.NewCommandHandler(C))
dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsDirectMessages
err = dg.Open()
if err != nil {
log.Fatalf("error opening connection: %v\n", err)
}
log.Info("The bot is now running. Press CTRL-C to exit.")
defer dg.Close()
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-sc
log.Info("Shutting down")
}
func setupConfig() {
var err error
C = bot.NewConfig()
flag.Bool("debug", false, "enable debug logging")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
viper.BindPFlags(pflag.CommandLine)
viper.SetEnvPrefix("BEEPBOOP")
viper.AutomaticEnv()
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err = viper.ReadInConfig()
viper.BindEnv("DEBUG")
viper.BindEnv("DISCORD_TOKEN")
viper.BindEnv("OPEN_WEATHER_MAP_TOKEN")
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
log.Fatalf("fatal error config file: %v", err)
}
err = viper.Unmarshal(&C)
if err != nil {
log.Fatalf("unable to decode into struct: %v", err)
}
if viper.GetBool("debug") {
log.SetLevel(log.DebugLevel)
} }
} }

View File

@ -17,9 +17,7 @@ func Contains[T comparable](s []T, v T) bool {
} }
func JoinInt(a []int, sep string) string { func JoinInt(a []int, sep string) string {
var b []string b := make([]string, len(a))
b = make([]string, len(a))
for i, v := range a { for i, v := range a {
b[i] = strconv.Itoa(v) b[i] = strconv.Itoa(v)
@ -37,11 +35,7 @@ func SumInt(a []int) int {
} }
func Itob(v int) bool { func Itob(v int) bool {
if v == 1 { return v == 1
return true
}
return false
} }
func BuildURI(rawuri, rawpath string) string { func BuildURI(rawuri, rawpath string) string {