onyxcord 2.0.13 → 3.2.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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/lib/onyxcord/application_commands/command.rb +4 -97
  3. data/lib/onyxcord/application_commands/context.rb +4 -94
  4. data/lib/onyxcord/application_commands/option.rb +4 -75
  5. data/lib/onyxcord/application_commands/registry.rb +4 -45
  6. data/lib/onyxcord/application_commands.rb +8 -5
  7. data/lib/onyxcord/bot.rb +24 -1759
  8. data/lib/onyxcord/{cache.rb → cache/manager.rb} +16 -14
  9. data/lib/onyxcord/cache/stores/gateway.rb +272 -0
  10. data/lib/onyxcord/commands/bot/channels.rb +48 -0
  11. data/lib/onyxcord/commands/bot/execution.rb +174 -0
  12. data/lib/onyxcord/commands/bot/message_dispatch.rb +58 -0
  13. data/lib/onyxcord/commands/bot/permissions.rb +72 -0
  14. data/lib/onyxcord/commands/bot.rb +209 -0
  15. data/lib/onyxcord/commands/container.rb +21 -2
  16. data/lib/onyxcord/commands/parser.rb +30 -1
  17. data/lib/onyxcord/container.rb +16 -960
  18. data/lib/onyxcord/core/bot/application_commands.rb +210 -0
  19. data/lib/onyxcord/core/bot/awaits.rb +112 -0
  20. data/lib/onyxcord/core/bot/invites.rb +42 -0
  21. data/lib/onyxcord/core/bot/messaging.rb +161 -0
  22. data/lib/onyxcord/core/bot/oauth.rb +27 -0
  23. data/lib/onyxcord/core/bot/presence.rb +103 -0
  24. data/lib/onyxcord/core/bot/runtime.rb +183 -0
  25. data/lib/onyxcord/core/bot/voice.rb +69 -0
  26. data/lib/onyxcord/{errors.rb → core/errors.rb} +18 -3
  27. data/lib/onyxcord/{logger.rb → core/logger.rb} +5 -0
  28. data/lib/onyxcord/core/version.rb +5 -0
  29. data/lib/onyxcord/events/await/base.rb +48 -0
  30. data/lib/onyxcord/events/await.rb +1 -46
  31. data/lib/onyxcord/events/ban/base.rb +54 -0
  32. data/lib/onyxcord/events/ban/remove.rb +11 -0
  33. data/lib/onyxcord/events/bans.rb +2 -58
  34. data/lib/onyxcord/events/channels/base.rb +91 -0
  35. data/lib/onyxcord/events/channels/delete.rb +73 -0
  36. data/lib/onyxcord/events/channels/pins.rb +44 -0
  37. data/lib/onyxcord/events/channels/recipients.rb +77 -0
  38. data/lib/onyxcord/events/channels.rb +4 -239
  39. data/lib/onyxcord/events/guilds/audit_logs.rb +79 -0
  40. data/lib/onyxcord/events/guilds/base.rb +97 -0
  41. data/lib/onyxcord/events/guilds/emoji.rb +147 -0
  42. data/lib/onyxcord/events/guilds.rb +3 -267
  43. data/lib/onyxcord/events/handlers/channels.rb +133 -0
  44. data/lib/onyxcord/events/handlers/core.rb +146 -0
  45. data/lib/onyxcord/events/handlers/guilds.rb +375 -0
  46. data/lib/onyxcord/events/handlers/interactions.rb +238 -0
  47. data/lib/onyxcord/events/handlers/lifetime.rb +71 -0
  48. data/lib/onyxcord/events/handlers/messages.rb +218 -0
  49. data/lib/onyxcord/events/handlers/presence.rb +56 -0
  50. data/lib/onyxcord/events/handlers/raw.rb +39 -0
  51. data/lib/onyxcord/events/handlers/reactions.rb +98 -0
  52. data/lib/onyxcord/events/handlers/scheduled_events.rb +243 -0
  53. data/lib/onyxcord/events/handlers/voice.rb +46 -0
  54. data/lib/onyxcord/events/integration/base.rb +45 -0
  55. data/lib/onyxcord/events/integration/create.rb +11 -0
  56. data/lib/onyxcord/events/integration/delete.rb +48 -0
  57. data/lib/onyxcord/events/integration/update.rb +11 -0
  58. data/lib/onyxcord/events/integrations.rb +4 -98
  59. data/lib/onyxcord/events/interactions/application_commands.rb +185 -0
  60. data/lib/onyxcord/events/interactions/autocomplete.rb +62 -0
  61. data/lib/onyxcord/events/interactions/base.rb +175 -0
  62. data/lib/onyxcord/events/interactions/components.rb +221 -0
  63. data/lib/onyxcord/events/interactions/permissions.rb +53 -0
  64. data/lib/onyxcord/events/interactions.rb +5 -622
  65. data/lib/onyxcord/events/invite/create.rb +79 -0
  66. data/lib/onyxcord/events/invite/delete.rb +55 -0
  67. data/lib/onyxcord/events/invites.rb +2 -125
  68. data/lib/onyxcord/events/lifetime/base.rb +31 -0
  69. data/lib/onyxcord/events/lifetime.rb +1 -29
  70. data/lib/onyxcord/events/member/add.rb +12 -0
  71. data/lib/onyxcord/events/member/base.rb +67 -0
  72. data/lib/onyxcord/events/member/delete.rb +21 -0
  73. data/lib/onyxcord/events/member/update.rb +25 -0
  74. data/lib/onyxcord/events/members.rb +4 -108
  75. data/lib/onyxcord/events/message/base.rb +295 -0
  76. data/lib/onyxcord/events/message/ids.rb +71 -0
  77. data/lib/onyxcord/events/message/mentions.rb +55 -0
  78. data/lib/onyxcord/events/message/updates.rb +27 -0
  79. data/lib/onyxcord/events/message.rb +4 -397
  80. data/lib/onyxcord/events/poll/add.rb +11 -0
  81. data/lib/onyxcord/events/poll/base.rb +106 -0
  82. data/lib/onyxcord/events/poll/remove.rb +11 -0
  83. data/lib/onyxcord/events/polls.rb +3 -116
  84. data/lib/onyxcord/events/presence/playing.rb +77 -0
  85. data/lib/onyxcord/events/presence/status.rb +60 -0
  86. data/lib/onyxcord/events/presence.rb +2 -129
  87. data/lib/onyxcord/events/raw/base.rb +74 -0
  88. data/lib/onyxcord/events/raw.rb +1 -72
  89. data/lib/onyxcord/events/reactions/base.rb +143 -0
  90. data/lib/onyxcord/events/reactions/clear.rb +99 -0
  91. data/lib/onyxcord/events/reactions.rb +2 -216
  92. data/lib/onyxcord/events/role/create.rb +46 -0
  93. data/lib/onyxcord/events/role/delete.rb +40 -0
  94. data/lib/onyxcord/events/role/update.rb +11 -0
  95. data/lib/onyxcord/events/roles.rb +3 -85
  96. data/lib/onyxcord/events/scheduled_events/events.rb +112 -0
  97. data/lib/onyxcord/events/scheduled_events/users.rb +91 -0
  98. data/lib/onyxcord/events/scheduled_events.rb +2 -169
  99. data/lib/onyxcord/events/thread/base.rb +49 -0
  100. data/lib/onyxcord/events/thread/members.rb +44 -0
  101. data/lib/onyxcord/events/thread/update.rb +18 -0
  102. data/lib/onyxcord/events/threads.rb +3 -98
  103. data/lib/onyxcord/events/typing/base.rb +73 -0
  104. data/lib/onyxcord/events/typing.rb +1 -71
  105. data/lib/onyxcord/events/voice/server_update.rb +48 -0
  106. data/lib/onyxcord/events/voice/state_update.rb +137 -0
  107. data/lib/onyxcord/events/voice_server_update.rb +2 -46
  108. data/lib/onyxcord/events/voice_state_update.rb +2 -135
  109. data/lib/onyxcord/events/webhook/update.rb +65 -0
  110. data/lib/onyxcord/events/webhooks.rb +1 -63
  111. data/lib/onyxcord/gateway/client.rb +460 -0
  112. data/lib/onyxcord/interactions/command.rb +120 -0
  113. data/lib/onyxcord/interactions/context.rb +109 -0
  114. data/lib/onyxcord/interactions/internal/application_command.rb +203 -0
  115. data/lib/onyxcord/interactions/internal/message.rb +152 -0
  116. data/lib/onyxcord/interactions/internal/metadata.rb +109 -0
  117. data/lib/onyxcord/interactions/internal/option_builder.rb +230 -0
  118. data/lib/onyxcord/interactions/internal/permission_builder.rb +90 -0
  119. data/lib/onyxcord/interactions/option.rb +88 -0
  120. data/lib/onyxcord/interactions/registry.rb +50 -0
  121. data/lib/onyxcord/interactions.rb +16 -0
  122. data/lib/onyxcord/internal/async_runtime.rb +32 -0
  123. data/lib/onyxcord/internal/event_bus.rb +591 -0
  124. data/lib/onyxcord/internal/event_executor.rb +155 -0
  125. data/lib/onyxcord/internal/gateway/opcodes.rb +22 -0
  126. data/lib/onyxcord/internal/gateway/session.rb +45 -0
  127. data/lib/onyxcord/internal/http.rb +189 -0
  128. data/lib/onyxcord/internal/json.rb +51 -0
  129. data/lib/onyxcord/internal/message_payload.rb +78 -0
  130. data/lib/onyxcord/internal/rate_limiter/async_rest.rb +151 -0
  131. data/lib/onyxcord/internal/rate_limiter/gateway.rb +44 -0
  132. data/lib/onyxcord/internal/rate_limiter/rest.rb +144 -0
  133. data/lib/onyxcord/internal/upload.rb +39 -0
  134. data/lib/onyxcord/internal/websocket.rb +79 -0
  135. data/lib/onyxcord/light/data.rb +1 -1
  136. data/lib/onyxcord/light/integrations.rb +1 -1
  137. data/lib/onyxcord/light/light_bot.rb +7 -7
  138. data/lib/onyxcord/{data → models}/activity.rb +2 -2
  139. data/lib/onyxcord/{data → models}/application.rb +3 -3
  140. data/lib/onyxcord/{data → models}/avatar_decoration.rb +1 -1
  141. data/lib/onyxcord/{data → models}/channel.rb +23 -23
  142. data/lib/onyxcord/{data → models}/collectibles.rb +1 -1
  143. data/lib/onyxcord/{data → models}/emoji.rb +1 -1
  144. data/lib/onyxcord/models/interaction.rb +450 -0
  145. data/lib/onyxcord/{data → models}/invite.rb +1 -1
  146. data/lib/onyxcord/{data → models}/member.rb +11 -11
  147. data/lib/onyxcord/{data → models}/message.rb +22 -14
  148. data/lib/onyxcord/{data → models}/poll.rb +2 -2
  149. data/lib/onyxcord/{data → models}/primary_server.rb +1 -1
  150. data/lib/onyxcord/{data → models}/profile.rb +4 -4
  151. data/lib/onyxcord/{data → models}/role.rb +6 -12
  152. data/lib/onyxcord/{data → models}/scheduled_event.rb +5 -5
  153. data/lib/onyxcord/{data → models}/server.rb +41 -41
  154. data/lib/onyxcord/{data → models}/server_preview.rb +2 -2
  155. data/lib/onyxcord/{data → models}/team.rb +1 -1
  156. data/lib/onyxcord/{data → models}/user.rb +5 -5
  157. data/lib/onyxcord/{data → models}/webhook.rb +13 -11
  158. data/lib/onyxcord/models.rb +57 -0
  159. data/lib/onyxcord/{api.rb → rest/client.rb} +83 -27
  160. data/lib/onyxcord/{api → rest/routes}/application.rb +79 -57
  161. data/lib/onyxcord/rest/routes/channel/base.rb +73 -0
  162. data/lib/onyxcord/rest/routes/channel/groups.rb +78 -0
  163. data/lib/onyxcord/rest/routes/channel/messages.rb +130 -0
  164. data/lib/onyxcord/rest/routes/channel/permissions.rb +73 -0
  165. data/lib/onyxcord/rest/routes/channel/pins.rb +45 -0
  166. data/lib/onyxcord/rest/routes/channel/polls.rb +32 -0
  167. data/lib/onyxcord/rest/routes/channel/reactions.rb +86 -0
  168. data/lib/onyxcord/rest/routes/channel/threads.rb +176 -0
  169. data/lib/onyxcord/rest/routes/channel/webhooks.rb +47 -0
  170. data/lib/onyxcord/rest/routes/channel.rb +12 -0
  171. data/lib/onyxcord/{api/interaction.rb → rest/routes/interaction/base.rb} +10 -33
  172. data/lib/onyxcord/rest/routes/interaction/response.rb +24 -0
  173. data/lib/onyxcord/rest/routes/interaction.rb +4 -0
  174. data/lib/onyxcord/{api → rest/routes}/invite.rb +7 -7
  175. data/lib/onyxcord/rest/routes/server/admin.rb +174 -0
  176. data/lib/onyxcord/rest/routes/server/assets.rb +25 -0
  177. data/lib/onyxcord/rest/routes/server/bans.rb +67 -0
  178. data/lib/onyxcord/rest/routes/server/base.rb +77 -0
  179. data/lib/onyxcord/rest/routes/server/channels.rb +58 -0
  180. data/lib/onyxcord/rest/routes/server/emoji.rb +48 -0
  181. data/lib/onyxcord/rest/routes/server/members.rb +109 -0
  182. data/lib/onyxcord/rest/routes/server/messages.rb +19 -0
  183. data/lib/onyxcord/rest/routes/server/roles.rb +156 -0
  184. data/lib/onyxcord/rest/routes/server/scheduled_events.rb +86 -0
  185. data/lib/onyxcord/rest/routes/server.rb +12 -0
  186. data/lib/onyxcord/{api → rest/routes}/user.rb +23 -23
  187. data/lib/onyxcord/{api → rest/routes}/webhook.rb +30 -32
  188. data/lib/onyxcord/{allowed_mentions.rb → utils/allowed_mentions.rb} +9 -1
  189. data/lib/onyxcord/utils/timestamp.rb +69 -0
  190. data/lib/onyxcord/voice/{voice_bot.rb → client.rb} +4 -4
  191. data/lib/onyxcord/voice/encoder.rb +1 -1
  192. data/lib/onyxcord/voice/network/udp.rb +135 -0
  193. data/lib/onyxcord/voice/network/websocket.rb +225 -0
  194. data/lib/onyxcord/voice/network.rb +5 -357
  195. data/lib/onyxcord/webhooks/builder.rb +1 -1
  196. data/lib/onyxcord/webhooks/client.rb +13 -13
  197. data/lib/onyxcord/webhooks/modal/group_builder.rb +55 -0
  198. data/lib/onyxcord/webhooks/modal/label_builder.rb +183 -0
  199. data/lib/onyxcord/webhooks/modal.rb +2 -239
  200. data/lib/onyxcord/webhooks/version.rb +3 -3
  201. data/lib/onyxcord/webhooks/view/container_builder.rb +80 -0
  202. data/lib/onyxcord/webhooks/view/file_builder.rb +24 -0
  203. data/lib/onyxcord/webhooks/view/media_gallery_builder.rb +50 -0
  204. data/lib/onyxcord/webhooks/view/row_builder.rb +120 -0
  205. data/lib/onyxcord/webhooks/view/section_builder.rb +61 -0
  206. data/lib/onyxcord/webhooks/view/select_menu_builder.rb +77 -0
  207. data/lib/onyxcord/webhooks/view/separator_builder.rb +22 -0
  208. data/lib/onyxcord/webhooks/view/text_display_builder.rb +20 -0
  209. data/lib/onyxcord/webhooks/view.rb +9 -425
  210. data/lib/onyxcord.rb +106 -40
  211. metadata +208 -91
  212. data/.github/CONTRIBUTING.md +0 -13
  213. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  214. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
  215. data/.github/pull_request_template.md +0 -37
  216. data/.github/workflows/ci.yml +0 -78
  217. data/.github/workflows/codeql.yml +0 -65
  218. data/.github/workflows/deploy.yml +0 -54
  219. data/.github/workflows/release.yml +0 -51
  220. data/.gitignore +0 -17
  221. data/.markdownlint.json +0 -4
  222. data/.overcommit.yml +0 -7
  223. data/.rspec +0 -2
  224. data/.rubocop.yml +0 -129
  225. data/.yardopts +0 -1
  226. data/CHANGELOG.md +0 -202
  227. data/Gemfile +0 -6
  228. data/LICENSE.txt +0 -21
  229. data/README.md +0 -448
  230. data/Rakefile +0 -13
  231. data/lib/onyxcord/api/channel.rb +0 -705
  232. data/lib/onyxcord/api/server.rb +0 -775
  233. data/lib/onyxcord/async/runtime.rb +0 -30
  234. data/lib/onyxcord/commands/command_bot.rb +0 -505
  235. data/lib/onyxcord/data/interaction.rb +0 -1143
  236. data/lib/onyxcord/data.rb +0 -57
  237. data/lib/onyxcord/event_executor.rb +0 -153
  238. data/lib/onyxcord/gateway.rb +0 -500
  239. data/lib/onyxcord/http.rb +0 -115
  240. data/lib/onyxcord/json.rb +0 -49
  241. data/lib/onyxcord/rate_limiter/async_rest.rb +0 -149
  242. data/lib/onyxcord/rate_limiter/gateway.rb +0 -42
  243. data/lib/onyxcord/rate_limiter/rest.rb +0 -142
  244. data/lib/onyxcord/version.rb +0 -7
  245. data/lib/onyxcord/websocket.rb +0 -77
  246. data/onyxcord.gemspec +0 -63
  247. /data/lib/onyxcord/{configuration.rb → core/configuration.rb} +0 -0
  248. /data/lib/onyxcord/{data → models}/attachment.rb +0 -0
  249. /data/lib/onyxcord/{data → models}/audit_logs.rb +0 -0
  250. /data/lib/onyxcord/{data → models}/call.rb +0 -0
  251. /data/lib/onyxcord/{data → models}/channel_tag.rb +0 -0
  252. /data/lib/onyxcord/{data → models}/component.rb +0 -0
  253. /data/lib/onyxcord/{data → models}/embed.rb +0 -0
  254. /data/lib/onyxcord/{data → models}/install_params.rb +0 -0
  255. /data/lib/onyxcord/{data → models}/integration.rb +0 -0
  256. /data/lib/onyxcord/{data → models}/message_activity.rb +0 -0
  257. /data/lib/onyxcord/{data → models}/overwrite.rb +0 -0
  258. /data/lib/onyxcord/{data → models}/reaction.rb +0 -0
  259. /data/lib/onyxcord/{data → models}/recipient.rb +0 -0
  260. /data/lib/onyxcord/{data → models}/role_connection_data.rb +0 -0
  261. /data/lib/onyxcord/{data → models}/role_subscription.rb +0 -0
  262. /data/lib/onyxcord/{data → models}/snapshot.rb +0 -0
  263. /data/lib/onyxcord/{data → models}/timestamp.rb +0 -0
  264. /data/lib/onyxcord/{data → models}/voice_region.rb +0 -0
  265. /data/lib/onyxcord/{data → models}/voice_state.rb +0 -0
  266. /data/lib/onyxcord/{colour_rgb.rb → utils/colour_rgb.rb} +0 -0
  267. /data/lib/onyxcord/{id_object.rb → utils/id_object.rb} +0 -0
  268. /data/lib/onyxcord/{message_components.rb → utils/message_components.rb} +0 -0
  269. /data/lib/onyxcord/{paginator.rb → utils/paginator.rb} +0 -0
  270. /data/lib/onyxcord/{permissions.rb → utils/permissions.rb} +0 -0
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ class Bot
5
+ module Runtime
6
+ # Runs the bot, which logs into Discord and connects the WebSocket. This
7
+ # prevents all further execution unless it is executed with
8
+ # `background` = `true`.
9
+ # @param background [true, false] If it is `true`, then the bot will run in
10
+ # another thread to allow further execution. If it is `false`, this method
11
+ # will block until {#stop} is called. If the bot is run with `true`, make
12
+ # sure to eventually call {#join} so the script doesn't stop prematurely.
13
+ # @note Running the bot in the background means that you can call some
14
+ # methods that require a gateway connection *before* that connection is
15
+ # established. In most cases an exception will be raised if you try to do
16
+ # this. If you need a way to safely run code after the bot is fully
17
+ # connected, use a {#ready} event handler instead.
18
+ def run(background = false)
19
+ if background
20
+ @run_task = Internal::AsyncRuntime.async { run_forever }
21
+ return @run_task
22
+ end
23
+
24
+ Internal::AsyncRuntime.run { run_forever }
25
+ end
26
+
27
+ def run_forever
28
+ @gateway.run
29
+ end
30
+
31
+ def join
32
+ @run_task&.wait
33
+ end
34
+ alias_method :sync, :join
35
+
36
+ def stop(_no_sync = nil)
37
+ @gateway.stop
38
+ @event_executor.shutdown
39
+ @run_task&.stop if @run_task.respond_to?(:stop)
40
+ nil
41
+ end
42
+
43
+ # @return [true, false] whether or not the bot is currently connected to Discord.
44
+ def connected?
45
+ @gateway.open?
46
+ end
47
+
48
+ # Sets debug mode. If debug mode is on, many things will be outputted to STDOUT.
49
+ def debug=(new_debug)
50
+ LOGGER.debug = new_debug
51
+ end
52
+
53
+ # Sets the logging mode
54
+ # @see Logger#mode=
55
+ def mode=(new_mode)
56
+ LOGGER.mode = new_mode
57
+ end
58
+
59
+ def runtime_stats
60
+ {
61
+ mode: @mode,
62
+ cache: cache_stats,
63
+ event_executor: @event_executor.class.name,
64
+ event_threads: @event_threads&.count(&:alive?) || 0,
65
+ event_queue_size: @event_executor.respond_to?(:queue_size) ? @event_executor.queue_size : 0
66
+ }
67
+ end
68
+
69
+ # Prevents the READY packet from being printed regardless of debug mode.
70
+ def suppress_ready_debug
71
+ @prevent_ready = true
72
+ end
73
+
74
+ private
75
+
76
+ # Throws a useful exception if there's currently no gateway connection.
77
+ def gateway_check
78
+ 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?
79
+ end
80
+
81
+ # Logs a warning if there are servers which are still unavailable.
82
+ # e.g. due to a Discord outage or because the servers are large and taking a while to load.
83
+ def unavailable_servers_check
84
+ # Return unless there are servers that are unavailable.
85
+ return unless @unavailable_servers&.positive?
86
+
87
+ LOGGER.warn("#{@unavailable_servers} servers haven't been cached yet.")
88
+ 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.')
89
+ end
90
+
91
+ def process_token(type, token)
92
+ # Remove the "Bot " prefix if it exists
93
+ token = token[4..] if token.start_with? 'Bot '
94
+
95
+ token = "Bot #{token}" unless type == :user
96
+ token
97
+ end
98
+
99
+ # Notifies everything there is to be notified that the connection is now ready
100
+ def notify_ready
101
+ if @mode == :raw
102
+ notify_raw_ready
103
+ return
104
+ end
105
+
106
+ # Make sure to raise the event
107
+ raise_event(ReadyEvent.new(self))
108
+ LOGGER.good 'Ready'
109
+
110
+ @gateway.notify_ready
111
+ end
112
+
113
+ def raise_event(event)
114
+ debug("Raised a #{event.class}")
115
+ handle_awaits(event)
116
+
117
+ @event_handlers ||= {}
118
+ handlers = @event_handlers[event.class]
119
+ return unless handlers
120
+
121
+ handlers.dup.each do |handler|
122
+ call_event(handler, event) if handler.matches?(event)
123
+ end
124
+ end
125
+
126
+ def call_event(handler, event)
127
+ @event_executor.post do
128
+ Thread.current[:onyxcord_name] = next_event_thread_name('et')
129
+ begin
130
+ handler.call(event)
131
+ handler.after_call(event)
132
+ rescue StandardError => e
133
+ log_exception(e)
134
+ end
135
+ end
136
+ end
137
+
138
+ def handle_awaits(event)
139
+ @awaits ||= {}
140
+ @awaits.each_value do |await|
141
+ key, should_delete = await.match(event)
142
+ next unless key
143
+
144
+ debug("should_delete: #{should_delete}")
145
+ @awaits.delete(await.key) if should_delete
146
+
147
+ await_event = OnyxCord::Events::AwaitEvent.new(await, event, self)
148
+ raise_event(await_event)
149
+ end
150
+ end
151
+
152
+ def calculate_intents(intents)
153
+ intents = [intents] unless intents.is_a? Array
154
+
155
+ intents.reduce(0) do |sum, intent|
156
+ case intent
157
+ when Symbol
158
+ intent = INTENT_ALIASES[intent] || intent
159
+
160
+ if INTENTS[intent]
161
+ sum | INTENTS[intent]
162
+ else
163
+ LOGGER.warn("Unknown intent: #{intent}")
164
+ sum
165
+ end
166
+ when Integer
167
+ sum | intent
168
+ else
169
+ LOGGER.warn("Invalid intent: #{intent}")
170
+ sum
171
+ end
172
+ end
173
+ end
174
+
175
+ def next_event_thread_name(prefix)
176
+ @current_thread_mutex.synchronize do
177
+ @current_thread += 1
178
+ "#{prefix}-#{@current_thread}"
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ class Bot
5
+ module VoiceControl
6
+ # @return [Hash<Integer => Client>] the voice connections this bot currently has, by the server ID to which they are connected.
7
+ attr_reader :voices
8
+
9
+ # Gets the voice bot for a particular server or channel. You can connect to a new channel using the {#voice_connect}
10
+ # method.
11
+ # @param thing [Channel, Server, Integer] the server or channel you want to get the voice bot for, or its ID.
12
+ # @return [Voice::Client, nil] the Client for the thing you specified, or nil if there is no connection yet
13
+ def voice(thing)
14
+ id = thing.resolve_id
15
+ return @voices[id] if @voices[id]
16
+
17
+ channel = channel(id)
18
+ return nil unless channel
19
+
20
+ server_id = channel.server.id
21
+ return @voices[server_id] if @voices[server_id]
22
+ end
23
+
24
+ # Connects to a voice channel, initializes network connections and returns the {Voice::Client} over which audio
25
+ # data can then be sent. After connecting, the bot can also be accessed using {#voice}. If the bot is already
26
+ # connected to voice, the existing connection will be terminated - you don't have to call
27
+ # {OnyxCord::Voice::Client#destroy} before calling this method.
28
+ # @param chan [Channel, String, Integer] The voice channel, or its ID, to connect to.
29
+ # @param encrypted [true, false] Whether voice communication should be encrypted using
30
+ # (uses an XSalsa20 stream cipher for encryption and Poly1305 for authentication)
31
+ # @return [Voice::Client] the initialized bot over which audio data can then be sent.
32
+ def voice_connect(chan, encrypted = true)
33
+ raise ArgumentError, 'Unencrypted voice connections are no longer supported.' unless encrypted
34
+
35
+ chan = channel(chan.resolve_id)
36
+ server_id = chan.server.id
37
+
38
+ if @voices[chan.id]
39
+ debug('Voice bot exists already! Destroying it')
40
+ @voices[chan.id].destroy
41
+ @voices.delete(chan.id)
42
+ end
43
+
44
+ debug("Got voice channel: #{chan}")
45
+
46
+ @should_connect_to_voice[server_id] = chan
47
+ @gateway.send_voice_state_update(server_id.to_s, chan.id.to_s, false, false)
48
+
49
+ debug('Voice channel init packet sent! Now waiting.')
50
+
51
+ Internal::AsyncRuntime.sleep(0.05) until @voices[server_id]
52
+ debug('Voice connect succeeded!')
53
+ @voices[server_id]
54
+ end
55
+
56
+ # Disconnects the client from a specific voice connection given the server ID. Usually it's more convenient to use
57
+ # {OnyxCord::Voice::Client#destroy} rather than this.
58
+ # @param server [Server, String, Integer] The server, or server ID, the voice connection is on.
59
+ # @param destroy_vws [true, false] Whether or not the VWS should also be destroyed. If you're calling this method
60
+ # directly, you should leave it as true.
61
+ def voice_destroy(server, destroy_vws = true)
62
+ server = server.resolve_id
63
+ @gateway.send_voice_state_update(server.to_s, nil, false, false)
64
+ @voices[server].destroy if @voices[server] && destroy_vws
65
+ @voices.delete(server)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -14,8 +14,22 @@ module OnyxCord
14
14
  # Raised when a message is over the character limit
