Current section
Files
Jump to
Current section
Files
src/shot_utils.erl
-module(shot_utils).
%%% ==================================================================
%%% API
%%% ==================================================================
-export([
to_binary/1,
get_code/1,
get_body/1,
redirect/1,
catch_redirect/1,
http/1,
multipart/1
]).
%%% ==================================================================
%%% Includes
%%% ==================================================================
-include("shot.hrl").
%%% ==================================================================
%%% Public functions
%%% ==================================================================
%% -------------------------------------------------------------------
%% @doc
%% httpc request without headers
%% @end
%% -------------------------------------------------------------------
-spec http(Params :: maps:map()) -> {ok, Result :: tuple()} | {error, Reason :: tuple()}.
http(#{m := post, u := URL}) -> httpc:request(post, {URL, [], [], []}, [], []);
http(#{m := Method, u := URL}) -> httpc:request(Method, {URL, []}, [?NO_REDIRECT], []).
%% -------------------------------------------------------------------
%% @doc
%% httpc request for upload file
%% #{m := method, u := "URL", p := "Path2File", o := Ops, cd := "Content-Disposition", ct := "Content-Type"}
%% @end
%% -------------------------------------------------------------------
multipart(#{m := M, u := U, p := P, o := O, cd := CD, ct := CT}) when M =:= post; M =:= put ->
case file:read_file(P) of
{ok, Bin} ->
Data = binary_to_list(Bin),
ReqBody = form_data(fname(P), Data, CD, CT),
ContentType = lists:concat(["multipart/form-data; boundary=", ?BOUNDARY]),
ReqHeader = [{"Content-Length", integer_to_list(length(ReqBody))}],
httpc:request(M, {U, ReqHeader, ContentType, ReqBody}, O, []);
_ -> {error, <<"Cannot find file">>}
end;
multipart(_) -> {error, <<"Shot Error: The method not allowed">>}.
%% -------------------------------------------------------------------
%% @doc
%% Returns HTTP response code.
%% @end
%% -------------------------------------------------------------------
-spec get_code(HttpcResult :: tuple()) -> Code :: pos_integer().
get_code({{_, Code, _}, _, _}) -> Code.
%% -------------------------------------------------------------------
%% @doc
%% Returns HTTP response body.
%% @end
%% -------------------------------------------------------------------
-spec get_body(HttpcResult :: tuple()) -> Body :: list().
get_body({_, _, Body}) -> Body.
%% -------------------------------------------------------------------
%% @doc
%% Catch redirect and GET response from redirect URL
%% > {_, Resp1} = shot_utils:http(get, "http://google.com").
%% > {_, Resp2} = shot_utils:redirect(Resp).
%% @end
%% -------------------------------------------------------------------
-spec redirect(HttpcResult :: tuple()) -> {ok, Result :: tuple()} | {error, Reason :: tuple()}.
redirect({{_, 301, _}, Headers, _}) -> http(#{m => get, u => proplists:get_value("location", Headers)}).
%% -------------------------------------------------------------------
%% @doc
%% Catch redirect URL
%% @end
%% -------------------------------------------------------------------
-spec catch_redirect(HttpcResult :: tuple()) -> Result :: tuple() | list().
catch_redirect({{_, 301, _}, Headers, _} = Resp) -> proplists:get_value("location", Headers, Resp);
catch_redirect(Resp) -> Resp.
%% -------------------------------------------------------------------
%% @doc
%% Convert any to binary
%% @end
%% -------------------------------------------------------------------
-spec to_binary(Data) -> Result :: binary() when Data :: atom() | list() | binary().
to_binary(Data) when is_binary(Data) -> Data;
to_binary(Data) when is_atom(Data) -> list_to_binary(atom_to_list(Data));
to_binary(Data) when is_list(Data) -> list_to_binary([to_binary(El) || El <- Data]);
to_binary(Data) when is_integer(Data) -> integer_to_binary(Data);
to_binary(Data) when is_tuple(Data) -> to_binary([to_binary(El) || El <- tuple_to_list(Data)]);
to_binary(Data) when is_map(Data) -> to_binary([to_binary(El) || El <- maps:to_list(Data)]).
%%% ==================================================================
%%% Internal/Private functions
%%% ==================================================================
%% -------------------------------------------------------------------
%% @private
%% @doc
%% Prepare Multipart Form Data
%% @end
%% -------------------------------------------------------------------
-spec form_data(Fname :: list(), Data :: list(), CD :: list(), CT :: list()) -> Result :: string().
form_data(Fname, Data, CD, CT) ->
string:join([
lists:concat(["--", ?BOUNDARY]),
lists:concat(["Content-Disposition: ", CD, ";", "name=", Fname]),
lists:concat(["Content-Type: ", CT]),
"",
Data,
lists:concat(["--", ?BOUNDARY, "--"])
], "\r\n").
%% -------------------------------------------------------------------
%% @private
%% @doc
%% Prepare Multipart Form Data
%% @end
%% -------------------------------------------------------------------
-spec fname(Path :: list()) -> Fname :: list().
fname(Path) ->
L = binary:split(list_to_binary(Path), <<"/">>, [global]),
[H|_] = lists:reverse(L),
binary_to_list(H).