Current section

Files

Jump to
glisten src glisten@handler.erl
Raw

src/glisten@handler.erl

-module(glisten@handler).
-compile(no_auto_import).
-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, nil} |
{tcp, gleam@otp@port:port_(), bitstring()} |
{tcp_closed, nil}.
-type loop_state(GSN) :: {loop_state,
glisten@socket:socket(),
gleam@erlang@process:subject(handler_message()),
glisten@socket:transport(),
GSN}.
-type handler(GSS) :: {handler,
glisten@socket:socket(),
GSS,
fun((handler_message(), loop_state(GSS)) -> gleam@otp@actor:next(loop_state(GSS))),
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()}.
-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@process:new_selector(),
_pipe@1 = gleam@erlang@process:selecting(
_pipe,
Subject,
fun gleam@function:identity/1
),
gleam@erlang@process:selecting_anything(
_pipe@1,
fun(Msg) -> case gleam@dynamic:unsafe_coerce(Msg) of
{tcp, _@1, Data} ->
{receive_message, Data};
{ssl, _@1, Data} ->
{receive_message, Data};
Msg@1 ->
Msg@1
end end
)
end,
{ready,
{loop_state,
erlang:element(2, Handler),
Subject,
erlang:element(7, Handler),
erlang:element(3, Handler)},
Selector}
end,
1000,
fun(Msg@2, State) -> case Msg@2 of
{tcp_closed, _@2} ->
Close = case erlang:element(7, Handler) of
ssl ->
fun glisten@ssl:close/1;
tcp ->
fun glisten@tcp:close/1
end,
Close(erlang:element(2, State)),
_@4 = case erlang:element(6, Handler) of
{some, Func} ->
Func(erlang:element(3, State));
_@3 ->
nil
end,
{stop, normal};
{ssl_closed, _@2} ->
Close = case erlang:element(7, Handler) of
ssl ->
fun glisten@ssl:close/1;
tcp ->
fun glisten@tcp:close/1
end,
Close(erlang:element(2, State)),
_@4 = case erlang:element(6, Handler) of
{some, Func} ->
Func(erlang:element(3, State));
_@3 ->
nil
end,
{stop, normal};
close ->
Close = case erlang:element(7, Handler) of
ssl ->
fun glisten@ssl:close/1;
tcp ->
fun glisten@tcp:close/1
end,
Close(erlang:element(2, State)),
_@4 = case erlang:element(6, Handler) of
{some, Func} ->
Func(erlang:element(3, State));
_@3 ->
nil
end,
{stop, normal};
ready ->
{Handshake, Set_opts} = case erlang:element(7, Handler) of
ssl ->
{fun glisten@ssl:handshake/1,
fun glisten@ssl:set_opts/2};
tcp ->
{fun(_) -> {ok, nil} end,
fun glisten@tcp:set_opts/2}
end,
_pipe@2 = erlang:element(2, State),
_pipe@3 = Handshake(_pipe@2),
_pipe@4 = gleam@result:replace_error(
_pipe@3,
<<"Failed to handshake socket"/utf8>>
),
_pipe@5 = gleam@result:map(
_pipe@4,
fun(_) -> _@3 = case erlang:element(5, Handler) of
{some, Func} ->
Func(erlang:element(3, State));
_@2 ->
nil
end end
),
_pipe@7 = gleam@result:then(
_pipe@5,
fun(_) ->
_pipe@6 = Set_opts(
erlang:element(2, State),
[{active_mode, once}]
),
gleam@result:replace_error(
_pipe@6,
<<"Failed to set socket active"/utf8>>
)
end
),
_pipe@8 = gleam@result:replace(_pipe@7, {continue, State}),
_pipe@9 = gleam@result:map_error(
_pipe@8,
fun(Reason) -> {stop, {abnormal, Reason}} end
),
gleam@result:unwrap_both(_pipe@9);
Msg@3 ->
Set_opts@1 = case erlang:element(7, Handler) of
tcp ->
fun glisten@tcp:set_opts/2;
ssl ->
fun glisten@ssl:set_opts/2
end,
case (erlang:element(4, Handler))(Msg@3, State) of
{continue, Next_state} ->
{ok, nil} = case Set_opts@1(
erlang:element(2, State),
[{active_mode, once}]
) of
{ok, nil} -> {ok, nil};
_try ->
erlang:error(#{gleam_error => assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _try,
module => <<"glisten/handler"/utf8>>,
function => <<"start"/utf8>>,
line => 124})
end,
{continue, Next_state};
Msg@4 ->
Msg@4
end
end end}
).
-spec func(
fun((bitstring(), loop_state(GTO)) -> gleam@otp@actor:next(loop_state(GTO)))
) -> fun((handler_message(), loop_state(GTO)) -> gleam@otp@actor:next(loop_state(GTO))).
func(Func) ->
fun(Msg, State) -> case Msg of
{tcp, _@1, _@2} ->
glisten@logger:error(
{<<"Received an unexpected TCP message"/utf8>>, Msg}
),
{continue, State};
ready ->
glisten@logger:error(
{<<"Received an unexpected TCP message"/utf8>>, Msg}
),
{continue, State};
{receive_message, Data} ->
Func(Data, State);
{send_message, Data@1} ->
case glisten@tcp:send(erlang:element(2, State), Data@1) of
{ok, _@1} ->
{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.