defmodule Reactivity.Registry do use GenServer require Logger alias Reactivity.Signal.Source alias Reactivity.Signal.Derived ############# # GenServer # ############# def start_link(args \\ []) do GenServer.start_link(__MODULE__, args, name: __MODULE__) end def init(args) do table = :ets.new(:sources, [:named_table, :set, :protected]) {:ok, %{:table => table, :subs => MapSet.new()}} end ############# # Callbacks # ############# def handle_cast(m, state) do Logger.debug "Cast: #{inspect m}" {:noreply, state} end def handle_call({:insert, source, name}, _from, %{:table => t} = state) do :ets.insert(t, {name, source}) publish_new_signal(source, name, state) {:reply, :ok, state} end def handle_call({:remove, name}, _from, %{:table => t} = state) do :ets.delete(t, name) {:reply, :ok, state} end def handle_call({:get, name}, _from, %{:table => t} = state) do case :ets.lookup(t, name) do [{^name, val}] -> {:reply, {:ok, val}, state} [] -> {:reply, {:error, "not found"}, state} end end def handle_call({:subscribe, pid}, _from, %{:subs => ss} = state) do Logger.debug "Adding subscription for #{inspect pid}" {:reply, :ok, %{state | :subs => MapSet.put(ss, pid)}} end def handle_call({:unsubscribe, pid}, _from, %{:subs => ss} = state) do {:reply, :ok, %{state | :subs => MapSet.delete(ss, pid)}} end def handle_call(m, from, state) do Logger.debug "Call: #{inspect m} from #{inspect from}" {:reply, :ok, state} end def handle_info(m, state) do Logger.debug "Info: #{inspect m}" {:noreply, state} end ########### # Private # ########### defp publish_new_signal(source, name, %{:subs => ss} = state) do ss |> Enum.map(fn(sub) -> send(sub, {:new_signal, source, name}) end) end ############# # Interface # ############# def add_source(source, name) do GenServer.call(__MODULE__, {:insert, source, name}) end def remove_source(name) do GenServer.call(__MODULE__, {:remove, name}) end def get_source(name) do GenServer.call(__MODULE__, {:get, name}) end def subscribe(pid) do GenServer.call(__MODULE__, {:subscribe, pid}) end def unsubscribe(pid) do GenServer.call(__MODULE__, {:unsubscribe, pid}) end end