Packages
The shared sans-io core of the gleam-atproto client packages: XRPC error vocabulary and response handling, plus the OAuth effect kernel.
Current section
Files
Jump to
Current section
Files
src/atproto_core@xrpc.erl
-module(atproto_core@xrpc).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/atproto_core/xrpc.gleam").
-export([transport_error_to_string/1, describe/1, parse/2, check_ok/1, check_ok_bits/1]).
-export_type([transport_error/0, xrpc_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" The target-agnostic XRPC vocabulary shared by every client package:\n"
" transport and XRPC error types, response checking, and JSON body\n"
" parsing. Sync and async clients (`atproto_client`, `atproto_browser`)\n"
" wrap their own `send` functions around these.\n"
).
-type transport_error() :: {invalid_url, binary()} |
timeout |
{connection_failed, binary()} |
{other, binary()}.
-type xrpc_error() :: {request_failed, transport_error()} |
{bad_status,
integer(),
gleam@option:option(binary()),
gleam@option:option(binary()),
binary()} |
{decode_failed, binary()}.
-file("src/atproto_core/xrpc.gleam", 26).
?DOC(" A one-line human-readable rendering of a transport error.\n").
-spec transport_error_to_string(transport_error()) -> binary().
transport_error_to_string(Error) ->
case Error of
{invalid_url, Url} ->
<<"invalid url: "/utf8, Url/binary>>;
timeout ->
<<"timed out"/utf8>>;
{connection_failed, Detail} ->
<<"connection failed: "/utf8, Detail/binary>>;
{other, Detail@1} ->
Detail@1
end.
-file("src/atproto_core/xrpc.gleam", 50).
?DOC(" A one-line human-readable rendering of an error, for CLI and log output.\n").
-spec describe(xrpc_error()) -> binary().
describe(Error) ->
case Error of
{request_failed, E} ->
<<"request failed: "/utf8, (transport_error_to_string(E))/binary>>;
{bad_status, Status, Code, Message, _} ->
<<<<<<"HTTP "/utf8, (gleam@string:inspect(Status))/binary>>/binary,
(begin
_pipe = gleam@option:map(
Code,
fun(C) -> <<" "/utf8, C/binary>> end
),
gleam@option:unwrap(_pipe, <<""/utf8>>)
end)/binary>>/binary,
(begin
_pipe@1 = gleam@option:map(
Message,
fun(M) -> <<": "/utf8, M/binary>> end
),
gleam@option:unwrap(_pipe@1, <<""/utf8>>)
end)/binary>>;
{decode_failed, E@1} ->
<<"decode failed: "/utf8, E@1/binary>>
end.
-file("src/atproto_core/xrpc.gleam", 63).
?DOC(" Decode a JSON response body, wrapping decode failures as `DecodeFailed`.\n").
-spec parse(binary(), gleam@dynamic@decode:decoder(EQS)) -> {ok, EQS} |
{error, xrpc_error()}.
parse(Body, Decoder) ->
_pipe = gleam@json:parse(Body, Decoder),
gleam@result:map_error(
_pipe,
fun(E) -> {decode_failed, gleam@string:inspect(E)} end
).
-file("src/atproto_core/xrpc.gleam", 96).
-spec parse_error(binary()) -> {gleam@option:option(binary()),
gleam@option:option(binary())}.
parse_error(Body) ->
Decoder = begin
gleam@dynamic@decode:optional_field(
<<"error"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
fun(Error) ->
gleam@dynamic@decode:optional_field(
<<"message"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
fun(Message) ->
gleam@dynamic@decode:success({Error, Message})
end
)
end
)
end,
_pipe = gleam@json:parse(Body, Decoder),
gleam@result:unwrap(_pipe, {none, none}).
-file("src/atproto_core/xrpc.gleam", 70).
?DOC(
" Turn a received response into a `Result`: `Ok` on 2xx, else a `BadStatus`\n"
" with the atproto `error`/`message` parsed out of the body when present.\n"
).
-spec check_ok(gleam@http@response:response(binary())) -> {ok,
gleam@http@response:response(binary())} |
{error, xrpc_error()}.
check_ok(Resp) ->
case (erlang:element(2, Resp) >= 200) andalso (erlang:element(2, Resp) < 300) of
true ->
{ok, Resp};
false ->
{Error, Message} = parse_error(erlang:element(4, Resp)),
{error,
{bad_status,
erlang:element(2, Resp),
Error,
Message,
erlang:element(4, Resp)}}
end.
-file("src/atproto_core/xrpc.gleam", 82).
?DOC(
" `check_ok` for byte-bodied responses (blob and image downloads); the\n"
" error body on a bad status is decoded leniently for the message.\n"
).
-spec check_ok_bits(gleam@http@response:response(bitstring())) -> {ok,
gleam@http@response:response(bitstring())} |
{error, xrpc_error()}.
check_ok_bits(Resp) ->
case (erlang:element(2, Resp) >= 200) andalso (erlang:element(2, Resp) < 300) of
true ->
{ok, Resp};
false ->
Body = begin
_pipe = gleam@bit_array:to_string(erlang:element(4, Resp)),
gleam@result:unwrap(_pipe, <<"<binary body>"/utf8>>)
end,
{Error, Message} = parse_error(Body),
{error, {bad_status, erlang:element(2, Resp), Error, Message, Body}}
end.