-
Notifications
You must be signed in to change notification settings - Fork 1
/
bot.go
executable file
·166 lines (150 loc) · 4.07 KB
/
bot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package bot
import (
"fmt"
"regexp"
"github.com/andersfylling/disgord"
"github.com/andersfylling/disgord/std"
)
// Bot is a simple wrapper over a disgord Client. It is not protected by a mutex.
type Bot struct {
Client *disgord.Client
Info Info
commands map[string]*Command
commandList []*Command
helpCommand *Command
}
// Info wraps some bot info.
type Info struct {
disgord.Config
Name string
Prefix string
Description string
SupportURL string
}
// Command represents a bot command.
type Command struct {
ID string
Usage string
Description string
Handler func(*Context)
}
// Used for parsing args, the string `hello "wor ld"` will be parsed to ["hello", "wor ld"]
var argsRe = regexp.MustCompile(`"([^"]+)"|([^\s]+)`)
// New creates a new bot with the given BotInfo.
func New(info Info) *Bot {
bot := Bot{
Client: disgord.New(info.Config),
Info: info,
commands: make(map[string]*Command),
}
bot.helpCommand = &Command{
ID: "help",
Description: "Shows the bot help message",
Handler: bot.sendHelp,
}
bot.Client.Gateway().
WithMiddleware(
filterMsgCreateNotBot, std.CopyMsgEvt, filterMsgCreateStripPrefix(bot.Info.Prefix)).
MessageCreate(bot.maybeHandleCommand)
return &bot
}
// OnMessageCreate attaches a handler that is called on the message create event.
func (bot *Bot) OnMessageCreate(handler func(*Context, *disgord.MessageCreate)) {
wrapped := func(s disgord.Session, evt *disgord.MessageCreate) {
ctx := &Context{
Bot: bot,
Session: s,
Message: evt.Message,
Logger: s.Logger(),
}
handler(ctx, evt)
}
bot.Client.Gateway().WithMiddleware(filterMsgCreateNotBot).MessageCreate(wrapped)
}
// AddCommand adds a Command to the bot.
func (bot *Bot) AddCommand(command *Command) {
bot.commands[command.ID] = command
bot.commandList = append(bot.commandList, command)
}
func (bot *Bot) maybeHandleCommand(s disgord.Session, evt *disgord.MessageCreate) {
ctx := &Context{
Bot: bot,
Session: s,
Message: evt.Message,
Logger: s.Logger(),
}
if ctx.Args = argsRe.FindAllString(evt.Message.Content, -1); ctx.Args == nil {
bot.rejectCommand(ctx, "")
return
}
commandID := ctx.Args[0]
var ok bool
if ctx.Command, ok = bot.commands[commandID]; ok {
ctx.Logger.Info("Dispatching command: ", commandID)
ctx.Command.Handler(ctx)
} else if commandID == bot.helpCommand.ID {
ctx.Logger.Info("Dispatching help command")
ctx.Command = bot.helpCommand
ctx.Command.Handler(ctx)
} else {
bot.rejectCommand(ctx, commandID)
}
}
func (bot *Bot) sendHelp(ctx *Context) {
go func() {
if len(ctx.Args) > 1 {
ctx.SendIncorrectUsageMsg()
return
}
ctx.Send(bot.buildHelpEmbed())
}()
}
func (bot *Bot) rejectCommand(ctx *Context, commandID string) {
var content string
switch commandID {
case "":
content = fmt.Sprintf(
"Missing command, send `%v` for help",
bot.addPrefix(bot.helpCommand))
default:
content = fmt.Sprintf(
"Unknown command `%v`, send `%v` for help",
commandID, bot.addPrefix(bot.helpCommand))
}
ctx.Send(content)
}
func (bot *Bot) addPrefix(command *Command) string {
return bot.Info.Prefix + command.FullUsage()
}
func (bot *Bot) buildHelpEmbed() *disgord.Embed {
var fields []*disgord.EmbedField
for _, command := range bot.commandList {
fields = append(fields, &disgord.EmbedField{
Name: command.FullUsage(),
Value: command.Description,
Inline: true,
})
}
fields = append(fields, &disgord.EmbedField{
Name: bot.helpCommand.FullUsage(),
Value: bot.helpCommand.Description,
Inline: true,
})
embed := disgord.Embed{
Description: bot.Info.Description + "\n\n**Commands**",
Fields: fields,
}
return &embed
}
// FullUsage returns the "ID Usage" form of the command.
func (com *Command) FullUsage() string {
if com.Usage == "" {
return com.ID
}
return com.ID + " " + com.Usage
}
// IncorrectUsageMsg returns a message that may be sent if the command is invoked with incorrect
// arguments.
func (com *Command) IncorrectUsageMsg() string {
return fmt.Sprintf("Incorrect usage, expected `%v`", com.FullUsage())
}