discorb 0.0.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.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +56 -0
  3. data/.yardopts +6 -0
  4. data/Changelog.md +5 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +70 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +53 -0
  9. data/Rakefile +46 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/discorb.gemspec +37 -0
  13. data/docs/Examples.md +26 -0
  14. data/docs/events.md +480 -0
  15. data/docs/voice_events.md +283 -0
  16. data/examples/components/authorization_button.rb +43 -0
  17. data/examples/components/select_menu.rb +61 -0
  18. data/examples/extension/main.rb +12 -0
  19. data/examples/extension/message_expander.rb +41 -0
  20. data/examples/simple/eval.rb +32 -0
  21. data/examples/simple/ping_pong.rb +16 -0
  22. data/examples/simple/rolepanel.rb +65 -0
  23. data/examples/simple/wait_for_message.rb +30 -0
  24. data/lib/discorb/application.rb +157 -0
  25. data/lib/discorb/asset.rb +57 -0
  26. data/lib/discorb/audit_logs.rb +323 -0
  27. data/lib/discorb/channel.rb +1101 -0
  28. data/lib/discorb/client.rb +363 -0
  29. data/lib/discorb/color.rb +173 -0
  30. data/lib/discorb/common.rb +123 -0
  31. data/lib/discorb/components.rb +290 -0
  32. data/lib/discorb/dictionary.rb +119 -0
  33. data/lib/discorb/embed.rb +345 -0
  34. data/lib/discorb/emoji.rb +218 -0
  35. data/lib/discorb/emoji_table.rb +3799 -0
  36. data/lib/discorb/error.rb +98 -0
  37. data/lib/discorb/event.rb +35 -0
  38. data/lib/discorb/extend.rb +18 -0
  39. data/lib/discorb/extension.rb +54 -0
  40. data/lib/discorb/file.rb +69 -0
  41. data/lib/discorb/flag.rb +109 -0
  42. data/lib/discorb/gateway.rb +967 -0
  43. data/lib/discorb/gateway_requests.rb +47 -0
  44. data/lib/discorb/guild.rb +1244 -0
  45. data/lib/discorb/guild_template.rb +211 -0
  46. data/lib/discorb/image.rb +43 -0
  47. data/lib/discorb/integration.rb +111 -0
  48. data/lib/discorb/intents.rb +137 -0
  49. data/lib/discorb/interaction.rb +333 -0
  50. data/lib/discorb/internet.rb +285 -0
  51. data/lib/discorb/invite.rb +145 -0
  52. data/lib/discorb/log.rb +70 -0
  53. data/lib/discorb/member.rb +232 -0
  54. data/lib/discorb/message.rb +583 -0
  55. data/lib/discorb/modules.rb +138 -0
  56. data/lib/discorb/permission.rb +270 -0
  57. data/lib/discorb/presence.rb +308 -0
  58. data/lib/discorb/reaction.rb +48 -0
  59. data/lib/discorb/role.rb +189 -0
  60. data/lib/discorb/sticker.rb +157 -0
  61. data/lib/discorb/user.rb +163 -0
  62. data/lib/discorb/utils.rb +16 -0
  63. data/lib/discorb/voice_state.rb +251 -0
  64. data/lib/discorb/webhook.rb +420 -0
  65. data/lib/discorb.rb +51 -0
  66. metadata +120 -0
