develop SessionsSupervisor, SessionServer & SessionPubSub

This commit is contained in:
Victor Martinez 2024-03-29 15:53:36 +01:00
parent e60e1be337
commit a03a2b69db
4 changed files with 173 additions and 0 deletions

View file

@ -11,6 +11,7 @@ defmodule Intisync.Application do
IntisyncWeb.Telemetry,
{DNSCluster, query: Application.get_env(:intisync, :dns_cluster_query) || :ignore},
{Phoenix.PubSub, name: Intisync.PubSub},
{Intisync.SessionsSupervisor, %{}},
{IntisyncWeb.LiveViewMonitor, %{}},
IntisyncWeb.Endpoint
]

View file

@ -0,0 +1,12 @@
defmodule Intisync.SessionPubSub do
def broadcast!(session_id, topic, event, payload) do
topic = "#{topic}:#{event}:#{session_id}"
payload = %{payload: payload, topic: topic}
Phoenix.PubSub.broadcast!(Intisync.PubSub, topic, payload)
end
def subscribe!(session_id, topic, event) do
:ok = Phoenix.PubSub.subscribe(Intisync.PubSub, "#{topic}:#{event}:#{session_id}")
end
end

View file

@ -0,0 +1,121 @@
defmodule Intisync.SessionServer do
alias Intisync.SessionPubSub
use GenServer
def init(session_id) do
{:ok,
%{
session_id: session_id,
remote_connection_status: :disconnected,
devices: %{}
}}
end
def start_link({session_id}) do
GenServer.start_link(__MODULE__, session_id, name: {:global, "session:#{session_id}"})
end
def get_id(pid) do
GenServer.call(pid, {:get_id})
end
def remote_connected(pid) do
GenServer.cast(pid, {:remote_connected})
end
def remote_disconnected(pid) do
GenServer.cast(pid, {:remote_disconnected})
end
def device_connected(pid, index, device) do
GenServer.call(pid, {:device_connected, index, device})
end
def device_disconnected(pid, index) do
GenServer.call(pid, {:device_disconnected, index})
end
def empty_devices(pid) do
GenServer.call(pid, {:empty_devices})
end
def vibrate_device(pid, index, vibration) do
GenServer.call(pid, {:vibrate_device, index, vibration})
end
def get_devices(pid) do
GenServer.call(pid, {:get_devices})
end
def is_full?(pid) do
GenServer.call(pid, {:is_full?})
end
def handle_call({:get_id}, _from, state) do
{:reply, state.session_id, state}
end
def handle_call({:get_devices}, _from, state) do
{:reply, state.devices, state}
end
def handle_call({:is_full?}, _from, state) do
is_full? = state.remote_connection_status == :connected
{:reply, is_full?, state}
end
def handle_call({:device_connected, index, device}, _from, state) do
new_devices = Map.put_new(state.devices, index, device)
GenServer.cast(
self(),
{:publish, "devices", "connected", %{index: index}}
)
{:reply, :ok, %{state | devices: new_devices}}
end
def handle_call({:device_disconnected, index}, _from, state) do
new_devices = Map.delete(state.devices, index)
GenServer.cast(
self(),
{:publish, "devices", "disconnected", %{index: index}}
)
{:reply, :ok, %{state | devices: new_devices}}
end
def handle_call({:vibrate_device, index, vibration}, _from, state) do
devices = state.devices
new_devices = Map.replace!(devices, index, %{devices[index] | vibration: vibration})
GenServer.cast(
self(),
{:publish, "devices", "vibrate", %{index: index, vibration: vibration}}
)
{:reply, :ok, %{state | devices: new_devices}}
end
def handle_call({:empty_devices}, _from, state) do
GenServer.cast(self(), {:publish, "devices", "empty", %{}})
{:reply, :ok, %{state | devices: %{}}}
end
def handle_cast({:remote_connected}, state) do
GenServer.cast(self(), {:publish, "remote", "connected", %{}})
{:noreply, %{state | remote_connection_status: :connected}}
end
def handle_cast({:remote_disconnected}, state) do
GenServer.cast(self(), {:publish, "remote", "disconnected", %{}})
{:noreply, %{state | remote_connection_status: :disconnected}}
end
def handle_cast({:publish, topic, event, payload}, state) do
SessionPubSub.broadcast!(state.session_id, topic, event, payload)
{:noreply, state}
end
end

View file

@ -0,0 +1,39 @@
defmodule Intisync.SessionsSupervisor do
use DynamicSupervisor
alias Intisync.SessionServer
alias Intisync.SessionPubSub
def start_link(_arg) do
DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
DynamicSupervisor.init(strategy: :one_for_one)
end
def start_session(session_id) do
child_spec = {SessionServer, {session_id}}
DynamicSupervisor.start_child(__MODULE__, child_spec)
end
def whereis(session_id) do
GenServer.whereis({:global, "session:#{session_id}"})
end
def close_session(pid) do
session_id = SessionServer.get_id(pid)
SessionPubSub.broadcast!(session_id, "session", "closed", %{})
DynamicSupervisor.terminate_child(__MODULE__, pid)
end
# Nice utility method to check which processes are under supervision
def children do
DynamicSupervisor.which_children(__MODULE__)
end
# Nice utility method to check which processes are under supervision
def count_children do
DynamicSupervisor.count_children(__MODULE__)
end
end