init commit
This commit is contained in:
160
bolt.go
Normal file
160
bolt.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package bolt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dg "github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
const (
|
||||
TOKEN_ENV_VAR = "DISCORD_TOKEN" //label for token environment variable
|
||||
|
||||
BOT_INTENTS = dg.IntentGuildMembers | //discord permissions for the bot
|
||||
dg.IntentGuildPresences |
|
||||
dg.IntentMessageContent
|
||||
)
|
||||
|
||||
// basic bot structure containing discordgo connection as well as the command map
|
||||
type bolt struct {
|
||||
*dg.Session //holds discordgo internals
|
||||
Commands map[string]Command //maps trigger phrase to command struct for fast lookup
|
||||
}
|
||||
|
||||
type Bolt interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
AddCommands(cmd Command)
|
||||
messageHandler(s *dg.Session, msg *dg.MessageCreate)
|
||||
createReply(content, message, channel, guild string) *dg.MessageSend
|
||||
}
|
||||
|
||||
// setup
|
||||
func init() {
|
||||
//validate environment variables
|
||||
_, check := os.LookupEnv(TOKEN_ENV_VAR)
|
||||
if !check {
|
||||
log.Fatalf("the %s environment variable must be set", TOKEN_ENV_VAR)
|
||||
}
|
||||
}
|
||||
|
||||
// create a new bolt interface
|
||||
func New() *bolt {
|
||||
bot, err := dg.New(fmt.Sprintf("Bot %s", os.Getenv(TOKEN_ENV_VAR)))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
bot.Identify.Intents = BOT_INTENTS
|
||||
|
||||
return &bolt{
|
||||
Session: bot,
|
||||
}
|
||||
}
|
||||
|
||||
// adds command handler and starts the bot
|
||||
func (b *bolt) Start() error {
|
||||
//register commands and open connection
|
||||
b.AddHandler(b.messageHandler)
|
||||
|
||||
return b.Open()
|
||||
}
|
||||
|
||||
// stops the bot
|
||||
func (b *bolt) Stop() error {
|
||||
return b.Close()
|
||||
}
|
||||
|
||||
// adds commands to bot command map for use
|
||||
func (b *bolt) AddCommands(cmd ...Command) {
|
||||
for _, c := range cmd {
|
||||
b.Commands[c.Trigger] = c
|
||||
}
|
||||
}
|
||||
|
||||
// handler function that parses message data and executes any command payloads
|
||||
func (b *bolt) messageHandler(s *dg.Session, msg *dg.MessageCreate) {
|
||||
//get server information
|
||||
server, err := s.Guild(msg.GuildID)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
channel, err := s.Channel(msg.ChannelID)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
//if there is no content it is likely an image or a GIF, updating message content for
|
||||
//better logging and to avoid confusion
|
||||
if len(msg.Content) == 0 {
|
||||
msg.Content = "GIF/IMAGE"
|
||||
}
|
||||
|
||||
//log message
|
||||
log.Printf("< %s | %s | %s > %s\n", server.Name, channel.Name, msg.Author.Username, msg.Content)
|
||||
|
||||
//the bot will ignore it's own messages to prevent command loops
|
||||
if msg.Author.ID == s.State.User.ID {
|
||||
return
|
||||
}
|
||||
|
||||
//does the message have the command indicator "."
|
||||
if msg.Content[:1] == "." {
|
||||
words := strings.Split(msg.Content, " ")
|
||||
run, ok := b.Commands[words[0]]
|
||||
if !ok {
|
||||
return //command doesn't exist, maybe log or respond to author
|
||||
}
|
||||
|
||||
//has command met its timeout requirements
|
||||
if !time.Now().After(run.LastRun.Add(run.Timeout)) {
|
||||
return //running too soon, maybe respond letting know time remaining
|
||||
}
|
||||
|
||||
//run command payload
|
||||
res, err := run.Payload(Message{
|
||||
Author: Author{
|
||||
Username: msg.Author.Username,
|
||||
Roles: msg.Member.Roles,
|
||||
},
|
||||
Words: words,
|
||||
Message: msg.Content,
|
||||
Channel: channel.Name,
|
||||
Server: server.Name,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
//if a reply is returned send back to Discord
|
||||
if res != "" {
|
||||
reply := b.createReply(res, msg.ID, msg.ChannelID, msg.GuildID)
|
||||
_, err := s.ChannelMessageSendComplex(msg.ChannelID, reply)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// basic wrapper function to create easy Discord responses
|
||||
func (b *bolt) createReply(content, message, channel, guild string) *dg.MessageSend {
|
||||
details := &dg.MessageReference{
|
||||
MessageID: message,
|
||||
ChannelID: channel,
|
||||
GuildID: guild,
|
||||
}
|
||||
|
||||
return &dg.MessageSend{
|
||||
Content: content,
|
||||
Reference: details,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user