lib/http_client.ex

defmodule NearApi.HttpClient do
  use HTTPoison.Base
  require Logger
  @retry_attempts 2

  @doc """
  Performs a "method" call to NEAR RPC API
  """
  def api_call_method(payload, method) do
    perform_call(method, payload)
  end

  def process_request_url(url) do
    endpoint_url() <> url
  end

  def process_response_body(body) do
    Jason.decode!(body)
  end

  def process_request_headers(headers) do
    headers ++ ["Content-Type": "application/json"]
  end

  @doc """
  Wraps payload into the NEAR query structure
  """
  def params(method, payload) do
    %{
      id: "dontcare",
      jsonrpc: "2.0",
      method: method,
      params: payload
    }
  end

  defp perform_call(method, payload, retry_attempt \\ 0)

  defp perform_call(method, payload, retry_attempt) when retry_attempt < @retry_attempts do
    params_encoded = NearApi.HttpClient.params(method, payload) |> Jason.encode!()
    recv_timeout = Application.get_env(:near_api, :recv_timeout, 50_000)
    timeout = Application.get_env(:near_api, :timeout, 50_000)

    case NearApi.HttpClient.post("/", params_encoded, [], recv_timeout: recv_timeout, timeout: timeout) do
      {:ok, response} ->
        response.body

      {:error, %HTTPoison.Error{reason: :timeout}} ->
        Logger.warn(
          "#{__MODULE__}: Timeout making a transaciton call: #{inspect({method, payload})}; attempt: #{retry_attempt}"
        )

        perform_call(method, payload, retry_attempt + 1)

      error ->
        error
    end
  end

  defp perform_call(_method, _payload, _retry_attempt) do
    Logger.error("#{__MODULE__}: Aborted retrying calls to NEAR API because of timeouts")
    {:error, :timeouted_after_multiple_retries}
  end

  defp endpoint_url do
    System.get_env("NEAR_NODE_URL")
  end
end