onyxcord 2.0.0 → 2.0.5
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +47 -0
- data/README.md +64 -1
- data/lib/onyxcord/api.rb +58 -55
- data/lib/onyxcord/bot.rb +47 -15
- data/lib/onyxcord/data/interaction.rb +4 -0
- data/lib/onyxcord/event_executor.rb +56 -6
- data/lib/onyxcord/gateway.rb +15 -15
- data/lib/onyxcord/http.rb +115 -0
- data/lib/onyxcord/json.rb +49 -0
- data/lib/onyxcord/version.rb +1 -1
- data/lib/onyxcord/websocket.rb +2 -15
- metadata +3 -4
- data/.devcontainer/Dockerfile +0 -13
- data/.devcontainer/devcontainer.json +0 -29
- data/.devcontainer/postcreate.sh +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e5d5e025fe9ad9abb42d0fca6da5fe8bf9f32bfbe527de27a2da742bfe5f262
|
|
4
|
+
data.tar.gz: e7b494fd1d4821c2c517f24ceca4a6da27720f552618b71f5a5452c5a3ef915b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '059ec009fb6fd52704a2906bdfc8fb6a20f0e06dd2ac783e1f466ce4cfabbe71c2fa9cb269a332e69fc3a05cdef7d8e394cfc3a3e1bfb11c94c0c7d43c0dd26d'
|
|
7
|
+
data.tar.gz: c4f5fb863ec9a636d4b7591b50afe16d4a0174c28390f5d42aa84f7ff32a2e904cfe71de4104b4425a7661cb82e71a9b114abc6b874888c52d8ad74683f14d58
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.5 - 2026-06-28
|
|
4
|
+
|
|
5
|
+
### Async Runtime (Infraestrutura nao-bloqueante)
|
|
6
|
+
|
|
7
|
+
- **`OnyxCord::AsyncRuntime`**: modulo central que gerencia o reactor `async` com `run`, `async` e `sleep`, reaproveitando reactor existente quando disponivel.
|
|
8
|
+
- **`EventExecutor::AsyncPool`**: novo pool de workers baseado em `Async::Queue` e fibers, sem threads.
|
|
9
|
+
- **Gateway**: `run_async` nao cria mais `Thread.new` — usa `@task = AsyncRuntime.async { run }`. Todos os `sleep` trocados por `AsyncRuntime.sleep`.
|
|
10
|
+
- **WebSocket**: usa `AsyncRuntime.async` em vez de `Async do` solto na classe.
|
|
11
|
+
- **API REST**: `request` agora delega para `request_async` automaticamente quando dentro de um reactor. `request_async` usa rate limiter async, `AsyncRuntime.sleep`, e retry com limite em 502.
|
|
12
|
+
- **Rate Limiter Async**: novo `OnyxCord::RateLimiter::AsyncRest` que evita `mutex.synchronize { sleep }` bloqueante.
|
|
13
|
+
- **Bot**: `run`/`stop`/`join` refatorados para o runtime async. `send_temporary_message` e `voice_connect` usam sleeps async.
|
|
14
|
+
- Compatibilidade sync mantida: a API publica continua funcionando de forma sincrona quando chamada fora de um reactor.
|
|
15
|
+
|
|
16
|
+
### Modern Application Commands DSL
|
|
17
|
+
|
|
18
|
+
- **`bot.slash`, `bot.user_command`, `bot.message_command`**: nova DSL para comandos modernos com definicao e handler unificados.
|
|
19
|
+
- **`bot.sync_application_commands!`**: sincroniza todos os commands registrados com a API do Discord de uma vez.
|
|
20
|
+
- **`bot.bulk_overwrite_global_application_commands`** e **`bot.bulk_overwrite_guild_application_commands`**: wrappers para bulk overwrite.
|
|
21
|
+
- **`ApplicationCommands::Context`**: wrapper com `respond`, `defer`, `edit_original`, `delete_original`, `followup` e acesso a `options`, `guild`, `channel`, `user`.
|
|
22
|
+
- **`Interaction#edit_original`**, **`Interaction#delete_original`**, **`Interaction#followup`**: novos aliases dos metodos originais.
|
|
23
|
+
- API legacy (`register_application_command` + `application_command`) mantida com compatibilidade total.
|
|
24
|
+
|
|
25
|
+
### Exemplo da nova DSL
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
bot.slash :ban, description: "Bane um membro", default_member_permissions: [:ban_members] do
|
|
29
|
+
user :member, "Membro que sera banido", required: true
|
|
30
|
+
string :reason, "Motivo do banimento", max_length: 512
|
|
31
|
+
|
|
32
|
+
execute do |ctx|
|
|
33
|
+
ctx.defer(ephemeral: true)
|
|
34
|
+
member = ctx.options[:member]
|
|
35
|
+
reason = ctx.options[:reason] || "Sem motivo informado"
|
|
36
|
+
ctx.guild.ban(member, reason: reason)
|
|
37
|
+
ctx.edit_original(content: "Membro banido com sucesso.")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
bot.sync_application_commands!(server_id: ENV.fetch('DISCORD_SERVER_ID'))
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Validacao
|
|
45
|
+
|
|
46
|
+
- `bundle exec rspec`: 460 exemplos, 0 falhas, 3 pendentes.
|
|
47
|
+
- `ruby -c lib/onyxcord/**/*.rb`: todos os arquivos com sintaxe OK.
|
|
48
|
+
- `gem build onyxcord.gemspec`: sucesso.
|
|
49
|
+
|
|
3
50
|
## 2.0.0 - 2026-06-28
|
|
4
51
|
|
|
5
52
|
### Arquitetura & Performance (Major Refactoring)
|
data/README.md
CHANGED
|
@@ -22,6 +22,8 @@ Simple to start, deep enough to control.
|
|
|
22
22
|
- Friendly Ruby API for Discord bots.
|
|
23
23
|
- Traditional object events for productivity.
|
|
24
24
|
- Raw gateway events for performance and lower allocation.
|
|
25
|
+
- **Modern async runtime** built on `async` gem with non-blocking gateway, REST and event dispatch.
|
|
26
|
+
- **New modern slash command DSL** with `bot.slash`, `execute`, and `bot.sync_application_commands!`.
|
|
25
27
|
- Components V2 support with `Text Display`, `Container`, `Section`, `Media Gallery`, `File`, `Separator`, and `Thumbnail`.
|
|
26
28
|
- Modern modal components, including `Label`, `Text Display`, modal selects, file upload, radio group, checkbox group, and checkbox.
|
|
27
29
|
- Webhooks with embeds, files, and components.
|
|
@@ -112,6 +114,25 @@ bot.application_command(:feedback) do |event|
|
|
|
112
114
|
end
|
|
113
115
|
```
|
|
114
116
|
|
|
117
|
+
### Modern Command DSL
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
bot.slash :ban, description: 'Ban a member', default_member_permissions: [:ban_members] do
|
|
121
|
+
user :member, 'Member to ban', required: true
|
|
122
|
+
string :reason, 'Ban reason', max_length: 512
|
|
123
|
+
|
|
124
|
+
execute do |ctx|
|
|
125
|
+
ctx.defer(ephemeral: true)
|
|
126
|
+
member = ctx.options[:member]
|
|
127
|
+
reason = ctx.options[:reason] || 'No reason provided'
|
|
128
|
+
ctx.guild.ban(member, reason: reason)
|
|
129
|
+
ctx.edit_original(content: 'Member banned.')
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
bot.sync_application_commands!(server_id: ENV.fetch('DISCORD_SERVER_ID'))
|
|
134
|
+
```
|
|
135
|
+
|
|
115
136
|
### Community
|
|
116
137
|
|
|
117
138
|
Join the Discord server for support, updates, examples, and feedback: https://discord.gg/Jy2tpCUtzM
|
|
@@ -131,6 +152,8 @@ Simples para comecar, profundo para controlar.
|
|
|
131
152
|
- API Ruby amigavel para bots do Discord.
|
|
132
153
|
- Eventos tradicionais com objetos para quem quer produtividade.
|
|
133
154
|
- Eventos raw para quem quer performance e menos alocacao.
|
|
155
|
+
- **Runtime async moderno** baseado na gem `async`: gateway, REST e dispatch de eventos nao-bloqueantes.
|
|
156
|
+
- **Nova DSL moderna de slash commands** com `bot.slash`, `execute` e `bot.sync_application_commands!`.
|
|
134
157
|
- Components V2 com `Text Display`, `Container`, `Section`, `Media Gallery`, `File`, `Separator` e `Thumbnail`.
|
|
135
158
|
- Novos componentes de modal, incluindo `Label`, `Text Display`, selects em modal, upload, radio group, checkbox group e checkbox.
|
|
136
159
|
- Webhooks com embeds, arquivos e componentes.
|
|
@@ -221,6 +244,25 @@ bot.application_command(:feedback) do |event|
|
|
|
221
244
|
end
|
|
222
245
|
```
|
|
223
246
|
|
|
247
|
+
### DSL Moderna de Comandos
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
bot.slash :ban, description: 'Bane um membro', default_member_permissions: [:ban_members] do
|
|
251
|
+
user :member, 'Membro que sera banido', required: true
|
|
252
|
+
string :reason, 'Motivo do banimento', max_length: 512
|
|
253
|
+
|
|
254
|
+
execute do |ctx|
|
|
255
|
+
ctx.defer(ephemeral: true)
|
|
256
|
+
member = ctx.options[:member]
|
|
257
|
+
reason = ctx.options[:reason] || 'Sem motivo informado'
|
|
258
|
+
ctx.guild.ban(member, reason: reason)
|
|
259
|
+
ctx.edit_original(content: 'Membro banido com sucesso.')
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
bot.sync_application_commands!(server_id: ENV.fetch('DISCORD_SERVER_ID'))
|
|
264
|
+
```
|
|
265
|
+
|
|
224
266
|
### Comunidade
|
|
225
267
|
|
|
226
268
|
Entre no servidor do Discord para suporte, atualizacoes, exemplos e feedback: https://discord.gg/Jy2tpCUtzM
|
|
@@ -237,9 +279,11 @@ Simple para empezar, profundo para controlar.
|
|
|
237
279
|
|
|
238
280
|
### Caracteristicas
|
|
239
281
|
|
|
240
|
-
- API Ruby
|
|
282
|
+
- API Ruby amigavel para bots de Discord.
|
|
241
283
|
- Eventos tradicionales con objetos para productividad.
|
|
242
284
|
- Eventos raw para rendimiento y menos asignaciones.
|
|
285
|
+
- **Runtime async moderno** basado en la gem `async`: gateway, REST y dispatch de eventos no bloqueantes.
|
|
286
|
+
- **Nueva DSL moderna de slash commands** con `bot.slash`, `execute` y `bot.sync_application_commands!`.
|
|
243
287
|
- Components V2 con `Text Display`, `Container`, `Section`, `Media Gallery`, `File`, `Separator` y `Thumbnail`.
|
|
244
288
|
- Componentes modernos de modal, incluyendo `Label`, `Text Display`, selects en modal, subida de archivos, radio group, checkbox group y checkbox.
|
|
245
289
|
- Webhooks con embeds, archivos y componentes.
|
|
@@ -330,6 +374,25 @@ bot.application_command(:feedback) do |event|
|
|
|
330
374
|
end
|
|
331
375
|
```
|
|
332
376
|
|
|
377
|
+
### DSL Moderna de Comandos
|
|
378
|
+
|
|
379
|
+
```ruby
|
|
380
|
+
bot.slash :ban, description: 'Banear a un miembro', default_member_permissions: [:ban_members] do
|
|
381
|
+
user :member, 'Miembro a banear', required: true
|
|
382
|
+
string :reason, 'Motivo del baneo', max_length: 512
|
|
383
|
+
|
|
384
|
+
execute do |ctx|
|
|
385
|
+
ctx.defer(ephemeral: true)
|
|
386
|
+
member = ctx.options[:member]
|
|
387
|
+
reason = ctx.options[:reason] || 'Sin motivo'
|
|
388
|
+
ctx.guild.ban(member, reason: reason)
|
|
389
|
+
ctx.edit_original(content: 'Miembro baneado.')
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
bot.sync_application_commands!(server_id: ENV.fetch('DISCORD_SERVER_ID'))
|
|
394
|
+
```
|
|
395
|
+
|
|
333
396
|
### Comunidad
|
|
334
397
|
|
|
335
398
|
Unete al servidor de Discord para soporte, actualizaciones, ejemplos y feedback: https://discord.gg/Jy2tpCUtzM
|
data/lib/onyxcord/api.rb
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require 'onyxcord/http'
|
|
4
4
|
require 'onyxcord/json'
|
|
5
|
+
require 'onyxcord/async/runtime'
|
|
5
6
|
require 'time'
|
|
6
7
|
|
|
7
8
|
require 'onyxcord/errors'
|
|
8
9
|
require 'onyxcord/rate_limiter/rest'
|
|
10
|
+
require 'onyxcord/rate_limiter/async_rest'
|
|
9
11
|
|
|
10
12
|
# List of methods representing endpoints in Discord's API
|
|
11
13
|
module OnyxCord::API
|
|
@@ -61,16 +63,25 @@ module OnyxCord::API
|
|
|
61
63
|
# Resets all rate limit mutexes
|
|
62
64
|
def reset_mutexes
|
|
63
65
|
@rate_limiter = OnyxCord::RateLimiter::Rest.new
|
|
66
|
+
@async_rate_limiter = OnyxCord::RateLimiter::AsyncRest.new
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
def rate_limiter
|
|
67
70
|
@rate_limiter ||= OnyxCord::RateLimiter::Rest.new
|
|
68
71
|
end
|
|
69
72
|
|
|
73
|
+
def async_rate_limiter
|
|
74
|
+
@async_rate_limiter ||= OnyxCord::RateLimiter::AsyncRest.new
|
|
75
|
+
end
|
|
76
|
+
|
|
70
77
|
def rate_limiter_stats
|
|
71
78
|
rate_limiter.stats
|
|
72
79
|
end
|
|
73
80
|
|
|
81
|
+
def async_rate_limiter_stats
|
|
82
|
+
async_rate_limiter.stats
|
|
83
|
+
end
|
|
84
|
+
|
|
74
85
|
# Wait a specified amount of time synchronised with the specified mutex.
|
|
75
86
|
def sync_wait(time, mutex)
|
|
76
87
|
mutex.synchronize { sleep time }
|
|
@@ -110,11 +121,18 @@ module OnyxCord::API
|
|
|
110
121
|
|
|
111
122
|
# Make an API request, including rate limit handling.
|
|
112
123
|
def request(key, major_parameter, type, *attributes)
|
|
113
|
-
|
|
124
|
+
if Async::Task.current?
|
|
125
|
+
request_async(key, major_parameter, type, *attributes)
|
|
126
|
+
else
|
|
127
|
+
OnyxCord::AsyncRuntime.run { request_async(key, major_parameter, type, *attributes) }
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Async version of request.
|
|
132
|
+
def request_async(key, major_parameter, type, *attributes)
|
|
114
133
|
url = attributes.shift
|
|
115
134
|
headers_or_body = attributes
|
|
116
135
|
|
|
117
|
-
# Separate body and headers from the positional args
|
|
118
136
|
body = nil
|
|
119
137
|
headers = {}
|
|
120
138
|
|
|
@@ -126,89 +144,74 @@ module OnyxCord::API
|
|
|
126
144
|
end
|
|
127
145
|
end
|
|
128
146
|
|
|
129
|
-
# Extract content_type from headers for HTTPX
|
|
130
147
|
content_type = headers.delete(:content_type)
|
|
131
148
|
headers['content-type'] = 'application/json' if content_type == :json
|
|
132
149
|
|
|
133
|
-
# Add user agent
|
|
134
150
|
headers['user-agent'] = user_agent
|
|
135
151
|
|
|
152
|
+
retries = 0
|
|
153
|
+
max_retries = key == :gateway ? 0 : 3
|
|
154
|
+
|
|
136
155
|
begin
|
|
137
|
-
|
|
156
|
+
async_rate_limiter.before_request(key, major_parameter)
|
|
138
157
|
|
|
139
158
|
response = nil
|
|
140
|
-
|
|
159
|
+
loop do
|
|
141
160
|
response = OnyxCord::HTTP.request(type, url, body, **headers)
|
|
161
|
+
break unless response.code == 502
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
noprm.define_singleton_method(:_response) { response }
|
|
146
|
-
raise noprm, "The bot doesn't have the required permission to do this!"
|
|
147
|
-
end
|
|
163
|
+
retries += 1
|
|
164
|
+
break unless retries < max_retries
|
|
148
165
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return request(key, major_parameter, type, url, body, headers)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
# Handle error status codes
|
|
156
|
-
if response.code >= 400 && response.code != 429
|
|
157
|
-
data = begin
|
|
158
|
-
JSON.parse(response.body)
|
|
159
|
-
rescue StandardError
|
|
160
|
-
nil
|
|
161
|
-
end
|
|
166
|
+
OnyxCord::LOGGER.warn('Got a 502 while sending a request! Not a big deal, retrying the request')
|
|
167
|
+
OnyxCord::AsyncRuntime.sleep(retries * 0.5)
|
|
168
|
+
end
|
|
162
169
|
|
|
163
|
-
|
|
170
|
+
if response.code == 403
|
|
171
|
+
noprm = OnyxCord::Errors::NoPermission.new
|
|
172
|
+
noprm.define_singleton_method(:_response) { response }
|
|
173
|
+
raise noprm, "The bot doesn't have the required permission to do this!"
|
|
174
|
+
end
|
|
164
175
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
rescue OnyxCord::Errors::NoPermission => e
|
|
171
|
-
if e.respond_to?(:_response)
|
|
172
|
-
response = e._response
|
|
173
|
-
else
|
|
174
|
-
OnyxCord::LOGGER.warn("NoPermission doesn't respond_to? _response!")
|
|
176
|
+
if response.code >= 400 && response.code != 429
|
|
177
|
+
data = begin
|
|
178
|
+
JSON.parse(response.body)
|
|
179
|
+
rescue StandardError
|
|
180
|
+
nil
|
|
175
181
|
end
|
|
176
182
|
|
|
183
|
+
raise "HTTP #{response.code}: #{response.body}" unless data
|
|
184
|
+
|
|
185
|
+
err_klass = OnyxCord::Errors.error_class_for(data['code'] || 0)
|
|
186
|
+
e = err_klass.new(data['message'], data['errors'])
|
|
187
|
+
OnyxCord::LOGGER.error(e.full_message)
|
|
177
188
|
raise e
|
|
178
|
-
ensure
|
|
179
|
-
if response
|
|
180
|
-
rate_limiter.record_response(key, major_parameter, response.headers)
|
|
181
|
-
else
|
|
182
|
-
OnyxCord::LOGGER.ratelimit('Response was nil before trying to preemptively rate limit!')
|
|
183
|
-
end
|
|
184
189
|
end
|
|
185
|
-
rescue OnyxCord::Errors::
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
rescue OnyxCord::Errors::NoPermission => e
|
|
191
|
+
async_rate_limiter.record_response(key, major_parameter, e._response.headers) if e.respond_to?(:_response)
|
|
192
|
+
raise e
|
|
193
|
+
else
|
|
194
|
+
async_rate_limiter.record_response(key, major_parameter, response.headers)
|
|
189
195
|
end
|
|
190
196
|
|
|
191
|
-
|
|
192
|
-
if response&.code == 429
|
|
197
|
+
if response.code == 429
|
|
193
198
|
trace("429 #{key} #{major_parameter}")
|
|
194
|
-
|
|
195
|
-
return
|
|
199
|
+
async_rate_limiter.handle_rate_limit(key, major_parameter, response)
|
|
200
|
+
return request_async(key, major_parameter, type, url, body, headers)
|
|
196
201
|
end
|
|
197
202
|
|
|
198
|
-
|
|
199
|
-
# amount of time indicated by the response body, and then recursively retry and return the request.
|
|
200
|
-
if response&.code == 202 && response&.body
|
|
203
|
+
if response.code == 202 && response.body
|
|
201
204
|
body_data = JSON.parse(response.body)
|
|
202
205
|
|
|
203
206
|
if body_data['code'] == 110_000
|
|
204
207
|
case body_data['retry_after']
|
|
205
208
|
when 0, 1, nil
|
|
206
|
-
sleep(rand(4.5..5.0))
|
|
209
|
+
OnyxCord::AsyncRuntime.sleep(rand(4.5..5.0))
|
|
207
210
|
else
|
|
208
|
-
sleep(body_data['retry_after'])
|
|
211
|
+
OnyxCord::AsyncRuntime.sleep(body_data['retry_after'])
|
|
209
212
|
end
|
|
210
213
|
|
|
211
|
-
return
|
|
214
|
+
return request_async(key, major_parameter, type, url, body, headers)
|
|
212
215
|
end
|
|
213
216
|
end
|
|
214
217
|
|
data/lib/onyxcord/bot.rb
CHANGED
|
@@ -33,6 +33,7 @@ require 'onyxcord/api/invite'
|
|
|
33
33
|
require 'onyxcord/api/interaction'
|
|
34
34
|
require 'onyxcord/api/application'
|
|
35
35
|
|
|
36
|
+
require 'onyxcord/async/runtime'
|
|
36
37
|
require 'onyxcord/errors'
|
|
37
38
|
require 'onyxcord/message_components'
|
|
38
39
|
require 'onyxcord/data'
|
|
@@ -42,6 +43,7 @@ require 'onyxcord/websocket'
|
|
|
42
43
|
require 'onyxcord/cache'
|
|
43
44
|
require 'onyxcord/gateway'
|
|
44
45
|
|
|
46
|
+
require 'onyxcord/application_commands'
|
|
45
47
|
require 'onyxcord/voice/voice_bot'
|
|
46
48
|
|
|
47
49
|
module OnyxCord
|
|
@@ -309,28 +311,27 @@ module OnyxCord
|
|
|
309
311
|
# this. If you need a way to safely run code after the bot is fully
|
|
310
312
|
# connected, use a {#ready} event handler instead.
|
|
311
313
|
def run(background = false)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
+
if background
|
|
315
|
+
@run_task = OnyxCord::AsyncRuntime.async { run_forever }
|
|
316
|
+
return @run_task
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
OnyxCord::AsyncRuntime.run { run_forever }
|
|
320
|
+
end
|
|
314
321
|
|
|
315
|
-
|
|
316
|
-
@gateway.
|
|
322
|
+
def run_forever
|
|
323
|
+
@gateway.run
|
|
317
324
|
end
|
|
318
325
|
|
|
319
|
-
# Joins the bot's connection thread with the current thread.
|
|
320
|
-
# This blocks execution until the websocket stops, which should only happen
|
|
321
|
-
# manually triggered. or due to an error. This is necessary to have a
|
|
322
|
-
# continuously running bot.
|
|
323
326
|
def join
|
|
324
|
-
@
|
|
327
|
+
@run_task&.wait
|
|
325
328
|
end
|
|
326
329
|
alias_method :sync, :join
|
|
327
330
|
|
|
328
|
-
# Stops the bot gracefully, disconnecting the websocket without immediately killing the thread. This means that
|
|
329
|
-
# Discord is immediately aware of the closed connection and makes the bot appear offline instantly.
|
|
330
|
-
# @note This method no longer takes an argument as of 3.4.0
|
|
331
331
|
def stop(_no_sync = nil)
|
|
332
332
|
@gateway.stop
|
|
333
333
|
@event_executor.shutdown
|
|
334
|
+
@run_task&.stop if @run_task.respond_to?(:stop)
|
|
334
335
|
nil
|
|
335
336
|
end
|
|
336
337
|
|
|
@@ -411,7 +412,7 @@ module OnyxCord
|
|
|
411
412
|
|
|
412
413
|
debug('Voice channel init packet sent! Now waiting.')
|
|
413
414
|
|
|
414
|
-
sleep(0.05) until @voices[server_id]
|
|
415
|
+
OnyxCord::AsyncRuntime.sleep(0.05) until @voices[server_id]
|
|
415
416
|
debug('Voice connect succeeded!')
|
|
416
417
|
@voices[server_id]
|
|
417
418
|
end
|
|
@@ -477,9 +478,9 @@ module OnyxCord
|
|
|
477
478
|
# @param enforce_nonce [true, false] Whether the nonce should be enforced and used for message de-duplication.
|
|
478
479
|
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
|
|
479
480
|
def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false, poll = nil)
|
|
480
|
-
|
|
481
|
+
OnyxCord::AsyncRuntime.async do
|
|
481
482
|
message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, flags, nonce, enforce_nonce, poll)
|
|
482
|
-
sleep(timeout)
|
|
483
|
+
OnyxCord::AsyncRuntime.sleep(timeout)
|
|
483
484
|
message.delete
|
|
484
485
|
end
|
|
485
486
|
|
|
@@ -864,6 +865,37 @@ module OnyxCord
|
|
|
864
865
|
ApplicationCommand.new(JSON.parse(resp), self, server_id)
|
|
865
866
|
end
|
|
866
867
|
|
|
868
|
+
# @return [OnyxCord::ApplicationCommands::Registry]
|
|
869
|
+
def commands
|
|
870
|
+
@modern_command_registry ||= OnyxCord::ApplicationCommands::Registry.new(self)
|
|
871
|
+
end
|
|
872
|
+
|
|
873
|
+
def slash(name, description: nil, **attributes, &block)
|
|
874
|
+
commands.slash(name, description: description, **attributes, &block)
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
def user_command(name, **attributes, &block)
|
|
878
|
+
commands.user(name, **attributes, &block)
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
def message_command(name, **attributes, &block)
|
|
882
|
+
commands.message(name, **attributes, &block)
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
def sync_application_commands!(server_id: nil, delete_unknown: false)
|
|
886
|
+
commands.sync!(server_id: server_id, delete_unknown: delete_unknown)
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
def bulk_overwrite_global_application_commands(commands)
|
|
890
|
+
response = API::Application.bulk_overwrite_global_commands(@token, profile.id, commands)
|
|
891
|
+
JSON.parse(response).map { |data| ApplicationCommand.new(data, self) }
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
def bulk_overwrite_guild_application_commands(server_id, commands)
|
|
895
|
+
response = API::Application.bulk_overwrite_guild_commands(@token, profile.id, server_id.resolve_id, commands)
|
|
896
|
+
JSON.parse(response).map { |data| ApplicationCommand.new(data, self, server_id) }
|
|
897
|
+
end
|
|
898
|
+
|
|
867
899
|
# @yieldparam [OptionBuilder]
|
|
868
900
|
# @yieldparam [PermissionBuilder]
|
|
869
901
|
# @example
|
|
@@ -299,6 +299,10 @@ module OnyxCord
|
|
|
299
299
|
Interactions::Message.new(JSON.parse(resp), @bot, self)
|
|
300
300
|
end
|
|
301
301
|
|
|
302
|
+
alias edit_original edit_response
|
|
303
|
+
alias delete_original delete_response
|
|
304
|
+
alias followup send_message
|
|
305
|
+
|
|
302
306
|
# @param message [String, Integer, InteractionMessage, Message] The message created by this interaction to be edited.
|
|
303
307
|
# @param content [String] The message content.
|
|
304
308
|
# @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'async'
|
|
3
|
+
require 'onyxcord/async/runtime'
|
|
4
4
|
|
|
5
5
|
module OnyxCord
|
|
6
|
-
# Event execution strategies used by bot dispatch.
|
|
7
6
|
module EventExecutor
|
|
8
7
|
STOP = Object.new.freeze
|
|
9
8
|
|
|
10
|
-
# Deterministic executor useful for tests, benchmarks, and tiny bots.
|
|
11
9
|
class Inline
|
|
12
10
|
def post
|
|
13
11
|
yield
|
|
@@ -20,8 +18,6 @@ module OnyxCord
|
|
|
20
18
|
end
|
|
21
19
|
end
|
|
22
20
|
|
|
23
|
-
# Async-based worker pool for event handlers.
|
|
24
|
-
# Uses Async tasks (fibers) instead of threads for lightweight concurrency.
|
|
25
21
|
class Pool
|
|
26
22
|
attr_reader :queue
|
|
27
23
|
|
|
@@ -47,7 +43,6 @@ module OnyxCord
|
|
|
47
43
|
@queue.size
|
|
48
44
|
end
|
|
49
45
|
|
|
50
|
-
# Compatibility with code that checks worker threads.
|
|
51
46
|
def threads
|
|
52
47
|
@workers
|
|
53
48
|
end
|
|
@@ -87,6 +82,59 @@ module OnyxCord
|
|
|
87
82
|
end
|
|
88
83
|
end
|
|
89
84
|
|
|
85
|
+
class AsyncPool
|
|
86
|
+
attr_reader :queue
|
|
87
|
+
|
|
88
|
+
def initialize(size:, queue_size: nil)
|
|
89
|
+
raise ArgumentError, 'Pool size must be greater than zero' unless size.positive?
|
|
90
|
+
|
|
91
|
+
@size = size
|
|
92
|
+
@queue = ::Async::Queue.new
|
|
93
|
+
@closed = false
|
|
94
|
+
@workers = []
|
|
95
|
+
start_workers
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def post(&block)
|
|
99
|
+
raise ArgumentError, 'EventExecutor::AsyncPool#post requires a block' unless block
|
|
100
|
+
raise 'Event executor has been shut down' if @closed
|
|
101
|
+
|
|
102
|
+
@queue.enqueue(block)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def queue_size
|
|
106
|
+
@queue.size
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def shutdown
|
|
110
|
+
return if @closed
|
|
111
|
+
|
|
112
|
+
@closed = true
|
|
113
|
+
@size.times { @queue.enqueue(STOP) }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def threads
|
|
117
|
+
[]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
|
|
122
|
+
def start_workers
|
|
123
|
+
@workers = Array.new(@size) do
|
|
124
|
+
OnyxCord::AsyncRuntime.async do
|
|
125
|
+
loop do
|
|
126
|
+
job = @queue.dequeue
|
|
127
|
+
break if job.equal?(STOP)
|
|
128
|
+
|
|
129
|
+
job.call
|
|
130
|
+
rescue StandardError => e
|
|
131
|
+
OnyxCord::LOGGER.log_exception(e) if defined?(OnyxCord::LOGGER)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
90
138
|
module_function
|
|
91
139
|
|
|
92
140
|
def build(type, workers:, queue_size: nil)
|
|
@@ -95,6 +143,8 @@ module OnyxCord
|
|
|
95
143
|
Inline.new
|
|
96
144
|
when :pool
|
|
97
145
|
Pool.new(size: workers, queue_size: queue_size)
|
|
146
|
+
when :async_pool
|
|
147
|
+
AsyncPool.new(size: workers, queue_size: queue_size)
|
|
98
148
|
else
|
|
99
149
|
raise ArgumentError, "Unknown event executor: #{type.inspect}"
|
|
100
150
|
end
|
data/lib/onyxcord/gateway.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require 'async'
|
|
4
4
|
require 'async/http/endpoint'
|
|
5
5
|
require 'async/websocket/client'
|
|
6
|
+
require 'onyxcord/async/runtime'
|
|
6
7
|
require 'onyxcord/rate_limiter/gateway'
|
|
7
8
|
|
|
8
9
|
module OnyxCord
|
|
@@ -86,25 +87,24 @@ module OnyxCord
|
|
|
86
87
|
|
|
87
88
|
# Connect to the gateway server inside an Async reactor.
|
|
88
89
|
def run_async
|
|
89
|
-
@
|
|
90
|
-
Thread.current[:onyxcord_name] = 'gateway'
|
|
91
|
-
Async do |task|
|
|
92
|
-
@reactor_task = task
|
|
93
|
-
connect_loop
|
|
94
|
-
LOGGER.warn('The gateway loop exited!')
|
|
95
|
-
end
|
|
96
|
-
end
|
|
90
|
+
@task = OnyxCord::AsyncRuntime.async { run }
|
|
97
91
|
|
|
98
|
-
LOGGER.debug('Gateway
|
|
92
|
+
LOGGER.debug('Gateway task created! Waiting for confirmation...')
|
|
99
93
|
loop do
|
|
100
|
-
sleep(0.5)
|
|
94
|
+
OnyxCord::AsyncRuntime.sleep(0.5)
|
|
101
95
|
break if @ws_success
|
|
102
96
|
break if @should_reconnect == false
|
|
103
97
|
end
|
|
104
98
|
end
|
|
105
99
|
|
|
100
|
+
def run
|
|
101
|
+
@reactor_task = Async::Task.current
|
|
102
|
+
connect_loop
|
|
103
|
+
LOGGER.warn('The gateway loop exited!')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
106
|
def sync
|
|
107
|
-
@
|
|
107
|
+
@task&.wait
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
def open?
|
|
@@ -118,7 +118,7 @@ module OnyxCord
|
|
|
118
118
|
end
|
|
119
119
|
|
|
120
120
|
def kill
|
|
121
|
-
@
|
|
121
|
+
@task&.stop
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
def notify_ready
|
|
@@ -224,7 +224,7 @@ module OnyxCord
|
|
|
224
224
|
@heartbeat_task = @reactor_task&.async do
|
|
225
225
|
loop do
|
|
226
226
|
if (@session && !@session.suspended?) || !@session
|
|
227
|
-
sleep
|
|
227
|
+
OnyxCord::AsyncRuntime.sleep(@heartbeat_interval)
|
|
228
228
|
if !@closed && @connection
|
|
229
229
|
@bot.raise_heartbeat_event
|
|
230
230
|
heartbeat
|
|
@@ -232,7 +232,7 @@ module OnyxCord
|
|
|
232
232
|
LOGGER.debug('Tried to heartbeat without connection — skipping.')
|
|
233
233
|
end
|
|
234
234
|
else
|
|
235
|
-
sleep
|
|
235
|
+
OnyxCord::AsyncRuntime.sleep(1)
|
|
236
236
|
end
|
|
237
237
|
rescue StandardError => e
|
|
238
238
|
LOGGER.error('Error while heartbeating!')
|
|
@@ -260,7 +260,7 @@ module OnyxCord
|
|
|
260
260
|
|
|
261
261
|
def wait_for_reconnect
|
|
262
262
|
LOGGER.debug("Reconnecting in #{@falloff} seconds.")
|
|
263
|
-
sleep
|
|
263
|
+
OnyxCord::AsyncRuntime.sleep(@falloff)
|
|
264
264
|
@falloff *= 1.5
|
|
265
265
|
@falloff = 115 + (rand * 10) if @falloff > 120
|
|
266
266
|
end
|
|
@@ -0,0 +1,115 @@
|
|
|
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.
|
|
49
|
+
def session
|
|
50
|
+
@session ||= HTTPX.plugin(:persistent)
|
|
51
|
+
.plugin(:follow_redirects)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Reset the HTTP session (useful for tests).
|
|
55
|
+
def reset!
|
|
56
|
+
@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
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
data/lib/onyxcord/version.rb
CHANGED
data/lib/onyxcord/websocket.rb
CHANGED
|
@@ -1,25 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'async'
|
|
3
|
+
require 'onyxcord/async/runtime'
|
|
4
4
|
require 'async/http/endpoint'
|
|
5
5
|
require 'async/websocket/client'
|
|
6
6
|
|
|
7
7
|
module OnyxCord
|
|
8
|
-
# Wrapper around async-websocket that provides the same callback-based
|
|
9
|
-
# interface used by the Gateway and Voice subsystems. This replaces the
|
|
10
|
-
# previous websocket-client-simple implementation.
|
|
11
8
|
class WebSocket
|
|
12
|
-
# @return [Boolean] whether the connection is currently open.
|
|
13
9
|
attr_reader :connected
|
|
14
10
|
|
|
15
11
|
alias_method :connected?, :connected
|
|
16
12
|
|
|
17
|
-
# Creates a new WebSocket wrapper.
|
|
18
|
-
# @param host [String] The `wss://` endpoint URL to connect to.
|
|
19
|
-
# @param open_handler [Proc] Called once the connection is established.
|
|
20
|
-
# @param message_handler [Proc] Called for every text frame received.
|
|
21
|
-
# @param error_handler [Proc] Called when an error occurs.
|
|
22
|
-
# @param close_handler [Proc] Called when the connection closes.
|
|
23
13
|
def initialize(host, open_handler, message_handler, error_handler, close_handler)
|
|
24
14
|
@host = host
|
|
25
15
|
@open_handler = open_handler
|
|
@@ -33,8 +23,6 @@ module OnyxCord
|
|
|
33
23
|
connect
|
|
34
24
|
end
|
|
35
25
|
|
|
36
|
-
# Send a text message over the WebSocket.
|
|
37
|
-
# @param data [String, Hash] Data to send. Hashes are JSON-encoded automatically.
|
|
38
26
|
def send(data)
|
|
39
27
|
return unless @connection
|
|
40
28
|
|
|
@@ -45,7 +33,6 @@ module OnyxCord
|
|
|
45
33
|
@error_handler&.call(e)
|
|
46
34
|
end
|
|
47
35
|
|
|
48
|
-
# Cleanly close the connection.
|
|
49
36
|
def close
|
|
50
37
|
@connected = false
|
|
51
38
|
@connection&.close
|
|
@@ -58,7 +45,7 @@ module OnyxCord
|
|
|
58
45
|
def connect
|
|
59
46
|
endpoint = Async::HTTP::Endpoint.parse(@host)
|
|
60
47
|
|
|
61
|
-
|
|
48
|
+
@task = OnyxCord::AsyncRuntime.async do
|
|
62
49
|
Async::WebSocket::Client.connect(endpoint) do |connection|
|
|
63
50
|
@connection = connection
|
|
64
51
|
@connected = true
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: onyxcord
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gustavo Silva
|
|
@@ -365,9 +365,6 @@ executables: []
|
|
|
365
365
|
extensions: []
|
|
366
366
|
extra_rdoc_files: []
|
|
367
367
|
files:
|
|
368
|
-
- ".devcontainer/Dockerfile"
|
|
369
|
-
- ".devcontainer/devcontainer.json"
|
|
370
|
-
- ".devcontainer/postcreate.sh"
|
|
371
368
|
- ".github/CONTRIBUTING.md"
|
|
372
369
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
|
373
370
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
|
@@ -474,7 +471,9 @@ files:
|
|
|
474
471
|
- lib/onyxcord/events/voice_state_update.rb
|
|
475
472
|
- lib/onyxcord/events/webhooks.rb
|
|
476
473
|
- lib/onyxcord/gateway.rb
|
|
474
|
+
- lib/onyxcord/http.rb
|
|
477
475
|
- lib/onyxcord/id_object.rb
|
|
476
|
+
- lib/onyxcord/json.rb
|
|
478
477
|
- lib/onyxcord/light.rb
|
|
479
478
|
- lib/onyxcord/light/data.rb
|
|
480
479
|
- lib/onyxcord/light/integrations.rb
|
data/.devcontainer/Dockerfile
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# Which Ruby version to use. You may need to use a more restrictive version,
|
|
2
|
-
# e.g. `3.0`
|
|
3
|
-
ARG VARIANT=3.3
|
|
4
|
-
|
|
5
|
-
# Pull Microsoft's ruby devcontainer base image
|
|
6
|
-
FROM mcr.microsoft.com/devcontainers/ruby:${VARIANT}
|
|
7
|
-
|
|
8
|
-
# Install libsodium dependency for voice channel interactions
|
|
9
|
-
RUN apt update -yq && apt install -y libsodium-dev
|
|
10
|
-
|
|
11
|
-
# Ensure we're running the latest bundler, as what ships with the Ruby image may
|
|
12
|
-
# not be current, and bundler will auto-downgrade to match the Gemfile.lock
|
|
13
|
-
RUN gem install bundler
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Ruby",
|
|
3
|
-
"build": {
|
|
4
|
-
"dockerfile": "Dockerfile"
|
|
5
|
-
},
|
|
6
|
-
|
|
7
|
-
// Configure tool-specific properties.
|
|
8
|
-
"customizations": {
|
|
9
|
-
// Configure properties specific to VS Code.
|
|
10
|
-
"vscode": {
|
|
11
|
-
// Add the IDs of extensions you want installed when the container is created.
|
|
12
|
-
"extensions": [
|
|
13
|
-
"shopify.ruby-lsp"
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
// Set the environment variables
|
|
19
|
-
// "runArgs": ["--env-file",".env"],
|
|
20
|
-
|
|
21
|
-
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
22
|
-
// "forwardPorts": [],
|
|
23
|
-
|
|
24
|
-
// Use 'postCreateCommand' to run commands after the container is created.
|
|
25
|
-
"postCreateCommand": "bash .devcontainer/postcreate.sh",
|
|
26
|
-
|
|
27
|
-
// Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
|
28
|
-
"remoteUser": "vscode"
|
|
29
|
-
}
|
data/.devcontainer/postcreate.sh
DELETED