Class: Discordrb::Gateway
- Inherits:
-
Object
- Object
- Discordrb::Gateway
- Defined in:
- lib/discordrb/gateway.rb
Overview
Client for the Discord gateway protocol
Constant Summary collapse
- LARGE_THRESHOLD =
How many members there need to be in a server for it to count as "large"
100
- GATEWAY_VERSION =
The version of the gateway that's supposed to be used.
6
Instance Method Summary collapse
-
#heartbeat ⇒ Object
Sends a heartbeat with the last received packet's seq (to acknowledge that we have received it and all packets before it), or if none have been received yet, with 0.
-
#identify ⇒ Object
Identifies to Discord with the default parameters.
-
#initialize(bot, token) ⇒ Gateway
constructor
A new instance of Gateway.
-
#inject_error(e) ⇒ Object
Injects a terminal gateway error into the handler.
-
#inject_reconnect(url = nil) ⇒ Object
Injects a reconnect event (op 7) into the event processor, causing Discord to reconnect to the given gateway URL.
-
#inject_resume(seq) ⇒ Object
Injects a resume packet (op 6) into the gateway.
-
#kill ⇒ Object
Kills the websocket thread, stopping all connections to Discord.
-
#notify_ready ⇒ Object
Notifies the #run_async method that everything is ready and the caller can now continue (i.e. with syncing, or with doing processing and then syncing).
-
#open? ⇒ Boolean
Whether the WebSocket connection to the gateway is currently open.
-
#resume ⇒ Object
Resumes the session from the last recorded point.
-
#run_async ⇒ Object
Connect to the gateway server in a separate thread.
-
#send_heartbeat(sequence) ⇒ Object
Sends a heartbeat packet (op 1).
-
#send_identify(token, properties, compress, large_threshold) ⇒ Object
Sends an identify packet (op 2).
-
#send_request_members(server_id, query, limit) ⇒ Object
Sends a request members packet (op 8).
-
#send_resume(token, session_id, seq) ⇒ Object
Sends a resume packet (op 6).
-
#send_status_update(status, since, game, afk) ⇒ Object
Sends a status update packet (op 3).
-
#send_voice_state_update(server_id, channel_id, self_mute, self_deaf) ⇒ Object
Sends a voice state update packet (op 4).
-
#stop(no_sync = false) ⇒ Object
Stops the bot gracefully, disconnecting the websocket without immediately killing the thread.
-
#sync ⇒ Object
Prevents all further execution until the websocket thread stops (e. g. through a closed connection).
Constructor Details
#initialize(bot, token) ⇒ Gateway
Returns a new instance of Gateway.
131 132 133 134 135 136 137 138 139 |
# File 'lib/discordrb/gateway.rb', line 131 def initialize(bot, token) @token = token @bot = bot @getc_mutex = Mutex.new # Whether the connection to the gateway has succeeded yet @ws_success = false end |
Instance Method Details
#heartbeat ⇒ Object
Sends a heartbeat with the last received packet's seq (to acknowledge that we have received it and all packets before it), or if none have been received yet, with 0.
215 216 217 |
# File 'lib/discordrb/gateway.rb', line 215 def heartbeat send_heartbeat(@session ? @session.sequence : 0) end |
#identify ⇒ Object
Identifies to Discord with the default parameters.
228 229 230 231 232 233 234 235 236 |
# File 'lib/discordrb/gateway.rb', line 228 def identify send_identify(@token, { :'$os' => RUBY_PLATFORM, :'$browser' => 'discordrb', :'$device' => 'discordrb', :'$referrer' => '', :'$referring_domain' => '' }, true, 100) end |
#inject_error(e) ⇒ Object
Injects a terminal gateway error into the handler. Useful for testing the reconnect logic.
208 209 210 |
# File 'lib/discordrb/gateway.rb', line 208 def inject_error(e) handle_internal_close(e) end |
#inject_reconnect(url = nil) ⇒ Object
Injects a reconnect event (op 7) into the event processor, causing Discord to reconnect to the given gateway URL. If the URL is set to nil, it will reconnect and get an entirely new gateway URL. This method has not much use outside of testing and implementing highly custom reconnect logic.
188 189 190 191 192 193 194 195 196 |
# File 'lib/discordrb/gateway.rb', line 188 def inject_reconnect(url = nil) # When no URL is specified, the data should be nil, as is the case with Discord-sent packets. data = url ? { url: url } : nil ({ op: Opcodes::RECONNECT, d: data }.to_json) end |
#inject_resume(seq) ⇒ Object
Injects a resume packet (op 6) into the gateway. If this is done with a running connection, it will cause an error. It has no use outside of testing stuff that I know of, but if you want to use it anyway for some reason, here it is.
202 203 204 |
# File 'lib/discordrb/gateway.rb', line 202 def inject_resume(seq) send_resume(raw_token, @session_id, seq || @sequence) end |
#kill ⇒ Object
Kills the websocket thread, stopping all connections to Discord.
174 175 176 |
# File 'lib/discordrb/gateway.rb', line 174 def kill @ws_thread.kill end |
#notify_ready ⇒ Object
Notifies the #run_async method that everything is ready and the caller can now continue (i.e. with syncing, or with doing processing and then syncing)
180 181 182 |
# File 'lib/discordrb/gateway.rb', line 180 def notify_ready @ws_success = true end |
#open? ⇒ Boolean
Whether the WebSocket connection to the gateway is currently open
160 161 162 |
# File 'lib/discordrb/gateway.rb', line 160 def open? @handshake && @handshake.finished? && !@closed end |
#resume ⇒ Object
Resumes the session from the last recorded point.
304 305 306 |
# File 'lib/discordrb/gateway.rb', line 304 def resume send_resume(@token, @session.session_id, @session.sequence) end |
#run_async ⇒ Object
Connect to the gateway server in a separate thread
142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/discordrb/gateway.rb', line 142 def run_async @ws_thread = Thread.new do Thread.current[:discordrb_name] = 'websocket' connect_loop LOGGER.warn('The WS loop exited! Not sure if this is a good thing') end LOGGER.debug('WS thread created! Now waiting for confirmation that everything worked') sleep(0.5) until @ws_success LOGGER.debug('Confirmation received! Exiting run.') end |
#send_heartbeat(sequence) ⇒ Object
Sends a heartbeat packet (op 1). This tells Discord that the current connection is still active and that the last packets until the given sequence have been processed (in case of a resume).
222 223 224 |
# File 'lib/discordrb/gateway.rb', line 222 def send_heartbeat(sequence) send_packet(Opcodes::HEARTBEAT, sequence) end |
#send_identify(token, properties, compress, large_threshold) ⇒ Object
Sends an identify packet (op 2). This starts a new session on the current connection and tells Discord who we are. This can only be done once a connection.
254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/discordrb/gateway.rb', line 254 def send_identify(token, properties, compress, large_threshold) data = { # Don't send a v anymore as it's entirely determined by the URL now token: token, properties: properties, compress: compress, large_threshold: large_threshold } send_packet(Opcodes::IDENTIFY, data) end |
#send_request_members(server_id, query, limit) ⇒ Object
Sends a request members packet (op 8). This will order Discord to gradually sent all requested members as dispatch
events with type GUILD_MEMBERS_CHUNK
. It is necessary to use this method in order to get all members of a large
server (see large_threshold
in #send_identify), however it can also be used for other purposes.
335 336 337 338 339 340 341 342 343 |
# File 'lib/discordrb/gateway.rb', line 335 def send_request_members(server_id, query, limit) data = { guild_id: server_id, query: query, limit: limit } send_packet(Opcodes::REQUEST_MEMBERS, data) end |
#send_resume(token, session_id, seq) ⇒ Object
Sends a resume packet (op 6). This replays all events from a previous point specified by its packet sequence. This will not work if the packet to resume from has already been acknowledged using a heartbeat, or if the session ID belongs to a now invalid session.
If this packet is sent at the beginning of a connection, it will act similarly to an #identify in that it creates a session on the current connection. Unlike identify however, this packet can also be sent in an existing session and will just replay some of the events.
318 319 320 321 322 323 324 325 326 |
# File 'lib/discordrb/gateway.rb', line 318 def send_resume(token, session_id, seq) data = { token: token, session_id: session_id, seq: seq } send_packet(Opcodes::RESUME, data) end |
#send_status_update(status, since, game, afk) ⇒ Object
Sends a status update packet (op 3). This sets the bot user's status (online/idle/...) and game playing/streaming.
273 274 275 276 277 278 279 280 281 282 |
# File 'lib/discordrb/gateway.rb', line 273 def send_status_update(status, since, game, afk) data = { status: status, since: since, game: game, afk: afk } send_packet(Opcodes::PRESENCE, data) end |
#send_voice_state_update(server_id, channel_id, self_mute, self_deaf) ⇒ Object
Sends a voice state update packet (op 4). This packet can connect a user to a voice channel, update self mute/deaf status in an existing voice connection, move the user to a new voice channel on the same server or disconnect an existing voice connection.
291 292 293 294 295 296 297 298 299 300 |
# File 'lib/discordrb/gateway.rb', line 291 def send_voice_state_update(server_id, channel_id, self_mute, self_deaf) data = { guild_id: server_id, channel_id: channel_id, self_mute: self_mute, self_deaf: self_deaf } send_packet(Opcodes::VOICE_STATE, data) end |
#stop(no_sync = false) ⇒ Object
Stops the bot gracefully, disconnecting the websocket without immediately killing the thread. This means that Discord is immediately aware of the closed connection and makes the bot appear offline instantly.
If this method doesn't work or you're looking for something more drastic, use #kill instead.
168 169 170 171 |
# File 'lib/discordrb/gateway.rb', line 168 def stop(no_sync = false) @should_reconnect = false close(no_sync) end |
#sync ⇒ Object
Prevents all further execution until the websocket thread stops (e. g. through a closed connection).
155 156 157 |
# File 'lib/discordrb/gateway.rb', line 155 def sync @ws_thread.join end |