lib/roles/callee.ex

defmodule Wampex.Roles.Callee do
  @moduledoc """
  Handles requests and responses for a Callee
  """

  alias Wampex.Role
  alias Wampex.Roles.Dealer.Invocation
  alias Wampex.Roles.Peer.Error
  @behaviour Role

  @error 8
  @register 64
  @registered 65
  @unregister 66
  @unregistered 67
  @invocation 68
  @yield 70
  @interrupt 69

  defmodule Register do
    @moduledoc false
    @enforce_keys [:procedure]
    defstruct [:request_id, :registration_id, :procedure, options: %{}]

    @type t :: %__MODULE__{
            registration_id: integer() | nil,
            request_id: integer() | nil,
            procedure: binary(),
            options: map()
          }
  end

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

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

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

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

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

  @spec register(Register.t()) :: Wampex.message()
  def register(%Register{procedure: p, options: opts}) do
    [@register, opts, p]
  end

  @spec unregister(Unregister.t()) :: Wampex.message()
  def unregister(%Unregister{registration_id: ri}) do
    [@unregister, ri]
  end

  @spec yield(Yield.t()) :: Wampex.message()
  def yield(%Yield{request_id: ri, arg_list: al, arg_kw: akw, options: opts}) do
    [@yield, ri, opts, al, akw]
  end

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

  @impl true
  def handle(<<@unregistered, request_id>>) do
    {[{:next_event, :internal, :established}], request_id, {:ok, request_id}}
  end

  @impl true
  def handle([@unregistered, request_id]) do
    {[{:next_event, :internal, :established}], request_id, {:ok, request_id}}
  end

  @impl true
  def handle([@registered, request_id, id]) do
    {[{:next_event, :internal, :established}], request_id, {:ok, id}}
  end

  @impl true
  def handle([@invocation, id, reg_id, dets]) do
    handle([@invocation, id, reg_id, dets, [], %{}])
  end

  @impl true
  def handle([@invocation, id, reg_id, dets, arg_l]) do
    handle([@invocation, id, reg_id, dets, arg_l, %{}])
  end

  @impl true
  def handle([@invocation, id, reg_id, dets, arg_l, arg_kw]) do
    {[{:next_event, :internal, :invocation}], id,
     {:update, :invocation,
      %Invocation{
        request_id: id,
        registration_id: reg_id,
        details: dets,
        arg_list: arg_l,
        arg_kw: arg_kw
      }}}
  end

  @impl true
  def handle([@interrupt, id, opts]) do
    {[{:next_event, :internal, :interrupt}], id, {:update, :interrupt, {id, opts}}}
  end
end