Changeset View
Changeset View
Standalone View
Standalone View
lib/kolab_chat/web/channels/system_channel.ex
defmodule KolabChat.Web.SystemChannel do | defmodule KolabChat.Web.SystemChannel do | ||||
use KolabChat.Web, :channel | use KolabChat.Web, :channel | ||||
@status [ | |||||
# user is available for chat | |||||
:online, | |||||
:away, | |||||
# user is connected and visible, but not available | |||||
:busy, | |||||
:unavailable, | |||||
# user is shown as offline | |||||
:invisible, | |||||
:offline | |||||
] | |||||
@spec join(topic :: binary(), args :: map(), socket :: pid()) :: {:ok, socket :: pid()} | @spec join(topic :: binary(), args :: map(), socket :: pid()) :: {:ok, socket :: pid()} | ||||
def join("system", %{"context" => context}, socket) do | def join("system", args, socket) do | ||||
perform_join(context, socket) | perform_join(get_context(args), socket) | ||||
end | |||||
def join("system", _args, socket) do | |||||
perform_join("default", socket) | |||||
end | end | ||||
@spec handle_info(:after_join, socket :: pid()) :: {:noreply, socket :: pid()} | @spec handle_info(:after_join, socket :: pid()) :: {:noreply, socket :: pid()} | ||||
def handle_info(:after_join, socket) do | def handle_info(:after_join, socket) do | ||||
push socket, "presence_state", Presence.list(socket) | push socket, "presence_state", Presence.list(socket) | ||||
push socket, "info", %{user: socket.assigns.user.username, userId: socket.assigns.user.id} | push socket, "info", %{user: socket.assigns.user.username, userId: socket.assigns.user.id} | ||||
Presence.track(socket, socket.assigns.user.id, %{ | Presence.track_presence(socket) | ||||
username: socket.assigns.user.username, | |||||
status: get_user_status(socket), | |||||
context: socket.assigns.context | |||||
}) | |||||
{:noreply, socket} | {:noreply, socket} | ||||
end | end | ||||
@spec handle_in(topic :: binary, args :: map(), socket :: pid()) :: {:noreply, socket :: pid()} | @spec handle_in(topic :: binary, args :: map(), socket :: pid()) :: {:noreply, socket :: pid()} | ||||
def handle_in("set-status", %{"status" => status}, socket) do | def handle_in("set-status", %{"status" => status}, socket) do | ||||
status = check_status(status) | |||||
socket | socket | ||||
|> update_presence_status(status) | |> Presence.update_status(status) | ||||
|> set_user_status(status) | |> Presence.set_status(status) | ||||
{:noreply, socket} | {:noreply, socket} | ||||
end | end | ||||
defp perform_join(context, socket) do | defp perform_join(context, socket) do | ||||
socket = assign(socket, :context, context) | socket = assign(socket, :context, context) | ||||
send self(), :after_join | send self(), :after_join | ||||
{:ok, socket} | {:ok, socket} | ||||
end | end | ||||
defp update_presence_status(socket, :invalid), do: socket | defp get_context(args) do | ||||
defp update_presence_status(socket, status) do | case args do | ||||
Presence.update(socket, socket.assigns.user.id, %{ | %{:context => context} -> context | ||||
username: socket.assigns.user.username, | _ -> "default" | ||||
status: status, | |||||
context: socket.assigns.context | |||||
}) | |||||
socket | |||||
end | |||||
# Makes sure the provided status name is supported | |||||
# Returns status name as an atom | |||||
defp check_status(status) do | |||||
status = String.to_atom(status) | |||||
if Enum.member?(@status, status) do | |||||
status | |||||
else | |||||
:invalid | |||||
end | |||||
end | |||||
# Get the last user/context status from the database | |||||
defp get_user_status(socket) do | |||||
require Amnesia | |||||
require Amnesia.Helper | |||||
key = Integer.to_string(socket.assigns.user.id) <> ":" <> socket.assigns.context | |||||
Amnesia.transaction do | |||||
case Database.Status.read(key) do | |||||
# use last status | |||||
%Database.Status{status: status} -> status | |||||
# otherwise set status to online | |||||
_ -> :online | |||||
end | |||||
end | |||||
end | end | ||||
# Save the current user/context status to the database | |||||
defp set_user_status(socket, :invalid), do: socket | |||||
defp set_user_status(socket, status) do | |||||
require Amnesia | |||||
require Amnesia.Helper | |||||
key = Integer.to_string(socket.assigns.user.id) <> ":" <> socket.assigns.context | |||||
Amnesia.transaction do | |||||
Database.Status.write(%Database.Status{key: key, status: status}) | |||||
end | end | ||||
socket | |||||
end | |||||
end | end |