View Source Fresh behaviour (Fresh v0.3.0)

Callback behaviours and functions for WebSocket client.

Summary

Types

Represents the response for all connection handle callback.

Represents control frames in a WebSocket connection.

Represents data frames in a WebSocket connection.

Represents various error scenarios that can occur during WebSocket communication.

Represents the response of a generic callback and enables you to manage state.

Represents optional configurations for WebSocket configuration.

Represents the state of the given module, which can be anything.

Callbacks

Callback is invoked when a WebSocket connection is successfully established.

Callback is invoked when a control frame is received from the server.

Callback is invoked when the WebSocket connection is being disconnected.

Callback is invoked when an error occurs, allows you to define custom error handling logic to handle various scenarios gracefully.

Callback is invoked when a data frame is received from the server.

Callback is invoked when an incomprehensible message is received.

Callback is invoked when the process is about to terminate.

Functions

This macro simplifies the implementation of WebSocket client. It automatically configures child_spec/1, start/1 and start_link/1 for the module, and provides empty handlers for all required callbacks, which can be overridden.

Sends a WebSocket close frame to the server.

Sends a WebSocket frame to the server.

Starts a WebSocket connection without linking process. Refer to start_link/4 for more information.

Starts a WebSocket connection.

Types

Link to this type

connection_handle_response()

View Source
@type connection_handle_response() ::
  {:ignore, state()}
  | {:reconnect, state()}
  | {:close, term()}
  | :reconnect
  | :close

Represents the response for all connection handle callback.

  • {:ignore, state}: Indicates an intent to ignore and continue.

    Example: {:ignore, state}

  • {:reconnect, state}: Indicates an intent to reconnect, with given state.

    Example: {:reconnect, 0}

  • {:close, reason}: Indicates an intent to close connection, with custom reason. Can be used to force Supervisor to restart process.

    Example: {:close, {:error, :unknown}}

  • :reconnect: Indicates an intent to reconnect, with initial state.

  • :close: Indicates an intent to close connection normally.

@type control_frame() :: {:ping, binary()} | {:pong, binary()}

Represents control frames in a WebSocket connection.

@type data_frame() :: {:text, String.t()} | {:binary, binary()}

Represents data frames in a WebSocket connection.

@type error() ::
  {:connecting_failed, Mint.Types.error()}
  | {:upgrading_failed, Mint.WebSocket.error()}
  | {:streaming_failed, Mint.Types.error()}
  | {:establishing_failed, Mint.WebSocket.error()}
  | {:processing_failed, term()}
  | {:decoding_failed, any()}
  | {:encoding_failed, any()}
  | {:casting_failed, Mint.WebSocket.error()}

Represents various error scenarios that can occur during WebSocket communication.

Link to this type

generic_handle_response()

View Source
@type generic_handle_response() ::
  {:ok, state()}
  | {:reply, [Mint.WebSocket.frame()], state()}
  | {:close, non_neg_integer(), binary(), state()}

Represents the response of a generic callback and enables you to manage state.

  • {:ok, state}: Indicates a successful operation.

    Examples: {:ok, state + 1}, {:ok, state}

  • {:reply, frames, state}: Denotes a successful operation with a list of WebSocket frames sent as a reply to the server.

    Example: {:reply, [{:text, "Bousou"}, {:text, "暴走"}], state}

  • {:close, code, reason, state}: Signifies the closure of the connection with a non-negative integer code and a binary reason.

    Example: {:close, 1000, "Normal Closure", state} - Normal closure with a reason and no state change.

@type option() ::
  {:name, :gen_statem.server_name()}
  | {:headers, Mint.Types.headers()}
  | {:transport_opts, keyword()}
  | {:mint_upgrade_opts, keyword()}
  | {:ping_interval, non_neg_integer()}
  | {:error_logging, boolean()}
  | {:info_logging, boolean()}

Represents optional configurations for WebSocket configuration.

  • :name: Registers a name for the WebSocket connection, allowing you to refer to it later using a name.

    Example: {:local, Example.WebSocket}

  • :headers: A list of headers to include in the WebSocket connection request. These headers will be sent during the connection upgrade.

    Example: {:headers, [{"Authorization", "Bearer token"}]}

  • :transport_opts: Additional options to pass to the transport layer used for the WebSocket connection. Consult the Mint.HTTP documentation for more informations.

    Example: {:transport_opts, [cacertfile: "/my/file"]}

  • :mint_upgrade_opts: Extra options to provide to Mint.WebSocket during the WebSocket upgrade process. Consult the Mint.WebSocket documentation for additional information.

    Example: {:mint_upgrade_opts, [extensions: [Mint.WebSocket.PerMessageDeflate]]}

  • :ping_interval: This option is used to keep connection alive by sending empty ping frames based on given time as milliseconds. By default it is set to 30000. To disable it, set it to 0.

    Example: {:ping_interval, 60_000}

  • :error_logging: Allows you to toggle logging for error/0 error(s). Enabled by default.

    Example: {:error_logging, false}

  • :info_logging: Allows you to toggle logging information message(s). Enabled by default.

    Example: {:info_logging, false}

@type state() :: any()

Represents the state of the given module, which can be anything.

Callbacks

Link to this callback

handle_connect(status, headers, state)

View Source
@callback handle_connect(status, headers, state()) :: generic_handle_response()
when status: Mint.Types.status(), headers: Mint.Types.headers()

Callback is invoked when a WebSocket connection is successfully established.

  • status: The status received during the connection upgrade.

  • headers: The headers received during the connection upgrade.

    Example: [{"upgrade", "websocket"}, {"connection", "upgrade"}]

  • state: The current state of the module.

