WebsockexAdapter.Client (WebsockexAdapter v0.1.1)

View Source

WebSocket client GenServer using Gun as transport layer.

Overview

The Client module is implemented as a GenServer to handle asynchronous Gun messages. Gun sends all WebSocket messages to the process that opens the connection, so the Client GenServer owns the Gun connection to receive these messages directly.

Public API

Despite being a GenServer internally, the public API returns struct-based responses for backward compatibility:

{:ok, client} = Client.connect("wss://example.com")
# client is a struct with gun_pid, stream_ref, and server_pid fields

:ok = Client.send_message(client, "hello")
Client.close(client)

Connection Ownership and Reconnection

Initial Connection

When you call connect/2, a new Client GenServer is started which:

  1. Opens a Gun connection from within the GenServer
  2. Receives all Gun messages (gun_ws, gun_up, gun_down, etc.)
  3. Returns a client struct containing the GenServer PID

Automatic Reconnection

On connection failure, the Client GenServer:

  1. Detects the failure via process monitoring
  2. Cleans up the old Gun connection
  3. Opens a new Gun connection from the same GenServer process
  4. Maintains Gun message ownership continuity
  5. Preserves the same Client GenServer PID throughout

This ensures that integrated heartbeat functionality continues to work seamlessly across reconnections without needing to track connection changes.

The Client GenServer handles all reconnection logic internally to maintain Gun message ownership throughout the connection lifecycle.

Core Functions

  • connect/2 - Establish connection
  • send_message/2 - Send messages
  • close/1 - Close connection
  • subscribe/2 - Subscribe to channels
  • get_state/1 - Get connection state

Configuration Options

The connect/2 function accepts all options from WebsockexAdapter.Config:

# Customize reconnection behavior
{:ok, client} = Client.connect("wss://example.com",
  retry_count: 5,              # Try reconnecting 5 times
  retry_delay: 2000,           # Start with 2 second delay
  max_backoff: 60_000,         # Cap backoff at 1 minute
  reconnect_on_error: true     # Auto-reconnect on errors
)

# Disable auto-reconnection for critical operations
{:ok, client} = Client.connect("wss://example.com",
  reconnect_on_error: false
)

See WebsockexAdapter.Config for all available options.

Summary

Functions

Returns a child specification for starting a Client under a supervisor.

Gets detailed metrics about the client's internal state.

Starts a Client GenServer under a supervisor.

Types

state()

@type state() :: %{
  gun_pid: pid() | nil,
  stream_ref: reference() | nil,
  state: :connecting | :connected | :disconnected,
  url: String.t() | nil,
  monitor_ref: reference() | nil
}

t()

@type t() :: %WebsockexAdapter.Client{
  gun_pid: pid() | nil,
  monitor_ref: reference() | nil,
  server_pid: pid() | nil,
  state: :connecting | :connected | :disconnected,
  stream_ref: reference() | nil,
  url: String.t() | nil
}

Functions

child_spec(init_arg)

Returns a child specification for starting a Client under a supervisor.

Examples

# In your application's supervision tree
children = [
  {WebsockexAdapter.Client, url: "wss://example.com", id: :my_client},
  # Or with full configuration
  {WebsockexAdapter.Client, [
    url: "wss://example.com",
    heartbeat_config: %{type: :deribit, interval: 30_000},
    retry_count: 10
  ]}
]

Supervisor.start_link(children, strategy: :one_for_one)

close(client)

@spec close(t()) :: :ok

connect(url_or_config, opts \\ [])

@spec connect(
  String.t() | WebsockexAdapter.Config.t(),
  keyword()
) :: {:ok, t()} | {:error, term()}

get_heartbeat_health(client)

@spec get_heartbeat_health(t()) :: map() | nil

get_state(client)

@spec get_state(t()) :: :connecting | :connected | :disconnected

get_state_metrics(client)

@spec get_state_metrics(t()) :: map() | nil

Gets detailed metrics about the client's internal state.

Returns a map containing:

  • Data structure sizes (heartbeats, subscriptions, pending requests)
  • Memory usage information
  • Process statistics

reconnect(client)

@spec reconnect(t()) :: {:ok, t()} | {:error, term()}

send_message(client, message)

@spec send_message(t(), binary()) :: :ok | {:ok, map()} | {:error, term()}

start_link(url_or_config, opts \\ [])

@spec start_link(
  String.t() | WebsockexAdapter.Config.t(),
  keyword()
) :: {:ok, pid()} | {:error, term()}

Starts a Client GenServer under a supervisor.

This function is designed to be called by a supervisor. For direct usage, prefer connect/2 which provides better error handling and connection establishment feedback.

subscribe(client, channels)

@spec subscribe(t(), list()) :: :ok | {:error, term()}