drab v0.9.0 Drab.Presence

Conveniences for Phoenix.Presence.

Provides Phoenix Presence module for Drab, along with some helper functions.

Installation

It is disabled by default, to enable it, add :presence to config.exs.

config :drab, :presence, true

Next, add Drab.Presence to your supervision tree in lib/my_app_web.ex:

children = [
  ...
  Drab.Presence,
]

Please also ensure that there otp_app and endpoint for this app are configured correctly:

config :drab, MyAppWeb.Endpoint,
  otp_app: :my_app_web

In multiple endpoint configuration, you need to specify which endpoint to use with Drab.Presence:

config :drab, :presence, endpoint: MyAppWeb.Endpoint

Usage

When installed, system tracks the presence over every Drab topic, both static topics configured by Drab.Commander.broadcasting/1 and runtime topics run by Drab.Commander.subscribe/2. The default ID of the presence list is a browser UUID (Drab.Browser.id/1):

iex> Drab.Presence.list socket
%{
  "2bd34ffc-b365-46a9-9479-474b628364ed" => %{
    metas: [%{online_at: 1520417565, phx_ref: ...}]
  }
}

The ID may also be taken from Plug Session or from the Drab Store. For example, you have a :current_user_id stored in the session, you may want to use it as an id with id config option:

config :drab, :presence, id: [session: :current_user_id]

So this ID will become the key of the presence map:

iex> Drab.Presence.list socket
%{
  "42" => %{
    metas: [%{online_at: 1520417565, phx_ref: ...}]
  }
}

Notice that system transforms the key value to the binary string.

The similar would be with the Drab Store:

config :drab, :presence, id: [store: :current_user_id]

Example

Here we are going to show how to display number of connected users online. The solution is to broadcast every connect and disconnect using Commander’s callbacks. Thus, in the commander:

defmodule MyAppWeb.MyCommander
  use Drab.Commander
  import Drab.Presence

  broadcasting "global"
  onconnect :connected
  ondisconnect :disconnected

  def connected(socket) do
    broadcast_html socket, "#number_of_users", count_users(socket)
  end

  def disconnected(_store, _session) do
    topic = same_topic("global")
    broadcast_html topic, "#number_of_users", count_users(topic)
  end
end

Notice the difference between connected and disconnected callbacks. In the first case we could use the default topic derived from the socket, but after disconnect socket does not longer exists.

Own Presence module

You may also want to provide your own presence module, for example to override Phoenix.Presence.fetch/2 function. In this case, add your module to children list and configure Drab to run it:

config :drab, :presence, module: MyAppWeb.MyPresence

You module must provide start/2 function, which will be launched by Drab on the client connect, along with stop/2, which runs when user unsubscribe from the topic.

defmodule MyAppWeb.MyPresence do
  use Phoenix.Presence, otp_app: :my_app, pubsub_server: MyApp.PubSub

  def start(socket, topic) do
    client_id = Drab.Browser.id!(socket)
    track(socket.channel_pid, topic, client_id, %{online_at: System.system_time(:seconds)})
  end

  def stop(socket, topic) do
    client_id = Drab.Browser.id!(socket)
    untrack(socket.channel_pid, topic, client_id)
  end
end

Link to this section Summary

Functions

Returns the number of total connections to the topic

Counts the number of connected unique users or browsers

Callback implementation for Phoenix.Presence.init/1

Callback implementation for Phoenix.Presence.list/1

Callback implementation for Phoenix.Presence.untrack/2

Link to this section Functions

Link to this function count_connections(topic)
count_connections(Phoenix.Socket.t() | String.t()) :: integer()

Returns the number of total connections to the topic.

Link to this function count_users(topic)
count_users(Phoenix.Socket.t() | String.t()) :: integer()

Counts the number of connected unique users or browsers.

Link to this function fetch(topic, presences)

Callback implementation for Phoenix.Presence.fetch/2.

Link to this function handle_diff(diff, state)

Callback implementation for Phoenix.Presence.handle_diff/2.

Callback implementation for Phoenix.Presence.init/1.

Callback implementation for Phoenix.Presence.list/1.

Link to this function start_link(opts \\ [])

Callback implementation for Phoenix.Presence.start_link/1.

Link to this function track(socket, key, meta)

Callback implementation for Phoenix.Presence.track/3.

Link to this function track(pid, topic, key, meta)

Callback implementation for Phoenix.Presence.track/4.

Link to this function untrack(socket, key)

Callback implementation for Phoenix.Presence.untrack/2.

Link to this function untrack(pid, topic, key)

Callback implementation for Phoenix.Presence.untrack/3.

Link to this function update(socket, key, meta)

Callback implementation for Phoenix.Presence.update/3.

Link to this function update(pid, topic, key, meta)

Callback implementation for Phoenix.Presence.update/4.