NAME

Discord::Client::Gateway - Discord Gateway connections and events

SYNOPSIS

use Discord::Client::Gateway;

# Configure the connection.
my $gateway = Discord::Client::Gateway->new(
    token => $ENV{DISCORD_BOT_TOKEN}, loop => $loop, intents => ['GUILDS'],
);

# Return asynchronous work from the event handler.
$gateway->on(MESSAGE_CREATE => sub {
    my ($data, $gateway, $packet) = @_;
    return handle_message($data);
});

# Start on the application's loop.
my $ready = $gateway->connect;

DESCRIPTION

Receives Discord v10 JSON events and manages the WebSocket connection, heartbeats, Resume and reconnects. Use it independently or through Discord::Client. The caller drives the loop. Standalone Gateway intents default to zero.

METHODS

new

new(token => $token, loop => $loop, intents => ['GUILDS']) returns a Gateway without I/O. loop is optional; otherwise one is created. Intents accept a bitmask or arrayref of names. Set intents for the events you need. rest and identify_limiter can inject caller-owned discovery resources. shard => [$id, $total] selects a shard.

connect

Discovers /gateway/bot, opens a verified TLS WebSocket and returns a Future resolving to the Gateway on READY or RESUMED. During reconnects, it waits for the next ready session. Cancelling it closes the Gateway.

completion

Returns the lifetime Future, resolving on orderly shutdown and failing on fatal errors.

close

Returns a Future waiting for transport shutdown. Cancels timers, writes and handlers. Repeated calls return the same Future. Injected REST clients and Identify limiters remain caller-owned.

on

on(EVENT => CODE) registers an event callback and returns the Gateway. Callbacks and failure handling are described under "EVENTS AND FAILURES".

send

send(opcode, data) returns a Future completing after the write, only while ready. Heartbeat, Identify and Resume are driver-managed. Payloads must fit 4096 bytes. The SDK limits traffic to 120 payloads per 60 seconds and reserves capacity for protocol traffic.

Cancelling removes an unsent write. Cancelling an active write resets the connection because delivery is uncertain. Application writes are not replayed.

state

Returns the connection state string.

loop

Returns the IO::Async::Loop.

session

Returns the internal protocol object. Use events for application work.

identify_limiter

Returns the internal Identify scheduler. Its API is not a public contract.

stats

Returns a hashref of counters, queue sizes and heartbeat latency.

EVENTS AND FAILURES

Event names are uppercase. Callbacks receive ($data, $gateway, $packet). on('*' => CODE) receives ($event, $data, $gateway, $packet). Unknown events and fields are preserved; unknown opcodes produce OPCODE with {op, d}.

Return handler Futures. Pending Futures do not delay heartbeats or incoming packets, but blocking Perl code blocks the loop. Thrown exceptions and failed Futures produce handler errors without stopping the connection.

on_error => CODE receives ($error, $gateway) synchronously. Without it, the SDK warns with a generic message. Errors omit raw frames, exceptions and credentials. Fatal close codes appear in close_code and stop reconnecting.

When the callback queue is full, the incoming event's application callbacks are dropped. Through Discord::Client, SDK cache and READY state updates and interaction dispatch occur before this queue and are preserved. Interaction dispatch still has its own bounded capacity. A queue_full error is reported once per saturation episode; stats counts all dropped_events and dropped_callbacks. Earlier work continues. Dropped events are not replayed; applications needing a complete stream must reconcile state. Each callback invocation uses capacity, even with a shared Future.

RECONNECTS AND IDENTIFY

The SDK schedules heartbeats from HELLO and reconnects if ACK is missing. Resume uses the saved URL, session ID and sequence. Non-resumable sessions Identify again; fatal close codes stop the driver. Reconnects use jittered backoff, reset after stable operation. Opcode 7 starts the first Resume attempt immediately. Compression is not requested.

shard => [$id, $total] selects a shard. Identify uses session-start metadata from /gateway/bot and a five-second cooldown per concurrency bucket. The cooldown starts when Identify is sent. Resume consumes no session start. Exhausted budgets wait for reset and refresh metadata. An exhausted budget with zero reset_after refreshes every second until starts or a positive delay become available. Heartbeats continue during Identify waits.

For several shards, use the shard manager. Identify coordination is local to one process; separate processes need external coordination.

OPTIONS

max_outgoing

Queued and active writes; default 128.

max_events

Queued callback invocations; default 1024.

max_handlers

Pending callback invocations; default 64.

connect_timeout

Seconds for connection/HELLO or sent authentication; default 30.

backoff_base

Initial backoff in seconds; default 1.

backoff_max

Maximum backoff in seconds; default 60.

stable_after

Seconds before resetting backoff; default 60.

Identify waiting is excluded from the authentication timeout. stats returns counters, queue sizes and heartbeat latency. on_diagnostic receives synchronous events with state and reconnect timing, without raw payloads.

TRANSPORT INJECTION

websocket_factory receives loop, on_text and on_close. Its transport provides Future-returning connect($url), send($unicode_json), abort and close($code). Resolve connection before delivering text. abort stops I/O; close waits for cleanup. on_close supplies a numeric code without raw reason text. Pathless Gateway URLs use / for the handshake.

clock, delay, defer and random hooks allow deterministic tests. websocket_options => {tls => {...}} can supply a local test CA; peer and hostname verification remain enabled. The adapter accepts frames up to 16 MiB.

LICENSE

Apache License 2.0.