defmodule HeliumElixir.BlockchainApi do
use HTTPoison.Base
require HTTPoison.Retry
alias HTTPoison.Response
alias HTTPoison.Retry
@base_url "https://helium-api.stakejoy.com/v1"
def process_request_url(url) do
@base_url <> url
end
def post(url, body \\ %{}) do
case post(url, Jason.encode!(body), [{"Content-Type", "application/json"}]) do
{:ok, %Response{body: body}} ->
{:ok, body |> Jason.decode!()}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
def get_json(url, params \\ %{}) do
start()
case get(url, [], timeout: 20_000, recv_timeout: 20_000, params: params)
|> Retry.autoretry(
max_attempts: 2,
wait: 15000,
include_404s: true,
retry_unknown_errors: true
) do
{:ok, %Response{body: body, status_code: status_code}} ->
case status_code do
200 ->
{:ok, body |> Jason.decode!()}
_ ->
{:error, status_code}
end
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
# paginates through all entries of a provided url
def paginate_all(url, acc \\ [], cursor \\ nil) do
case get_json(url, %{cursor: cursor}) do
{:ok, %{"data" => data, "cursor" => next_cursor}} ->
paginate_all(url, acc ++ data, next_cursor)
{:ok, %{"data" => data}} ->
{:ok, acc ++ data}
{:error, error} ->
{:error, error}
end
end
# paginates through all entries of a provided url until count
def take(url, count, acc \\ [], cursor \\ nil) do
case get_json(url, %{cursor: cursor}) do
{:ok, %{"data" => data, "cursor" => next_cursor}} ->
next_data = acc ++ data
acc_count = length(next_data)
if(acc_count >= count || is_nil(next_cursor)) do
{:ok, %{"data" => next_data, "cursor" => next_cursor}}
else
take(url, count, next_data, next_cursor)
end
{:ok, %{"data" => data}} ->
{:ok, %{"data" => acc ++ data, "cursor" => ""}}
{:error, error} ->
len = length(acc)
case len do
0 ->
{:error, error}
_ ->
{:ok, %{"data" => acc, "cursor" => cursor}}
end
end
end
def each_page(url, fun, cursor \\ nil) do
case get_json(url, %{cursor: cursor}) do
{:ok, %{"data" => data, "cursor" => next_cursor}} ->
fun.(data)
each_page(url, fun, next_cursor)
{:ok, %{"data" => data}} ->
fun.(data)
:ok
{:error, error} ->
{:error, error}
end
end
# paginates through all entries of a provided url, while fun returns true
def paginate_while(url, fun, params \\ %{}, acc \\ [], cursor \\ nil) do
case get_json(url, Map.merge(params, %{cursor: cursor})) do
{:ok, %{"data" => data, "cursor" => next_cursor}} ->
filtered_data = data |> Enum.take_while(fn d -> fun.(d) end)
if length(filtered_data) == length(data) do
paginate_while(url, fun, params, acc ++ filtered_data, next_cursor)
else
{:ok, acc ++ filtered_data}
end
{:ok, %{"data" => data}} ->
filtered_data = data |> Enum.take_while(fn d -> fun.(d) end)
{:ok, acc ++ filtered_data}
{:error, error} ->
{:error, error}
end
end
# returns the first entry that fun evaluates true for
def paginate_find(url, fun, params \\ %{}, cursor \\ nil) do
case get_json(url, Map.merge(params, %{cursor: cursor})) do
{:ok, %{"data" => data, "cursor" => next_cursor}} ->
case Enum.find(data, fun) do
nil ->
paginate_find(url, fun, params, next_cursor)
found ->
{:ok, found}
end
{:ok, %{"data" => data}} ->
case Enum.find(data, fun) do
nil ->
{:error, :not_found}
found ->
{:ok, found}
end
{:error, error} ->
{:error, error}
end
end
end