onyxcord 1.1.2 → 1.1.4
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/CHANGELOG.md +41 -0
- data/README.md +15 -2
- data/lib/onyxcord/api.rb +5 -1
- data/lib/onyxcord/bot.rb +20 -20
- data/lib/onyxcord/cache.rb +29 -0
- data/lib/onyxcord/configuration.rb +13 -2
- data/lib/onyxcord/data/component.rb +2 -2
- data/lib/onyxcord/event_executor.rb +9 -5
- data/lib/onyxcord/rate_limiter/rest.rb +56 -3
- data/lib/onyxcord/version.rb +1 -1
- data/lib/onyxcord/voice/network.rb +9 -1
- data/lib/onyxcord/voice/voice_bot.rb +23 -22
- data/onyxcord-webhooks.gemspec +1 -1
- data/onyxcord.gemspec +4 -4
- data/relator.md +298 -0
- data/relatorio2.md +0 -0
- metadata +29 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: faa13116d56881eff441634bdd885ed2650739cdea9be5e3807ec94d0c4c8965
|
|
4
|
+
data.tar.gz: 8738d765d59e229c5c1476bc1029e32c82f6ad1d417295380ffaae4fb8d65e22
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e36c649784e3eda4f2928bf2801013072fabf8bd40b4f5bcba232fef37155fc36ccfa27041656ef988152a78d1bbe9b4d3145e7cf384169b8279d1f80417f5f6
|
|
7
|
+
data.tar.gz: a4dd38f5c246e0bc9e9432ee0f75f54a641bbce30cf143a4b95eb73f8da08810baa76d4fd46e81e279e9d2cac5e4618df8f3f0acbb9c15ecc5643e411ac21592
|
data/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.4 - 2026-06-28
|
|
4
|
+
|
|
5
|
+
### Melhorias
|
|
6
|
+
|
|
7
|
+
- `MediaGallery` agora aceita URLs diretas e hashes no builder, como `media_gallery('https://...')`, alem do formato em bloco.
|
|
8
|
+
- `FileComponent`/`file_display` agora aceita a URL do attachment como primeiro argumento, como `file_display('attachment://arquivo.txt')`.
|
|
9
|
+
|
|
10
|
+
### Correcoes
|
|
11
|
+
|
|
12
|
+
- Parser de `MediaGallery` e `FileUpload` ficou mais tolerante quando o payload nao traz `items` ou `values`.
|
|
13
|
+
|
|
14
|
+
### Validacao
|
|
15
|
+
|
|
16
|
+
- `bundle exec rspec spec/components_v2_spec.rb`: 13 exemplos, 0 falhas.
|
|
17
|
+
|
|
18
|
+
## 1.1.3 - 2026-06-23
|
|
19
|
+
|
|
20
|
+
### Melhorias
|
|
21
|
+
|
|
22
|
+
- Alterado o modo padrao do bot para `:hybrid`, mantendo suporte a handlers raw e eventos em objeto sem configuracao extra.
|
|
23
|
+
- Adicionado `event_queue_size` para permitir fila de eventos com limite via `SizedQueue`.
|
|
24
|
+
- Application commands agora usam o `EventExecutor`, evitando criacao direta de threads por interaction.
|
|
25
|
+
- Adicionados `runtime_stats`, `cache_stats`, `prune_cache!` e `OnyxCord::API.rate_limiter_stats` para diagnostico de memoria e runtime.
|
|
26
|
+
- Rate limiter REST agora expoe `stats`, `prune!` e limpeza automatica de bookkeeping antigo.
|
|
27
|
+
- Voice recebeu limpeza mais segura de UDP, WebSocket, threads e leitura DCA com fechamento garantido de arquivo.
|
|
28
|
+
- Dependencias principais receberam upper bounds conservadores para reduzir risco de quebra em releases futuras.
|
|
29
|
+
|
|
30
|
+
### Correcoes
|
|
31
|
+
|
|
32
|
+
- Corrigido retry de respostas REST `202` para reutilizar a rota e o major parameter originais.
|
|
33
|
+
- Removidos logs temporarios de interaction no caminho quente de dispatch.
|
|
34
|
+
- Corrigido warning de spec causado por expectativa em cache de usuarios nulo.
|
|
35
|
+
|
|
36
|
+
### Validacao
|
|
37
|
+
|
|
38
|
+
- `bundle exec rspec`: 456 exemplos, 0 falhas, 3 pendentes.
|
|
39
|
+
- RuboCop nos arquivos alterados: sem offenses.
|
|
40
|
+
- `gem build onyxcord.gemspec`: sucesso.
|
|
41
|
+
- `gem build onyxcord-webhooks.gemspec`: sucesso.
|
data/README.md
CHANGED
|
@@ -103,8 +103,21 @@ end
|
|
|
103
103
|
bot.run
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
Use `mode: :raw` quando quiser evitar a criação de objetos pesados
|
|
107
|
-
**Importante:** O `OnyxCord` roda em `:
|
|
106
|
+
Use `mode: :raw` quando quiser evitar a criação de objetos pesados e processar apenas os pacotes de Gateway diretamente.
|
|
107
|
+
**Importante:** O `OnyxCord` roda em `:hybrid` por padrão, entao comandos de aplicação normais (`application_command`), modais e outros eventos em objeto ja funcionam sem precisar informar `mode: :hybrid`.
|
|
108
|
+
|
|
109
|
+
## Performance e memória
|
|
110
|
+
|
|
111
|
+
Para limitar crescimento de fila quando handlers ficam lentos, configure um tamanho maximo para a fila do executor:
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
OnyxCord.configure do |config|
|
|
115
|
+
config.event_workers = 4
|
|
116
|
+
config.event_queue_size = 1_000
|
|
117
|
+
end
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Em bots grandes, use `bot.runtime_stats`, `bot.cache_stats` e `bot.prune_cache!` para acompanhar e limpar caches em runtime.
|
|
108
121
|
|
|
109
122
|
## Components V2
|
|
110
123
|
|
data/lib/onyxcord/api.rb
CHANGED
|
@@ -67,6 +67,10 @@ module OnyxCord::API
|
|
|
67
67
|
@rate_limiter ||= OnyxCord::RateLimiter::Rest.new
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
def rate_limiter_stats
|
|
71
|
+
rate_limiter.stats
|
|
72
|
+
end
|
|
73
|
+
|
|
70
74
|
# Wait a specified amount of time synchronised with the specified mutex.
|
|
71
75
|
def sync_wait(time, mutex)
|
|
72
76
|
mutex.synchronize { sleep time }
|
|
@@ -151,7 +155,7 @@ module OnyxCord::API
|
|
|
151
155
|
sleep(body['retry_after'])
|
|
152
156
|
end
|
|
153
157
|
|
|
154
|
-
return request(
|
|
158
|
+
return request(key, major_parameter, type, *attributes)
|
|
155
159
|
end
|
|
156
160
|
end
|
|
157
161
|
|
data/lib/onyxcord/bot.rb
CHANGED
|
@@ -132,13 +132,14 @@ module OnyxCord
|
|
|
132
132
|
type: nil, name: '', fancy_log: false, suppress_ready: false, parse_self: false,
|
|
133
133
|
shard_id: nil, num_shards: nil, redact_token: true, ignore_bots: false,
|
|
134
134
|
compress_mode: :large, intents: :minimal,
|
|
135
|
-
mode: nil, cache: nil, event_executor: nil, event_workers: nil
|
|
135
|
+
mode: nil, cache: nil, event_executor: nil, event_workers: nil, event_queue_size: nil
|
|
136
136
|
)
|
|
137
137
|
config = OnyxCord.configuration
|
|
138
138
|
@mode = config.normalize_mode(mode)
|
|
139
139
|
@cache_policy = config.normalize_cache(cache)
|
|
140
140
|
executor_type = config.normalize_event_executor(event_executor)
|
|
141
141
|
executor_workers = config.normalize_event_workers(event_workers)
|
|
142
|
+
executor_queue_size = config.normalize_event_queue_size(event_queue_size)
|
|
142
143
|
|
|
143
144
|
LOGGER.mode = log_mode
|
|
144
145
|
LOGGER.token = token if redact_token
|
|
@@ -185,7 +186,7 @@ module OnyxCord
|
|
|
185
186
|
|
|
186
187
|
@current_thread = 0
|
|
187
188
|
@current_thread_mutex = Mutex.new
|
|
188
|
-
@event_executor = EventExecutor.build(executor_type, workers: executor_workers)
|
|
189
|
+
@event_executor = EventExecutor.build(executor_type, workers: executor_workers, queue_size: executor_queue_size)
|
|
189
190
|
@event_threads = @event_executor.threads
|
|
190
191
|
|
|
191
192
|
@status = :online
|
|
@@ -712,6 +713,16 @@ module OnyxCord
|
|
|
712
713
|
LOGGER.mode = new_mode
|
|
713
714
|
end
|
|
714
715
|
|
|
716
|
+
def runtime_stats
|
|
717
|
+
{
|
|
718
|
+
mode: @mode,
|
|
719
|
+
cache: cache_stats,
|
|
720
|
+
event_executor: @event_executor.class.name,
|
|
721
|
+
event_threads: @event_threads&.count(&:alive?) || 0,
|
|
722
|
+
event_queue_size: @event_executor.respond_to?(:queue_size) ? @event_executor.queue_size : 0
|
|
723
|
+
}
|
|
724
|
+
end
|
|
725
|
+
|
|
715
726
|
# Prevents the READY packet from being printed regardless of debug mode.
|
|
716
727
|
def suppress_ready_debug
|
|
717
728
|
@prevent_ready = true
|
|
@@ -1677,30 +1688,19 @@ module OnyxCord
|
|
|
1677
1688
|
|
|
1678
1689
|
raise_event(event)
|
|
1679
1690
|
when :INTERACTION_CREATE
|
|
1680
|
-
OnyxCord::LOGGER.info(">>> INTERACTION_CREATE received inside bot.rb! type: #{data['type']}")
|
|
1681
1691
|
event = InteractionCreateEvent.new(data, self)
|
|
1682
1692
|
raise_event(event)
|
|
1683
|
-
OnyxCord::LOGGER.info(">>> raised InteractionCreateEvent successfully")
|
|
1684
1693
|
|
|
1685
1694
|
case data['type']
|
|
1686
1695
|
when Interaction::TYPES[:command]
|
|
1687
|
-
OnyxCord::LOGGER.info(">>> creating ApplicationCommandEvent")
|
|
1688
1696
|
event = ApplicationCommandEvent.new(data, self)
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
handler = @application_commands[evt.command_name]
|
|
1697
|
-
OnyxCord::LOGGER.info(">>> Handler found? #{!handler.nil?}")
|
|
1698
|
-
handler&.call(evt)
|
|
1699
|
-
OnyxCord::LOGGER.info(">>> Handler call finished")
|
|
1700
|
-
rescue Exception => e
|
|
1701
|
-
OnyxCord::LOGGER.error(">>> FATAL EXCEPTION IN THREAD: #{e.class}: #{e.message}")
|
|
1702
|
-
log_exception(e)
|
|
1703
|
-
end
|
|
1697
|
+
|
|
1698
|
+
@event_executor.post do
|
|
1699
|
+
Thread.current[:onyxcord_name] = next_event_thread_name('it')
|
|
1700
|
+
handler = @application_commands[event.command_name]
|
|
1701
|
+
handler&.call(event)
|
|
1702
|
+
rescue StandardError => e
|
|
1703
|
+
log_exception(e)
|
|
1704
1704
|
end
|
|
1705
1705
|
when Interaction::TYPES[:component]
|
|
1706
1706
|
case data['data']['component_type']
|
data/lib/onyxcord/cache.rb
CHANGED
|
@@ -12,6 +12,17 @@ module OnyxCord
|
|
|
12
12
|
# the caching (like, storing the user hashes or making API calls to retrieve things) from the Bot that
|
|
13
13
|
# actually uses it.
|
|
14
14
|
module Cache
|
|
15
|
+
CACHE_STORES = {
|
|
16
|
+
users: :@users,
|
|
17
|
+
voice_regions: :@voice_regions,
|
|
18
|
+
servers: :@servers,
|
|
19
|
+
channels: :@channels,
|
|
20
|
+
pm_channels: :@pm_channels,
|
|
21
|
+
thread_members: :@thread_members,
|
|
22
|
+
server_previews: :@server_previews,
|
|
23
|
+
request_members: :@request_members_rl
|
|
24
|
+
}.freeze
|
|
25
|
+
|
|
15
26
|
# Initializes this cache
|
|
16
27
|
def init_cache
|
|
17
28
|
@cache_policy ||= OnyxCord.configuration.normalize_cache(:full)
|
|
@@ -32,6 +43,24 @@ module OnyxCord
|
|
|
32
43
|
@cache_policy.fetch(key, true)
|
|
33
44
|
end
|
|
34
45
|
|
|
46
|
+
def cache_stats
|
|
47
|
+
CACHE_STORES.each_with_object({}) do |(key, ivar), stats|
|
|
48
|
+
store = instance_variable_get(ivar)
|
|
49
|
+
stats[key] = store.respond_to?(:size) ? store.size : 0
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def prune_cache!(*keys)
|
|
54
|
+
keys = CACHE_STORES.keys if keys.empty?
|
|
55
|
+
|
|
56
|
+
keys.each_with_object({}) do |key, pruned|
|
|
57
|
+
ivar = CACHE_STORES.fetch(key)
|
|
58
|
+
store = instance_variable_get(ivar)
|
|
59
|
+
pruned[key] = store.respond_to?(:size) ? store.size : 0
|
|
60
|
+
store&.clear
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
35
64
|
# Returns or caches the available voice regions
|
|
36
65
|
def voice_regions
|
|
37
66
|
return fetch_voice_regions unless cache_enabled?(:voice_regions)
|
|
@@ -43,13 +43,14 @@ module OnyxCord
|
|
|
43
43
|
}
|
|
44
44
|
}.freeze
|
|
45
45
|
|
|
46
|
-
attr_accessor :mode, :cache, :event_executor, :event_workers
|
|
46
|
+
attr_accessor :mode, :cache, :event_executor, :event_workers, :event_queue_size
|
|
47
47
|
|
|
48
48
|
def initialize
|
|
49
|
-
@mode = :
|
|
49
|
+
@mode = :hybrid
|
|
50
50
|
@cache = :none
|
|
51
51
|
@event_executor = :pool
|
|
52
52
|
@event_workers = 4
|
|
53
|
+
@event_queue_size = nil
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def dup
|
|
@@ -58,6 +59,7 @@ module OnyxCord
|
|
|
58
59
|
copy.cache = @cache.is_a?(Hash) ? @cache.dup : @cache
|
|
59
60
|
copy.event_executor = @event_executor
|
|
60
61
|
copy.event_workers = @event_workers
|
|
62
|
+
copy.event_queue_size = @event_queue_size
|
|
61
63
|
copy
|
|
62
64
|
end
|
|
63
65
|
|
|
@@ -82,6 +84,15 @@ module OnyxCord
|
|
|
82
84
|
workers
|
|
83
85
|
end
|
|
84
86
|
|
|
87
|
+
def normalize_event_queue_size(value = @event_queue_size)
|
|
88
|
+
return nil if value.nil?
|
|
89
|
+
|
|
90
|
+
size = Integer(value)
|
|
91
|
+
raise ArgumentError, 'event_queue_size must be greater than zero' unless size.positive?
|
|
92
|
+
|
|
93
|
+
size
|
|
94
|
+
end
|
|
95
|
+
|
|
85
96
|
def normalize_cache(value = @cache)
|
|
86
97
|
cache = value.nil? ? @cache : value
|
|
87
98
|
|
|
@@ -331,7 +331,7 @@ module OnyxCord
|
|
|
331
331
|
def initialize(data, bot)
|
|
332
332
|
@bot = bot
|
|
333
333
|
@id = data['id']
|
|
334
|
-
@items = data['items'].map { |item| Item.new(item, @bot) }
|
|
334
|
+
@items = Array(data['items']).map { |item| Item.new(item, @bot) }
|
|
335
335
|
end
|
|
336
336
|
|
|
337
337
|
# A singular media attachment.
|
|
@@ -515,7 +515,7 @@ module OnyxCord
|
|
|
515
515
|
@bot = bot
|
|
516
516
|
@id = data['id']
|
|
517
517
|
@custom_id = data['custom_id']
|
|
518
|
-
@values = data['values'].map(&:to_i)
|
|
518
|
+
@values = Array(data['values']).map(&:to_i)
|
|
519
519
|
end
|
|
520
520
|
end
|
|
521
521
|
|
|
@@ -20,12 +20,12 @@ module OnyxCord
|
|
|
20
20
|
|
|
21
21
|
# Fixed-size worker pool for event handlers.
|
|
22
22
|
class Pool
|
|
23
|
-
attr_reader :threads
|
|
23
|
+
attr_reader :threads, :queue
|
|
24
24
|
|
|
25
|
-
def initialize(size:)
|
|
25
|
+
def initialize(size:, queue_size: nil)
|
|
26
26
|
raise ArgumentError, 'Pool size must be greater than zero' unless size.positive?
|
|
27
27
|
|
|
28
|
-
@queue = Queue.new
|
|
28
|
+
@queue = queue_size ? SizedQueue.new(queue_size) : Queue.new
|
|
29
29
|
@closed = false
|
|
30
30
|
@threads = Array.new(size) do |index|
|
|
31
31
|
Thread.new do
|
|
@@ -42,6 +42,10 @@ module OnyxCord
|
|
|
42
42
|
@queue << block
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def queue_size
|
|
46
|
+
@queue.size
|
|
47
|
+
end
|
|
48
|
+
|
|
45
49
|
def shutdown
|
|
46
50
|
return if @closed
|
|
47
51
|
|
|
@@ -66,12 +70,12 @@ module OnyxCord
|
|
|
66
70
|
|
|
67
71
|
module_function
|
|
68
72
|
|
|
69
|
-
def build(type, workers:)
|
|
73
|
+
def build(type, workers:, queue_size: nil)
|
|
70
74
|
case type
|
|
71
75
|
when :inline
|
|
72
76
|
Inline.new
|
|
73
77
|
when :pool
|
|
74
|
-
Pool.new(size: workers)
|
|
78
|
+
Pool.new(size: workers, queue_size: queue_size)
|
|
75
79
|
else
|
|
76
80
|
raise ArgumentError, "Unknown event executor: #{type.inspect}"
|
|
77
81
|
end
|
|
@@ -7,10 +7,18 @@ module OnyxCord
|
|
|
7
7
|
# Discord REST rate limiter keyed by route/major parameter and remapped to
|
|
8
8
|
# X-RateLimit-Bucket whenever Discord returns a concrete bucket id.
|
|
9
9
|
class Rest
|
|
10
|
-
|
|
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)
|
|
11
14
|
@route_buckets = {}
|
|
12
15
|
@bucket_mutexes = {}
|
|
16
|
+
@bucket_last_used = {}
|
|
13
17
|
@global_mutex = Mutex.new
|
|
18
|
+
@clock = clock
|
|
19
|
+
@entry_ttl = entry_ttl
|
|
20
|
+
@prune_interval = prune_interval
|
|
21
|
+
@requests_since_prune = 0
|
|
14
22
|
end
|
|
15
23
|
|
|
16
24
|
def before_request(route, major_parameter)
|
|
@@ -21,8 +29,14 @@ module OnyxCord
|
|
|
21
29
|
def record_response(route, major_parameter, headers)
|
|
22
30
|
headers = normalize_headers(headers)
|
|
23
31
|
bucket = headers[:x_ratelimit_bucket]
|
|
32
|
+
key = route_key(route, major_parameter)
|
|
33
|
+
touch(key)
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
if bucket
|
|
36
|
+
bucket = bucket_key(bucket, major_parameter)
|
|
37
|
+
@route_buckets[key] = bucket
|
|
38
|
+
touch(bucket)
|
|
39
|
+
end
|
|
26
40
|
|
|
27
41
|
return unless headers[:x_ratelimit_remaining] == '0'
|
|
28
42
|
|
|
@@ -40,10 +54,37 @@ module OnyxCord
|
|
|
40
54
|
sync_wait(wait_seconds, mutex) if wait_seconds.positive?
|
|
41
55
|
end
|
|
42
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
|
+
|
|
43
82
|
private
|
|
44
83
|
|
|
45
84
|
def mutex_for(route, major_parameter)
|
|
46
|
-
|
|
85
|
+
key = resolved_key(route, major_parameter)
|
|
86
|
+
touch(key)
|
|
87
|
+
@bucket_mutexes[key] ||= Mutex.new
|
|
47
88
|
end
|
|
48
89
|
|
|
49
90
|
def resolved_key(route, major_parameter)
|
|
@@ -76,6 +117,18 @@ module OnyxCord
|
|
|
76
117
|
end
|
|
77
118
|
end
|
|
78
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
|
+
|
|
79
132
|
def sync_wait(time, mutex)
|
|
80
133
|
mutex.synchronize { sleep time }
|
|
81
134
|
end
|
data/lib/onyxcord/version.rb
CHANGED
|
@@ -113,6 +113,10 @@ module OnyxCord::Voice
|
|
|
113
113
|
send_packet(discovery_packet)
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
+
def close
|
|
117
|
+
@socket.close unless @socket.closed?
|
|
118
|
+
end
|
|
119
|
+
|
|
116
120
|
private
|
|
117
121
|
|
|
118
122
|
# Encrypts audio data using libsodium
|
|
@@ -339,8 +343,12 @@ module OnyxCord::Voice
|
|
|
339
343
|
end
|
|
340
344
|
|
|
341
345
|
# Disconnects the websocket and kills the thread
|
|
342
|
-
def destroy
|
|
346
|
+
def destroy(join_timeout = 1)
|
|
343
347
|
@heartbeat_running = false
|
|
348
|
+
@client&.close
|
|
349
|
+
@udp.close
|
|
350
|
+
@thread&.join(join_timeout)
|
|
351
|
+
@thread&.kill if @thread&.alive?
|
|
344
352
|
end
|
|
345
353
|
|
|
346
354
|
private
|
|
@@ -265,36 +265,37 @@ module OnyxCord::Voice
|
|
|
265
265
|
stop_playing(true) if @playing
|
|
266
266
|
|
|
267
267
|
@bot.debug "Reading DCA file #{file}"
|
|
268
|
-
input_stream = File.open(file)
|
|
269
268
|
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
File.open(file) do |input_stream|
|
|
270
|
+
magic = input_stream.read(4)
|
|
271
|
+
raise ArgumentError, 'Not a DCA1 file! The file might have been corrupted, please recreate it.' unless magic == 'DCA1'
|
|
272
272
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
273
|
+
# Read the metadata header, then read the metadata and discard it as we don't care about it
|
|
274
|
+
metadata_header = input_stream.read(4).unpack1('l<')
|
|
275
|
+
input_stream.read(metadata_header)
|
|
276
276
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
277
|
+
# Play the data, without re-encoding it to opus
|
|
278
|
+
play_internal do
|
|
279
|
+
begin
|
|
280
|
+
# Read header
|
|
281
|
+
header_str = input_stream.read(2)
|
|
282
|
+
|
|
283
|
+
unless header_str
|
|
284
|
+
@bot.debug 'Finished DCA parsing (header is nil)'
|
|
285
|
+
next :stop
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
header = header_str.unpack1('s<')
|
|
282
289
|
|
|
283
|
-
|
|
284
|
-
|
|
290
|
+
raise 'Negative header in DCA file! Your file is likely corrupted.' if header.negative?
|
|
291
|
+
rescue EOFError
|
|
292
|
+
@bot.debug 'Finished DCA parsing (EOFError)'
|
|
285
293
|
next :stop
|
|
286
294
|
end
|
|
287
295
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
raise 'Negative header in DCA file! Your file is likely corrupted.' if header.negative?
|
|
291
|
-
rescue EOFError
|
|
292
|
-
@bot.debug 'Finished DCA parsing (EOFError)'
|
|
293
|
-
next :stop
|
|
296
|
+
# Read bytes
|
|
297
|
+
input_stream.read(header)
|
|
294
298
|
end
|
|
295
|
-
|
|
296
|
-
# Read bytes
|
|
297
|
-
input_stream.read(header)
|
|
298
299
|
end
|
|
299
300
|
end
|
|
300
301
|
|
data/onyxcord-webhooks.gemspec
CHANGED
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
19
|
spec.require_paths = ['lib']
|
|
20
20
|
|
|
21
|
-
spec.add_dependency 'rest-client', '>= 2.0.0'
|
|
21
|
+
spec.add_dependency 'rest-client', '>= 2.0.0', '< 3'
|
|
22
22
|
|
|
23
23
|
spec.required_ruby_version = '>= 3.3'
|
|
24
24
|
spec.metadata = {
|
data/onyxcord.gemspec
CHANGED
|
@@ -27,10 +27,10 @@ Gem::Specification.new do |spec|
|
|
|
27
27
|
spec.require_paths = ['lib']
|
|
28
28
|
|
|
29
29
|
spec.add_dependency 'base64', '~> 0.2'
|
|
30
|
-
spec.add_dependency 'ffi', '>= 1.9.24'
|
|
31
|
-
spec.add_dependency 'opus-ruby'
|
|
32
|
-
spec.add_dependency 'rest-client', '>= 2.0.0'
|
|
33
|
-
spec.add_dependency 'websocket-client-simple', '>= 0.9.0'
|
|
30
|
+
spec.add_dependency 'ffi', '>= 1.9.24', '< 2'
|
|
31
|
+
spec.add_dependency 'opus-ruby', '>= 0', '< 2'
|
|
32
|
+
spec.add_dependency 'rest-client', '>= 2.0.0', '< 3'
|
|
33
|
+
spec.add_dependency 'websocket-client-simple', '>= 0.9.0', '< 1'
|
|
34
34
|
|
|
35
35
|
spec.add_dependency 'onyxcord-webhooks', "~> #{OnyxCord::Webhooks::VERSION}"
|
|
36
36
|
|
data/relator.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Relatorio geral da OnyxCord
|
|
2
|
+
|
|
3
|
+
Data da analise: 2026-06-23
|
|
4
|
+
|
|
5
|
+
Escopo analisado:
|
|
6
|
+
- Gem Ruby `onyxcord` e `onyxcord-webhooks`.
|
|
7
|
+
- Areas principais: REST API, gateway WebSocket, cache, executor de eventos, comandos/interactions, voice e webhooks.
|
|
8
|
+
- Teste executado: `bundle exec rspec`.
|
|
9
|
+
|
|
10
|
+
Resultado da validacao atual:
|
|
11
|
+
- `bundle exec rspec`: 456 exemplos, 0 falhas, 3 pendentes.
|
|
12
|
+
- Cobertura reportada pelo SimpleCov: 60,84% de linhas.
|
|
13
|
+
- `gem build onyxcord.gemspec`: sucesso, gerou `onyxcord-1.1.2.gem`.
|
|
14
|
+
- `gem build onyxcord-webhooks.gemspec`: sucesso, gerou `onyxcord-webhooks-1.1.2.gem`.
|
|
15
|
+
|
|
16
|
+
Status das correcoes aplicadas:
|
|
17
|
+
- Corrigido retry REST `202` preservando route e major parameter.
|
|
18
|
+
- Application commands agora executam pelo `EventExecutor`, sem `Thread.new` direto nesse caminho.
|
|
19
|
+
- Adicionado `event_queue_size` com `SizedQueue` opcional.
|
|
20
|
+
- Adicionados `runtime_stats`, `cache_stats`, `prune_cache!` e `OnyxCord::API.rate_limiter_stats`.
|
|
21
|
+
- Rate limiter REST agora tem `stats`, `prune!` e limpeza automatica de bookkeeping antigo.
|
|
22
|
+
- Voice fecha melhor recursos de UDP/WebSocket/thread, e `play_dca` usa `File.open` com bloco.
|
|
23
|
+
- Dependencias principais receberam upper bounds conservadores.
|
|
24
|
+
- Warning de spec em `spec/bot_spec.rb:114` foi corrigido.
|
|
25
|
+
|
|
26
|
+
## Resumo executivo
|
|
27
|
+
|
|
28
|
+
A lib ja tem algumas decisoes boas para performance:
|
|
29
|
+
- O modo padrao do bot agora e `hybrid`, equilibrando handlers raw com eventos em objeto.
|
|
30
|
+
- O cache padrao global esta em `:none`, o que ajuda a reduzir RAM para bots pequenos.
|
|
31
|
+
- Ja existe `EventExecutor::Pool`, evitando uma thread nova para cada evento comum.
|
|
32
|
+
- O rate limiter REST ja centraliza buckets, global limit e `retry_after`.
|
|
33
|
+
- O gateway usa zlib stream, economizando trafego e CPU em payloads grandes.
|
|
34
|
+
|
|
35
|
+
Os maiores ganhos agora estao em 5 frentes:
|
|
36
|
+
1. Eliminar threads soltas em interactions e waits.
|
|
37
|
+
2. Colocar limite/backpressure no executor de eventos.
|
|
38
|
+
3. Colocar estrategia de limite/limpeza nos caches e nos mapas do rate limiter.
|
|
39
|
+
4. Corrigir um bug provavel no retry de resposta REST `202`.
|
|
40
|
+
5. Fechar recursos de voz/arquivos/sockets de forma garantida.
|
|
41
|
+
|
|
42
|
+
## Prioridade alta
|
|
43
|
+
|
|
44
|
+
### 1. Corrigir retry de REST `202` em `OnyxCord::API.request`
|
|
45
|
+
|
|
46
|
+
Arquivo: `lib/onyxcord/api.rb:141-154`
|
|
47
|
+
|
|
48
|
+
Problema:
|
|
49
|
+
- Quando Discord retorna `202` com codigo `110000`, o metodo tenta repetir a request.
|
|
50
|
+
- A chamada atual usa `return request(*key, type, *attributes)`.
|
|
51
|
+
- Na maior parte da API, `key` e um `Symbol`, entao `*key` tende a quebrar com `TypeError` ou chamar `request` com parametros errados.
|
|
52
|
+
|
|
53
|
+
Impacto:
|
|
54
|
+
- Endpoints baseados em Elasticsearch podem falhar justamente no fluxo em que deveriam aguardar e tentar de novo.
|
|
55
|
+
|
|
56
|
+
Sugestao:
|
|
57
|
+
- Trocar para `return request(key, major_parameter, type, *attributes)`.
|
|
58
|
+
- Adicionar spec cobrindo response `202` com `retry_after`.
|
|
59
|
+
|
|
60
|
+
### 2. Application commands criam `Thread.new` fora do executor
|
|
61
|
+
|
|
62
|
+
Arquivo: `lib/onyxcord/bot.rb:1679-1704`
|
|
63
|
+
|
|
64
|
+
Problema:
|
|
65
|
+
- O fluxo de `INTERACTION_CREATE` para command cria uma thread direta por comando.
|
|
66
|
+
- Isso ignora `EventExecutor::Pool`, ignora `event_workers` e remove qualquer controle de concorrencia.
|
|
67
|
+
- Tambem ha logs temporarios com prefixo `>>>` em caminho quente.
|
|
68
|
+
- O rescue usa `rescue Exception`, que captura sinais de sistema e saidas do processo.
|
|
69
|
+
|
|
70
|
+
Impacto:
|
|
71
|
+
- Em pico de interactions, o processo pode criar muitas threads, consumindo RAM e escalonamento de CPU.
|
|
72
|
+
- Logs verbosos em production aumentam I/O e custo de CPU.
|
|
73
|
+
|
|
74
|
+
Sugestao:
|
|
75
|
+
- Executar handler via `@event_executor.post`.
|
|
76
|
+
- Usar `rescue StandardError`.
|
|
77
|
+
- Trocar logs `info` temporarios por `debug` ou remover.
|
|
78
|
+
- Nomear a thread dentro do bloco do executor, como ja acontece em `call_event`.
|
|
79
|
+
|
|
80
|
+
### 3. Fila de eventos sem limite
|
|
81
|
+
|
|
82
|
+
Arquivo: `lib/onyxcord/event_executor.rb:28-42`
|
|
83
|
+
|
|
84
|
+
Problema:
|
|
85
|
+
- `Queue.new` e ilimitada.
|
|
86
|
+
- Se os handlers forem mais lentos que os eventos recebidos, a fila cresce sem backpressure.
|
|
87
|
+
|
|
88
|
+
Impacto:
|
|
89
|
+
- Pode virar crescimento progressivo de RAM em servidores grandes ou bots com handlers pesados.
|
|
90
|
+
|
|
91
|
+
Sugestao:
|
|
92
|
+
- Adicionar opcao `event_queue_size`, usando `SizedQueue`.
|
|
93
|
+
- Expor comportamento configuravel: bloquear, rejeitar com log, ou executar inline em emergencia.
|
|
94
|
+
- Medir tamanho da fila em debug/telemetria.
|
|
95
|
+
|
|
96
|
+
## Prioridade media
|
|
97
|
+
|
|
98
|
+
### 4. Rate limiter guarda mutexes e buckets para sempre
|
|
99
|
+
|
|
100
|
+
Arquivo: `lib/onyxcord/rate_limiter/rest.rb:10-47`
|
|
101
|
+
|
|
102
|
+
Problema:
|
|
103
|
+
- `@route_buckets` e `@bucket_mutexes` crescem conforme novas rotas/major parameters aparecem.
|
|
104
|
+
- Para bots que tocam muitos canais, guilds, mensagens ou webhooks, isso pode acumular.
|
|
105
|
+
|
|
106
|
+
Impacto:
|
|
107
|
+
- RAM pequena por item, mas permanente.
|
|
108
|
+
|
|
109
|
+
Sugestao:
|
|
110
|
+
- Guardar `last_used_at` por bucket e limpar entradas antigas.
|
|
111
|
+
- Alternativa simples: limitar por LRU.
|
|
112
|
+
- Adicionar metodo `prune!` chamado ocasionalmente em `record_response`.
|
|
113
|
+
|
|
114
|
+
### 5. Cache full pode crescer sem limite
|
|
115
|
+
|
|
116
|
+
Arquivo: `lib/onyxcord/cache.rb:16-29`
|
|
117
|
+
|
|
118
|
+
Problema:
|
|
119
|
+
- Caches de users, channels, pm_channels, thread_members e server_previews sao Hashes sem TTL/max size.
|
|
120
|
+
- O default global e `:none`, mas quem usa `:full` pode segurar muitos objetos.
|
|
121
|
+
|
|
122
|
+
Impacto:
|
|
123
|
+
- Em bots grandes, memoria cresce com o tempo e dificilmente volta.
|
|
124
|
+
|
|
125
|
+
Sugestao:
|
|
126
|
+
- Manter `:none` como default.
|
|
127
|
+
- Adicionar opcoes por cache: `max_users`, `max_channels`, `max_messages`, `ttl`.
|
|
128
|
+
- Oferecer `bot.prune_cache!` e `bot.cache_stats`.
|
|
129
|
+
- Considerar guardar payload cru em modo leve, criando objeto sob demanda.
|
|
130
|
+
|
|
131
|
+
### 6. `request_chunks` cria buckets por guild sem limpeza
|
|
132
|
+
|
|
133
|
+
Arquivo: `lib/onyxcord/cache.rb:235-253`
|
|
134
|
+
|
|
135
|
+
Problema:
|
|
136
|
+
- `@request_members_rl[id]` guarda mutex/time por guild e nunca remove.
|
|
137
|
+
|
|
138
|
+
Impacto:
|
|
139
|
+
- Baixo por guild, mas permanente em bots que entram/saem de muitos servidores.
|
|
140
|
+
|
|
141
|
+
Sugestao:
|
|
142
|
+
- Remover no evento de saida de guild.
|
|
143
|
+
- Limpar buckets nao usados ha alguns minutos/horas.
|
|
144
|
+
|
|
145
|
+
### 7. Voice pode deixar arquivo aberto em `play_dca`
|
|
146
|
+
|
|
147
|
+
Arquivo: `lib/onyxcord/voice/voice_bot.rb:264-299`
|
|
148
|
+
|
|
149
|
+
Problema:
|
|
150
|
+
- `File.open(file)` nao usa bloco nem `ensure`.
|
|
151
|
+
- Se erro ocorrer durante validacao ou playback, o descritor pode ficar aberto.
|
|
152
|
+
|
|
153
|
+
Impacto:
|
|
154
|
+
- Vazamento de file descriptor em uso repetido de voz.
|
|
155
|
+
|
|
156
|
+
Sugestao:
|
|
157
|
+
- Usar `File.open(file) do |input_stream| ... end` ou `ensure input_stream&.close`.
|
|
158
|
+
|
|
159
|
+
### 8. Voice WebSocket nao fecha/junta thread explicitamente
|
|
160
|
+
|
|
161
|
+
Arquivo: `lib/onyxcord/voice/network.rb:321-344`
|
|
162
|
+
|
|
163
|
+
Problema:
|
|
164
|
+
- `destroy` apenas seta `@heartbeat_running = false`.
|
|
165
|
+
- Nao fecha o WebSocket, nao fecha UDP e nao faz join da thread.
|
|
166
|
+
|
|
167
|
+
Impacto:
|
|
168
|
+
- Possivel sobra de thread/socket em reconexoes ou destroy repetido.
|
|
169
|
+
|
|
170
|
+
Sugestao:
|
|
171
|
+
- Implementar close de `@client`, close de UDP socket e `@thread.join` com timeout curto.
|
|
172
|
+
- Adicionar spec com fake socket/client garantindo cleanup.
|
|
173
|
+
|
|
174
|
+
### 9. Busy wait com `sleep` em pontos sensiveis
|
|
175
|
+
|
|
176
|
+
Arquivos:
|
|
177
|
+
- `lib/onyxcord/voice/network.rb:338`
|
|
178
|
+
- `lib/onyxcord/voice/voice_bot.rb:315`
|
|
179
|
+
- `lib/onyxcord/bot.rb:413`
|
|
180
|
+
|
|
181
|
+
Problema:
|
|
182
|
+
- Loops `sleep until` e `sleep while` sao simples, mas acordam periodicamente sem evento real.
|
|
183
|
+
|
|
184
|
+
Impacto:
|
|
185
|
+
- Baixo em poucos bots, mas piora com muitas conexoes/threads.
|
|
186
|
+
|
|
187
|
+
Sugestao:
|
|
188
|
+
- Usar `ConditionVariable` para readiness/pausa.
|
|
189
|
+
- Para voice playback, manter cuidado para nao prejudicar o timing de audio.
|
|
190
|
+
|
|
191
|
+
## Prioridade baixa / limpeza
|
|
192
|
+
|
|
193
|
+
### 10. Webhooks nao usam o rate limiter central
|
|
194
|
+
|
|
195
|
+
Arquivo: `lib/onyxcord/webhooks/client.rb`
|
|
196
|
+
|
|
197
|
+
Problema:
|
|
198
|
+
- Chamadas usam `RestClient.post/patch/delete` direto.
|
|
199
|
+
- Isso e simples, mas nao aproveita `OnyxCord::RateLimiter::Rest`.
|
|
200
|
+
|
|
201
|
+
Impacto:
|
|
202
|
+
- Clientes de webhook intensivos podem bater 429 com menos controle.
|
|
203
|
+
|
|
204
|
+
Sugestao:
|
|
205
|
+
- Criar transport compartilhado leve para webhooks.
|
|
206
|
+
- Ou criar um rate limiter dedicado por webhook URL.
|
|
207
|
+
|
|
208
|
+
### 11. Dependencias abertas demais
|
|
209
|
+
|
|
210
|
+
Arquivos:
|
|
211
|
+
- `onyxcord.gemspec`
|
|
212
|
+
- `onyxcord-webhooks.gemspec`
|
|
213
|
+
|
|
214
|
+
Problema:
|
|
215
|
+
- Algumas dependencias permitem qualquer versao acima do minimo, como `rest-client >= 2.0.0`, `websocket-client-simple >= 0.9.0`, `ffi >= 1.9.24` e `opus-ruby` sem limite.
|
|
216
|
+
|
|
217
|
+
Impacto:
|
|
218
|
+
- Atualizacao futura pode quebrar performance ou compatibilidade.
|
|
219
|
+
|
|
220
|
+
Sugestao:
|
|
221
|
+
- Definir upper bounds conservadores, por exemplo `< 3` quando fizer sentido.
|
|
222
|
+
- Rodar CI com Ruby 3.3 e 3.4 se a gem prometer suporte moderno.
|
|
223
|
+
|
|
224
|
+
### 12. Arquivo `bot.rb` esta grande demais
|
|
225
|
+
|
|
226
|
+
Arquivo: `lib/onyxcord/bot.rb` tem cerca de 1971 linhas.
|
|
227
|
+
|
|
228
|
+
Problema:
|
|
229
|
+
- O arquivo mistura boot, REST helpers, dispatch, cache orchestration, interactions, voice e commands.
|
|
230
|
+
|
|
231
|
+
Impacto:
|
|
232
|
+
- Dificulta otimizar sem regressao.
|
|
233
|
+
|
|
234
|
+
Sugestao:
|
|
235
|
+
- Extrair aos poucos:
|
|
236
|
+
- `Bot::Interactions`
|
|
237
|
+
- `Bot::Dispatch`
|
|
238
|
+
- `Bot::Voice`
|
|
239
|
+
- `Bot::ApplicationCommands`
|
|
240
|
+
- Fazer isso depois das correcoes de runtime, para nao misturar refactor com bugfix.
|
|
241
|
+
|
|
242
|
+
## Otimizacoes praticas sugeridas
|
|
243
|
+
|
|
244
|
+
### Perfil leve recomendado para usuarios
|
|
245
|
+
|
|
246
|
+
Documentar no README um preset para bots pequenos:
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
OnyxCord.configure do |config|
|
|
250
|
+
config.mode = :raw
|
|
251
|
+
config.cache = :none
|
|
252
|
+
config.event_executor = :pool
|
|
253
|
+
config.event_workers = 2
|
|
254
|
+
end
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Para bots medios:
|
|
258
|
+
|
|
259
|
+
```ruby
|
|
260
|
+
OnyxCord.configure do |config|
|
|
261
|
+
config.mode = :hybrid
|
|
262
|
+
config.cache = :minimal
|
|
263
|
+
config.event_workers = 4
|
|
264
|
+
end
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Medir antes/depois
|
|
268
|
+
|
|
269
|
+
Criar specs/benchmarks simples para:
|
|
270
|
+
- `INTERACTION_CREATE` com 1000 commands simulados.
|
|
271
|
+
- `MESSAGE_CREATE` em modo `raw`, `hybrid` e `object`.
|
|
272
|
+
- crescimento de `@users`, `@channels`, `@thread_members`.
|
|
273
|
+
- fila do executor quando handler dorme 50ms.
|
|
274
|
+
|
|
275
|
+
### Instrumentacao leve
|
|
276
|
+
|
|
277
|
+
Adicionar metodos opcionais:
|
|
278
|
+
- `bot.runtime_stats`
|
|
279
|
+
- `bot.cache_stats`
|
|
280
|
+
- `bot.event_queue_size`
|
|
281
|
+
- `OnyxCord::API.rate_limiter_stats`
|
|
282
|
+
|
|
283
|
+
Isso ajuda a diagnosticar RAM e lentidao sem profiler externo.
|
|
284
|
+
|
|
285
|
+
## Plano de acao recomendado
|
|
286
|
+
|
|
287
|
+
1. Corrigir `API.request` no retry `202` e adicionar spec.
|
|
288
|
+
2. Remover threads soltas dos application commands e usar `@event_executor`.
|
|
289
|
+
3. Remover logs `>>>` ou rebaixar para `debug`.
|
|
290
|
+
4. Trocar `Queue` por `SizedQueue` configuravel.
|
|
291
|
+
5. Adicionar `cache_stats` e `prune_cache!`.
|
|
292
|
+
6. Fechar corretamente recursos de voice (`File.open`, UDP, WS, thread).
|
|
293
|
+
7. Adicionar limpeza/LRU no rate limiter REST.
|
|
294
|
+
8. Depois disso, refatorar `bot.rb` em modulos menores.
|
|
295
|
+
|
|
296
|
+
## Conclusao
|
|
297
|
+
|
|
298
|
+
A OnyxCord ja esta no caminho certo para ser pratica no modo padrao `hybrid` e ainda leve quando o usuario escolher `raw` com cache `:none`. O maior risco atual nao e um unico algoritmo pesado, e sim crescimento sem limite: threads por interaction, fila ilimitada, caches sem TTL e mapas internos que nao expiram. Corrigir esses pontos deve reduzir RAM em carga real, deixar o bot mais previsivel em pico e facilitar otimizar depois sem mexer na API publica.
|
data/relatorio2.md
ADDED
|
File without changes
|
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: 1.1.
|
|
4
|
+
version: 1.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gustavo Silva
|
|
@@ -30,6 +30,9 @@ dependencies:
|
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: 1.9.24
|
|
33
|
+
- - "<"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '2'
|
|
33
36
|
type: :runtime
|
|
34
37
|
prerelease: false
|
|
35
38
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -37,6 +40,9 @@ dependencies:
|
|
|
37
40
|
- - ">="
|
|
38
41
|
- !ruby/object:Gem::Version
|
|
39
42
|
version: 1.9.24
|
|
43
|
+
- - "<"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '2'
|
|
40
46
|
- !ruby/object:Gem::Dependency
|
|
41
47
|
name: opus-ruby
|
|
42
48
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,6 +50,9 @@ dependencies:
|
|
|
44
50
|
- - ">="
|
|
45
51
|
- !ruby/object:Gem::Version
|
|
46
52
|
version: '0'
|
|
53
|
+
- - "<"
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '2'
|
|
47
56
|
type: :runtime
|
|
48
57
|
prerelease: false
|
|
49
58
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -51,6 +60,9 @@ dependencies:
|
|
|
51
60
|
- - ">="
|
|
52
61
|
- !ruby/object:Gem::Version
|
|
53
62
|
version: '0'
|
|
63
|
+
- - "<"
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '2'
|
|
54
66
|
- !ruby/object:Gem::Dependency
|
|
55
67
|
name: rest-client
|
|
56
68
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,6 +70,9 @@ dependencies:
|
|
|
58
70
|
- - ">="
|
|
59
71
|
- !ruby/object:Gem::Version
|
|
60
72
|
version: 2.0.0
|
|
73
|
+
- - "<"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3'
|
|
61
76
|
type: :runtime
|
|
62
77
|
prerelease: false
|
|
63
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -65,6 +80,9 @@ dependencies:
|
|
|
65
80
|
- - ">="
|
|
66
81
|
- !ruby/object:Gem::Version
|
|
67
82
|
version: 2.0.0
|
|
83
|
+
- - "<"
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '3'
|
|
68
86
|
- !ruby/object:Gem::Dependency
|
|
69
87
|
name: websocket-client-simple
|
|
70
88
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,6 +90,9 @@ dependencies:
|
|
|
72
90
|
- - ">="
|
|
73
91
|
- !ruby/object:Gem::Version
|
|
74
92
|
version: 0.9.0
|
|
93
|
+
- - "<"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '1'
|
|
75
96
|
type: :runtime
|
|
76
97
|
prerelease: false
|
|
77
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -79,20 +100,23 @@ dependencies:
|
|
|
79
100
|
- - ">="
|
|
80
101
|
- !ruby/object:Gem::Version
|
|
81
102
|
version: 0.9.0
|
|
103
|
+
- - "<"
|
|
104
|
+
- !ruby/object:Gem::Version
|
|
105
|
+
version: '1'
|
|
82
106
|
- !ruby/object:Gem::Dependency
|
|
83
107
|
name: onyxcord-webhooks
|
|
84
108
|
requirement: !ruby/object:Gem::Requirement
|
|
85
109
|
requirements:
|
|
86
110
|
- - "~>"
|
|
87
111
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 1.1.
|
|
112
|
+
version: 1.1.4
|
|
89
113
|
type: :runtime
|
|
90
114
|
prerelease: false
|
|
91
115
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
116
|
requirements:
|
|
93
117
|
- - "~>"
|
|
94
118
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: 1.1.
|
|
119
|
+
version: 1.1.4
|
|
96
120
|
- !ruby/object:Gem::Dependency
|
|
97
121
|
name: bundler
|
|
98
122
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -392,6 +416,8 @@ files:
|
|
|
392
416
|
- lib/onyxcord/websocket.rb
|
|
393
417
|
- onyxcord-webhooks.gemspec
|
|
394
418
|
- onyxcord.gemspec
|
|
419
|
+
- relator.md
|
|
420
|
+
- relatorio2.md
|
|
395
421
|
homepage: https://github.com/kruldevb/OnyxCord
|
|
396
422
|
licenses:
|
|
397
423
|
- MIT
|