Raxol.Gateway.Adapter.Discord.GatewaySocket (RaxolGateway v0.2.0)

Copy Markdown View Source

Holds one connection to the Discord Gateway (v10, JSON encoding) and hands each dispatch frame to a caller-supplied function.

This is the Discord update feed, the counterpart of Raxol.Telegram.UpdatePoller: sink-agnostic, :on_event decides what a frame means. Pair it with Raxol.Gateway.Adapter.Discord.normalize_event/1 and authorize BEFORE routing:

{:ok, conn} = Raxol.Gateway.Adapter.Discord.connect(bot_token: token)

Raxol.Gateway.Adapter.Discord.GatewaySocket.start_link(
  token: token,
  on_event: fn frame ->
    with {:ok, route, event} <- Raxol.Gateway.Adapter.Discord.normalize_event(frame),
         :allow <- Raxol.Gateway.Pairing.authorize(MyPairing, route) do
      Raxol.Gateway.SessionRouter.route(MyRouter, route, event)
    else
      :ignore -> :ok
      :deny -> Logger.info("unauthorized discord chat denied")
    end
  end
)

Options

  • :token (required) - the bot token, sent in identify/resume
  • :on_event (required) - 1-arity function called per dispatch frame (op 0), in order, with the raw string-keyed frame (%{"t" => type, "d" => data, ...}). A crash inside it is caught and logged.
  • :intents - intent bitfield (default Raxol.Gateway.Adapter.Discord.Protocol.default_intents/0; note MESSAGE_CONTENT is privileged and must also be enabled in the developer portal)
  • :gateway_url - default "wss://gateway.discord.gg"; the ?v=10&encoding=json query is appended, so pass it query-free
  • :transport / :transport_opts - the Raxol.Gateway.Adapter.Discord.GatewaySocket.Transport module (default MintTransport, which needs the optional :mint_web_socket dependency) and its options
  • :parent - optional pid receiving {:discord_socket, payload} lifecycle notifications (:ready, {:disconnected, reason}, {:reconnecting, attempt, delay})
  • :reconnect_base_ms / :reconnect_max_ms - backoff window (defaults 500 / 30_000)
  • :jitter_fn - 0-arity float source for the first-heartbeat jitter (default :rand.uniform/0); injectable so tests control when the heartbeat timer can fire
  • :name - optional registered name

Semantics

Heartbeats are client-initiated at the HELLO interval (first beat jittered per the gateway docs); a beat that is never acknowledged marks the connection a zombie and forces a reconnect. After READY the socket resumes interrupted sessions (session id + sequence + resume URL) so missed dispatches replay; an unresumable session re-identifies from scratch. Reconnects back off exponentially from :reconnect_base_ms doubling to :reconnect_max_ms, resetting once a session reaches READY/RESUMED. Frames are never logged whole - identify and resume embed the token.

Summary

Functions

Returns a specification to start this module under a supervisor.

Gracefully close the connection and stop the socket.

Current connection phase. Mostly for tests and introspection.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

close(server)

@spec close(GenServer.server()) :: :ok

Gracefully close the connection and stop the socket.

phase(server)

@spec phase(GenServer.server()) :: atom()

Current connection phase. Mostly for tests and introspection.

start_link(init_opts \\ [])