--- /dev/null
+defmodule Wampex.Client.Handler do
+ @moduledoc """
+ Macros and behaviours for client implemenations
+ """
+ @callback do_init(any()) :: %{client_name: atom()}
+
+ defmacro __using__(_opts) do
+ quote do
+ use GenServer
+ alias Wampex.Client
+ alias Wampex.Roles.Callee.Yield
+ alias Wampex.Roles.Peer.Error
+ import unquote(__MODULE__)
+ @before_compile unquote(__MODULE__)
+ @procedures []
+ @topics []
+
+ def start_link(opts) do
+ {name, opts} = Keyword.pop(opts, :name)
+ GenServer.start_link(__MODULE__, opts, name: name)
+ end
+
+ @impl true
+ def init(opts) do
+ {cn, opts} = Keyword.pop(opts, :client_name)
+ state = do_init(opts)
+ Client.add(cn, self())
+ {:ok, %{state | client_name: cn}}
+ end
+
+ @impl true
+ def handle_continue({:registered, _}, state), do: {:noreply, state}
+
+ def do_init(_opts), do: %{client_name: nil}
+
+ def handle_invocation_block({:ok, al, kw, state}, id) do
+ Client.yield(state.client_name, %Yield{request_id: id, arg_list: al, arg_kw: kw})
+ state
+ end
+
+ def handle_invocation_block({:error, error, al, kw, state}, id) do
+ Client.error(state.client_name, %Error{
+ request_id: id,
+ error: error,
+ arg_list: al,
+ arg_kw: kw
+ })
+
+ state
+ end
+
+ defoverridable do_init: 1, handle_continue: 2
+ end
+ end
+
+ defmacro __before_compile__(env) do
+ procedures = Module.get_attribute(env.module, :procedures)
+ topics = Module.get_attribute(env.module, :topics)
+
+ quote do
+ alias Wampex.Client
+ alias Wampex.Roles.Callee.Register
+ alias Wampex.Roles.Subscriber.Subscribe
+ @impl true
+ def handle_info({:connected, _}, %{client_name: cn} = state) do
+ regs =
+ Enum.map(unquote(procedures), fn p ->
+ Client.register(cn, %Register{procedure: p})
+ end)
+
+ subs =
+ Enum.map(unquote(topics), fn
+ {t, match} ->
+ Client.subscribe(cn, %Subscribe{topic: t, options: %{"match" => match}})
+
+ t ->
+ Client.subscribe(cn, %Subscribe{topic: t})
+ end)
+
+ {:noreply, state, {:continue, {:registered, %{registrations: regs, subscriptions: subs}}}}
+ end
+ end
+ end
+
+ defmacro invocation(procedure, list, kws, state, do: block) do
+ quote location: :keep do
+ alias Wampex.Roles.Dealer.Invocation
+
+ @procedures [unquote(procedure) | @procedures]
+
+ @impl true
+ def handle_info(
+ %Invocation{
+ request_id: id,
+ details: %{"procedure" => unquote(procedure)},
+ arg_list: unquote(list),
+ arg_kw: unquote(kws)
+ },
+ unquote(state) = state
+ ) do
+ state = handle_invocation_block(unquote(block), id)
+ {:noreply, state}
+ end
+ end
+ end
+
+ defmacro event(topic, list, kws, state, do: block) do
+ quote location: :keep do
+ alias Wampex.Client
+ alias Wampex.Roles.Broker.Event
+
+ @topics [unquote(topic) | @topics]
+
+ @impl true
+ def handle_info(
+ %Event{
+ details: %{"topic" => unquote(topic)},
+ arg_list: unquote(list),
+ arg_kw: unquote(kws)
+ },
+ unquote(state) = state
+ ) do
+ state = unquote(block)
+ {:noreply, state}
+ end
+ end
+ end
+end