15
15
  class MessageTooLong < RuntimeError; end
16
16
 
17
+ class HTTPError < RuntimeError
18
+ attr_reader :status, :code, :headers, :route, :body, :response
19
+
20
+ def initialize(message = nil, status: nil, code: 0, headers: {}, route: nil, body: nil, response: nil)
21
+ super(message)
22
+ @status = status
23
+ @code = code || 0
24
+ @headers = headers
25
+ @route = route
26
+ @body = body
27
+ @response = response
28
+ end
29
+ end
30
+
17
31
  # Raised when the bot can't do something because its permissions on the server are insufficient
18
- class NoPermission < RuntimeError; end
32
+ class NoPermission < HTTPError; end
19
33
 
20
34
  # Raised when the bot gets a HTTP 502 error, which is usually caused by Cloudflare.
21
35
  class CloudflareError < RuntimeError; end
@@ -24,7 +38,7 @@ module OnyxCord
24
38
  class UnauthorizedWebhook < RuntimeError; end
25
39
 
26
40
  # Generic class for errors denoted by API error codes
27
- class CodeError < RuntimeError
41
+ class CodeError < HTTPError
28
42
  class << self
29
43
  # @return [Integer] The error code represented by this error class.
30
44
  attr_reader :code
@@ -33,10 +47,11 @@ module OnyxCord
33
47
  # Create a new error with a particular message (the code should be defined by the class instance variable)
