rubycord 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/lib/rubycord/allowed_mentions.rb +34 -0
  3. data/lib/rubycord/api/application.rb +200 -0
  4. data/lib/rubycord/api/channel.rb +597 -0
  5. data/lib/rubycord/api/interaction.rb +52 -0
  6. data/lib/rubycord/api/invite.rb +42 -0
  7. data/lib/rubycord/api/server.rb +557 -0
  8. data/lib/rubycord/api/user.rb +153 -0
  9. data/lib/rubycord/api/webhook.rb +138 -0
  10. data/lib/rubycord/api.rb +356 -0
  11. data/lib/rubycord/await.rb +49 -0
  12. data/lib/rubycord/bot.rb +1757 -0
  13. data/lib/rubycord/cache.rb +259 -0
  14. data/lib/rubycord/colour_rgb.rb +41 -0
  15. data/lib/rubycord/commands/command_bot.rb +519 -0
  16. data/lib/rubycord/commands/container.rb +110 -0
  17. data/lib/rubycord/commands/events.rb +9 -0
  18. data/lib/rubycord/commands/parser.rb +325 -0
  19. data/lib/rubycord/commands/rate_limiter.rb +142 -0
  20. data/lib/rubycord/container.rb +753 -0
  21. data/lib/rubycord/data/activity.rb +269 -0
  22. data/lib/rubycord/data/application.rb +48 -0
  23. data/lib/rubycord/data/attachment.rb +109 -0
  24. data/lib/rubycord/data/audit_logs.rb +343 -0
  25. data/lib/rubycord/data/channel.rb +996 -0
  26. data/lib/rubycord/data/component.rb +227 -0
  27. data/lib/rubycord/data/embed.rb +249 -0
  28. data/lib/rubycord/data/emoji.rb +80 -0
  29. data/lib/rubycord/data/integration.rb +120 -0
  30. data/lib/rubycord/data/interaction.rb +798 -0
  31. data/lib/rubycord/data/invite.rb +135 -0
  32. data/lib/rubycord/data/member.rb +370 -0
  33. data/lib/rubycord/data/message.rb +412 -0
  34. data/lib/rubycord/data/overwrite.rb +106 -0
  35. data/lib/rubycord/data/profile.rb +89 -0
  36. data/lib/rubycord/data/reaction.rb +31 -0
  37. data/lib/rubycord/data/recipient.rb +32 -0
  38. data/lib/rubycord/data/role.rb +246 -0
  39. data/lib/rubycord/data/server.rb +1002 -0
  40. data/lib/rubycord/data/user.rb +261 -0
  41. data/lib/rubycord/data/voice_region.rb +43 -0
  42. data/lib/rubycord/data/voice_state.rb +39 -0
  43. data/lib/rubycord/data/webhook.rb +232 -0
  44. data/lib/rubycord/data.rb +40 -0
  45. data/lib/rubycord/errors.rb +737 -0
  46. data/lib/rubycord/events/await.rb +46 -0
  47. data/lib/rubycord/events/bans.rb +58 -0
  48. data/lib/rubycord/events/channels.rb +186 -0
  49. data/lib/rubycord/events/generic.rb +126 -0
  50. data/lib/rubycord/events/guilds.rb +191 -0
  51. data/lib/rubycord/events/interactions.rb +480 -0
  52. data/lib/rubycord/events/invites.rb +123 -0
  53. data/lib/rubycord/events/lifetime.rb +29 -0
  54. data/lib/rubycord/events/members.rb +91 -0
  55. data/lib/rubycord/events/message.rb +337 -0
  56. data/lib/rubycord/events/presence.rb +127 -0
  57. data/lib/rubycord/events/raw.rb +45 -0
  58. data/lib/rubycord/events/reactions.rb +156 -0
  59. data/lib/rubycord/events/roles.rb +86 -0
  60. data/lib/rubycord/events/threads.rb +94 -0
  61. data/lib/rubycord/events/typing.rb +70 -0
  62. data/lib/rubycord/events/voice_server_update.rb +45 -0
  63. data/lib/rubycord/events/voice_state_update.rb +103 -0
  64. data/lib/rubycord/events/webhooks.rb +62 -0
  65. data/lib/rubycord/gateway.rb +867 -0
  66. data/lib/rubycord/id_object.rb +37 -0
  67. data/lib/rubycord/light/data.rb +60 -0
  68. data/lib/rubycord/light/integrations.rb +71 -0
  69. data/lib/rubycord/light/light_bot.rb +56 -0
  70. data/lib/rubycord/light.rb +6 -0
  71. data/lib/rubycord/logger.rb +118 -0
  72. data/lib/rubycord/paginator.rb +55 -0
  73. data/lib/rubycord/permissions.rb +251 -0
  74. data/lib/rubycord/version.rb +5 -0
  75. data/lib/rubycord/voice/encoder.rb +113 -0
  76. data/lib/rubycord/voice/network.rb +366 -0
  77. data/lib/rubycord/voice/sodium.rb +96 -0
  78. data/lib/rubycord/voice/voice_bot.rb +408 -0
  79. data/lib/rubycord/webhooks/builder.rb +100 -0
  80. data/lib/rubycord/webhooks/client.rb +132 -0
  81. data/lib/rubycord/webhooks/embeds.rb +248 -0
  82. data/lib/rubycord/webhooks/modal.rb +78 -0
  83. data/lib/rubycord/webhooks/version.rb +7 -0
  84. data/lib/rubycord/webhooks/view.rb +192 -0
  85. data/lib/rubycord/webhooks.rb +12 -0
  86. data/lib/rubycord/websocket.rb +70 -0
  87. data/lib/rubycord.rb +140 -0
  88. metadata +231 -0
