glyde/gateway/close
Gateway close codes and what to do about them.
Main gateway only. Voice reuses the numbers for other things: voice 4014 is a disconnected call, gateway 4014 is a bot that must never reconnect.
A close we send has no disposition here. The decision was made before the
frame went out, and it travels as an Intent: code picks the number,
intent_keeps_session says what we still hold. from_gateway answers only
for closes we did not choose, and the echo of our own close never reaches
it, because the state machine has already moved on from that connection.
Types
A close code Discord can send. Every number this module reasons about is
named here, so parse is the only table of numbers and everything else
matches on the name.
pub type CloseCode {
NormalClosure
GoingAway
NoStatusReceived
AbnormalClosure
ServiceRestart
UnknownError
UnknownOpcode
DecodeError
NotAuthenticated
AlreadyAuthenticated
InvalidSeq
RateLimited
SessionTimedOut
Unfixable(reason: Reason)
UnknownCode(code: Int)
}
Constructors
-
NormalClosureFrom Discord this still leaves the session resumable. The rule that 1000 ends a session is about closes we send.
-
GoingAway -
NoStatusReceivedThe peer closed with no code in the frame.
-
AbnormalClosureThe socket died without a close frame.
-
ServiceRestart -
UnknownError -
UnknownOpcode -
DecodeErrorWe sent something Discord could not read.
-
NotAuthenticatedA command before IDENTIFY, or a session Discord has invalidated.
-
AlreadyAuthenticatedA second IDENTIFY on one connection.
-
InvalidSeq -
RateLimitedWe flooded the command budget.
-
SessionTimedOut -
Unfixable(reason: Reason)A code no reconnect can fix. The fatal set lives in one variant so the same six numbers cannot be listed twice and drift apart.
-
UnknownCode(code: Int)Not a gateway code, including anything Discord adds after this list.
What to do next.
pub type Disposition {
ReconnectResume
ReconnectThrottled
ReconnectFresh
Fatal(Reason)
}
Constructors
-
ReconnectResumeOpen a new connection and resume. Missed events get replayed.
-
ReconnectThrottledResume, but wait before redialling and throw the queued commands away. Discord closes a command flood with 4008, and redialling straight into the same backlog earns the next one.
-
ReconnectFreshOpen a new connection and identify from scratch. The session is gone, so a resume would only earn an INVALID_SESSION.
-
Fatal(Reason)Stop. Reconnecting cannot fix this.
What we mean to happen when we close the connection ourselves.
pub type Intent {
Reconnect
FreshIdentify
Terminal
}
Constructors
-
ReconnectDrop this socket, keep the session, resume on the next one.
-
FreshIdentifyDrop the session too and identify from scratch.
-
TerminalShut down for good.
Why the connection can never succeed as configured.
pub type Reason {
BadToken
InvalidShard
ShardingRequired
InvalidApiVersion
InvalidIntents
DisallowedIntents
}
Constructors
-
BadTokenThe bot token is wrong.
-
InvalidShardThe shard id or shard count in IDENTIFY was invalid.
-
ShardingRequiredToo many guilds for one connection. The bot has to shard.
-
InvalidApiVersionThe gateway version in the URL is not supported.
-
InvalidIntentsThe intents bitfield contained a bit Discord does not recognise.
-
DisallowedIntentsThe intents included a privileged one that is not enabled for this application. Enable it in the developer portal.
Values
pub fn code(intent: Intent) -> Int
The code to send for an intent. 1000 tells Discord the session is over and marks the bot offline; anything else leaves it resumable, and 4000 reads as “unknown error”.
pub fn describe(code: CloseCode) -> String
Discord’s name for a code, for logs and error messages.
pub fn from_gateway(code: option.Option(Int)) -> Disposition
Decide what to do about a connection Discord closed. None is a transport
that died with no close frame, which Discord documents as resumable.
Resume by default. A wrong resume costs one INVALID_SESSION round trip, a wrong identify spends from a budget of 1000 a day.
pub fn intent_keeps_session(intent: Intent) -> Bool
Whether we still hold a session after closing with this intent. Not a
property of the code: FreshIdentify sends a code Discord would let us
resume with and throws the session away anyway.
pub fn parse(code: Int) -> CloseCode
Classify a raw close code. The only place a close number is written down.
pub fn session_survives(disposition: Disposition) -> Bool
Whether a close leaves the session usable, for a caller that only wants to know “can I resume”.