Skip to content

Commit

Permalink
Implementing Handlers behaviour for common messages handling at live …
Browse files Browse the repository at this point in the history
…views!
  • Loading branch information
diegomanuel committed Aug 17, 2019
1 parent c69ace8 commit df154bd
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 200 deletions.
10 changes: 4 additions & 6 deletions config/config.exs
Expand Up @@ -20,8 +20,8 @@ config :live_qchatex, LiveQchatexWeb.Endpoint,

# Configures app timers in SECONDS
config :live_qchatex, :timers,
cron_interval_clean_chats: 60 * 30,
cron_interval_clean_users: 60 * 10,
cron_interval_clean_chats: 60 * 10,
cron_interval_clean_users: 60 * 5,
user_typing_timeout: 3

# Configures Memento/Mnesia
Expand All @@ -31,15 +31,13 @@ config :mnesia,

# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
format: "[$level][$time] $metadata$message\n",
metadata: [:socket_id, :view]

# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
config :phoenix, :template_engines, leex: Phoenix.LiveView.Engine

# config :phoenix, :template_engines, leex: Phoenix.LiveView.Engine

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
4 changes: 2 additions & 2 deletions config/dev.exs
Expand Up @@ -56,8 +56,8 @@ config :live_qchatex, LiveQchatexWeb.Endpoint,
]
]

# Do not include metadata nor timestamps in development logs
config :logger, :console, format: "[$level] $message\n"
# Exclude timestamps in development logs
config :logger, :console, format: "[$level] $metadata$message\n"

# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
Expand Down
4 changes: 2 additions & 2 deletions config/prod.exs
Expand Up @@ -18,8 +18,8 @@ config :live_qchatex, LiveQchatexWeb.Endpoint,

# Configures app timers in SECONDS
config :live_qchatex, :timers,
cron_interval_clean_chats: 60 * 60,
cron_interval_clean_users: 60 * 30
cron_interval_clean_chats: 60 * 30,
cron_interval_clean_users: 60 * 5

# Do not print debug messages in production
config :logger, level: :info
Expand Down
19 changes: 19 additions & 0 deletions lib/live_qchatex_web.ex
Expand Up @@ -47,6 +47,25 @@ defmodule LiveQchatexWeb do
end
end

def live_view do
quote do
use Phoenix.LiveView

require Logger

use LiveQchatexWeb.LiveChat.Handlers

alias LiveQchatex.Chats
alias LiveQchatex.Models
alias LiveQchatexWeb.ChatView
alias LiveQchatexWeb.LiveChat.Handlers
alias LiveQchatexWeb.Router.Helpers, as: Routes

defp setup_logger(socket, view),
do: Logger.metadata(socket_id: "[#{socket.id}]", view: "[#{view}]")
end
end

def router do
quote do
use Phoenix.Router
Expand Down
116 changes: 38 additions & 78 deletions lib/live_qchatex_web/live/chat.ex
@@ -1,12 +1,12 @@
defmodule LiveQchatexWeb.LiveChat.Chat do
use Phoenix.LiveView
require Logger
alias LiveQchatex.Chats
alias LiveQchatex.Models
alias LiveQchatexWeb.ChatView
alias LiveQchatexWeb.Router.Helpers, as: Routes
use LiveQchatexWeb, :live_view

@behaviour Handlers
@view_name "chat-room"

def mount(%{sid: sid, path_params: %{"id" => id}}, socket) do
setup_logger(socket, @view_name)

try do
socket = socket |> fetch_chat!(id) |> fetch_user(sid)
if connected?(socket), do: Chats.track(socket.assigns.chat, socket.assigns.user)
Expand All @@ -27,83 +27,56 @@ defmodule LiveQchatexWeb.LiveChat.Chat do
ChatView.render("chat.html", assigns)
end

def handle_info({[:chat, :created], _chat} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE CHAT CREATED: #{inspect(info)}",
ansi_color: :magenta
)
@impl Handlers
def handle_chat_created(socket, _chat),
do: socket |> update_counter(:chats, 1)

{:noreply, socket |> update_counter(:chats, 1)}
end
@impl Handlers
def handle_chat_updated(socket, chat),
do: socket |> update_chat(chat)

def handle_info({[:chat, :updated], chat} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE CHAT UPDATED: #{inspect(info)}",
ansi_color: :magenta
)
@impl Handlers
def handle_chat_cleared(socket, counter),
do: socket |> set_counter(:chats, counter)

{:noreply, socket |> update_chat(chat)}
end
@impl Handlers
def handle_user_created(socket, _user),
do: socket |> update_counter(:users, 1)

