Class: DiscordRDA::GatewayClient
- Inherits:
-
Object
- Object
- DiscordRDA::GatewayClient
- Defined in:
- lib/discord_rda/connection/gateway_client.rb
Overview
WebSocket client for Discord Gateway. Handles connection, heartbeat, resume, and message dispatch.
Constant Summary collapse
- DEFAULT_VERSION =
Gateway versions
10- ENCODING =
Gateway encoding
'json'- OPCODES =
Gateway opcodes
{ dispatch: 0, heartbeat: 1, identify: 2, presence_update: 3, voice_state_update: 4, resume: 6, reconnect: 7, request_guild_members: 8, invalid_session: 9, hello: 10, heartbeat_ack: 11 }.freeze
Instance Attribute Summary collapse
-
#config ⇒ Configuration
readonly
Configuration instance.
-
#connected ⇒ Boolean
readonly
Whether connected.
-
#event_bus ⇒ EventBus
readonly
Event bus for dispatching events.
-
#logger ⇒ Logger
readonly
Logger instance.
-
#resume_gateway_url ⇒ String?
readonly
Resume gateway URL.
-
#sequence ⇒ Integer
readonly
Current sequence number.
-
#session_id ⇒ String
readonly
Session ID for resuming.
Instance Method Summary collapse
-
#connect ⇒ Async::Task
Connect to the Discord Gateway.
-
#disconnect ⇒ void
Disconnect from the Gateway.
-
#identify ⇒ void
Send an identify payload.
-
#initialize(config, event_bus, logger, shard_id: 0, shard_count: 1) ⇒ GatewayClient
constructor
Initialize the gateway client.
-
#request_guild_members(guild_id, query: '', limit: 0, presences: false, user_ids: nil, nonce: nil) ⇒ void
Request guild members (chunking).
- #restore_session_state(session_id:, sequence:, resume_gateway_url: nil) ⇒ Object
-
#resume ⇒ void
Send a resume payload.
-
#run ⇒ void
Run the gateway event loop.
-
#update_presence(status: 'online', activity: nil, afk: false) ⇒ void
Update presence.
Constructor Details
#initialize(config, event_bus, logger, shard_id: 0, shard_count: 1) ⇒ GatewayClient
Initialize the gateway client
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 67 def initialize(config, event_bus, logger, shard_id: 0, shard_count: 1) @config = config @event_bus = event_bus @logger = logger @shard_id = shard_id @shard_count = shard_count @sequence = 0 @session_id = nil @connected = false @heartbeat_interval = nil @heartbeat_task = nil @websocket = nil @zlib = nil @buffer = +'' @last_heartbeat_ack = Time.now @resume_gateway_url = nil end |
Instance Attribute Details
#config ⇒ Configuration (readonly)
Returns Configuration instance.
41 42 43 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 41 def config @config end |
#connected ⇒ Boolean (readonly)
Returns Whether connected.
59 60 61 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 59 def connected @connected end |
#event_bus ⇒ EventBus (readonly)
Returns Event bus for dispatching events.
44 45 46 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 44 def event_bus @event_bus end |
#logger ⇒ Logger (readonly)
Returns Logger instance.
47 48 49 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 47 def logger @logger end |
#resume_gateway_url ⇒ String? (readonly)
Returns Resume gateway URL.
56 57 58 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 56 def resume_gateway_url @resume_gateway_url end |
#sequence ⇒ Integer (readonly)
Returns Current sequence number.
50 51 52 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 50 def sequence @sequence end |
#session_id ⇒ String (readonly)
Returns Session ID for resuming.
53 54 55 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 53 def session_id @session_id end |
Instance Method Details
#connect ⇒ Async::Task
Connect to the Discord Gateway
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 87 def connect Async do gateway_url = @resume_gateway_url || fetch_gateway_url endpoint = build_endpoint(gateway_url) @logger&.info('Connecting to Gateway', shard: @shard_id, url: gateway_url) @zlib = Zlib::Inflate.new(15 + 32) if @config.gateway_compression == :zlib_stream @buffer = +'' begin Async::WebSocket::Client.connect(endpoint) do |websocket| @websocket = websocket @connected = true @logger&.info('Gateway connected', shard: @shard_id) end rescue => e @logger&.error('Gateway connection error', error: e, shard: @shard_id) @connected = false raise end end end |
#disconnect ⇒ void
This method returns an undefined value.
Disconnect from the Gateway
121 122 123 124 125 126 127 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 121 def disconnect @connected = false @heartbeat_task&.stop @websocket&.close @zlib&.close @logger&.info('Gateway disconnected', shard: @shard_id) end |
#identify ⇒ void
This method returns an undefined value.
Send an identify payload
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 131 def identify payload = { op: OPCODES[:identify], d: { token: @config.token, properties: { os: 'linux', browser: 'discord_rda', device: 'discord_rda' }, compress: @config.gateway_compression == :zlib_stream, large_threshold: 250, shard: [@shard_id, @shard_count], intents: @config.intents_bitmask } } send_payload(payload) @logger&.info('Sent identify', shard: @shard_id) end |
#request_guild_members(guild_id, query: '', limit: 0, presences: false, user_ids: nil, nonce: nil) ⇒ void
This method returns an undefined value.
Request guild members (chunking)
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 197 def request_guild_members(guild_id, query: '', limit: 0, presences: false, user_ids: nil, nonce: nil) payload = { op: OPCODES[:request_guild_members], d: { guild_id: guild_id, query: query, limit: limit, presences: presences, user_ids: user_ids, nonce: nonce }.compact } send_payload(payload) end |
#restore_session_state(session_id:, sequence:, resume_gateway_url: nil) ⇒ Object
213 214 215 216 217 218 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 213 def restore_session_state(session_id:, sequence:, resume_gateway_url: nil) @session_id = session_id @sequence = sequence.to_i @resume_gateway_url = resume_gateway_url if resume_gateway_url @logger&.info('Restored gateway session state', shard: @shard_id, session: @session_id, seq: @sequence) end |
#resume ⇒ void
This method returns an undefined value.
Send a resume payload
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 154 def resume return unless @session_id && @sequence > 0 payload = { op: OPCODES[:resume], d: { token: @config.token, session_id: @session_id, seq: @sequence } } send_payload(payload) @logger&.info('Sent resume', shard: @shard_id, session: @session_id, seq: @sequence) end |
#run ⇒ void
This method returns an undefined value.
Run the gateway event loop
115 116 117 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 115 def run connect.wait end |
#update_presence(status: 'online', activity: nil, afk: false) ⇒ void
This method returns an undefined value.
Update presence
175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/discord_rda/connection/gateway_client.rb', line 175 def update_presence(status: 'online', activity: nil, afk: false) payload = { op: OPCODES[:presence_update], d: { since: afk ? Time.now.to_i * 1000 : nil, activities: activity ? [activity] : [], status: status, afk: afk } } send_payload(payload) end |