commit 0354fdc032c4530ac39729cafd42c7e4c737085c Author: FernandoJVideira <03.pleaser-minster@icloud.com> Date: Tue Mar 17 04:20:39 2026 +0000 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d10f7d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.cursor \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bb28788 --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module velox-bot + +go 1.26.1 + +require ( + github.com/bwmarrin/discordgo v0.29.0 + github.com/joho/godotenv v1.5.1 +) + +require ( + github.com/gorilla/websocket v1.4.2 // indirect + golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect + golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..04715b6 --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno= +github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/bot/bot.go b/internal/bot/bot.go new file mode 100644 index 0000000..5ed2147 --- /dev/null +++ b/internal/bot/bot.go @@ -0,0 +1,59 @@ +package bot + +import ( + "log" + "velox-bot/internal/commands" + + "github.com/bwmarrin/discordgo" +) + +type Bot struct { + Session *discordgo.Session + AppID string + GuildID string + Commands []*discordgo.ApplicationCommand + registeredCommands []*discordgo.ApplicationCommand +} + +func NewBot(token, appID, guildID string, cmds []*discordgo.ApplicationCommand) (*Bot, error) { + session, err := discordgo.New("Bot " + token) + if err != nil { + return nil, err + } + + return &Bot{ + Session: session, + AppID: appID, + GuildID: guildID, + Commands: cmds, + }, nil +} + +func (b *Bot) Start() error { + if err := b.Session.Open(); err != nil { + return err + } + + b.registeredCommands = make([]*discordgo.ApplicationCommand, len(b.Commands)) + for _, cmd := range b.Commands { + created, err := b.Session.ApplicationCommandCreate(b.AppID, b.GuildID, cmd) + if err != nil { + log.Printf("Cannot create '%v' command: %v", cmd.Name, err) + continue + } + b.registeredCommands = append(b.registeredCommands, created) + } + + b.Session.AddHandler(commands.HandleInteraction) + return nil + +} + +func (b *Bot) Close() error { + for _, cmd := range b.registeredCommands { + if err := b.Session.ApplicationCommandDelete(b.AppID, b.GuildID, cmd.ID); err != nil { + log.Printf("cannot delete '%s' command: %v", cmd.Name, err) + } + } + return b.Session.Close() +} diff --git a/internal/commands/commands.go b/internal/commands/commands.go new file mode 100644 index 0000000..fdafb6a --- /dev/null +++ b/internal/commands/commands.go @@ -0,0 +1,21 @@ +package commands + +import ( + "velox-bot/internal/commands/fun" + + "github.com/bwmarrin/discordgo" +) + +var AllCommands = []*discordgo.ApplicationCommand{ + fun.PingCommand, +} + +var handlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ + "ping": fun.HandlePing, +} + +func HandleInteraction(s *discordgo.Session, i *discordgo.InteractionCreate) { + if h, ok := handlers[i.ApplicationCommandData().Name]; ok { + h(s, i) + } +} diff --git a/internal/commands/fun/ping.go b/internal/commands/fun/ping.go new file mode 100644 index 0000000..1567bfd --- /dev/null +++ b/internal/commands/fun/ping.go @@ -0,0 +1,17 @@ +package fun + +import "github.com/bwmarrin/discordgo" + +var PingCommand = &discordgo.ApplicationCommand{ + Name: "ping", + Description: "Ping the bot", +} + +func HandlePing(s *discordgo.Session, i *discordgo.InteractionCreate) { + s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "Pong!", + }, + }) +} diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..aa58118 --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,41 @@ +package config + +import ( + "fmt" + "os" + + "github.com/joho/godotenv" +) + +type Config struct { + BotToken string + AppID string + GuildID string +} + +func LoadConfig() (*Config, error) { + if err := godotenv.Load(); err != nil { + return nil, err + } + + token := os.Getenv("BOT_TOKEN") + if token == "" { + return nil, fmt.Errorf("BOT_TOKEN is not set") + } + + appID := os.Getenv("APP_ID") + if appID == "" { + return nil, fmt.Errorf("APP_ID is not set") + } + + guildID := os.Getenv("GUILD_ID") + if guildID == "" { + return nil, fmt.Errorf("GUILD_ID is not set") + } + + return &Config{ + BotToken: token, + AppID: appID, + GuildID: guildID, + }, nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..8d2a608 --- /dev/null +++ b/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/signal" + "syscall" + "velox-bot/internal/bot" + "velox-bot/internal/commands" + "velox-bot/internal/config" +) + +func main() { + config, err := config.LoadConfig() + if err != nil { + log.Fatalf("Error loading config: %v", err) + return + } + + bot, err := bot.NewBot(config.BotToken, config.AppID, config.GuildID, commands.AllCommands) + if err != nil { + log.Fatalf("Error creating bot: %v", err) + return + } + + err = bot.Start() + if err != nil { + log.Fatalf("Error starting bot: %v", err) + } + + defer bot.Close() + + fmt.Println("Bot is running...") + + sc := make(chan os.Signal, 1) + signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) + <-sc +}