defmodule PlanB.EventBus do use GenServer @moduledoc """ ## Module EventBus This module is created as a GenServer. To use it just call start_link/1, then create a channel and register subscribers to it. """ # Server side @spec init(any) :: {:ok, any} def init(state) do {:ok, state} end def handle_call({:lookup, name}, _from, state) when is_binary(name) do state |> Map.fetch(name) |> case do :error -> {:reply, :fail, state} {:ok, modules} -> results = modules |> Enum.map(fn (module) -> {module, Process.whereis(module) } end) {:reply, {name, results}, state} end end def handle_call({:register, {name, module}}, _from, state) do state |> Map.fetch(name) |> case do :error -> new_state = state |> Map.put(name, [ module ]) {:reply, :ok, new_state} {:ok, modules} -> modules |> Enum.member?(module) |> case do true -> {:reply, :ok, state} false -> new_state = state |> Map.put(name, modules ++ [module]) {:reply, :ok, new_state} end end end def handle_cast({:publish, name, payload}, state) do state |> Map.fetch(name) |> case do :error -> {:noreply, state} {:ok, modules} -> modules |> Enum.each(fn (module) -> GenServer.cast(module, payload) end) {:noreply, state} end end # Client side @doc """ ### start_link/1 """ @spec start_link(any) :: :ignore | {:error, any} | {:ok, pid} def start_link([state] = args) when is_list(args) and is_map(state) do GenServer.start_link __MODULE__, state, name: __MODULE__ end @doc """ ### stop_server/0 """ @spec stop_server :: :ok def stop_server, do: GenServer.stop __MODULE__ @doc """ ### health_check/0 """ @spec health_check :: :fail | :ok def health_check do case GenServer.whereis(__MODULE__) do pid when is_pid(pid) -> :ok _ -> :fail end end @doc """ ### register/2 """ @spec register(binary, Module) :: any def register(name, module), do: GenServer.call __MODULE__, {:register, {name, module}} @doc """ ### lookup/1 """ @spec lookup(binary) :: any def lookup(name) when is_binary(name), do: GenServer.call __MODULE__, {:lookup, name} @doc """ ### publish/2 """ @spec publish(binary, any) :: any def publish(name, payload) when is_binary(name), do: GenServer.cast __MODULE__, {:publish, name, payload} end