rubycord 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/lib/rubycord/allowed_mentions.rb +34 -0
  3. data/lib/rubycord/api/application.rb +200 -0
  4. data/lib/rubycord/api/channel.rb +597 -0
  5. data/lib/rubycord/api/interaction.rb +52 -0
  6. data/lib/rubycord/api/invite.rb +42 -0
  7. data/lib/rubycord/api/server.rb +557 -0
  8. data/lib/rubycord/api/user.rb +153 -0
  9. data/lib/rubycord/api/webhook.rb +138 -0
  10. data/lib/rubycord/api.rb +356 -0
  11. data/lib/rubycord/await.rb +49 -0
  12. data/lib/rubycord/bot.rb +1757 -0
  13. data/lib/rubycord/cache.rb +259 -0
  14. data/lib/rubycord/colour_rgb.rb +41 -0
  15. data/lib/rubycord/commands/command_bot.rb +519 -0
  16. data/lib/rubycord/commands/container.rb +110 -0
  17. data/lib/rubycord/commands/events.rb +9 -0
  18. data/lib/rubycord/commands/parser.rb +325 -0
  19. data/lib/rubycord/commands/rate_limiter.rb +142 -0
  20. data/lib/rubycord/container.rb +753 -0
  21. data/lib/rubycord/data/activity.rb +269 -0
  22. data/lib/rubycord/data/application.rb +48 -0
  23. data/lib/rubycord/data/attachment.rb +109 -0
  24. data/lib/rubycord/data/audit_logs.rb +343 -0
  25. data/lib/rubycord/data/channel.rb +996 -0
  26. data/lib/rubycord/data/component.rb +227 -0
  27. data/lib/rubycord/data/embed.rb +249 -0
  28. data/lib/rubycord/data/emoji.rb +80 -0
  29. data/lib/rubycord/data/integration.rb +120 -0
  30. data/lib/rubycord/data/interaction.rb +798 -0
  31. data/lib/rubycord/data/invite.rb +135 -0
  32. data/lib/rubycord/data/member.rb +370 -0
  33. data/lib/rubycord/data/message.rb +412 -0
  34. data/lib/rubycord/data/overwrite.rb +106 -0
  35. data/lib/rubycord/data/profile.rb +89 -0
  36. data/lib/rubycord/data/reaction.rb +31 -0
  37. data/lib/rubycord/data/recipient.rb +32 -0
  38. data/lib/rubycord/data/role.rb +246 -0
  39. data/lib/rubycord/data/server.rb +1002 -0
  40. data/lib/rubycord/data/user.rb +261 -0
  41. data/lib/rubycord/data/voice_region.rb +43 -0
  42. data/lib/rubycord/data/voice_state.rb +39 -0
  43. data/lib/rubycord/data/webhook.rb +232 -0
  44. data/lib/rubycord/data.rb +40 -0
  45. data/lib/rubycord/errors.rb +737 -0
  46. data/lib/rubycord/events/await.rb +46 -0
  47. data/lib/rubycord/events/bans.rb +58 -0
  48. data/lib/rubycord/events/channels.rb +186 -0
  49. data/lib/rubycord/events/generic.rb +126 -0
  50. data/lib/rubycord/events/guilds.rb +191 -0
  51. data/lib/rubycord/events/interactions.rb +480 -0
  52. data/lib/rubycord/events/invites.rb +123 -0
  53. data/lib/rubycord/events/lifetime.rb +29 -0
  54. data/lib/rubycord/events/members.rb +91 -0
  55. data/lib/rubycord/events/message.rb +337 -0
  56. data/lib/rubycord/events/presence.rb +127 -0
  57. data/lib/rubycord/events/raw.rb +45 -0
  58. data/lib/rubycord/events/reactions.rb +156 -0
  59. data/lib/rubycord/events/roles.rb +86 -0
  60. data/lib/rubycord/events/threads.rb +94 -0
  61. data/lib/rubycord/events/typing.rb +70 -0
  62. data/lib/rubycord/events/voice_server_update.rb +45 -0
  63. data/lib/rubycord/events/voice_state_update.rb +103 -0
  64. data/lib/rubycord/events/webhooks.rb +62 -0
  65. data/lib/rubycord/gateway.rb +867 -0
  66. data/lib/rubycord/id_object.rb +37 -0
  67. data/lib/rubycord/light/data.rb +60 -0
  68. data/lib/rubycord/light/integrations.rb +71 -0
  69. data/lib/rubycord/light/light_bot.rb +56 -0
  70. data/lib/rubycord/light.rb +6 -0
  71. data/lib/rubycord/logger.rb +118 -0
  72. data/lib/rubycord/paginator.rb +55 -0
  73. data/lib/rubycord/permissions.rb +251 -0
  74. data/lib/rubycord/version.rb +5 -0
  75. data/lib/rubycord/voice/encoder.rb +113 -0
  76. data/lib/rubycord/voice/network.rb +366 -0
  77. data/lib/rubycord/voice/sodium.rb +96 -0
  78. data/lib/rubycord/voice/voice_bot.rb +408 -0
  79. data/lib/rubycord/webhooks/builder.rb +100 -0
  80. data/lib/rubycord/webhooks/client.rb +132 -0
  81. data/lib/rubycord/webhooks/embeds.rb +248 -0
  82. data/lib/rubycord/webhooks/modal.rb +78 -0
  83. data/lib/rubycord/webhooks/version.rb +7 -0
  84. data/lib/rubycord/webhooks/view.rb +192 -0
  85. data/lib/rubycord/webhooks.rb +12 -0
  86. data/lib/rubycord/websocket.rb +70 -0
  87. data/lib/rubycord.rb +140 -0
  88. metadata +231 -0
