-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.go
294 lines (241 loc) · 9.35 KB
/
main.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/switchupcb/disgo"
tools "github.com/switchupcb/disgo/tools"
)
// Environment Variables.
var (
// token represents the bot's token.
token = os.Getenv("TOKEN")
// appid represents the bot's ApplicationID.
//
// Use Developer Mode to find it, or call GetCurrentUser (request) in your program
// and set it programmatically.
appid = os.Getenv("APPID")
)
func main() {
// enable the logger for the API Wrapper.
// zerolog.SetGlobalLevel(zerolog.DebugLevel)
log.Println("Program is started.")
// create a new Bot Client.
bot := &disgo.Client{
ApplicationID: appid, // REQUIRED (for this example).
Authentication: disgo.BotToken(token), // or BearerToken("TOKEN")
Config: disgo.DefaultConfig(),
Handlers: new(disgo.Handlers),
Sessions: disgo.NewSessionManager(),
}
log.Println("Creating an application command...")
// Create a Create Global Application Command request.
request := &disgo.CreateGlobalApplicationCommand{
Name: "autocomplete",
Description: disgo.Pointer("Learn about autocompletion."),
Options: []*disgo.ApplicationCommandOption{
{
Name: "freewill",
Description: "Do you have it?",
Type: disgo.FlagApplicationCommandOptionTypeSTRING,
Required: disgo.Pointer(true),
// The following choices are the ONLY valid choices for this option.
Choices: []*disgo.ApplicationCommandOptionChoice{
{
Name: "Yes",
Value: "y",
},
{
Name: "No",
Value: "n",
},
},
},
{
Name: "confirm",
Description: "Confirm your answer.",
Type: disgo.FlagApplicationCommandOptionTypeSTRING,
Required: disgo.Pointer(true),
// Autocomplete choices will be provided, but the user can still
// input any value for this option.
Autocomplete: disgo.Pointer(true),
},
},
}
// Register the new command by sending the request to Discord using the bot.
//
// returns a disgo.ApplicationCommand
newCommand, err := request.Send(bot)
if err != nil {
log.Printf("failure sending command to Discord: %v", err)
return
}
log.Println("Adding an event handler.")
// Add an event handler to the bot.
//
// confirm the event handler is added to the bot.
if err := bot.Handle(disgo.FlagGatewayEventNameInteractionCreate, func(i *disgo.InteractionCreate) {
log.Println("Received interaction.")
// see func declaration below.
if err := onInteraction(bot, i.Interaction); err != nil {
log.Println(err)
}
}); err != nil {
// when the Handle(eventname, function) parameters are not configured correctly.
log.Printf("Failed to add event handler to bot: %v", err)
os.Exit(1)
}
log.Println("Connecting to the Discord Gateway...")
// Connect a new session to the Discord Gateway (WebSocket Connection).
session := disgo.NewSession()
if err := session.Connect(bot); err != nil {
log.Printf("can't open websocket session to Discord Gateway: %v", err)
return
}
log.Println("Successfully connected to the Discord Gateway. Waiting for an interaction...")
// end the program using a SIGINT call via `Ctrl + C` from the terminal.
if err := tools.InterceptSignal(tools.Signals, session); err != nil {
log.Printf("error exiting program: %v", err)
}
log.Println("Exiting program due to signal...")
// tools.InterceptSignal() calls s.Disconnect() which disconnects the Session from the Discord Gateway.
log.Println("Disconnected from the Discord Gateway.")
// The following code is not necessarily required, but useful for the cleanup of this program.
//
// delete the Global Application Command.
log.Println("Deleting the application command...")
requestDeleteGlobalApplicationCommand := &disgo.DeleteGlobalApplicationCommand{CommandID: newCommand.ID}
if err := requestDeleteGlobalApplicationCommand.Send(bot); err != nil {
log.Printf("error deleting Global Application Command: %v", err)
return
}
log.Printf("Program executed successfully.")
}
// onInteraction sends the user autocomplete choices.
//
// In this example, onInteraction is called when a user sends a `/autocomplete` interaction to the bot.
func onInteraction(bot *disgo.Client, interaction *disgo.Interaction) error {
// User input will be returned as partial data to this bot application.
//
// check whether autocomplete data or a command submission has been received.
switch interaction.Type {
case disgo.FlagInteractionTypeAPPLICATION_COMMAND_AUTOCOMPLETE:
log.Println("The interaction contains autocompletion data. Sending choices...")
// access the interaction's options in the order provided by the user.
//
// The following commands assist with type converting Interaction Data
// into the respective data structs.
//
// ApplicationCommand()
// MessageComponent()
// ModalSubmit()
//
options := interaction.ApplicationCommand().Options
// Alternatively, convert the option slice into a map (in an efficient manner).
//
// Note: It's recommended to specify the amount explicitly when possible (i.e 3).
// Otherwise, the tools package provides an easy way to determine the amount of options.
optionMap := tools.OptionsToMap(nil, options, tools.NumOptions(options))
// determine the choices that will be sent to the user depending on the incoming options.
//
// Discord will highlight the closest choice to the user's input.
choices := []*disgo.ApplicationCommandOptionChoice{
{
Name: "Yes",
Value: "y",
},
{
Name: "No",
Value: "n",
},
}
// Note: In order to receive autocompletion data, one option must be non-nil,
// but this does NOT imply that the non-nil option is NOT empty (i.e "").
freewill := optionMap["freewill"]
confirm := optionMap["confirm"]
switch {
// When the user is completing their first option, send both choices.
case (freewill != nil && confirm == nil) || (freewill == nil && confirm != nil):
log.Println("Sending both choices...")
// When the user has completed both options, determine which option is focused
// to provide the correct choice.
//
// This case is executed when the freewill option is focused.
case freewill != nil && freewill.Focused != nil && *freewill.Focused:
if confirm.Value.String() == "Yes" {
choices = choices[1:] // n
} else if confirm.Value.String() == "No" {
choices = choices[0:1] // y
}
log.Println("Sending choice opposite of confirm...")
// This case is executed when the confirm option is focused.
case confirm != nil && confirm.Focused != nil && *confirm.Focused:
if freewill.Value.String() == "y" {
choices = choices[1:] // n
} else {
choices = choices[0:1] // y
}
log.Println("Sending choice opposite of freewill...")
default:
log.Println("Unknown choice state encountered. Sending both choices...")
}
requestAutocomplete := &disgo.CreateInteractionResponse{
InteractionID: interaction.ID,
InteractionToken: interaction.Token,
InteractionResponse: &disgo.InteractionResponse{
Type: disgo.FlagInteractionCallbackTypeAPPLICATION_COMMAND_AUTOCOMPLETE_RESULT,
Data: &disgo.Autocomplete{
Choices: choices,
},
},
}
if err := requestAutocomplete.Send(bot); err != nil {
return fmt.Errorf("failure sending autocompletion command to Discord: %w", err)
}
log.Println("Sent choices.")
case disgo.FlagInteractionTypeAPPLICATION_COMMAND:
log.Println("The interaction contains command data. Sending interaction response...")
// determine the response.
options := interaction.ApplicationCommand().Options
optionMap := tools.OptionsToMap(nil, options, tools.NumOptions(options))
freewill := optionMap["freewill"]
confirm := optionMap["confirm"]
response := "Hmmm. I guess you aren't sure..."
if freewill.Value.String() == "y" && strings.ToLower(confirm.Value.String()) == "yes" {
response = "Where there's a will there's a way."
} else if freewill.Value.String() == "n" && strings.ToLower(confirm.Value.String()) == "no" {
response = "Fate awaits you."
}
// When the interaction is submitted, send an interaction response to reply to the user.
requestCreateInteractionResponse := &disgo.CreateInteractionResponse{
InteractionID: interaction.ID,
// Interaction tokens are valid for 15 minutes,
// but an initial response to an interaction must be sent within 3 seconds (of receiving it),
// otherwise the token is invalidated.
InteractionToken: interaction.Token,
// https://discord.com/developers/docs/interactions/receiving-and-responding#responding-to-an-interaction
InteractionResponse: &disgo.InteractionResponse{
Type: disgo.FlagInteractionCallbackTypeCHANNEL_MESSAGE_WITH_SOURCE,
// Any of the following objects can be used.
//
// Messages
// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-messages
//
// Autocomplete
// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-autocomplete
//
// Modal
// https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-modal
Data: &disgo.Messages{
Content: disgo.Pointer(response), // &response
},
},
}
if err := requestCreateInteractionResponse.Send(bot); err != nil {
return fmt.Errorf("error sending interaction response: %w", err)
}
log.Println("Sent interaction response.")
}
return nil
}