Current section
Files
Jump to
Current section
Files
src/gleeth@rpc@client.erl
-module(gleeth@rpc@client).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleeth/rpc/client.gleam").
-export([make_request/3, make_request_with_retry/4, make_batch_request/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/gleeth/rpc/client.gleam", 122).
-spec encode_request(gleeth@rpc@types:json_rpc_request()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
encode_request(Req) ->
Json_object = gleam@json:object(
[{<<"jsonrpc"/utf8>>, gleam@json:string(erlang:element(2, Req))},
{<<"method"/utf8>>, gleam@json:string(erlang:element(3, Req))},
{<<"params"/utf8>>,
gleam@json:array(erlang:element(4, Req), fun(X) -> X end)},
{<<"id"/utf8>>, gleam@json:int(erlang:element(5, Req))}]
),
{ok, gleam@json:to_string(Json_object)}.
-file("src/gleeth/rpc/client.gleam", 185).
-spec parse_url(binary()) -> {ok, {binary(), binary(), binary()}} |
{error, gleeth@rpc@types:gleeth_error()}.
parse_url(Url) ->
case gleam@string:split(Url, <<"://"/utf8>>) of
[Scheme, Rest] ->
case gleam@string:split_once(Rest, <<"/"/utf8>>) of
{ok, {Host, Path}} ->
{ok, {Scheme, Host, <<"/"/utf8, Path/binary>>}};
{error, _} ->
{ok, {Scheme, Rest, <<"/"/utf8>>}}
end;
_ ->
{error,
{invalid_rpc_url,
<<"Invalid URL format - must include scheme (http:// or https://)"/utf8>>}}
end.
-file("src/gleeth/rpc/client.gleam", 137).
-spec send_http_request(binary(), binary()) -> {ok,
gleam@http@response:response(binary())} |
{error, gleeth@rpc@types:gleeth_error()}.
send_http_request(Rpc_url, Body) ->
Req = begin
_pipe = gleam@http@request:new(),
_pipe@1 = gleam@http@request:set_method(_pipe, post),
_pipe@2 = gleam@http@request:set_body(_pipe@1, Body),
_pipe@3 = gleam@http@request:set_header(
_pipe@2,
<<"content-type"/utf8>>,
<<"application/json"/utf8>>
),
gleam@http@request:set_header(
_pipe@3,
<<"user-agent"/utf8>>,
<<"gleeth/1.0"/utf8>>
)
end,
case parse_url(Rpc_url) of
{ok, {Scheme, Host, Path}} ->
Req_with_scheme = case Scheme of
<<"https"/utf8>> ->
gleam@http@request:set_scheme(Req, https);
_ ->
gleam@http@request:set_scheme(Req, http)
end,
Req_with_host = gleam@http@request:set_host(Req_with_scheme, Host),
Req_with_path = gleam@http@request:set_path(Req_with_host, Path),
case gleam@httpc:send(Req_with_path) of
{ok, Response} ->
{ok, Response};
{error, _} ->
{error,
{network_error, <<"Failed to send HTTP request"/utf8>>}}
end;
{error, Err} ->
{error, Err}
end.
-file("src/gleeth/rpc/client.gleam", 15).
-spec make_request(binary(), binary(), list(gleam@json:json())) -> {ok,
binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
make_request(Rpc_url, Method, Params) ->
Json_rpc_request = {json_rpc_request, <<"2.0"/utf8>>, Method, Params, 1},
gleam@result:'try'(
encode_request(Json_rpc_request),
fun(Request_json) ->
gleam@result:'try'(
send_http_request(Rpc_url, Request_json),
fun(Http_response) -> case erlang:element(2, Http_response) of
200 ->
{ok, erlang:element(4, Http_response)};
Status ->
{error,
{network_error,
<<"HTTP request failed with status: "/utf8,
(erlang:integer_to_binary(Status))/binary>>}}
end end
)
end
).
-file("src/gleeth/rpc/client.gleam", 60).
-spec do_request_with_retry(
binary(),
binary(),
list(gleam@json:json()),
integer(),
integer(),
integer(),
integer()
) -> {ok, binary()} | {error, gleeth@rpc@types:gleeth_error()}.
do_request_with_retry(
Rpc_url,
Method,
Params,
Max_retries,
Backoff_ms,
Max_backoff_ms,
Attempt
) ->
Json_rpc_request = {json_rpc_request, <<"2.0"/utf8>>, Method, Params, 1},
case encode_request(Json_rpc_request) of
{error, E} ->
{error, E};
{ok, Request_json} ->
case send_http_request(Rpc_url, Request_json) of
{ok, Http_response} ->
case erlang:element(2, Http_response) of
200 ->
{ok, erlang:element(4, Http_response)};
429 when Attempt < Max_retries ->
gleam_erlang_ffi:sleep(Backoff_ms),
Next_backoff = gleam@int:min(
Backoff_ms * 2,
Max_backoff_ms
),
do_request_with_retry(
Rpc_url,
Method,
Params,
Max_retries,
Next_backoff,
Max_backoff_ms,
Attempt + 1
);
503 when Attempt < Max_retries ->
gleam_erlang_ffi:sleep(Backoff_ms),
Next_backoff = gleam@int:min(
Backoff_ms * 2,
Max_backoff_ms
),
do_request_with_retry(
Rpc_url,
Method,
Params,
Max_retries,
Next_backoff,
Max_backoff_ms,
Attempt + 1
);
Status ->
{error,
{network_error,
<<"HTTP request failed with status: "/utf8,
(erlang:integer_to_binary(Status))/binary>>}}
end;
{error, _} when Attempt < Max_retries ->
gleam_erlang_ffi:sleep(Backoff_ms),
Next_backoff@1 = gleam@int:min(
Backoff_ms * 2,
Max_backoff_ms
),
do_request_with_retry(
Rpc_url,
Method,
Params,
Max_retries,
Next_backoff@1,
Max_backoff_ms,
Attempt + 1
);
{error, E@1} ->
{error, E@1}
end
end.
-file("src/gleeth/rpc/client.gleam", 43).
?DOC(
" Make a JSON-RPC request with automatic retry on transient errors.\n"
" Retries on HTTP 429 (rate limited), 503 (service unavailable), and\n"
" connection failures, using exponential backoff from the retry config.\n"
).
-spec make_request_with_retry(
binary(),
binary(),
list(gleam@json:json()),
gleeth@provider:retry_config()
) -> {ok, binary()} | {error, gleeth@rpc@types:gleeth_error()}.
make_request_with_retry(Rpc_url, Method, Params, Retry_config) ->
do_request_with_retry(
Rpc_url,
Method,
Params,
erlang:element(2, Retry_config),
erlang:element(3, Retry_config),
erlang:element(4, Retry_config),
0
).
-file("src/gleeth/rpc/client.gleam", 170).
?DOC(
" Send a batch of JSON-RPC requests in a single HTTP call.\n"
" The body should be a JSON array of request objects.\n"
" Returns the raw response body (a JSON array of responses).\n"
).
-spec make_batch_request(binary(), binary()) -> {ok, binary()} |
{error, gleeth@rpc@types:gleeth_error()}.
make_batch_request(Rpc_url, Batch_body) ->
gleam@result:'try'(
send_http_request(Rpc_url, Batch_body),
fun(Http_response) -> case erlang:element(2, Http_response) of
200 ->
{ok, erlang:element(4, Http_response)};
Status ->
{error,
{network_error,
<<"HTTP request failed with status: "/utf8,
(erlang:integer_to_binary(Status))/binary>>}}
end end
).