discordrb 3.4.3 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +13 -0
- data/.devcontainer/devcontainer.json +29 -0
- data/.devcontainer/postcreate.sh +4 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -1
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -1
- data/.github/workflows/ci.yml +78 -0
- data/.github/workflows/codeql.yml +65 -0
- data/.github/workflows/deploy.yml +54 -0
- data/.github/workflows/release.yml +45 -0
- data/.markdownlint.json +4 -0
- data/.rubocop.yml +58 -2
- data/CHANGELOG.md +485 -225
- data/LICENSE.txt +1 -1
- data/README.md +38 -26
- data/discordrb-webhooks.gemspec +4 -1
- data/discordrb.gemspec +18 -10
- data/lib/discordrb/api/application.rb +278 -0
- data/lib/discordrb/api/channel.rb +222 -18
- data/lib/discordrb/api/interaction.rb +63 -0
- data/lib/discordrb/api/invite.rb +2 -2
- data/lib/discordrb/api/server.rb +123 -66
- data/lib/discordrb/api/user.rb +20 -5
- data/lib/discordrb/api/webhook.rb +72 -0
- data/lib/discordrb/api.rb +35 -25
- data/lib/discordrb/bot.rb +437 -66
- data/lib/discordrb/cache.rb +41 -22
- data/lib/discordrb/commands/command_bot.rb +13 -21
- data/lib/discordrb/commands/container.rb +1 -1
- data/lib/discordrb/commands/parser.rb +7 -7
- data/lib/discordrb/commands/rate_limiter.rb +1 -1
- data/lib/discordrb/container.rb +178 -3
- data/lib/discordrb/data/activity.rb +1 -1
- data/lib/discordrb/data/application.rb +1 -0
- data/lib/discordrb/data/attachment.rb +38 -3
- data/lib/discordrb/data/audit_logs.rb +3 -3
- data/lib/discordrb/data/avatar_decoration.rb +26 -0
- data/lib/discordrb/data/call.rb +22 -0
- data/lib/discordrb/data/channel.rb +299 -30
- data/lib/discordrb/data/collectibles.rb +45 -0
- data/lib/discordrb/data/component.rb +229 -0
- data/lib/discordrb/data/embed.rb +10 -3
- data/lib/discordrb/data/emoji.rb +20 -1
- data/lib/discordrb/data/integration.rb +45 -3
- data/lib/discordrb/data/interaction.rb +937 -0
- data/lib/discordrb/data/invite.rb +1 -1
- data/lib/discordrb/data/member.rb +236 -44
- data/lib/discordrb/data/message.rb +278 -51
- data/lib/discordrb/data/overwrite.rb +15 -7
- data/lib/discordrb/data/primary_server.rb +60 -0
- data/lib/discordrb/data/profile.rb +2 -7
- data/lib/discordrb/data/reaction.rb +2 -1
- data/lib/discordrb/data/recipient.rb +1 -1
- data/lib/discordrb/data/role.rb +204 -18
- data/lib/discordrb/data/server.rb +194 -118
- data/lib/discordrb/data/server_preview.rb +68 -0
- data/lib/discordrb/data/snapshot.rb +110 -0
- data/lib/discordrb/data/user.rb +132 -12
- data/lib/discordrb/data/voice_region.rb +1 -0
- data/lib/discordrb/data/webhook.rb +99 -9
- data/lib/discordrb/data.rb +9 -0
- data/lib/discordrb/errors.rb +47 -3
- data/lib/discordrb/events/await.rb +1 -1
- data/lib/discordrb/events/channels.rb +38 -1
- data/lib/discordrb/events/generic.rb +2 -0
- data/lib/discordrb/events/guilds.rb +6 -1
- data/lib/discordrb/events/interactions.rb +575 -0
- data/lib/discordrb/events/invites.rb +2 -0
- data/lib/discordrb/events/members.rb +19 -2
- data/lib/discordrb/events/message.rb +42 -8
- data/lib/discordrb/events/presence.rb +23 -14
- data/lib/discordrb/events/raw.rb +1 -0
- data/lib/discordrb/events/reactions.rb +2 -1
- data/lib/discordrb/events/roles.rb +2 -0
- data/lib/discordrb/events/threads.rb +100 -0
- data/lib/discordrb/events/typing.rb +1 -0
- data/lib/discordrb/events/voice_server_update.rb +1 -0
- data/lib/discordrb/events/voice_state_update.rb +1 -0
- data/lib/discordrb/events/webhooks.rb +1 -0
- data/lib/discordrb/gateway.rb +57 -28
- data/lib/discordrb/paginator.rb +3 -3
- data/lib/discordrb/permissions.rb +71 -35
- data/lib/discordrb/version.rb +1 -1
- data/lib/discordrb/voice/encoder.rb +2 -2
- data/lib/discordrb/voice/network.rb +18 -7
- data/lib/discordrb/voice/sodium.rb +3 -1
- data/lib/discordrb/voice/voice_bot.rb +3 -3
- data/lib/discordrb/webhooks.rb +2 -0
- data/lib/discordrb/websocket.rb +0 -10
- data/lib/discordrb.rb +54 -5
- metadata +87 -25
- data/.circleci/config.yml +0 -126
- data/.codeclimate.yml +0 -16
- data/.travis.yml +0 -32
- data/bin/travis_build_docs.sh +0 -17
data/lib/discordrb/bot.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'rest-client'
|
|
4
4
|
require 'zlib'
|
|
5
|
-
require 'set'
|
|
6
5
|
|
|
7
6
|
require 'discordrb/events/message'
|
|
8
7
|
require 'discordrb/events/typing'
|
|
@@ -19,11 +18,16 @@ require 'discordrb/events/raw'
|
|
|
19
18
|
require 'discordrb/events/reactions'
|
|
20
19
|
require 'discordrb/events/webhooks'
|
|
21
20
|
require 'discordrb/events/invites'
|
|
21
|
+
require 'discordrb/events/interactions'
|
|
22
|
+
require 'discordrb/events/threads'
|
|
22
23
|
|
|
23
24
|
require 'discordrb/api'
|
|
24
25
|
require 'discordrb/api/channel'
|
|
25
26
|
require 'discordrb/api/server'
|
|
26
27
|
require 'discordrb/api/invite'
|
|
28
|
+
require 'discordrb/api/interaction'
|
|
29
|
+
require 'discordrb/api/application'
|
|
30
|
+
|
|
27
31
|
require 'discordrb/errors'
|
|
28
32
|
require 'discordrb/data'
|
|
29
33
|
require 'discordrb/await'
|
|
@@ -93,23 +97,26 @@ module Discordrb
|
|
|
93
97
|
# @param parse_self [true, false] Whether the bot should react on its own messages. It's best to turn this off
|
|
94
98
|
# unless you really need this so you don't inadvertently create infinite loops.
|
|
95
99
|
# @param shard_id [Integer] The number of the shard this bot should handle. See
|
|
96
|
-
# https://github.com/
|
|
100
|
+
# https://github.com/discord/discord-api-docs/issues/17 for how to do sharding.
|
|
97
101
|
# @param num_shards [Integer] The total number of shards that should be running. See
|
|
98
|
-
# https://github.com/
|
|
102
|
+
# https://github.com/discord/discord-api-docs/issues/17 for how to do sharding.
|
|
99
103
|
# @param redact_token [true, false] Whether the bot should redact the token in logs. Default is true.
|
|
100
104
|
# @param ignore_bots [true, false] Whether the bot should ignore bot accounts or not. Default is false.
|
|
101
105
|
# @param compress_mode [:none, :large, :stream] Sets which compression mode should be used when connecting
|
|
102
106
|
# to Discord's gateway. `:none` will request that no payloads are received compressed (not recommended for
|
|
103
107
|
# production bots). `:large` will request that large payloads are received compressed. `:stream` will request
|
|
104
108
|
# that all data be received in a continuous compressed stream.
|
|
105
|
-
# @param intents [:all, Array<Symbol>,
|
|
106
|
-
#
|
|
109
|
+
# @param intents [:all, :unprivileged, Array<Symbol>, :none, Integer] Gateway intents that this bot requires. `:all` will
|
|
110
|
+
# request all intents. `:unprivileged` will request only intents that are not defined as "Privileged". `:none`
|
|
111
|
+
# will request no intents. An array of symbols will request only those intents specified. An integer value will request
|
|
112
|
+
# exactly all the intents specified in the bitwise value.
|
|
113
|
+
# @see Discordrb::INTENTS
|
|
107
114
|
def initialize(
|
|
108
115
|
log_mode: :normal,
|
|
109
116
|
token: nil, client_id: nil,
|
|
110
117
|
type: nil, name: '', fancy_log: false, suppress_ready: false, parse_self: false,
|
|
111
118
|
shard_id: nil, num_shards: nil, redact_token: true, ignore_bots: false,
|
|
112
|
-
compress_mode: :large, intents:
|
|
119
|
+
compress_mode: :large, intents: :all
|
|
113
120
|
)
|
|
114
121
|
LOGGER.mode = log_mode
|
|
115
122
|
LOGGER.token = token if redact_token
|
|
@@ -130,7 +137,16 @@ module Discordrb
|
|
|
130
137
|
|
|
131
138
|
raise 'Token string is empty or nil' if token.nil? || token.empty?
|
|
132
139
|
|
|
133
|
-
@intents =
|
|
140
|
+
@intents = case intents
|
|
141
|
+
when :all
|
|
142
|
+
ALL_INTENTS
|
|
143
|
+
when :unprivileged
|
|
144
|
+
UNPRIVILEGED_INTENTS
|
|
145
|
+
when :none
|
|
146
|
+
NO_INTENTS
|
|
147
|
+
else
|
|
148
|
+
calculate_intents(intents)
|
|
149
|
+
end
|
|
134
150
|
|
|
135
151
|
@token = process_token(@type, token)
|
|
136
152
|
@gateway = Gateway.new(self, @token, @shard_key, @compress_mode, @intents)
|
|
@@ -147,6 +163,8 @@ module Discordrb
|
|
|
147
163
|
@current_thread = 0
|
|
148
164
|
|
|
149
165
|
@status = :online
|
|
166
|
+
|
|
167
|
+
@application_commands = {}
|
|
150
168
|
end
|
|
151
169
|
|
|
152
170
|
# The list of users the bot shares a server with.
|
|
@@ -165,6 +183,14 @@ module Discordrb
|
|
|
165
183
|
@servers
|
|
166
184
|
end
|
|
167
185
|
|
|
186
|
+
# The list of members in threads the bot can see.
|
|
187
|
+
# @return [Hash<Integer => Hash<Integer => Hash<String => Object>>]
|
|
188
|
+
def thread_members
|
|
189
|
+
gateway_check
|
|
190
|
+
unavailable_servers_check
|
|
191
|
+
@thread_members
|
|
192
|
+
end
|
|
193
|
+
|
|
168
194
|
# @overload emoji(id)
|
|
169
195
|
# Return an emoji by its ID
|
|
170
196
|
# @param id [String, Integer] The emoji's ID.
|
|
@@ -197,8 +223,10 @@ module Discordrb
|
|
|
197
223
|
# to edit user data like the current username (see {Profile#username=}).
|
|
198
224
|
# @return [Profile] The bot's profile that can be used to edit data.
|
|
199
225
|
def profile
|
|
200
|
-
|
|
201
|
-
|
|
226
|
+
return @profile if @profile
|
|
227
|
+
|
|
228
|
+
response = Discordrb::API::User.profile(@token)
|
|
229
|
+
@profile = Profile.new(JSON.parse(response), self)
|
|
202
230
|
end
|
|
203
231
|
|
|
204
232
|
alias_method :bot_user, :profile
|
|
@@ -279,13 +307,21 @@ module Discordrb
|
|
|
279
307
|
# Creates an OAuth invite URL that can be used to invite this bot to a particular server.
|
|
280
308
|
# @param server [Server, nil] The server the bot should be invited to, or nil if a general invite should be created.
|
|
281
309
|
# @param permission_bits [String, Integer] Permission bits that should be appended to invite url.
|
|
310
|
+
# @param redirect_uri [String] Redirect URI that should be appended to invite url.
|
|
311
|
+
# @param scopes [Array<String>] Scopes that should be appended to invite url.
|
|
282
312
|
# @return [String] the OAuth invite URL.
|
|
283
|
-
def invite_url(server: nil, permission_bits: nil)
|
|
313
|
+
def invite_url(server: nil, permission_bits: nil, redirect_uri: nil, scopes: ['bot'])
|
|
284
314
|
@client_id ||= bot_application.id
|
|
285
315
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
316
|
+
query = URI.encode_www_form({
|
|
317
|
+
client_id: @client_id,
|
|
318
|
+
guild_id: server&.id,
|
|
319
|
+
permissions: permission_bits,
|
|
320
|
+
redirect_uri: redirect_uri,
|
|
321
|
+
scope: scopes.join(' ')
|
|
322
|
+
}.compact)
|
|
323
|
+
|
|
324
|
+
"https://discord.com/oauth2/authorize?#{query}"
|
|
289
325
|
end
|
|
290
326
|
|
|
291
327
|
# @return [Hash<Integer => VoiceBot>] the voice connections this bot currently has, by the server ID to which they are connected.
|
|
@@ -362,17 +398,22 @@ module Discordrb
|
|
|
362
398
|
# @param channel [Channel, String, Integer] The channel, or its ID, to send something to.
|
|
363
399
|
# @param content [String] The text that should be sent as a message. It is limited to 2000 characters (Discord imposed).
|
|
364
400
|
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
365
|
-
# @param
|
|
401
|
+
# @param embeds [Hash, Discordrb::Webhooks::Embed, Array<Hash>, Array<Discordrb::Webhooks::Embed> nil] The rich embed(s) to append to this message.
|
|
366
402
|
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
367
|
-
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
|
403
|
+
# @param message_reference [Message, String, Integer, Hash, nil] The message, or message ID, to reply to if any.
|
|
404
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
405
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
|
|
406
|
+
# @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
|
|
407
|
+
# @param enforce_nonce [true, false] whether the nonce should be enforced and used for message de-duplication.
|
|
368
408
|
# @return [Message] The message that was sent.
|
|
369
|
-
def send_message(channel, content, tts = false,
|
|
409
|
+
def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false)
|
|
370
410
|
channel = channel.resolve_id
|
|
371
411
|
debug("Sending message to #{channel} with content '#{content}'")
|
|
372
412
|
allowed_mentions = { parse: [] } if allowed_mentions == false
|
|
373
|
-
message_reference = { message_id: message_reference.
|
|
413
|
+
message_reference = { message_id: message_reference.resolve_id } if message_reference.respond_to?(:resolve_id)
|
|
414
|
+
embeds = (embeds.instance_of?(Array) ? embeds.map(&:to_hash) : [embeds&.to_hash]).compact
|
|
374
415
|
|
|
375
|
-
response = API::Channel.create_message(token, channel, content, tts,
|
|
416
|
+
response = API::Channel.create_message(token, channel, content, tts, embeds, nonce, attachments, allowed_mentions&.to_hash, message_reference, components, flags, enforce_nonce)
|
|
376
417
|
Message.new(JSON.parse(response), self)
|
|
377
418
|
end
|
|
378
419
|
|
|
@@ -382,15 +423,19 @@ module Discordrb
|
|
|
382
423
|
# @param content [String] The text that should be sent as a message. It is limited to 2000 characters (Discord imposed).
|
|
383
424
|
# @param timeout [Float] The amount of time in seconds after which the message sent will be deleted.
|
|
384
425
|
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
385
|
-
# @param
|
|
426
|
+
# @param embeds [Hash, Discordrb::Webhooks::Embed, Array<Hash>, Array<Discordrb::Webhooks::Embed> nil] The rich embed(s) to append to this message.
|
|
386
427
|
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
|
387
428
|
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
388
429
|
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
|
389
|
-
|
|
430
|
+
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
431
|
+
# @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
|
|
432
|
+
# @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
|
|
433
|
+
# @param enforce_nonce [true, false] whether the nonce should be enforced and used for message de-duplication.
|
|
434
|
+
def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false)
|
|
390
435
|
Thread.new do
|
|
391
436
|
Thread.current[:discordrb_name] = "#{@current_thread}-temp-msg"
|
|
392
437
|
|
|
393
|
-
message = send_message(channel, content, tts,
|
|
438
|
+
message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, flags, nonce, enforce_nonce)
|
|
394
439
|
sleep(timeout)
|
|
395
440
|
message.delete
|
|
396
441
|
end
|
|
@@ -416,6 +461,7 @@ module Discordrb
|
|
|
416
461
|
end
|
|
417
462
|
# https://github.com/rest-client/rest-client/blob/v2.0.2/lib/restclient/payload.rb#L160
|
|
418
463
|
file.define_singleton_method(:original_filename) { filename } if filename
|
|
464
|
+
file.define_singleton_method(:path) { filename } if filename
|
|
419
465
|
end
|
|
420
466
|
|
|
421
467
|
channel = channel.resolve_id
|
|
@@ -423,20 +469,6 @@ module Discordrb
|
|
|
423
469
|
Message.new(JSON.parse(response), self)
|
|
424
470
|
end
|
|
425
471
|
|
|
426
|
-
# Creates a server on Discord with a specified name and a region.
|
|
427
|
-
# @note Discord's API doesn't directly return the server when creating it, so this method
|
|
428
|
-
# waits until the data has been received via the websocket. This may make the execution take a while.
|
|
429
|
-
# @param name [String] The name the new server should have. Doesn't have to be alphanumeric.
|
|
430
|
-
# @param region [Symbol] The region where the server should be created, for example 'eu-central' or 'hongkong'.
|
|
431
|
-
# @return [Server] The server that was created.
|
|
432
|
-
def create_server(name, region = :'eu-central')
|
|
433
|
-
response = API::Server.create(token, name, region)
|
|
434
|
-
id = JSON.parse(response)['id'].to_i
|
|
435
|
-
sleep 0.1 until (server = @servers[id])
|
|
436
|
-
debug "Successfully created server #{server.id} with name #{server.name}"
|
|
437
|
-
server
|
|
438
|
-
end
|
|
439
|
-
|
|
440
472
|
# Creates a new application to do OAuth authorization with. This allows you to use OAuth to authorize users using
|
|
441
473
|
# Discord. For information how to use this, see the docs: https://discord.com/developers/docs/topics/oauth2
|
|
442
474
|
# @param name [String] What your application should be called.
|
|
@@ -485,7 +517,7 @@ module Discordrb
|
|
|
485
517
|
end
|
|
486
518
|
end
|
|
487
519
|
elsif /(?<animated>^a|^${0}):(?<name>\w+):(?<id>\d+)/ =~ mention
|
|
488
|
-
array_to_return << (emoji(id) || Emoji.new({ 'animated' =>
|
|
520
|
+
array_to_return << (emoji(id) || Emoji.new({ 'animated' => animated != '', 'name' => name, 'id' => id }, self, nil))
|
|
489
521
|
end
|
|
490
522
|
end
|
|
491
523
|
array_to_return
|
|
@@ -595,6 +627,36 @@ module Discordrb
|
|
|
595
627
|
update_status(:invisible, @activity, nil)
|
|
596
628
|
end
|
|
597
629
|
|
|
630
|
+
# Join a thread
|
|
631
|
+
# @param channel [Channel, Integer, String]
|
|
632
|
+
def join_thread(channel)
|
|
633
|
+
API::Channel.join_thread(@token, channel.resolve_id)
|
|
634
|
+
nil
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# Leave a thread
|
|
638
|
+
# @param channel [Channel, Integer, String]
|
|
639
|
+
def leave_thread(channel)
|
|
640
|
+
API::Channel.leave_thread(@token, channel.resolve_id)
|
|
641
|
+
nil
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Add a member to a thread
|
|
645
|
+
# @param channel [Channel, Integer, String]
|
|
646
|
+
# @param member [Member, Integer, String]
|
|
647
|
+
def add_thread_member(channel, member)
|
|
648
|
+
API::Channel.add_thread_member(@token, channel.resolve_id, member.resolve_id)
|
|
649
|
+
nil
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
# Remove a member from a thread
|
|
653
|
+
# @param channel [Channel, Integer, String]
|
|
654
|
+
# @param member [Member, Integer, String]
|
|
655
|
+
def remove_thread_member(channel, member)
|
|
656
|
+
API::Channel.remove_thread_member(@token, channel.resolve_id, member.resolve_id)
|
|
657
|
+
nil
|
|
658
|
+
end
|
|
659
|
+
|
|
598
660
|
# Sets debug mode. If debug mode is on, many things will be outputted to STDOUT.
|
|
599
661
|
def debug=(new_debug)
|
|
600
662
|
LOGGER.debug = new_debug
|
|
@@ -721,6 +783,158 @@ module Discordrb
|
|
|
721
783
|
end
|
|
722
784
|
end
|
|
723
785
|
|
|
786
|
+
# Get all application commands.
|
|
787
|
+
# @param server_id [String, Integer, nil] The ID of the server to get the commands from. Global if `nil`.
|
|
788
|
+
# @return [Array<ApplicationCommand>]
|
|
789
|
+
def get_application_commands(server_id: nil)
|
|
790
|
+
resp = if server_id
|
|
791
|
+
API::Application.get_guild_commands(@token, profile.id, server_id)
|
|
792
|
+
else
|
|
793
|
+
API::Application.get_global_commands(@token, profile.id)
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
JSON.parse(resp).map do |command_data|
|
|
797
|
+
ApplicationCommand.new(command_data, self, server_id)
|
|
798
|
+
end
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
# Get an application command by ID.
|
|
802
|
+
# @param command_id [String, Integer]
|
|
803
|
+
# @param server_id [String, Integer, nil] The ID of the server to get the command from. Global if `nil`.
|
|
804
|
+
def get_application_command(command_id, server_id: nil)
|
|
805
|
+
resp = if server_id
|
|
806
|
+
API::Application.get_guild_command(@token, profile.id, server_id, command_id)
|
|
807
|
+
else
|
|
808
|
+
API::Application.get_global_command(@token, profile.id, command_id)
|
|
809
|
+
end
|
|
810
|
+
ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
# @yieldparam [OptionBuilder]
|
|
814
|
+
# @yieldparam [PermissionBuilder]
|
|
815
|
+
# @example
|
|
816
|
+
# bot.register_application_command(:reddit, 'Reddit Commands') do |cmd|
|
|
817
|
+
# cmd.subcommand_group(:subreddit, 'Subreddit Commands') do |group|
|
|
818
|
+
# group.subcommand(:hot, "What's trending") do |sub|
|
|
819
|
+
# sub.string(:subreddit, 'Subreddit to search')
|
|
820
|
+
# end
|
|
821
|
+
# group.subcommand(:new, "What's new") do |sub|
|
|
822
|
+
# sub.string(:since, 'How long ago', choices: ['this hour', 'today', 'this week', 'this month', 'this year', 'all time'])
|
|
823
|
+
# sub.string(:subreddit, 'Subreddit to search')
|
|
824
|
+
# end
|
|
825
|
+
# end
|
|
826
|
+
# end
|
|
827
|
+
def register_application_command(name, description, server_id: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, nsfw: false)
|
|
828
|
+
type = ApplicationCommand::TYPES[type] || type
|
|
829
|
+
|
|
830
|
+
builder = Interactions::OptionBuilder.new
|
|
831
|
+
permission_builder = Interactions::PermissionBuilder.new
|
|
832
|
+
yield(builder, permission_builder) if block_given?
|
|
833
|
+
|
|
834
|
+
resp = if server_id
|
|
835
|
+
API::Application.create_guild_command(@token, profile.id, server_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
|
|
836
|
+
else
|
|
837
|
+
API::Application.create_global_command(@token, profile.id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
|
|
838
|
+
end
|
|
839
|
+
cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
840
|
+
|
|
841
|
+
if permission_builder.to_a.any?
|
|
842
|
+
raise ArgumentError, 'Permissions can only be set for guild commands' unless server_id
|
|
843
|
+
|
|
844
|
+
edit_application_command_permissions(cmd.id, server_id, permission_builder.to_a)
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
cmd
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# @yieldparam [OptionBuilder]
|
|
851
|
+
# @yieldparam [PermissionBuilder]
|
|
852
|
+
def edit_application_command(command_id, server_id: nil, name: nil, description: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, nsfw: nil)
|
|
853
|
+
type = ApplicationCommand::TYPES[type] || type
|
|
854
|
+
|
|
855
|
+
builder = Interactions::OptionBuilder.new
|
|
856
|
+
permission_builder = Interactions::PermissionBuilder.new
|
|
857
|
+
|
|
858
|
+
yield(builder, permission_builder) if block_given?
|
|
859
|
+
|
|
860
|
+
resp = if server_id
|
|
861
|
+
API::Application.edit_guild_command(@token, profile.id, server_id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
|
|
862
|
+
else
|
|
863
|
+
API::Application.edit_global_command(@token, profile.id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions, contexts, nsfw)
|
|
864
|
+
end
|
|
865
|
+
cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
866
|
+
|
|
867
|
+
if permission_builder.to_a.any?
|
|
868
|
+
raise ArgumentError, 'Permissions can only be set for guild commands' unless server_id
|
|
869
|
+
|
|
870
|
+
edit_application_command_permissions(cmd.id, server_id, permission_builder.to_a)
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
cmd
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
# Remove an application command from the commands registered with discord.
|
|
877
|
+
# @param command_id [String, Integer] The ID of the command to remove.
|
|
878
|
+
# @param server_id [String, Integer] The ID of the server to delete this command from, global if `nil`.
|
|
879
|
+
def delete_application_command(command_id, server_id: nil)
|
|
880
|
+
if server_id
|
|
881
|
+
API::Application.delete_guild_command(@token, profile.id, server_id, command_id)
|
|
882
|
+
else
|
|
883
|
+
API::Application.delete_global_command(@token, profile.id, command_id)
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
# @param command_id [Integer, String]
|
|
888
|
+
# @param server_id [Integer, String]
|
|
889
|
+
# @param permissions [Array<Hash>] An array of objects formatted as `{ id: ENTITY_ID, type: 1 or 2, permission: true or false }`
|
|
890
|
+
def edit_application_command_permissions(command_id, server_id, permissions = [])
|
|
891
|
+
builder = Interactions::PermissionBuilder.new
|
|
892
|
+
yield builder if block_given?
|
|
893
|
+
|
|
894
|
+
permissions += builder.to_a
|
|
895
|
+
API::Application.edit_guild_command_permissions(@token, profile.id, server_id, command_id, permissions)
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
# Fetches all the application emojis that the bot can use.
|
|
899
|
+
# @return [Array<Emoji>] Returns an array of emoji objects.
|
|
900
|
+
def application_emojis
|
|
901
|
+
response = API::Application.list_application_emojis(@token, profile.id)
|
|
902
|
+
JSON.parse(response)['items'].map { |emoji| Emoji.new(emoji, self) }
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
# Fetches a single application emoji from its ID.
|
|
906
|
+
# @param emoji_id [Integer, String] ID of the application emoji.
|
|
907
|
+
# @return [Emoji] The application emoji.
|
|
908
|
+
def application_emoji(emoji_id)
|
|
909
|
+
response = API::Application.get_application_emoji(@token, profile.id, emoji_id.resolve_id)
|
|
910
|
+
Emoji.new(JSON.parse(response), self)
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
# Creates a new custom emoji that can be used by this application.
|
|
914
|
+
# @param name [String] The name of emoji to create.
|
|
915
|
+
# @param image [String, #read] Base64 string with the image data, or an object that responds to #read.
|
|
916
|
+
# @return [Emoji] The emoji that has been created.
|
|
917
|
+
def create_application_emoji(name:, image:)
|
|
918
|
+
image = image.respond_to?(:read) ? Discordrb.encode64(image) : image
|
|
919
|
+
response = API::Application.create_application_emoji(@token, profile.id, name, image)
|
|
920
|
+
Emoji.new(JSON.parse(response), self)
|
|
921
|
+
end
|
|
922
|
+
|
|
923
|
+
# Edits an existing application emoji.
|
|
924
|
+
# @param emoji_id [Integer, String, Emoji] ID of the application emoji to edit.
|
|
925
|
+
# @param name [String] The new name of the emoji.
|
|
926
|
+
# @return [Emoji] Returns the updated emoji object on success.
|
|
927
|
+
def edit_application_emoji(emoji_id, name:)
|
|
928
|
+
response = API::Application.edit_application_emoji(@token, profile.id, emoji_id.resolve_id, name)
|
|
929
|
+
Emoji.new(JSON.parse(response), self)
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
# Deletes an existing application emoji.
|
|
933
|
+
# @param emoji_id [Integer, String, Emoji] ID of the application emoji to delete.
|
|
934
|
+
def delete_application_emoji(emoji_id)
|
|
935
|
+
API::Application.delete_application_emoji(@token, profile.id, emoji_id.resolve_id)
|
|
936
|
+
end
|
|
937
|
+
|
|
724
938
|
private
|
|
725
939
|
|
|
726
940
|
# Throws a useful exception if there's currently no gateway connection.
|
|
@@ -772,10 +986,16 @@ module Discordrb
|
|
|
772
986
|
|
|
773
987
|
username = data['user']['username']
|
|
774
988
|
if username && !member_is_new # Don't set the username for newly-cached members
|
|
775
|
-
debug "Implicitly updating presence-obtained information for member #{user_id}"
|
|
989
|
+
debug "Implicitly updating presence-obtained information username for member #{user_id}"
|
|
776
990
|
member.update_username(username)
|
|
777
991
|
end
|
|
778
992
|
|
|
993
|
+
global_name = data['user']['global_name']
|
|
994
|
+
if global_name && !member_is_new # Don't set the global_name for newly-cached members
|
|
995
|
+
debug "Implicitly updating presence-obtained information global_name for member #{user_id}"
|
|
996
|
+
member.update_global_name(global_name)
|
|
997
|
+
end
|
|
998
|
+
|
|
779
999
|
member.update_presence(data)
|
|
780
1000
|
|
|
781
1001
|
member.avatar_id = data['user']['avatar'] if data['user']['avatar']
|
|
@@ -836,14 +1056,14 @@ module Discordrb
|
|
|
836
1056
|
|
|
837
1057
|
# Internal handler for CHANNEL_CREATE
|
|
838
1058
|
def create_channel(data)
|
|
839
|
-
channel = Channel.new(data, self)
|
|
1059
|
+
channel = data.is_a?(Discordrb::Channel) ? data : Channel.new(data, self)
|
|
840
1060
|
server = channel.server
|
|
841
1061
|
|
|
842
1062
|
# Handle normal and private channels separately
|
|
843
1063
|
if server
|
|
844
1064
|
server.add_channel(channel)
|
|
845
1065
|
@channels[channel.id] = channel
|
|
846
|
-
elsif channel.
|
|
1066
|
+
elsif channel.private?
|
|
847
1067
|
@pm_channels[channel.recipient.id] = channel
|
|
848
1068
|
elsif channel.group?
|
|
849
1069
|
@channels[channel.id] = channel
|
|
@@ -873,6 +1093,8 @@ module Discordrb
|
|
|
873
1093
|
elsif channel.group?
|
|
874
1094
|
@channels.delete(channel.id)
|
|
875
1095
|
end
|
|
1096
|
+
|
|
1097
|
+
@thread_members.delete(channel.id) if channel.thread?
|
|
876
1098
|
end
|
|
877
1099
|
|
|
878
1100
|
# Internal handler for CHANNEL_RECIPIENT_ADD
|
|
@@ -909,10 +1131,12 @@ module Discordrb
|
|
|
909
1131
|
server_id = data['guild_id'].to_i
|
|
910
1132
|
server = self.server(server_id)
|
|
911
1133
|
|
|
912
|
-
|
|
913
|
-
member.
|
|
914
|
-
|
|
915
|
-
|
|
1134
|
+
# Only attempt to update members that're already cached
|
|
1135
|
+
if (member = server.member(data['user']['id'].to_i, false))
|
|
1136
|
+
member.update_data(data)
|
|
1137
|
+
else
|
|
1138
|
+
ensure_user(data['user'])
|
|
1139
|
+
end
|
|
916
1140
|
end
|
|
917
1141
|
|
|
918
1142
|
# Internal handler for GUILD_MEMBER_DELETE
|
|
@@ -929,7 +1153,7 @@ module Discordrb
|
|
|
929
1153
|
|
|
930
1154
|
# Internal handler for GUILD_CREATE
|
|
931
1155
|
def create_guild(data)
|
|
932
|
-
ensure_server(data)
|
|
1156
|
+
ensure_server(data, true)
|
|
933
1157
|
end
|
|
934
1158
|
|
|
935
1159
|
# Internal handler for GUILD_UPDATE
|
|
@@ -1020,7 +1244,7 @@ module Discordrb
|
|
|
1020
1244
|
|
|
1021
1245
|
def process_token(type, token)
|
|
1022
1246
|
# Remove the "Bot " prefix if it exists
|
|
1023
|
-
token = token[4
|
|
1247
|
+
token = token[4..] if token.start_with? 'Bot '
|
|
1024
1248
|
|
|
1025
1249
|
token = "Bot #{token}" unless type == :user
|
|
1026
1250
|
token
|
|
@@ -1028,7 +1252,7 @@ module Discordrb
|
|
|
1028
1252
|
|
|
1029
1253
|
def handle_dispatch(type, data)
|
|
1030
1254
|
# Check whether there are still unavailable servers and there have been more than 10 seconds since READY
|
|
1031
|
-
if @unavailable_servers&.positive? && (Time.now - @unavailable_timeout_time) > 10 && !(
|
|
1255
|
+
if @unavailable_servers&.positive? && (Time.now - @unavailable_timeout_time) > 10 && !(@intents || 0).nobits?(INTENTS[:servers])
|
|
1032
1256
|
# The server streaming timed out!
|
|
1033
1257
|
LOGGER.debug("Server streaming timed out with #{@unavailable_servers} servers remaining")
|
|
1034
1258
|
LOGGER.debug('Calling ready now because server loading is taking a long time. Servers may be unavailable due to an outage, or your bot is on very large servers.')
|
|
@@ -1048,6 +1272,8 @@ module Discordrb
|
|
|
1048
1272
|
|
|
1049
1273
|
@profile = Profile.new(data['user'], self)
|
|
1050
1274
|
|
|
1275
|
+
@client_id ||= data['application']['id']&.to_i
|
|
1276
|
+
|
|
1051
1277
|
# Initialize servers
|
|
1052
1278
|
@servers = {}
|
|
1053
1279
|
|
|
@@ -1057,14 +1283,14 @@ module Discordrb
|
|
|
1057
1283
|
data['guilds'].each do |element|
|
|
1058
1284
|
# Check for true specifically because unavailable=false indicates that a previously unavailable server has
|
|
1059
1285
|
# come online
|
|
1060
|
-
if element['unavailable']
|
|
1286
|
+
if element['unavailable']
|
|
1061
1287
|
@unavailable_servers += 1
|
|
1062
1288
|
|
|
1063
1289
|
# Ignore any unavailable servers
|
|
1064
1290
|
next
|
|
1065
1291
|
end
|
|
1066
1292
|
|
|
1067
|
-
ensure_server(element)
|
|
1293
|
+
ensure_server(element, true)
|
|
1068
1294
|
end
|
|
1069
1295
|
|
|
1070
1296
|
# Add PM and group channels
|
|
@@ -1089,14 +1315,16 @@ module Discordrb
|
|
|
1089
1315
|
when :GUILD_MEMBERS_CHUNK
|
|
1090
1316
|
id = data['guild_id'].to_i
|
|
1091
1317
|
server = server(id)
|
|
1092
|
-
server.process_chunk(data['members'])
|
|
1318
|
+
server.process_chunk(data['members'], data['chunk_index'], data['chunk_count'])
|
|
1319
|
+
when :USER_UPDATE
|
|
1320
|
+
@profile = Profile.new(data, self)
|
|
1093
1321
|
when :INVITE_CREATE
|
|
1094
1322
|
invite = Invite.new(data, self)
|
|
1095
1323
|
raise_event(InviteCreateEvent.new(data, invite, self))
|
|
1096
1324
|
when :INVITE_DELETE
|
|
1097
1325
|
raise_event(InviteDeleteEvent.new(data, self))
|
|
1098
1326
|
when :MESSAGE_CREATE
|
|
1099
|
-
if ignored?(data['author']['id']
|
|
1327
|
+
if ignored?(data['author']['id'])
|
|
1100
1328
|
debug("Ignored author with ID #{data['author']['id']}")
|
|
1101
1329
|
return
|
|
1102
1330
|
end
|
|
@@ -1106,12 +1334,29 @@ module Discordrb
|
|
|
1106
1334
|
return
|
|
1107
1335
|
end
|
|
1108
1336
|
|
|
1337
|
+
if !should_parse_self && profile.id == data['author']['id'].to_i
|
|
1338
|
+
debug('Ignored message from the current bot')
|
|
1339
|
+
return
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1109
1342
|
# If create_message is overwritten with a method that returns the parsed message, use that instead, so we don't
|
|
1110
1343
|
# parse the message twice (which is just thrown away performance)
|
|
1111
1344
|
message = create_message(data)
|
|
1112
1345
|
message = Message.new(data, self) unless message.is_a? Message
|
|
1113
1346
|
|
|
1114
|
-
|
|
1347
|
+
# Update the existing member if it exists in the cache.
|
|
1348
|
+
if data['member']
|
|
1349
|
+
member = message.channel.server&.member(data['author']['id'].to_i, false)
|
|
1350
|
+
data['member']['user'] = data['author']
|
|
1351
|
+
member&.update_data(data['member'])
|
|
1352
|
+
end
|
|
1353
|
+
|
|
1354
|
+
# Dispatch a ChannelCreateEvent for channels we don't have cached
|
|
1355
|
+
if message.channel.private? && @pm_channels[message.channel.recipient.id].nil?
|
|
1356
|
+
create_channel(message.channel)
|
|
1357
|
+
|
|
1358
|
+
raise_event(ChannelCreateEvent.new(message.channel, self))
|
|
1359
|
+
end
|
|
1115
1360
|
|
|
1116
1361
|
event = MessageEvent.new(message, self)
|
|
1117
1362
|
raise_event(event)
|
|
@@ -1128,18 +1373,28 @@ module Discordrb
|
|
|
1128
1373
|
when :MESSAGE_UPDATE
|
|
1129
1374
|
update_message(data)
|
|
1130
1375
|
|
|
1376
|
+
if !should_parse_self && profile.id == data['author']['id'].to_i
|
|
1377
|
+
debug('Ignored message from the current bot')
|
|
1378
|
+
return
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1131
1381
|
message = Message.new(data, self)
|
|
1132
1382
|
|
|
1133
1383
|
event = MessageUpdateEvent.new(message, self)
|
|
1134
1384
|
raise_event(event)
|
|
1135
1385
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
unless message.author
|
|
1386
|
+
if data['author'].nil?
|
|
1139
1387
|
LOGGER.debug("Edited a message with nil author! Content: #{message.content.inspect}, channel: #{message.channel.inspect}")
|
|
1140
1388
|
return
|
|
1141
1389
|
end
|
|
1142
1390
|
|
|
1391
|
+
# Update the existing member if it exists in the cache.
|
|
1392
|
+
if data['member']
|
|
1393
|
+
member = message.channel.server&.member(data['author']['id'].to_i, false)
|
|
1394
|
+
data['member']['user'] = data['author']
|
|
1395
|
+
member&.update_data(data['member'])
|
|
1396
|
+
end
|
|
1397
|
+
|
|
1143
1398
|
event = MessageEditEvent.new(message, self)
|
|
1144
1399
|
raise_event(event)
|
|
1145
1400
|
when :MESSAGE_DELETE
|
|
@@ -1177,6 +1432,12 @@ module Discordrb
|
|
|
1177
1432
|
|
|
1178
1433
|
return if profile.id == data['user_id'].to_i && !should_parse_self
|
|
1179
1434
|
|
|
1435
|
+
if data['member']
|
|
1436
|
+
server = self.server(data['guild_id'].to_i)
|
|
1437
|
+
|
|
1438
|
+
server&.cache_member(Member.new(data['member'], server, self))
|
|
1439
|
+
end
|
|
1440
|
+
|
|
1180
1441
|
event = ReactionAddEvent.new(data, self)
|
|
1181
1442
|
raise_event(event)
|
|
1182
1443
|
when :MESSAGE_REACTION_REMOVE
|
|
@@ -1195,18 +1456,28 @@ module Discordrb
|
|
|
1195
1456
|
# Ignore friends list presences
|
|
1196
1457
|
return unless data['guild_id']
|
|
1197
1458
|
|
|
1198
|
-
|
|
1459
|
+
new_activities = (data['activities'] || []).map { |act_data| Activity.new(act_data, self) }
|
|
1199
1460
|
presence_user = @users[data['user']['id'].to_i]
|
|
1200
|
-
|
|
1461
|
+
old_activities = (presence_user&.activities || [])
|
|
1201
1462
|
update_presence(data)
|
|
1202
1463
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1464
|
+
# Starting a new game
|
|
1465
|
+
playing_change = new_activities.reject do |act|
|
|
1466
|
+
old_activities.find { |old| old.name == act.name }
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
# Exiting an existing game
|
|
1470
|
+
playing_change += old_activities.reject do |old|
|
|
1471
|
+
new_activities.find { |act| act.name == old.name }
|
|
1472
|
+
end
|
|
1208
1473
|
|
|
1209
|
-
|
|
1474
|
+
if playing_change.any?
|
|
1475
|
+
playing_change.each do |act|
|
|
1476
|
+
raise_event(PlayingEvent.new(data, act, self))
|
|
1477
|
+
end
|
|
1478
|
+
else
|
|
1479
|
+
raise_event(PresenceEvent.new(data, self))
|
|
1480
|
+
end
|
|
1210
1481
|
when :VOICE_STATE_UPDATE
|
|
1211
1482
|
old_channel_id = update_voice_state(data)
|
|
1212
1483
|
|
|
@@ -1241,6 +1512,12 @@ module Discordrb
|
|
|
1241
1512
|
remove_recipient(data)
|
|
1242
1513
|
|
|
1243
1514
|
event = ChannelRecipientRemoveEvent.new(data, self)
|
|
1515
|
+
raise_event(event)
|
|
1516
|
+
when :CHANNEL_PINS_UPDATE
|
|
1517
|
+
event = ChannelPinsUpdateEvent.new(data, self)
|
|
1518
|
+
|
|
1519
|
+
event.channel.process_last_pin_timestamp(data['last_pin_timestamp']) if data.key?('last_pin_timestamp')
|
|
1520
|
+
|
|
1244
1521
|
raise_event(event)
|
|
1245
1522
|
when :GUILD_MEMBER_ADD
|
|
1246
1523
|
add_guild_member(data)
|
|
@@ -1343,9 +1620,101 @@ module Discordrb
|
|
|
1343
1620
|
event = ServerEmojiUpdateEvent.new(server, old_emoji_data[e], new_emoji_data[e], self)
|
|
1344
1621
|
raise_event(event)
|
|
1345
1622
|
end
|
|
1623
|
+
when :APPLICATION_COMMAND_PERMISSIONS_UPDATE
|
|
1624
|
+
event = ApplicationCommandPermissionsUpdateEvent.new(data, self)
|
|
1625
|
+
|
|
1626
|
+
raise_event(event)
|
|
1627
|
+
when :INTERACTION_CREATE
|
|
1628
|
+
event = InteractionCreateEvent.new(data, self)
|
|
1629
|
+
raise_event(event)
|
|
1630
|
+
|
|
1631
|
+
case data['type']
|
|
1632
|
+
when Interaction::TYPES[:command]
|
|
1633
|
+
event = ApplicationCommandEvent.new(data, self)
|
|
1634
|
+
|
|
1635
|
+
Thread.new(event) do |evt|
|
|
1636
|
+
Thread.current[:discordrb_name] = "it-#{evt.interaction.id}"
|
|
1637
|
+
|
|
1638
|
+
begin
|
|
1639
|
+
debug("Executing application command #{evt.command_name}:#{evt.command_id}")
|
|
1640
|
+
|
|
1641
|
+
@application_commands[evt.command_name]&.call(evt)
|
|
1642
|
+
rescue StandardError => e
|
|
1643
|
+
log_exception(e)
|
|
1644
|
+
end
|
|
1645
|
+
end
|
|
1646
|
+
when Interaction::TYPES[:component]
|
|
1647
|
+
case data['data']['component_type']
|
|
1648
|
+
when Webhooks::View::COMPONENT_TYPES[:button]
|
|
1649
|
+
event = ButtonEvent.new(data, self)
|
|
1650
|
+
|
|
1651
|
+
raise_event(event)
|
|
1652
|
+
when Webhooks::View::COMPONENT_TYPES[:string_select]
|
|
1653
|
+
event = StringSelectEvent.new(data, self)
|
|
1654
|
+
|
|
1655
|
+
raise_event(event)
|
|
1656
|
+
when Webhooks::View::COMPONENT_TYPES[:user_select]
|
|
1657
|
+
event = UserSelectEvent.new(data, self)
|
|
1658
|
+
|
|
1659
|
+
raise_event(event)
|
|
1660
|
+
when Webhooks::View::COMPONENT_TYPES[:role_select]
|
|
1661
|
+
event = RoleSelectEvent.new(data, self)
|
|
1662
|
+
|
|
1663
|
+
raise_event(event)
|
|
1664
|
+
when Webhooks::View::COMPONENT_TYPES[:mentionable_select]
|
|
1665
|
+
event = MentionableSelectEvent.new(data, self)
|
|
1666
|
+
|
|
1667
|
+
raise_event(event)
|
|
1668
|
+
when Webhooks::View::COMPONENT_TYPES[:channel_select]
|
|
1669
|
+
event = ChannelSelectEvent.new(data, self)
|
|
1670
|
+
|
|
1671
|
+
raise_event(event)
|
|
1672
|
+
end
|
|
1673
|
+
when Interaction::TYPES[:modal_submit]
|
|
1674
|
+
|
|
1675
|
+
event = ModalSubmitEvent.new(data, self)
|
|
1676
|
+
raise_event(event)
|
|
1677
|
+
when Interaction::TYPES[:autocomplete]
|
|
1678
|
+
|
|
1679
|
+
event = AutocompleteEvent.new(data, self)
|
|
1680
|
+
raise_event(event)
|
|
1681
|
+
end
|
|
1346
1682
|
when :WEBHOOKS_UPDATE
|
|
1347
1683
|
event = WebhookUpdateEvent.new(data, self)
|
|
1348
1684
|
raise_event(event)
|
|
1685
|
+
when :THREAD_CREATE
|
|
1686
|
+
create_channel(data)
|
|
1687
|
+
|
|
1688
|
+
event = ThreadCreateEvent.new(data, self)
|
|
1689
|
+
raise_event(event)
|
|
1690
|
+
when :THREAD_UPDATE
|
|
1691
|
+
update_channel(data)
|
|
1692
|
+
|
|
1693
|
+
event = ThreadUpdateEvent.new(data, self)
|
|
1694
|
+
raise_event(event)
|
|
1695
|
+
when :THREAD_DELETE
|
|
1696
|
+
delete_channel(data)
|
|
1697
|
+
@thread_members.delete(data['id']&.resolve_id)
|
|
1698
|
+
|
|
1699
|
+
# raise ThreadDeleteEvent
|
|
1700
|
+
when :THREAD_LIST_SYNC
|
|
1701
|
+
data['members'].map { |member| ensure_thread_member(member) }
|
|
1702
|
+
data['threads'].map { |channel| ensure_channel(channel, data['guild_id']) }
|
|
1703
|
+
|
|
1704
|
+
# raise ThreadListSyncEvent?
|
|
1705
|
+
when :THREAD_MEMBER_UPDATE
|
|
1706
|
+
ensure_thread_member(data)
|
|
1707
|
+
when :THREAD_MEMBERS_UPDATE
|
|
1708
|
+
data['added_members']&.each do |added_member|
|
|
1709
|
+
ensure_thread_member(added_member) if added_member['user_id']
|
|
1710
|
+
end
|
|
1711
|
+
|
|
1712
|
+
data['removed_member_ids']&.each do |member_id|
|
|
1713
|
+
@thread_members[data['id']&.resolve_id]&.delete(member_id&.resolve_id)
|
|
1714
|
+
end
|
|
1715
|
+
|
|
1716
|
+
event = ThreadMembersUpdateEvent.new(data, self)
|
|
1717
|
+
raise_event(event)
|
|
1349
1718
|
else
|
|
1350
1719
|
# another event that we don't support yet
|
|
1351
1720
|
debug "Event #{type} has been received but is unsupported. Raising UnknownEvent"
|
|
@@ -1388,15 +1757,15 @@ module Discordrb
|
|
|
1388
1757
|
end
|
|
1389
1758
|
|
|
1390
1759
|
def call_event(handler, event)
|
|
1391
|
-
t = Thread.new do
|
|
1760
|
+
t = Thread.new(event) do |evt|
|
|
1392
1761
|
@event_threads ||= []
|
|
1393
1762
|
@current_thread ||= 0
|
|
1394
1763
|
|
|
1395
1764
|
@event_threads << t
|
|
1396
1765
|
Thread.current[:discordrb_name] = "et-#{@current_thread += 1}"
|
|
1397
1766
|
begin
|
|
1398
|
-
handler.call(
|
|
1399
|
-
handler.after_call(
|
|
1767
|
+
handler.call(evt)
|
|
1768
|
+
handler.after_call(evt)
|
|
1400
1769
|
rescue StandardError => e
|
|
1401
1770
|
log_exception(e)
|
|
1402
1771
|
ensure
|
|
@@ -1407,7 +1776,7 @@ module Discordrb
|
|
|
1407
1776
|
|
|
1408
1777
|
def handle_awaits(event)
|
|
1409
1778
|
@awaits ||= {}
|
|
1410
|
-
@awaits.
|
|
1779
|
+
@awaits.each_value do |await|
|
|
1411
1780
|
key, should_delete = await.match(event)
|
|
1412
1781
|
next unless key
|
|
1413
1782
|
|
|
@@ -1420,6 +1789,8 @@ module Discordrb
|
|
|
1420
1789
|
end
|
|
1421
1790
|
|
|
1422
1791
|
def calculate_intents(intents)
|
|
1792
|
+
intents = [intents] unless intents.is_a? Array
|
|
1793
|
+
|
|
1423
1794
|
intents.reduce(0) do |sum, intent|
|
|
1424
1795
|
case intent
|
|
1425
1796
|
when Symbol
|