lib/roles/dealer.ex

defmodule Wampex.Roles.Dealer do
  @moduledoc """
  Handles requests and responses for a Dealer
  """
  alias Wampex.Role
  alias Wampex.Roles.Callee.{Register, Unregister, Yield}
  alias Wampex.Roles.Caller.Call
  alias Wampex.Roles.Peer.Error
  @behaviour Role

  @error 8
  @call 48
  @result 50
  @register 64
  @registered 65
  @unregister 66
  @unregistered 67
  @invocation 68
  @yield 70

  defmodule Registered do
    @moduledoc false
    @enforce_keys [:request_id, :registration_id]
    defstruct [:request_id, :registration_id]

    @type t :: %__MODULE__{
            request_id: integer(),
            registration_id: integer()
          }
  end

  defmodule Unregistered do
    @moduledoc false
    @enforce_keys [:request_id]
    defstruct [:request_id]

    @type t :: %__MODULE__{
            request_id: integer()
          }
  end

  defmodule Result do
    @moduledoc false
    @enforce_keys [:request_id]
    defstruct [:request_id, arg_list: [], arg_kw: %{}, details: %{}]

    @type t :: %__MODULE__{
            request_id: integer(),
            arg_list: list(any()),
            arg_kw: map(),
            details: map()
          }
  end

  defmodule Invocation do
    @moduledoc false
    @enforce_keys [:request_id, :registration_id]
    defstruct [:request_id, :registration_id, arg_list: [], arg_kw: %{}, details: %{}]

    @type t :: %__MODULE__{
            request_id: integer(),
            registration_id: integer(),
            arg_list: list(any()),
            arg_kw: map(),
            details: map()
          }
  end

  @impl true
  def add(roles) do
    Map.put(roles, :dealer, %{})
  end

  @spec registered(Registered.t()) :: Wampex.message()
  def registered(%Registered{request_id: ri, registration_id: reg_id}) do
    [@registered, ri, reg_id]
  end

  @spec unregistered(Unregistered.t()) :: Wampex.message()
  def unregistered(%Unregistered{request_id: ri}) do
    [@unregistered, ri]
  end

  @spec invocation(Invocation.t()) :: Wampex.message()
  def invocation(%Invocation{
        request_id: ri,
        registration_id: reg_id,
        details: opts,
        arg_list: al,
        arg_kw: akw
      }) do
    [@invocation, ri, reg_id, opts, al, akw]
  end

  @spec call_error(Error.t()) :: Wampex.message()
  def call_error(%Error{request_id: rid, error: er, details: dets, arg_list: al, arg_kw: akw}) do
    [@error, @call, rid, dets, er, al, akw]
  end

  @spec register_error(Error.t()) :: Wampex.message()
  def register_error(%Error{request_id: rid, error: er, details: dets}) do
    [@error, @register, rid, dets, er]
  end

  @spec result(Result.t()) :: Wampex.message()
  def result(%Result{
        request_id: ri,
        arg_list: al,
        arg_kw: akw,
        details: dets
      }) do
    [@result, ri, dets, al, akw]
  end

  @impl true
  def handle([@unregister, request_id, registration_id]) do
    {[{:next_event, :internal, :unregister}], request_id,
     {:update, :unregister, %Unregister{request_id: request_id, registration_id: registration_id}}}
  end

  @impl true
  def handle([@register, request_id, opts, procedure]) do
    {[{:next_event, :internal, :register}], request_id,
     {:update, :register, %Register{request_id: request_id, options: opts, procedure: procedure}}}
  end

  @impl true
  def handle([@call, id, opts, proc]) do
    handle([@call, id, opts, proc, [], %{}])
  end

  @impl true
  def handle([@call, id, opts, proc, arg_l]) do
    handle([@call, id, opts, proc, arg_l, %{}])
  end

  @impl true
  def handle([@call, id, opts, proc, arg_l, arg_kw]) do
    {[{:next_event, :internal, :call}], id,
     {:update, :call,
      %Call{request_id: id, options: opts, procedure: proc, arg_list: arg_l, arg_kw: arg_kw}}}
  end

  @impl true
  def handle([@yield, id, opts]) do
    handle([@yield, id, opts, [], %{}])
  end

  @impl true
  def handle([@yield, id, opts, arg_l]) do
    handle([@yield, id, opts, arg_l, %{}])
  end

  @impl true
  def handle([@yield, id, opts, arg_l, arg_kw]) do
    {[{:next_event, :internal, :yield}], id,
     {:update, :yield, %Yield{request_id: id, options: opts, arg_list: arg_l, arg_kw: arg_kw}}}
  end
end