defmodule Orcha do @type message() :: term() @type timestamp() :: pos_integer() @opaque t() :: %__MODULE__{ registry: %{atom() => any()} } @callback handle_request({module(), message()}, timestamp(), t()) :: {{:ok, result :: term()}, t()} | {:error, reason :: term()} defstruct registry: %{} def initialize(_args \\ []), do: %__MODULE__{} def register(%__MODULE__{} = realm, {mod, func, args}) do state = apply(mod, func, args) put_state(mod, state, realm) end def request({mod, msg}, timestamp, realm) do with {:ok, state} <- Map.fetch(realm.registry, mod) do case apply(mod, :handle_request, [msg, {timestamp, realm}, state]) do {result, new_state} -> new_realm = put_state(mod, new_state, realm) {result, new_realm} {result, new_state, %__MODULE__{} = new_realm} -> new_realm = put_state(mod, new_state, new_realm) {result, new_realm} end else :error -> raise "Requesting unregistered service: #{inspect(mod)}" end end defp put_state(mod, state, %__MODULE__{} = realm) do update_in(realm.registry, &Map.put(&1, mod, state)) end end