Current section

Files

Jump to
glisten src glisten@handler.erl
Raw

src/glisten@handler.erl

-module(glisten@handler).
-compile([no_auto_import, nowarn_unused_vars]).
-export([start/1, func/1]).
-export_type([handler_message/0, loop_state/1, handler/1]).
-type handler_message() :: close |
ready |
{receive_message, bitstring()} |
{send_message, gleam@bit_builder:bit_builder()} |
{ssl, gleam@otp@port:port_(), bitstring()} |
ssl_closed |
{tcp, gleam@otp@port:port_(), bitstring()} |
tcp_closed.
-type loop_state(HEC) :: {loop_state,
{ok, {{integer(), integer(), integer(), integer()}, integer()}} |
{error, nil},
glisten@socket:socket(),
gleam@erlang@process:subject(handler_message()),
glisten@socket@transport:transport(),
HEC}.
-type handler(HED) :: {handler,
glisten@socket:socket(),
HED,
fun((handler_message(), loop_state(HED)) -> gleam@otp@actor:next(handler_message(), loop_state(HED))),
gleam@option:option(fun((gleam@erlang@process:subject(handler_message())) -> nil)),
gleam@option:option(fun((gleam@erlang@process:subject(handler_message())) -> nil)),
glisten@socket@transport:transport()}.
-spec start(handler(any())) -> {ok,
gleam@erlang@process:subject(handler_message())} |
{error, gleam@otp@actor:start_error()}.
start(Handler) ->
gleam@otp@actor:start_spec(
{spec,
fun() ->
Subject = gleam@erlang@process:new_subject(),
Selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
_pipe@4 = gleam@erlang@process:selecting_record3(
_pipe,
erlang:binary_to_atom(<<"tcp"/utf8>>),
fun(_, Data) -> _pipe@1 = Data,
_pipe@2 = gleam@dynamic:bit_string(_pipe@1),
_pipe@3 = gleam@result:unwrap(_pipe@2, <<>>),
{receive_message, _pipe@3} end
),
_pipe@8 = gleam@erlang@process:selecting_record3(
_pipe@4,
erlang:binary_to_atom(<<"ssl"/utf8>>),
fun(_, Data@1) -> _pipe@5 = Data@1,
_pipe@6 = gleam@dynamic:bit_string(_pipe@5),
_pipe@7 = gleam@result:unwrap(_pipe@6, <<>>),
{receive_message, _pipe@7} end
),
_pipe@9 = gleam@erlang@process:selecting_record2(
_pipe@8,
erlang:binary_to_atom(<<"ssl_closed"/utf8>>),
fun(_) -> ssl_closed end
),
_pipe@10 = gleam@erlang@process:selecting_record2(
_pipe@9,
erlang:binary_to_atom(<<"tcp_closed"/utf8>>),
fun(_) -> tcp_closed end
),
gleam@erlang@process:selecting(
_pipe@10,
Subject,
fun gleam@function:identity/1
)
end,
{ready,
{loop_state,
(erlang:element(9, erlang:element(7, Handler)))(
erlang:element(2, Handler)
),
erlang:element(2, Handler),
Subject,
erlang:element(7, Handler),
erlang:element(3, Handler)},
Selector}
end,
1000,
fun(Msg, State) -> case Msg of
tcp_closed ->
case (erlang:element(4, erlang:element(5, State)))(
erlang:element(3, State)
) of
{ok, nil} ->
_ = case erlang:element(6, Handler) of
{some, On_close} ->
On_close(erlang:element(4, State));
_ ->
nil
end,
{stop, normal};
{error, Err} ->
{stop, {abnormal, gleam@string:inspect(Err)}}
end;
ssl_closed ->
case (erlang:element(4, erlang:element(5, State)))(
erlang:element(3, State)
) of
{ok, nil} ->
_ = case erlang:element(6, Handler) of
{some, On_close} ->
On_close(erlang:element(4, State));
_ ->
nil
end,
{stop, normal};
{error, Err} ->
{stop, {abnormal, gleam@string:inspect(Err)}}
end;
close ->
case (erlang:element(4, erlang:element(5, State)))(
erlang:element(3, State)
) of
{ok, nil} ->
_ = case erlang:element(6, Handler) of
{some, On_close} ->
On_close(erlang:element(4, State));
_ ->
nil
end,
{stop, normal};
{error, Err} ->
{stop, {abnormal, gleam@string:inspect(Err)}}
end;
ready ->
_pipe@11 = erlang:element(3, State),
_pipe@12 = (erlang:element(6, erlang:element(5, State)))(
_pipe@11
),
_pipe@13 = gleam@result:replace_error(
_pipe@12,
<<"Failed to handshake socket"/utf8>>
),
_pipe@14 = gleam@result:map(
_pipe@13,
fun(_) -> _ = case erlang:element(5, Handler) of
{some, On_init} ->
On_init(erlang:element(4, State));
_ ->
nil
end end
),
_pipe@16 = gleam@result:then(
_pipe@14,
fun(_) ->
_pipe@15 = (erlang:element(
13,
erlang:element(5, State)
))(
erlang:element(3, State),
[{active_mode, once}]
),
gleam@result:replace_error(
_pipe@15,
<<"Failed to set socket active"/utf8>>
)
end
),
_pipe@17 = gleam@result:replace(
_pipe@16,
gleam@otp@actor:continue(State)
),
_pipe@18 = gleam@result:map_error(
_pipe@17,
fun(Reason) -> {stop, {abnormal, Reason}} end
),
gleam@result:unwrap_both(_pipe@18);
Msg@1 ->
case (erlang:element(4, Handler))(Msg@1, State) of
{continue, Next_state, Selector@1} ->
_assert_subject = (erlang:element(
13,
erlang:element(5, State)
))(
erlang:element(3, State),
[{active_mode, once}]
),
{ok, nil} = case _assert_subject of
{ok, nil} -> _assert_subject;
_assert_fail ->
erlang:error(
#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"glisten/handler"/utf8>>,
function => <<"start"/utf8>>,
line => 143}
)
end,
{continue, Next_state, Selector@1};
Msg@2 ->
Msg@2
end
end end}
).
-spec func(
fun((bitstring(), loop_state(HEW)) -> gleam@otp@actor:next(handler_message(), loop_state(HEW)))
) -> fun((handler_message(), loop_state(HEW)) -> gleam@otp@actor:next(handler_message(), loop_state(HEW))).
func(Func) ->
fun(Msg, State) -> case Msg of
{tcp, _, _} ->
glisten@logger:error(
{<<"Received an unexpected TCP message"/utf8>>, Msg}
),
gleam@otp@actor:continue(State);
ready ->
glisten@logger:error(
{<<"Received an unexpected TCP message"/utf8>>, Msg}
),
gleam@otp@actor:continue(State);
{receive_message, Data} ->
Func(Data, State);
{send_message, Data@1} ->
case (erlang:element(12, erlang:element(5, State)))(
erlang:element(3, State),
Data@1
) of
{ok, _} ->
gleam@otp@actor:continue(State);
{error, Reason} ->
glisten@logger:error(
{<<"Failed to send data"/utf8>>, Reason}
),
{stop, {abnormal, <<"Failed to send data"/utf8>>}}
end;
Msg@1 ->
glisten@logger:error({<<"Unhandled TCP message"/utf8>>, Msg@1}),
{stop, {abnormal, <<"Unhandled TCP message"/utf8>>}}
end end.