Packages
glisten
0.6.2
9.0.1
9.0.0
9.0.0-rc1
8.0.3
8.0.2
8.0.1
8.0.0
8.0.0-rc1
7.0.1
7.0.0
6.0.0
5.0.0
4.0.0
3.0.0
2.0.0
1.0.0
0.11.0
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
a shiny Gleam TCP/TLS server
Current section
Files
Jump to
Current section
Files
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.