Current section
Files
Jump to
Current section
Files
src/glitch@auth@redirect_server.erl
-module(glitch@auth@redirect_server).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([start/1, shutdown/1, new/3]).
-export_type([redirect_server/0, status/0, message/0]).
-opaque redirect_server() :: {state,
binary(),
gleam@erlang@process:subject(binary()),
gleam@option:option(gleam@erlang@process:subject(gleam@otp@supervisor:message())),
gleam@uri:uri(),
status()}.
-type status() :: running | stopped.
-type message() :: shutdown | start.
-spec start(gleam@erlang@process:subject(message())) -> nil.
start(Server) ->
gleam@otp@actor:send(Server, start).
-spec shutdown(gleam@erlang@process:subject(message())) -> nil.
shutdown(Server) ->
gleam@otp@actor:send(Server, shutdown).
-spec make_mist_body(gleam@option:option(binary())) -> mist:response_data().
make_mist_body(Body) ->
_pipe = Body,
_pipe@1 = gleam@option:unwrap(_pipe, <<""/utf8>>),
_pipe@2 = gleam_stdlib:wrap_list(_pipe@1),
{bytes, _pipe@2}.
-spec get_code_and_csrf_token_query_params(gleam@http@request:request(any())) -> {gleam@option:option(binary()),
gleam@option:option(binary())}.
get_code_and_csrf_token_query_params(Req) ->
Query_params = begin
_pipe = gleam@http@request:get_query(Req),
gleam@result:unwrap(_pipe, [])
end,
Code_result = gleam@list:key_find(Query_params, <<"code"/utf8>>),
Csrf_state_result = gleam@list:key_find(Query_params, <<"state"/utf8>>),
{gleam@option:from_result(Code_result),
gleam@option:from_result(Csrf_state_result)}.
-spec bad_request_response(gleam@option:option(binary())) -> gleam@http@response:response(mist:response_data()).
bad_request_response(Message) ->
_pipe = gleam@http@response:new(400),
gleam@http@response:set_body(_pipe, make_mist_body(Message)).
-spec generic_bad_request_response() -> gleam@http@response:response(mist:response_data()).
generic_bad_request_response() ->
bad_request_response(none).
-spec ok_response(gleam@option:option(binary())) -> gleam@http@response:response(mist:response_data()).
ok_response(Body) ->
_pipe = gleam@http@response:new(200),
gleam@http@response:set_body(_pipe, make_mist_body(Body)).
-spec send_response(redirect_server(), binary()) -> fun((any()) -> gleam@http@response:response(mist:response_data())).
send_response(Server, Code) ->
fun(_) ->
gleam@erlang@process:send_after(erlang:element(3, Server), 250, Code),
ok_response(
{some,
<<"Successfully received redirect payload from Twitch."/utf8>>}
)
end.
-spec make_redirect_handler(redirect_server()) -> fun((gleam@http@request:request(mist@internal@http:connection())) -> gleam@http@response:response(mist:response_data())).
make_redirect_handler(Server) ->
Handle_redirect = fun(Req) ->
case get_code_and_csrf_token_query_params(Req) of
{{some, Code}, {some, State}} when State =:= erlang:element(
2,
Server
) ->
_pipe = mist:read_body(Req, 10485760),
_pipe@1 = gleam@result:map(_pipe, send_response(Server, Code)),
gleam@result:lazy_unwrap(
_pipe@1,
fun generic_bad_request_response/0
);
{{some, _}, {some, _}} ->
bad_request_response({some, <<"Invalid csrf state"/utf8>>});
{{some, _}, none} ->
bad_request_response({some, <<"No csrf state received"/utf8>>});
{none, _} ->
bad_request_response({some, <<"No code received"/utf8>>})
end
end,
Handle_redirect.
-spec new_router(redirect_server()) -> fun((gleam@http@request:request(mist@internal@http:connection())) -> gleam@http@response:response(mist:response_data())).
new_router(Server) ->
Redirect_path = erlang:element(6, erlang:element(5, Server)),
Router = fun(Req) ->
case {erlang:element(2, Req), gleam@http@request:path_segments(Req)} of
{get, [Path]} when Path =:= Redirect_path ->
(make_redirect_handler(Server))(Req);
{_, _} ->
_pipe = gleam@http@response:new(404),
gleam@http@response:set_body(
_pipe,
{bytes, gleam@bytes_builder:new()}
)
end
end,
Router.
-spec handle_message(message(), redirect_server()) -> gleam@otp@actor:next(message(), redirect_server()).
handle_message(Message, State) ->
case Message of
shutdown ->
_assert_subject = begin
_pipe = erlang:element(4, State),
_pipe@1 = gleam@option:map(
_pipe,
fun gleam@erlang@process:subject_owner/1
),
gleam@option:map(_pipe@1, fun gleam@erlang@process:kill/1)
end,
{some, nil} = case _assert_subject of
{some, nil} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"glitch/auth/redirect_server"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 50})
end,
{stop, normal};
start ->
Port = gleam@option:unwrap(
erlang:element(5, erlang:element(5, State)),
3000
),
_assert_subject@1 = begin
_pipe@2 = mist:new(new_router(State)),
_pipe@3 = mist:port(_pipe@2, Port),
mist:start_http(_pipe@3)
end,
{ok, Mist_subject} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"glitch/auth/redirect_server"/utf8>>,
function => <<"handle_message"/utf8>>,
line => 60})
end,
gleam@otp@actor:continue(
erlang:setelement(
6,
erlang:setelement(4, State, {some, Mist_subject}),
running
)
)
end.
-spec new(binary(), gleam@erlang@process:subject(binary()), gleam@uri:uri()) -> {ok,
gleam@erlang@process:subject(message())} |
{error, gleam@otp@actor:start_error()}.
new(Csrf_state, Mailbox, Redirect_uri) ->
State = {state, Csrf_state, Mailbox, none, Redirect_uri, stopped},
gleam@otp@actor:start(State, fun handle_message/2).