feat(discord bot): added in a ping host command to get the bot going :D

more commands will be added as we continue working on this bot, including service restarts, log
monitors
This commit is contained in:
2025-09-11 06:44:50 -05:00
parent 463dabfcf4
commit 3244f284fd
7 changed files with 262 additions and 5 deletions

View File

@@ -1,5 +1,84 @@
package bot
func main() {
import (
"context"
"fmt"
"os"
"os/signal"
"github.com/bwmarrin/discordgo"
)
func TheBot() {
Token := os.Getenv("BOT_KEY")
if Token == "" {
fmt.Println("You must set DISCORD_TOKEN environment variable.")
return
}
// Create bot session
dg, err := discordgo.New("Bot " + Token)
if err != nil {
fmt.Println("Error creating Discord session,", err)
return
}
dg.Identify.Intents = discordgo.IntentsGuildMessages |
discordgo.IntentsDirectMessages |
discordgo.IntentsMessageContent | discordgo.IntentsGuilds
// Register messageCreate as a callback for MessageCreate events
dg.AddHandler(interactionCreate)
// // Open the websocket and begin listening
err = dg.Open()
if err != nil {
fmt.Println("Error opening Discord session,", err)
return
}
// Wait here until CTRL-C or other term signal is received.
fmt.Println("Bot is now running. Press CTRL-C to exit.")
// Register commands, passing the session
registerCommands(dg)
// sc := make(chan os.Signal, 1)
// signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
// <-sc
// // Cleanly close down the Discord session.
// dg.Close()
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
<-ctx.Done()
cleanupCommands(dg)
dg.Close()
}
// This function will be called (due to event handler registration above)
// every time a new message is created on any channel that the authed bot has access to.
// func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
// // ignore bots (including self)
// if m.Author == nil || m.Author.Bot {
// return
// }
// // debug: log incoming messages so you can see them in console
// fmt.Printf("msg from %s: %s\n", m.Author.Username, m.Content)
// // choose the prefix you want — here I check for "!ping"
// if m.Content == "!ping" {
// if _, err := s.ChannelMessageSend(m.ChannelID, "Pong!"); err != nil {
// fmt.Println("send error:", err)
// }
// }
// if m.Content == "!pong" {
// if _, err := s.ChannelMessageSend(m.ChannelID, "Ping!"); err != nil {
// fmt.Println("send error:", err)
// }
// }
// }

View File

@@ -0,0 +1,64 @@
package bot
import (
"fmt"
"github.com/bwmarrin/discordgo"
)
var registeredCommands = []*discordgo.ApplicationCommand{
{
Name: "ping",
Description: "Ping a server to make sure it's still online.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "host",
Description: "The server hostname or IP to ping",
Required: true,
},
},
},
// future commands can be added here
}
func registerCommands(s *discordgo.Session) {
existing, err := s.ApplicationCommands(s.State.User.ID, "")
if err != nil {
fmt.Println("Failed to list existing commands:", err)
return
}
for _, cmd := range registeredCommands {
alreadyExists := false
for _, e := range existing {
if e.Name == cmd.Name {
alreadyExists = true
break
}
}
if alreadyExists {
fmt.Printf("Command '%s' already exists, skipping registration.\n", cmd.Name)
continue
}
_, err := s.ApplicationCommandCreate(s.State.User.ID, "", cmd)
if err != nil {
fmt.Printf("Cannot create command '%s': %v\n", cmd.Name, err)
} else {
fmt.Printf("Registered command: %s\n", cmd.Name)
}
}
}
// Cleanup commands on shutdown
func cleanupCommands(s *discordgo.Session) {
commands, err := s.ApplicationCommands(s.State.User.ID, "")
if err != nil {
return
}
for _, cmd := range commands {
_ = s.ApplicationCommandDelete(s.State.User.ID, "", cmd.ID)
}
}

View File

@@ -0,0 +1,18 @@
package bot
import (
"github.com/bwmarrin/discordgo"
)
func interactionCreate(s *discordgo.Session, i *discordgo.InteractionCreate) {
if i.Type != discordgo.InteractionApplicationCommand {
return
}
switch i.ApplicationCommandData().Name {
case "ping":
// Get the host parameter
// sending s sends the session over to pinger, then i is the interactions we send over
HandlePingCommand(s, i)
}
}

View File

@@ -0,0 +1,59 @@
package bot
import (
"fmt"
"net"
"github.com/bwmarrin/discordgo"
)
func HandlePingCommand(s *discordgo.Session, i *discordgo.InteractionCreate) {
// Get the host parameter
options := i.ApplicationCommandData().Options
host := options[0].StringValue()
// Optionally, do a DNS lookup or ICMP ping
ips, err := net.LookupIP(host)
if err != nil {
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("Could not resolve host `%s`: %v", host, err),
},
})
return
}
// // host is the user-provided hostname
// pinger, err := probing.NewPinger(host)
// if err != nil {
// s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
// Type: discordgo.InteractionResponseChannelMessageWithSource,
// Data: &discordgo.InteractionResponseData{
// Content: fmt.Sprintf("Error creating pinger: %v", err),
// },
// })
// return
// }
// pinger.Count = 3
// pinger.SetPrivileged(false) // <- key for Windows non-admin
// err = pinger.Run()
// if err != nil {
// s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
// Type: discordgo.InteractionResponseChannelMessageWithSource,
// Data: &discordgo.InteractionResponseData{
// Content: fmt.Sprintf("Error running ping: %v", err),
// },
// })
// return
// }
// stats := pinger.Statistics()
// Respond with the first IP found
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("Host `%s` resolves to %s ✅", host, ips[0].String()),
},
})
}