Class: OnyxCord::Gateway::Client
- Inherits:
-
Object
- Object
- OnyxCord::Gateway::Client
- Defined in:
- lib/onyxcord/gateway/client.rb
Overview
Client for the Discord gateway protocol — fully async.
Constant Summary collapse
- LARGE_THRESHOLD =
100- GATEWAY_VERSION =
ENV.fetch('DISCORD_GATEWAY_VERSION', '10').to_i
- FATAL_CLOSE_CODES =
[4003, 4004, 4011, 4014].freeze
Instance Attribute Summary collapse
-
#check_heartbeat_acks ⇒ Object
Returns the value of attribute check_heartbeat_acks.
-
#intents ⇒ Object
readonly
Returns the value of attribute intents.
-
#latency ⇒ Object
readonly
Returns the value of attribute latency.
Instance Method Summary collapse
- #heartbeat ⇒ Object
- #identify ⇒ Object
-
#initialize(bot, token, shard_key = nil, compress_mode = :stream, intents = ALL_INTENTS) ⇒ Client
constructor
A new instance of Client.
- #inject_error(e) ⇒ Object
- #inject_reconnect(url = nil) ⇒ Object
- #inject_resume(seq) ⇒ Object
- #kill ⇒ Object
- #notify_ready ⇒ Object
- #open? ⇒ Boolean
- #reconnect(attempt_resume = true) ⇒ Object
- #resume ⇒ Object
- #run ⇒ Object
-
#run_async ⇒ Object
Connect to the gateway server inside an Async reactor.
- #send_heartbeat(sequence) ⇒ Object
- #send_identify(token, properties, compress, large_threshold, shard_key = nil, intents = ALL_INTENTS) ⇒ Object
- #send_packet(opcode, packet) ⇒ Object
- #send_raw(data, _type = :text) ⇒ Object
- #send_request_members(server_id, query, limit) ⇒ Object
- #send_resume(token, session_id, seq) ⇒ Object
- #send_status_update(status, since, game, afk) ⇒ Object
- #send_voice_state_update(server_id, channel_id, self_mute, self_deaf) ⇒ Object
- #stop ⇒ Object
- #sync ⇒ Object
Constructor Details
#initialize(bot, token, shard_key = nil, compress_mode = :stream, intents = ALL_INTENTS) ⇒ Client
Returns a new instance of Client.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/onyxcord/gateway/client.rb', line 22 def initialize(bot, token, shard_key = nil, compress_mode = :stream, intents = ALL_INTENTS) @token = token @bot = bot @shard_key = shard_key @ws_success = false @check_heartbeat_acks = true @compress_mode = compress_mode @intents = intents @send_limiter = Internal::RateLimiter::Gateway.new @zlib_mutex = Mutex.new @connection = nil @closed = true @pipe_broken = false @missed_heartbeat_acks = 0 end |
Instance Attribute Details
#check_heartbeat_acks ⇒ Object
Returns the value of attribute check_heartbeat_acks.
19 20 21 |
# File 'lib/onyxcord/gateway/client.rb', line 19 def check_heartbeat_acks @check_heartbeat_acks end |
#intents ⇒ Object (readonly)
Returns the value of attribute intents.
20 21 22 |
# File 'lib/onyxcord/gateway/client.rb', line 20 def intents @intents end |
#latency ⇒ Object (readonly)
Returns the value of attribute latency.
20 21 22 |
# File 'lib/onyxcord/gateway/client.rb', line 20 def latency @latency end |
Instance Method Details
#heartbeat ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/onyxcord/gateway/client.rb', line 92 def heartbeat if check_heartbeat_acks if @last_heartbeat_acked @missed_heartbeat_acks = 0 else @missed_heartbeat_acks += 1 if @missed_heartbeat_acks >= 2 LOGGER.warn('Last heartbeats were not acked — zombie connection! Reconnecting') @pipe_broken = true reconnect return end LOGGER.warn('Last heartbeat was not acked — waiting one more interval before reconnecting') end @last_heartbeat_acked = false end send_heartbeat(@session ? @session.sequence : 0) end |
#identify ⇒ Object
117 118 119 120 121 122 123 124 |
# File 'lib/onyxcord/gateway/client.rb', line 117 def identify compress = @compress_mode == :large send_identify(@token, { os: RUBY_PLATFORM, browser: 'onyxcord', device: 'onyxcord' }, compress, LARGE_THRESHOLD, @shard_key, @intents) end |
#inject_error(e) ⇒ Object
88 89 90 |
# File 'lib/onyxcord/gateway/client.rb', line 88 def inject_error(e) handle_internal_close(e) end |
#inject_reconnect(url = nil) ⇒ Object
79 80 81 82 |
# File 'lib/onyxcord/gateway/client.rb', line 79 def inject_reconnect(url = nil) data = url ? { op: Internal::Gateway::Opcodes::RECONNECT, d: { url: url } } : { op: Internal::Gateway::Opcodes::RECONNECT, d: nil } (data.to_json) end |
#inject_resume(seq) ⇒ Object
84 85 86 |
# File 'lib/onyxcord/gateway/client.rb', line 84 def inject_resume(seq) send_resume(raw_token, @session_id, seq || @sequence) end |
#kill ⇒ Object
71 72 73 |
# File 'lib/onyxcord/gateway/client.rb', line 71 def kill @task&.stop end |
#notify_ready ⇒ Object
75 76 77 |
# File 'lib/onyxcord/gateway/client.rb', line 75 def notify_ready @ws_success = true end |
#open? ⇒ Boolean
60 61 62 |
# File 'lib/onyxcord/gateway/client.rb', line 60 def open? !@closed && @connection end |
#reconnect(attempt_resume = true) ⇒ Object
153 154 155 156 157 158 159 160 161 |
# File 'lib/onyxcord/gateway/client.rb', line 153 def reconnect(attempt_resume = true) @session.suspend if @session && attempt_resume @session.invalidate if attempt_resume && @session && !@received_hello @instant_reconnect = true @should_reconnect = true @heartbeat_task&.stop @heartbeat_task = nil close(4000) end |
#resume ⇒ Object
149 150 151 |
# File 'lib/onyxcord/gateway/client.rb', line 149 def resume send_resume(@token, @session.session_id, @session.sequence) end |
#run ⇒ Object
50 51 52 53 54 |
# File 'lib/onyxcord/gateway/client.rb', line 50 def run @reactor_task = Async::Task.current connect_loop LOGGER.warn('The gateway loop exited!') end |
#run_async ⇒ Object
Connect to the gateway server inside an Async reactor.
39 40 41 42 43 44 45 46 47 48 |
# File 'lib/onyxcord/gateway/client.rb', line 39 def run_async @task = Internal::AsyncRuntime.async { run } LOGGER.debug('Gateway task created! Waiting for confirmation...') loop do Internal::AsyncRuntime.sleep(0.5) break if @ws_success break if @should_reconnect == false end end |
#send_heartbeat(sequence) ⇒ Object
112 113 114 115 |
# File 'lib/onyxcord/gateway/client.rb', line 112 def send_heartbeat(sequence) @last_heartbeat_sent_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) send_packet(Internal::Gateway::Opcodes::HEARTBEAT, sequence) end |
#send_identify(token, properties, compress, large_threshold, shard_key = nil, intents = ALL_INTENTS) ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/onyxcord/gateway/client.rb', line 126 def send_identify(token, properties, compress, large_threshold, shard_key = nil, intents = ALL_INTENTS) data = { token: token, properties: properties, compress: compress, large_threshold: large_threshold, intents: intents } data[:shard] = shard_key if shard_key send_packet(Internal::Gateway::Opcodes::IDENTIFY, data) end |
#send_packet(opcode, packet) ⇒ Object
171 172 173 |
# File 'lib/onyxcord/gateway/client.rb', line 171 def send_packet(opcode, packet) send({ op: opcode, d: packet }.to_json) end |
#send_raw(data, _type = :text) ⇒ Object
175 176 177 |
# File 'lib/onyxcord/gateway/client.rb', line 175 def send_raw(data, _type = :text) send(data) end |
#send_request_members(server_id, query, limit) ⇒ Object
167 168 169 |
# File 'lib/onyxcord/gateway/client.rb', line 167 def send_request_members(server_id, query, limit) send_packet(Internal::Gateway::Opcodes::REQUEST_MEMBERS, { guild_id: server_id, query: query, limit: limit }) end |
#send_resume(token, session_id, seq) ⇒ Object
163 164 165 |
# File 'lib/onyxcord/gateway/client.rb', line 163 def send_resume(token, session_id, seq) send_packet(Internal::Gateway::Opcodes::RESUME, { token: token, session_id: session_id, seq: seq }) end |
#send_status_update(status, since, game, afk) ⇒ Object
138 139 140 |
# File 'lib/onyxcord/gateway/client.rb', line 138 def send_status_update(status, since, game, afk) send_packet(Internal::Gateway::Opcodes::PRESENCE, { status: status, since: since, game: game, afk: afk }) end |
#send_voice_state_update(server_id, channel_id, self_mute, self_deaf) ⇒ Object
142 143 144 145 146 147 |
# File 'lib/onyxcord/gateway/client.rb', line 142 def send_voice_state_update(server_id, channel_id, self_mute, self_deaf) send_packet(Internal::Gateway::Opcodes::VOICE_STATE, { guild_id: server_id, channel_id: channel_id, self_mute: self_mute, self_deaf: self_deaf }) end |
#stop ⇒ Object
64 65 66 67 68 69 |
# File 'lib/onyxcord/gateway/client.rb', line 64 def stop @should_reconnect = false @intentional_shutdown = true close nil end |
#sync ⇒ Object
56 57 58 |
# File 'lib/onyxcord/gateway/client.rb', line 56 def sync @task&.wait end |