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
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Voice networking — uses OnyxCord::WebSocket (async-websocket based)
|
|
3
|
+
# Voice networking — uses OnyxCord::Internal::WebSocket (async-websocket based)
|
|
4
4
|
require 'socket'
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
require 'onyxcord/websocket'
|
|
5
|
+
require_relative '../internal/json'
|
|
6
|
+
require_relative '../internal/websocket'
|
|
8
7
|
require 'onyxcord/voice/opcodes'
|
|
9
8
|
|
|
10
9
|
begin
|
|
@@ -32,357 +31,6 @@ module OnyxCord::Voice
|
|
|
32
31
|
# Encryption modes supported by Discord
|
|
33
32
|
ENCRYPTION_MODES = %w[aead_xchacha20_poly1305_rtpsize].freeze
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# @return [true, false] whether or not UDP communications are encrypted.
|
|
38
|
-
# @deprecated Discord no longer supports unencrypted voice communication.
|
|
39
|
-
attr_accessor :encrypted
|
|
40
|
-
alias_method :encrypted?, :encrypted
|
|
41
|
-
|
|
42
|
-
# Sets the secret key used for encryption
|
|
43
|
-
attr_writer :secret_key
|
|
44
|
-
|
|
45
|
-
# The UDP encryption mode
|
|
46
|
-
attr_reader :mode
|
|
47
|
-
|
|
48
|
-
# @!visibility private
|
|
49
|
-
attr_writer :mode
|
|
50
|
-
|
|
51
|
-
# Creates a new UDP connection. Only creates a socket as the discovery reply may come before the data is
|
|
52
|
-
# initialized.
|
|
53
|
-
def initialize
|
|
54
|
-
@socket = UDPSocket.new
|
|
55
|
-
@encrypted = true
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Initializes the UDP socket with data obtained from opcode 2.
|
|
59
|
-
# @param ip [String] The IP address to connect to.
|
|
60
|
-
# @param port [Integer] The port to connect to.
|
|
61
|
-
# @param ssrc [Integer] The Super Secret Relay Code (SSRC). Discord uses this to identify different voice users
|
|
62
|
-
# on the same endpoint.
|
|
63
|
-
def connect(ip, port, ssrc)
|
|
64
|
-
@ip = ip
|
|
65
|
-
@port = port
|
|
66
|
-
@ssrc = ssrc
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Waits for a UDP discovery reply, and returns the sent data.
|
|
70
|
-
# @return [Array(String, Integer)] the IP and port received from the discovery reply.
|
|
71
|
-
def receive_discovery_reply
|
|
72
|
-
# Wait for a UDP message
|
|
73
|
-
message = @socket.recv(74)
|
|
74
|
-
ip = message[8..-3].delete("\0")
|
|
75
|
-
port = message[-2..].unpack1('n')
|
|
76
|
-
[ip, port]
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Makes an audio packet from a buffer and sends it to Discord.
|
|
80
|
-
# @param buf [String] The audio data to send, must be exactly one Opus frame
|
|
81
|
-
# @param sequence [Integer] The packet sequence number, incremented by one for subsequent packets
|
|
82
|
-
# @param time [Integer] When this packet should be played back, in no particular unit (essentially just the
|
|
83
|
-
# sequence number multiplied by 960)
|
|
84
|
-
def send_audio(buf, sequence, time)
|
|
85
|
-
# Header of the audio packet
|
|
86
|
-
header = generate_header(sequence, time)
|
|
87
|
-
|
|
88
|
-
nonce = generate_nonce
|
|
89
|
-
buf = encrypt_audio(buf, header, nonce)
|
|
90
|
-
data = header + buf + nonce.byteslice(0, 4)
|
|
91
|
-
|
|
92
|
-
send_packet(data)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Sends the UDP discovery packet with the internally stored SSRC. Discord will send a reply afterwards which can
|
|
96
|
-
# be received using {#receive_discovery_reply}
|
|
97
|
-
def send_discovery
|
|
98
|
-
# Create empty packet
|
|
99
|
-
discovery_packet = ''
|
|
100
|
-
|
|
101
|
-
# Add Type request (0x1 = request, 0x2 = response)
|
|
102
|
-
discovery_packet += [0x1].pack('n')
|
|
103
|
-
|
|
104
|
-
# Add Length (excluding Type and itself = 70)
|
|
105
|
-
discovery_packet += [70].pack('n')
|
|
106
|
-
|
|
107
|
-
# Add SSRC
|
|
108
|
-
discovery_packet += [@ssrc].pack('N')
|
|
109
|
-
|
|
110
|
-
# Add 66 zeroes so the packet is 74 bytes long
|
|
111
|
-
discovery_packet += "\0" * 66
|
|
112
|
-
|
|
113
|
-
send_packet(discovery_packet)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def close
|
|
117
|
-
@socket.close unless @socket.closed?
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
private
|
|
121
|
-
|
|
122
|
-
# Encrypts audio data using libsodium
|
|
123
|
-
# @param buf [String] The encoded audio data to be encrypted
|
|
124
|
-
# @param header [String] The RTP header of the packet, used as associated data
|
|
125
|
-
# @param nonce [String] The nonce to be used to encrypt the data
|
|
126
|
-
# @return [String] the audio data, encrypted
|
|
127
|
-
def encrypt_audio(buf, header, nonce)
|
|
128
|
-
raise 'No secret key found, despite encryption being enabled!' unless @secret_key
|
|
129
|
-
|
|
130
|
-
case @mode
|
|
131
|
-
when 'aead_xchacha20_poly1305_rtpsize'
|
|
132
|
-
OnyxCord::Voice::XChaCha20AEAD.encrypt(buf, header, nonce, @secret_key)
|
|
133
|
-
else
|
|
134
|
-
raise "`#{@mode}' is not a supported encryption mode"
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def send_packet(packet)
|
|
139
|
-
@socket.send(packet, 0, @ip, @port)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# @return [String]
|
|
143
|
-
def generate_nonce
|
|
144
|
-
case @mode
|
|
145
|
-
when 'aead_xchacha20_poly1305_rtpsize'
|
|
146
|
-
case @incremental_nonce
|
|
147
|
-
when nil, 0xff_ff_ff_ff
|
|
148
|
-
@incremental_nonce = 0
|
|
149
|
-
else
|
|
150
|
-
@incremental_nonce += 1
|
|
151
|
-
end
|
|
152
|
-
[@incremental_nonce].pack('N').ljust(24, "\0")
|
|
153
|
-
else
|
|
154
|
-
raise "`#{@mode}' is not a supported encryption mode"
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
# @return [String]
|
|
159
|
-
def generate_header(sequence, time)
|
|
160
|
-
[0x80, 0x78, sequence, time, @ssrc].pack('CCnNN')
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# Represents a websocket client connection to the voice server. The websocket connection (sometimes called vWS) is
|
|
165
|
-
# used to manage general data about the connection, such as sending the speaking packet, which determines the green
|
|
166
|
-
# circle around users on Discord, and obtaining UDP connection info.
|
|
167
|
-
class VoiceWS
|
|
168
|
-
# The version of the voice gateway that's supposed to be used.
|
|
169
|
-
VOICE_GATEWAY_VERSION = 8
|
|
170
|
-
|
|
171
|
-
# @return [VoiceUDP] the UDP voice connection over which the actual audio data is sent.
|
|
172
|
-
attr_reader :udp
|
|
173
|
-
|
|
174
|
-
# Makes a new voice websocket client, but doesn't connect it (see {#connect} for that)
|
|
175
|
-
# @param channel [Channel] The voice channel to connect to
|
|
176
|
-
# @param bot [Bot] The regular bot to which this vWS is bound
|
|
177
|
-
# @param token [String] The authentication token which is also used for REST requests
|
|
178
|
-
# @param session [String] The voice session ID Discord sends over the regular websocket
|
|
179
|
-
# @param endpoint [String] The endpoint URL to connect to
|
|
180
|
-
def initialize(channel, bot, token, session, endpoint)
|
|
181
|
-
raise 'libsodium is unavailable - unable to create voice bot! Please read https://github.com/kruldevb/OnyxCord/wiki/Installing-libsodium' unless LIBSODIUM_AVAILABLE
|
|
182
|
-
|
|
183
|
-
@channel = channel
|
|
184
|
-
@bot = bot
|
|
185
|
-
@token = token
|
|
186
|
-
@session = session
|
|
187
|
-
|
|
188
|
-
@endpoint = endpoint
|
|
189
|
-
|
|
190
|
-
@udp = VoiceUDP.new
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# Send a connection init packet (op 0)
|
|
194
|
-
# @param server_id [Integer] The ID of the server to connect to
|
|
195
|
-
# @param bot_user_id [Integer] The ID of the bot that is connecting
|
|
196
|
-
# @param session_id [String] The voice session ID
|
|
197
|
-
# @param token [String] The Discord authentication token
|
|
198
|
-
def send_init(server_id, bot_user_id, session_id, token)
|
|
199
|
-
send_opcode(
|
|
200
|
-
Opcodes::IDENTIFY,
|
|
201
|
-
{
|
|
202
|
-
server_id: server_id,
|
|
203
|
-
user_id: bot_user_id,
|
|
204
|
-
session_id: session_id,
|
|
205
|
-
token: token
|
|
206
|
-
}
|
|
207
|
-
)
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
# Sends the UDP connection packet (op 1)
|
|
211
|
-
# @param ip [String] The IP to bind UDP to
|
|
212
|
-
# @param port [Integer] The port to bind UDP to
|
|
213
|
-
# @param mode [Object] Which mode to use for the voice connection
|
|
214
|
-
def send_udp_connection(ip, port, mode)
|
|
215
|
-
send_opcode(
|
|
216
|
-
Opcodes::SELECT_PROTOCOL,
|
|
217
|
-
{
|
|
218
|
-
protocol: 'udp',
|
|
219
|
-
data: {
|
|
220
|
-
address: ip,
|
|
221
|
-
port: port,
|
|
222
|
-
mode: mode
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
)
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
# Send a heartbeat (op 3), has to be done every @heartbeat_interval seconds or the connection will terminate
|
|
229
|
-
def send_heartbeat
|
|
230
|
-
millis = Time.now.strftime('%s%L').to_i
|
|
231
|
-
@bot.debug("Sending voice heartbeat at #{millis}")
|
|
232
|
-
|
|
233
|
-
send_opcode(
|
|
234
|
-
Opcodes::HEARTBEAT,
|
|
235
|
-
{
|
|
236
|
-
t: millis,
|
|
237
|
-
seq_ack: @seq
|
|
238
|
-
}
|
|
239
|
-
)
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
# Send a speaking packet (op 5). This determines the green circle around the avatar in the voice channel
|
|
243
|
-
# @param value [true, false, Integer] Whether or not the bot should be speaking, can also be a bitmask denoting audio type.
|
|
244
|
-
def send_speaking(value)
|
|
245
|
-
@bot.debug("Speaking: #{value}")
|
|
246
|
-
send_opcode(
|
|
247
|
-
Opcodes::SPEAKING,
|
|
248
|
-
{
|
|
249
|
-
speaking: value,
|
|
250
|
-
delay: 0
|
|
251
|
-
}
|
|
252
|
-
)
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def send_opcode(opcode, data)
|
|
256
|
-
@bot.debug("Sending voice opcode #{opcode} with data: #{data}")
|
|
257
|
-
@client.send({
|
|
258
|
-
op: opcode,
|
|
259
|
-
d: data
|
|
260
|
-
}.to_json)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
# Event handlers; public for websocket-simple to work correctly
|
|
264
|
-
# @!visibility private
|
|
265
|
-
def websocket_open
|
|
266
|
-
# Give the current thread a name ('Voice Web Socket Internal')
|
|
267
|
-
Thread.current[:onyxcord_name] = 'vws-i'
|
|
268
|
-
|
|
269
|
-
# Send the init packet
|
|
270
|
-
send_init(@channel.server.id, @bot.profile.id, @session, @token)
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
# @!visibility private
|
|
274
|
-
def websocket_message(msg)
|
|
275
|
-
@bot.debug("Received VWS message! #{msg}")
|
|
276
|
-
packet = JSON.parse(msg)
|
|
277
|
-
|
|
278
|
-
@seq = packet['seq'] if packet['seq']
|
|
279
|
-
|
|
280
|
-
case packet['op']
|
|
281
|
-
when OnyxCord::Voice::Opcodes::READY
|
|
282
|
-
# Opcode 2 contains data to initialize the UDP connection
|
|
283
|
-
@ws_data = packet['d']
|
|
284
|
-
|
|
285
|
-
@ssrc = @ws_data['ssrc']
|
|
286
|
-
@port = @ws_data['port']
|
|
287
|
-
|
|
288
|
-
@udp_mode = (ENCRYPTION_MODES & @ws_data['modes']).first
|
|
289
|
-
|
|
290
|
-
@udp.connect(@ws_data['ip'], @port, @ssrc)
|
|
291
|
-
@udp.send_discovery
|
|
292
|
-
when OnyxCord::Voice::Opcodes::SESSION_DESCRIPTION
|
|
293
|
-
# Opcode 4 sends the secret key used for encryption
|
|
294
|
-
@ws_data = packet['d']
|
|
295
|
-
|
|
296
|
-
# Reset the sequence when starting a new session
|
|
297
|
-
@seq = 0
|
|
298
|
-
|
|
299
|
-
@ready = true
|
|
300
|
-
@udp.secret_key = @ws_data['secret_key'].pack('C*')
|
|
301
|
-
@udp.mode = @ws_data['mode']
|
|
302
|
-
when OnyxCord::Voice::Opcodes::HELLO
|
|
303
|
-
# Opcode 8 contains the heartbeat interval.
|
|
304
|
-
@heartbeat_interval = packet['d']['heartbeat_interval']
|
|
305
|
-
send_heartbeat
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
# Communication goes like this:
|
|
310
|
-
# me discord
|
|
311
|
-
# | |
|
|
312
|
-
# websocket connect -> |
|
|
313
|
-
# | |
|
|
314
|
-
# | <- websocket opcode 2
|
|
315
|
-
# | |
|
|
316
|
-
# UDP discovery -> |
|
|
317
|
-
# | |
|
|
318
|
-
# | <- UDP reply packet
|
|
319
|
-
# | |
|
|
320
|
-
# websocket opcode 1 -> |
|
|
321
|
-
# | |
|
|
322
|
-
# ...
|
|
323
|
-
def connect
|
|
324
|
-
# Connect websocket
|
|
325
|
-
@thread = Thread.new do
|
|
326
|
-
Thread.current[:onyxcord_name] = 'vws'
|
|
327
|
-
init_ws
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
@bot.debug('Started websocket initialization, now waiting for UDP discovery reply')
|
|
331
|
-
|
|
332
|
-
# Now wait for opcode 2 and the resulting UDP reply packet
|
|
333
|
-
ip, port = @udp.receive_discovery_reply
|
|
334
|
-
@bot.debug("UDP discovery reply received! #{ip} #{port}")
|
|
335
|
-
|
|
336
|
-
# Send UDP init packet with received UDP data
|
|
337
|
-
send_udp_connection(ip, port, @udp_mode)
|
|
338
|
-
|
|
339
|
-
@bot.debug('Waiting for op 4 now')
|
|
340
|
-
|
|
341
|
-
# Wait for op 4, then finish
|
|
342
|
-
sleep 0.05 until @ready
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
# Disconnects the websocket and kills the thread
|
|
346
|
-
def destroy(join_timeout = 1)
|
|
347
|
-
@heartbeat_running = false
|
|
348
|
-
@client&.close
|
|
349
|
-
@udp.close
|
|
350
|
-
@thread&.join(join_timeout)
|
|
351
|
-
@thread&.kill if @thread&.alive?
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
private
|
|
355
|
-
|
|
356
|
-
def heartbeat_loop
|
|
357
|
-
@heartbeat_running = true
|
|
358
|
-
while @heartbeat_running
|
|
359
|
-
if @heartbeat_interval
|
|
360
|
-
sleep @heartbeat_interval / 1000.0
|
|
361
|
-
send_heartbeat
|
|
362
|
-
else
|
|
363
|
-
# If no interval has been set yet, sleep a second and check again
|
|
364
|
-
sleep 1
|
|
365
|
-
end
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
def init_ws
|
|
370
|
-
host = "wss://#{@endpoint}/?v=#{VOICE_GATEWAY_VERSION}"
|
|
371
|
-
@bot.debug("Connecting VWS to host: #{host}")
|
|
372
|
-
|
|
373
|
-
# Connect the WS
|
|
374
|
-
@client = OnyxCord::WebSocket.new(
|
|
375
|
-
host,
|
|
376
|
-
method(:websocket_open),
|
|
377
|
-
method(:websocket_message),
|
|
378
|
-
proc { |e| OnyxCord::LOGGER.error "VWS error: #{e}" },
|
|
379
|
-
proc { |e| OnyxCord::LOGGER.warn "VWS close: #{e}" }
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
@bot.debug('VWS connected')
|
|
383
|
-
|
|
384
|
-
# Block any further execution
|
|
385
|
-
heartbeat_loop
|
|
386
|
-
end
|
|
387
|
-
end
|
|
34
|
+
require 'onyxcord/voice/network/udp'
|
|
35
|
+
require 'onyxcord/voice/network/websocket'
|
|
388
36
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'onyxcord/http'
|
|
4
|
-
require 'onyxcord/json'
|
|
3
|
+
require 'onyxcord/internal/http'
|
|
4
|
+
require 'onyxcord/internal/json'
|
|
5
5
|
|
|
6
6
|
require 'onyxcord/webhooks/builder'
|
|
7
7
|
|
|
@@ -38,7 +38,7 @@ module OnyxCord::Webhooks
|
|
|
38
38
|
# embed.image = OnyxCord::Webhooks::EmbedImage.new(url: 'https://i.imgur.com/PcMltU7.jpg')
|
|
39
39
|
# end
|
|
40
40
|
# end
|
|
41
|
-
# @return [OnyxCord::HTTP::Response] the response returned by Discord.
|
|
41
|
+
# @return [::OnyxCord::Internal::HTTP::Response] the response returned by Discord.
|
|
42
42
|
def execute(builder = nil, wait = false, components = nil, thread_id: nil, flags: nil, has_components: false, components_v2: false)
|
|
43
43
|
raise TypeError, 'builder needs to be nil or like a OnyxCord::Webhooks::Builder!' unless
|
|
44
44
|
(builder.respond_to?(:file) && builder.respond_to?(:to_multipart_hash)) || builder.respond_to?(:to_json_hash) || builder.nil?
|
|
@@ -61,9 +61,9 @@ module OnyxCord::Webhooks
|
|
|
61
61
|
# @param name [String, nil] The default name.
|
|
62
62
|
# @param avatar [String, #read, nil] The new avatar, in base64-encoded JPG format.
|
|
63
63
|
# @param channel_id [String, Integer, nil] The channel to move the webhook to.
|
|
64
|
-
# @return [OnyxCord::HTTP::Response] the response returned by Discord.
|
|
64
|
+
# @return [::OnyxCord::Internal::HTTP::Response] the response returned by Discord.
|
|
65
65
|
def modify(name: nil, avatar: nil, channel_id: nil)
|
|
66
|
-
OnyxCord::HTTP.patch(
|
|
66
|
+
::OnyxCord::Internal::HTTP.patch(
|
|
67
67
|
@url,
|
|
68
68
|
{ name: name, avatar: avatarise(avatar), channel_id: channel_id }.compact.to_json,
|
|
69
69
|
'content-type' => 'application/json'
|
|
@@ -72,10 +72,10 @@ module OnyxCord::Webhooks
|
|
|
72
72
|
|
|
73
73
|
# Delete this webhook.
|
|
74
74
|
# @param reason [String, nil] The reason this webhook was deleted.
|
|
75
|
-
# @return [OnyxCord::HTTP::Response] the response returned by Discord.
|
|
75
|
+
# @return [::OnyxCord::Internal::HTTP::Response] the response returned by Discord.
|
|
76
76
|
# @note This is permanent and cannot be undone.
|
|
77
77
|
def delete(reason: nil)
|
|
78
|
-
OnyxCord::HTTP.delete(@url, 'X-Audit-Log-Reason' => reason)
|
|
78
|
+
::OnyxCord::Internal::HTTP.delete(@url, 'X-Audit-Log-Reason' => reason)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
# Edit a message from this webhook.
|
|
@@ -85,7 +85,7 @@ module OnyxCord::Webhooks
|
|
|
85
85
|
# @param embeds [Array<Embed, Hash>]
|
|
86
86
|
# @param allowed_mentions [Hash]
|
|
87
87
|
# @param thread_id [String, Integer, nil] The id of the thread in which the message resides
|
|
88
|
-
# @return [OnyxCord::HTTP::Response] the response returned by Discord.
|
|
88
|
+
# @return [::OnyxCord::Internal::HTTP::Response] the response returned by Discord.
|
|
89
89
|
# @example Edit message content
|
|
90
90
|
# client.edit_message(message_id, content: 'goodbye world!')
|
|
91
91
|
# @example Edit a message via builder
|
|
@@ -106,7 +106,7 @@ module OnyxCord::Webhooks
|
|
|
106
106
|
builder_flags = data[:flags] if data.is_a?(Hash)
|
|
107
107
|
flags = View.apply_v2_flag(flags || builder_flags, components, force: has_components || components_v2)
|
|
108
108
|
data = data.merge({ content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components, flags: flags }.compact)
|
|
109
|
-
OnyxCord::HTTP.patch(
|
|
109
|
+
::OnyxCord::Internal::HTTP.patch(
|
|
110
110
|
"#{@url}/messages/#{message_id}#{(query.empty? ? '' : "?#{query}")}",
|
|
111
111
|
data.compact.to_json,
|
|
112
112
|
'content-type' => 'application/json'
|
|
@@ -115,9 +115,9 @@ module OnyxCord::Webhooks
|
|
|
115
115
|
|
|
116
116
|
# Delete a message created by this webhook.
|
|
117
117
|
# @param message_id [String, Integer] The ID of the message to delete.
|
|
118
|
-
# @return [OnyxCord::HTTP::Response] the response returned by Discord.
|
|
118
|
+
# @return [::OnyxCord::Internal::HTTP::Response] the response returned by Discord.
|
|
119
119
|
def delete_message(message_id)
|
|
120
|
-
OnyxCord::HTTP.delete("#{@url}/messages/#{message_id}")
|
|
120
|
+
::OnyxCord::Internal::HTTP.delete("#{@url}/messages/#{message_id}")
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
private
|
|
@@ -139,7 +139,7 @@ module OnyxCord::Webhooks
|
|
|
139
139
|
flags = View.apply_v2_flag(flags || builder_flags, components, force: has_components)
|
|
140
140
|
data = data.merge({ components: components })
|
|
141
141
|
data[:flags] = flags unless flags.nil?
|
|
142
|
-
OnyxCord::HTTP.post(
|
|
142
|
+
::OnyxCord::Internal::HTTP.post(
|
|
143
143
|
encode_url(wait, thread_id, with_components: components.any?),
|
|
144
144
|
data.to_json,
|
|
145
145
|
'content-type' => 'application/json'
|
|
@@ -153,7 +153,7 @@ module OnyxCord::Webhooks
|
|
|
153
153
|
flags = View.apply_v2_flag(flags || builder_flags, components, force: has_components)
|
|
154
154
|
data[:components] = components if components.any?
|
|
155
155
|
data[:flags] = flags unless flags.nil?
|
|
156
|
-
OnyxCord::HTTP.post(
|
|
156
|
+
::OnyxCord::Internal::HTTP.post(
|
|
157
157
|
encode_url(wait, thread_id, with_components: components.any?),
|
|
158
158
|
data.compact
|
|
159
159
|
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class OnyxCord::Webhooks::Modal
|
|
4
|
+
class GroupBuilder
|
|
5
|
+
# @!visibility private
|
|
6
|
+
def initialize(type, custom_id, id, options = [], required = nil, min_values = nil, max_values = nil)
|
|
7
|
+
@id = id
|
|
8
|
+
@type = type
|
|
9
|
+
@custom_id = custom_id
|
|
10
|
+
@options = options
|
|
11
|
+
@required = required
|
|
12
|
+
@min_values = min_values
|
|
13
|
+
@max_values = max_values
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Add a checkbox component to the group.
|
|
17
|
+
# @param value [String] The value that the checkbox represents.
|
|
18
|
+
# @param label [String] The primary text of the checkbox.
|
|
19
|
+
# @param description [String, nil] The description of the checkbox.
|
|
20
|
+
# @param default [true, false, nil] Whether or not the checkbox should be checked by default.
|
|
21
|
+
def checkbox(value:, label:, description: nil, default: nil)
|
|
22
|
+
raise "Cannot add a checkbox to a #{@type}" unless @type == :checkbox_group
|
|
23
|
+
|
|
24
|
+
@options << { value: value, label: label, description: description, default: default }.compact
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Add a radio button component to the group.
|
|
28
|
+
# @param value [String] The value that the radio button represents.
|
|
29
|
+
# @param label [String] The primary text of the radio button.
|
|
30
|
+
# @param description [String, nil] The description of the radio button.
|
|
31
|
+
# @param default [true, false, nil] Whether or not the radio button should be selected by default.
|
|
32
|
+
def radio_button(value:, label:, description: nil, default: nil)
|
|
33
|
+
raise "Cannot add a radio button to a #{@type}" unless @type == :radio_group
|
|
34
|
+
|
|
35
|
+
@options << { value: value, label: label, description: description, default: default }.compact
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
alias_method :button, :radio_button
|
|
39
|
+
|
|
40
|
+
# @!visibility private
|
|
41
|
+
def to_h
|
|
42
|
+
{
|
|
43
|
+
id: @id,
|
|
44
|
+
type: COMPONENT_TYPES[@type],
|
|
45
|
+
custom_id: @custom_id,
|
|
46
|
+
options: @options.map(&:to_h),
|
|
47
|
+
required: @required,
|
|
48
|
+
min_values: @min_values,
|
|
49
|
+
max_values: @max_values
|
|
50
|
+
}.compact
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# This builder is used when adding a label component to a modal.
|
|
55
|
+
end
|