class GatewayConnection
Represents a gateway connection to Discord, which can be used to send and receive messages via a WebSocket connection.
Nested
Definitions
DISPATCH = 0
Gateway Opcodes:
ERROR_CODES = {...}
Gateway Error Codes.
Implementation
ERROR_CODES = {
4000 => "UNKNOWN_ERROR",
4001 => "UNKNOWN_OPCODE",
4002 => "DECODE_ERROR",
4003 => "NOT_AUTHENTICATED",
4004 => "AUTHENTICATION_FAILED",
4005 => "ALREADY_AUTHENTICATED",
4007 => "INVALID_SEQUENCE",
4008 => "RATE_LIMITED",
4009 => "SESSION_TIMEOUT",
4010 => "INVALID_SHARD",
4011 => "SHARDING_REQUIRED",
4012 => "INVALID_VERSION",
4013 => "INVALID_INTENT",
4014 => "DISALLOWED_INTENT"
}
DEFAULT_INTENT = Intent::GUILDS | Intent::GUILD_MESSAGES | Intent::DIRECT_MESSAGES
Default intent for a bot.
DEFAULT_PROPERTIES = {...}
Default properties for a bot.
Implementation
DEFAULT_PROPERTIES = {
os: RUBY_PLATFORM,
browser: Async::Discord.name,
device: Async::Discord.name,
}
DEFAULT_PRESENCE = {...}
Default presence for a bot.
Implementation
DEFAULT_PRESENCE = {
status: "online",
afk: false,
activities: [],
}
def initialize(...)
Initialize the gateway connection.
Implementation
def initialize(...)
super
@heartbeat_task = nil
@sequence = nil
end
def close(...)
Close the gateway connection, including the heartbeat task.
Implementation
def close(...)
if heartbeat_task = @heartbeat_task
@heartbeat_task = nil
heartbeat_task.stop
end
super
end
def identify(**identity)
Identify the bot with the given identity.
Signature
-
returns
Hash
the payload from the READY event.
Implementation
def identify(**identity)
while message = self.read
payload = message.parse
case payload[:op]
when HELLO
@heartbeat_task ||= self.run_heartbeat(payload[:d][:heartbeat_interval])
break
else
Console.warn(self, "Unexpected payload during identify: #{payload}")
end
end
identity[:intents] ||= DEFAULT_INTENT
identity[:properties] ||= DEFAULT_PROPERTIES
identity[:presence] ||= DEFAULT_PRESENCE
Console.debug(self, "Identifying...", identity: identity)
::Protocol::WebSocket::TextMessage.generate(op: IDENTIFY, d: identity).send(self)
while message = self.read
payload = message.parse
if payload[:op] == DISPATCH && payload[:t] == "READY"
Console.info(self, "Identified successfully.")
# Store the sequence number for future heartbeats:
@sequence = payload[:s]
return payload[:d]
elsif payload[:op] == INVALID_SESSION
Console.warn(self, "Invalid session.")
break
else
Console.warn(self, "Unexpected payload during identify: #{payload}")
end
end
end
def listen
Listen for events from the gateway.
Signature
-
yields
{|payload| ...}
-
parameter
payload
Hash
The parsed payload.
-
parameter
Implementation
def listen
while message = self.read
payload = message.parse
case payload[:op]
when DISPATCH
@sequence = payload[:s]
yield payload
when HEARTBEAT
Console.debug(self, "Received heartbeat request.", payload: payload)
heartbeat_message = ::Protocol::WebSocket::TextMessage.generate(op: HEARTBEAT_ACK, d: @sequence)
heartbeat_message.send(self)
when HEARTBEAT_ACK
Console.debug(self, "Received heartbeat ACK.", payload: payload)
else
yield payload
end
end
end
def run_heartbeat(duration_ms)
Run a heartbeat task at the given interval.
Implementation
def run_heartbeat(duration_ms)
duration = duration_ms / 1000.0
Console.debug(self, "Running heartbeat every #{duration} seconds.")
Async do |task|
sleep(duration * rand)
while !self.closed?
Console.debug(self, "Sending heartbeat.", sequence: @sequence)
heartbeat_message = ::Protocol::WebSocket::TextMessage.generate(op: HEARTBEAT, d: @sequence)
heartbeat_message.send(self)
self.flush
sleep(duration)
end
end
end