Example

def handle_connect(_status, _headers, state) do
  payload = "{ \"op\": 1, \"data\": {} }"
  {:reply, [{:text, payload}], state}
end
Link to this callback

handle_control(frame, state)

View Source
@callback handle_control(frame :: control_frame(), state()) :: generic_handle_response()

Callback is invoked when a control frame is received from the server.

  • frame: The received WebSocket frame.
  • state: The current state of the module.

Example

def handle_control({:ping, message}, state) do
  IO.puts("Received ping with content: #{message}!")
  {:ok, state}
end

def handle_control({:pong, message}, state) do
  IO.puts("Received pong with content: #{message}!")
  {:ok, state}
end
Link to this callback

handle_disconnect(code, reason, state)

View Source
@callback handle_disconnect(code, reason, state()) :: connection_handle_response()
when code: non_neg_integer() | nil, reason: binary() | nil

Callback is invoked when the WebSocket connection is being disconnected.

  • code: The disconnection code (if available).

    Example: 1002

  • reason: The reason for the disconnection (if available).

    Example: "timeout"

  • state: The current state of the module.

Example

def handle_disconnect(1002, _reason, _state), do: :reconnect
def handle_disconnect(_code, _reason, _state), do: :close
Link to this callback

handle_error(error, state)

View Source
@callback handle_error(error(), state()) :: connection_handle_response()

Callback is invoked when an error occurs, allows you to define custom error handling logic to handle various scenarios gracefully.

  • error: The encountered error.
  • state: The current state of the module.

Example

def handle_error({error, _reason}, state)
    when error in [:encoding_failed, :casting_failed],
    do: {:ignore, state}

def handle_error(_error, _state), do: :reconnect
@callback handle_in(frame :: data_frame(), state()) :: generic_handle_response()

Callback is invoked when a data frame is received from the server.

  • frame: The received WebSocket frame.
  • state: The current state of the module.

Example

def handle_in({:text, message}, state) do
  %{"data" => updated_data} = Jason.decode!(message)
  {:ok, updated_data}
end

def handle_in({:binary, _message}, state) do
  {:reply, [{:text, "i don't accept binary!"}], state}
end
Link to this callback

handle_info(data, state)

View Source
@callback handle_info(data :: any(), state()) :: generic_handle_response()

Callback is invoked when an incomprehensible message is received.

  • data: The received message.
  • state: The current state of the module.

Example

def handle_info({:reply, message}, state) do
  {:reply, [{:text, message}], state}
end

Can be used like:

send(:ws_conn, {:reply, "hello!"})
Link to this callback

handle_terminate(reason, state)

View Source (since 0.2.0)
@callback handle_terminate(reason :: any(), state()) :: ignored :: any()

Callback is invoked when the process is about to terminate.

  • reason: The reason for the termination.

    Example: :normal, :shutdown, {:error, :unknown_data}

  • state: The current state of the module.

Return value is always ignored.

Example

def handle_terminate(reason, _state) do
  IO.puts("Process is terminating with reason: #{inspect(reason)}")
end

Functions

Link to this macro

__using__(opts)

View Source (macro)

This macro simplifies the implementation of WebSocket client. It automatically configures child_spec/1, start/1 and start_link/1 for the module, and provides empty handlers for all required callbacks, which can be overridden.

Starting the WebSocket client using start_link/1 with the desired options:

iex> Example.WebSocket.start_link(uri: "wss://example.com/socket", state: %{}, opts: [
iex>   name: {:local, :ws_conn}
iex> ])
{:ok, #PID<0.233.0>}

Starting the WebSocket client using Supervisor (recommended):

children = [
  {Example.WebSocket,
   uri: "wss://example.com/socket",
   state: %{},
   opts: [
     name: {:local, :ws_conn}
   ]}
  # Add other child specifications...
]

Supervisor.start_link(children, strategy: :one_for_one)
Link to this function

close(pid, code, reason)

View Source (since 0.2.1)
@spec close(:gen_statem.server_ref(), non_neg_integer(), binary()) :: :ok

Sends a WebSocket close frame to the server.

  • pid: The WebSocket connection process.

  • code: WebSocket close code.

    Example: 1000

  • reason: WebSocket close reason.

    Example: "dunno"

Example

iex> Fresh.close(:ws_conn, 1000, "dunno")
:ok

Sends a WebSocket frame to the server.

  • pid: The WebSocket connection process.

  • frame: The WebSocket frame to send.

    Example: {:text, "hi!"}

Example

iex> Fresh.send(:ws_conn, {:text, "hi!"})
:ok
Link to this function

start(uri, module, state, opts)

View Source
@spec start(binary(), module(), any(), [option()]) :: :gen_statem.start_ret()

Starts a WebSocket connection without linking process. Refer to start_link/4 for more information.

Link to this function

start_link(uri, module, state, opts)

View Source
@spec start_link(binary(), module(), any(), [option()]) :: :gen_statem.start_ret()

Starts a WebSocket connection.

  • uri: The URI to connect to.

    Example: "wss://example.com/socket"

  • module: The module that implementes the WebSocket client behaviour.

    Example: Example.WebSocket

  • state: The initial state to be passed to the module when it starts.

    Example: %{}

  • opts: A list of options to configure the WebSocket connection. Refer to option/0 for available options.

    Example: [name: {:local, :ws_conn}, headers: [{"Authorization", "Bearer token"}]]

Example

iex> Fresh.start_link("wss://example.com/socket", Example.WebSocket, %{}, name: {:local, :ws_conn})
{:ok, #PID<0.233.0>}