@@ -0,0 +1,138 @@
1
+ # API calls for Webhook object
2
+ module Rubycord::API::Webhook
3
+ module_function
4
+
5
+ # Get a webhook
6
+ # https://discord.com/developers/docs/resources/webhook#get-webhook
7
+ def webhook(token, webhook_id)
8
+ Rubycord::API.request(
9
+ :webhooks_wid,
10
+ nil,
11
+ :get,
12
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}",
13
+ Authorization: token
14
+ )
15
+ end
16
+
17
+ # Get a webhook via webhook token
18
+ # https://discord.com/developers/docs/resources/webhook#get-webhook-with-token
19
+ def token_webhook(webhook_token, webhook_id)
20
+ Rubycord::API.request(
21
+ :webhooks_wid,
22
+ nil,
23
+ :get,
24
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}"
25
+ )
26
+ end
27
+
28
+ # Execute a webhook via token.
29
+ # https://discord.com/developers/docs/resources/webhook#execute-webhook
30
+ def token_execute_webhook(webhook_token, webhook_id, wait = false, content = nil, username = nil, avatar_url = nil, tts = nil, file = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil)
31
+ body = {content: content, username: username, avatar_url: avatar_url, tts: tts, embeds: embeds&.map(&:to_hash), allowed_mentions: allowed_mentions, flags: flags, components: components}
32
+ body = if file
33
+ {file: file, payload_json: body.to_json}
34
+ else
35
+ body.to_json
36
+ end
37
+
38
+ headers = {content_type: :json} unless file
39
+
40
+ Rubycord::API.request(
41
+ :webhooks_wid,
42
+ webhook_id,
43
+ :post,
44
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}?wait=#{wait}",
45
+ body,
46
+ headers
47
+ )
48
+ end
49
+
50
+ # Update a webhook
51
+ # https://discord.com/developers/docs/resources/webhook#modify-webhook
52
+ def update_webhook(token, webhook_id, data, reason = nil)
53
+ Rubycord::API.request(
54
+ :webhooks_wid,
55
+ webhook_id,
56
+ :patch,
57
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}",
58
+ data.to_json,
59
+ Authorization: token,
60
+ content_type: :json,
61
+ "X-Audit-Log-Reason": reason
62
+ )
63
+ end
64
+
65
+ # Update a webhook via webhook token
66
+ # https://discord.com/developers/docs/resources/webhook#modify-webhook-with-token
67
+ def token_update_webhook(webhook_token, webhook_id, data, reason = nil)
68
+ Rubycord::API.request(
69
+ :webhooks_wid,
70
+ webhook_id,
71
+ :patch,
72
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}",
73
+ data.to_json,
74
+ content_type: :json,
75
+ "X-Audit-Log-Reason": reason
76
+ )
77
+ end
78
+
79
+ # Deletes a webhook
80
+ # https://discord.com/developers/docs/resources/webhook#delete-webhook
81
+ def delete_webhook(token, webhook_id, reason = nil)
82
+ Rubycord::API.request(
83
+ :webhooks_wid,
84
+ webhook_id,
85
+ :delete,
86
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}",
87
+ Authorization: token,
88
+ "X-Audit-Log-Reason": reason
89
+ )
90
+ end
91
+
92
+ # Deletes a webhook via webhook token
93
+ # https://discord.com/developers/docs/resources/webhook#delete-webhook-with-token
94
+ def token_delete_webhook(webhook_token, webhook_id, reason = nil)
95
+ Rubycord::API.request(
96
+ :webhooks_wid,
97
+ webhook_id,
98
+ :delete,
99
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}",
100
+ "X-Audit-Log-Reason": reason
101
+ )
102
+ end
103
+
104
+ # Get a message that was created by the webhook corresponding to the provided token.
105
+ # https://discord.com/developers/docs/resources/webhook#get-webhook-message
106
+ def token_get_message(webhook_token, webhook_id, message_id)
107
+ Rubycord::API.request(
108
+ :webhooks_wid_messages_mid,
109
+ webhook_id,
110
+ :get,
111
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}"
112
+ )
113
+ end
114
+
115
+ # Edit a webhook message via webhook token
116
+ # https://discord.com/developers/docs/resources/webhook#edit-webhook-message
117
+ def token_edit_message(webhook_token, webhook_id, message_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil)
118
+ Rubycord::API.request(
119
+ :webhooks_wid_messages,
120
+ webhook_id,
121
+ :patch,
122
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}",
123
+ {content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components}.to_json,
124
+ content_type: :json
125
+ )
126
+ end
127
+
128
+ # Delete a webhook message via webhook token.
129
+ # https://discord.com/developers/docs/resources/webhook#delete-webhook-message
130
+ def token_delete_message(webhook_token, webhook_id, message_id)
131
+ Rubycord::API.request(
132
+ :webhooks_wid_messages,
133
+ webhook_id,
134
+ :delete,
135
+ "#{Rubycord::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}"
136
+ )
137
+ end
138
+ end
@@ -0,0 +1,356 @@
1
+ require "rest-client"
2
+ require "json"
3
+ require "time"
4
+
5
+ require "rubycord/errors"
6
+
7
+ # List of methods representing endpoints in Discord's API
8
+ module Rubycord::API
9
+ # The base URL of the Discord REST API.
10
+ APIBASE = "https://discord.com/api/v9"
11
+
12
+ # The URL of Discord's CDN
13
+ CDN_URL = "https://cdn.discordapp.com"
14
+
15
+ module_function
16
+
17
+ # @return [String] the currently used API base URL.
18
+ def api_base
19
+ @api_base || APIBASE
20
+ end
21
+
22
+ # Sets the API base URL to something.
23
+ def api_base=(value)
24
+ @api_base = value
25
+ end
26
+
27
+ # @return [String] the currently used CDN url
28
+ def cdn_url
29
+ @cdn_url || CDN_URL
30
+ end
31
+
32
+ # @return [String] the bot name, previously specified using {.bot_name=}.
33
+ def bot_name
34
+ @bot_name
35
+ end
36
+
37
+ # Sets the bot name to something. Used in {.user_agent}. For the bot's username, see {Profile#username=}.
38
+ def bot_name=(value)
39
+ @bot_name = value
40
+ end
41
+
42
+ # Changes the rate limit tracing behaviour. If rate limit tracing is on, a full backtrace will be logged on every RL
43
+ # hit.
44
+ # @param value [true, false] whether or not to enable rate limit tracing
45
+ def trace=(value)
46
+ @trace = value
47
+ end
48
+
49
+ # Generate a user agent identifying this requester as rubycord.
50
+ def user_agent
51
+ # This particular string is required by the Discord devs.
52
+ required = "DiscordBot (https://github.com/dakurei-gems/rubycord, v#{Rubycord::VERSION})"
53
+ @bot_name ||= ""
54
+
55
+ "#{required} rest-client/#{RestClient::VERSION} #{RUBY_ENGINE}/#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} rubycord/#{Rubycord::VERSION} #{@bot_name}"
56
+ end
57
+
58
+ # Resets all rate limit mutexes
59
+ def reset_mutexes
60
+ @mutexes = {}
61
+ @global_mutex = Mutex.new
62
+ end
63
+
64
+ # Wait a specified amount of time synchronised with the specified mutex.
65
+ def sync_wait(time, mutex)
66
+ mutex.synchronize { sleep time }
67
+ end
68
+
69
+ # Wait for a specified mutex to unlock and do nothing with it afterwards.
70
+ def mutex_wait(mutex)
71
+ mutex.lock
72
+ mutex.unlock
73
+ end
74
+
75
+ # Performs a RestClient request.
76
+ # @param type [Symbol] The type of HTTP request to use.
77
+ # @param attributes [Array] The attributes for the request.
78
+ def raw_request(type, attributes)
79
+ RestClient.send(type, *attributes)
80
+ rescue RestClient::Forbidden => e
81
+ # HACK: for #request, dynamically inject restclient's response into NoPermission - this allows us to rate limit
82
+ noprm = Rubycord::Errors::NoPermission.new
83
+ noprm.define_singleton_method(:_rc_response) { e.response }
84
+ raise noprm, "The bot doesn't have the required permission to do this!"
85
+ rescue RestClient::BadGateway
86
+ Rubycord::LOGGER.warn("Got a 502 while sending a request! Not a big deal, retrying the request")
87
+ retry
88
+ end
89
+
90
+ # Make an API request, including rate limit handling.
91
+ def request(key, major_parameter, type, *attributes)
92
+ # Add a custom user agent
93
+ attributes.last[:user_agent] = user_agent if attributes.last.is_a? Hash
94
+
95
+ # The most recent Discord rate limit requirements require the support of major parameters, where a particular route
96
+ # and major parameter combination (*not* the HTTP method) uniquely identifies a RL bucket.
97
+ key = [key, major_parameter].freeze
98
+
99
+ begin
100
+ mutex = @mutexes[key] ||= Mutex.new
101
+
102
+ # Lock and unlock, i.e. wait for the mutex to unlock and don't do anything with it afterwards
103
+ mutex_wait(mutex)
104
+
105
+ # If the global mutex happens to be locked right now, wait for that as well.
106
+ mutex_wait(@global_mutex) if @global_mutex.locked?
107
+
108
+ response = nil
109
+ begin
110
+ response = raw_request(type, attributes)
111
+ rescue RestClient::Exception => e
112
+ response = e.response
113
+
114
+ if response.body && !e.is_a?(RestClient::TooManyRequests)
115
+ data = JSON.parse(response.body)
116
+ err_klass = Rubycord::Errors.error_class_for(data["code"] || 0)
117
+ e = err_klass.new(data["message"], data["errors"])
118
+
119
+ Rubycord::LOGGER.error(e.full_message)
120
+ end
121
+
122
+ raise e
123
+ rescue Rubycord::Errors::NoPermission => e
124
+ if e.respond_to?(:_rc_response)
125
+ response = e._rc_response
126
+ else
127
+ Rubycord::LOGGER.warn("NoPermission doesn't respond_to? _rc_response!")
128
+ end
129
+
130
+ raise e
131
+ ensure
132
+ if response
133
+ handle_preemptive_rl(response.headers, mutex, key) if response.headers[:x_ratelimit_remaining] == "0" && !mutex.locked?
134
+ else
135
+ Rubycord::LOGGER.ratelimit("Response was nil before trying to preemptively rate limit!")
136
+ end
137
+ end
138
+ rescue RestClient::TooManyRequests => e
139
+ # If the 429 is from the global RL, then we have to use the global mutex instead.
140
+ mutex = @global_mutex if e.response.headers[:x_ratelimit_global] == "true"
141
+
142
+ unless mutex.locked?
143
+ response = JSON.parse(e.response)
144
+ wait_seconds = response["retry_after"] ? response["retry_after"].to_f : e.response.headers[:retry_after].to_i
145
+ Rubycord::LOGGER.ratelimit("Locking RL mutex (key: #{key}) for #{wait_seconds} seconds due to Discord rate limiting")
146
+ trace("429 #{key.join(" ")}")
147
+
148
+ # Wait the required time synchronized by the mutex (so other incoming requests have to wait) but only do it if
149
+ # the mutex isn't locked already so it will only ever wait once
150
+ sync_wait(wait_seconds, mutex)
151
+ end
152
+
153
+ retry
154
+ end
155
+
156
+ response
157
+ end
158
+
159
+ # Handles pre-emptive rate limiting by waiting the given mutex by the difference of the Date header to the
160
+ # X-Ratelimit-Reset header, thus making sure we don't get 429'd in any subsequent requests.
161
+ def handle_preemptive_rl(headers, mutex, key)
162
+ Rubycord::LOGGER.ratelimit "RL bucket depletion detected! Date: #{headers[:date]} Reset: #{headers[:x_ratelimit_reset]}"
163
+ delta = headers[:x_ratelimit_reset_after].to_f
164
+ Rubycord::LOGGER.warn("Locking RL mutex (key: #{key}) for #{delta} seconds pre-emptively")
165
+ sync_wait(delta, mutex)
166
+ end
167
+
168
+ # Perform rate limit tracing. All this method does is log the current backtrace to the console with the `:ratelimit`
169
+ # level.
170
+ # @param reason [String] the reason to include with the backtrace.
171
+ def trace(reason)
172
+ unless @trace
173
+ Rubycord::LOGGER.debug("trace was called with reason #{reason}, but tracing is not enabled")
174
+ return
175
+ end
176
+
177
+ Rubycord::LOGGER.ratelimit("Trace (#{reason}):")
178
+
179
+ caller.each do |str|
180
+ Rubycord::LOGGER.ratelimit(" #{str}")
181
+ end
182
+ end
183
+
184
+ # Make an icon URL from server and icon IDs
185
+ def icon_url(server_id, icon_id, format = "webp")
186
+ "#{cdn_url}/icons/#{server_id}/#{icon_id}.#{format}"
187
+ end
188
+
189
+ # Make an icon URL from application and icon IDs
190
+ def app_icon_url(app_id, icon_id, format = "webp")
191
+ "#{cdn_url}/app-icons/#{app_id}/#{icon_id}.#{format}"
192
+ end
193
+
194
+ # Make a widget picture URL from server ID
195
+ def widget_url(server_id, style = "shield")
196
+ "#{api_base}/guilds/#{server_id}/widget.png?style=#{style}"
197
+ end
198
+
199
+ # Make a splash URL from server and splash IDs
200
+ def splash_url(server_id, splash_id, format = "webp")
201
+ "#{cdn_url}/splashes/#{server_id}/#{splash_id}.#{format}"
202
+ end
203
+
204
+ # Make a banner URL from server and banner IDs
205
+ def banner_url(server_id, banner_id, format = "webp")
206
+ "#{cdn_url}/banners/#{server_id}/#{banner_id}.#{format}"
207
+ end
208
+
209
+ # Make an emoji icon URL from emoji ID
210
+ def emoji_icon_url(emoji_id, format = "webp")
211
+ "#{cdn_url}/emojis/#{emoji_id}.#{format}"
212
+ end
213
+
214
+ # Make an asset URL from application and asset IDs
215
+ def asset_url(application_id, asset_id, format = "webp")
216
+ "#{cdn_url}/app-assets/#{application_id}/#{asset_id}.#{format}"
217
+ end
218
+
219
+ # Make an achievement icon URL from application ID, achievement ID, and icon hash
220
+ def achievement_icon_url(application_id, achievement_id, icon_hash, format = "webp")
221
+ "#{cdn_url}/app-assets/#{application_id}/achievements/#{achievement_id}/icons/#{icon_hash}.#{format}"
222
+ end
223
+
224
+ # @param role_id [String, Integer]
225
+ # @param icon_hash [String]
226
+ # @param format ['webp', 'png', 'jpeg']
227
+ # @return [String]
228
+ def role_icon_url(role_id, icon_hash, format = "webp")
229
+ "#{cdn_url}/role-icons/#{role_id}/#{icon_hash}.#{format}"
230
+ end
231
+
232
+ # Login to the server
233
+ def login(email, password)
234
+ request(
235
+ :auth_login,
236
+ nil,
237
+ :post,
238
+ "#{api_base}/auth/login",
239
+ email: email,
240
+ password: password
241
+ )
242
+ end
243
+
244
+ # Logout from the server
245
+ def logout(token)
246
+ request(
247
+ :auth_logout,
248
+ nil,
249
+ :post,
250
+ "#{api_base}/auth/logout",
251
+ nil,
252
+ Authorization: token
253
+ )
254
+ end
255
+
256
+ # Create an OAuth application
257
+ def create_oauth_application(token, name, redirect_uris)
258
+ request(
259
+ :oauth2_applications,
260
+ nil,
261
+ :post,
262
+ "#{api_base}/oauth2/applications",
263
+ {name: name, redirect_uris: redirect_uris}.to_json,
264
+ Authorization: token,
265
+ content_type: :json
266
+ )
267
+ end
268
+
269
+ # Change an OAuth application's properties
270
+ def update_oauth_application(token, name, redirect_uris, description = "", icon = nil)
271
+ request(
272
+ :oauth2_applications,
273
+ nil,
274
+ :put,
275
+ "#{api_base}/oauth2/applications",
276
+ {name: name, redirect_uris: redirect_uris, description: description, icon: icon}.to_json,
277
+ Authorization: token,
278
+ content_type: :json
279
+ )
280
+ end
281
+
282
+ # Get the bot's OAuth application's information
283
+ def oauth_application(token)
284
+ request(
285
+ :oauth2_applications_me,
286
+ nil,
287
+ :get,
288
+ "#{api_base}/oauth2/applications/@me",
289
+ Authorization: token
290
+ )
291
+ end
292
+
293
+ # Acknowledge that a message has been received
294
+ # The last acknowledged message will be sent in the ready packet,
295
+ # so this is an easy way to catch up on messages
296
+ def acknowledge_message(token, channel_id, message_id)
297
+ request(
298
+ :channels_cid_messages_mid_ack,
299
+ nil, # This endpoint is unavailable for bot accounts and thus isn't subject to its rate limit requirements.
300
+ :post,
301
+ "#{api_base}/channels/#{channel_id}/messages/#{message_id}/ack",
302
+ nil,
303
+ Authorization: token
304
+ )
305
+ end
306
+
307
+ # Get the gateway to be used
308
+ def gateway(token)
309
+ request(
310
+ :gateway,
311
+ nil,
312
+ :get,
313
+ "#{api_base}/gateway",
314
+ Authorization: token
315
+ )
316
+ end
317
+
318
+ # Get the gateway to be used, with additional information for sharding and
319
+ # session start limits
320
+ def gateway_bot(token)
321
+ request(
322
+ :gateway_bot,
323
+ nil,
324
+ :get,
325
+ "#{api_base}/gateway/bot",
326
+ Authorization: token
327
+ )
328
+ end
329
+
330
+ # Validate a token (this request will fail if the token is invalid)
331
+ def validate_token(token)
332
+ request(
333
+ :auth_login,
334
+ nil,
335
+ :post,
336
+ "#{api_base}/auth/login",
337
+ {}.to_json,
338
+ Authorization: token,
339
+ content_type: :json
340
+ )
341
+ end
342
+
343
+ # Get a list of available voice regions
344
+ def voice_regions(token)
345
+ request(
346
+ :voice_regions,
347
+ nil,
348
+ :get,
349
+ "#{api_base}/voice/regions",
350
+ Authorization: token,
351
+ content_type: :json
352
+ )
353
+ end
354
+ end
355
+
356
+ Rubycord::API.reset_mutexes
@@ -0,0 +1,49 @@
1
+ module Rubycord
2
+ # Awaits are a way to register new, temporary event handlers on the fly. Awaits can be
3
+ # registered using {Bot#add_await}, {User#await}, {Message#await} and {Channel#await}.
4
+ #
5
+ # Awaits contain a block that will be called before the await event will be triggered.
6
+ # If this block returns anything that is not `false` exactly, the await will be deleted.
7
+ # If no block is present, the await will also be deleted. This is an easy way to make
8
+ # temporary events that are only temporary under certain conditions.
9
+ #
10
+ # Besides the given block, an {Rubycord::Events::AwaitEvent} will also be executed with the key and
11
+ # the type of the await that was triggered. It's possible to register multiple events
12
+ # that trigger on the same await.
13
+ class Await
14
+ # The key that uniquely identifies this await.
15
+ # @return [Symbol] The unique key.
16
+ attr_reader :key
17
+
18
+ # The class of the event that this await listens for.
19
+ # @return [Class] The event class.
20
+ attr_reader :type
21
+
22
+ # The attributes of the event that will be listened for.
23
+ # @return [Hash] A hash of attributes.
24
+ attr_reader :attributes
25
+
26
+ # Makes a new await. For internal use only.
27
+ # @!visibility private
28
+ def initialize(bot, key, type, attributes, block = nil)
29
+ @bot = bot
30
+ @key = key
31
+ @type = type
32
+ @attributes = attributes
33
+ @block = block
34
+ end
35
+
36
+ # Checks whether the await can be triggered by the given event, and if it can, execute the block
37
+ # and return its result along with this await's key.
38
+ # @param event [Event] An event to check for.
39
+ # @return [Array] This await's key and whether or not it should be deleted. If there was no match, both are nil.
40
+ def match(event)
41
+ dummy_handler = EventContainer.handler_class(@type).new(@attributes, @bot)
42
+ return [nil, nil] unless event.instance_of?(@type) && dummy_handler.matches?(event)
43
+
44
+ should_delete = true if (@block && @block.call(event) != false) || !@block
45
+
46
+ [@key, should_delete]
47
+ end
48
+ end
49
+ end