34
48
  # @param message [String] the message to use
35
49
  # @param errors [Hash] API errors
36
- def initialize(message, errors = nil)
50
+ def initialize(message, errors = nil, status: nil, headers: {}, route: nil, body: nil, response: nil)
37
51
  @message = message
38
52
 
39
53
  @errors = errors ? flatten_errors(errors) : []
54
+ super(full_message, status: status, code: code, headers: headers, route: route, body: body, response: response)
40
55
  end
41
56
 
42
57
  # @return [Integer] The error code represented by this error.
@@ -81,6 +81,11 @@ module OnyxCord
81
81
  # Logs an exception to the console.
82
82
  # @param e [Exception] The exception to log.
83
83
  def log_exception(e)
84
+ if defined?(OnyxCord::Errors::UnknownMessage) && e.is_a?(OnyxCord::Errors::UnknownMessage)
85
+ warn('Ignoring stale Discord message reference.')
86
+ return
87
+ end
88
+
84
89
  error("Exception: #{e.inspect}")
85
90
  e.backtrace.each { |line| error(line) }
86
91
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ VERSION = '3.2.0'
5
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/generic'
4
+ require 'onyxcord/await'
5
+
6
+ module OnyxCord::Events
7
+ # @see Bot#await
8
+ class AwaitEvent < Event
9
+ # The await that was triggered.
10
+ # @return [Await] The await
11
+ attr_reader :await
12
+
13
+ # The event that triggered the await.
14
+ # @return [Event] The event
15
+ attr_reader :event
16
+
17
+ # @!attribute [r] key
18
+ # @return [Symbol] the await's key.
19
+ # @see Await#key
20
+ # @!attribute [r] type
21
+ # @return [Class] the await's event class.
22
+ # @see Await#type
23
+ # @!attribute [r] attributes
24
+ # @return [Hash] a hash of attributes defined on the await.
25
+ # @see Await#attributes
26
+ delegate :key, :type, :attributes, to: :await
27
+
28
+ # @!visibility private
29
+ def initialize(await, event, bot)
30
+ @await = await
31
+ @event = event
32
+ @bot = bot
33
+ end
34
+ end
35
+
36
+ # Event handler for {AwaitEvent}
37
+ class AwaitEventHandler < EventHandler
38
+ def matches?(event)
39
+ # Check for the proper event type
40
+ return false unless event.is_a? AwaitEvent
41
+
42
+ [
43
+ matches_all(@attributes[:key], event.key) { |a, e| a == e },
44
+ matches_all(@attributes[:type], event.type) { |a, e| a == e }
45
+ ].reduce(true, &:&)
46
+ end
47
+ end
48
+ end
@@ -1,48 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'onyxcord/events/generic'
4
- require 'onyxcord/await'
5
-
6
- module OnyxCord::Events
7
- # @see Bot#await
8
- class AwaitEvent < Event
9
- # The await that was triggered.
10
- # @return [Await] The await
11
- attr_reader :await
12
-
13
- # The event that triggered the await.
14
- # @return [Event] The event
15
- attr_reader :event
16
-
17
- # @!attribute [r] key
18
- # @return [Symbol] the await's key.
19
- # @see Await#key
20
- # @!attribute [r] type
21
- # @return [Class] the await's event class.
22
- # @see Await#type
23
- # @!attribute [r] attributes
24
- # @return [Hash] a hash of attributes defined on the await.
25
- # @see Await#attributes
26
- delegate :key, :type, :attributes, to: :await
27
-
28
- # @!visibility private
29
- def initialize(await, event, bot)
30
- @await = await
31
- @event = event
32
- @bot = bot
33
- end
34
- end
35
-
36
- # Event handler for {AwaitEvent}
37
- class AwaitEventHandler < EventHandler
38
- def matches?(event)
39
- # Check for the proper event type
40
- return false unless event.is_a? AwaitEvent
41
-
42
- [
43
- matches_all(@attributes[:key], event.key) { |a, e| a == e },
44
- matches_all(@attributes[:type], event.type) { |a, e| a == e }
45
- ].reduce(true, &:&)
46
- end
47
- end
48
- end
3
+ require 'onyxcord/events/await/base'
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/generic'
4
+
5
+ module OnyxCord::Events
6
+ # Raised when a user is banned
7
+ class UserBanEvent < Event
8
+ # @return [User] the user that was banned
9
+ attr_reader :user
10
+
11
+ # @return [Server] the server from which the user was banned
12
+ attr_reader :server
13
+
14
+ # @!visibility private
15
+ def initialize(data, bot)
16
+ @user = bot.user(data['user']['id'].to_i)
17
+ @server = bot.server(data['guild_id'].to_i)
18
+ @bot = bot
19
+ end
20
+ end
21
+
22
+ # Event handler for {UserBanEvent}
23
+ class UserBanEventHandler < EventHandler
24
+ def matches?(event)
25
+ # Check for the proper event type
26
+ return false unless event.is_a? UserBanEvent
27
+
28
+ [
29
+ matches_all(@attributes[:user], event.user) do |a, e|
30
+ case a
31
+ when String
32
+ a == e.name
33
+ when Integer
34
+ a == e.id
35
+ when :bot
36
+ e.current_bot?
37
+ else
38
+ a == e
39
+ end
40
+ end,
41
+ matches_all(@attributes[:server], event.server) do |a, e|
42
+ a == case a
43
+ when String
44
+ e.name
45
+ when Integer
46
+ e.id
47
+ else
48
+ e
49
+ end
50
+ end
51
+ ].reduce(true, &:&)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/ban/base'
4
+
5
+ module OnyxCord::Events
6
+ # Raised when a user is unbanned from a server
7
+ class UserUnbanEvent < UserBanEvent; end
8
+
9
+ # Event handler for {UserUnbanEvent}
10
+ class UserUnbanEventHandler < UserBanEventHandler; end
11
+ end
@@ -1,60 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'onyxcord/events/generic'
4
-
5
- module OnyxCord::Events
6
- # Raised when a user is banned
7
- class UserBanEvent < Event
8
- # @return [User] the user that was banned
9
- attr_reader :user
10
-
11
- # @return [Server] the server from which the user was banned
12
- attr_reader :server
13
-
14
- # @!visibility private
15
- def initialize(data, bot)
16
- @user = bot.user(data['user']['id'].to_i)
17
- @server = bot.server(data['guild_id'].to_i)
18
- @bot = bot
19
- end
20
- end
21
-
22
- # Event handler for {UserBanEvent}
23
- class UserBanEventHandler < EventHandler
24
- def matches?(event)
25
- # Check for the proper event type
26
- return false unless event.is_a? UserBanEvent
27
-
28
- [
29
- matches_all(@attributes[:user], event.user) do |a, e|
30
- case a
31
- when String
32
- a == e.name
33
- when Integer
34
- a == e.id
35
- when :bot
36
- e.current_bot?
37
- else
38
- a == e
39
- end
40
- end,
41
- matches_all(@attributes[:server], event.server) do |a, e|
42
- a == case a
43
- when String
44
- e.name
45
- when Integer
46
- e.id
47
- else
48
- e
49
- end
50
- end
51
- ].reduce(true, &:&)
52
- end
53
- end
54
-
55
- # Raised when a user is unbanned from a server
56
- class UserUnbanEvent < UserBanEvent; end
57
-
58
- # Event handler for {UserUnbanEvent}
59
- class UserUnbanEventHandler < UserBanEventHandler; end
60
- end
3
+ require 'onyxcord/events/ban/base'
4
+ require 'onyxcord/events/ban/remove'
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/generic'
4
+ require 'onyxcord/models'
5
+
6
+ module OnyxCord::Events
7
+ # Raised when a channel is created
8
+ class ChannelCreateEvent < Event
9
+ # @return [Channel] the channel in question.
10
+ attr_reader :channel
11
+
12
+ # @!attribute [r] type
13
+ # @return [Integer] the channel's type (0: text, 1: private, 2: voice, 3: group).
14
+ # @see Channel#type
15
+ # @!attribute [r] topic
16
+ # @return [String] the channel's topic.
17
+ # @see Channel#topic
18
+ # @!attribute [r] position
19
+ # @return [Integer] the position of the channel in the channels list.
20
+ # @see Channel#position
21
+ # @!attribute [r] name
22
+ # @return [String] the channel's name
23
+ # @see Channel#name
24
+ # @!attribute [r] id
25
+ # @return [Integer] the channel's unique ID.
26
+ # @see Channel#id
27
+ # @!attribute [r] server
28
+ # @return [Server] the server the channel belongs to.
29
+ # @see Channel#server
30
+ delegate :name, :server, :type, :owner_id, :recipients, :topic, :user_limit, :position, :permission_overwrites, to: :channel
31
+
32
+ # @!visibility private
33
+ def initialize(data, bot)
34
+ @bot = bot
35
+ @channel = if data.is_a?(OnyxCord::Channel)
36
+ data
37
+ else
38
+ cached_channel(bot, data['id']) || OnyxCord::Channel.new(data, bot, cached_server(bot, data['guild_id']))
39
+ end
40
+ end
41
+
42
+ def cached_channel(bot, channel_id)
43
+ channels = bot.instance_variable_get(:@channels)
44
+ channels&.[](channel_id.to_i)
45
+ end
46
+
47
+ def cached_server(bot, server_id)
48
+ return nil unless server_id
49
+
50
+ servers = bot.instance_variable_get(:@servers)
51
+ servers&.[](server_id.to_i)
52
+ end
53
+ end
54
+
55
+ # Event handler for ChannelCreateEvent
56
+
57
+ # Event handler for ChannelCreateEvent
58
+ class ChannelCreateEventHandler < EventHandler
59
+ def matches?(event)
60
+ # Check for the proper event type
61
+ return false unless event.is_a? ChannelCreateEvent
62
+
63
+ [
64
+ matches_all(@attributes[:type], event.type) do |a, e|
65
+ a == if a.is_a? String
66
+ e.name
67
+ else
68
+ e
69
+ end
70
+ end,
71
+ matches_all(@attributes[:name], event.name) do |a, e|
72
+ a == if a.is_a? String
73
+ e.to_s
74
+ else
75
+ e
76
+ end
77
+ end
78
+ ].reduce(true, &:&)
79
+ end
80
+ end
81
+
82
+ # Raised when a channel is deleted
83
+
84
+ # Raised when a channel is updated (e.g. topic changes)
85
+ class ChannelUpdateEvent < ChannelCreateEvent; end
86
+
87
+ # Event handler for ChannelUpdateEvent
88
+
89
+ # Event handler for ChannelUpdateEvent
90
+ class ChannelUpdateEventHandler < ChannelCreateEventHandler; end
91
+ end