Current section
Files
Jump to
Current section
Files
lib/brook/server.ex
defmodule Brook.Server do
@moduledoc """
Process event messages to and from the underlying event stream
message bus implementation. Interact with the application's
persisted view state of the event stream with getter and setter
functions to write and update events from the view state as well
as delete them.
"""
use GenServer
require Logger
@doc """
Start a Brook server and link it to the current process
"""
@spec start_link(term()) :: {:ok, pid()}
def start_link(%Brook.Config{} = config) do
GenServer.start_link(__MODULE__, config, name: via(config.registry))
end
@doc """
Initialize a Brook server configuration.
"""
@spec init(term()) :: {:ok, term()}
def init(%Brook.Config{} = config) do
Brook.ViewState.init(config.instance)
config.dispatcher.init(instance: config.instance)
{:ok, config}
end
def handle_call({:execute_test_function, event, function}, _from, state) when is_function(function, 0) do
register(state.instance, event)
function.()
Brook.ViewState.commit(state.instance)
unregister()
{:reply, :ok, state}
end
def handle_call({:process, event}, _from, state) do
process(event, state)
{:reply, :ok, state}
end
def handle_cast({:process, event}, state) do
process(event, state)
{:noreply, state}
end
defp process(%Brook.Event{forwarded: false} = event, state) do
register(state.instance, event)
Enum.each(state.event_handlers, fn handler ->
case apply(handler, :handle_event, [event]) do
{:create, collection, key, value} ->
Brook.ViewState.create(collection, key, value)
{:merge, collection, key, value} ->
Brook.ViewState.merge(collection, key, value)
{:delete, collection, key} ->
Brook.ViewState.delete(collection, key)
:discard ->
nil
:ok ->
nil
end
end)
Brook.ViewState.commit(state.instance)
apply(state.dispatcher, :dispatch, [state.instance, event])
unregister()
end
defp process(%Brook.Event{forwarded: true} = event, state) do
register(state.instance, event)
Enum.each(state.event_handlers, fn handler ->
apply(handler, :handle_event, [event])
end)
Brook.ViewState.rollback(state.instance)
unregister()
end
defp process(event, state) do
case Brook.Deserializer.deserialize(struct(Brook.Event), event) do
{:ok, brook_event} ->
process(brook_event, state)
{:error, reason} ->
Logger.error("Unable to deserialize event: #{inspect(event)}, error reason: #{inspect(reason)}")
end
end
defp register(instance, event) do
Process.put(:brook_instance, instance)
Process.put(:brook_current_event, event)
end
defp unregister() do
Process.delete(:brook_current_event)
Process.delete(:brook_instance)
end
defp via(registry), do: {:via, Registry, {registry, __MODULE__}}
end