From: Christopher Coté Date: Tue, 2 Nov 2021 01:15:18 +0000 (-0400) Subject: adds macros for easier handling of registrations and subscriptions X-Git-Url: http://git.entropealabs.com/?a=commitdiff_plain;h=621b05e374aae95390199976a29f2db83642d64b;p=wampex_client.git adds macros for easier handling of registrations and subscriptions --- diff --git a/lib/client/handler.ex b/lib/client/handler.ex new file mode 100644 index 0000000..e90664a --- /dev/null +++ b/lib/client/handler.ex @@ -0,0 +1,128 @@ +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