defmodule Chaperon.Action.WebSocket.ReceiveMessage do @moduledoc """ WebSocket action to receive message in a WebSocket-connected session. """ defstruct options: [], decode: nil, callback: nil @type t :: %__MODULE__{ options: [any], callback: Chaperon.Session.result_callback() } end defimpl Chaperon.Actionable, for: Chaperon.Action.WebSocket.ReceiveMessage do import Chaperon.Timing import Chaperon.Action.WebSocket.ReceiveMessage import Chaperon.Session use Chaperon.Session.Logging alias Chaperon.Action.WebSocket def run(action, session) do {socket, ws_url} = session |> WebSocket.for_action(action) session |> log_debug("WS_RECV #{ws_url} on socket #{inspect(socket)}") start = timestamp() case WebSocket.Client.recv_message(socket, action.options[:timeout]) do {:binary, message} -> session |> log_debug("WS_RECV binary (#{byte_size(message)} bytes)") |> handle_message(action, message, start) {:text, message} -> session |> log_debug("WS_RECV: #{message}") |> handle_message(action, message, start) {:error, {:timeout, timeout}} -> session |> log_error("WS_RECV timeout: #{timeout}") |> run_error_callback(action, {:timeout, timeout}) |> error({:timeout, timeout}, action) other -> session |> log_warn("WS_RECV unexpected message: #{inspect(other)}") |> ok end end def handle_message( session, action, message, start_time ) do {_, ws_url} = session |> WebSocket.for_action(action) dt = timestamp() - start_time session |> add_ws_result(action, message) |> add_metric(:ws_recv, dt) |> add_metric({:ws_recv, ws_url}, dt) |> run_callback(action, message) |> ok end def abort(action, session) do {:ok, action, session} end end defimpl String.Chars, for: Chaperon.Action.WebSocket.ReceiveMessage do def to_string(%{options: []}), do: "WS-Recv" def to_string(%{options: opts}), do: "WS-Recv#{inspect(opts)}" end