# `Raxol.Gateway.Adapter.Discord.GatewaySocket`
[🔗](https://github.com/DROOdotFOO/raxol/blob/raxol_gateway-v0.2.0/lib/raxol/gateway/adapter/discord/gateway_socket.ex#L1)

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.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `close`

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

Gracefully close the connection and stop the socket.

# `phase`

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

Current connection phase. Mostly for tests and introspection.

# `start_link`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
