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,591 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord
4
+ module Internal
5
+ module EventBus
6
+ include Events
7
+
8
+ def handle_dispatch(type, data)
9
+ # Check whether there are still unavailable servers and there have been more than 10 seconds since READY
10
+ if @unavailable_servers&.positive? && (Time.now - @unavailable_timeout_time) > 10 && !(@intents || 0).nobits?(INTENTS[:servers])
11
+ # The server streaming timed out!
12
+ LOGGER.debug("Server streaming timed out with #{@unavailable_servers} servers remaining")
13
+ LOGGER.debug('Calling ready now because server loading is taking a long time. Servers may be unavailable due to an outage, or your bot is on very large servers.')
14
+
15
+ # Unset the unavailable server count so this doesn't get triggered again
16
+ @unavailable_servers = 0
17
+
18
+ notify_ready
19
+ end
20
+
21
+ case type
22
+ when :READY
23
+ # As READY may be called multiple times over a single process lifetime, we here need to reset the cache entirely
24
+ # to prevent possible inconsistencies, like objects referencing old versions of other objects which have been
25
+ # replaced.
26
+ init_cache
27
+
28
+ @profile = Profile.new(data['user'], self)
29
+
30
+ @client_id ||= data['application']['id']&.to_i
31
+
32
+ # Initialize servers
33
+ @servers = {}
34
+
35
+ # Count unavailable servers
36
+ @unavailable_servers = 0
37
+
38
+ data['guilds'].each do |element|
39
+ # Check for true specifically because unavailable=false indicates that a previously unavailable server has
40
+ # come online
41
+ if element['unavailable']
42
+ @unavailable_servers += 1
43
+
44
+ # Ignore any unavailable servers
45
+ next
46
+ end
47
+
48
+ ensure_server(element, true)
49
+ end
50
+
51
+ # Don't notify yet if there are unavailable servers because they need to get available before the bot truly has
52
+ # all the data
53
+ if @unavailable_servers.zero?
54
+ # No unavailable servers - we're ready!
55
+ notify_ready
56
+ end
57
+
58
+ @ready_time = Time.now
59
+ @unavailable_timeout_time = Time.now
60
+ when :GUILD_MEMBERS_CHUNK
61
+ id = data['guild_id'].to_i
62
+ server = server(id)
63
+ server.process_chunk(data['members'], data['chunk_index'], data['chunk_count'])
64
+ when :USER_UPDATE
65
+ @profile = Profile.new(data, self)
66
+ when :INVITE_CREATE
67
+ invite = Invite.new(data, self)
68
+ raise_event(InviteCreateEvent.new(data, invite, self))
69
+ when :INVITE_DELETE
70
+ raise_event(InviteDeleteEvent.new(data, self))
71
+ when :MESSAGE_CREATE
72
+ if ignored?(data['author']['id'])
73
+ debug("Ignored author with ID #{data['author']['id']}")
74
+ return
75
+ end
76
+
77
+ if @ignore_bots && data['author']['bot']
78
+ debug("Ignored Bot account with ID #{data['author']['id']}")
79
+ return
80
+ end
81
+
82
+ if !should_parse_self && profile.id == data['author']['id'].to_i
83
+ debug('Ignored message from the current bot')
84
+ return
85
+ end
86
+
87
+ # If create_message is overwritten with a method that returns the parsed message, use that instead, so we don't
88
+ # parse the message twice (which is just thrown away performance)
89
+ message = create_message(data)
90
+ message = Message.new(data, self) unless message.is_a? Message
91
+
92
+ # Update the existing member if it exists in the cache.
93
+ if data['member']
94
+ member = message.channel.server&.member(data['author']['id'].to_i, false)
95
+ data['member']['user'] = data['author']
96
+ member&.update_data(data['member'])
97
+ end
98
+
99
+ # Dispatch a ChannelCreateEvent for channels we don't have cached
100
+ if message.channel.private? && !@pm_channels&.key?(message.channel.recipient.id)
101
+ create_channel(message.channel)
102
+
103
+ raise_event(ChannelCreateEvent.new(message.channel, self))
104
+ end
105
+
106
+ message.channel.process_last_message_id(message.id)
107
+
108
+ event = MessageEvent.new(message, self)
109
+ raise_event(event)
110
+
111
+ # Raise a mention event for any direct mentions.
112
+ if message.mentions.any? { |user| user.id == profile.id }
113
+ event = MentionEvent.new(message, self, false)
114
+ raise_event(event)
115
+ end
116
+
117
+ # Raise a mention event for the current bot's auto-generated role.
118
+ if message.role_mentions.any? { |role| role.tags&.bot_id == profile.id }
119
+ event = MentionEvent.new(message, self, true)
120
+ raise_event(event)
121
+ end
122
+
123
+ if message.channel.private?
124
+ event = PrivateMessageEvent.new(message, self)
125
+ raise_event(event)
126
+ end
127
+ when :MESSAGE_UPDATE
128
+ update_message(data)
129
+
130
+ if !should_parse_self && profile.id == data['author']['id'].to_i
131
+ debug('Ignored message from the current bot')
132
+ return
133
+ end
134
+
135
+ message = Message.new(data, self)
136
+
137
+ event = MessageUpdateEvent.new(message, self)
138
+ raise_event(event)
139
+
140
+ if data['author'].nil?
141
+ LOGGER.debug("Edited a message with nil author! Content: #{message.content.inspect}, channel: #{message.channel.inspect}")
142
+ return
143
+ end
144
+
145
+ # Update the existing member if it exists in the cache.
146
+ if data['member']
147
+ member = message.channel.server&.member(data['author']['id'].to_i, false)
148
+ data['member']['user'] = data['author']
149
+ member&.update_data(data['member'])
150
+ end
151
+
152
+ event = MessageEditEvent.new(message, self)
153
+ raise_event(event)
154
+ when :MESSAGE_DELETE
155
+ delete_message(data)
156
+
157
+ event = MessageDeleteEvent.new(data, self)
158
+ raise_event(event)
159
+ when :MESSAGE_DELETE_BULK
160
+ debug("MESSAGE_DELETE_BULK will raise #{data['ids'].length} events")
161
+
162
+ data['ids'].each do |single_id|
163
+ # Form a data hash for a single ID so the methods get what they want
164
+ single_data = {
165
+ 'id' => single_id,
166
+ 'channel_id' => data['channel_id']
167
+ }
168
+
169
+ # Raise as normal
170
+ delete_message(single_data)
171
+
172
+ event = MessageDeleteEvent.new(single_data, self)
173
+ raise_event(event)
174
+ end
175
+ when :TYPING_START
176
+ start_typing(data)
177
+
178
+ begin
179
+ event = TypingEvent.new(data, self)
180
+ raise_event(event)
181
+ rescue OnyxCord::Errors::NoPermission
182
+ debug 'Typing started in channel the bot has no access to, ignoring'
183
+ end
184
+ when :MESSAGE_REACTION_ADD
185
+ add_message_reaction(data)
186
+
187
+ return if profile.id == data['user_id'].to_i && !should_parse_self
188
+
189
+ if data['member']
190
+ server = self.server(data['guild_id'].to_i)
191
+
192
+ server&.cache_member(Member.new(data['member'], server, self))
193
+ end
194
+
195
+ event = ReactionAddEvent.new(data, self)
196
+ raise_event(event)
197
+ when :MESSAGE_REACTION_REMOVE
198
+ remove_message_reaction(data)
199
+
200
+ return if profile.id == data['user_id'].to_i && !should_parse_self
201
+
202
+ event = ReactionRemoveEvent.new(data, self)
203
+ raise_event(event)
204
+ when :MESSAGE_REACTION_REMOVE_ALL
205
+ remove_all_message_reactions(data)
206
+
207
+ event = ReactionRemoveAllEvent.new(data, self)
208
+ raise_event(event)
209
+ when :MESSAGE_REACTION_REMOVE_EMOJI
210
+
211
+ event = ReactionRemoveEmojiEvent.new(data, self)
212
+ raise_event(event)
213
+ when :PRESENCE_UPDATE
214
+ # Ignore friends list presences
215
+ return unless data['guild_id']
216
+
217
+ new_activities = (data['activities'] || []).map { |act_data| Activity.new(act_data, self) }
218
+ presence_user = @users[data['user']['id'].to_i]
219
+ old_activities = (presence_user&.activities || [])
220
+ update_presence(data)
221
+
222
+ # Starting a new game
223
+ playing_change = new_activities.reject do |act|
224
+ old_activities.find { |old| old.name == act.name }
225
+ end
226
+
227
+ # Exiting an existing game
228
+ playing_change += old_activities.reject do |old|
229
+ new_activities.find { |act| act.name == old.name }
230
+ end
231
+
232
+ if playing_change.any?
233
+ playing_change.each do |act|
234
+ raise_event(PlayingEvent.new(data, act, self))
235
+ end
236
+ else
237
+ raise_event(PresenceEvent.new(data, self))
238
+ end
239
+ when :VOICE_STATE_UPDATE
240
+ old_channel_id = update_voice_state(data)
241
+
242
+ event = VoiceStateUpdateEvent.new(data, old_channel_id, self)
243
+ raise_event(event)
244
+ when :VOICE_SERVER_UPDATE
245
+ update_voice_server(data)
246
+
247
+ event = VoiceServerUpdateEvent.new(data, self)
248
+ raise_event(event)
249
+ when :CHANNEL_CREATE
250
+ create_channel(data)
251
+
252
+ event = ChannelCreateEvent.new(data, self)
253
+ raise_event(event)
254
+ when :CHANNEL_UPDATE
255
+ update_channel(data)
256
+
257
+ event = ChannelUpdateEvent.new(data, self)
258
+ raise_event(event)
259
+ when :CHANNEL_DELETE
260
+ delete_channel(data)
261
+
262
+ event = ChannelDeleteEvent.new(data, self)
263
+ raise_event(event)
264
+ when :CHANNEL_PINS_UPDATE
265
+ event = ChannelPinsUpdateEvent.new(data, self)
266
+
267
+ event.channel.process_last_pin_timestamp(data['last_pin_timestamp']) if data.key?('last_pin_timestamp')
268
+
269
+ raise_event(event)
270
+ when :GUILD_MEMBER_ADD
271
+ add_guild_member(data)
272
+
273
+ event = ServerMemberAddEvent.new(data, self)
274
+ raise_event(event)
275
+ when :GUILD_MEMBER_UPDATE
276
+ update_guild_member(data)
277
+
278
+ event = ServerMemberUpdateEvent.new(data, self)
279
+ raise_event(event)
280
+ when :GUILD_MEMBER_REMOVE
281
+ delete_guild_member(data)
282
+
283
+ event = ServerMemberDeleteEvent.new(data, self)
284
+ raise_event(event)
285
+ when :GUILD_AUDIT_LOG_ENTRY_CREATE
286
+ event = AuditLogEntryCreateEvent.new(data, self)
287
+ raise_event(event)
288
+ when :GUILD_BAN_ADD
289
+ add_user_ban(data)
290
+
291
+ event = UserBanEvent.new(data, self)
292
+ raise_event(event)
293
+ when :GUILD_BAN_REMOVE
294
+ remove_user_ban(data)
295
+
296
+ event = UserUnbanEvent.new(data, self)
297
+ raise_event(event)
298
+ when :GUILD_ROLE_UPDATE
299
+ update_guild_role(data)
300
+
301
+ event = ServerRoleUpdateEvent.new(data, self)
302
+ raise_event(event)
303
+ when :GUILD_ROLE_CREATE
304
+ update_guild_role(data)
305
+
306
+ event = ServerRoleCreateEvent.new(data, self)
307
+ raise_event(event)
308
+ when :GUILD_ROLE_DELETE
309
+ delete_guild_role(data)
310
+
311
+ event = ServerRoleDeleteEvent.new(data, self)
312
+ raise_event(event)
313
+ when :INTEGRATION_CREATE
314
+ event = IntegrationCreateEvent.new(data, self)
315
+ raise_event(event)
316
+ when :INTEGRATION_UPDATE
317
+ event = IntegrationUpdateEvent.new(data, self)
318
+ raise_event(event)
319
+ when :INTEGRATION_DELETE
320
+ event = IntegrationDeleteEvent.new(data, self)
321
+ raise_event(event)
322
+ when :GUILD_CREATE
323
+ create_guild(data)
324
+
325
+ # Check for false specifically (no data means the server has never been unavailable)
326
+ if data['unavailable'].is_a? FalseClass
327
+ @unavailable_servers -= 1 if @unavailable_servers
328
+ @unavailable_timeout_time = Time.now
329
+
330
+ notify_ready if @unavailable_servers.zero?
331
+
332
+ # Return here so the event doesn't get triggered
333
+ return
334
+ end
335
+
336
+ event = ServerCreateEvent.new(data, self)
337
+ raise_event(event)
338
+ when :GUILD_UPDATE
339
+ update_guild(data)
340
+
341
+ event = ServerUpdateEvent.new(data, self)
342
+ raise_event(event)
343
+ when :GUILD_DELETE
344
+ delete_guild(data)
345
+
346
+ if data['unavailable'].is_a? TrueClass
347
+ LOGGER.warn("Server #{data['id']} is unavailable due to an outage!")
348
+ return # Don't raise an event
349
+ end
350
+
351
+ event = ServerDeleteEvent.new(data, self)
352
+ raise_event(event)
353
+ when :GUILD_EMOJIS_UPDATE
354
+ server_id = data['guild_id'].to_i
355
+ server = @servers[server_id]
356
+ old_emoji_data = server.emoji.clone
357
+ update_guild_emoji(data)
358
+ new_emoji_data = server.emoji
359
+
360
+ created_ids = new_emoji_data.keys - old_emoji_data.keys
361
+ deleted_ids = old_emoji_data.keys - new_emoji_data.keys
362
+ updated_ids = old_emoji_data.select do |k, v|
363
+ new_emoji_data[k] && (v.name != new_emoji_data[k].name || v.roles != new_emoji_data[k].roles)
364
+ end.keys
365
+
366
+ event = ServerEmojiChangeEvent.new(server, data, self)
367
+ raise_event(event)
368
+
369
+ created_ids.each do |e|
370
+ event = ServerEmojiCreateEvent.new(server, new_emoji_data[e], self)
371
+ raise_event(event)
372
+ end
373
+
374
+ deleted_ids.each do |e|
375
+ event = ServerEmojiDeleteEvent.new(server, old_emoji_data[e], self)
376
+ raise_event(event)
377
+ end
378
+
379
+ updated_ids.each do |e|
380
+ event = ServerEmojiUpdateEvent.new(server, old_emoji_data[e], new_emoji_data[e], self)
381
+ raise_event(event)
382
+ end
383
+ when :APPLICATION_COMMAND_PERMISSIONS_UPDATE
384
+ event = ApplicationCommandPermissionsUpdateEvent.new(data, self)
385
+
386
+ raise_event(event)
387
+ when :INTERACTION_CREATE
388
+ event = InteractionCreateEvent.new(data, self)
389
+ raise_event(event)
390
+
391
+ case data['type']
392
+ when Interaction::TYPES[:command]
393
+ event = ApplicationCommandEvent.new(data, self)
394
+
395
+ @event_executor.post do
396
+ Thread.current[:onyxcord_name] = next_event_thread_name('it')
397
+ handler = @application_commands[event.command_name]
398
+ handler&.call(event)
399
+ rescue StandardError => e
400
+ log_exception(e)
401
+ end
402
+ when Interaction::TYPES[:component]
403
+ case data['data']['component_type']
404
+ when Webhooks::View::COMPONENT_TYPES[:button]
405
+ event = ButtonEvent.new(data, self)
406
+
407
+ raise_event(event)
408
+ when Webhooks::View::COMPONENT_TYPES[:string_select]
409
+ event = StringSelectEvent.new(data, self)
410
+
411
+ raise_event(event)
412
+ when Webhooks::View::COMPONENT_TYPES[:user_select]
413
+ event = UserSelectEvent.new(data, self)
414
+
415
+ raise_event(event)
416
+ when Webhooks::View::COMPONENT_TYPES[:role_select]
417
+ event = RoleSelectEvent.new(data, self)
418
+
419
+ raise_event(event)
420
+ when Webhooks::View::COMPONENT_TYPES[:mentionable_select]
421
+ event = MentionableSelectEvent.new(data, self)
422
+
423
+ raise_event(event)
424
+ when Webhooks::View::COMPONENT_TYPES[:channel_select]
425
+ event = ChannelSelectEvent.new(data, self)
426
+
427
+ raise_event(event)
428
+ end
429
+ when Interaction::TYPES[:modal_submit]
430
+
431
+ event = ModalSubmitEvent.new(data, self)
432
+ raise_event(event)
433
+ when Interaction::TYPES[:autocomplete]
434
+
435
+ event = AutocompleteEvent.new(data, self)
436
+ raise_event(event)
437
+ end
438
+ when :WEBHOOKS_UPDATE
439
+ event = WebhookUpdateEvent.new(data, self)
440
+ raise_event(event)
441
+ when :THREAD_CREATE
442
+ create_channel(data)
443
+
444
+ event = ThreadCreateEvent.new(data, self)
445
+ raise_event(event)
446
+ when :THREAD_UPDATE
447
+ update_channel(data)
448
+
449
+ event = ThreadUpdateEvent.new(data, self)
450
+ raise_event(event)
451
+ when :THREAD_DELETE
452
+ delete_channel(data)
453
+ @thread_members.delete(data['id']&.resolve_id)
454
+
455
+ # raise ThreadDeleteEvent
456
+ when :THREAD_LIST_SYNC
457
+ server_id = data['guild_id'].to_i
458
+ server = @servers[server_id]
459
+
460
+ # The `channel_ids` field has two meanings:
461
+ #
462
+ # 1. If the field is not present, the thread list is being synced for the whole server.
463
+ #
464
+ # 2. We are syncing the threads for a specific channel. This can happen when gaining access
465
+ # to a channel.
466
+ if (ids = data['channel_ids']&.map(&:to_i))
467
+ @channels.delete_if { |_, channel| channel.thread? && ids.any?(channel.parent&.id) }
468
+ server&.clear_threads(ids)
469
+ else
470
+ @channels.delete_if { |_, channel| channel.server.id == server_id && channel.thread? }
471
+ server&.clear_threads
472
+ end
473
+
474
+ data['members'].each { |member| ensure_thread_member(member) }
475
+ data['threads'].each { |channel| ensure_channel(channel) }
476
+
477
+ # raise ThreadListSyncEvent?
478
+ when :THREAD_MEMBER_UPDATE
479
+ ensure_thread_member(data)
480
+ when :THREAD_MEMBERS_UPDATE
481
+ data['added_members']&.each do |added_member|
482
+ ensure_thread_member(added_member) if added_member['user_id']
483
+ end
484
+
485
+ data['removed_member_ids']&.each do |member_id|
486
+ @thread_members[data['id']&.resolve_id]&.delete(member_id&.resolve_id)
487
+ end
488
+
489
+ event = ThreadMembersUpdateEvent.new(data, self)
490
+ raise_event(event)
491
+ when :MESSAGE_POLL_VOTE_ADD
492
+ event = PollVoteAddEvent.new(data, self)
493
+ raise_event(event)
494
+ when :MESSAGE_POLL_VOTE_REMOVE
495
+ event = PollVoteRemoveEvent.new(data, self)
496
+ raise_event(event)
497
+ when :GUILD_SCHEDULED_EVENT_CREATE
498
+ update_guild_scheduled_event(data)
499
+
500
+ event = ScheduledEventCreateEvent.new(data, self)
501
+ raise_event(event)
502
+ when :GUILD_SCHEDULED_EVENT_UPDATE
503
+ update_guild_scheduled_event(data)
504
+
505
+ event = ScheduledEventUpdateEvent.new(data, self)
506
+ raise_event(event)
507
+ when :GUILD_SCHEDULED_EVENT_DELETE
508
+ @servers[data['guild_id'].to_i]&.delete_scheduled_event(data['id'].to_i)
509
+
510
+ event = ScheduledEventDeleteEvent.new(data, self)
511
+ raise_event(event)
512
+ when :GUILD_SCHEDULED_EVENT_USER_ADD
513
+ server = @servers[data['guild_id'].to_i]
514
+ server&.scheduled_event(data['guild_scheduled_event_id'], request: false)&.increment_user_count
515
+
516
+ event = ScheduledEventUserAddEvent.new(data, self)
517
+ raise_event(event)
518
+ when :GUILD_SCHEDULED_EVENT_USER_REMOVE
519
+ server = @servers[data['guild_id'].to_i]
520
+ server&.scheduled_event(data['guild_scheduled_event_id'], request: false)&.deincrement_user_count
521
+
522
+ event = ScheduledEventUserRemoveEvent.new(data, self)
523
+ raise_event(event)
524
+ else
525
+ # another event that we don't support yet
526
+ debug "Event #{type} has been received but is unsupported. Raising UnknownEvent"
527
+
528
+ event = UnknownEvent.new(type, data, self)
529
+ raise_event(event)
530
+ end
531
+
532
+ # The existence of this array is checked before for performance reasons, since this has to be done for *every*
533
+ # dispatch.
534
+ if @event_handlers && @event_handlers[RawEvent]
535
+ event = RawEvent.new(type, data, self)
536
+ raise_event(event)
537
+ end
538
+ rescue Exception => e
539
+ if defined?(Async::Cancel) && e.is_a?(Async::Cancel)
540
+ LOGGER.debug('Gateway message handling was cancelled.')
541
+ return
542
+ end
543
+
544
+ LOGGER.error('Gateway message error!')
545
+ log_exception(e)
546
+ end
547
+
548
+ def dispatch_packet(packet)
549
+ type = packet['t']&.intern
550
+ data = packet['d']
551
+
552
+ case @mode
553
+ when :raw
554
+ dispatch_raw_packet(packet)
555
+ notify_raw_ready if type == :READY
556
+ when :hybrid
557
+ dispatch_raw_packet(packet)
558
+ handle_dispatch(type, data)
559
+ else
560
+ handle_dispatch(type, data)
561
+ end
562
+ end
563
+
564
+ def dispatch_raw_packet(packet)
565
+ handlers = @raw_handlers
566
+ return unless handlers
567
+
568
+ handlers.dup.each do |handler|
569
+ call_raw_handler(handler, packet) if handler.matches?(packet)
570
+ end
571
+ end
572
+
573
+ def call_raw_handler(handler, packet)
574
+ @event_executor.post do
575
+ Thread.current[:onyxcord_name] = next_event_thread_name('rt')
576
+ handler.call(packet)
577
+ rescue StandardError => e
578
+ log_exception(e)
579
+ end
580
+ end
581
+
582
+ def notify_raw_ready
583
+ return if @raw_ready_notified
584
+
585
+ @raw_ready_notified = true
586
+ LOGGER.good 'Ready'
587
+ @gateway.notify_ready
588
+ end
589
+ end
590
+ end
591
+ end