@@ -0,0 +1,248 @@
1
+ module Rubycord::Webhooks
2
+ # An embed is a multipart-style attachment to a webhook message that can have a variety of different purposes and
3
+ # appearances.
4
+ class Embed
5
+ def initialize(title: nil, description: nil, url: nil, timestamp: nil, colour: nil, color: nil, footer: nil,
6
+ image: nil, thumbnail: nil, video: nil, provider: nil, author: nil, fields: [])
7
+ @title = title
8
+ @description = description
9
+ @url = url
10
+ @timestamp = timestamp
11
+ self.colour = colour || color
12
+ @footer = footer
13
+ @image = image
14
+ @thumbnail = thumbnail
15
+ @video = video
16
+ @provider = provider
17
+ @author = author
18
+ @fields = fields
19
+ end
20
+
21
+ # @return [String, nil] title of the embed that will be displayed above everything else.
22
+ attr_accessor :title
23
+
24
+ # @return [String, nil] description for this embed
25
+ attr_accessor :description
26
+
27
+ # @return [String, nil] URL the title should point to
28
+ attr_accessor :url
29
+
30
+ # @return [Time, nil] timestamp for this embed. Will be displayed just below the title.
31
+ attr_accessor :timestamp
32
+
33
+ # @return [Integer, nil] the colour of the bar to the side, in decimal form
34
+ attr_reader :colour
35
+ alias_method :color, :colour
36
+
37
+ # Sets the colour of the bar to the side of the embed to something new.
38
+ # @param value [String, Integer, {Integer, Integer, Integer}, #to_i, nil] The colour in decimal, hexadecimal, R/G/B decimal, or nil to clear the embeds colour
39
+ # form.
40
+ def colour=(value)
41
+ if value.nil?
42
+ @colour = nil
43
+ elsif value.is_a? Integer
44
+ raise ArgumentError, "Embed colour must be 24-bit!" if value >= 16_777_216
45
+
46
+ @colour = value
47
+ elsif value.is_a? String
48
+ self.colour = value.delete("#").to_i(16)
49
+ elsif value.is_a? Array
50
+ raise ArgumentError, "Colour tuple must have three values!" if value.length != 3
51
+
52
+ self.colour = (value[0] << 16) | (value[1] << 8) | value[2]
53
+ else
54
+ self.colour = value.to_i
55
+ end
56
+ end
57
+
58
+ alias_method :color=, :colour=
59
+
60
+ # @example Add a footer to an embed
61
+ # embed.footer = Rubycord::Webhooks::EmbedFooter.new(text: 'Hello', icon_url: 'https://i.imgur.com/j69wMDu.jpg')
62
+ # @return [EmbedFooter, nil] footer for this embed
63
+ attr_accessor :footer
64
+
65
+ # @see EmbedImage
66
+ # @example Add a image to an embed
67
+ # embed.image = Rubycord::Webhooks::EmbedImage.new(url: 'https://i.imgur.com/PcMltU7.jpg')
68
+ # @return [EmbedImage, nil] image for this embed
69
+ attr_accessor :image
70
+
71
+ # @see EmbedThumbnail
72
+ # @example Add a thumbnail to an embed
73
+ # embed.thumbnail = Rubycord::Webhooks::EmbedThumbnail.new(url: 'https://i.imgur.com/xTG3a1I.jpg')
74
+ # @return [EmbedThumbnail, nil] thumbnail for this embed
75
+ attr_accessor :thumbnail
76
+
77
+ # @see EmbedAuthor
78
+ # @example Add a author to an embed
79
+ # embed.author = Rubycord::Webhooks::EmbedAuthor.new(name: 'meew0', url: 'https://github.com/meew0', icon_url: 'https://avatars2.githubusercontent.com/u/3662915?v=3&s=466')
80
+ # @return [EmbedAuthor, nil] author for this embed
81
+ attr_accessor :author
82
+
83
+ # Add a field object to this embed.
84
+ # @param field [EmbedField] The field to add.
85
+ def <<(field)
86
+ @fields << field
87
+ end
88
+
89
+ # Convenience method to add a field to the embed without having to create one manually.
90
+ # @see EmbedField
91
+ # @example Add a field to an embed, conveniently
92
+ # embed.add_field(name: 'A field', value: "The field's content")
93
+ # @param name [String] The field's name
94
+ # @param value [String] The field's value
95
+ # @param inline [true, false] Whether the field should be inline
96
+ def add_field(name: nil, value: nil, inline: nil)
97
+ self << EmbedField.new(name: name, value: value, inline: inline)
98
+ end
99
+
100
+ # @return [Array<EmbedField>] the fields attached to this embed.
101
+ attr_accessor :fields
102
+
103
+ # @return [Hash] a hash representation of this embed, to be converted to JSON.
104
+ def to_hash
105
+ {
106
+ title: @title,
107
+ description: @description,
108
+ url: @url,
109
+ timestamp: @timestamp&.utc&.iso8601,
110
+ color: @colour,
111
+ footer: @footer&.to_hash,
112
+ image: @image&.to_hash,
113
+ thumbnail: @thumbnail&.to_hash,
114
+ video: @video&.to_hash,
115
+ provider: @provider&.to_hash,
116
+ author: @author&.to_hash,
117
+ fields: @fields.map(&:to_hash)
118
+ }
119
+ end
120
+ end
121
+
122
+ # An embed's footer will be displayed at the very bottom of an embed, together with the timestamp. An icon URL can be
123
+ # set together with some text to be displayed.
124
+ class EmbedFooter
125
+ # @return [String, nil] text to be displayed in the footer
126
+ attr_accessor :text
127
+
128
+ # @return [String, nil] URL to an icon to be showed alongside the text
129
+ attr_accessor :icon_url
130
+
131
+ # Creates a new footer object.
132
+ # @param text [String, nil] The text to be displayed in the footer.
133
+ # @param icon_url [String, nil] The URL to an icon to be showed alongside the text.
134
+ def initialize(text: nil, icon_url: nil)
135
+ @text = text
136
+ @icon_url = icon_url
137
+ end
138
+
139
+ # @return [Hash] a hash representation of this embed footer, to be converted to JSON.
140
+ def to_hash
141
+ {
142
+ text: @text,
143
+ icon_url: @icon_url
144
+ }
145
+ end
146
+ end
147
+
148
+ # An embed's image will be displayed at the bottom, in large format. It will replace a footer icon URL if one is set.
149
+ class EmbedImage
150
+ # @return [String, nil] URL of the image
151
+ attr_accessor :url
152
+
153
+ # Creates a new image object.
154
+ # @param url [String, nil] The URL of the image.
155
+ def initialize(url: nil)
156
+ @url = url
157
+ end
158
+
159
+ # @return [Hash] a hash representation of this embed image, to be converted to JSON.
160
+ def to_hash
161
+ {
162
+ url: @url
163
+ }
164
+ end
165
+ end
166
+
167
+ # An embed's thumbnail will be displayed at the right of the message, next to the description and fields. When clicked
168
+ # it will point to the embed URL.
169
+ class EmbedThumbnail
170
+ # @return [String, nil] URL of the thumbnail
171
+ attr_accessor :url
172
+
173
+ # Creates a new thumbnail object.
174
+ # @param url [String, nil] The URL of the thumbnail.
175
+ def initialize(url: nil)
176
+ @url = url
177
+ end
178
+
179
+ # @return [Hash] a hash representation of this embed thumbnail, to be converted to JSON.
180
+ def to_hash
181
+ {
182
+ url: @url
183
+ }
184
+ end
185
+ end
186
+
187
+ # An embed's author will be shown at the top to indicate who "authored" the particular event the webhook was sent for.
188
+ class EmbedAuthor
189
+ # @return [String, nil] name of the author
190
+ attr_accessor :name
191
+
192
+ # @return [String, nil] URL the name should link to
193
+ attr_accessor :url
194
+
195
+ # @return [String, nil] URL of the icon to be displayed next to the author
196
+ attr_accessor :icon_url
197
+
198
+ # Creates a new author object.
199
+ # @param name [String, nil] The name of the author.
200
+ # @param url [String, nil] The URL the name should link to.
201
+ # @param icon_url [String, nil] The URL of the icon to be displayed next to the author.
202
+ def initialize(name: nil, url: nil, icon_url: nil)
203
+ @name = name
204
+ @url = url
205
+ @icon_url = icon_url
206
+ end
207
+
208
+ # @return [Hash] a hash representation of this embed author, to be converted to JSON.
209
+ def to_hash
210
+ {
211
+ name: @name,
212
+ url: @url,
213
+ icon_url: @icon_url
214
+ }
215
+ end
216
+ end
217
+
218
+ # A field is a small block of text with a header that can be relatively freely layouted with other fields.
219
+ class EmbedField
220
+ # @return [String, nil] name of the field, displayed in bold at the top of the field.
221
+ attr_accessor :name
222
+
223
+ # @return [String, nil] value of the field, displayed in normal text below the name.
224
+ attr_accessor :value
225
+
226
+ # @return [true, false] whether the field should be displayed inline with other fields.
227
+ attr_accessor :inline
228
+
229
+ # Creates a new field object.
230
+ # @param name [String, nil] The name of the field, displayed in bold at the top of the field.
231
+ # @param value [String, nil] The value of the field, displayed in normal text below the name.
232
+ # @param inline [true, false] Whether the field should be displayed inline with other fields.
233
+ def initialize(name: nil, value: nil, inline: false)
234
+ @name = name
235
+ @value = value
236
+ @inline = inline
237
+ end
238
+
239
+ # @return [Hash] a hash representation of this embed field, to be converted to JSON.
240
+ def to_hash
241
+ {
242
+ name: @name,
243
+ value: @value,
244
+ inline: @inline
245
+ }
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,78 @@
1
+ # Modal component builder.
2
+ class Rubycord::Webhooks::Modal
3
+ # A mapping of names to types of components usable in a modal.
4
+ COMPONENT_TYPES = {
5
+ action_row: 1,
6
+ text_input: 4
7
+ }.freeze
8
+
9
+ # This builder is used when constructing an ActionRow. All current components must be within an action row, but this can
10
+ # change in the future. A message can have 5 action rows, each action row can hold a weight of 5. Buttons have a weight of 1,
11
+ # and dropdowns have a weight of 5.
12
+ class RowBuilder
13
+ # A mapping of short names to types of input styles. `short` is a single line where `paragraph` is a block.
14
+ TEXT_INPUT_STYLES = {
15
+ short: 1,
16
+ paragraph: 2
17
+ }.freeze
18
+
19
+ # @!visibility private
20
+ def initialize
21
+ @components = []
22
+ end
23
+
24
+ # Add a text input to this action row.
25
+ # @param style [Symbol, Integer] The text input's style type. See {TEXT_INPUT_STYLES}
26
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
27
+ # There is a limit of 100 characters to each custom_id.
28
+ # @param label [String, nil] The text label for the field.
29
+ # @param min_length [Integer, nil] The minimum input length for a text input, min 0, max 4000.
30
+ # @param max_length [Integer, nil] The maximum input length for a text input, min 1, max 4000.
31
+ # @param required [true, false, nil] Whether this component is required to be filled, default true.
32
+ # @param value [String, nil] A pre-filled value for this component, max 4000 characters.
33
+ # @param placeholder [String, nil] Custom placeholder text if the input is empty, max 100 characters
34
+ def text_input(style:, custom_id:, label: nil, min_length: nil, max_length: nil, required: nil, value: nil, placeholder: nil)
35
+ style = TEXT_INPUT_STYLES[style] || style
36
+
37
+ @components << {
38
+ style: style,
39
+ custom_id: custom_id,
40
+ type: COMPONENT_TYPES[:text_input],
41
+ label: label,
42
+ min_length: min_length,
43
+ max_length: max_length,
44
+ required: required,
45
+ value: value,
46
+ placeholder: placeholder
47
+ }
48
+ end
49
+
50
+ # @!visibility private
51
+ def to_h
52
+ {type: COMPONENT_TYPES[:action_row], components: @components}
53
+ end
54
+ end
55
+
56
+ attr_reader :rows
57
+
58
+ def initialize
59
+ @rows = []
60
+
61
+ yield self if block_given?
62
+ end
63
+
64
+ # Add a new ActionRow to the view
65
+ # @yieldparam [RowBuilder]
66
+ def row
67
+ new_row = RowBuilder.new
68
+
69
+ yield new_row
70
+
71
+ @rows << new_row
72
+ end
73
+
74
+ # @!visibility private
75
+ def to_a
76
+ @rows.map(&:to_h)
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ # Webhook support for rubycord
2
+ module Rubycord
3
+ module Webhooks
4
+ # The current version of rubycord-webhooks.
5
+ VERSION = "1.0.0" unless const_defined?(:VERSION)
6
+ end
7
+ end
@@ -0,0 +1,192 @@
1
+ # A reusable view representing a component collection, with builder methods.
2
+ class Rubycord::Webhooks::View
3
+ # Possible button style names and values.
4
+ BUTTON_STYLES = {
5
+ primary: 1,
6
+ secondary: 2,
7
+ success: 3,
8
+ danger: 4,
9
+ link: 5
10
+ }.freeze
11
+
12
+ # Component types.
13
+ # @see https://discord.com/developers/docs/interactions/message-components#component-types
14
+ COMPONENT_TYPES = {
15
+ action_row: 1,
16
+ button: 2,
17
+ string_select: 3,
18
+ # text_input: 4, # (defined in modal.rb)
19
+ user_select: 5,
20
+ role_select: 6,
21
+ mentionable_select: 7,
22
+ channel_select: 8
23
+ }.freeze
24
+
25
+ # This builder is used when constructing an ActionRow. All current components must be within an action row, but this can
26
+ # change in the future. A message can have 5 action rows, each action row can hold a weight of 5. Buttons have a weight of 1,
27
+ # and dropdowns have a weight of 5.
28
+ class RowBuilder
29
+ # @!visibility private
30
+ def initialize
31
+ @components = []
32
+ end
33
+
34
+ # Add a button to this action row.
35
+ # @param style [Symbol, Integer] The button's style type. See {BUTTON_STYLES}
36
+ # @param label [String, nil] The text label for the button. Either a label or emoji must be provided.
37
+ # @param emoji [#to_h, String, Integer] An emoji ID, or unicode emoji to attach to the button. Can also be a object
38
+ # that responds to `#to_h` which returns a hash in the format of `{ id: Integer, name: string }`.
39
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
40
+ # There is a limit of 100 characters to each custom_id.
41
+ # @param disabled [true, false] Whether this button is disabled and shown as greyed out.
42
+ # @param url [String, nil] The URL, when using a link style button.
43
+ def button(style:, label: nil, emoji: nil, custom_id: nil, disabled: nil, url: nil)
44
+ style = BUTTON_STYLES[style] || style
45
+
46
+ emoji = case emoji
47
+ when Integer, String
48
+ emoji.to_i.positive? ? {id: emoji} : {name: emoji}
49
+ else
50
+ emoji&.to_h
51
+ end
52
+
53
+ @components << {type: COMPONENT_TYPES[:button], label: label, emoji: emoji, style: style, custom_id: custom_id, disabled: disabled, url: url}
54
+ end
55
+
56
+ # Add a select string to this action row.
57
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
58
+ # There is a limit of 100 characters to each custom_id.
59
+ # @param options [Array<Hash>] Options that can be selected in this menu. Can also be provided via the yielded builder.
60
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
61
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
62
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
63
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
64
+ # @yieldparam builder [SelectMenuBuilder]
65
+ def string_select(custom_id:, options: [], placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
66
+ builder = SelectMenuBuilder.new(custom_id, options, placeholder, min_values, max_values, disabled, select_type: :string_select)
67
+
68
+ yield builder if block_given?
69
+
70
+ @components << builder.to_h
71
+ end
72
+
73
+ alias_method :select_menu, :string_select
74
+
75
+ # Add a select user to this action row.
76
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
77
+ # There is a limit of 100 characters to each custom_id.
78
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
79
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
80
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
81
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
82
+ def user_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
83
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :user_select).to_h
84
+ end
85
+
86
+ # Add a select role to this action row.
87
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
88
+ # There is a limit of 100 characters to each custom_id.
89
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
90
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
91
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
92
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
93
+ def role_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
94
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :role_select).to_h
95
+ end
96
+
97
+ # Add a select mentionable to this action row.
98
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
99
+ # There is a limit of 100 characters to each custom_id.
100
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
101
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
102
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
103
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
104
+ def mentionable_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
105
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :mentionable_select).to_h
106
+ end
107
+
108
+ # Add a select channel to this action row.
109
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
110
+ # There is a limit of 100 characters to each custom_id.
111
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
112
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
113
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
114
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
115
+ def channel_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
116
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :channel_select).to_h
117
+ end
118
+
119
+ # @!visibility private
120
+ def to_h
121
+ {type: COMPONENT_TYPES[:action_row], components: @components}
122
+ end
123
+ end
124
+
125
+ # A builder to assist in adding options to select menus.
126
+ class SelectMenuBuilder
127
+ # @!visibility hidden
128
+ def initialize(custom_id, options = [], placeholder = nil, min_values = nil, max_values = nil, disabled = nil, select_type: :string_select)
129
+ @custom_id = custom_id
130
+ @options = options
131
+ @placeholder = placeholder
132
+ @min_values = min_values
133
+ @max_values = max_values
134
+ @disabled = disabled
135
+ @select_type = select_type
136
+ end
137
+
138
+ # Add an option to this select menu.
139
+ # @param label [String] The title of this option.
140
+ # @param value [String] The value that this option represents.
141
+ # @param description [String, nil] An optional description of the option.
142
+ # @param emoji [#to_h, String, Integer] An emoji ID, or unicode emoji to attach to the button. Can also be a object
143
+ # that responds to `#to_h` which returns a hash in the format of `{ id: Integer, name: string }`.
144
+ # @param default [true, false, nil] Whether this is the default selected option.
145
+ def option(label:, value:, description: nil, emoji: nil, default: nil)
146
+ emoji = case emoji
147
+ when Integer, String
148
+ emoji.to_i.positive? ? {id: emoji} : {name: emoji}
149
+ else
150
+ emoji&.to_h
151
+ end
152
+
153
+ @options << {label: label, value: value, description: description, emoji: emoji, default: default}
154
+ end
155
+
156
+ # @!visibility private
157
+ def to_h
158
+ {
159
+ type: COMPONENT_TYPES[@select_type],
160
+ options: @options,
161
+ placeholder: @placeholder,
162
+ min_values: @min_values,
163
+ max_values: @max_values,
164
+ custom_id: @custom_id,
165
+ disabled: @disabled
166
+ }
167
+ end
168
+ end
169
+
170
+ attr_reader :rows
171
+
172
+ def initialize
173
+ @rows = []
174
+
175
+ yield self if block_given?
176
+ end
177
+
178
+ # Add a new ActionRow to the view
179
+ # @yieldparam [RowBuilder]
180
+ def row
181
+ new_row = RowBuilder.new
182
+
183
+ yield new_row
184
+
185
+ @rows << new_row
186
+ end
187
+
188
+ # @!visibility private
189
+ def to_a
190
+ @rows.map(&:to_h)
191
+ end
192
+ end
@@ -0,0 +1,12 @@
1
+ require "rubycord/webhooks/version"
2
+ require "rubycord/webhooks/embeds"
3
+ require "rubycord/webhooks/client"
4
+ require "rubycord/webhooks/builder"
5
+ require "rubycord/webhooks/view"
6
+ require "rubycord/webhooks/modal"
7
+
8
+ module Rubycord
9
+ # Webhook client
10
+ module Webhooks
11
+ end
12
+ end
@@ -0,0 +1,70 @@
1
+ require "websocket-client-simple"
2
+
3
+ # The WSCS module which we're hooking
4
+ # @see Websocket::Client::Simple::Client
5
+ module WebSocket::Client::Simple
6
+ # Patch to the WSCS class to allow reading the internal thread
7
+ class Client
8
+ # @return [Thread] the internal thread this client is using for the event loop.
9
+ attr_reader :thread
10
+ end
11
+ end
12
+
13
+ module Rubycord
14
+ # Utility wrapper class that abstracts an instance of WSCS. Useful should we decide that WSCS isn't good either -
15
+ # in that case we can just switch to something else
16
+ class WebSocket
17
+ attr_reader :open_handler, :message_handler, :close_handler, :error_handler
18
+
19
+ # Create a new WebSocket and connect to the given endpoint.
20
+ # @param endpoint [String] Where to connect to.
21
+ # @param open_handler [#call] The handler that should be called when the websocket has opened successfully.
22
+ # @param message_handler [#call] The handler that should be called when the websocket receives a message. The
23
+ # handler can take one parameter which will have a `data` attribute for normal messages and `code` and `data` for
24
+ # close frames.
25
+ # @param close_handler [#call] The handler that should be called when the websocket is closed due to an internal
26
+ # error. The error will be passed as the first parameter to the handler.
27
+ # @param error_handler [#call] The handler that should be called when an error occurs in another handler. The error
28
+ # will be passed as the first parameter to the handler.
29
+ def initialize(endpoint, open_handler, message_handler, close_handler, error_handler)
30
+ Rubycord::LOGGER.debug "Using WSCS version: #{::WebSocket::Client::Simple::VERSION}"
31
+
32
+ @open_handler = open_handler
33
+ @message_handler = message_handler
34
+ @close_handler = close_handler
35
+ @error_handler = error_handler
36
+
37
+ instance = self # to work around WSCS's weird way of handling blocks
38
+
39
+ @client = ::WebSocket::Client::Simple.connect(endpoint) do |ws|
40
+ ws.on(:open) { instance.open_handler.call }
41
+ ws.on(:message) do |msg|
42
+ # If the message has a code attribute, it is in reality a close message
43
+ if msg.code
44
+ instance.close_handler.call(msg)
45
+ else
46
+ instance.message_handler.call(msg.data)
47
+ end
48
+ end
49
+ ws.on(:close) { |err| instance.close_handler.call(err) }
50
+ ws.on(:error) { |err| instance.error_handler.call(err) }
51
+ end
52
+ end
53
+
54
+ # Send data over this WebSocket
55
+ # @param data [String] What to send
56
+ def send(data)
57
+ @client.send(data)
58
+ end
59
+
60
+ # Close the WebSocket connection
61
+ def close
62
+ @client.close
63
+ end
64
+
65
+ # @return [Thread] the internal WSCS thread
66
+ def thread
67
+ @client.thread
68
+ end
69
+ end
70
+ end