glyde/rest/route
A route is the rate-limit identity of a call. glyde/rest/seg is the only
way to build one: alongside the path from typed segments, or read back out
of a path string with seg.from_path. Both walk the same segment rules, so
two spellings of one endpoint cannot land in two buckets.
Types
Discord’s major parameters. Two channels have independent buckets for the same endpoint; two messages in the same channel do not.
pub type Major {
NoMajor
ChannelMajor(String)
GuildMajor(String)
WebhookMajor(id: String, token: WebhookToken)
}
Constructors
-
NoMajor -
ChannelMajor(String) -
GuildMajor(String) -
WebhookMajor(id: String, token: WebhookToken)Id and token together. The token is absent on the
GET /webhooks/{webhook.id}form, where Discord takes the id alone.
Opaque because class is derived from template. A record update could
move one and leave the other, and a route that wrongly claims to be an
interaction callback skips the global limit.
pub opaque type Route
Discord’s undocumented per-resource sublimits. Invisible in the headers:
a 429 with a large retry_after on a bucket that still claims capacity.
pub type Sublimit {
NoSublimit
Named(String)
Aged(created_at_ms: Int)
}
Constructors
-
NoSublimit -
Named(String)A named subset of an endpoint: “name-or-topic” on
PATCH /channels/{id}is 2 per 10 minutes. -
Aged(created_at_ms: Int)Deleting a message older than two weeks lands in a different bucket (discord-api-docs#1295). The limiter has the clock, so it resolves this.
A live credential that is also half a major parameter. A closure, not a
field, because echo and string.inspect read straight through an opaque
record. Reaching the bucket key is the one thing it still has to do, so
key and major_key return the token in plain text and everything else
does not.
pub opaque type WebhookToken
Values
pub const channel_placeholder: String
pub const guild_placeholder: String
pub const id_placeholder: String
Any id that is not a major parameter. Discord buckets these together, so they need no name of their own.
pub fn key(route: Route, now_ms now_ms: Int) -> String
The provisional bucket key, until x-ratelimit-bucket names the real one.
Holds the webhook token on a webhook route, so keep it out of logs.
pub fn major_key(route: Route) -> String
The major half of the key, to pair with Discord’s x-ratelimit-bucket
hash. Holds the webhook token on a webhook route, so keep it out of logs.
pub fn method(route: Route) -> http.Method
pub fn new(
method: http.Method,
template: String,
major: Major,
sublimit: Sublimit,
) -> Route
Every route goes through here, so the one endpoint Discord exempts from the global limit is recognised in a single place.
pub const opaque_placeholder: String
Text that is neither an id nor a literal: an interaction token, an invite code.
pub const reaction_placeholder: String
A reaction emoji and everything after it.
pub fn route_key(route: Route, now_ms now_ms: Int) -> String
The route half of the key. Discord reports one hash per route and the real bucket is that hash paired with the major parameter, so both halves exist.
pub fn same_major(one: Major, other: Major) -> Bool
Whether two majors name the same bucket. Major holds a closure, and
comparing closures with == does not answer this question.
pub fn template(route: Route) -> String
The unsubstituted template, e.g. “/channels/{channel.id}/messages”.
pub fn unbound(route: Route) -> Bool
Exempt from the global limit and in no bucket. True for interaction callbacks and nothing else.
pub const webhook_placeholder: String
pub fn webhook_token(
token: option.Option(String),
) -> WebhookToken
None is the tokenless GET /webhooks/{webhook.id} form.
pub const webhook_token_placeholder: String
Half of a webhook’s major parameter, which has no business in a template.