Current section
Files
Jump to
Current section
Files
src/olive@proxy.erl
-module(olive@proxy).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([start_http/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.
?MODULEDOC(
" The `proxy` module starts the proxy server that redirects to the \"main\" server\n"
" It also injects a websocket connection and handles it, via the `client_registry`\n"
" module, to add / remove them, and send them a websocket message to trigger the\n"
" actual reload of the browser.\n"
).
-file("src/olive/proxy.gleam", 39).
-spec handle_websocket(
gleam@http@request:request(mist@internal@http:connection()),
olive@client_registry:client_registry(),
olive@config:config()
) -> gleam@http@response:response(mist:response_data()).
handle_websocket(Req, Clients, Config) ->
mist:websocket(Req, fun(Client, Conn, Message) -> case Message of
{custom, reload} ->
case mist:send_text_frame(Conn, <<"reload"/utf8>>) of
{ok, _} ->
olive@logging:notice(
erlang:element(2, Config),
<<"Successfully sent reload message to client"/utf8>>
),
gleam@otp@actor:continue(Client);
{error, _} ->
olive@logging:error(
erlang:element(2, Config),
<<"Could not send message to client"/utf8>>
),
{stop, normal}
end;
closed ->
olive@logging:warning(
erlang:element(2, Config),
<<"Client has disconnected unexpectedly"/utf8>>
),
olive@client_registry:remove(Clients, Client),
{stop, normal};
shutdown ->
olive@logging:warning(
erlang:element(2, Config),
<<"Client has disconnected unexpectedly"/utf8>>
),
olive@client_registry:remove(Clients, Client),
{stop, normal};
{text, _} ->
gleam@otp@actor:continue(Client);
{binary, _} ->
gleam@otp@actor:continue(Client)
end end, fun(_) ->
Client@1 = gleam@erlang@process:new_subject(),
olive@client_registry:add(Clients, Client@1),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:selecting(
_pipe,
Client@1,
fun gleam@function:identity/1
)
end,
{Client@1, {some, Selector}}
end, fun(Client@2) ->
olive@client_registry:remove(Clients, Client@2)
end).
-file("src/olive/proxy.gleam", 108).
-spec inject(binary()) -> binary().
inject(Html) ->
_assert_subject = fun gleam_erlang_ffi:priv_directory/1(<<"olive"/utf8>>),
{ok, Priv_dir} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"olive/proxy"/utf8>>,
function => <<"inject"/utf8>>,
line => 109})
end,
_assert_subject@1 = simplifile:read(<<Priv_dir/binary, "/proxy.js"/utf8>>),
{ok, File_content} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"olive/proxy"/utf8>>,
function => <<"inject"/utf8>>,
line => 110})
end,
Script = <<<<"<script>"/utf8, File_content/binary>>/binary,
"</script>"/utf8>>,
_pipe = Html,
gleam@string:replace(
_pipe,
<<"</head>"/utf8>>,
<<Script/binary, "</head>"/utf8>>
).
-file("src/olive/proxy.gleam", 101).
-spec maybe_inject_ws(bitstring()) -> bitstring().
maybe_inject_ws(Response) ->
case gleam@bit_array:to_string(Response) of
{ok, Str} ->
gleam_stdlib:identity(inject(Str));
{error, _} ->
Response
end.
-file("src/olive/proxy.gleam", 87).
-spec handle_request(
olive@config:config(),
gleam@http@request:request(mist@internal@http:connection())
) -> gleam@http@response:response(mist:response_data()).
handle_request(Config, Req) ->
Internal_error = begin
_pipe = gleam@http@response:new(500),
gleam@http@response:set_body(_pipe, {bytes, gleam@bytes_tree:new()})
end,
_assert_subject = mist:read_body(Req, (100 * 1024) * 1024),
{ok, Req@1} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"olive/proxy"/utf8>>,
function => <<"handle_request"/utf8>>,
line => 92})
end,
_pipe@1 = begin
_record = Req@1,
{request,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
{some, erlang:element(3, Config)},
erlang:element(8, _record),
erlang:element(9, _record)}
end,
_pipe@2 = gleam@httpc:send_bits(_pipe@1),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(_capture) ->
gleam@http@response:map(_capture, fun maybe_inject_ws/1)
end
),
_pipe@4 = gleam@result:map(
_pipe@3,
fun(_capture@1) ->
gleam@http@response:map(
_capture@1,
fun gleam@bytes_tree:from_bit_array/1
)
end
),
_pipe@5 = gleam@result:map(
_pipe@4,
fun(_capture@2) ->
gleam@http@response:map(
_capture@2,
fun(Field@0) -> {bytes, Field@0} end
)
end
),
gleam@result:unwrap(_pipe@5, Internal_error).
-file("src/olive/proxy.gleam", 24).
-spec start_http(olive@config:config(), olive@client_registry:client_registry()) -> {ok,
gleam@erlang@process:subject(gleam@otp@supervisor:message())} |
{error, glisten:start_error()}.
start_http(Config, Clients) ->
_pipe = fun(Req) -> case gleam@http@request:path_segments(Req) of
[<<"ws_livereload"/utf8>>] ->
handle_websocket(Req, Clients, Config);
_ ->
handle_request(Config, Req)
end end,
_pipe@1 = mist:new(_pipe),
_pipe@2 = mist:bind(_pipe@1, erlang:element(5, Config)),
_pipe@3 = mist:port(_pipe@2, erlang:element(4, Config)),
mist:start_http(_pipe@3).