@@ -0,0 +1,333 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a user interaction with the bot.
6
+ #
7
+ class Interaction < DiscordModel
8
+ # @return [Discorb::Snowflake] The ID of the interaction.
9
+ attr_reader :id
10
+ # @return [Discorb::Snowflake] The ID of the application that created the interaction.
11
+ attr_reader :application_id
12
+ # @return [Symbol] The type of interaction.
13
+ attr_reader :type
14
+ # @return [Discorb::Member] The member that created the interaction.
15
+ attr_reader :member
16
+ # @return [Discorb::User] The user that created the interaction.
17
+ attr_reader :user
18
+ # @return [Integer] The type of interaction.
19
+ # @note This is always `1` for now.
20
+ attr_reader :version
21
+ # @return [String] The token for the interaction.
22
+ attr_reader :token
23
+
24
+ # @!attribute [r] guild
25
+ # @macro client_cache
26
+ # @return [Discorb::Guild] The guild the interaction took place in.
27
+ # @!attribute [r] channel
28
+ # @macro client_cache
29
+ # @return [Discorb::Channel] The channel the interaction took place in.
30
+ # @!attribute [r] target
31
+ # @return [Discorb::User, Discorb::Member] The user or member the interaction took place with.
32
+
33
+ @interaction_type = nil
34
+ @interaction_name = nil
35
+
36
+ # @!visibility private
37
+ def initialize(client, data)
38
+ @client = client
39
+ @id = Snowflake.new(data[:id])
40
+ @application_id = Snowflake.new(data[:application_id])
41
+ @type = self.class.interaction_name
42
+ @type_id = self.class.interaction_type
43
+ @guild_id = data[:guild_id] && Snowflake.new(data[:guild_id])
44
+ @channel_id = data[:channel_id] && Snowflake.new(data[:channel_id])
45
+ @member = guild.members[data[:member][:id]] || Member.new(@client, @guild_id, data[:member][:user], data[:member]) if data[:member]
46
+ @user = @client.users[data[:user][:id]] || User.new(@client, data[:user]) if data[:user]
47
+ @token = data[:token]
48
+ @version = data[:version]
49
+ @defered = false
50
+ @responded = false
51
+ _set_data(data[:data])
52
+ end
53
+
54
+ def guild
55
+ @client.guilds[@guild_id]
56
+ end
57
+
58
+ def channel
59
+ @client.channels[@channel_id]
60
+ end
61
+
62
+ def target
63
+ @member || @user
64
+ end
65
+
66
+ alias fired_by target
67
+
68
+ def inspect
69
+ "#<#{self.class} id=#{@id}>"
70
+ end
71
+
72
+ class << self
73
+ # @!visibility private
74
+ attr_reader :interaction_type, :interaction_name, :event_name
75
+
76
+ # @!visibility private
77
+ def make_interaction(client, data)
78
+ descendants.each do |klass|
79
+ return klass.make_interaction(client, data) if !klass.interaction_type.nil? && klass.interaction_type == data[:type]
80
+ end
81
+ client.log.warn("Unknown interaction type #{data[:type]}, initialized Interaction")
82
+ Interaction.new(client, data)
83
+ end
84
+
85
+ # @!visibility private
86
+ def descendants
87
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
88
+ end
89
+ end
90
+
91
+ #
92
+ # A module for response with source.
93
+ #
94
+ module SourceResponse
95
+ #
96
+ # Response with `DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE`(`5`).
97
+ #
98
+ # @param [Boolean] hide Whether to hide the response (ephemeral).
99
+ #
100
+ def defer_source(hide: false)
101
+ Async do
102
+ @client.internet.post("/interactions/#{@id}/#{@token}/callback", {
103
+ type: 5,
104
+ data: {
105
+ flags: (hide ? 1 << 6 : 0),
106
+ },
107
+ }).wait
108
+ @defered = true
109
+ end
110
+ end
111
+
112
+ #
113
+ # Response with `CHANNEL_MESSAGE_WITH_SOURCE`(`4`).
114
+ #
115
+ # @param [String] content The content of the response.
116
+ # @param [Boolean] tts Whether to send the message as text-to-speech.
117
+ # @param [Discorb::Embed] embed The embed to send.
118
+ # @param [Array<Discorb::Embed>] embeds The embeds to send. (max: 10)
119
+ # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
120
+ # @param [Array<Discorb::Components>, Array<Array<Discorb::Components>>] components The components to send.
121
+ # @param [Boolean] hide Whether to hide the response (ephemeral).
122
+ #
123
+ def post(content, tts: false, embed: nil, embeds: nil, allowed_mentions: nil, components: nil, hide: false)
124
+ payload = {}
125
+ payload[:content] = content if content
126
+ payload[:tts] = tts
127
+ tmp_embed = if embed
128
+ [embed]
129
+ elsif embeds
130
+ embeds
131
+ end
132
+ payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
133
+ payload[:allowed_mentions] = allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
134
+ if components
135
+ tmp_components = []
136
+ tmp_row = []
137
+ components.each do |c|
138
+ case c
139
+ when Array
140
+ tmp_components << tmp_row
141
+ tmp_row = []
142
+ tmp_components << c
143
+ when SelectMenu
144
+ tmp_components << tmp_row
145
+ tmp_row = []
146
+ tmp_components << [c]
147
+ else
148
+ tmp_row << c
149
+ end
150
+ end
151
+ tmp_components << tmp_row
152
+ payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
153
+ end
154
+ payload[:flags] = (hide ? 1 << 6 : 0)
155
+ if @responded
156
+ @client.internet.post("/webhooks/#{@id}/#{@token}", { type: 4, data: payload }).wait
157
+ elsif @defered
158
+ @client.internet.post("/interactions/#{@id}/#{@token}/@original/edit", { type: 4, data: payload }).wait
159
+ else
160
+ @client.internet.post("/interactions/#{@id}/#{@token}/callback", { type: 4, data: payload }).wait
161
+ end
162
+ @responded = true
163
+ end
164
+ end
165
+
166
+ #
167
+ # A module for response with update.
168
+ #
169
+ module UpdateResponse
170
+ #
171
+ # Response with `DEFERRED_UPDATE_MESSAGE`(`6`).
172
+ #
173
+ # @param [Boolean] hide Whether to hide the response (ephemeral).
174
+ #
175
+ def defer_update(hide: false)
176
+ Async do
177
+ @client.internet.post("/interactions/#{@id}/#{@token}/callback", {
178
+ type: 7,
179
+ data: {
180
+ flags: (hide ? 1 << 6 : 0),
181
+ },
182
+ }).wait
183
+ end
184
+ end
185
+
186
+ #
187
+ # Response with `UPDATE_MESSAGE`(`7`).
188
+ #
189
+ # @param [String] content The content of the response.
190
+ # @param [Boolean] tts Whether to send the message as text-to-speech.
191
+ # @param [Discorb::Embed] embed The embed to send.
192
+ # @param [Array<Discorb::Embed>] embeds The embeds to send. (max: 10)
193
+ # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions to send.
194
+ # @param [Array<Discorb::Components>, Array<Array<Discorb::Components>>] components The components to send.
195
+ # @param [Boolean] hide Whether to hide the response (ephemeral).
196
+ #
197
+ def edit(content, tts: false, embed: nil, embeds: nil, allowed_mentions: nil, components: nil, hide: false)
198
+ payload = {}
199
+ payload[:content] = content if content
200
+ payload[:tts] = tts
201
+ tmp_embed = if embed
202
+ [embed]
203
+ elsif embeds
204
+ embeds
205
+ end
206
+ payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
207
+ payload[:allowed_mentions] = allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
208
+ if components
209
+ tmp_components = []
210
+ tmp_row = []
211
+ components.each do |c|
212
+ case c
213
+ when Array
214
+ tmp_components << tmp_row
215
+ tmp_row = []
216
+ tmp_components << c
217
+ when SelectMenu
218
+ tmp_components << tmp_row
219
+ tmp_row = []
220
+ tmp_components << [c]
221
+ else
222
+ tmp_row << c
223
+ end
224
+ end
225
+ tmp_components << tmp_row
226
+ payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
227
+ end
228
+ payload[:flags] = (hide ? 1 << 6 : 0)
229
+ @client.internet.post("/interactions/#{@id}/#{@token}/callback", { type: 6, data: payload }).wait
230
+ end
231
+ end
232
+
233
+ private
234
+
235
+ def _set_data(*)
236
+ nil
237
+ end
238
+ end
239
+
240
+ #
241
+ # Represents a slash command interaction.
242
+ # @todo Implement this.
243
+ #
244
+ class SlashCommandInteraction < Interaction
245
+ @interaction_type = 2
246
+ @interaction_name = :slash_command
247
+
248
+ def _set_data(data)
249
+ p data
250
+ end
251
+ end
252
+
253
+ #
254
+ # Represents a message component interaction.
255
+ # @abstract
256
+ #
257
+ class MessageComponentInteraction < Interaction
258
+ include Interaction::SourceResponse
259
+ include Interaction::UpdateResponse
260
+ # @return [String] The content of the response.
261
+ attr_reader :custom_id
262
+
263
+ @interaction_type = 3
264
+ @interaction_name = :message_component
265
+
266
+ # @!visibility private
267
+ def initialize(client, data)
268
+ super
269
+ @message = Message.new(@client, data[:message].merge({ member: data[:member] }))
270
+ end
271
+
272
+ class << self
273
+ # @!visibility private
274
+ attr_reader :component_type
275
+
276
+ # @!visibility private
277
+ def make_interaction(client, data)
278
+ nested_classes.each do |klass|
279
+ return klass.new(client, data) if !klass.component_type.nil? && klass.component_type == data[:type]
280
+ end
281
+ client.log.warn("Unknown component type #{data[:component_type]}, initialized Interaction")
282
+ MessageComponentInteraction.new(client, data)
283
+ end
284
+
285
+ # @!visibility private
286
+ def nested_classes
287
+ constants.select { |c| const_get(c).is_a? Class }.map { |c| const_get(c) }
288
+ end
289
+ end
290
+
291
+ #
292
+ # Represents a button interaction.
293
+ #
294
+ class Button < MessageComponentInteraction
295
+ @component_type = 2
296
+ @event_name = :button_click
297
+ # @return [String] The custom id of the button.
298
+ attr_reader :custom_id
299
+
300
+ private
301
+
302
+ def _set_data(data)
303
+ @custom_id = data[:custom_id]
304
+ end
305
+ end
306
+
307
+ #
308
+ # Represents a select menu interaction.
309
+ #
310
+ class SelectMenu < MessageComponentInteraction
311
+ @component_type = 3
312
+ @event_name = :select_menu_select
313
+ # @return [String] The custom id of the select menu.
314
+ attr_reader :custom_id
315
+ # @return [Array<String>] The selected options.
316
+ attr_reader :values
317
+
318
+ # @!attribute [r] value
319
+ # @return [String] The first selected value.
320
+
321
+ def value
322
+ @values[0]
323
+ end
324
+
325
+ private
326
+
327
+ def _set_data(data)
328
+ @custom_id = data[:custom_id]
329
+ @values = data[:values]
330
+ end
331
+ end
332
+ end
333
+ end
@@ -0,0 +1,285 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/https"
4
+
5
+ module Discorb
6
+ #
7
+ # A class to handle internet requests.
8
+ # This class is internal use only.
9
+ #
10
+ class Internet
11
+ @nil_body = nil
12
+
13
+ # @!visibility private
14
+ def initialize(client)
15
+ @client = client
16
+ end
17
+
18
+ #
19
+ # Execute a GET request.
20
+ # @macro async
21
+ #
22
+ # @param [String] path The path to the resource.
23
+ # @param [Hash] headers The headers to send with the request.
24
+ # @param [String] audit_log_reason The audit log reason to send with the request.
25
+ # @param [Hash] kwargs The keyword arguments.
26
+ #
27
+ # @return [Array[Net::HTTPResponse, Hash]] The response and as JSON.
28
+ # @return [Array[Net::HTTPResponse, nil]] The response was 204.
29
+ #
30
+ # @raise [Discorb::HTTPError] The request was failed.
31
+ #
32
+ def get(path, headers: nil, audit_log_reason: nil, **kwargs)
33
+ Async do |task|
34
+ resp = http.get(get_path(path), get_headers(headers, "", audit_log_reason), **kwargs)
35
+ rd = resp.body
36
+ data = if rd.nil? || rd.empty?
37
+ nil
38
+ else
39
+ JSON.parse(rd, symbolize_names: true)
40
+ end
41
+ test_error(if resp.code == "429"
42
+ @client.log.warn "Ratelimit exceeded for #{path}, trying again in #{data[:retry_after]} seconds."
43
+ task.sleep(data[:retry_after])
44
+ get(path, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
45
+ else
46
+ [resp, data]
47
+ end)
48
+ end
49
+ end
50
+
51
+ #
52
+ # Execute a POST request.
53
+ # @macro async
54
+ #
55
+ # @param [String] path The path to the resource.
56
+ # @param [String, Hash] body The body of the request.
57
+ # @param [Hash] headers The headers to send with the request.
58
+ # @param [String] audit_log_reason The audit log reason to send with the request.
59
+ # @param [Hash] kwargs The keyword arguments.
60
+ #
61
+ # @return [Array[Net::HTTPResponse, Hash]] The response and as JSON.
62
+ # @return [Array[Net::HTTPResponse, nil]] The response was 204.
63
+ #
64
+ # @raise [Discorb::HTTPError] The request was failed.
65
+ #
66
+ def post(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
67
+ Async do |task|
68
+ resp = http.post(get_path(path), get_body(body), get_headers(headers, body, audit_log_reason), **kwargs)
69
+ rd = resp.body
70
+ data = if rd.nil? || rd.empty?
71
+ nil
72
+ else
73
+ JSON.parse(rd, symbolize_names: true)
74
+ end
75
+ test_error(if resp.code == "429"
76
+ task.sleep(data[:retry_after])
77
+ post(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
78
+ else
79
+ [resp, data]
80
+ end)
81
+ end
82
+ end
83
+
84
+ #
85
+ # Execute a PATCH request.
86
+ # @macro async
87
+ #
88
+ # @param [String] path The path to the resource.
89
+ # @param [String, Hash] body The body of the request.
90
+ # @param [Hash] headers The headers to send with the request.
91
+ # @param [String] audit_log_reason The audit log reason to send with the request.
92
+ # @param [Hash] kwargs The keyword arguments.
93
+ #
94
+ # @return [Array[Net::HTTPResponse, Hash]] The response and as JSON.
95
+ # @return [Array[Net::HTTPResponse, nil]] The response was 204.
96
+ #
97
+ # @raise [Discorb::HTTPError] The request was failed.
98
+ #
99
+ def patch(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
100
+ Async do |task|
101
+ resp = http.patch(get_path(path), get_body(body), get_headers(headers, body, audit_log_reason), **kwargs)
102
+ rd = resp.body
103
+ data = if rd.nil? || rd.empty?
104
+ nil
105
+ else
106
+ JSON.parse(rd, symbolize_names: true)
107
+ end
108
+ test_error(if resp.code == "429"
109
+ task.sleep(data[:retry_after])
110
+ patch(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
111
+ else
112
+ [resp, data]
113
+ end)
114
+ end
115
+ end
116
+
117
+ #
118
+ # Execute a PUT request.
119
+ # @macro async
120
+ #
121
+ # @param [String] path The path to the resource.
122
+ # @param [String, Hash] body The body of the request.
123
+ # @param [Hash] headers The headers to send with the request.
124
+ # @param [String] audit_log_reason The audit log reason to send with the request.
125
+ # @param [Hash] kwargs The keyword arguments.
126
+ #
127
+ # @return [Array[Net::HTTPResponse, Hash]] The response and as JSON.
128
+ # @return [Array[Net::HTTPResponse, nil]] The response was 204.
129
+ #
130
+ # @raise [Discorb::HTTPError] The request was failed.
131
+ #
132
+ def put(path, body = "", headers: nil, audit_log_reason: nil, **kwargs)
133
+ Async do |task|
134
+ resp = http.put(get_path(path), get_body(body), get_headers(headers, body, audit_log_reason), **kwargs)
135
+ rd = resp.body
136
+ data = if rd.nil? || rd.empty?
137
+ nil
138
+ else
139
+ JSON.parse(rd, symbolize_names: true)
140
+ end
141
+ test_error(if resp.code == "429"
142
+ task.sleep(data[:retry_after])
143
+ put(path, body, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
144
+ else
145
+ [resp, data]
146
+ end)
147
+ end
148
+ end
149
+
150
+ #
151
+ # Execute a DELETE request.
152
+ # @macro async
153
+ #
154
+ # @param [String] path The path to the resource.
155
+ # @param [Hash] headers The headers to send with the request.
156
+ # @param [String] audit_log_reason The audit log reason to send with the request.
157
+ # @param [Hash] kwargs The keyword arguments.
158
+ #
159
+ # @return [Array[Net::HTTPResponse, Hash]] The response and as JSON.
160
+ # @return [Array[Net::HTTPResponse, nil]] The response was 204.
161
+ #
162
+ # @raise [Discorb::HTTPError] The request was failed.
163
+ #
164
+ def delete(path, headers: nil, audit_log_reason: nil, **kwargs)
165
+ Async do |task|
166
+ resp = http.delete(get_path(path), get_headers(headers, "", audit_log_reason))
167
+ rd = resp.body
168
+ data = if rd.nil? || rd.empty?
169
+ nil
170
+ else
171
+ JSON.parse(rd, symbolize_names: true)
172
+ end
173
+ test_error(if resp.code == "429"
174
+ task.sleep(data[:retry_after])
175
+ delete(path, headers: headers, audit_log_reason: audit_log_reason, **kwargs).wait
176
+ else
177
+ [resp, data]
178
+ end)
179
+ end
180
+ end
181
+
182
+ def inspect
183
+ "#<#{self.class} client=#{@client}>"
184
+ end
185
+
186
+ #
187
+ # A helper method to send multipart/form-data requests.
188
+ #
189
+ # @param [Hash] payload The payload to send.
190
+ # @param [Array<Discorb::File>] files The files to send.
191
+ #
192
+ # @return [Array[String, String]] The boundary and body.
193
+ #
194
+ def self.multipart(payload, files)
195
+ boundary = "DiscorbBySevenC7CMultipartFormData#{Time.now.to_f}"
196
+ str_payloads = [<<~HTTP]
197
+ Content-Disposition: form-data; name="payload_json"
198
+ Content-Type: application/json
199
+
200
+ #{payload.to_json}
201
+ HTTP
202
+ files.each do |single_file|
203
+ str_payloads << <<~HTTP
204
+ Content-Disposition: form-data; name="file"; filename="#{single_file.filename}"
205
+ Content-Type: #{single_file.content_type}
206
+
207
+ #{single_file.io.read}
208
+ HTTP
209
+ end
210
+ [boundary, "--#{boundary}\n#{str_payloads.join("\n--#{boundary}\n")}\n--#{boundary}--"]
211
+ end
212
+
213
+ private
214
+
215
+ def test_error(ary)
216
+ resp, data = *ary
217
+ case resp.code
218
+ when "400"
219
+ raise BadRequestError.new(resp, data)
220
+ when "403"
221
+ raise ForbiddenError.new(resp, data)
222
+ when "404"
223
+ raise NotFoundError.new(resp, data)
224
+ else
225
+ [resp, data]
226
+ end
227
+ end
228
+
229
+ def get_headers(headers, body = "", audit_log_reason = nil)
230
+ ret = if body.nil? || body.empty?
231
+ { "User-Agent" => USER_AGENT, "authorization" => "Bot #{@client.token}" }
232
+ else
233
+ { "User-Agent" => USER_AGENT, "authorization" => "Bot #{@client.token}",
234
+ "content-type" => "application/json" }
235
+ end
236
+ ret.merge(headers) if !headers.nil? && headers.length.positive?
237
+ ret["X-Audit-Log-Reason"] = audit_log_reason unless audit_log_reason.nil?
238
+ ret
239
+ end
240
+
241
+ def get_body(body)
242
+ if body.nil?
243
+ ""
244
+ elsif body.is_a?(String)
245
+ body
246
+ else
247
+ recr_utf8(body).to_json
248
+ end
249
+ end
250
+
251
+ def get_path(path)
252
+ full_path = if path.start_with?("https://")
253
+ path
254
+ else
255
+ API_BASE_URL + path
256
+ end
257
+ URI(full_path).path
258
+ end
259
+
260
+ def http
261
+ https = Net::HTTP.new("discord.com", 443)
262
+ https.use_ssl = true
263
+ https
264
+ end
265
+
266
+ def recr_utf8(data)
267
+ case data
268
+ when Hash
269
+ data.each do |k, v|
270
+ data[k] = recr_utf8(v)
271
+ end
272
+ data
273
+ when Array
274
+ data.each_index do |i|
275
+ data[i] = recr_utf8(data[i])
276
+ end
277
+ data
278
+ when String
279
+ data.dup.force_encoding(Encoding::UTF_8)
280
+ else
281
+ data
282
+ end
283
+ end
284
+ end
285
+ end