def handle_info({[:chat, :cleared], counter} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE CHAT CLEARED: #{inspect(info)}",
ansi_color: :magenta
)

{:noreply, socket |> set_counter(:chats, counter)}
end

def handle_info({[:user, :created], _user} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE USER CREATED: #{inspect(info)}",
ansi_color: :magenta
)
@impl Handlers
def handle_user_cleared(socket, counter),
do: socket |> set_counter(:users, counter)

{:noreply, socket |> update_counter(:users, 1)}
end
@impl Handlers
def handle_presence_payload(socket, topic, payload) do
cond do
topic == Chats.topic(:presence, :chats) ->
socket |> maybe_clear_invite(payload) |> update_invites()

def handle_info({[:user, :cleared], counter} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE USER CLEARED: #{inspect(info)}",
ansi_color: :magenta
)
topic == Chats.topic(socket.assigns.user) ->
socket |> update_invites()

{:noreply, socket |> set_counter(:users, counter)}
true ->
socket |> update_members()
end
end

def handle_info({[:user, :typing, :end]} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE USER TYPING end: #{inspect(info)}",
ansi_color: :magenta
)
Logger.debug("HANDLE USER TYPING END: #{inspect(info)}", ansi_color: :magenta)

user = Chats.update_last_activity!(socket.assigns.user)
Chats.update_member_typing(socket.assigns.chat, socket.assigns.user, false)
{:noreply, socket |> assign(:user, user)}
end

def handle_info({[:message, :created], message} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE MESSAGE CREATED: #{inspect(info)}",
ansi_color: :magenta
)
Logger.debug("HANDLE MESSAGE CREATED: #{inspect(info)}", ansi_color: :magenta)

{:noreply, socket |> update_messages(message)}
end

def handle_info(%{event: "presence_diff", topic: topic, payload: payload}, socket) do
Logger.debug(
"[#{socket.id}][chat-view] HANDLE PRESENCE DIFF FOR '#{topic}': #{inspect(payload)}",
ansi_color: :magenta
)

{:noreply, socket |> handle_presence_payload(topic, payload)}
end

def handle_info({:hearthbeat, _, _} = info, socket) do
Logger.debug("[#{socket.id}][chat-view] HANDLE HEARTHBEAT: #{inspect(info)}",
ansi_color: :magenta
)

Chats.handle_hearthbeat(info, socket)
end

def handle_info(info, socket) do
Logger.warn("[#{socket.id}][chat-view] UNHANDLED INFO: #{inspect(info)}")
Logger.warn("UNHANDLED INFO: #{inspect(info)}")
{:noreply, socket}
end

Expand Down Expand Up @@ -169,23 +142,10 @@ defmodule LiveQchatexWeb.LiveChat.Chat do
end

def handle_event(event, data, socket) do
Logger.warn("[#{socket.id}][chat-view] UNHANDLED EVENT '#{event}': #{inspect(data)}")
Logger.warn("UNHANDLED EVENT '#{event}': #{inspect(data)}")
{:noreply, socket}
end

defp handle_presence_payload(socket, topic, payload) do
cond do
topic == Chats.topic(:presence, :chats) ->
socket |> maybe_clear_invite(payload) |> update_invites()

topic == Chats.topic(socket.assigns.user) ->
socket |> update_invites()

true ->
socket |> update_members()
end
end

defp fetch_chat!(socket, id) do
socket |> assign(chat_id: id, chat: Chats.get_chat!(id))
end
Expand Down Expand Up @@ -252,7 +212,7 @@ defmodule LiveQchatexWeb.LiveChat.Chat do
end

defp update_nickname(%{:assigns => %{:user => user}} = socket, nick) do
Logger.debug("[#{socket.id}][chat-view] Changed nickname to: #{inspect(nick)}")
Logger.debug("Changed nickname to: #{inspect(nick)}")
message = "Renamed from #{inspect(user.nickname)} to #{inspect(nick)}"

