defmodule Wampex.Roles.Peer do
@moduledoc """
Handles requests and responses for low-level Peer/Session interactions
"""
alias Wampex.Role
@behaviour Role
@hello 1
@welcome 2
@abort 3
@challenge 4
@authenticate 5
@goodbye 6
@error 8
@invocation 68
defmodule Hello do
@moduledoc false
@enforce_keys [:realm, :roles]
defstruct [:realm, :roles, options: %{}, agent: "WAMPex"]
@type t :: %__MODULE__{
realm: binary(),
roles: nonempty_list(module()),
agent: binary(),
options: map()
}
end
defmodule Welcome do
@moduledoc false
@enforce_keys [:session_id]
defstruct [:session_id, options: %{}]
@type t :: %__MODULE__{
session_id: integer(),
options: map()
}
end
defmodule Challenge do
@moduledoc false
@enforce_keys [:auth_method]
defstruct [:auth_method, extra: %{}]
@type t :: %__MODULE__{
auth_method: String.t(),
extra: %{}
}
end
defmodule Goodbye do
@moduledoc false
@enforce_keys [:reason]
defstruct [:reason, options: %{}]
@type t :: %__MODULE__{
reason: binary(),
options: map()
}
end
defmodule Authenticate do
@moduledoc false
@enforce_keys [:signature, :extra]
defstruct [:signature, :extra]
@type t :: %__MODULE__{
signature: binary(),
extra: map()
}
end
defmodule Abort do
@moduledoc false
@enforce_keys [:reason]
defstruct [:reason, details: %{}]
@type t :: %__MODULE__{
reason: String.t(),
details: map()
}
end
defmodule Error do
@moduledoc false
@enforce_keys [:error]
defstruct [:request_id, :type, :error, arg_list: [], arg_kw: %{}, details: %{}]
@type t :: %__MODULE__{
request_id: integer() | nil,
type: integer() | nil,
error: String.t(),
arg_list: list(),
arg_kw: map(),
details: map()
}
end
@impl true
def add(roles), do: roles
@spec hello(Hello.t()) :: Wampex.message()
def hello(%Hello{realm: r, roles: roles, agent: agent, options: opts}) do
options =
Map.merge(opts, %{agent: agent, roles: Enum.reduce(roles, %{}, fn r, acc -> r.add(acc) end)})
[@hello, r, options]
end
@spec welcome(Welcome.t()) :: Wampex.message()
def welcome(%Welcome{session_id: si, options: opts}) do
[@welcome, si, opts]
end
@spec abort(Abort.t()) :: Wampex.message()
def abort(%Abort{reason: reason, details: opts}) do
[@abort, opts, reason]
end
@spec challenge(Challenge.t()) :: Wampex.message()
def challenge(%Challenge{auth_method: am, extra: ext}) do
[@challenge, am, ext]
end
@spec goodbye(Goodbye.t()) :: Wampex.message()
def goodbye(%Goodbye{reason: r, options: opts}) do
[@goodbye, opts, r]
end
@spec authenticate(Authenticate.t()) :: Wampex.message()
def authenticate(%Authenticate{signature: s, extra: e}) do
[@authenticate, s, e]
end
@impl true
def handle([@hello, realm, opts]) do
{[{:next_event, :internal, :hello}], nil,
{:update, :hello,
%Hello{
realm: realm,
options: opts,
roles: get_in(opts, ["roles"]),
agent: get_in(opts, ["agent"])
}}}
end
@impl true
def handle([@authenticate, sig, extra]) do
{[{:next_event, :internal, :authenticate}], nil,
{:update, :authenticate, %Authenticate{signature: sig, extra: extra}}}
end
@impl true
def handle([@welcome, session_id, _dets]) do
{[{:next_event, :internal, :welcome}], nil, {:update, :id, session_id}}
end
@impl true
def handle([@abort, _dets, reason]) do
{[{:next_event, :internal, :abort}], nil, {:update, :error, reason}}
end
@impl true
def handle([@goodbye, _dets, reason]) do
{[{:next_event, :internal, :goodbye}], nil, {:update, :goodbye, reason}}
end
@impl true
def handle([@challenge, auth_method, extra]) do
{[{:next_event, :internal, :challenge}], nil,
{:update, :challenge, %Challenge{auth_method: auth_method, extra: extra}}}
end
@impl true
def handle([@error, type, id, dets, error]) do
handle([@error, type, id, dets, error, [], %{}])
end
@impl true
def handle([@error, type, id, dets, error, arg_l]) do
handle([@error, type, id, dets, error, arg_l, %{}])
end
@impl true
def handle([@error, @invocation, id, dets, err, arg_l, arg_kw]) do
{[{:next_event, :internal, :invocation_error}], id,
{:update, :error,
%Error{
type: @invocation,
request_id: id,
error: err,
details: dets,
arg_list: arg_l,
arg_kw: arg_kw
}}}
end
@impl true
def handle([@error, type, id, dets, error, arg_l, arg_kw]) do
{[{:next_event, :internal, :established}], id,
%Error{
type: type,
request_id: id,
error: error,
details: dets,
arg_list: arg_l,
arg_kw: arg_kw
}}
end
end