onyxcord 2.1.0 → 3.2.1
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/lib/onyxcord/application_commands/command.rb +4 -97
- data/lib/onyxcord/application_commands/context.rb +4 -94
- data/lib/onyxcord/application_commands/option.rb +4 -75
- data/lib/onyxcord/application_commands/registry.rb +4 -45
- data/lib/onyxcord/application_commands.rb +8 -5
- data/lib/onyxcord/bot.rb +24 -1759
- data/lib/onyxcord/{cache.rb → cache/manager.rb} +16 -14
- data/lib/onyxcord/cache/stores/gateway.rb +272 -0
- data/lib/onyxcord/commands/bot/channels.rb +48 -0
- data/lib/onyxcord/commands/bot/execution.rb +174 -0
- data/lib/onyxcord/commands/bot/message_dispatch.rb +58 -0
- data/lib/onyxcord/commands/bot/permissions.rb +72 -0
- data/lib/onyxcord/commands/bot.rb +209 -0
- data/lib/onyxcord/commands/container.rb +21 -2
- data/lib/onyxcord/commands/parser.rb +30 -1
- data/lib/onyxcord/container.rb +16 -960
- data/lib/onyxcord/core/bot/application_commands.rb +210 -0
- data/lib/onyxcord/core/bot/awaits.rb +112 -0
- data/lib/onyxcord/core/bot/invites.rb +42 -0
- data/lib/onyxcord/core/bot/messaging.rb +161 -0
- data/lib/onyxcord/core/bot/oauth.rb +27 -0
- data/lib/onyxcord/core/bot/presence.rb +103 -0
- data/lib/onyxcord/core/bot/runtime.rb +183 -0
- data/lib/onyxcord/core/bot/voice.rb +69 -0
- data/lib/onyxcord/{logger.rb → core/logger.rb} +5 -0
- data/lib/onyxcord/core/version.rb +5 -0
- data/lib/onyxcord/events/await/base.rb +48 -0
- data/lib/onyxcord/events/await.rb +1 -46
- data/lib/onyxcord/events/ban/base.rb +54 -0
- data/lib/onyxcord/events/ban/remove.rb +11 -0
- data/lib/onyxcord/events/bans.rb +2 -58
- data/lib/onyxcord/events/channels/base.rb +91 -0
- data/lib/onyxcord/events/channels/delete.rb +73 -0
- data/lib/onyxcord/events/channels/pins.rb +44 -0
- data/lib/onyxcord/events/channels/recipients.rb +77 -0
- data/lib/onyxcord/events/channels.rb +4 -239
- data/lib/onyxcord/events/guilds/audit_logs.rb +79 -0
- data/lib/onyxcord/events/guilds/base.rb +97 -0
- data/lib/onyxcord/events/guilds/emoji.rb +147 -0
- data/lib/onyxcord/events/guilds.rb +3 -267
- data/lib/onyxcord/events/handlers/channels.rb +133 -0
- data/lib/onyxcord/events/handlers/core.rb +146 -0
- data/lib/onyxcord/events/handlers/guilds.rb +375 -0
- data/lib/onyxcord/events/handlers/interactions.rb +238 -0
- data/lib/onyxcord/events/handlers/lifetime.rb +71 -0
- data/lib/onyxcord/events/handlers/messages.rb +218 -0
- data/lib/onyxcord/events/handlers/presence.rb +56 -0
- data/lib/onyxcord/events/handlers/raw.rb +39 -0
- data/lib/onyxcord/events/handlers/reactions.rb +98 -0
- data/lib/onyxcord/events/handlers/scheduled_events.rb +243 -0
- data/lib/onyxcord/events/handlers/voice.rb +46 -0
- data/lib/onyxcord/events/integration/base.rb +45 -0
- data/lib/onyxcord/events/integration/create.rb +11 -0
- data/lib/onyxcord/events/integration/delete.rb +48 -0
- data/lib/onyxcord/events/integration/update.rb +11 -0
- data/lib/onyxcord/events/integrations.rb +4 -98
- data/lib/onyxcord/events/interactions/application_commands.rb +185 -0
- data/lib/onyxcord/events/interactions/autocomplete.rb +62 -0
- data/lib/onyxcord/events/interactions/base.rb +175 -0
- data/lib/onyxcord/events/interactions/components.rb +221 -0
- data/lib/onyxcord/events/interactions/permissions.rb +53 -0
- data/lib/onyxcord/events/interactions.rb +5 -622
- data/lib/onyxcord/events/invite/create.rb +79 -0
- data/lib/onyxcord/events/invite/delete.rb +55 -0
- data/lib/onyxcord/events/invites.rb +2 -125
- data/lib/onyxcord/events/lifetime/base.rb +31 -0
- data/lib/onyxcord/events/lifetime.rb +1 -29
- data/lib/onyxcord/events/member/add.rb +12 -0
- data/lib/onyxcord/events/member/base.rb +67 -0
- data/lib/onyxcord/events/member/delete.rb +21 -0
- data/lib/onyxcord/events/member/update.rb +25 -0
- data/lib/onyxcord/events/members.rb +4 -108
- data/lib/onyxcord/events/message/base.rb +295 -0
- data/lib/onyxcord/events/message/ids.rb +71 -0
- data/lib/onyxcord/events/message/mentions.rb +55 -0
- data/lib/onyxcord/events/message/updates.rb +27 -0
- data/lib/onyxcord/events/message.rb +4 -397
- data/lib/onyxcord/events/poll/add.rb +11 -0
- data/lib/onyxcord/events/poll/base.rb +106 -0
- data/lib/onyxcord/events/poll/remove.rb +11 -0
- data/lib/onyxcord/events/polls.rb +3 -116
- data/lib/onyxcord/events/presence/playing.rb +77 -0
- data/lib/onyxcord/events/presence/status.rb +60 -0
- data/lib/onyxcord/events/presence.rb +2 -129
- data/lib/onyxcord/events/raw/base.rb +74 -0
- data/lib/onyxcord/events/raw.rb +1 -72
- data/lib/onyxcord/events/reactions/base.rb +143 -0
- data/lib/onyxcord/events/reactions/clear.rb +99 -0
- data/lib/onyxcord/events/reactions.rb +2 -216
- data/lib/onyxcord/events/role/create.rb +46 -0
- data/lib/onyxcord/events/role/delete.rb +40 -0
- data/lib/onyxcord/events/role/update.rb +11 -0
- data/lib/onyxcord/events/roles.rb +3 -85
- data/lib/onyxcord/events/scheduled_events/events.rb +112 -0
- data/lib/onyxcord/events/scheduled_events/users.rb +91 -0
- data/lib/onyxcord/events/scheduled_events.rb +2 -169
- data/lib/onyxcord/events/thread/base.rb +49 -0
- data/lib/onyxcord/events/thread/members.rb +44 -0
- data/lib/onyxcord/events/thread/update.rb +18 -0
- data/lib/onyxcord/events/threads.rb +3 -98
- data/lib/onyxcord/events/typing/base.rb +73 -0
- data/lib/onyxcord/events/typing.rb +1 -71
- data/lib/onyxcord/events/voice/server_update.rb +48 -0
- data/lib/onyxcord/events/voice/state_update.rb +137 -0
- data/lib/onyxcord/events/voice_server_update.rb +2 -46
- data/lib/onyxcord/events/voice_state_update.rb +2 -135
- data/lib/onyxcord/events/webhook/update.rb +65 -0
- data/lib/onyxcord/events/webhooks.rb +1 -63
- data/lib/onyxcord/gateway/client.rb +460 -0
- data/lib/onyxcord/interactions/command.rb +120 -0
- data/lib/onyxcord/interactions/context.rb +109 -0
- data/lib/onyxcord/interactions/internal/application_command.rb +203 -0
- data/lib/onyxcord/interactions/internal/message.rb +152 -0
- data/lib/onyxcord/interactions/internal/metadata.rb +109 -0
- data/lib/onyxcord/interactions/internal/option_builder.rb +230 -0
- data/lib/onyxcord/interactions/internal/permission_builder.rb +90 -0
- data/lib/onyxcord/interactions/option.rb +88 -0
- data/lib/onyxcord/interactions/registry.rb +50 -0
- data/lib/onyxcord/interactions.rb +16 -0
- data/lib/onyxcord/internal/async_runtime.rb +32 -0
- data/lib/onyxcord/internal/event_bus.rb +591 -0
- data/lib/onyxcord/internal/event_executor.rb +155 -0
- data/lib/onyxcord/internal/gateway/opcodes.rb +22 -0
- data/lib/onyxcord/internal/gateway/session.rb +45 -0
- data/lib/onyxcord/internal/http.rb +189 -0
- data/lib/onyxcord/internal/json.rb +51 -0
- data/lib/onyxcord/{message_payload.rb → internal/message_payload.rb} +3 -3
- data/lib/onyxcord/internal/rate_limiter/async_rest.rb +151 -0
- data/lib/onyxcord/internal/rate_limiter/gateway.rb +44 -0
- data/lib/onyxcord/internal/rate_limiter/rest.rb +144 -0
- data/lib/onyxcord/internal/websocket.rb +79 -0
- data/lib/onyxcord/light/data.rb +1 -1
- data/lib/onyxcord/light/integrations.rb +1 -1
- data/lib/onyxcord/light/light_bot.rb +7 -7
- data/lib/onyxcord/{data → models}/activity.rb +2 -2
- data/lib/onyxcord/{data → models}/application.rb +3 -3
- data/lib/onyxcord/{data → models}/avatar_decoration.rb +1 -1
- data/lib/onyxcord/{data → models}/channel.rb +23 -23
- data/lib/onyxcord/{data → models}/collectibles.rb +1 -1
- data/lib/onyxcord/{data → models}/emoji.rb +1 -1
- data/lib/onyxcord/models/interaction.rb +450 -0
- data/lib/onyxcord/{data → models}/invite.rb +1 -1
- data/lib/onyxcord/{data → models}/member.rb +11 -11
- data/lib/onyxcord/{data → models}/message.rb +18 -14
- data/lib/onyxcord/{data → models}/poll.rb +2 -2
- data/lib/onyxcord/{data → models}/primary_server.rb +1 -1
- data/lib/onyxcord/{data → models}/profile.rb +4 -4
- data/lib/onyxcord/{data → models}/role.rb +6 -12
- data/lib/onyxcord/{data → models}/scheduled_event.rb +5 -5
- data/lib/onyxcord/{data → models}/server.rb +41 -41
- data/lib/onyxcord/{data → models}/server_preview.rb +2 -2
- data/lib/onyxcord/{data → models}/team.rb +1 -1
- data/lib/onyxcord/{data → models}/user.rb +5 -5
- data/lib/onyxcord/{data → models}/webhook.rb +10 -10
- data/lib/onyxcord/models.rb +57 -0
- data/lib/onyxcord/{api.rb → rest/client.rb} +23 -22
- data/lib/onyxcord/{api → rest/routes}/application.rb +79 -57
- data/lib/onyxcord/rest/routes/channel/base.rb +73 -0
- data/lib/onyxcord/rest/routes/channel/groups.rb +78 -0
- data/lib/onyxcord/rest/routes/channel/messages.rb +130 -0
- data/lib/onyxcord/rest/routes/channel/permissions.rb +73 -0
- data/lib/onyxcord/rest/routes/channel/pins.rb +45 -0
- data/lib/onyxcord/rest/routes/channel/polls.rb +32 -0
- data/lib/onyxcord/rest/routes/channel/reactions.rb +86 -0
- data/lib/onyxcord/rest/routes/channel/threads.rb +176 -0
- data/lib/onyxcord/rest/routes/channel/webhooks.rb +47 -0
- data/lib/onyxcord/rest/routes/channel.rb +12 -0
- data/lib/onyxcord/{api/interaction.rb → rest/routes/interaction/base.rb} +7 -25
- data/lib/onyxcord/rest/routes/interaction/response.rb +24 -0
- data/lib/onyxcord/rest/routes/interaction.rb +4 -0
- data/lib/onyxcord/{api → rest/routes}/invite.rb +7 -7
- data/lib/onyxcord/rest/routes/server/admin.rb +174 -0
- data/lib/onyxcord/rest/routes/server/assets.rb +25 -0
- data/lib/onyxcord/rest/routes/server/bans.rb +67 -0
- data/lib/onyxcord/rest/routes/server/base.rb +77 -0
- data/lib/onyxcord/rest/routes/server/channels.rb +58 -0
- data/lib/onyxcord/rest/routes/server/emoji.rb +48 -0
- data/lib/onyxcord/rest/routes/server/members.rb +109 -0
- data/lib/onyxcord/rest/routes/server/messages.rb +19 -0
- data/lib/onyxcord/rest/routes/server/roles.rb +156 -0
- data/lib/onyxcord/rest/routes/server/scheduled_events.rb +86 -0
- data/lib/onyxcord/rest/routes/server.rb +12 -0
- data/lib/onyxcord/{api → rest/routes}/user.rb +23 -23
- data/lib/onyxcord/{api → rest/routes}/webhook.rb +22 -22
- data/lib/onyxcord/{allowed_mentions.rb → utils/allowed_mentions.rb} +1 -1
- data/lib/onyxcord/utils/timestamp.rb +69 -0
- data/lib/onyxcord/voice/{voice_bot.rb → client.rb} +4 -4
- data/lib/onyxcord/voice/encoder.rb +1 -1
- data/lib/onyxcord/voice/network/udp.rb +135 -0
- data/lib/onyxcord/voice/network/websocket.rb +225 -0
- data/lib/onyxcord/voice/network.rb +5 -357
- data/lib/onyxcord/webhooks/builder.rb +1 -1
- data/lib/onyxcord/webhooks/client.rb +13 -13
- data/lib/onyxcord/webhooks/modal/group_builder.rb +55 -0
- data/lib/onyxcord/webhooks/modal/label_builder.rb +183 -0
- data/lib/onyxcord/webhooks/modal.rb +2 -239
- data/lib/onyxcord/webhooks/version.rb +3 -3
- data/lib/onyxcord/webhooks/view/container_builder.rb +80 -0
- data/lib/onyxcord/webhooks/view/file_builder.rb +24 -0
- data/lib/onyxcord/webhooks/view/media_gallery_builder.rb +50 -0
- data/lib/onyxcord/webhooks/view/row_builder.rb +120 -0
- data/lib/onyxcord/webhooks/view/section_builder.rb +61 -0
- data/lib/onyxcord/webhooks/view/select_menu_builder.rb +77 -0
- data/lib/onyxcord/webhooks/view/separator_builder.rb +22 -0
- data/lib/onyxcord/webhooks/view/text_display_builder.rb +20 -0
- data/lib/onyxcord/webhooks/view.rb +9 -425
- data/lib/onyxcord.rb +106 -42
- metadata +207 -92
- data/.github/CONTRIBUTING.md +0 -13
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
- data/.github/pull_request_template.md +0 -37
- data/.github/workflows/ci.yml +0 -78
- data/.github/workflows/codeql.yml +0 -65
- data/.github/workflows/deploy.yml +0 -54
- data/.github/workflows/release.yml +0 -51
- data/.gitignore +0 -17
- data/.markdownlint.json +0 -4
- data/.overcommit.yml +0 -7
- data/.rspec +0 -2
- data/.rubocop.yml +0 -129
- data/.yardopts +0 -1
- data/CHANGELOG.md +0 -257
- data/Gemfile +0 -6
- data/LICENSE.txt +0 -21
- data/README.md +0 -448
- data/Rakefile +0 -13
- data/lib/onyxcord/api/channel.rb +0 -703
- data/lib/onyxcord/api/server.rb +0 -775
- data/lib/onyxcord/async/runtime.rb +0 -30
- data/lib/onyxcord/commands/command_bot.rb +0 -505
- data/lib/onyxcord/data/interaction.rb +0 -1151
- data/lib/onyxcord/data.rb +0 -57
- data/lib/onyxcord/event_executor.rb +0 -153
- data/lib/onyxcord/gateway.rb +0 -505
- data/lib/onyxcord/http.rb +0 -186
- data/lib/onyxcord/json.rb +0 -49
- data/lib/onyxcord/rate_limiter/async_rest.rb +0 -150
- data/lib/onyxcord/rate_limiter/gateway.rb +0 -42
- data/lib/onyxcord/rate_limiter/rest.rb +0 -142
- data/lib/onyxcord/version.rb +0 -7
- data/lib/onyxcord/websocket.rb +0 -77
- data/onyxcord.gemspec +0 -63
- /data/lib/onyxcord/{configuration.rb → core/configuration.rb} +0 -0
- /data/lib/onyxcord/{errors.rb → core/errors.rb} +0 -0
- /data/lib/onyxcord/{upload.rb → internal/upload.rb} +0 -0
- /data/lib/onyxcord/{data → models}/attachment.rb +0 -0
- /data/lib/onyxcord/{data → models}/audit_logs.rb +0 -0
- /data/lib/onyxcord/{data → models}/call.rb +0 -0
- /data/lib/onyxcord/{data → models}/channel_tag.rb +0 -0
- /data/lib/onyxcord/{data → models}/component.rb +0 -0
- /data/lib/onyxcord/{data → models}/embed.rb +0 -0
- /data/lib/onyxcord/{data → models}/install_params.rb +0 -0
- /data/lib/onyxcord/{data → models}/integration.rb +0 -0
- /data/lib/onyxcord/{data → models}/message_activity.rb +0 -0
- /data/lib/onyxcord/{data → models}/overwrite.rb +0 -0
- /data/lib/onyxcord/{data → models}/reaction.rb +0 -0
- /data/lib/onyxcord/{data → models}/recipient.rb +0 -0
- /data/lib/onyxcord/{data → models}/role_connection_data.rb +0 -0
- /data/lib/onyxcord/{data → models}/role_subscription.rb +0 -0
- /data/lib/onyxcord/{data → models}/snapshot.rb +0 -0
- /data/lib/onyxcord/{data → models}/timestamp.rb +0 -0
- /data/lib/onyxcord/{data → models}/voice_region.rb +0 -0
- /data/lib/onyxcord/{data → models}/voice_state.rb +0 -0
- /data/lib/onyxcord/{colour_rgb.rb → utils/colour_rgb.rb} +0 -0
- /data/lib/onyxcord/{id_object.rb → utils/id_object.rb} +0 -0
- /data/lib/onyxcord/{message_components.rb → utils/message_components.rb} +0 -0
- /data/lib/onyxcord/{paginator.rb → utils/paginator.rb} +0 -0
- /data/lib/onyxcord/{permissions.rb → utils/permissions.rb} +0 -0
data/lib/onyxcord/bot.rb
CHANGED
|
@@ -1,50 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'onyxcord/http'
|
|
4
3
|
require 'zlib'
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
require 'onyxcord/events/channels'
|
|
14
|
-
require 'onyxcord/events/members'
|
|
15
|
-
require 'onyxcord/events/roles'
|
|
16
|
-
require 'onyxcord/events/guilds'
|
|
17
|
-
require 'onyxcord/events/await'
|
|
18
|
-
require 'onyxcord/events/bans'
|
|
19
|
-
require 'onyxcord/events/raw'
|
|
20
|
-
require 'onyxcord/events/reactions'
|
|
21
|
-
require 'onyxcord/events/webhooks'
|
|
22
|
-
require 'onyxcord/events/invites'
|
|
23
|
-
require 'onyxcord/events/interactions'
|
|
24
|
-
require 'onyxcord/events/threads'
|
|
25
|
-
require 'onyxcord/events/integrations'
|
|
26
|
-
require 'onyxcord/events/scheduled_events'
|
|
27
|
-
require 'onyxcord/events/polls'
|
|
28
|
-
|
|
29
|
-
require 'onyxcord/api'
|
|
30
|
-
require 'onyxcord/api/channel'
|
|
31
|
-
require 'onyxcord/api/server'
|
|
32
|
-
require 'onyxcord/api/invite'
|
|
33
|
-
require 'onyxcord/api/interaction'
|
|
34
|
-
require 'onyxcord/api/application'
|
|
35
|
-
|
|
36
|
-
require 'onyxcord/async/runtime'
|
|
37
|
-
require 'onyxcord/errors'
|
|
38
|
-
require 'onyxcord/message_components'
|
|
39
|
-
require 'onyxcord/data'
|
|
40
|
-
require 'onyxcord/await'
|
|
41
|
-
require 'onyxcord/container'
|
|
42
|
-
require 'onyxcord/websocket'
|
|
43
|
-
require 'onyxcord/cache'
|
|
44
|
-
require 'onyxcord/gateway'
|
|
45
|
-
|
|
46
|
-
require 'onyxcord/application_commands'
|
|
47
|
-
require 'onyxcord/voice/voice_bot'
|
|
4
|
+
require_relative 'core/bot/runtime'
|
|
5
|
+
require_relative 'core/bot/invites'
|
|
6
|
+
require_relative 'core/bot/voice'
|
|
7
|
+
require_relative 'core/bot/messaging'
|
|
8
|
+
require_relative 'core/bot/oauth'
|
|
9
|
+
require_relative 'core/bot/presence'
|
|
10
|
+
require_relative 'core/bot/awaits'
|
|
11
|
+
require_relative 'core/bot/application_commands'
|
|
48
12
|
|
|
49
13
|
module OnyxCord
|
|
50
14
|
# Represents a Discord bot, including servers, users, etc.
|
|
@@ -81,11 +45,20 @@ module OnyxCord
|
|
|
81
45
|
# @return [Hash] the normalized cache policy for this bot.
|
|
82
46
|
attr_reader :cache_policy
|
|
83
47
|
|
|
84
|
-
# @return [
|
|
48
|
+
# @return [Internal::EventExecutor::Inline, Internal::EventExecutor::Pool, Internal::EventExecutor::AsyncPool]
|
|
85
49
|
attr_reader :event_executor
|
|
86
50
|
|
|
87
51
|
include EventContainer
|
|
88
52
|
include Cache
|
|
53
|
+
include Internal::EventBus
|
|
54
|
+
include Runtime
|
|
55
|
+
include Invites
|
|
56
|
+
include VoiceControl
|
|
57
|
+
include Messaging
|
|
58
|
+
include OAuth
|
|
59
|
+
include Presence
|
|
60
|
+
include Awaits
|
|
61
|
+
include ApplicationCommands
|
|
89
62
|
|
|
90
63
|
# Makes a new bot with the given authentication data. It will be ready to be added event handlers to and can
|
|
91
64
|
# eventually be run with {#run}.
|
|
@@ -176,7 +149,7 @@ module OnyxCord
|
|
|
176
149
|
end
|
|
177
150
|
|
|
178
151
|
@token = process_token(@type, token)
|
|
179
|
-
@gateway = Gateway.new(self, @token, @shard_key, @compress_mode, @intents)
|
|
152
|
+
@gateway = Gateway::Client.new(self, @token, @shard_key, @compress_mode, @intents)
|
|
180
153
|
|
|
181
154
|
init_cache
|
|
182
155
|
|
|
@@ -188,7 +161,7 @@ module OnyxCord
|
|
|
188
161
|
|
|
189
162
|
@current_thread = 0
|
|
190
163
|
@current_thread_mutex = Mutex.new
|
|
191
|
-
@event_executor = EventExecutor.build(executor_type, workers: executor_workers, queue_size: executor_queue_size)
|
|
164
|
+
@event_executor = Internal::EventExecutor.build(executor_type, workers: executor_workers, queue_size: executor_queue_size)
|
|
192
165
|
@event_threads = @event_executor.threads
|
|
193
166
|
|
|
194
167
|
@status = :online
|
|
@@ -261,7 +234,7 @@ module OnyxCord
|
|
|
261
234
|
def profile
|
|
262
235
|
return @profile if @profile
|
|
263
236
|
|
|
264
|
-
response = OnyxCord::
|
|
237
|
+
response = OnyxCord::REST::User.profile(@token)
|
|
265
238
|
@profile = Profile.new(JSON.parse(response), self)
|
|
266
239
|
end
|
|
267
240
|
|
|
@@ -270,7 +243,7 @@ module OnyxCord
|
|
|
270
243
|
# The bot's OAuth application.
|
|
271
244
|
# @return [Application] The bot's application info.
|
|
272
245
|
def bot_application
|
|
273
|
-
response =
|
|
246
|
+
response = REST.oauth_application(token)
|
|
274
247
|
Application.new(JSON.parse(response), self)
|
|
275
248
|
end
|
|
276
249
|
|
|
@@ -280,7 +253,7 @@ module OnyxCord
|
|
|
280
253
|
# Get the role connection metadata records associated with this application.
|
|
281
254
|
# @return [Array<RoleConnectionMetadata>] the role connection metadata records associated with this application.
|
|
282
255
|
def role_connection_metadata_records
|
|
283
|
-
response =
|
|
256
|
+
response = REST::Application.get_application_role_connection_metadata_records(@bot.token, @id)
|
|
284
257
|
JSON.parse(response).map { |role_connection| RoleConnectionMetadata.new(role_connection, @bot) }
|
|
285
258
|
end
|
|
286
259
|
|
|
@@ -288,7 +261,7 @@ module OnyxCord
|
|
|
288
261
|
# {API} methods.
|
|
289
262
|
# @return [String] The API token.
|
|
290
263
|
def token
|
|
291
|
-
|
|
264
|
+
REST.bot_name = @name
|
|
292
265
|
@token
|
|
293
266
|
end
|
|
294
267
|
|
|
@@ -298,1717 +271,9 @@ module OnyxCord
|
|
|
298
271
|
@token.split(' ').last
|
|
299
272
|
end
|
|
300
273
|
|
|
301
|
-
# Runs the bot, which logs into Discord and connects the WebSocket. This
|
|
302
|
-
# prevents all further execution unless it is executed with
|
|
303
|
-
# `background` = `true`.
|
|
304
|
-
# @param background [true, false] If it is `true`, then the bot will run in
|
|
305
|
-
# another thread to allow further execution. If it is `false`, this method
|
|
306
|
-
# will block until {#stop} is called. If the bot is run with `true`, make
|
|
307
|
-
# sure to eventually call {#join} so the script doesn't stop prematurely.
|
|
308
|
-
# @note Running the bot in the background means that you can call some
|
|
309
|
-
# methods that require a gateway connection *before* that connection is
|
|
310
|
-
# established. In most cases an exception will be raised if you try to do
|
|
311
|
-
# this. If you need a way to safely run code after the bot is fully
|
|
312
|
-
# connected, use a {#ready} event handler instead.
|
|
313
|
-
def run(background = false)
|
|
314
|
-
if background
|
|
315
|
-
@run_task = OnyxCord::AsyncRuntime.async { run_forever }
|
|
316
|
-
return @run_task
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
OnyxCord::AsyncRuntime.run { run_forever }
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
def run_forever
|
|
323
|
-
@gateway.run
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
def join
|
|
327
|
-
@run_task&.wait
|
|
328
|
-
end
|
|
329
|
-
alias_method :sync, :join
|
|
330
|
-
|
|
331
|
-
def stop(_no_sync = nil)
|
|
332
|
-
@gateway.stop
|
|
333
|
-
@event_executor.shutdown
|
|
334
|
-
@run_task&.stop if @run_task.respond_to?(:stop)
|
|
335
|
-
nil
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
# @return [true, false] whether or not the bot is currently connected to Discord.
|
|
339
|
-
def connected?
|
|
340
|
-
@gateway.open?
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
# Makes the bot join an invite to a server.
|
|
344
|
-
# @param invite [String, Invite] The invite to join. For possible formats see {#resolve_invite_code}.
|
|
345
|
-
def accept_invite(invite)
|
|
346
|
-
resolved = invite(invite).code
|
|
347
|
-
API::Invite.accept(token, resolved)
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
# Creates an OAuth invite URL that can be used to invite this bot to a particular server.
|
|
351
|
-
# @param server [Server, nil] The server the bot should be invited to, or nil if a general invite should be created.
|
|
352
|
-
# @param permission_bits [String, Integer] Permission bits that should be appended to invite url.
|
|
353
|
-
# @param redirect_uri [String] Redirect URI that should be appended to invite url.
|
|
354
|
-
# @param scopes [Array<String>] Scopes that should be appended to invite url.
|
|
355
|
-
# @return [String] the OAuth invite URL.
|
|
356
|
-
def invite_url(server: nil, permission_bits: nil, redirect_uri: nil, scopes: ['bot'])
|
|
357
|
-
@client_id ||= bot_application.id
|
|
358
|
-
|
|
359
|
-
query = URI.encode_www_form({
|
|
360
|
-
client_id: @client_id,
|
|
361
|
-
guild_id: server&.id,
|
|
362
|
-
permissions: permission_bits,
|
|
363
|
-
redirect_uri: redirect_uri,
|
|
364
|
-
scope: scopes.join(' ')
|
|
365
|
-
}.compact)
|
|
366
|
-
|
|
367
|
-
"https://discord.com/oauth2/authorize?#{query}"
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
# @return [Hash<Integer => VoiceBot>] the voice connections this bot currently has, by the server ID to which they are connected.
|
|
371
|
-
attr_reader :voices
|
|
372
|
-
|
|
373
|
-
# Gets the voice bot for a particular server or channel. You can connect to a new channel using the {#voice_connect}
|
|
374
|
-
# method.
|
|
375
|
-
# @param thing [Channel, Server, Integer] the server or channel you want to get the voice bot for, or its ID.
|
|
376
|
-
# @return [Voice::VoiceBot, nil] the VoiceBot for the thing you specified, or nil if there is no connection yet
|
|
377
|
-
def voice(thing)
|
|
378
|
-
id = thing.resolve_id
|
|
379
|
-
return @voices[id] if @voices[id]
|
|
380
|
-
|
|
381
|
-
channel = channel(id)
|
|
382
|
-
return nil unless channel
|
|
383
|
-
|
|
384
|
-
server_id = channel.server.id
|
|
385
|
-
return @voices[server_id] if @voices[server_id]
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
# Connects to a voice channel, initializes network connections and returns the {Voice::VoiceBot} over which audio
|
|
389
|
-
# data can then be sent. After connecting, the bot can also be accessed using {#voice}. If the bot is already
|
|
390
|
-
# connected to voice, the existing connection will be terminated - you don't have to call
|
|
391
|
-
# {OnyxCord::Voice::VoiceBot#destroy} before calling this method.
|
|
392
|
-
# @param chan [Channel, String, Integer] The voice channel, or its ID, to connect to.
|
|
393
|
-
# @param encrypted [true, false] Whether voice communication should be encrypted using
|
|
394
|
-
# (uses an XSalsa20 stream cipher for encryption and Poly1305 for authentication)
|
|
395
|
-
# @return [Voice::VoiceBot] the initialized bot over which audio data can then be sent.
|
|
396
|
-
def voice_connect(chan, encrypted = true)
|
|
397
|
-
raise ArgumentError, 'Unencrypted voice connections are no longer supported.' unless encrypted
|
|
398
|
-
|
|
399
|
-
chan = channel(chan.resolve_id)
|
|
400
|
-
server_id = chan.server.id
|
|
401
|
-
|
|
402
|
-
if @voices[chan.id]
|
|
403
|
-
debug('Voice bot exists already! Destroying it')
|
|
404
|
-
@voices[chan.id].destroy
|
|
405
|
-
@voices.delete(chan.id)
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
debug("Got voice channel: #{chan}")
|
|
409
|
-
|
|
410
|
-
@should_connect_to_voice[server_id] = chan
|
|
411
|
-
@gateway.send_voice_state_update(server_id.to_s, chan.id.to_s, false, false)
|
|
412
|
-
|
|
413
|
-
debug('Voice channel init packet sent! Now waiting.')
|
|
414
|
-
|
|
415
|
-
OnyxCord::AsyncRuntime.sleep(0.05) until @voices[server_id]
|
|
416
|
-
debug('Voice connect succeeded!')
|
|
417
|
-
@voices[server_id]
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
# Disconnects the client from a specific voice connection given the server ID. Usually it's more convenient to use
|
|
421
|
-
# {OnyxCord::Voice::VoiceBot#destroy} rather than this.
|
|
422
|
-
# @param server [Server, String, Integer] The server, or server ID, the voice connection is on.
|
|
423
|
-
# @param destroy_vws [true, false] Whether or not the VWS should also be destroyed. If you're calling this method
|
|
424
|
-
# directly, you should leave it as true.
|
|
425
|
-
def voice_destroy(server, destroy_vws = true)
|
|
426
|
-
server = server.resolve_id
|
|
427
|
-
@gateway.send_voice_state_update(server.to_s, nil, false, false)
|
|
428
|
-
@voices[server].destroy if @voices[server] && destroy_vws
|
|
429
|
-
@voices.delete(server)
|
|
430
|
-
end
|
|
431
|
-
|
|
432
|
-
# Revokes an invite to a server. Will fail unless you have the *Manage Server* permission.
|
|
433
|
-
# It is recommended that you use {Invite#delete} instead.
|
|
434
|
-
# @param code [String, Invite] The invite to revoke. For possible formats see {#resolve_invite_code}.
|
|
435
|
-
def delete_invite(code)
|
|
436
|
-
invite = resolve_invite_code(code)
|
|
437
|
-
API::Invite.delete(token, invite)
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
# Sends a text message to a channel given its ID and the message's content.
|
|
441
|
-
# @param channel [Channel, String, Integer] The channel, or its ID, to send something to.
|
|
442
|
-
# @param content [String] The text that should be sent as a message. It is limited to 2000 characters (Discord imposed).
|
|
443
|
-
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
444
|
-
# @param embeds [Hash, OnyxCord::Webhooks::Embed, Array<Hash>, Array<OnyxCord::Webhooks::Embed> nil] The rich embed(s) to append to this message.
|
|
445
|
-
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
446
|
-
# @param message_reference [Message, String, Integer, Hash, nil] The message, or message ID, to reply to if any.
|
|
447
|
-
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
448
|
-
# @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.
|
|
449
|
-
# @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
|
|
450
|
-
# @param enforce_nonce [true, false] Whether the nonce should be enforced and used for message de-duplication.
|
|
451
|
-
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
|
|
452
|
-
# @return [Message] The message that was sent.
|
|
453
|
-
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, poll = nil)
|
|
454
|
-
channel = channel.resolve_id
|
|
455
|
-
debug("Sending message to #{channel} with content '#{content}'")
|
|
456
|
-
allowed_mentions = { parse: [] } if allowed_mentions == false
|
|
457
|
-
message_reference = { message_id: message_reference.resolve_id } if message_reference.respond_to?(:resolve_id)
|
|
458
|
-
embeds = (embeds.instance_of?(Array) ? embeds.map(&:to_hash) : [embeds&.to_hash]).compact
|
|
459
|
-
flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components)
|
|
460
|
-
|
|
461
|
-
response = API::Channel.create_message(token, channel, content, tts, embeds, nonce, attachments, allowed_mentions&.to_hash, message_reference, components, flags, enforce_nonce, poll&.to_h)
|
|
462
|
-
Message.new(JSON.parse(response), self)
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
# Sends a text message to a channel given its ID and the message's content,
|
|
466
|
-
# then deletes it after the specified timeout in seconds.
|
|
467
|
-
# @param channel [Channel, String, Integer] The channel, or its ID, to send something to.
|
|
468
|
-
# @param content [String] The text that should be sent as a message. It is limited to 2000 characters (Discord imposed).
|
|
469
|
-
# @param timeout [Float] The amount of time in seconds after which the message sent will be deleted.
|
|
470
|
-
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
|
|
471
|
-
# @param embeds [Hash, OnyxCord::Webhooks::Embed, Array<Hash>, Array<OnyxCord::Webhooks::Embed> nil] The rich embed(s) to append to this message.
|
|
472
|
-
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
|
|
473
|
-
# @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
|
|
474
|
-
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
|
|
475
|
-
# @param components [View, Array<Hash>] Interaction components to associate with this message.
|
|
476
|
-
# @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.
|
|
477
|
-
# @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
|
|
478
|
-
# @param enforce_nonce [true, false] Whether the nonce should be enforced and used for message de-duplication.
|
|
479
|
-
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
|
|
480
|
-
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, poll = nil)
|
|
481
|
-
OnyxCord::AsyncRuntime.async do
|
|
482
|
-
message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, flags, nonce, enforce_nonce, poll)
|
|
483
|
-
OnyxCord::AsyncRuntime.sleep(timeout)
|
|
484
|
-
message.delete
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
nil
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
# Sends a file to a channel. If it is an image, it will automatically be embedded.
|
|
491
|
-
# @note This executes in a blocking way, so if you're sending long files, be wary of delays.
|
|
492
|
-
# @param channel [Channel, String, Integer] The channel, or its ID, to send something to.
|
|
493
|
-
# @param file [File] The file that should be sent.
|
|
494
|
-
# @param caption [string] The caption for the file.
|
|
495
|
-
# @param tts [true, false] Whether or not this file's caption should be sent using Discord text-to-speech.
|
|
496
|
-
# @param filename [String] Overrides the filename of the uploaded file
|
|
497
|
-
# @param spoiler [true, false] Whether or not this file should appear as a spoiler.
|
|
498
|
-
# @example Send a file from disk
|
|
499
|
-
# bot.send_file(83281822225530880, File.open('rubytaco.png', 'r'))
|
|
500
|
-
def send_file(channel, file, caption: nil, tts: false, filename: nil, spoiler: nil)
|
|
501
|
-
if file.respond_to?(:read)
|
|
502
|
-
if spoiler
|
|
503
|
-
filename ||= File.basename(file.path)
|
|
504
|
-
filename = "SPOILER_#{filename}" unless filename.start_with? 'SPOILER_'
|
|
505
|
-
end
|
|
506
|
-
file.define_singleton_method(:original_filename) { filename } if filename
|
|
507
|
-
file.define_singleton_method(:path) { filename } if filename
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
channel = channel.resolve_id
|
|
511
|
-
response = API::Channel.upload_file(token, channel, file, caption: caption, tts: tts)
|
|
512
|
-
Message.new(JSON.parse(response), self)
|
|
513
|
-
end
|
|
514
|
-
|
|
515
|
-
# Creates a new application to do OAuth authorization with. This allows you to use OAuth to authorize users using
|
|
516
|
-
# Discord. For information how to use this, see the docs: https://discord.com/developers/docs/topics/oauth2
|
|
517
|
-
# @param name [String] What your application should be called.
|
|
518
|
-
# @param redirect_uris [Array<String>] URIs that Discord should redirect your users to after authorizing.
|
|
519
|
-
# @return [Array(String, String)] your applications' client ID and client secret to be used in OAuth authorization.
|
|
520
|
-
def create_oauth_application(name, redirect_uris)
|
|
521
|
-
response = JSON.parse(API.create_oauth_application(@token, name, redirect_uris))
|
|
522
|
-
[response['id'], response['secret']]
|
|
523
|
-
end
|
|
524
|
-
|
|
525
|
-
# Changes information about your OAuth application
|
|
526
|
-
# @param name [String] What your application should be called.
|
|
527
|
-
# @param redirect_uris [Array<String>] URIs that Discord should redirect your users to after authorizing.
|
|
528
|
-
# @param description [String] A string that describes what your application does.
|
|
529
|
-
# @param icon [String, nil] A data URI for your icon image (for example a base 64 encoded image), or nil if no icon
|
|
530
|
-
# should be set or changed.
|
|
531
|
-
def update_oauth_application(name, redirect_uris, description = '', icon = nil)
|
|
532
|
-
API.update_oauth_application(@token, name, redirect_uris, description, icon)
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
# Gets the users, channels, roles and emoji from a string.
|
|
536
|
-
# @param mentions [String] The mentions, which should look like `<@12314873129>`, `<#123456789>`, `<@&123456789>` or `<:name:126328:>`.
|
|
537
|
-
# @param server [Server, nil] The server of the associated mentions. (recommended for role parsing, to speed things up)
|
|
538
|
-
# @return [Array<User, Channel, Role, Emoji>] The array of users, channels, roles and emoji identified by the mentions, or `nil` if none exists.
|
|
539
|
-
def parse_mentions(mentions, server = nil)
|
|
540
|
-
array_to_return = []
|
|
541
|
-
# While possible mentions may be in message
|
|
542
|
-
while mentions.include?('<') && mentions.include?('>')
|
|
543
|
-
# Removing all content before the next possible mention
|
|
544
|
-
mentions = mentions.split('<', 2)[1]
|
|
545
|
-
# Locate the first valid mention enclosed in `<...>`, otherwise advance to the next open `<`
|
|
546
|
-
next unless mentions.split('>', 2).first.length < mentions.split('<', 2).first.length
|
|
547
|
-
|
|
548
|
-
# Store the possible mention value to be validated with RegEx
|
|
549
|
-
mention = mentions.split('>', 2).first
|
|
550
|
-
if /@!?(?<id>\d+)/ =~ mention
|
|
551
|
-
array_to_return << user(id) unless user(id).nil?
|
|
552
|
-
elsif /#(?<id>\d+)/ =~ mention
|
|
553
|
-
array_to_return << channel(id, server) unless channel(id, server).nil?
|
|
554
|
-
elsif /@&(?<id>\d+)/ =~ mention
|
|
555
|
-
if server
|
|
556
|
-
array_to_return << server.role(id) unless server.role(id).nil?
|
|
557
|
-
else
|
|
558
|
-
@servers.each_value do |element|
|
|
559
|
-
array_to_return << element.role(id) unless element.role(id).nil?
|
|
560
|
-
end
|
|
561
|
-
end
|
|
562
|
-
elsif /(?<animated>^a|^${0}):(?<name>\w+):(?<id>\d+)/ =~ mention
|
|
563
|
-
array_to_return << (emoji(id) || Emoji.new({ 'animated' => animated != '', 'name' => name, 'id' => id }, self, nil))
|
|
564
|
-
end
|
|
565
|
-
end
|
|
566
|
-
array_to_return
|
|
567
|
-
end
|
|
568
|
-
|
|
569
|
-
# Gets the user, channel, role or emoji from a string.
|
|
570
|
-
# @param mention [String] The mention, which should look like `<@12314873129>`, `<#123456789>`, `<@&123456789>` or `<:name:126328:>`.
|
|
571
|
-
# @param server [Server, nil] The server of the associated mention. (recommended for role parsing, to speed things up)
|
|
572
|
-
# @return [User, Channel, Role, Emoji] The user, channel, role or emoji identified by the mention, or `nil` if none exists.
|
|
573
|
-
def parse_mention(mention, server = nil)
|
|
574
|
-
parse_mentions(mention, server).first
|
|
575
|
-
end
|
|
576
|
-
|
|
577
|
-
# Updates presence status.
|
|
578
|
-
# @param status [String] The status the bot should show up as. Can be `online`, `dnd`, `idle`, or `invisible`
|
|
579
|
-
# @param activity [String, nil] The name of the activity to be played/watched/listened to/stream name on the stream.
|
|
580
|
-
# @param url [String, nil] The Twitch URL to display as a stream. nil for no stream.
|
|
581
|
-
# @param since [Integer] When this status was set.
|
|
582
|
-
# @param afk [true, false] Whether the bot is AFK.
|
|
583
|
-
# @param activity_type [Integer] The type of activity status to display.
|
|
584
|
-
# Can be 0 (Playing), 1 (Streaming), 2 (Listening), 3 (Watching), or 5 (Competing).
|
|
585
|
-
# @see Gateway#send_status_update
|
|
586
|
-
def update_status(status, activity, url, since = 0, afk = false, activity_type = 0)
|
|
587
|
-
gateway_check
|
|
588
|
-
|
|
589
|
-
@activity = activity
|
|
590
|
-
@status = status
|
|
591
|
-
@streamurl = url
|
|
592
|
-
type = url ? 1 : activity_type
|
|
593
|
-
|
|
594
|
-
activity_obj = activity || url ? { 'name' => activity, 'url' => url, 'type' => type } : nil
|
|
595
|
-
@gateway.send_status_update(status, since, activity_obj, afk)
|
|
596
|
-
|
|
597
|
-
# Update the status in the cache
|
|
598
|
-
profile.update_presence('status' => status.to_s, 'activities' => [activity_obj].compact)
|
|
599
|
-
end
|
|
600
|
-
|
|
601
|
-
# Sets the currently playing game to the specified game.
|
|
602
|
-
# @param name [String] The name of the game to be played.
|
|
603
|
-
# @return [String] The game that is being played now.
|
|
604
|
-
def game=(name)
|
|
605
|
-
gateway_check
|
|
606
|
-
update_status(@status, name, nil)
|
|
607
|
-
end
|
|
608
|
-
|
|
609
|
-
alias_method :playing=, :game=
|
|
610
|
-
|
|
611
|
-
# Sets the current listening status to the specified name.
|
|
612
|
-
# @param name [String] The thing to be listened to.
|
|
613
|
-
# @return [String] The thing that is now being listened to.
|
|
614
|
-
def listening=(name)
|
|
615
|
-
gateway_check
|
|
616
|
-
update_status(@status, name, nil, nil, nil, 2)
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
# Sets the current watching status to the specified name.
|
|
620
|
-
# @param name [String] The thing to be watched.
|
|
621
|
-
# @return [String] The thing that is now being watched.
|
|
622
|
-
def watching=(name)
|
|
623
|
-
gateway_check
|
|
624
|
-
update_status(@status, name, nil, nil, nil, 3)
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
# Sets the currently online stream to the specified name and Twitch URL.
|
|
628
|
-
# @param name [String] The name of the stream to display.
|
|
629
|
-
# @param url [String] The url of the current Twitch stream.
|
|
630
|
-
# @return [String] The stream name that is being displayed now.
|
|
631
|
-
def stream(name, url)
|
|
632
|
-
gateway_check
|
|
633
|
-
update_status(@status, name, url)
|
|
634
|
-
name
|
|
635
|
-
end
|
|
636
|
-
|
|
637
|
-
# Sets the currently competing status to the specified name.
|
|
638
|
-
# @param name [String] The name of the game to be competing in.
|
|
639
|
-
# @return [String] The game that is being competed in now.
|
|
640
|
-
def competing=(name)
|
|
641
|
-
gateway_check
|
|
642
|
-
update_status(@status, name, nil, nil, nil, 5)
|
|
643
|
-
end
|
|
644
|
-
|
|
645
|
-
# Sets status to online.
|
|
646
|
-
def online
|
|
647
|
-
gateway_check
|
|
648
|
-
update_status(:online, @activity, @streamurl)
|
|
649
|
-
end
|
|
650
|
-
|
|
651
|
-
alias_method :on, :online
|
|
652
|
-
|
|
653
|
-
# Sets status to idle.
|
|
654
|
-
def idle
|
|
655
|
-
gateway_check
|
|
656
|
-
update_status(:idle, @activity, nil)
|
|
657
|
-
end
|
|
658
|
-
|
|
659
|
-
alias_method :away, :idle
|
|
660
|
-
|
|
661
|
-
# Sets the bot's status to DnD (red icon).
|
|
662
|
-
def dnd
|
|
663
|
-
gateway_check
|
|
664
|
-
update_status(:dnd, @activity, nil)
|
|
665
|
-
end
|
|
666
|
-
|
|
667
|
-
# Sets the bot's status to invisible (appears offline).
|
|
668
|
-
def invisible
|
|
669
|
-
gateway_check
|
|
670
|
-
update_status(:invisible, @activity, nil)
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
# Join a thread
|
|
674
|
-
# @param channel [Channel, Integer, String]
|
|
675
|
-
def join_thread(channel)
|
|
676
|
-
API::Channel.join_thread(@token, channel.resolve_id)
|
|
677
|
-
nil
|
|
678
|
-
end
|
|
679
|
-
|
|
680
|
-
# Leave a thread
|
|
681
|
-
# @param channel [Channel, Integer, String]
|
|
682
|
-
def leave_thread(channel)
|
|
683
|
-
API::Channel.leave_thread(@token, channel.resolve_id)
|
|
684
|
-
nil
|
|
685
|
-
end
|
|
686
|
-
|
|
687
|
-
# Add a member to a thread
|
|
688
|
-
# @param channel [Channel, Integer, String]
|
|
689
|
-
# @param member [Member, Integer, String]
|
|
690
|
-
def add_thread_member(channel, member)
|
|
691
|
-
API::Channel.add_thread_member(@token, channel.resolve_id, member.resolve_id)
|
|
692
|
-
nil
|
|
693
|
-
end
|
|
694
|
-
|
|
695
|
-
# Remove a member from a thread
|
|
696
|
-
# @param channel [Channel, Integer, String]
|
|
697
|
-
# @param member [Member, Integer, String]
|
|
698
|
-
def remove_thread_member(channel, member)
|
|
699
|
-
API::Channel.remove_thread_member(@token, channel.resolve_id, member.resolve_id)
|
|
700
|
-
nil
|
|
701
|
-
end
|
|
702
|
-
|
|
703
|
-
# Sets debug mode. If debug mode is on, many things will be outputted to STDOUT.
|
|
704
|
-
def debug=(new_debug)
|
|
705
|
-
LOGGER.debug = new_debug
|
|
706
|
-
end
|
|
707
|
-
|
|
708
|
-
# Sets the logging mode
|
|
709
|
-
# @see Logger#mode=
|
|
710
|
-
def mode=(new_mode)
|
|
711
|
-
LOGGER.mode = new_mode
|
|
712
|
-
end
|
|
713
|
-
|
|
714
|
-
def runtime_stats
|
|
715
|
-
{
|
|
716
|
-
mode: @mode,
|
|
717
|
-
cache: cache_stats,
|
|
718
|
-
event_executor: @event_executor.class.name,
|
|
719
|
-
event_threads: @event_threads&.count(&:alive?) || 0,
|
|
720
|
-
event_queue_size: @event_executor.respond_to?(:queue_size) ? @event_executor.queue_size : 0
|
|
721
|
-
}
|
|
722
|
-
end
|
|
723
|
-
|
|
724
|
-
# Prevents the READY packet from being printed regardless of debug mode.
|
|
725
|
-
def suppress_ready_debug
|
|
726
|
-
@prevent_ready = true
|
|
727
|
-
end
|
|
728
|
-
|
|
729
|
-
# Add an await the bot should listen to. For information on awaits, see {Await}.
|
|
730
|
-
# @param key [Symbol] The key that uniquely identifies the await for {AwaitEvent}s to listen to (see {#await}).
|
|
731
|
-
# @param type [Class] The event class that should be listened for.
|
|
732
|
-
# @param attributes [Hash] The attributes the event should check for. The block will only be executed if all attributes match.
|
|
733
|
-
# @yield Is executed when the await is triggered.
|
|
734
|
-
# @yieldparam event [Event] The event object that was triggered.
|
|
735
|
-
# @return [Await] The await that was created.
|
|
736
|
-
# @deprecated Will be changed to blocking behavior in v4.0. Use {#add_await!} instead.
|
|
737
|
-
def add_await(key, type, attributes = {}, &block)
|
|
738
|
-
raise "You can't await an AwaitEvent!" if type == OnyxCord::Events::AwaitEvent
|
|
739
|
-
|
|
740
|
-
await = Await.new(self, key, type, attributes, block)
|
|
741
|
-
@awaits ||= {}
|
|
742
|
-
@awaits[key] = await
|
|
743
|
-
end
|
|
744
|
-
|
|
745
|
-
# Awaits an event, blocking the current thread until a response is received.
|
|
746
|
-
# @param type [Class] The event class that should be listened for.
|
|
747
|
-
# @option attributes [Numeric] :timeout the amount of time (in seconds) to wait for a response before returning `nil`. Waits forever if omitted.
|
|
748
|
-
# @yield Executed when a matching event is received.
|
|
749
|
-
# @yieldparam event [Event] The event object that was triggered.
|
|
750
|
-
# @yieldreturn [true, false] Whether the event matches extra await criteria described by the block
|
|
751
|
-
# @return [Event, nil] The event object that was triggered, or `nil` if a `timeout` was set and no event was raised in time.
|
|
752
|
-
# @raise [ArgumentError] if `timeout` is given and is not a positive numeric value
|
|
753
|
-
def add_await!(type, attributes = {})
|
|
754
|
-
raise "You can't await an AwaitEvent!" if type == OnyxCord::Events::AwaitEvent
|
|
755
|
-
|
|
756
|
-
timeout = attributes[:timeout]
|
|
757
|
-
raise ArgumentError, 'Timeout must be a number > 0' if timeout.is_a?(Numeric) && !timeout.positive?
|
|
758
|
-
|
|
759
|
-
mutex = Mutex.new
|
|
760
|
-
cv = ConditionVariable.new
|
|
761
|
-
response = nil
|
|
762
|
-
block = lambda do |event|
|
|
763
|
-
mutex.synchronize do
|
|
764
|
-
response = event
|
|
765
|
-
if block_given?
|
|
766
|
-
result = yield(event)
|
|
767
|
-
cv.signal if result.is_a?(TrueClass)
|
|
768
|
-
else
|
|
769
|
-
cv.signal
|
|
770
|
-
end
|
|
771
|
-
end
|
|
772
|
-
end
|
|
773
|
-
|
|
774
|
-
handler = register_event(type, attributes, block)
|
|
775
|
-
|
|
776
|
-
if timeout
|
|
777
|
-
Thread.new do
|
|
778
|
-
sleep timeout
|
|
779
|
-
mutex.synchronize { cv.signal }
|
|
780
|
-
end
|
|
781
|
-
end
|
|
782
|
-
|
|
783
|
-
mutex.synchronize { cv.wait(mutex) }
|
|
784
|
-
|
|
785
|
-
remove_handler(handler)
|
|
786
|
-
raise 'ConditionVariable was signaled without returning an event!' if response.nil? && timeout.nil?
|
|
787
|
-
|
|
788
|
-
response
|
|
789
|
-
end
|
|
790
|
-
|
|
791
|
-
# Add a user to the list of ignored users. Those users will be ignored in message events at event processing level.
|
|
792
|
-
# @note Ignoring a user only prevents any message events (including mentions, commands etc.) from them! Typing and
|
|
793
|
-
# presence and any other events will still be received.
|
|
794
|
-
# @param user [User, String, Integer] The user, or its ID, to be ignored.
|
|
795
|
-
def ignore_user(user)
|
|
796
|
-
@ignored_ids << user.resolve_id
|
|
797
|
-
end
|
|
798
|
-
|
|
799
|
-
# Remove a user from the ignore list.
|
|
800
|
-
# @param user [User, String, Integer] The user, or its ID, to be unignored.
|
|
801
|
-
def unignore_user(user)
|
|
802
|
-
@ignored_ids.delete(user.resolve_id)
|
|
803
|
-
end
|
|
804
|
-
|
|
805
|
-
# Checks whether a user is being ignored.
|
|
806
|
-
# @param user [User, String, Integer] The user, or its ID, to check.
|
|
807
|
-
# @return [true, false] whether or not the user is ignored.
|
|
808
|
-
def ignored?(user)
|
|
809
|
-
@ignored_ids.include?(user.resolve_id)
|
|
810
|
-
end
|
|
811
|
-
|
|
812
|
-
# @see Logger#debug
|
|
813
|
-
def debug(message)
|
|
814
|
-
LOGGER.debug(message)
|
|
815
|
-
end
|
|
816
|
-
|
|
817
|
-
# @see Logger#log_exception
|
|
818
|
-
def log_exception(e)
|
|
819
|
-
LOGGER.log_exception(e)
|
|
820
|
-
end
|
|
821
|
-
|
|
822
|
-
# Dispatches an event to this bot. Called by the gateway connection handler used internally.
|
|
823
|
-
def dispatch(type, data = nil)
|
|
824
|
-
return dispatch_packet(type) if data.nil? && type.is_a?(Hash)
|
|
825
|
-
|
|
826
|
-
handle_dispatch(type, data)
|
|
827
|
-
end
|
|
828
|
-
|
|
829
|
-
# Raises a heartbeat event. Called by the gateway connection handler used internally.
|
|
830
|
-
def raise_heartbeat_event
|
|
831
|
-
raise_event(HeartbeatEvent.new(self))
|
|
832
|
-
end
|
|
833
|
-
|
|
834
|
-
# Makes the bot leave any groups with no recipients remaining
|
|
835
|
-
def prune_empty_groups
|
|
836
|
-
@channels.each_value do |channel|
|
|
837
|
-
channel.leave_group if channel.group? && channel.recipients.empty?
|
|
838
|
-
end
|
|
839
|
-
end
|
|
840
|
-
|
|
841
|
-
# Get all application commands.
|
|
842
|
-
# @param server_id [String, Integer, nil] The ID of the server to get the commands from. Global if `nil`.
|
|
843
|
-
# @return [Array<ApplicationCommand>]
|
|
844
|
-
def get_application_commands(server_id: nil)
|
|
845
|
-
resp = if server_id
|
|
846
|
-
API::Application.get_guild_commands(@token, profile.id, server_id)
|
|
847
|
-
else
|
|
848
|
-
API::Application.get_global_commands(@token, profile.id)
|
|
849
|
-
end
|
|
850
|
-
|
|
851
|
-
JSON.parse(resp).map do |command_data|
|
|
852
|
-
ApplicationCommand.new(command_data, self, server_id)
|
|
853
|
-
end
|
|
854
|
-
end
|
|
855
|
-
|
|
856
|
-
# Get an application command by ID.
|
|
857
|
-
# @param command_id [String, Integer]
|
|
858
|
-
# @param server_id [String, Integer, nil] The ID of the server to get the command from. Global if `nil`.
|
|
859
|
-
def get_application_command(command_id, server_id: nil)
|
|
860
|
-
resp = if server_id
|
|
861
|
-
API::Application.get_guild_command(@token, profile.id, server_id, command_id)
|
|
862
|
-
else
|
|
863
|
-
API::Application.get_global_command(@token, profile.id, command_id)
|
|
864
|
-
end
|
|
865
|
-
ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
866
|
-
end
|
|
867
|
-
|
|
868
|
-
# @return [OnyxCord::ApplicationCommands::Registry]
|
|
869
|
-
def commands
|
|
870
|
-
@modern_command_registry ||= OnyxCord::ApplicationCommands::Registry.new(self)
|
|
871
|
-
end
|
|
872
|
-
|
|
873
|
-
def slash(name, description: nil, **attributes, &block)
|
|
874
|
-
commands.slash(name, description: description, **attributes, &block)
|
|
875
|
-
end
|
|
876
|
-
|
|
877
|
-
def user_command(name, **attributes, &block)
|
|
878
|
-
commands.user(name, **attributes, &block)
|
|
879
|
-
end
|
|
880
|
-
|
|
881
|
-
def message_command(name, **attributes, &block)
|
|
882
|
-
commands.message(name, **attributes, &block)
|
|
883
|
-
end
|
|
884
|
-
|
|
885
|
-
def sync_application_commands!(server_id: nil, delete_unknown: false)
|
|
886
|
-
commands.sync!(server_id: server_id, delete_unknown: delete_unknown)
|
|
887
|
-
end
|
|
888
|
-
|
|
889
|
-
def bulk_overwrite_global_application_commands(commands)
|
|
890
|
-
response = API::Application.bulk_overwrite_global_commands(@token, profile.id, commands)
|
|
891
|
-
JSON.parse(response).map { |data| ApplicationCommand.new(data, self) }
|
|
892
|
-
end
|
|
893
|
-
|
|
894
|
-
def bulk_overwrite_guild_application_commands(server_id, commands)
|
|
895
|
-
response = API::Application.bulk_overwrite_guild_commands(@token, profile.id, server_id.resolve_id, commands)
|
|
896
|
-
JSON.parse(response).map { |data| ApplicationCommand.new(data, self, server_id) }
|
|
897
|
-
end
|
|
898
|
-
|
|
899
|
-
# @yieldparam [OptionBuilder]
|
|
900
|
-
# @yieldparam [PermissionBuilder]
|
|
901
|
-
# @example
|
|
902
|
-
# bot.register_application_command(:reddit, 'Reddit Commands') do |cmd|
|
|
903
|
-
# cmd.subcommand_group(:subreddit, 'Subreddit Commands') do |group|
|
|
904
|
-
# group.subcommand(:hot, "What's trending") do |sub|
|
|
905
|
-
# sub.string(:subreddit, 'Subreddit to search')
|
|
906
|
-
# end
|
|
907
|
-
# group.subcommand(:new, "What's new") do |sub|
|
|
908
|
-
# sub.string(:since, 'How long ago', choices: ['this hour', 'today', 'this week', 'this month', 'this year', 'all time'])
|
|
909
|
-
# sub.string(:subreddit, 'Subreddit to search')
|
|
910
|
-
# end
|
|
911
|
-
# end
|
|
912
|
-
# end
|
|
913
|
-
def register_application_command(name, description, server_id: nil, default_permission: nil, type: :chat_input, default_member_permissions: nil, contexts: nil, nsfw: false, integration_types: nil)
|
|
914
|
-
type = ApplicationCommand::TYPES[type] || type
|
|
915
|
-
|
|
916
|
-
contexts = contexts&.map { |context| Interaction::CONTEXTS[context] || context }
|
|
917
|
-
integration_types = integration_types&.map { |type| Interaction::INTEGRATION_TYPES[type] || type }
|
|
918
|
-
default_member_permissions = Permissions.bits(default_member_permissions) if default_member_permissions.is_a?(Array)
|
|
919
|
-
|
|
920
|
-
builder = Interactions::OptionBuilder.new
|
|
921
|
-
permission_builder = Interactions::PermissionBuilder.new
|
|
922
|
-
yield(builder, permission_builder) if block_given?
|
|
923
|
-
|
|
924
|
-
resp = if server_id
|
|
925
|
-
API::Application.create_guild_command(@token, profile.id, server_id, name, description, builder.to_a, default_permission, type, default_member_permissions&.to_s, contexts, nsfw)
|
|
926
|
-
else
|
|
927
|
-
API::Application.create_global_command(@token, profile.id, name, description, builder.to_a, default_permission, type, default_member_permissions&.to_s, contexts, nsfw, integration_types)
|
|
928
|
-
end
|
|
929
|
-
cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
930
|
-
|
|
931
|
-
if permission_builder.to_a.any?
|
|
932
|
-
raise ArgumentError, 'Permissions can only be set for guild commands' unless server_id
|
|
933
|
-
|
|
934
|
-
edit_application_command_permissions(cmd.id, server_id, permission_builder.to_a)
|
|
935
|
-
end
|
|
936
|
-
|
|
937
|
-
cmd
|
|
938
|
-
end
|
|
939
|
-
|
|
940
|
-
# @yieldparam [OptionBuilder]
|
|
941
|
-
# @yieldparam [PermissionBuilder]
|
|
942
|
-
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, integration_types: nil)
|
|
943
|
-
type = ApplicationCommand::TYPES[type] || type
|
|
944
|
-
|
|
945
|
-
contexts = contexts&.map { |context| Interaction::CONTEXTS[context] || context }
|
|
946
|
-
integration_types = integration_types&.map { |type| Interaction::INTEGRATION_TYPES[type] || type }
|
|
947
|
-
default_member_permissions = Permissions.bits(default_member_permissions) if default_member_permissions.is_a?(Array)
|
|
948
|
-
|
|
949
|
-
builder = Interactions::OptionBuilder.new
|
|
950
|
-
permission_builder = Interactions::PermissionBuilder.new
|
|
951
|
-
|
|
952
|
-
yield(builder, permission_builder) if block_given?
|
|
953
|
-
|
|
954
|
-
resp = if server_id
|
|
955
|
-
API::Application.edit_guild_command(@token, profile.id, server_id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions&.to_s, contexts, nsfw)
|
|
956
|
-
else
|
|
957
|
-
API::Application.edit_global_command(@token, profile.id, command_id, name, description, builder.to_a, default_permission, type, default_member_permissions&.to_s, contexts, nsfw, integration_types)
|
|
958
|
-
end
|
|
959
|
-
cmd = ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
960
|
-
|
|
961
|
-
if permission_builder.to_a.any?
|
|
962
|
-
raise ArgumentError, 'Permissions can only be set for guild commands' unless server_id
|
|
963
|
-
|
|
964
|
-
edit_application_command_permissions(cmd.id, server_id, permission_builder.to_a)
|
|
965
|
-
end
|
|
966
|
-
|
|
967
|
-
cmd
|
|
968
|
-
end
|
|
969
|
-
|
|
970
|
-
# Remove an application command from the commands registered with discord.
|
|
971
|
-
# @param command_id [String, Integer] The ID of the command to remove.
|
|
972
|
-
# @param server_id [String, Integer] The ID of the server to delete this command from, global if `nil`.
|
|
973
|
-
def delete_application_command(command_id, server_id: nil)
|
|
974
|
-
if server_id
|
|
975
|
-
API::Application.delete_guild_command(@token, profile.id, server_id, command_id)
|
|
976
|
-
else
|
|
977
|
-
API::Application.delete_global_command(@token, profile.id, command_id)
|
|
978
|
-
end
|
|
979
|
-
end
|
|
980
|
-
|
|
981
|
-
# @param command_id [Integer, String]
|
|
982
|
-
# @param server_id [Integer, String]
|
|
983
|
-
# @param permissions [Array<Hash>] An array of objects formatted as `{ id: ENTITY_ID, type: 1 or 2, permission: true or false }`
|
|
984
|
-
# @param bearer_token [String] A valid bearer token that has permission to manage the server and its roles.
|
|
985
|
-
def edit_application_command_permissions(command_id, server_id, permissions = [], bearer_token = nil)
|
|
986
|
-
builder = Interactions::PermissionBuilder.new
|
|
987
|
-
yield builder if block_given?
|
|
988
|
-
|
|
989
|
-
raise ArgumentError, 'This method requires a valid bearer token to be provided' unless bearer_token
|
|
990
|
-
|
|
991
|
-
permissions += builder.to_a
|
|
992
|
-
bearer_token = "Bearer #{bearer_token.delete_prefix('Bearer ')}"
|
|
993
|
-
API::Application.edit_guild_command_permissions(bearer_token, profile.id, server_id, command_id, permissions)
|
|
994
|
-
end
|
|
995
|
-
|
|
996
|
-
# Get the permissions for all of the application commands in a specific server.
|
|
997
|
-
# @param server_id [Integer, String, nil] The ID of the server to fetch application command permissions for.
|
|
998
|
-
# @return [Array<ApplicationCommand::Permission>] The permissions for all of the application commands in the given server.
|
|
999
|
-
def application_command_permissions(server_id:)
|
|
1000
|
-
response = API::Application.get_guild_application_command_permissions(@token, profile.id, server_id.resolve_id)
|
|
1001
|
-
JSON.parse(response).flat_map { |data| data['permissions'].map { |inner| ApplicationCommand::Permission.new(inner, data, self) } }
|
|
1002
|
-
end
|
|
1003
|
-
|
|
1004
|
-
# Fetches all the application emojis that the bot can use.
|
|
1005
|
-
# @return [Array<Emoji>] Returns an array of emoji objects.
|
|
1006
|
-
def application_emojis
|
|
1007
|
-
response = API::Application.list_application_emojis(@token, profile.id)
|
|
1008
|
-
JSON.parse(response)['items'].map { |emoji| Emoji.new(emoji, self) }
|
|
1009
|
-
end
|
|
1010
|
-
|
|
1011
|
-
# Fetches a single application emoji from its ID.
|
|
1012
|
-
# @param emoji_id [Integer, String] ID of the application emoji.
|
|
1013
|
-
# @return [Emoji] The application emoji.
|
|
1014
|
-
def application_emoji(emoji_id)
|
|
1015
|
-
response = API::Application.get_application_emoji(@token, profile.id, emoji_id.resolve_id)
|
|
1016
|
-
Emoji.new(JSON.parse(response), self)
|
|
1017
|
-
end
|
|
1018
|
-
|
|
1019
|
-
# Creates a new custom emoji that can be used by this application.
|
|
1020
|
-
# @param name [String] The name of emoji to create.
|
|
1021
|
-
# @param image [String, #read] Base64 string with the image data, or an object that responds to #read.
|
|
1022
|
-
# @return [Emoji] The emoji that has been created.
|
|
1023
|
-
def create_application_emoji(name:, image:)
|
|
1024
|
-
image = image.respond_to?(:read) ? OnyxCord.encode64(image) : image
|
|
1025
|
-
response = API::Application.create_application_emoji(@token, profile.id, name, image)
|
|
1026
|
-
Emoji.new(JSON.parse(response), self)
|
|
1027
|
-
end
|
|
1028
|
-
|
|
1029
|
-
# Edits an existing application emoji.
|
|
1030
|
-
# @param emoji_id [Integer, String, Emoji] ID of the application emoji to edit.
|
|
1031
|
-
# @param name [String] The new name of the emoji.
|
|
1032
|
-
# @return [Emoji] Returns the updated emoji object on success.
|
|
1033
|
-
def edit_application_emoji(emoji_id, name:)
|
|
1034
|
-
response = API::Application.edit_application_emoji(@token, profile.id, emoji_id.resolve_id, name)
|
|
1035
|
-
Emoji.new(JSON.parse(response), self)
|
|
1036
|
-
end
|
|
1037
|
-
|
|
1038
|
-
# Deletes an existing application emoji.
|
|
1039
|
-
# @param emoji_id [Integer, String, Emoji] ID of the application emoji to delete.
|
|
1040
|
-
def delete_application_emoji(emoji_id)
|
|
1041
|
-
API::Application.delete_application_emoji(@token, profile.id, emoji_id.resolve_id)
|
|
1042
|
-
end
|
|
1043
|
-
|
|
1044
274
|
# @!visibility private
|
|
1045
275
|
def inspect
|
|
1046
276
|
"<Bot client_id=#{@client_id.inspect} redact_token=#{@redact_token.inspect}>"
|
|
1047
277
|
end
|
|
1048
|
-
|
|
1049
|
-
private
|
|
1050
|
-
|
|
1051
|
-
# Throws a useful exception if there's currently no gateway connection.
|
|
1052
|
-
def gateway_check
|
|
1053
|
-
raise "A gateway connection is necessary to call this method! You'll have to do it inside any event (e.g. `ready`) or after `bot.run :async`." unless connected?
|
|
1054
|
-
end
|
|
1055
|
-
|
|
1056
|
-
# Logs a warning if there are servers which are still unavailable.
|
|
1057
|
-
# e.g. due to a Discord outage or because the servers are large and taking a while to load.
|
|
1058
|
-
def unavailable_servers_check
|
|
1059
|
-
# Return unless there are servers that are unavailable.
|
|
1060
|
-
return unless @unavailable_servers&.positive?
|
|
1061
|
-
|
|
1062
|
-
LOGGER.warn("#{@unavailable_servers} servers haven't been cached yet.")
|
|
1063
|
-
LOGGER.warn('Servers may be unavailable due to an outage, or your bot is on very large servers that are taking a while to load.')
|
|
1064
|
-
end
|
|
1065
|
-
|
|
1066
|
-
### ## ## ######## ######## ######## ## ## ### ## ######
|
|
1067
|
-
## ### ## ## ## ## ## ### ## ## ## ## ## ##
|
|
1068
|
-
## #### ## ## ## ## ## #### ## ## ## ## ##
|
|
1069
|
-
## ## ## ## ## ###### ######## ## ## ## ## ## ## ######
|
|
1070
|
-
## ## #### ## ## ## ## ## #### ######### ## ##
|
|
1071
|
-
## ## ### ## ## ## ## ## ### ## ## ## ## ##
|
|
1072
|
-
### ## ## ## ######## ## ## ## ## ## ## ######## ######
|
|
1073
|
-
|
|
1074
|
-
# Internal handler for PRESENCE_UPDATE
|
|
1075
|
-
def update_presence(data)
|
|
1076
|
-
# Friends list presences have no server ID so ignore these to not cause an error
|
|
1077
|
-
return unless data['guild_id']
|
|
1078
|
-
|
|
1079
|
-
user_id = data['user']['id'].to_i
|
|
1080
|
-
server_id = data['guild_id'].to_i
|
|
1081
|
-
server = server(server_id)
|
|
1082
|
-
return unless server
|
|
1083
|
-
|
|
1084
|
-
member_is_new = false
|
|
1085
|
-
|
|
1086
|
-
if server.member_cached?(user_id)
|
|
1087
|
-
member = server.member(user_id)
|
|
1088
|
-
else
|
|
1089
|
-
# If the member is not cached yet, it means that it just came online from not being cached at all
|
|
1090
|
-
# due to large_threshold. Fortunately, Discord sends the entire member object in this case, and
|
|
1091
|
-
# not just a part of it - we can just cache this member directly
|
|
1092
|
-
member = Member.new(data, server, self)
|
|
1093
|
-
debug("Implicitly adding presence-obtained member #{user_id} to #{server_id} cache")
|
|
1094
|
-
|
|
1095
|
-
member_is_new = true
|
|
1096
|
-
end
|
|
1097
|
-
|
|
1098
|
-
username = data['user']['username']
|
|
1099
|
-
if username && !member_is_new # Don't set the username for newly-cached members
|
|
1100
|
-
debug "Implicitly updating presence-obtained information username for member #{user_id}"
|
|
1101
|
-
member.update_username(username)
|
|
1102
|
-
end
|
|
1103
|
-
|
|
1104
|
-
global_name = data['user']['global_name']
|
|
1105
|
-
if global_name && !member_is_new # Don't set the global_name for newly-cached members
|
|
1106
|
-
debug "Implicitly updating presence-obtained information global_name for member #{user_id}"
|
|
1107
|
-
member.update_global_name(global_name)
|
|
1108
|
-
end
|
|
1109
|
-
|
|
1110
|
-
member.update_presence(data)
|
|
1111
|
-
|
|
1112
|
-
member.avatar_id = data['user']['avatar'] if data['user']['avatar']
|
|
1113
|
-
|
|
1114
|
-
server.cache_member(member)
|
|
1115
|
-
end
|
|
1116
|
-
|
|
1117
|
-
# Internal handler for VOICE_STATE_UPDATE
|
|
1118
|
-
def update_voice_state(data)
|
|
1119
|
-
@session_id = data['session_id']
|
|
1120
|
-
|
|
1121
|
-
server_id = data['guild_id'].to_i
|
|
1122
|
-
server = @servers&.[](server_id)
|
|
1123
|
-
return unless server
|
|
1124
|
-
|
|
1125
|
-
user_id = data['user_id'].to_i
|
|
1126
|
-
old_voice_state = server.voice_states[user_id]
|
|
1127
|
-
old_channel_id = old_voice_state&.channel_id || old_voice_state&.voice_channel&.id
|
|
1128
|
-
|
|
1129
|
-
server.update_voice_state(data)
|
|
1130
|
-
|
|
1131
|
-
existing_voice = @voices[server_id]
|
|
1132
|
-
if user_id == @profile.id && existing_voice
|
|
1133
|
-
new_channel_id = data['channel_id']
|
|
1134
|
-
if new_channel_id
|
|
1135
|
-
channel_id = new_channel_id.to_i
|
|
1136
|
-
new_channel = @channels&.[](channel_id) || server.channels.find { |channel| channel.id == channel_id }
|
|
1137
|
-
existing_voice.channel = new_channel
|
|
1138
|
-
else
|
|
1139
|
-
voice_destroy(server_id)
|
|
1140
|
-
end
|
|
1141
|
-
end
|
|
1142
|
-
|
|
1143
|
-
old_channel_id
|
|
1144
|
-
end
|
|
1145
|
-
|
|
1146
|
-
# Internal handler for VOICE_SERVER_UPDATE
|
|
1147
|
-
def update_voice_server(data)
|
|
1148
|
-
server_id = data['guild_id'].to_i
|
|
1149
|
-
channel = @should_connect_to_voice[server_id]
|
|
1150
|
-
|
|
1151
|
-
debug("Voice server update received! chan: #{channel.inspect}")
|
|
1152
|
-
return unless channel
|
|
1153
|
-
|
|
1154
|
-
@should_connect_to_voice.delete(server_id)
|
|
1155
|
-
debug('Updating voice server!')
|
|
1156
|
-
|
|
1157
|
-
token = data['token']
|
|
1158
|
-
endpoint = data['endpoint']
|
|
1159
|
-
|
|
1160
|
-
unless endpoint
|
|
1161
|
-
debug('VOICE_SERVER_UPDATE sent with nil endpoint! Ignoring')
|
|
1162
|
-
return
|
|
1163
|
-
end
|
|
1164
|
-
|
|
1165
|
-
debug('Got data, now creating the bot.')
|
|
1166
|
-
@voices[server_id] = OnyxCord::Voice::VoiceBot.new(channel, self, token, @session_id, endpoint)
|
|
1167
|
-
end
|
|
1168
|
-
|
|
1169
|
-
# Internal handler for CHANNEL_CREATE
|
|
1170
|
-
def create_channel(data)
|
|
1171
|
-
channel = data.is_a?(OnyxCord::Channel) ? data : Channel.new(data, self)
|
|
1172
|
-
server = channel.server
|
|
1173
|
-
|
|
1174
|
-
# The last message ID of a forum channel is the most recent post
|
|
1175
|
-
channel.parent.process_last_message_id(channel.id) if channel.parent&.forum? || channel.parent&.media?
|
|
1176
|
-
|
|
1177
|
-
# Handle normal and private channels separately
|
|
1178
|
-
if server
|
|
1179
|
-
server.add_channel(channel)
|
|
1180
|
-
@channels[channel.id] = channel if @channels
|
|
1181
|
-
elsif channel.private?
|
|
1182
|
-
@pm_channels[channel.recipient.id] = channel if @pm_channels
|
|
1183
|
-
elsif channel.group?
|
|
1184
|
-
@channels[channel.id] = channel if @channels
|
|
1185
|
-
end
|
|
1186
|
-
end
|
|
1187
|
-
|
|
1188
|
-
# Internal handler for CHANNEL_UPDATE
|
|
1189
|
-
def update_channel(data)
|
|
1190
|
-
@channels&.[](data['id'].to_i)&.update_data(data)
|
|
1191
|
-
end
|
|
1192
|
-
|
|
1193
|
-
# Internal handler for CHANNEL_DELETE
|
|
1194
|
-
def delete_channel(data)
|
|
1195
|
-
channel = Channel.new(data, self)
|
|
1196
|
-
server = channel.server
|
|
1197
|
-
|
|
1198
|
-
# Handle normal and private channels separately
|
|
1199
|
-
if server
|
|
1200
|
-
@channels&.delete(channel.id)
|
|
1201
|
-
server.delete_channel(channel.id)
|
|
1202
|
-
elsif channel.pm?
|
|
1203
|
-
@pm_channels&.delete(channel.recipient.id)
|
|
1204
|
-
elsif channel.group?
|
|
1205
|
-
@channels&.delete(channel.id)
|
|
1206
|
-
end
|
|
1207
|
-
|
|
1208
|
-
@thread_members&.delete(channel.id) if channel.thread?
|
|
1209
|
-
end
|
|
1210
|
-
|
|
1211
|
-
# Internal handler for GUILD_MEMBER_ADD
|
|
1212
|
-
def add_guild_member(data)
|
|
1213
|
-
server_id = data['guild_id'].to_i
|
|
1214
|
-
server = self.server(server_id)
|
|
1215
|
-
|
|
1216
|
-
member = Member.new(data, server, self)
|
|
1217
|
-
server.add_member(member)
|
|
1218
|
-
end
|
|
1219
|
-
|
|
1220
|
-
# Internal handler for GUILD_MEMBER_UPDATE
|
|
1221
|
-
def update_guild_member(data)
|
|
1222
|
-
server_id = data['guild_id'].to_i
|
|
1223
|
-
server = self.server(server_id)
|
|
1224
|
-
|
|
1225
|
-
# Only attempt to update members that're already cached
|
|
1226
|
-
if (member = server.member(data['user']['id'].to_i, false))
|
|
1227
|
-
member.update_data(data)
|
|
1228
|
-
else
|
|
1229
|
-
ensure_user(data['user'])
|
|
1230
|
-
end
|
|
1231
|
-
end
|
|
1232
|
-
|
|
1233
|
-
# Internal handler for GUILD_MEMBER_DELETE
|
|
1234
|
-
def delete_guild_member(data)
|
|
1235
|
-
server_id = data['guild_id'].to_i
|
|
1236
|
-
server = self.server(server_id)
|
|
1237
|
-
return unless server
|
|
1238
|
-
|
|
1239
|
-
user_id = data['user']['id'].to_i
|
|
1240
|
-
server.delete_member(user_id)
|
|
1241
|
-
rescue OnyxCord::Errors::NoPermission
|
|
1242
|
-
OnyxCord::LOGGER.warn("delete_guild_member attempted to access a server for which the bot doesn't have permission! Not sure what happened here, ignoring")
|
|
1243
|
-
end
|
|
1244
|
-
|
|
1245
|
-
# Internal handler for GUILD_CREATE
|
|
1246
|
-
def create_guild(data)
|
|
1247
|
-
ensure_server(data, true)
|
|
1248
|
-
end
|
|
1249
|
-
|
|
1250
|
-
# Internal handler for GUILD_UPDATE
|
|
1251
|
-
def update_guild(data)
|
|
1252
|
-
server_id = data['id'].to_i
|
|
1253
|
-
server = @servers&.[](server_id)
|
|
1254
|
-
|
|
1255
|
-
if server
|
|
1256
|
-
server.update_data(data)
|
|
1257
|
-
else
|
|
1258
|
-
LOGGER.warn("GUILD_UPDATE received for uncached server #{server_id}; caching from payload")
|
|
1259
|
-
ensure_server(data, true)
|
|
1260
|
-
end
|
|
1261
|
-
end
|
|
1262
|
-
|
|
1263
|
-
# Internal handler for GUILD_DELETE
|
|
1264
|
-
def delete_guild(data)
|
|
1265
|
-
id = data['id'].to_i
|
|
1266
|
-
@servers.delete(id)
|
|
1267
|
-
end
|
|
1268
|
-
|
|
1269
|
-
# Internal handler for GUILD_ROLE_CREATE and GUILD_ROLE_UPDATE
|
|
1270
|
-
def update_guild_role(data)
|
|
1271
|
-
server = @servers[data['guild_id'].to_i]
|
|
1272
|
-
|
|
1273
|
-
if (role = server&.role(data['role']['id'].to_i))
|
|
1274
|
-
role.update_data(data['role'])
|
|
1275
|
-
else
|
|
1276
|
-
server&.add_role(Role.new(data['role'], self, server))
|
|
1277
|
-
end
|
|
1278
|
-
end
|
|
1279
|
-
|
|
1280
|
-
# Internal handler for GUILD_ROLE_DELETE
|
|
1281
|
-
def delete_guild_role(data)
|
|
1282
|
-
role_id = data['role_id'].to_i
|
|
1283
|
-
server_id = data['guild_id'].to_i
|
|
1284
|
-
server = @servers[server_id]
|
|
1285
|
-
server&.delete_role(role_id)
|
|
1286
|
-
end
|
|
1287
|
-
|
|
1288
|
-
# Internal handler for GUILD_EMOJIS_UPDATE
|
|
1289
|
-
def update_guild_emoji(data)
|
|
1290
|
-
server_id = data['guild_id'].to_i
|
|
1291
|
-
server = @servers[server_id]
|
|
1292
|
-
server&.update_emoji_data(data)
|
|
1293
|
-
end
|
|
1294
|
-
|
|
1295
|
-
# Internal handler for GUILD_SCHEDULED_EVENT_CREATE and GUILD_SCHEDULED_EVENT_UPDATE
|
|
1296
|
-
def update_guild_scheduled_event(data)
|
|
1297
|
-
server = @servers[data['guild_id'].to_i]
|
|
1298
|
-
|
|
1299
|
-
if (event = server&.scheduled_event(data['id'].to_i, request: false))
|
|
1300
|
-
event&.update_data(data)
|
|
1301
|
-
else
|
|
1302
|
-
server&.cache_scheduled_event(ScheduledEvent.new(data, server, self))
|
|
1303
|
-
end
|
|
1304
|
-
end
|
|
1305
|
-
|
|
1306
|
-
# Internal handler for MESSAGE_CREATE
|
|
1307
|
-
def create_message(data); end
|
|
1308
|
-
|
|
1309
|
-
# Internal handler for TYPING_START
|
|
1310
|
-
def start_typing(data); end
|
|
1311
|
-
|
|
1312
|
-
# Internal handler for MESSAGE_UPDATE
|
|
1313
|
-
def update_message(data); end
|
|
1314
|
-
|
|
1315
|
-
# Internal handler for MESSAGE_DELETE
|
|
1316
|
-
def delete_message(data); end
|
|
1317
|
-
|
|
1318
|
-
# Internal handler for MESSAGE_REACTION_ADD
|
|
1319
|
-
def add_message_reaction(data); end
|
|
1320
|
-
|
|
1321
|
-
# Internal handler for MESSAGE_REACTION_REMOVE
|
|
1322
|
-
def remove_message_reaction(data); end
|
|
1323
|
-
|
|
1324
|
-
# Internal handler for MESSAGE_REACTION_REMOVE_ALL
|
|
1325
|
-
def remove_all_message_reactions(data); end
|
|
1326
|
-
|
|
1327
|
-
# Internal handler for GUILD_BAN_ADD
|
|
1328
|
-
def add_user_ban(data); end
|
|
1329
|
-
|
|
1330
|
-
# Internal handler for GUILD_BAN_REMOVE
|
|
1331
|
-
def remove_user_ban(data); end
|
|
1332
|
-
|
|
1333
|
-
## ####### ###### #### ## ##
|
|
1334
|
-
## ## ## ## ## ## ### ##
|
|
1335
|
-
## ## ## ## ## #### ##
|
|
1336
|
-
## ## ## ## #### ## ## ## ##
|
|
1337
|
-
## ## ## ## ## ## ## ####
|
|
1338
|
-
## ## ## ## ## ## ## ###
|
|
1339
|
-
######## ####### ###### #### ## ##
|
|
1340
|
-
|
|
1341
|
-
def process_token(type, token)
|
|
1342
|
-
# Remove the "Bot " prefix if it exists
|
|
1343
|
-
token = token[4..] if token.start_with? 'Bot '
|
|
1344
|
-
|
|
1345
|
-
token = "Bot #{token}" unless type == :user
|
|
1346
|
-
token
|
|
1347
|
-
end
|
|
1348
|
-
|
|
1349
|
-
def handle_dispatch(type, data)
|
|
1350
|
-
# Check whether there are still unavailable servers and there have been more than 10 seconds since READY
|
|
1351
|
-
if @unavailable_servers&.positive? && (Time.now - @unavailable_timeout_time) > 10 && !(@intents || 0).nobits?(INTENTS[:servers])
|
|
1352
|
-
# The server streaming timed out!
|
|
1353
|
-
LOGGER.debug("Server streaming timed out with #{@unavailable_servers} servers remaining")
|
|
1354
|
-
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.')
|
|
1355
|
-
|
|
1356
|
-
# Unset the unavailable server count so this doesn't get triggered again
|
|
1357
|
-
@unavailable_servers = 0
|
|
1358
|
-
|
|
1359
|
-
notify_ready
|
|
1360
|
-
end
|
|
1361
|
-
|
|
1362
|
-
case type
|
|
1363
|
-
when :READY
|
|
1364
|
-
# As READY may be called multiple times over a single process lifetime, we here need to reset the cache entirely
|
|
1365
|
-
# to prevent possible inconsistencies, like objects referencing old versions of other objects which have been
|
|
1366
|
-
# replaced.
|
|
1367
|
-
init_cache
|
|
1368
|
-
|
|
1369
|
-
@profile = Profile.new(data['user'], self)
|
|
1370
|
-
|
|
1371
|
-
@client_id ||= data['application']['id']&.to_i
|
|
1372
|
-
|
|
1373
|
-
# Initialize servers
|
|
1374
|
-
@servers = {}
|
|
1375
|
-
|
|
1376
|
-
# Count unavailable servers
|
|
1377
|
-
@unavailable_servers = 0
|
|
1378
|
-
|
|
1379
|
-
data['guilds'].each do |element|
|
|
1380
|
-
# Check for true specifically because unavailable=false indicates that a previously unavailable server has
|
|
1381
|
-
# come online
|
|
1382
|
-
if element['unavailable']
|
|
1383
|
-
@unavailable_servers += 1
|
|
1384
|
-
|
|
1385
|
-
# Ignore any unavailable servers
|
|
1386
|
-
next
|
|
1387
|
-
end
|
|
1388
|
-
|
|
1389
|
-
ensure_server(element, true)
|
|
1390
|
-
end
|
|
1391
|
-
|
|
1392
|
-
# Don't notify yet if there are unavailable servers because they need to get available before the bot truly has
|
|
1393
|
-
# all the data
|
|
1394
|
-
if @unavailable_servers.zero?
|
|
1395
|
-
# No unavailable servers - we're ready!
|
|
1396
|
-
notify_ready
|
|
1397
|
-
end
|
|
1398
|
-
|
|
1399
|
-
@ready_time = Time.now
|
|
1400
|
-
@unavailable_timeout_time = Time.now
|
|
1401
|
-
when :GUILD_MEMBERS_CHUNK
|
|
1402
|
-
id = data['guild_id'].to_i
|
|
1403
|
-
server = server(id)
|
|
1404
|
-
server.process_chunk(data['members'], data['chunk_index'], data['chunk_count'])
|
|
1405
|
-
when :USER_UPDATE
|
|
1406
|
-
@profile = Profile.new(data, self)
|
|
1407
|
-
when :INVITE_CREATE
|
|
1408
|
-
invite = Invite.new(data, self)
|
|
1409
|
-
raise_event(InviteCreateEvent.new(data, invite, self))
|
|
1410
|
-
when :INVITE_DELETE
|
|
1411
|
-
raise_event(InviteDeleteEvent.new(data, self))
|
|
1412
|
-
when :MESSAGE_CREATE
|
|
1413
|
-
if ignored?(data['author']['id'])
|
|
1414
|
-
debug("Ignored author with ID #{data['author']['id']}")
|
|
1415
|
-
return
|
|
1416
|
-
end
|
|
1417
|
-
|
|
1418
|
-
if @ignore_bots && data['author']['bot']
|
|
1419
|
-
debug("Ignored Bot account with ID #{data['author']['id']}")
|
|
1420
|
-
return
|
|
1421
|
-
end
|
|
1422
|
-
|
|
1423
|
-
if !should_parse_self && profile.id == data['author']['id'].to_i
|
|
1424
|
-
debug('Ignored message from the current bot')
|
|
1425
|
-
return
|
|
1426
|
-
end
|
|
1427
|
-
|
|
1428
|
-
# If create_message is overwritten with a method that returns the parsed message, use that instead, so we don't
|
|
1429
|
-
# parse the message twice (which is just thrown away performance)
|
|
1430
|
-
message = create_message(data)
|
|
1431
|
-
message = Message.new(data, self) unless message.is_a? Message
|
|
1432
|
-
|
|
1433
|
-
# Update the existing member if it exists in the cache.
|
|
1434
|
-
if data['member']
|
|
1435
|
-
member = message.channel.server&.member(data['author']['id'].to_i, false)
|
|
1436
|
-
data['member']['user'] = data['author']
|
|
1437
|
-
member&.update_data(data['member'])
|
|
1438
|
-
end
|
|
1439
|
-
|
|
1440
|
-
# Dispatch a ChannelCreateEvent for channels we don't have cached
|
|
1441
|
-
if message.channel.private? && !@pm_channels&.key?(message.channel.recipient.id)
|
|
1442
|
-
create_channel(message.channel)
|
|
1443
|
-
|
|
1444
|
-
raise_event(ChannelCreateEvent.new(message.channel, self))
|
|
1445
|
-
end
|
|
1446
|
-
|
|
1447
|
-
message.channel.process_last_message_id(message.id)
|
|
1448
|
-
|
|
1449
|
-
event = MessageEvent.new(message, self)
|
|
1450
|
-
raise_event(event)
|
|
1451
|
-
|
|
1452
|
-
# Raise a mention event for any direct mentions.
|
|
1453
|
-
if message.mentions.any? { |user| user.id == profile.id }
|
|
1454
|
-
event = MentionEvent.new(message, self, false)
|
|
1455
|
-
raise_event(event)
|
|
1456
|
-
end
|
|
1457
|
-
|
|
1458
|
-
# Raise a mention event for the current bot's auto-generated role.
|
|
1459
|
-
if message.role_mentions.any? { |role| role.tags&.bot_id == profile.id }
|
|
1460
|
-
event = MentionEvent.new(message, self, true)
|
|
1461
|
-
raise_event(event)
|
|
1462
|
-
end
|
|
1463
|
-
|
|
1464
|
-
if message.channel.private?
|
|
1465
|
-
event = PrivateMessageEvent.new(message, self)
|
|
1466
|
-
raise_event(event)
|
|
1467
|
-
end
|
|
1468
|
-
when :MESSAGE_UPDATE
|
|
1469
|
-
update_message(data)
|
|
1470
|
-
|
|
1471
|
-
if !should_parse_self && profile.id == data['author']['id'].to_i
|
|
1472
|
-
debug('Ignored message from the current bot')
|
|
1473
|
-
return
|
|
1474
|
-
end
|
|
1475
|
-
|
|
1476
|
-
message = Message.new(data, self)
|
|
1477
|
-
|
|
1478
|
-
event = MessageUpdateEvent.new(message, self)
|
|
1479
|
-
raise_event(event)
|
|
1480
|
-
|
|
1481
|
-
if data['author'].nil?
|
|
1482
|
-
LOGGER.debug("Edited a message with nil author! Content: #{message.content.inspect}, channel: #{message.channel.inspect}")
|
|
1483
|
-
return
|
|
1484
|
-
end
|
|
1485
|
-
|
|
1486
|
-
# Update the existing member if it exists in the cache.
|
|
1487
|
-
if data['member']
|
|
1488
|
-
member = message.channel.server&.member(data['author']['id'].to_i, false)
|
|
1489
|
-
data['member']['user'] = data['author']
|
|
1490
|
-
member&.update_data(data['member'])
|
|
1491
|
-
end
|
|
1492
|
-
|
|
1493
|
-
event = MessageEditEvent.new(message, self)
|
|
1494
|
-
raise_event(event)
|
|
1495
|
-
when :MESSAGE_DELETE
|
|
1496
|
-
delete_message(data)
|
|
1497
|
-
|
|
1498
|
-
event = MessageDeleteEvent.new(data, self)
|
|
1499
|
-
raise_event(event)
|
|
1500
|
-
when :MESSAGE_DELETE_BULK
|
|
1501
|
-
debug("MESSAGE_DELETE_BULK will raise #{data['ids'].length} events")
|
|
1502
|
-
|
|
1503
|
-
data['ids'].each do |single_id|
|
|
1504
|
-
# Form a data hash for a single ID so the methods get what they want
|
|
1505
|
-
single_data = {
|
|
1506
|
-
'id' => single_id,
|
|
1507
|
-
'channel_id' => data['channel_id']
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
# Raise as normal
|
|
1511
|
-
delete_message(single_data)
|
|
1512
|
-
|
|
1513
|
-
event = MessageDeleteEvent.new(single_data, self)
|
|
1514
|
-
raise_event(event)
|
|
1515
|
-
end
|
|
1516
|
-
when :TYPING_START
|
|
1517
|
-
start_typing(data)
|
|
1518
|
-
|
|
1519
|
-
begin
|
|
1520
|
-
event = TypingEvent.new(data, self)
|
|
1521
|
-
raise_event(event)
|
|
1522
|
-
rescue OnyxCord::Errors::NoPermission
|
|
1523
|
-
debug 'Typing started in channel the bot has no access to, ignoring'
|
|
1524
|
-
end
|
|
1525
|
-
when :MESSAGE_REACTION_ADD
|
|
1526
|
-
add_message_reaction(data)
|
|
1527
|
-
|
|
1528
|
-
return if profile.id == data['user_id'].to_i && !should_parse_self
|
|
1529
|
-
|
|
1530
|
-
if data['member']
|
|
1531
|
-
server = self.server(data['guild_id'].to_i)
|
|
1532
|
-
|
|
1533
|
-
server&.cache_member(Member.new(data['member'], server, self))
|
|
1534
|
-
end
|
|
1535
|
-
|
|
1536
|
-
event = ReactionAddEvent.new(data, self)
|
|
1537
|
-
raise_event(event)
|
|
1538
|
-
when :MESSAGE_REACTION_REMOVE
|
|
1539
|
-
remove_message_reaction(data)
|
|
1540
|
-
|
|
1541
|
-
return if profile.id == data['user_id'].to_i && !should_parse_self
|
|
1542
|
-
|
|
1543
|
-
event = ReactionRemoveEvent.new(data, self)
|
|
1544
|
-
raise_event(event)
|
|
1545
|
-
when :MESSAGE_REACTION_REMOVE_ALL
|
|
1546
|
-
remove_all_message_reactions(data)
|
|
1547
|
-
|
|
1548
|
-
event = ReactionRemoveAllEvent.new(data, self)
|
|
1549
|
-
raise_event(event)
|
|
1550
|
-
when :MESSAGE_REACTION_REMOVE_EMOJI
|
|
1551
|
-
|
|
1552
|
-
event = ReactionRemoveEmojiEvent.new(data, self)
|
|
1553
|
-
raise_event(event)
|
|
1554
|
-
when :PRESENCE_UPDATE
|
|
1555
|
-
# Ignore friends list presences
|
|
1556
|
-
return unless data['guild_id']
|
|
1557
|
-
|
|
1558
|
-
new_activities = (data['activities'] || []).map { |act_data| Activity.new(act_data, self) }
|
|
1559
|
-
presence_user = @users[data['user']['id'].to_i]
|
|
1560
|
-
old_activities = (presence_user&.activities || [])
|
|
1561
|
-
update_presence(data)
|
|
1562
|
-
|
|
1563
|
-
# Starting a new game
|
|
1564
|
-
playing_change = new_activities.reject do |act|
|
|
1565
|
-
old_activities.find { |old| old.name == act.name }
|
|
1566
|
-
end
|
|
1567
|
-
|
|
1568
|
-
# Exiting an existing game
|
|
1569
|
-
playing_change += old_activities.reject do |old|
|
|
1570
|
-
new_activities.find { |act| act.name == old.name }
|
|
1571
|
-
end
|
|
1572
|
-
|
|
1573
|
-
if playing_change.any?
|
|
1574
|
-
playing_change.each do |act|
|
|
1575
|
-
raise_event(PlayingEvent.new(data, act, self))
|
|
1576
|
-
end
|
|
1577
|
-
else
|
|
1578
|
-
raise_event(PresenceEvent.new(data, self))
|
|
1579
|
-
end
|
|
1580
|
-
when :VOICE_STATE_UPDATE
|
|
1581
|
-
old_channel_id = update_voice_state(data)
|
|
1582
|
-
|
|
1583
|
-
event = VoiceStateUpdateEvent.new(data, old_channel_id, self)
|
|
1584
|
-
raise_event(event)
|
|
1585
|
-
when :VOICE_SERVER_UPDATE
|
|
1586
|
-
update_voice_server(data)
|
|
1587
|
-
|
|
1588
|
-
event = VoiceServerUpdateEvent.new(data, self)
|
|
1589
|
-
raise_event(event)
|
|
1590
|
-
when :CHANNEL_CREATE
|
|
1591
|
-
create_channel(data)
|
|
1592
|
-
|
|
1593
|
-
event = ChannelCreateEvent.new(data, self)
|
|
1594
|
-
raise_event(event)
|
|
1595
|
-
when :CHANNEL_UPDATE
|
|
1596
|
-
update_channel(data)
|
|
1597
|
-
|
|
1598
|
-
event = ChannelUpdateEvent.new(data, self)
|
|
1599
|
-
raise_event(event)
|
|
1600
|
-
when :CHANNEL_DELETE
|
|
1601
|
-
delete_channel(data)
|
|
1602
|
-
|
|
1603
|
-
event = ChannelDeleteEvent.new(data, self)
|
|
1604
|
-
raise_event(event)
|
|
1605
|
-
when :CHANNEL_PINS_UPDATE
|
|
1606
|
-
event = ChannelPinsUpdateEvent.new(data, self)
|
|
1607
|
-
|
|
1608
|
-
event.channel.process_last_pin_timestamp(data['last_pin_timestamp']) if data.key?('last_pin_timestamp')
|
|
1609
|
-
|
|
1610
|
-
raise_event(event)
|
|
1611
|
-
when :GUILD_MEMBER_ADD
|
|
1612
|
-
add_guild_member(data)
|
|
1613
|
-
|
|
1614
|
-
event = ServerMemberAddEvent.new(data, self)
|
|
1615
|
-
raise_event(event)
|
|
1616
|
-
when :GUILD_MEMBER_UPDATE
|
|
1617
|
-
update_guild_member(data)
|
|
1618
|
-
|
|
1619
|
-
event = ServerMemberUpdateEvent.new(data, self)
|
|
1620
|
-
raise_event(event)
|
|
1621
|
-
when :GUILD_MEMBER_REMOVE
|
|
1622
|
-
delete_guild_member(data)
|
|
1623
|
-
|
|
1624
|
-
event = ServerMemberDeleteEvent.new(data, self)
|
|
1625
|
-
raise_event(event)
|
|
1626
|
-
when :GUILD_AUDIT_LOG_ENTRY_CREATE
|
|
1627
|
-
event = AuditLogEntryCreateEvent.new(data, self)
|
|
1628
|
-
raise_event(event)
|
|
1629
|
-
when :GUILD_BAN_ADD
|
|
1630
|
-
add_user_ban(data)
|
|
1631
|
-
|
|
1632
|
-
event = UserBanEvent.new(data, self)
|
|
1633
|
-
raise_event(event)
|
|
1634
|
-
when :GUILD_BAN_REMOVE
|
|
1635
|
-
remove_user_ban(data)
|
|
1636
|
-
|
|
1637
|
-
event = UserUnbanEvent.new(data, self)
|
|
1638
|
-
raise_event(event)
|
|
1639
|
-
when :GUILD_ROLE_UPDATE
|
|
1640
|
-
update_guild_role(data)
|
|
1641
|
-
|
|
1642
|
-
event = ServerRoleUpdateEvent.new(data, self)
|
|
1643
|
-
raise_event(event)
|
|
1644
|
-
when :GUILD_ROLE_CREATE
|
|
1645
|
-
update_guild_role(data)
|
|
1646
|
-
|
|
1647
|
-
event = ServerRoleCreateEvent.new(data, self)
|
|
1648
|
-
raise_event(event)
|
|
1649
|
-
when :GUILD_ROLE_DELETE
|
|
1650
|
-
delete_guild_role(data)
|
|
1651
|
-
|
|
1652
|
-
event = ServerRoleDeleteEvent.new(data, self)
|
|
1653
|
-
raise_event(event)
|
|
1654
|
-
when :INTEGRATION_CREATE
|
|
1655
|
-
event = IntegrationCreateEvent.new(data, self)
|
|
1656
|
-
raise_event(event)
|
|
1657
|
-
when :INTEGRATION_UPDATE
|
|
1658
|
-
event = IntegrationUpdateEvent.new(data, self)
|
|
1659
|
-
raise_event(event)
|
|
1660
|
-
when :INTEGRATION_DELETE
|
|
1661
|
-
event = IntegrationDeleteEvent.new(data, self)
|
|
1662
|
-
raise_event(event)
|
|
1663
|
-
when :GUILD_CREATE
|
|
1664
|
-
create_guild(data)
|
|
1665
|
-
|
|
1666
|
-
# Check for false specifically (no data means the server has never been unavailable)
|
|
1667
|
-
if data['unavailable'].is_a? FalseClass
|
|
1668
|
-
@unavailable_servers -= 1 if @unavailable_servers
|
|
1669
|
-
@unavailable_timeout_time = Time.now
|
|
1670
|
-
|
|
1671
|
-
notify_ready if @unavailable_servers.zero?
|
|
1672
|
-
|
|
1673
|
-
# Return here so the event doesn't get triggered
|
|
1674
|
-
return
|
|
1675
|
-
end
|
|
1676
|
-
|
|
1677
|
-
event = ServerCreateEvent.new(data, self)
|
|
1678
|
-
raise_event(event)
|
|
1679
|
-
when :GUILD_UPDATE
|
|
1680
|
-
update_guild(data)
|
|
1681
|
-
|
|
1682
|
-
event = ServerUpdateEvent.new(data, self)
|
|
1683
|
-
raise_event(event)
|
|
1684
|
-
when :GUILD_DELETE
|
|
1685
|
-
delete_guild(data)
|
|
1686
|
-
|
|
1687
|
-
if data['unavailable'].is_a? TrueClass
|
|
1688
|
-
LOGGER.warn("Server #{data['id']} is unavailable due to an outage!")
|
|
1689
|
-
return # Don't raise an event
|
|
1690
|
-
end
|
|
1691
|
-
|
|
1692
|
-
event = ServerDeleteEvent.new(data, self)
|
|
1693
|
-
raise_event(event)
|
|
1694
|
-
when :GUILD_EMOJIS_UPDATE
|
|
1695
|
-
server_id = data['guild_id'].to_i
|
|
1696
|
-
server = @servers[server_id]
|
|
1697
|
-
old_emoji_data = server.emoji.clone
|
|
1698
|
-
update_guild_emoji(data)
|
|
1699
|
-
new_emoji_data = server.emoji
|
|
1700
|
-
|
|
1701
|
-
created_ids = new_emoji_data.keys - old_emoji_data.keys
|
|
1702
|
-
deleted_ids = old_emoji_data.keys - new_emoji_data.keys
|
|
1703
|
-
updated_ids = old_emoji_data.select do |k, v|
|
|
1704
|
-
new_emoji_data[k] && (v.name != new_emoji_data[k].name || v.roles != new_emoji_data[k].roles)
|
|
1705
|
-
end.keys
|
|
1706
|
-
|
|
1707
|
-
event = ServerEmojiChangeEvent.new(server, data, self)
|
|
1708
|
-
raise_event(event)
|
|
1709
|
-
|
|
1710
|
-
created_ids.each do |e|
|
|
1711
|
-
event = ServerEmojiCreateEvent.new(server, new_emoji_data[e], self)
|
|
1712
|
-
raise_event(event)
|
|
1713
|
-
end
|
|
1714
|
-
|
|
1715
|
-
deleted_ids.each do |e|
|
|
1716
|
-
event = ServerEmojiDeleteEvent.new(server, old_emoji_data[e], self)
|
|
1717
|
-
raise_event(event)
|
|
1718
|
-
end
|
|
1719
|
-
|
|
1720
|
-
updated_ids.each do |e|
|
|
1721
|
-
event = ServerEmojiUpdateEvent.new(server, old_emoji_data[e], new_emoji_data[e], self)
|
|
1722
|
-
raise_event(event)
|
|
1723
|
-
end
|
|
1724
|
-
when :APPLICATION_COMMAND_PERMISSIONS_UPDATE
|
|
1725
|
-
event = ApplicationCommandPermissionsUpdateEvent.new(data, self)
|
|
1726
|
-
|
|
1727
|
-
raise_event(event)
|
|
1728
|
-
when :INTERACTION_CREATE
|
|
1729
|
-
event = InteractionCreateEvent.new(data, self)
|
|
1730
|
-
raise_event(event)
|
|
1731
|
-
|
|
1732
|
-
case data['type']
|
|
1733
|
-
when Interaction::TYPES[:command]
|
|
1734
|
-
event = ApplicationCommandEvent.new(data, self)
|
|
1735
|
-
|
|
1736
|
-
@event_executor.post do
|
|
1737
|
-
Thread.current[:onyxcord_name] = next_event_thread_name('it')
|
|
1738
|
-
handler = @application_commands[event.command_name]
|
|
1739
|
-
handler&.call(event)
|
|
1740
|
-
rescue StandardError => e
|
|
1741
|
-
log_exception(e)
|
|
1742
|
-
end
|
|
1743
|
-
when Interaction::TYPES[:component]
|
|
1744
|
-
case data['data']['component_type']
|
|
1745
|
-
when Webhooks::View::COMPONENT_TYPES[:button]
|
|
1746
|
-
event = ButtonEvent.new(data, self)
|
|
1747
|
-
|
|
1748
|
-
raise_event(event)
|
|
1749
|
-
when Webhooks::View::COMPONENT_TYPES[:string_select]
|
|
1750
|
-
event = StringSelectEvent.new(data, self)
|
|
1751
|
-
|
|
1752
|
-
raise_event(event)
|
|
1753
|
-
when Webhooks::View::COMPONENT_TYPES[:user_select]
|
|
1754
|
-
event = UserSelectEvent.new(data, self)
|
|
1755
|
-
|
|
1756
|
-
raise_event(event)
|
|
1757
|
-
when Webhooks::View::COMPONENT_TYPES[:role_select]
|
|
1758
|
-
event = RoleSelectEvent.new(data, self)
|
|
1759
|
-
|
|
1760
|
-
raise_event(event)
|
|
1761
|
-
when Webhooks::View::COMPONENT_TYPES[:mentionable_select]
|
|
1762
|
-
event = MentionableSelectEvent.new(data, self)
|
|
1763
|
-
|
|
1764
|
-
raise_event(event)
|
|
1765
|
-
when Webhooks::View::COMPONENT_TYPES[:channel_select]
|
|
1766
|
-
event = ChannelSelectEvent.new(data, self)
|
|
1767
|
-
|
|
1768
|
-
raise_event(event)
|
|
1769
|
-
end
|
|
1770
|
-
when Interaction::TYPES[:modal_submit]
|
|
1771
|
-
|
|
1772
|
-
event = ModalSubmitEvent.new(data, self)
|
|
1773
|
-
raise_event(event)
|
|
1774
|
-
when Interaction::TYPES[:autocomplete]
|
|
1775
|
-
|
|
1776
|
-
event = AutocompleteEvent.new(data, self)
|
|
1777
|
-
raise_event(event)
|
|
1778
|
-
end
|
|
1779
|
-
when :WEBHOOKS_UPDATE
|
|
1780
|
-
event = WebhookUpdateEvent.new(data, self)
|
|
1781
|
-
raise_event(event)
|
|
1782
|
-
when :THREAD_CREATE
|
|
1783
|
-
create_channel(data)
|
|
1784
|
-
|
|
1785
|
-
event = ThreadCreateEvent.new(data, self)
|
|
1786
|
-
raise_event(event)
|
|
1787
|
-
when :THREAD_UPDATE
|
|
1788
|
-
update_channel(data)
|
|
1789
|
-
|
|
1790
|
-
event = ThreadUpdateEvent.new(data, self)
|
|
1791
|
-
raise_event(event)
|
|
1792
|
-
when :THREAD_DELETE
|
|
1793
|
-
delete_channel(data)
|
|
1794
|
-
@thread_members.delete(data['id']&.resolve_id)
|
|
1795
|
-
|
|
1796
|
-
# raise ThreadDeleteEvent
|
|
1797
|
-
when :THREAD_LIST_SYNC
|
|
1798
|
-
server_id = data['guild_id'].to_i
|
|
1799
|
-
server = @servers[server_id]
|
|
1800
|
-
|
|
1801
|
-
# The `channel_ids` field has two meanings:
|
|
1802
|
-
#
|
|
1803
|
-
# 1. If the field is not present, the thread list is being synced for the whole server.
|
|
1804
|
-
#
|
|
1805
|
-
# 2. We are syncing the threads for a specific channel. This can happen when gaining access
|
|
1806
|
-
# to a channel.
|
|
1807
|
-
if (ids = data['channel_ids']&.map(&:to_i))
|
|
1808
|
-
@channels.delete_if { |_, channel| channel.thread? && ids.any?(channel.parent&.id) }
|
|
1809
|
-
server&.clear_threads(ids)
|
|
1810
|
-
else
|
|
1811
|
-
@channels.delete_if { |_, channel| channel.server.id == server_id && channel.thread? }
|
|
1812
|
-
server&.clear_threads
|
|
1813
|
-
end
|
|
1814
|
-
|
|
1815
|
-
data['members'].each { |member| ensure_thread_member(member) }
|
|
1816
|
-
data['threads'].each { |channel| ensure_channel(channel) }
|
|
1817
|
-
|
|
1818
|
-
# raise ThreadListSyncEvent?
|
|
1819
|
-
when :THREAD_MEMBER_UPDATE
|
|
1820
|
-
ensure_thread_member(data)
|
|
1821
|
-
when :THREAD_MEMBERS_UPDATE
|
|
1822
|
-
data['added_members']&.each do |added_member|
|
|
1823
|
-
ensure_thread_member(added_member) if added_member['user_id']
|
|
1824
|
-
end
|
|
1825
|
-
|
|
1826
|
-
data['removed_member_ids']&.each do |member_id|
|
|
1827
|
-
@thread_members[data['id']&.resolve_id]&.delete(member_id&.resolve_id)
|
|
1828
|
-
end
|
|
1829
|
-
|
|
1830
|
-
event = ThreadMembersUpdateEvent.new(data, self)
|
|
1831
|
-
raise_event(event)
|
|
1832
|
-
when :MESSAGE_POLL_VOTE_ADD
|
|
1833
|
-
event = PollVoteAddEvent.new(data, self)
|
|
1834
|
-
raise_event(event)
|
|
1835
|
-
when :MESSAGE_POLL_VOTE_REMOVE
|
|
1836
|
-
event = PollVoteRemoveEvent.new(data, self)
|
|
1837
|
-
raise_event(event)
|
|
1838
|
-
when :GUILD_SCHEDULED_EVENT_CREATE
|
|
1839
|
-
update_guild_scheduled_event(data)
|
|
1840
|
-
|
|
1841
|
-
event = ScheduledEventCreateEvent.new(data, self)
|
|
1842
|
-
raise_event(event)
|
|
1843
|
-
when :GUILD_SCHEDULED_EVENT_UPDATE
|
|
1844
|
-
update_guild_scheduled_event(data)
|
|
1845
|
-
|
|
1846
|
-
event = ScheduledEventUpdateEvent.new(data, self)
|
|
1847
|
-
raise_event(event)
|
|
1848
|
-
when :GUILD_SCHEDULED_EVENT_DELETE
|
|
1849
|
-
@servers[data['guild_id'].to_i]&.delete_scheduled_event(data['id'].to_i)
|
|
1850
|
-
|
|
1851
|
-
event = ScheduledEventDeleteEvent.new(data, self)
|
|
1852
|
-
raise_event(event)
|
|
1853
|
-
when :GUILD_SCHEDULED_EVENT_USER_ADD
|
|
1854
|
-
server = @servers[data['guild_id'].to_i]
|
|
1855
|
-
server&.scheduled_event(data['guild_scheduled_event_id'], request: false)&.increment_user_count
|
|
1856
|
-
|
|
1857
|
-
event = ScheduledEventUserAddEvent.new(data, self)
|
|
1858
|
-
raise_event(event)
|
|
1859
|
-
when :GUILD_SCHEDULED_EVENT_USER_REMOVE
|
|
1860
|
-
server = @servers[data['guild_id'].to_i]
|
|
1861
|
-
server&.scheduled_event(data['guild_scheduled_event_id'], request: false)&.deincrement_user_count
|
|
1862
|
-
|
|
1863
|
-
event = ScheduledEventUserRemoveEvent.new(data, self)
|
|
1864
|
-
raise_event(event)
|
|
1865
|
-
else
|
|
1866
|
-
# another event that we don't support yet
|
|
1867
|
-
debug "Event #{type} has been received but is unsupported. Raising UnknownEvent"
|
|
1868
|
-
|
|
1869
|
-
event = UnknownEvent.new(type, data, self)
|
|
1870
|
-
raise_event(event)
|
|
1871
|
-
end
|
|
1872
|
-
|
|
1873
|
-
# The existence of this array is checked before for performance reasons, since this has to be done for *every*
|
|
1874
|
-
# dispatch.
|
|
1875
|
-
if @event_handlers && @event_handlers[RawEvent]
|
|
1876
|
-
event = RawEvent.new(type, data, self)
|
|
1877
|
-
raise_event(event)
|
|
1878
|
-
end
|
|
1879
|
-
rescue Exception => e
|
|
1880
|
-
if defined?(Async::Cancel) && e.is_a?(Async::Cancel)
|
|
1881
|
-
LOGGER.debug('Gateway message handling was cancelled.')
|
|
1882
|
-
return
|
|
1883
|
-
end
|
|
1884
|
-
|
|
1885
|
-
LOGGER.error('Gateway message error!')
|
|
1886
|
-
log_exception(e)
|
|
1887
|
-
end
|
|
1888
|
-
|
|
1889
|
-
# Notifies everything there is to be notified that the connection is now ready
|
|
1890
|
-
def notify_ready
|
|
1891
|
-
if @mode == :raw
|
|
1892
|
-
notify_raw_ready
|
|
1893
|
-
return
|
|
1894
|
-
end
|
|
1895
|
-
|
|
1896
|
-
# Make sure to raise the event
|
|
1897
|
-
raise_event(ReadyEvent.new(self))
|
|
1898
|
-
LOGGER.good 'Ready'
|
|
1899
|
-
|
|
1900
|
-
@gateway.notify_ready
|
|
1901
|
-
end
|
|
1902
|
-
|
|
1903
|
-
def raise_event(event)
|
|
1904
|
-
debug("Raised a #{event.class}")
|
|
1905
|
-
handle_awaits(event)
|
|
1906
|
-
|
|
1907
|
-
@event_handlers ||= {}
|
|
1908
|
-
handlers = @event_handlers[event.class]
|
|
1909
|
-
return unless handlers
|
|
1910
|
-
|
|
1911
|
-
handlers.dup.each do |handler|
|
|
1912
|
-
call_event(handler, event) if handler.matches?(event)
|
|
1913
|
-
end
|
|
1914
|
-
end
|
|
1915
|
-
|
|
1916
|
-
def call_event(handler, event)
|
|
1917
|
-
@event_executor.post do
|
|
1918
|
-
Thread.current[:onyxcord_name] = next_event_thread_name('et')
|
|
1919
|
-
begin
|
|
1920
|
-
handler.call(event)
|
|
1921
|
-
handler.after_call(event)
|
|
1922
|
-
rescue StandardError => e
|
|
1923
|
-
log_exception(e)
|
|
1924
|
-
end
|
|
1925
|
-
end
|
|
1926
|
-
end
|
|
1927
|
-
|
|
1928
|
-
def handle_awaits(event)
|
|
1929
|
-
@awaits ||= {}
|
|
1930
|
-
@awaits.each_value do |await|
|
|
1931
|
-
key, should_delete = await.match(event)
|
|
1932
|
-
next unless key
|
|
1933
|
-
|
|
1934
|
-
debug("should_delete: #{should_delete}")
|
|
1935
|
-
@awaits.delete(await.key) if should_delete
|
|
1936
|
-
|
|
1937
|
-
await_event = OnyxCord::Events::AwaitEvent.new(await, event, self)
|
|
1938
|
-
raise_event(await_event)
|
|
1939
|
-
end
|
|
1940
|
-
end
|
|
1941
|
-
|
|
1942
|
-
def calculate_intents(intents)
|
|
1943
|
-
intents = [intents] unless intents.is_a? Array
|
|
1944
|
-
|
|
1945
|
-
intents.reduce(0) do |sum, intent|
|
|
1946
|
-
case intent
|
|
1947
|
-
when Symbol
|
|
1948
|
-
intent = INTENT_ALIASES[intent] || intent
|
|
1949
|
-
|
|
1950
|
-
if INTENTS[intent]
|
|
1951
|
-
sum | INTENTS[intent]
|
|
1952
|
-
else
|
|
1953
|
-
LOGGER.warn("Unknown intent: #{intent}")
|
|
1954
|
-
sum
|
|
1955
|
-
end
|
|
1956
|
-
when Integer
|
|
1957
|
-
sum | intent
|
|
1958
|
-
else
|
|
1959
|
-
LOGGER.warn("Invalid intent: #{intent}")
|
|
1960
|
-
sum
|
|
1961
|
-
end
|
|
1962
|
-
end
|
|
1963
|
-
end
|
|
1964
|
-
|
|
1965
|
-
def dispatch_packet(packet)
|
|
1966
|
-
type = packet['t']&.intern
|
|
1967
|
-
data = packet['d']
|
|
1968
|
-
|
|
1969
|
-
case @mode
|
|
1970
|
-
when :raw
|
|
1971
|
-
dispatch_raw_packet(packet)
|
|
1972
|
-
notify_raw_ready if type == :READY
|
|
1973
|
-
when :hybrid
|
|
1974
|
-
dispatch_raw_packet(packet)
|
|
1975
|
-
handle_dispatch(type, data)
|
|
1976
|
-
else
|
|
1977
|
-
handle_dispatch(type, data)
|
|
1978
|
-
end
|
|
1979
|
-
end
|
|
1980
|
-
|
|
1981
|
-
def dispatch_raw_packet(packet)
|
|
1982
|
-
handlers = @raw_handlers
|
|
1983
|
-
return unless handlers
|
|
1984
|
-
|
|
1985
|
-
handlers.dup.each do |handler|
|
|
1986
|
-
call_raw_handler(handler, packet) if handler.matches?(packet)
|
|
1987
|
-
end
|
|
1988
|
-
end
|
|
1989
|
-
|
|
1990
|
-
def call_raw_handler(handler, packet)
|
|
1991
|
-
@event_executor.post do
|
|
1992
|
-
Thread.current[:onyxcord_name] = next_event_thread_name('rt')
|
|
1993
|
-
handler.call(packet)
|
|
1994
|
-
rescue StandardError => e
|
|
1995
|
-
log_exception(e)
|
|
1996
|
-
end
|
|
1997
|
-
end
|
|
1998
|
-
|
|
1999
|
-
def notify_raw_ready
|
|
2000
|
-
return if @raw_ready_notified
|
|
2001
|
-
|
|
2002
|
-
@raw_ready_notified = true
|
|
2003
|
-
LOGGER.good 'Ready'
|
|
2004
|
-
@gateway.notify_ready
|
|
2005
|
-
end
|
|
2006
|
-
|
|
2007
|
-
def next_event_thread_name(prefix)
|
|
2008
|
-
@current_thread_mutex.synchronize do
|
|
2009
|
-
@current_thread += 1
|
|
2010
|
-
"#{prefix}-#{@current_thread}"
|
|
2011
|
-
end
|
|
2012
|
-
end
|
|
2013
278
|
end
|
|
2014
279
|
end
|