handle_event(
Expand All @@ -274,7 +234,7 @@ defmodule LiveQchatexWeb.LiveChat.Chat do
end

defp update_title(%{:assigns => %{:chat => chat}} = socket, title) do
Logger.debug("[#{socket.id}][chat-view] Changed title to: #{inspect(title)}")
Logger.debug("Changed title to: #{inspect(title)}")
message = "Changed chat title from #{inspect(chat.title)} to #{inspect(title)}"

handle_event(
Expand All @@ -298,7 +258,7 @@ defmodule LiveQchatexWeb.LiveChat.Chat do
defp maybe_toggle_scope(%{:assigns => %{:chat => chat, :user => user}} = socket) do
if chat.user_id == user.id do
scope = if chat.private, do: "public", else: "private"
Logger.debug("[#{socket.id}][chat-view] Changing chat scope to: #{scope}")
Logger.debug("Changing chat scope to: #{scope}")

{:noreply, socket |> update_chat(:private, scope == "private")}
else
Expand Down
67 changes: 24 additions & 43 deletions lib/live_qchatex_web/live/chats_list.ex
@@ -1,10 +1,11 @@
defmodule LiveQchatexWeb.LiveChat.ChatsList do
use Phoenix.LiveView
require Logger
alias LiveQchatex.Chats
alias LiveQchatexWeb.ChatView
use LiveQchatexWeb, :live_view

@behaviour Handlers
@view_name "chat-list"

def mount(_, socket) do
setup_logger(socket, @view_name)
if connected?(socket), do: [Chats.subscribe(), Chats.subscribe(:presence, :chats)]
{:ok, socket |> fetch()}
end
Expand All @@ -13,46 +14,21 @@ defmodule LiveQchatexWeb.LiveChat.ChatsList do
ChatView.render("chats_list.html", assigns)
end

def handle_info({[:chat, :created], chat} = info, socket) do
Logger.debug("[#{socket.id}][chats-list-view] HANDLE CHAT CREATED: #{inspect(info)}",
ansi_color: :magenta
)

{:noreply, if(chat.private != true, do: add_public_chat(socket, chat), else: socket)}
end
@impl Handlers
def handle_chat_created(socket, chat),
do: if(chat.private != true, do: add_public_chat(socket, chat), else: socket)

def handle_info({[:chat, :updated], chat} = info, socket) do
Logger.debug("[#{socket.id}][chats-list-view] HANDLE CHAT UPDATED: #{inspect(info)}",
ansi_color: :magenta
)

{:noreply, socket |> update_public_chat(chat)}
end

def handle_info({[:chat, :cleared], _} = info, socket) do
Logger.debug("[#{socket.id}][chats-list-view] HANDLE CHAT CLEARED: #{inspect(info)}",
ansi_color: :magenta
)
@impl Handlers
def handle_chat_updated(socket, chat),
do: socket |> update_public_chat(chat)

@impl Handlers
def handle_chat_cleared(socket, _counter),
# Reload all public chats again (should be improved)
{:noreply, socket |> fetch()}
end

def handle_info(%{event: "presence_diff", topic: topic, payload: payload}, socket) do
Logger.debug(
"[#{socket.id}][chats-list-view] HANDLE PRESENCE DIFF FOR '#{topic}': #{inspect(payload)}",
ansi_color: :magenta
)

{:noreply, socket |> handle_presence_payload(topic, payload)}
end
do: socket |> fetch()

def handle_info(info, socket) do
Logger.warn("[#{socket.id}][chats-list-view] UNHANDLED INFO: #{inspect(info)}")
{:noreply, socket}
end

defp handle_presence_payload(socket, _topic, %{joins: joins, leaves: leaves}) do
@impl Handlers
def handle_presence_payload(socket, _topic, %{joins: joins, leaves: leaves}) do
chats_ids = Enum.uniq(Map.keys(joins) ++ Map.keys(leaves))

chats =
Expand All @@ -62,6 +38,11 @@ defmodule LiveQchatexWeb.LiveChat.ChatsList do
socket |> fetch(chats)
end

def handle_info(info, socket) do
Logger.warn("UNHANDLED INFO: #{inspect(info)}")
{:noreply, socket}
end

defp fetch(socket) do
socket |> fetch(Chats.get_public_chats() |> Enum.map(&add_chat_members_count/1))
end
Expand All @@ -75,7 +56,7 @@ defmodule LiveQchatexWeb.LiveChat.ChatsList do
end

defp add_public_chat(socket, chat) do
Logger.debug("[#{socket.id}][chats-list-view] Adding public chat: #{chat.title}")
Logger.debug("Adding public chat: #{chat.title}")
socket |> fetch([chat |> add_chat_members_count() | socket.assigns.chats])
end

Expand All @@ -87,14 +68,14 @@ defmodule LiveQchatexWeb.LiveChat.ChatsList do
socket

{true, _} ->
Logger.debug("[#{socket.id}][chats-list-view] Removing private chat: #{chat.title}")
Logger.debug("Removing private chat: #{chat.title}")
socket |> fetch(socket.assigns.chats |> Enum.reject(&(&1.id == chat.id)))

{false, nil} ->
socket |> add_public_chat(chat)

{false, _} ->
Logger.debug("[#{socket.id}][chats-list-view] Updating public chat: #{chat.title}")
Logger.debug("Updating public chat: #{chat.title}")

socket
|> fetch(
Expand Down

0 comments on commit df154bd

Please sign in to comment.