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
data/lib/onyxcord/http.rb DELETED
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'httpx'
4
- require 'onyxcord/json'
5
-
6
- module OnyxCord
7
- # Modern HTTP adapter wrapping HTTPX with persistent connections, automatic
8
- # retries on 502, and a response interface compatible with the rest of OnyxCord.
9
- module HTTP
10
- # Lightweight response wrapper so call-sites that relied on RestClient's
11
- # `.body`, `.headers`, `.code` interface keep working unchanged.
12
- class Response
13
- # @return [String] the response body
14
- attr_reader :body
15
-
16
- # @return [Integer] the HTTP status code
17
- attr_reader :code
18
-
19
- # @return [Hash] the response headers (symbol keys, underscored)
20
- attr_reader :headers
21
-
22
- def initialize(httpx_response)
23
- @raw = httpx_response
24
- @body = httpx_response.body.to_s
25
- @code = httpx_response.status
26
- @headers = normalize_headers(httpx_response.headers)
27
- end
28
-
29
- def to_s
30
- @body
31
- end
32
-
33
- # RestClient compatibility — some code calls `response` directly as a
34
- # string (implicit to_s).
35
- alias_method :to_str, :to_s
36
-
37
- private
38
-
39
- def normalize_headers(headers)
40
- headers.to_h.transform_keys do |key|
41
- key.to_s.tr('-', '_').downcase.to_sym
42
- end
43
- end
44
- end
45
-
46
- module_function
47
-
48
- # The shared HTTPX session with persistent connections for the current thread.
49
- def session
50
- Thread.current[:onyxcord_http_session] ||= HTTPX.plugin(:persistent)
51
- .plugin(:follow_redirects)
52
- end
53
-
54
- # Reset the HTTP session (useful for tests).
55
- def reset!
56
- Thread.current[:onyxcord_http_session] = nil
57
- end
58
-
59
- # Perform a raw HTTP request and return a {Response}.
60
- # @param type [Symbol] HTTP method (:get, :post, :put, :patch, :delete)
61
- # @param url [String] The full URL.
62
- # @param body [String, Hash, nil] The request body.
63
- # @param headers [Hash] Request headers.
64
- # @return [Response]
65
- def request(type, url, body = nil, **headers)
66
- http = session.with(headers: headers)
67
-
68
- raw = case type
69
- when :get
70
- http.get(url)
71
- when :post
72
- if body.is_a?(Hash) && body.any? { |_, v| v.respond_to?(:read) || v.respond_to?(:path) }
73
- # Multipart upload
74
- http.plugin(:multipart).post(url, form: body)
75
- else
76
- http.post(url, body: body)
77
- end
78
- when :put
79
- http.put(url, body: body)
80
- when :patch
81
- http.patch(url, body: body)
82
- when :delete
83
- http.delete(url)
84
- else
85
- raise ArgumentError, "Unknown HTTP method: #{type}"
86
- end
87
-
88
- # HTTPX returns an error response object on network failures
89
- raise raw.error if raw.is_a?(HTTPX::ErrorResponse)
90
-
91
- Response.new(raw)
92
- end
93
-
94
- # Convenience wrappers
95
- def get(url, **headers)
96
- request(:get, url, nil, **headers)
97
- end
98
-
99
- def post(url, body = nil, **headers)
100
- request(:post, url, body, **headers)
101
- end
102
-
103
- def put(url, body = nil, **headers)
104
- request(:put, url, body, **headers)
105
- end
106
-
107
- def patch(url, body = nil, **headers)
108
- request(:patch, url, body, **headers)
109
- end
110
-
111
- def delete(url, **headers)
112
- request(:delete, url, nil, **headers)
113
- end
114
- end
115
- end
data/lib/onyxcord/json.rb DELETED
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'oj'
4
-
5
- # Configure Oj in compat mode so that all stdlib JSON.parse / .to_json calls
6
- # are transparently accelerated. This is loaded early by the main onyxcord.rb
7
- # entry point so every module benefits automatically.
8
- module OnyxCord
9
- # Fast Oj-backed JSON wrapper providing compatibility with stdlib JSON methods.
10
- module JSON
11
- Oj.default_options = { mode: :compat, symbol_keys: false }
12
-
13
- module_function
14
-
15
- # Fast JSON decode using Oj via stdlib JSON compatibility.
16
- # @param data [String] The JSON string to decode.
17
- # @return [Hash, Array, String, Numeric, nil]
18
- def decode(data, *args)
19
- ::JSON.parse(data, *args)
20
- end
21
-
22
- # Fast JSON encode using Oj via stdlib JSON compatibility.
23
- # @param data [Object] The object to encode as JSON.
24
- # @return [String]
25
- def encode(data, *args)
26
- ::JSON.generate(data, *args)
27
- end
28
-
29
- # Alias parse to decode for standard library compatibility
30
- def parse(data, *args)
31
- ::JSON.parse(data, *args)
32
- end
33
-
34
- # Alias generate to encode for standard library compatibility
35
- def generate(data, *args)
36
- ::JSON.generate(data, *args)
37
- end
38
-
39
- # Alias load to decode for Oj/JSON compatibility
40
- def load(data, *args)
41
- ::JSON.parse(data, *args)
42
- end
43
-
44
- # Alias dump to encode for Oj/JSON compatibility
45
- def dump(data, *args)
46
- ::JSON.generate(data, *args)
47
- end
48
- end
49
- end
@@ -1,149 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
- require 'onyxcord/async/runtime'
5
-
6
- module OnyxCord
7
- module RateLimiter
8
- class AsyncRest
9
- DEFAULT_ENTRY_TTL = 3600
10
- DEFAULT_PRUNE_INTERVAL = 100
11
-
12
- def initialize(clock: -> { Time.now }, entry_ttl: DEFAULT_ENTRY_TTL, prune_interval: DEFAULT_PRUNE_INTERVAL)
13
- @route_buckets = {}
14
- @bucket_locks = {}
15
- @bucket_last_used = {}
16
- @global_lock = Mutex.new
17
- @clock = clock
18
- @entry_ttl = entry_ttl
19
- @prune_interval = prune_interval
20
- @requests_since_prune = 0
21
- end
22
-
23
- def before_request(route, major_parameter)
24
- wait_for(mutex_for(route, major_parameter))
25
- end
26
-
27
- def record_response(route, major_parameter, headers)
28
- headers = normalize_headers(headers)
29
- bucket = headers[:x_ratelimit_bucket]
30
- key = route_key(route, major_parameter)
31
- touch(key)
32
-
33
- if bucket
34
- bucket = bucket_key(bucket, major_parameter)
35
- @route_buckets[key] = bucket
36
- touch(bucket)
37
- end
38
-
39
- return unless headers[:x_ratelimit_remaining] == '0'
40
-
41
- wait_seconds = headers[:x_ratelimit_reset_after].to_f
42
- return unless wait_seconds.positive?
43
-
44
- async_wait(wait_seconds, mutex_for(route, major_parameter))
45
- end
46
-
47
- def handle_rate_limit(route, major_parameter, response)
48
- headers = normalize_headers(response.headers)
49
- wait_seconds = retry_after(response, headers)
50
-
51
- return unless wait_seconds.positive?
52
-
53
- if headers[:x_ratelimit_global] == 'true' || headers[:x_ratelimit_scope] == 'global'
54
- global_wait(wait_seconds)
55
- else
56
- async_wait(wait_seconds, mutex_for(route, major_parameter))
57
- end
58
- end
59
-
60
- def stats
61
- {
62
- route_buckets: @route_buckets.size,
63
- bucket_locks: @bucket_locks.size,
64
- tracked_keys: @bucket_last_used.size
65
- }
66
- end
67
-
68
- def prune!
69
- return 0 unless @entry_ttl
70
-
71
- cutoff = @clock.call - @entry_ttl
72
- stale_keys = @bucket_last_used.select { |_, last_used| last_used < cutoff }.keys
73
-
74
- stale_keys.each do |key|
75
- @bucket_locks.delete(key)
76
- @bucket_last_used.delete(key)
77
- @route_buckets.delete(key)
78
- @route_buckets.delete_if { |_, bucket_key| bucket_key == key }
79
- end
80
-
81
- @requests_since_prune = 0
82
- stale_keys.length
83
- end
84
-
85
- private
86
-
87
- def mutex_for(route, major_parameter)
88
- key = resolved_key(route, major_parameter)
89
- touch(key)
90
- @bucket_locks[key] ||= Mutex.new
91
- end
92
-
93
- def resolved_key(route, major_parameter)
94
- @route_buckets[route_key(route, major_parameter)] || route_key(route, major_parameter)
95
- end
96
-
97
- def route_key(route, major_parameter)
98
- [route, major_parameter].freeze
99
- end
100
-
101
- def bucket_key(bucket, major_parameter)
102
- [:bucket, bucket, major_parameter].freeze
103
- end
104
-
105
- def retry_after(response, headers)
106
- body = response.respond_to?(:body) ? response.body : response.to_s
107
- if body && !body.empty?
108
- data = JSON.parse(body)
109
- return data['retry_after'].to_f if data['retry_after']
110
- end
111
-
112
- (headers[:retry_after] || 0).to_f
113
- rescue JSON::ParserError
114
- (headers[:retry_after] || 0).to_f
115
- end
116
-
117
- def normalize_headers(headers)
118
- headers.each_with_object({}) do |(key, value), memo|
119
- memo[key.to_s.tr('-', '_').downcase.to_sym] = value.to_s
120
- end
121
- end
122
-
123
- def touch(key)
124
- @bucket_last_used[key] = @clock.call
125
- prune_if_needed
126
- end
127
-
128
- def prune_if_needed
129
- return unless @prune_interval
130
-
131
- @requests_since_prune += 1
132
- prune! if @requests_since_prune >= @prune_interval
133
- end
134
-
135
- def wait_for(mutex)
136
- mutex.lock
137
- mutex.unlock
138
- end
139
-
140
- def async_wait(time, mutex)
141
- mutex.synchronize { OnyxCord::AsyncRuntime.sleep(time) }
142
- end
143
-
144
- def global_wait(time)
145
- OnyxCord::AsyncRuntime.sleep(time)
146
- end
147
- end
148
- end
149
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OnyxCord
4
- module RateLimiter
5
- # Sliding-window limiter for Gateway sends.
6
- class Gateway
7
- DEFAULT_LIMIT = 120
8
- DEFAULT_INTERVAL = 60
9
-
10
- def initialize(limit: DEFAULT_LIMIT, interval: DEFAULT_INTERVAL, clock: -> { Time.now }, sleeper: ->(duration) { sleep(duration) })
11
- @limit = limit
12
- @interval = interval
13
- @clock = clock
14
- @sleeper = sleeper
15
- @sent_at = []
16
- @mutex = Mutex.new
17
- end
18
-
19
- def wait
20
- @mutex.synchronize do
21
- now = @clock.call
22
- prune(now)
23
-
24
- if @sent_at.length >= @limit
25
- sleep_for = @interval - (now - @sent_at.first)
26
- @sleeper.call(sleep_for) if sleep_for.positive?
27
- now = @clock.call
28
- prune(now)
29
- end
30
-
31
- @sent_at << now
32
- end
33
- end
34
-
35
- private
36
-
37
- def prune(now)
38
- @sent_at.shift while @sent_at.any? && (now - @sent_at.first) >= @interval
39
- end
40
- end
41
- end
42
- end
@@ -1,142 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'onyxcord/json'
4
-
5
- module OnyxCord
6
- module RateLimiter
7
- # Discord REST rate limiter keyed by route/major parameter and remapped to
8
- # X-RateLimit-Bucket whenever Discord returns a concrete bucket id.
9
- class Rest
10
- DEFAULT_ENTRY_TTL = 3600
11
- DEFAULT_PRUNE_INTERVAL = 100
12
-
13
- def initialize(clock: -> { Time.now }, entry_ttl: DEFAULT_ENTRY_TTL, prune_interval: DEFAULT_PRUNE_INTERVAL)
14
- @route_buckets = {}
15
- @bucket_mutexes = {}
16
- @bucket_last_used = {}
17
- @global_mutex = Mutex.new
18
- @clock = clock
19
- @entry_ttl = entry_ttl
20
- @prune_interval = prune_interval
21
- @requests_since_prune = 0
22
- end
23
-
24
- def before_request(route, major_parameter)
25
- mutex_wait(mutex_for(route, major_parameter))
26
- mutex_wait(@global_mutex) if @global_mutex.locked?
27
- end
28
-
29
- def record_response(route, major_parameter, headers)
30
- headers = normalize_headers(headers)
31
- bucket = headers[:x_ratelimit_bucket]
32
- key = route_key(route, major_parameter)
33
- touch(key)
34
-
35
- if bucket
36
- bucket = bucket_key(bucket, major_parameter)
37
- @route_buckets[key] = bucket
38
- touch(bucket)
39
- end
40
-
41
- return unless headers[:x_ratelimit_remaining] == '0'
42
-
43
- wait_seconds = headers[:x_ratelimit_reset_after].to_f
44
- return unless wait_seconds.positive?
45
-
46
- sync_wait(wait_seconds, mutex_for(route, major_parameter))
47
- end
48
-
49
- def handle_rate_limit(route, major_parameter, response)
50
- headers = normalize_headers(response.headers)
51
- mutex = headers[:x_ratelimit_global] == 'true' || headers[:x_ratelimit_scope] == 'global' ? @global_mutex : mutex_for(route, major_parameter)
52
- wait_seconds = retry_after(response, headers)
53
-
54
- sync_wait(wait_seconds, mutex) if wait_seconds.positive?
55
- end
56
-
57
- def stats
58
- {
59
- route_buckets: @route_buckets.size,
60
- bucket_mutexes: @bucket_mutexes.size,
61
- tracked_keys: @bucket_last_used.size
62
- }
63
- end
64
-
65
- def prune!
66
- return 0 unless @entry_ttl
67
-
68
- cutoff = @clock.call - @entry_ttl
69
- stale_keys = @bucket_last_used.select { |_, last_used| last_used < cutoff }.keys
70
-
71
- stale_keys.each do |key|
72
- @bucket_mutexes.delete(key)
73
- @bucket_last_used.delete(key)
74
- @route_buckets.delete(key)
75
- @route_buckets.delete_if { |_, bucket_key| bucket_key == key }
76
- end
77
-
78
- @requests_since_prune = 0
79
- stale_keys.length
80
- end
81
-
82
- private
83
-
84
- def mutex_for(route, major_parameter)
85
- key = resolved_key(route, major_parameter)
86
- touch(key)
87
- @bucket_mutexes[key] ||= Mutex.new
88
- end
89
-
90
- def resolved_key(route, major_parameter)
91
- @route_buckets[route_key(route, major_parameter)] || route_key(route, major_parameter)
92
- end
93
-
94
- def route_key(route, major_parameter)
95
- [route, major_parameter].freeze
96
- end
97
-
98
- def bucket_key(bucket, major_parameter)
99
- [:bucket, bucket, major_parameter].freeze
100
- end
101
-
102
- def retry_after(response, headers)
103
- body = response.respond_to?(:body) ? response.body : response.to_s
104
- if body && !body.empty?
105
- data = JSON.parse(body)
106
- return data['retry_after'].to_f if data['retry_after']
107
- end
108
-
109
- (headers[:retry_after] || 0).to_f
110
- rescue JSON::ParserError
111
- (headers[:retry_after] || 0).to_f
112
- end
113
-
114
- def normalize_headers(headers)
115
- headers.each_with_object({}) do |(key, value), memo|
116
- memo[key.to_s.tr('-', '_').downcase.to_sym] = value.to_s
117
- end
118
- end
119
-
120
- def touch(key)
121
- @bucket_last_used[key] = @clock.call
122
- prune_if_needed
123
- end
124
-
125
- def prune_if_needed
126
- return unless @prune_interval
127
-
128
- @requests_since_prune += 1
129
- prune! if @requests_since_prune >= @prune_interval
130
- end
131
-
132
- def sync_wait(time, mutex)
133
- mutex.synchronize { sleep time }
134
- end
135
-
136
- def mutex_wait(mutex)
137
- mutex.lock
138
- mutex.unlock
139
- end
140
- end
141
- end
142
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # OnyxCord and all its functionality, in this case only the version.
4
- module OnyxCord
5
- # The current version of onyxcord.
6
- VERSION = '2.0.13'
7
- end
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'onyxcord/async/runtime'
4
- require 'async/http/endpoint'
5
- require 'async/http/protocol/http11'
6
- require 'async/websocket/client'
7
-
8
- module OnyxCord
9
- class WebSocket
10
- attr_reader :connected
11
-
12
- alias_method :connected?, :connected
13
-
14
- def initialize(host, open_handler, message_handler, error_handler, close_handler)
15
- @host = host
16
- @open_handler = open_handler
17
- @message_handler = message_handler
18
- @error_handler = error_handler
19
- @close_handler = close_handler
20
-
21
- @connection = nil
22
- @connected = false
23
-
24
- connect
25
- end
26
-
27
- def send(data)
28
- return unless @connection
29
-
30
- data = data.to_json if data.is_a?(Hash)
31
- @connection.write(Protocol::WebSocket::TextMessage.generate(data))
32
- @connection.flush
33
- rescue StandardError => e
34
- @error_handler&.call(e)
35
- end
36
-
37
- def close
38
- @connected = false
39
- @connection&.close
40
- rescue StandardError
41
- # Ignore errors on close
42
- end
43
-
44
- private
45
-
46
- def connect
47
- endpoint = websocket_endpoint(@host)
48
-
49
- @task = OnyxCord::AsyncRuntime.async do
50
- Async::WebSocket::Client.connect(endpoint, extensions: nil) do |connection|
51
- @connection = connection
52
- @connected = true
53
- @open_handler&.call
54
-
55
- while (message = connection.read)
56
- @message_handler&.call(message.to_str)
57
- end
58
- rescue StandardError => e
59
- @error_handler&.call(e)
60
- ensure
61
- @connected = false
62
- @close_handler&.call(nil)
63
- end
64
- end
65
- rescue StandardError => e
66
- @error_handler&.call(e)
67
- end
68
-
69
- def websocket_endpoint(url)
70
- Async::HTTP::Endpoint.parse(
71
- url,
72
- protocol: Async::HTTP::Protocol::HTTP11,
73
- alpn_protocols: ['http/1.1']
74
- )
75
- end
76
- end
77
- end
data/onyxcord.gemspec DELETED
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'lib/onyxcord/version'
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = 'onyxcord'
7
- spec.version = OnyxCord::VERSION
8
- spec.authors = ['Gustavo Silva']
9
- spec.email = ['gustavosilva8kt@gmail.com']
10
-
11
- spec.summary = 'Discord API for Ruby with Components V2 support'
12
- spec.description = 'OnyxCord is a Ruby Discord API library with Components V2, modern modals, raw-first events, and community support: https://discord.gg/Jy2tpCUtzM.'
13
- spec.homepage = 'https://github.com/kruldevb/OnyxCord'
14
- spec.license = 'MIT'
15
-
16
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|examples)/}) }
17
- spec.bindir = 'exe'
18
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
- spec.metadata = {
20
- 'bug_tracker_uri' => 'https://github.com/kruldevb/OnyxCord/issues',
21
- 'changelog_uri' => 'https://github.com/kruldevb/OnyxCord/blob/main/CHANGELOG.md',
22
- 'documentation_uri' => 'https://github.com/kruldevb/OnyxCord#readme',
23
- 'source_code_uri' => 'https://github.com/kruldevb/OnyxCord',
24
- 'rubygems_mfa_required' => 'true'
25
- }
26
- spec.require_paths = ['lib']
27
-
28
- # Modern async runtime & networking
29
- spec.add_dependency 'async', '>= 2.0', '< 3'
30
- spec.add_dependency 'async-http', '>= 0.75', '< 1'
31
- spec.add_dependency 'async-websocket', '>= 0.26', '< 1'
32
-
33
- # HTTP client (modern, HTTP/2, persistent connections)
34
- spec.add_dependency 'httpx', '>= 1.0', '< 2'
35
-
36
- # Fast JSON parsing
37
- spec.add_dependency 'oj', '>= 3.0', '< 4'
38
-
39
- # Smart LRU caching
40
- spec.add_dependency 'lru_redux', '>= 1.0', '< 2'
41
-
42
- # Core dependencies
43
- spec.add_dependency 'base64', '~> 0.2'
44
- spec.add_dependency 'mime-types', '~> 3.0'
45
-
46
- # Voice support
47
- spec.add_dependency 'ffi', '>= 1.9.24', '< 2'
48
- spec.add_dependency 'opus-ruby', '>= 0', '< 2'
49
-
50
- spec.required_ruby_version = '>= 3.4'
51
-
52
- spec.add_development_dependency 'bundler', '>= 1.10', '< 5'
53
- spec.add_development_dependency 'rake', '~> 13.0'
54
- spec.add_development_dependency 'redcarpet', '~> 3.5' # YARD markdown formatting
55
- spec.add_development_dependency 'rspec', '~> 3.0'
56
- spec.add_development_dependency 'rspec_junit_formatter', '~> 0.6.0'
57
- spec.add_development_dependency 'rspec-prof', '~> 0.0.7'
58
- spec.add_development_dependency 'rubocop', '~> 1.77.0'
59
- spec.add_development_dependency 'rubocop-performance', '~> 1.25.0'
60
- spec.add_development_dependency 'rubocop-rake', '~> 0.7.0'
61
- spec.add_development_dependency 'simplecov', '~> 0.21'
62
- spec.add_development_dependency 'yard', '~> 0.9.37'
63
- end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes