phoenix_gen_socket_client v4.0.0 Phoenix.Channels.GenSocketClient behaviour View Source

Communication with a Phoenix Channels server.

This module powers a process which can connect to a Phoenix Channels server and exchange messages with it. Currently, only websocket communication protocol is supported.

The module is implemented as a behaviour. To use it, you need to implement the callback module. Then, you can invoke start_link/5 to start the socket process. The communication with the server is then controlled from that process.

The connection is not automatically established during the creation. Instead, the implementation can return {:connect, state} to try to establish the connection. As the result either handle_connected/2 or handle_disconnected/2 callbacks will be invoked.

To join a topic, join/3 function can be used. Depending on the result, either handle_joined/4 or handle_join_error/4 will be invoked. A client can join multiple topics on the same socket. It is also possible to leave a topic using the leave/3 function.

Once a client has joined a topic, it can use push/4 to send messages to the server. If the server directly replies to the message, it will be handled in the handle_reply/5 callback.

If a server sends an independent message (i.e. the one which is not a direct reply), the handle_message/5 callback will be invoked.

If the server closes the channel, the handle_channel_closed/4 will be invoked. This will not close the socket connection, and the client can continue to communicate on other channels, or attempt to rejoin the channel.

Sending messages over the socket

As mentioned, you can use join/3, push/4, and leave/3 to send messages to the server. All of these functions require the transport information as the first argument. This information is available in most of the callback functions.

Functions will return {:ok, ref} if the message was sent successfully, or {:error, reason}, where ref is the Phoenix ref used to uniquely identify a message on a channel.

Error responses are returned in following situations:

  • The client is not connected
  • Attempt to send a message on a non-joined channel
  • Attempt to leave a non-joined channel
  • Attempt to join the already joined channel

Keep in mind that there's no guarantee that a message will arrive to the server. You need to implement your own communication protocol on top of Phoenix Channels to obtain such guarantees.

Process structure and lifecycle

The behaviour will internally start the websocket client in a separate child process. This means that the communication runs concurrently to any processing which takes place in the behaviour.

The socket process will crash only if the websocket process crashes, which can be caused only by some bug in the websocket client library. If you want to survive this situation, you can simply trap exits in the socket process, by calling Process.flag(:trap_exit, true) in the init/1 callback. In this case, a crash of the websocket client process will be treated as a disconnect event.

The socket process never decides to stop on its own. If you want to stop it, you can simply return {:stop, reason, state} from any of the callback.

Link to this section Summary

Functions

Makes a synchronous call to the server and waits for its reply.

Returns a specification to start this module under a supervisor.

Returns true if the socket is joined on the given topic.

Notifies the socket process that the connection has been established.

Notifies the socket process about a disconnect.

Forwards a received message to the socket process.

Pushes a message to the topic.

Can be invoked to send a response to the client.

Callbacks

Invoked to handle a synchronous call.

Invoked after the server closes a channel.

Invoked after the client has successfully connected to the server.

Invoked after the client has been disconnected from the server.

Invoked to handle an Erlang message.

Invoked if the server has refused a topic join request.

Invoked after the client has successfully joined a topic.

Invoked when a message from the server arrives.

Invoked when the server replies to a message sent by the client.

Invoked when the process is created.

Optional callback invoked when the server is about to exit. It should do any cleanup required.

Link to this section Types

Specs

callback_state() :: any()

Specs

encoded_message() :: binary()

Specs

event() :: String.t()

Specs

handler_response() ::
  {:ok, callback_state()}
  | {:connect, callback_state()}
  | {:connect, url :: String.t(), query_params(), callback_state()}
  | {:stop, reason :: any(), callback_state()}

Specs

message() :: term()

Specs

out_payload() :: %{required(String.t() | atom()) => any()}

Specs

payload() :: %{required(String.t()) => any()}

Specs

query_params() :: [{String.t(), String.t()}]

Specs

ref() :: pos_integer()

Specs

socket_opts() :: [serializer: module(), transport_opts: transport_opts()]

Specs

topic() :: String.t()

Specs

transport()

Specs

transport_opts() :: any()

Link to this section Functions

Link to this function

call(server, request, timeout \\ 5000)

View Source

Specs

call(GenServer.server(), any(), timeout()) :: any()

Makes a synchronous call to the server and waits for its reply.

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

join(transport, topic, payload \\ %{})

View Source

Specs

join(transport(), topic(), out_payload()) ::
  {:ok, ref()} | {:error, reason :: any()}

Joins the topic.

Specs

joined?(topic()) :: boolean()

Returns true if the socket is joined on the given topic.

This function should be invoked from the GenSocketClient process.

Link to this function

leave(transport, topic, payload \\ %{})

View Source

Specs

leave(transport(), topic(), out_payload()) ::
  {:ok, ref()} | {:error, reason :: any()}

Leaves the topic.

Link to this function

notify_connected(socket)

View Source

Specs

notify_connected(GenServer.server()) :: :ok

Notifies the socket process that the connection has been established.

Link to this function

notify_disconnected(socket, reason)

View Source

Specs

notify_disconnected(GenServer.server(), any()) :: :ok

Notifies the socket process about a disconnect.

Link to this function

notify_message(socket, message)

View Source

Specs

notify_message(GenServer.server(), {:text | :binary, binary()}) :: :ok

Forwards a received message to the socket process.

Link to this function

push(transport, topic, event, payload)

View Source

Specs

push(transport(), topic(), event(), out_payload()) ::
  {:ok, ref()} | {:error, reason :: any()}

Pushes a message to the topic.

Specs

reply(GenServer.from(), any()) :: :ok

Can be invoked to send a response to the client.

Link to this function

start_link(callback, transport_mod, arg, socket_opts \\ [], gen_server_opts \\ [])

View Source

Specs

start_link(
  callback :: module(),
  transport_mod :: module(),
  any(),
  socket_opts(),
  GenServer.options()
) :: GenServer.on_start()

Starts the socket process.

Link to this section Callbacks

Link to this callback

handle_call(message, arg2, transport, callback_state)

View Source

Specs

handle_call(message :: any(), GenServer.from(), transport(), callback_state()) ::
  {:reply, reply, new_state}
  | {:reply, reply, new_state, timeout() | :hibernate}
  | {:noreply, new_state}
  | {:noreply, new_state, timeout() | :hibernate}
  | {:stop, reason, reply, new_state}
  | {:stop, reason, new_state}
when new_state: callback_state(), reply: term(), reason: term()

Invoked to handle a synchronous call.

Link to this callback

handle_channel_closed(topic, payload, transport, callback_state)

View Source

Specs

handle_channel_closed(topic(), payload(), transport(), callback_state()) ::
  handler_response()

Invoked after the server closes a channel.

Link to this callback

handle_connected(transport, callback_state)

View Source

Specs

handle_connected(transport(), callback_state()) :: handler_response()

Invoked after the client has successfully connected to the server.

Link to this callback

handle_disconnected(reason, callback_state)

View Source

Specs

handle_disconnected(reason :: any(), callback_state()) :: handler_response()

Invoked after the client has been disconnected from the server.

Link to this callback

handle_info(message, transport, callback_state)

View Source

Specs

handle_info(message :: any(), transport(), callback_state()) ::
  handler_response()

Invoked to handle an Erlang message.

Link to this callback

handle_join_error(topic, payload, transport, callback_state)

View Source

Specs

handle_join_error(topic(), payload(), transport(), callback_state()) ::
  handler_response()

Invoked if the server has refused a topic join request.

Link to this callback

handle_joined(topic, payload, transport, callback_state)

View Source

Specs

handle_joined(topic(), payload(), transport(), callback_state()) ::
  handler_response()

Invoked after the client has successfully joined a topic.

Link to this callback

handle_message(topic, event, payload, transport, callback_state)

View Source

Specs

handle_message(topic(), event(), payload(), transport(), callback_state()) ::
  handler_response()

Invoked when a message from the server arrives.

Link to this callback

handle_reply(topic, ref, payload, transport, callback_state)

View Source

Specs

handle_reply(topic(), ref(), payload(), transport(), callback_state()) ::
  handler_response()

Invoked when the server replies to a message sent by the client.

Specs

init(arg :: any()) ::
  {:connect, url :: String.t(), query_params(), callback_state()}
  | {:noconnect, url :: String.t(), query_params(), callback_state()}
  | :ignore
  | {:error, reason :: any()}

Invoked when the process is created.

Link to this callback

terminate(reason, state)

View Source (optional)

Specs

terminate(reason, state :: term()) :: term()
when reason: :normal | :shutdown | {:shutdown, term()}

Optional callback invoked when the server is about to exit. It should do any cleanup required.