onyxcord 2.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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/{logger.rb → core/logger.rb} +5 -0
  27. data/lib/onyxcord/core/version.rb +5 -0
  28. data/lib/onyxcord/events/await/base.rb +48 -0
  29. data/lib/onyxcord/events/await.rb +1 -46
  30. data/lib/onyxcord/events/ban/base.rb +54 -0
  31. data/lib/onyxcord/events/ban/remove.rb +11 -0
  32. data/lib/onyxcord/events/bans.rb +2 -58
  33. data/lib/onyxcord/events/channels/base.rb +91 -0
  34. data/lib/onyxcord/events/channels/delete.rb +73 -0
  35. data/lib/onyxcord/events/channels/pins.rb +44 -0
  36. data/lib/onyxcord/events/channels/recipients.rb +77 -0
  37. data/lib/onyxcord/events/channels.rb +4 -239
  38. data/lib/onyxcord/events/guilds/audit_logs.rb +79 -0
  39. data/lib/onyxcord/events/guilds/base.rb +97 -0
  40. data/lib/onyxcord/events/guilds/emoji.rb +147 -0
  41. data/lib/onyxcord/events/guilds.rb +3 -267
  42. data/lib/onyxcord/events/handlers/channels.rb +133 -0
  43. data/lib/onyxcord/events/handlers/core.rb +146 -0
  44. data/lib/onyxcord/events/handlers/guilds.rb +375 -0
  45. data/lib/onyxcord/events/handlers/interactions.rb +238 -0
  46. data/lib/onyxcord/events/handlers/lifetime.rb +71 -0
  47. data/lib/onyxcord/events/handlers/messages.rb +218 -0
  48. data/lib/onyxcord/events/handlers/presence.rb +56 -0
  49. data/lib/onyxcord/events/handlers/raw.rb +39 -0
  50. data/lib/onyxcord/events/handlers/reactions.rb +98 -0
  51. data/lib/onyxcord/events/handlers/scheduled_events.rb +243 -0
  52. data/lib/onyxcord/events/handlers/voice.rb +46 -0
  53. data/lib/onyxcord/events/integration/base.rb +45 -0
  54. data/lib/onyxcord/events/integration/create.rb +11 -0
  55. data/lib/onyxcord/events/integration/delete.rb +48 -0
  56. data/lib/onyxcord/events/integration/update.rb +11 -0
  57. data/lib/onyxcord/events/integrations.rb +4 -98
  58. data/lib/onyxcord/events/interactions/application_commands.rb +185 -0
  59. data/lib/onyxcord/events/interactions/autocomplete.rb +62 -0
  60. data/lib/onyxcord/events/interactions/base.rb +175 -0
  61. data/lib/onyxcord/events/interactions/components.rb +221 -0
  62. data/lib/onyxcord/events/interactions/permissions.rb +53 -0
  63. data/lib/onyxcord/events/interactions.rb +5 -622
  64. data/lib/onyxcord/events/invite/create.rb +79 -0
  65. data/lib/onyxcord/events/invite/delete.rb +55 -0
  66. data/lib/onyxcord/events/invites.rb +2 -125
  67. data/lib/onyxcord/events/lifetime/base.rb +31 -0
  68. data/lib/onyxcord/events/lifetime.rb +1 -29
  69. data/lib/onyxcord/events/member/add.rb +12 -0
  70. data/lib/onyxcord/events/member/base.rb +67 -0
  71. data/lib/onyxcord/events/member/delete.rb +21 -0
  72. data/lib/onyxcord/events/member/update.rb +25 -0
  73. data/lib/onyxcord/events/members.rb +4 -108
  74. data/lib/onyxcord/events/message/base.rb +295 -0
  75. data/lib/onyxcord/events/message/ids.rb +71 -0
  76. data/lib/onyxcord/events/message/mentions.rb +55 -0
  77. data/lib/onyxcord/events/message/updates.rb +27 -0
  78. data/lib/onyxcord/events/message.rb +4 -397
  79. data/lib/onyxcord/events/poll/add.rb +11 -0
  80. data/lib/onyxcord/events/poll/base.rb +106 -0
  81. data/lib/onyxcord/events/poll/remove.rb +11 -0
  82. data/lib/onyxcord/events/polls.rb +3 -116
  83. data/lib/onyxcord/events/presence/playing.rb +77 -0
  84. data/lib/onyxcord/events/presence/status.rb +60 -0
  85. data/lib/onyxcord/events/presence.rb +2 -129
  86. data/lib/onyxcord/events/raw/base.rb +74 -0
  87. data/lib/onyxcord/events/raw.rb +1 -72
  88. data/lib/onyxcord/events/reactions/base.rb +143 -0
  89. data/lib/onyxcord/events/reactions/clear.rb +99 -0
  90. data/lib/onyxcord/events/reactions.rb +2 -216
  91. data/lib/onyxcord/events/role/create.rb +46 -0
  92. data/lib/onyxcord/events/role/delete.rb +40 -0
  93. data/lib/onyxcord/events/role/update.rb +11 -0
  94. data/lib/onyxcord/events/roles.rb +3 -85
  95. data/lib/onyxcord/events/scheduled_events/events.rb +112 -0
  96. data/lib/onyxcord/events/scheduled_events/users.rb +91 -0
  97. data/lib/onyxcord/events/scheduled_events.rb +2 -169
  98. data/lib/onyxcord/events/thread/base.rb +49 -0
  99. data/lib/onyxcord/events/thread/members.rb +44 -0
  100. data/lib/onyxcord/events/thread/update.rb +18 -0
  101. data/lib/onyxcord/events/threads.rb +3 -98
  102. data/lib/onyxcord/events/typing/base.rb +73 -0
  103. data/lib/onyxcord/events/typing.rb +1 -71
  104. data/lib/onyxcord/events/voice/server_update.rb +48 -0
  105. data/lib/onyxcord/events/voice/state_update.rb +137 -0
  106. data/lib/onyxcord/events/voice_server_update.rb +2 -46
  107. data/lib/onyxcord/events/voice_state_update.rb +2 -135
  108. data/lib/onyxcord/events/webhook/update.rb +65 -0
  109. data/lib/onyxcord/events/webhooks.rb +1 -63
  110. data/lib/onyxcord/gateway/client.rb +460 -0
  111. data/lib/onyxcord/interactions/command.rb +120 -0
  112. data/lib/onyxcord/interactions/context.rb +109 -0
  113. data/lib/onyxcord/interactions/internal/application_command.rb +203 -0
  114. data/lib/onyxcord/interactions/internal/message.rb +152 -0
  115. data/lib/onyxcord/interactions/internal/metadata.rb +109 -0
  116. data/lib/onyxcord/interactions/internal/option_builder.rb +230 -0
  117. data/lib/onyxcord/interactions/internal/permission_builder.rb +90 -0
  118. data/lib/onyxcord/interactions/option.rb +88 -0
  119. data/lib/onyxcord/interactions/registry.rb +50 -0
  120. data/lib/onyxcord/interactions.rb +16 -0
  121. data/lib/onyxcord/internal/async_runtime.rb +32 -0
  122. data/lib/onyxcord/internal/event_bus.rb +591 -0
  123. data/lib/onyxcord/internal/event_executor.rb +155 -0
  124. data/lib/onyxcord/internal/gateway/opcodes.rb +22 -0
  125. data/lib/onyxcord/internal/gateway/session.rb +45 -0
  126. data/lib/onyxcord/internal/http.rb +189 -0
  127. data/lib/onyxcord/internal/json.rb +51 -0
  128. data/lib/onyxcord/{message_payload.rb → internal/message_payload.rb} +3 -3
  129. data/lib/onyxcord/internal/rate_limiter/async_rest.rb +151 -0
  130. data/lib/onyxcord/internal/rate_limiter/gateway.rb +44 -0
  131. data/lib/onyxcord/internal/rate_limiter/rest.rb +144 -0
  132. data/lib/onyxcord/internal/websocket.rb +79 -0
  133. data/lib/onyxcord/light/data.rb +1 -1
  134. data/lib/onyxcord/light/integrations.rb +1 -1
  135. data/lib/onyxcord/light/light_bot.rb +7 -7
  136. data/lib/onyxcord/{data → models}/activity.rb +2 -2
  137. data/lib/onyxcord/{data → models}/application.rb +3 -3
  138. data/lib/onyxcord/{data → models}/avatar_decoration.rb +1 -1
  139. data/lib/onyxcord/{data → models}/channel.rb +23 -23
  140. data/lib/onyxcord/{data → models}/collectibles.rb +1 -1
  141. data/lib/onyxcord/{data → models}/emoji.rb +1 -1
  142. data/lib/onyxcord/models/interaction.rb +450 -0
  143. data/lib/onyxcord/{data → models}/invite.rb +1 -1
  144. data/lib/onyxcord/{data → models}/member.rb +11 -11
  145. data/lib/onyxcord/{data → models}/message.rb +18 -14
  146. data/lib/onyxcord/{data → models}/poll.rb +2 -2
  147. data/lib/onyxcord/{data → models}/primary_server.rb +1 -1
  148. data/lib/onyxcord/{data → models}/profile.rb +4 -4
  149. data/lib/onyxcord/{data → models}/role.rb +6 -12
  150. data/lib/onyxcord/{data → models}/scheduled_event.rb +5 -5
  151. data/lib/onyxcord/{data → models}/server.rb +41 -41
  152. data/lib/onyxcord/{data → models}/server_preview.rb +2 -2
  153. data/lib/onyxcord/{data → models}/team.rb +1 -1
  154. data/lib/onyxcord/{data → models}/user.rb +5 -5
  155. data/lib/onyxcord/{data → models}/webhook.rb +10 -10
  156. data/lib/onyxcord/models.rb +57 -0
  157. data/lib/onyxcord/{api.rb → rest/client.rb} +23 -22
  158. data/lib/onyxcord/{api → rest/routes}/application.rb +79 -57
  159. data/lib/onyxcord/rest/routes/channel/base.rb +73 -0
  160. data/lib/onyxcord/rest/routes/channel/groups.rb +78 -0
  161. data/lib/onyxcord/rest/routes/channel/messages.rb +130 -0
  162. data/lib/onyxcord/rest/routes/channel/permissions.rb +73 -0
  163. data/lib/onyxcord/rest/routes/channel/pins.rb +45 -0
  164. data/lib/onyxcord/rest/routes/channel/polls.rb +32 -0
  165. data/lib/onyxcord/rest/routes/channel/reactions.rb +86 -0
  166. data/lib/onyxcord/rest/routes/channel/threads.rb +176 -0
  167. data/lib/onyxcord/rest/routes/channel/webhooks.rb +47 -0
  168. data/lib/onyxcord/rest/routes/channel.rb +12 -0
  169. data/lib/onyxcord/{api/interaction.rb → rest/routes/interaction/base.rb} +7 -25
  170. data/lib/onyxcord/rest/routes/interaction/response.rb +24 -0
  171. data/lib/onyxcord/rest/routes/interaction.rb +4 -0
  172. data/lib/onyxcord/{api → rest/routes}/invite.rb +7 -7
  173. data/lib/onyxcord/rest/routes/server/admin.rb +174 -0
  174. data/lib/onyxcord/rest/routes/server/assets.rb +25 -0
  175. data/lib/onyxcord/rest/routes/server/bans.rb +67 -0
  176. data/lib/onyxcord/rest/routes/server/base.rb +77 -0
  177. data/lib/onyxcord/rest/routes/server/channels.rb +58 -0
  178. data/lib/onyxcord/rest/routes/server/emoji.rb +48 -0
  179. data/lib/onyxcord/rest/routes/server/members.rb +109 -0
  180. data/lib/onyxcord/rest/routes/server/messages.rb +19 -0
  181. data/lib/onyxcord/rest/routes/server/roles.rb +156 -0
  182. data/lib/onyxcord/rest/routes/server/scheduled_events.rb +86 -0
  183. data/lib/onyxcord/rest/routes/server.rb +12 -0
  184. data/lib/onyxcord/{api → rest/routes}/user.rb +23 -23
  185. data/lib/onyxcord/{api → rest/routes}/webhook.rb +22 -22
  186. data/lib/onyxcord/{allowed_mentions.rb → utils/allowed_mentions.rb} +1 -1
  187. data/lib/onyxcord/utils/timestamp.rb +69 -0
  188. data/lib/onyxcord/voice/{voice_bot.rb → client.rb} +4 -4
  189. data/lib/onyxcord/voice/encoder.rb +1 -1
  190. data/lib/onyxcord/voice/network/udp.rb +135 -0
  191. data/lib/onyxcord/voice/network/websocket.rb +225 -0
  192. data/lib/onyxcord/voice/network.rb +5 -357
  193. data/lib/onyxcord/webhooks/builder.rb +1 -1
  194. data/lib/onyxcord/webhooks/client.rb +13 -13
  195. data/lib/onyxcord/webhooks/modal/group_builder.rb +55 -0
  196. data/lib/onyxcord/webhooks/modal/label_builder.rb +183 -0
  197. data/lib/onyxcord/webhooks/modal.rb +2 -239
  198. data/lib/onyxcord/webhooks/version.rb +3 -3
  199. data/lib/onyxcord/webhooks/view/container_builder.rb +80 -0
  200. data/lib/onyxcord/webhooks/view/file_builder.rb +24 -0
  201. data/lib/onyxcord/webhooks/view/media_gallery_builder.rb +50 -0
  202. data/lib/onyxcord/webhooks/view/row_builder.rb +120 -0
  203. data/lib/onyxcord/webhooks/view/section_builder.rb +61 -0
  204. data/lib/onyxcord/webhooks/view/select_menu_builder.rb +77 -0
  205. data/lib/onyxcord/webhooks/view/separator_builder.rb +22 -0
  206. data/lib/onyxcord/webhooks/view/text_display_builder.rb +20 -0
  207. data/lib/onyxcord/webhooks/view.rb +9 -425
  208. data/lib/onyxcord.rb +106 -42
  209. metadata +207 -92
  210. data/.github/CONTRIBUTING.md +0 -13
  211. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  212. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
  213. data/.github/pull_request_template.md +0 -37
  214. data/.github/workflows/ci.yml +0 -78
  215. data/.github/workflows/codeql.yml +0 -65
  216. data/.github/workflows/deploy.yml +0 -54
  217. data/.github/workflows/release.yml +0 -51
  218. data/.gitignore +0 -17
  219. data/.markdownlint.json +0 -4
  220. data/.overcommit.yml +0 -7
  221. data/.rspec +0 -2
  222. data/.rubocop.yml +0 -129
  223. data/.yardopts +0 -1
  224. data/CHANGELOG.md +0 -257
  225. data/Gemfile +0 -6
  226. data/LICENSE.txt +0 -21
  227. data/README.md +0 -448
  228. data/Rakefile +0 -13
  229. data/lib/onyxcord/api/channel.rb +0 -703
  230. data/lib/onyxcord/api/server.rb +0 -775
  231. data/lib/onyxcord/async/runtime.rb +0 -30
  232. data/lib/onyxcord/commands/command_bot.rb +0 -505
  233. data/lib/onyxcord/data/interaction.rb +0 -1151
  234. data/lib/onyxcord/data.rb +0 -57
  235. data/lib/onyxcord/event_executor.rb +0 -153
  236. data/lib/onyxcord/gateway.rb +0 -505
  237. data/lib/onyxcord/http.rb +0 -186
  238. data/lib/onyxcord/json.rb +0 -49
  239. data/lib/onyxcord/rate_limiter/async_rest.rb +0 -150
  240. data/lib/onyxcord/rate_limiter/gateway.rb +0 -42
  241. data/lib/onyxcord/rate_limiter/rest.rb +0 -142
  242. data/lib/onyxcord/version.rb +0 -7
  243. data/lib/onyxcord/websocket.rb +0 -77
  244. data/onyxcord.gemspec +0 -63
  245. /data/lib/onyxcord/{configuration.rb → core/configuration.rb} +0 -0
  246. /data/lib/onyxcord/{errors.rb → core/errors.rb} +0 -0
  247. /data/lib/onyxcord/{upload.rb → internal/upload.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,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../json'
4
+
5
+ module OnyxCord
6
+ module Internal
7
+ module RateLimiter
8
+ # Discord REST rate limiter keyed by route/major parameter and remapped to
9
+ # X-RateLimit-Bucket whenever Discord returns a concrete bucket id.
10
+ class Rest
11
+ DEFAULT_ENTRY_TTL = 3600
12
+ DEFAULT_PRUNE_INTERVAL = 100
13
+
14
+ def initialize(clock: -> { Time.now }, entry_ttl: DEFAULT_ENTRY_TTL, prune_interval: DEFAULT_PRUNE_INTERVAL)
15
+ @route_buckets = {}
16
+ @bucket_mutexes = {}
17
+ @bucket_last_used = {}
18
+ @global_mutex = Mutex.new
19
+ @clock = clock
20
+ @entry_ttl = entry_ttl
21
+ @prune_interval = prune_interval
22
+ @requests_since_prune = 0
23
+ end
24
+
25
+ def before_request(route, major_parameter)
26
+ mutex_wait(mutex_for(route, major_parameter))
27
+ mutex_wait(@global_mutex) if @global_mutex.locked?
28
+ end
29
+
30
+ def record_response(route, major_parameter, headers)
31
+ headers = normalize_headers(headers)
32
+ bucket = headers[:x_ratelimit_bucket]
33
+ key = route_key(route, major_parameter)
34
+ touch(key)
35
+
36
+ if bucket
37
+ bucket = bucket_key(bucket, major_parameter)
38
+ @route_buckets[key] = bucket
39
+ touch(bucket)
40
+ end
41
+
42
+ return unless headers[:x_ratelimit_remaining] == '0'
43
+
44
+ wait_seconds = headers[:x_ratelimit_reset_after].to_f
45
+ return unless wait_seconds.positive?
46
+
47
+ sync_wait(wait_seconds, mutex_for(route, major_parameter))
48
+ end
49
+
50
+ def handle_rate_limit(route, major_parameter, response)
51
+ headers = normalize_headers(response.headers)
52
+ mutex = headers[:x_ratelimit_global] == 'true' || headers[:x_ratelimit_scope] == 'global' ? @global_mutex : mutex_for(route, major_parameter)
53
+ wait_seconds = retry_after(response, headers)
54
+
55
+ sync_wait(wait_seconds, mutex) if wait_seconds.positive?
56
+ end
57
+
58
+ def stats
59
+ {
60
+ route_buckets: @route_buckets.size,
61
+ bucket_mutexes: @bucket_mutexes.size,
62
+ tracked_keys: @bucket_last_used.size
63
+ }
64
+ end
65
+
66
+ def prune!
67
+ return 0 unless @entry_ttl
68
+
69
+ cutoff = @clock.call - @entry_ttl
70
+ stale_keys = @bucket_last_used.select { |_, last_used| last_used < cutoff }.keys
71
+
72
+ stale_keys.each do |key|
73
+ @bucket_mutexes.delete(key)
74
+ @bucket_last_used.delete(key)
75
+ @route_buckets.delete(key)
76
+ @route_buckets.delete_if { |_, bucket_key| bucket_key == key }
77
+ end
78
+
79
+ @requests_since_prune = 0
80
+ stale_keys.length
81
+ end
82
+
83
+ private
84
+
85
+ def mutex_for(route, major_parameter)
86
+ key = resolved_key(route, major_parameter)
87
+ touch(key)
88
+ @bucket_mutexes[key] ||= Mutex.new
89
+ end
90
+
91
+ def resolved_key(route, major_parameter)
92
+ @route_buckets[route_key(route, major_parameter)] || route_key(route, major_parameter)
93
+ end
94
+
95
+ def route_key(route, major_parameter)
96
+ [route, major_parameter].freeze
97
+ end
98
+
99
+ def bucket_key(bucket, major_parameter)
100
+ [:bucket, bucket, major_parameter].freeze
101
+ end
102
+
103
+ def retry_after(response, headers)
104
+ body = response.respond_to?(:body) ? response.body : response.to_s
105
+ if body && !body.empty?
106
+ data = JSON.parse(body)
107
+ return data['retry_after'].to_f if data['retry_after']
108
+ end
109
+
110
+ (headers[:retry_after] || 0).to_f
111
+ rescue JSON::ParserError
112
+ (headers[:retry_after] || 0).to_f
113
+ end
114
+
115
+ def normalize_headers(headers)
116
+ headers.each_with_object({}) do |(key, value), memo|
117
+ memo[key.to_s.tr('-', '_').downcase.to_sym] = value.to_s
118
+ end
119
+ end
120
+
121
+ def touch(key)
122
+ @bucket_last_used[key] = @clock.call
123
+ prune_if_needed
124
+ end
125
+
126
+ def prune_if_needed
127
+ return unless @prune_interval
128
+
129
+ @requests_since_prune += 1
130
+ prune! if @requests_since_prune >= @prune_interval
131
+ end
132
+
133
+ def sync_wait(time, mutex)
134
+ mutex.synchronize { sleep time }
135
+ end
136
+
137
+ def mutex_wait(mutex)
138
+ mutex.lock
139
+ mutex.unlock
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'async_runtime'
4
+ require 'async/http/endpoint'
5
+ require 'async/http/protocol/http11'
6
+ require 'async/websocket/client'
7
+
8
+ module OnyxCord
9
+ module Internal
10
+ class WebSocket
11
+ attr_reader :connected
12
+
13
+ alias_method :connected?, :connected
14
+
15
+ def initialize(host, open_handler, message_handler, error_handler, close_handler)
16
+ @host = host
17
+ @open_handler = open_handler
18
+ @message_handler = message_handler
19
+ @error_handler = error_handler
20
+ @close_handler = close_handler
21
+
22
+ @connection = nil
23
+ @connected = false
24
+
25
+ connect
26
+ end
27
+
28
+ def send(data)
29
+ return unless @connection
30
+
31
+ data = data.to_json if data.is_a?(Hash)
32
+ @connection.write(Protocol::WebSocket::TextMessage.generate(data))
33
+ @connection.flush
34
+ rescue StandardError => e
35
+ @error_handler&.call(e)
36
+ end
37
+
38
+ def close
39
+ @connected = false
40
+ @connection&.close
41
+ rescue StandardError
42
+ # Ignore errors on close
43
+ end
44
+
45
+ private
46
+
47
+ def connect
48
+ endpoint = websocket_endpoint(@host)
49
+
50
+ @task = AsyncRuntime.async do
51
+ Async::WebSocket::Client.connect(endpoint, extensions: nil) do |connection|
52
+ @connection = connection
53
+ @connected = true
54
+ @open_handler&.call
55
+
56
+ while (message = connection.read)
57
+ @message_handler&.call(message.to_str)
58
+ end
59
+ rescue StandardError => e
60
+ @error_handler&.call(e)
61
+ ensure
62
+ @connected = false
63
+ @close_handler&.call(nil)
64
+ end
65
+ end
66
+ rescue StandardError => e
67
+ @error_handler&.call(e)
68
+ end
69
+
70
+ def websocket_endpoint(url)
71
+ Async::HTTP::Endpoint.parse(
72
+ url,
73
+ protocol: Async::HTTP::Protocol::HTTP11,
74
+ alpn_protocols: ['http/1.1']
75
+ )
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'onyxcord/data'
3
+ require 'onyxcord/models'
4
4
 
5
5
  module OnyxCord::Light
6
6
  # Represents the bot account used for the light bot, but without any methods to change anything.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'onyxcord/data'
3
+ require 'onyxcord/models'
4
4
  require 'onyxcord/light/data'
5
5
 
6
6
  module OnyxCord::Light
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'onyxcord/api'
4
- require 'onyxcord/api/invite'
5
- require 'onyxcord/api/user'
3
+ require 'onyxcord/rest/client'
4
+ require 'onyxcord/rest/routes/invite'
5
+ require 'onyxcord/rest/routes/user'
6
6
  require 'onyxcord/light/data'
7
7
  require 'onyxcord/light/integrations'
8
8
 
@@ -31,13 +31,13 @@ module OnyxCord::Light
31
31
 
32
32
  # @return [LightProfile] the details of the user this bot is connected to.
33
33
  def profile
34
- response = OnyxCord::API::User.profile(@token)
34
+ response = OnyxCord::REST::User.profile(@token)
35
35
  LightProfile.new(JSON.parse(response), self)
36
36
  end
37
37
 
38
38
  # @return [Array<LightServer>] the servers this bot is connected to.
39
39
  def servers
40
- response = OnyxCord::API::User.servers(@token)
40
+ response = OnyxCord::REST::User.servers(@token)
41
41
  JSON.parse(response).map { |e| LightServer.new(e, self) }
42
42
  end
43
43
 
@@ -45,13 +45,13 @@ module OnyxCord::Light
45
45
  # @param code [String] The code part of the invite (for example 0cDvIgU2voWn4BaD if the invite URL is
46
46
  # https://discord.gg/0cDvIgU2voWn4BaD)
47
47
  def join(code)
48
- OnyxCord::API::Invite.accept(@token, code)
48
+ OnyxCord::REST::Invite.accept(@token, code)
49
49
  end
50
50
 
51
51
  # Gets the connections associated with this account.
52
52
  # @return [Array<Connection>] this account's connections.
53
53
  def connections
54
- response = OnyxCord::API::User.connections(@token)
54
+ response = OnyxCord::REST::User.connections(@token)
55
55
  JSON.parse(response).map { |e| Connection.new(e, self) }
56
56
  end
57
57
  end
@@ -188,14 +188,14 @@ module OnyxCord
188
188
  # @param format [String, nil] If `nil`, the URL will default to `webp`. You can otherwise specify one of `webp`, `jpg`, or `png`.
189
189
  # @return [String] the URL to the large image asset.
190
190
  def large_image_url(format = 'webp')
191
- API.asset_url(@application_id, @large_image_id, format)
191
+ REST.asset_url(@application_id, @large_image_id, format)
192
192
  end
193
193
 
194
194
  # Utility function to get an Asset's large image URL.
195
195
  # @param format [String, nil] If `nil`, the URL will default to `webp`. You can otherwise specify one of `webp`, `jpg`, or `png`.
196
196
  # @return [String] the URL to the small image asset.
197
197
  def small_image_url(format = 'webp')
198
- API.asset_url(@application_id, @small_image_id, format)
198
+ REST.asset_url(@application_id, @small_image_id, format)
199
199
  end
200
200
  end
201
201
 
@@ -131,14 +131,14 @@ module OnyxCord
131
131
  # @param format [String] The URL will default to `webp`. You can otherwise specify one of `webp`, `jpg` or `png` to override this.
132
132
  # @return [String, nil] The URL of the icon image (`nil` if no image is set).
133
133
  def icon_url(format: 'webp')
134
- API.app_icon_url(@id, @icon_id, format) if @icon_id
134
+ REST.app_icon_url(@id, @icon_id, format) if @icon_id
135
135
  end
136
136
 
137
137
  # Utility method to get a application's cover image URL.
138
138
  # @param format [String] The URL will default to `webp`. You can otherwise specify one of `webp`, `jpg` or `png` to override this.
139
139
  # @return [String, nil] The URL of the cover image (`nil` if no cover is set).
140
140
  def cover_image_url(format: 'webp')
141
- API.app_cover_url(@id, @cover_image_id, format) if @cover_image_id
141
+ REST.app_cover_url(@id, @cover_image_id, format) if @cover_image_id
142
142
  end
143
143
 
144
144
  # Delete an integration types config for the application.
@@ -236,7 +236,7 @@ module OnyxCord
236
236
  data[:flags] = ((@flags & ~to_flags.call(remove_flags)) | to_flags.call(add_flags))
237
237
  end
238
238
 
239
- update_data(JSON.parse(API::Application.update_current_application(@bot.token, **data)))
239
+ update_data(JSON.parse(REST::Application.update_current_application(@bot.token, **data)))
240
240
  nil
241
241
  end
242
242
 
@@ -20,7 +20,7 @@ module OnyxCord
20
20
  # Utility method to get an avatar decoration URL.
21
21
  # @return [String] the URL to the avatar decoration.
22
22
  def url
23
- API.avatar_decoration_url(@decoration_id)
23
+ REST.avatar_decoration_url(@decoration_id)
24
24
  end
25
25
  end
26
26
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'onyxcord/webhooks/view'
4
- require 'onyxcord/message_components'
4
+ require 'onyxcord/utils/message_components'
5
5
  require 'time'
6
6
 
7
7
  module OnyxCord
@@ -412,7 +412,7 @@ module OnyxCord
412
412
  move_argument << hash
413
413
  end
414
414
 
415
- API::Server.update_channel_positions(@bot.token, @server_id, move_argument)
415
+ REST::Server.update_channel_positions(@bot.token, @server_id, move_argument)
416
416
  end
417
417
 
418
418
  # Check if this channel is marked as NSFW.
@@ -667,13 +667,13 @@ module OnyxCord
667
667
  # Deletes a message on this channel. Mostly useful in case a message needs to be deleted when only the ID is known
668
668
  # @param message [Message, String, Integer, String, Integer] The message, or its ID, that should be deleted.
669
669
  def delete_message(message)
670
- API::Channel.delete_message(@bot.token, @id, message.resolve_id)
670
+ REST::Channel.delete_message(@bot.token, @id, message.resolve_id)
671
671
  end
672
672
 
673
673
  # Permanently deletes this channel
674
674
  # @param reason [String] The reason the for the channel deletion.
675
675
  def delete(reason = nil)
676
- API::Channel.delete(@bot.token, @id, reason)
676
+ REST::Channel.delete(@bot.token, @id, reason)
677
677
  end
678
678
 
679
679
  # Sets this channel's name. The name must be alphanumeric with dashes, unless this is a voice channel (then there are no limitations)
@@ -743,7 +743,7 @@ module OnyxCord
743
743
  thing = Overwrite.new(thing, allow: allow_bits, deny: deny_bits)
744
744
  end
745
745
 
746
- API::Channel.update_permission(@bot.token, @id, thing.id, thing.allow.bits, thing.deny.bits, thing.type, reason)
746
+ REST::Channel.update_permission(@bot.token, @id, thing.id, thing.allow.bits, thing.deny.bits, thing.type, reason)
747
747
  end
748
748
 
749
749
  # Deletes a permission overwrite for this channel
@@ -752,7 +752,7 @@ module OnyxCord
752
752
  def delete_overwrite(target, reason = nil)
753
753
  raise 'Tried deleting a overwrite for an invalid target' unless target.respond_to?(:resolve_id)
754
754
 
755
- API::Channel.delete_permission(@bot.token, @id, target.resolve_id, reason)
755
+ REST::Channel.delete_permission(@bot.token, @id, target.resolve_id, reason)
756
756
  end
757
757
 
758
758
  # The list of users currently in this channel. For a voice channel, it will return all the members currently
@@ -780,7 +780,7 @@ module OnyxCord
780
780
  # last_ten_messages = channel.history(10, message.id)
781
781
  # @return [Array<Message>] the retrieved messages.
782
782
  def history(amount, before_id = nil, after_id = nil, around_id = nil)
783
- logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
783
+ logs = REST::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
784
784
  JSON.parse(logs).map { |message| Message.new(message, @bot) }
785
785
  end
786
786
 
@@ -788,7 +788,7 @@ module OnyxCord
788
788
  # @note For internal use only
789
789
  # @!visibility private
790
790
  def history_ids(amount, before_id = nil, after_id = nil, around_id = nil)
791
- logs = API::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
791
+ logs = REST::Channel.messages(@bot.token, @id, amount, before_id, after_id, around_id)
792
792
  JSON.parse(logs).map { |message| message['id'].to_i }
793
793
  end
794
794
 
@@ -798,7 +798,7 @@ module OnyxCord
798
798
  def load_message(message_id)
799
799
  raise ArgumentError, 'message_id cannot be nil' if message_id.nil?
800
800
 
801
- response = API::Channel.message(@bot.token, @id, message_id)
801
+ response = REST::Channel.message(@bot.token, @id, message_id)
802
802
  Message.new(JSON.parse(response), @bot)
803
803
  rescue OnyxCord::Errors::UnknownMessage
804
804
  nil
@@ -811,7 +811,7 @@ module OnyxCord
811
811
  # @return [Array<Message>] the messages pinned in the channel.
812
812
  def pins(limit: 50)
813
813
  get_pins = proc do |fetch_limit, before = nil|
814
- resp = API::Channel.pinned_messages(@bot.token, @id, fetch_limit, before&.iso8601)
814
+ resp = REST::Channel.pinned_messages(@bot.token, @id, fetch_limit, before&.iso8601)
815
815
  JSON.parse(resp)['items'].map { |pin| Message.new(pin['message'].merge({ 'pinned_at' => pin['pinned_at'] }), @bot) }
816
816
  end
817
817
 
@@ -853,7 +853,7 @@ module OnyxCord
853
853
  when 0
854
854
  0
855
855
  when 1
856
- API::Channel.delete_message(@bot.token, @id, messages.first, reason)
856
+ REST::Channel.delete_message(@bot.token, @id, messages.first, reason)
857
857
  1
858
858
  else
859
859
  bulk_delete(messages, strict, reason)
@@ -904,7 +904,7 @@ module OnyxCord
904
904
  # @param reason [String] The reason the for the creation of this invite.
905
905
  # @return [Invite] the created invite.
906
906
  def make_invite(max_age = 0, max_uses = 0, temporary = false, unique = false, reason = nil)
907
- response = API::Channel.create_invite(@bot.token, @id, max_age, max_uses, temporary, unique, reason)
907
+ response = REST::Channel.create_invite(@bot.token, @id, max_age, max_uses, temporary, unique, reason)
908
908
  Invite.new(JSON.parse(response), @bot)
909
909
  end
910
910
 
@@ -916,7 +916,7 @@ module OnyxCord
916
916
  # @example Send a typing indicator for the bot in a given channel.
917
917
  # channel.start_typing()
918
918
  def start_typing
919
- API::Channel.start_typing(@bot.token, @id)
919
+ REST::Channel.start_typing(@bot.token, @id)
920
920
  end
921
921
 
922
922
  # Creates a webhook in this channel
@@ -928,7 +928,7 @@ module OnyxCord
928
928
  def create_webhook(name, avatar = nil, reason = nil)
929
929
  raise ArgumentError, 'Tried to create a webhook in a non-server channel' unless server
930
930
 
931
- response = API::Channel.create_webhook(@bot.token, @id, name, avatar, reason)
931
+ response = REST::Channel.create_webhook(@bot.token, @id, name, avatar, reason)
932
932
  Webhook.new(JSON.parse(response), @bot)
933
933
  end
934
934
 
@@ -937,7 +937,7 @@ module OnyxCord
937
937
  def webhooks
938
938
  raise 'Tried to request webhooks from a non-server channel' unless server
939
939
 
940
- webhooks = JSON.parse(API::Channel.webhooks(@bot.token, @id))
940
+ webhooks = JSON.parse(REST::Channel.webhooks(@bot.token, @id))
941
941
  webhooks.map { |webhook_data| Webhook.new(webhook_data, @bot) }
942
942
  end
943
943
 
@@ -946,7 +946,7 @@ module OnyxCord
946
946
  def invites
947
947
  raise 'Tried to request invites from a non-server channel' unless server
948
948
 
949
- invites = JSON.parse(API::Channel.invites(@bot.token, @id))
949
+ invites = JSON.parse(REST::Channel.invites(@bot.token, @id))
950
950
  invites.map { |invite_data| Invite.new(invite_data, @bot) }
951
951
  end
952
952
 
@@ -957,7 +957,7 @@ module OnyxCord
957
957
  def follow(target, reason: nil)
958
958
  raise 'Cannot follow a non-announcement channel' unless news?
959
959
 
960
- JSON.parse(API::Channel.follow_channel(@bot.token, @id, target.resolve_id, reason))['webhook_id'].to_i
960
+ JSON.parse(REST::Channel.follow_channel(@bot.token, @id, target.resolve_id, reason))['webhook_id'].to_i
961
961
  end
962
962
 
963
963
  # Returns the last message or forum post created in this channel.
@@ -985,9 +985,9 @@ module OnyxCord
985
985
  type = TYPES[type] || type
986
986
 
987
987
  data = if message
988
- API::Channel.start_thread_with_message(@bot.token, @id, message_id, name, auto_archive_duration)
988
+ REST::Channel.start_thread_with_message(@bot.token, @id, message_id, name, auto_archive_duration)
989
989
  else
990
- API::Channel.start_thread_without_message(@bot.token, @id, name, auto_archive_duration, type)
990
+ REST::Channel.start_thread_without_message(@bot.token, @id, name, auto_archive_duration, type)
991
991
  end
992
992
 
993
993
  @bot.ensure_channel(JSON.parse(data))
@@ -1026,7 +1026,7 @@ module OnyxCord
1026
1026
  builder = builder.to_json_hash
1027
1027
 
1028
1028
  message = { content: builder[:content], embeds: builder[:embeds], allowed_mentions: builder[:allowed_mentions], components: components, sticker_ids: stickers&.map(&:resolve_id), flags: flags }
1029
- response = JSON.parse(API::Channel.start_thread_in_forum_or_media_channel(@bot.token, @id, name, message.compact, attachments, rate_limit_per_user, auto_archive_duration, tags&.map(&:resolve_id), reason))
1029
+ response = JSON.parse(REST::Channel.start_thread_in_forum_or_media_channel(@bot.token, @id, name, message.compact, attachments, rate_limit_per_user, auto_archive_duration, tags&.map(&:resolve_id), reason))
1030
1030
 
1031
1031
  Message.new(response['message'].merge!('channel_id' => response['id'], 'thread' => response), @bot)
1032
1032
  end
@@ -1207,7 +1207,7 @@ module OnyxCord
1207
1207
  data[:flags] = ((@flags & ~to_flags.call(remove_flags)) | to_flags.call(add_flags))
1208
1208
  end
1209
1209
 
1210
- update_data(JSON.parse(API::Channel.update!(@bot.token, @id, **data, reason: reason)))
1210
+ update_data(JSON.parse(REST::Channel.update!(@bot.token, @id, **data, reason: reason)))
1211
1211
  nil
1212
1212
  end
1213
1213
 
@@ -1249,7 +1249,7 @@ module OnyxCord
1249
1249
  # @note For internal use only
1250
1250
  # @!visibility private
1251
1251
  def update_data(new_data = nil)
1252
- new_data ||= JSON.parse(API::Channel.resolve(@bot.token, @id))
1252
+ new_data ||= JSON.parse(REST::Channel.resolve(@bot.token, @id))
1253
1253
  @type = new_data['type'] || 0
1254
1254
  @topic = new_data['topic']
1255
1255
  @bitrate = new_data['bitrate']
@@ -1316,7 +1316,7 @@ module OnyxCord
1316
1316
  true
1317
1317
  end
1318
1318
 
1319
- API::Channel.bulk_delete_messages(@bot.token, @id, ids, reason)
1319
+ REST::Channel.bulk_delete_messages(@bot.token, @id, ids, reason)
1320
1320
  ids.size
1321
1321
  end
1322
1322
 
@@ -40,7 +40,7 @@ module OnyxCord
40
40
  # nameplate instead of the animated URL.
41
41
  # @return [String] The CDN url of this nameplate.
42
42
  def url(static: false)
43
- static ? API.static_nameplate_url(@asset) : API.nameplate_url(@asset)
43
+ static ? REST.static_nameplate_url(@asset) : REST.nameplate_url(@asset)
44
44
  end
45
45
  end
46
46
  end
@@ -79,7 +79,7 @@ module OnyxCord
79
79
 
80
80
  # @return [String] the icon URL of the emoji
81
81
  def icon_url
82
- API.emoji_icon_url(id)
82
+ REST.emoji_icon_url(id)
83
83
  end
84
84
 
85
85
  # The inspect method is overwritten to give more useful output