From 411b7b567b7f35ff1db209b3aabccddb3ea1f8b2 Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 17 Mar 2020 16:12:27 -0500 Subject: [PATCH] handle call errors --- lib/roles/caller.ex | 7 +++ lib/roles/peer.ex | 18 +++++++- lib/router/session.ex | 104 +++++++++++++++++++++++------------------- lib/wampex.ex | 4 +- test/wampex_test.exs | 18 ++++++++ 5 files changed, 101 insertions(+), 50 deletions(-) diff --git a/lib/roles/caller.ex b/lib/roles/caller.ex index 254a5ab..c662f19 100644 --- a/lib/roles/caller.ex +++ b/lib/roles/caller.ex @@ -4,10 +4,12 @@ defmodule Wampex.Roles.Caller do """ alias Wampex.Role + alias Wampex.Roles.Peer.Error @behaviour Role @call 48 @cancel 49 + @error 8 @result 50 defmodule Call do @@ -45,6 +47,11 @@ defmodule Wampex.Roles.Caller do [@call, opts, p, al, akw] end + @spec call_error(Error.t()) :: Wampex.message() + def call_error(%Error{request_id: rid, error: er, details: dets, arg_l: al, arg_kw: akw}) do + [@error, @call, rid, dets, er, al, akw] + end + @spec cancel(Cancel.t()) :: Wampex.message() def cancel(%Cancel{request_id: ri, options: opts}) do [@cancel, ri, opts] diff --git a/lib/roles/peer.ex b/lib/roles/peer.ex index 8bb7911..329765e 100644 --- a/lib/roles/peer.ex +++ b/lib/roles/peer.ex @@ -81,6 +81,20 @@ defmodule Wampex.Roles.Peer do } end + defmodule Error do + @moduledoc false + @enforce_keys [:error] + defstruct [:request_id, :error, :arg_l, :arg_kw, details: %{}] + + @type t :: %__MODULE__{ + request_id: integer() | nil, + error: String.t(), + arg_l: list() | nil, + arg_kw: map() | nil, + details: map() + } + end + @impl true def add(roles), do: roles @@ -159,7 +173,7 @@ defmodule Wampex.Roles.Peer do end @impl true - def handle([@error, type, id, _dets, error, arg_l, arg_kw]) do - {[{:next_event, :internal, :established}], id, {:error, type, error, arg_l, arg_kw}} + def handle([@error, type, id, dets, error, arg_l, arg_kw]) do + {[{:next_event, :internal, :established}], id, {:error, type, error, dets, arg_l, arg_kw}} end end diff --git a/lib/router/session.ex b/lib/router/session.ex index 30bcc59..b4c7c63 100644 --- a/lib/router/session.ex +++ b/lib/router/session.ex @@ -9,8 +9,8 @@ defmodule Wampex.Router.Session do alias __MODULE__, as: Sess alias StatesLanguage, as: SL alias Wampex.Realm - alias Wampex.Roles.{Broker, Dealer, Peer} - alias Wampex.Roles.Peer.{Challenge, Welcome, Abort} + alias Wampex.Roles.{Broker, Caller, Dealer, Peer} + alias Wampex.Roles.Peer.{Abort, Challenge, Error, Welcome} alias Wampex.Router alias Wampex.Serializers.JSON alias Broker.{Subscribed, Published, Event} @@ -430,48 +430,67 @@ defmodule Wampex.Router.Session do %Sess{ db: db, proxy: proxy, - transport: _tt, - transport_pid: _t, + transport: tt, + transport_pid: t, realm: realm, request_id: ri, call: {:call, call_id, dets, proc, al, akw} } = data } = sl ) do - {_key, callees} = ClusterKV.get(db, realm, proc, 500) - - {data, actions} = - case get_live_callee(proxy, callees) do - {id, {pid, node}} -> - req_id = get_request_id(ri) + data = + with {_key, callees} <- ClusterKV.get(db, realm, proc, 500), + {id, {pid, node}} <- get_live_callee(proxy, callees) do + req_id = get_request_id(ri) - send( - {proxy, node}, + send( + {proxy, node}, + { { - { - call_id, - %Invocation{ - request_id: req_id, - registration_id: id, - options: dets, - arg_list: al, - arg_kw: akw - }, - {self(), Node.self()} + call_id, + %Invocation{ + request_id: req_id, + registration_id: id, + options: dets, + arg_list: al, + arg_kw: akw }, - pid - } + {self(), Node.self()} + }, + pid + } + ) + + %SL{sl | data: %Sess{data | request_id: req_id}} + else + {:error, :no_live_callees} -> + send_to_peer( + Caller.call_error(%Error{ + request_id: call_id, + error: "wamp.error.no_callees", + details: %{procedure: proc} + }), + tt, + t ) - {%SL{sl | data: %Sess{data | request_id: req_id}}, - [{:next_event, :internal, :transition}]} + sl - {:error, :no_live_callees} -> - {%SL{sl | data: %Sess{data | error: "wamp.error.no_callees_registered"}}, - [{:next_event, :internal, :transition}, {:next_event, :internal, :error}]} + :not_found -> + send_to_peer( + Caller.call_error(%Error{ + request_id: call_id, + error: "wamp.error.no_registration", + details: %{procedure: proc} + }), + tt, + t + ) + + sl end - {:ok, data, actions} + {:ok, data, [{:next_event, :internal, :transition}]} end @impl true @@ -482,22 +501,16 @@ defmodule Wampex.Router.Session do %SL{data: %Sess{proxy: proxy, invocations: inv, yield: {:yield, id, dets, arg_l, arg_kw}}} = data ) do - Logger.info("Handling yield #{id} - #{inspect(arg_kw)}") - - case Enum.find(inv, fn - {_, %Invocation{request_id: ^id}, _} -> true - _ -> false - end) do - {call_id, _, {pid, node}} -> - send( - {proxy, node}, - {%Result{request_id: call_id, arg_list: arg_l, arg_kw: arg_kw, options: dets}, pid} - ) + {call_id, _, {pid, node}} = + Enum.find(inv, fn + {_, %Invocation{request_id: ^id}, _} -> true + _ -> false + end) - nil -> - Logger.error("No invocation in #{inspect(inv)} for #{id} #{inspect(arg_kw)}") - :noop - end + send( + {proxy, node}, + {%Result{request_id: call_id, arg_list: arg_l, arg_kw: arg_kw, options: dets}, pid} + ) inv = Enum.filter(inv, fn @@ -556,7 +569,6 @@ defmodule Wampex.Router.Session do @impl true def handle_info(%Result{} = e, _, %SL{data: %Sess{transport: tt, transport_pid: t}} = data) do - Logger.info("Handling Result #{inspect(e)}") send_to_peer(Dealer.result(e), tt, t) {:ok, data, []} end diff --git a/lib/wampex.ex b/lib/wampex.ex index 7b0565e..bdf7f14 100644 --- a/lib/wampex.ex +++ b/lib/wampex.ex @@ -41,8 +41,8 @@ defmodule Wampex do arg_list :: arg_list(), arg_keyword :: arg_keyword()} @type error :: {:error, reason :: binary()} - | {:error, type :: integer(), error :: binary(), arg_list :: arg_list(), - arg_keyword :: arg_keyword()} + | {:error, type :: integer(), error :: binary(), details :: map(), + arg_list :: arg_list(), arg_keyword :: arg_keyword()} @type messages :: publish() | hello() diff --git a/test/wampex_test.exs b/test/wampex_test.exs index c5b562e..881d88b 100644 --- a/test/wampex_test.exs +++ b/test/wampex_test.exs @@ -281,6 +281,24 @@ defmodule WampexTest do assert_receive {:EXIT, ^pid, :shutdown}, 1000 end + @tag :client + test "caller receives error when calling unknown procedure" do + caller_name = TestCaller + Client.start_link(name: caller_name, session: @session) + + assert {:error, 48, "wamp.error.no_registration", %{"procedure" => "this.should.not.exist"}, + nil, + nil} = + Client.send_request( + caller_name, + Caller.call(%Call{ + procedure: "this.should.not.exist", + arg_list: [1], + arg_kw: %{color: "#FFFFFF"} + }) + ) + end + @tag :client test "callee is invoked and responds and caller gets result" do callee_name = TestCalleeRespond -- 2.45.3