Skip to content

Commit

Permalink
PubSub and LiveView logic
Browse files Browse the repository at this point in the history
  • Loading branch information
d-led committed Mar 10, 2022
1 parent 0d488a1 commit b685c71
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 10 deletions.
1 change: 0 additions & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ config :dzen, DzenWeb.Endpoint,
url: [scheme: "https", host: "red-dark-honeyeater.gigalixirapp.com", port: 443],
check_origin: ["https://red-dark-honeyeater.gigalixirapp.com"]


# Do not print debug messages in production
config :logger, level: :info

Expand Down
3 changes: 1 addition & 2 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ config :dzen, DzenWeb.Endpoint,
server: false

# In test we don't send emails.
config :dzen, Dzen.Mailer,
adapter: Swoosh.Adapters.Test
config :dzen, Dzen.Mailer, adapter: Swoosh.Adapters.Test

# Print only warnings and errors during test
config :logger, level: :warn
Expand Down
3 changes: 2 additions & 1 deletion lib/dzen/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ defmodule Dzen.Application do
# Start the PubSub system
{Phoenix.PubSub, name: Dzen.PubSub},
# Start the Endpoint (http/https)
DzenWeb.Endpoint
DzenWeb.Endpoint,
DzenWeb.Counter
# Start a worker by calling: Dzen.Worker.start_link(arg)
# {Dzen.Worker, arg}
]
Expand Down
107 changes: 107 additions & 0 deletions lib/dzen/counter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
defmodule DzenWeb.Counter do
use GenServer
## API

def start_link(_args \\ []) do
# demo purposes only: race condition. Serialized: see global:trans
case :global.whereis_name(__MODULE__) do
pid when is_pid(pid) ->
IO.puts("Skipping starting the global counter")
:ignore

_ ->
GenServer.start_link(__MODULE__, %{})
end
end

def total_sessions() do
case :global.whereis_name(__MODULE__) do
pid when is_pid(pid) ->
GenServer.call(pid, {:total_sessions})

_ ->
:unknown
end
end

# just a demo, not a watertight counter
def active_sessions() do
case :global.whereis_name(__MODULE__) do
pid when is_pid(pid) ->
GenServer.call(pid, {:active_sessions})

_ ->
:unknown
end
end

def session_started() do
case :global.whereis_name(__MODULE__) do
pid when is_pid(pid) ->
GenServer.cast(pid, {:session_started})

_ ->
:unknown
end
end

def session_stopped() do
case :global.whereis_name(__MODULE__) do
pid when is_pid(pid) ->
GenServer.cast(pid, {:session_stopped})

_ ->
:unknown
end
end

## Callbacks

def init(_args) do
IO.puts("Starting the global session counter")
:global.register_name(__MODULE__, self())
{:ok, %{total_sessions: 0, stopped_sessions: 0}}
end

def handle_cast({:session_stopped}, state = %{stopped_sessions: stopped_sessions}) do
state = %{state | stopped_sessions: stopped_sessions + 1}
broadcast_counter_state(state)
{:noreply, state}
end

def handle_cast({:session_started}, state = %{total_sessions: total_sessions}) do
state = %{state | total_sessions: total_sessions + 1}
broadcast_counter_state(state)
{:noreply, state}
end

def handle_call({:total_sessions}, _sender, state = %{total_sessions: total_sessions}) do
{:reply, total_sessions, state}
end

def handle_call(
{:active_sessions},
_sender,
state = %{total_sessions: total_sessions, stopped_sessions: stopped_sessions}
) do
{:reply, total_sessions - stopped_sessions, state}
end

## details
defp broadcast_counter_state(%{
total_sessions: total_sessions,
stopped_sessions: stopped_sessions
}) do
Phoenix.PubSub.broadcast(
Dzen.PubSub,
"live:counter::#{node()}",
{
:counter_state,
%{
total_count: total_sessions,
active_count: total_sessions - stopped_sessions
}
}
)
end
end
57 changes: 51 additions & 6 deletions lib/dzen_web/live/page_controller_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ defmodule DzenWeb.PageControllerLive do
def render(assigns) do
~H"""
<section class="phx-hero">
<h1><%= @total_count %></h1>
<%= if (@total_count > 0) do %>
<h1><%= @total_count %></h1>
<% end %>
<br>
<h1><%= @active_count %></h1>
<%= if (@active_count > 0) do %>
<h1><%= @active_count %></h1>
<% end %>
</section>
<section class="row">
Expand All @@ -18,9 +24,48 @@ defmodule DzenWeb.PageControllerLive do
end

def mount(_params, _user, socket) do
socket = socket
|> assign(:total_count, 1)
|> assign(:active_count, 1)
{:ok, socket }
if connected?(socket) do
# subscribe to the other modules sending live notifications
DzenWeb.Endpoint.subscribe("live:counter:#{node()}")

# let the system know that a session has started
DzenWeb.Counter.session_started()

:timer.send_after(1000, self(), :init)
end

socket =
socket
|> assign(:total_count, 0)
|> assign(:active_count, 0)

{:ok, socket}
end

def terminate(_reason, socket) do
if connected?(socket), do: DzenWeb.Counter.session_stopped()
end

# this is triggered upon the :init message triggered via :timer.send_after
def handle_info(:init, socket) do
socket =
socket
|> assign(:total_count, DzenWeb.Counter.total_sessions())
|> assign(:active_count, DzenWeb.Counter.active_sessions())

{:noreply, socket}
end

# this is triggered via the :counter_state message received via the "live:counter:#{node()}" PubSub channel
def handle_info(
{:counter_state, %{total_count: total_count, active_count: active_count}},
socket
) do
socket =
socket
|> assign(:total_count, total_count)
|> assign(:active_count, active_count)

{:noreply, socket}
end
end

0 comments on commit b685c71

Please sign in to comment.