Packages
glisten
9.0.1
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@internal@handler.erl
-module(glisten@internal@handler).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glisten/internal/handler.gleam").
-export([continue/1, with_selector/2, stop/0, stop_abnormal/1, start/1]).
-export_type([internal_message/0, message/1, loop_message/1, loop_state/2, connection/1, next/2, handler/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(false).
-type internal_message() :: close |
ready |
{receive_message, bitstring()} |
closed |
passive |
{socket_error, glisten@socket:socket_reason()}.
-type message(FRA) :: {internal, internal_message()} | {user, FRA}.
-type loop_message(FRB) :: {packet, bitstring()} | {custom, FRB}.
-type loop_state(FRC, FRD) :: {loop_state,
{ok, {glisten@socket@options:ip_address(), integer()}} | {error, nil},
glisten@socket:socket(),
gleam@erlang@process:subject(message(FRD)),
glisten@transport:transport(),
FRC}.
-type connection(FRE) :: {connection,
{ok, {glisten@socket@options:ip_address(), integer()}} | {error, nil},
glisten@socket:socket(),
glisten@transport:transport(),
gleam@erlang@process:subject(message(FRE))}.
-type next(FRF, FRG) :: {continue,
FRF,
gleam@option:option(gleam@erlang@process:selector(FRG))} |
normal_stop |
{abnormal_stop, binary()}.
-type handler(FRH, FRI) :: {handler,
glisten@socket:socket(),
fun((FRH, loop_message(FRI), connection(FRI)) -> next(FRH, loop_message(FRI))),
fun((connection(FRI)) -> {FRH,
gleam@option:option(gleam@erlang@process:selector(FRI))}),
gleam@option:option(fun((FRH) -> nil)),
glisten@transport:transport(),
glisten@socket@options:active_state()}.
-file("src/glisten/internal/handler.gleam", 65).
?DOC(false).
-spec continue(FRV) -> next(FRV, any()).
continue(State) ->
{continue, State, none}.
-file("src/glisten/internal/handler.gleam", 69).
?DOC(false).
-spec with_selector(next(FRZ, FSA), gleam@erlang@process:selector(FSA)) -> next(FRZ, FSA).
with_selector(Next, Selector) ->
case Next of
{continue, State, _} ->
{continue, State, {some, Selector}};
Stop ->
Stop
end.
-file("src/glisten/internal/handler.gleam", 79).
?DOC(false).
-spec stop() -> next(any(), any()).
stop() ->
normal_stop.
-file("src/glisten/internal/handler.gleam", 83).
?DOC(false).
-spec stop_abnormal(binary()) -> next(any(), any()).
stop_abnormal(Reason) ->
{abnormal_stop, Reason}.
-file("src/glisten/internal/handler.gleam", 104).
?DOC(false).
-spec start(handler(any(), FSP)) -> {ok,
gleam@otp@actor:started(gleam@erlang@process:subject(message(FSP)))} |
{error, gleam@otp@actor:start_error()}.
start(Handler) ->
_pipe@18 = gleam@otp@actor:new_with_initialiser(
1000,
fun(Subject) ->
Client_ip = begin
_pipe = glisten@transport:peername(
erlang:element(6, Handler),
erlang:element(2, Handler)
),
gleam@result:replace_error(_pipe, nil)
end,
Connection = {connection,
Client_ip,
erlang:element(2, Handler),
erlang:element(6, Handler),
Subject},
{Initial_state, User_selector} = (erlang:element(4, Handler))(
Connection
),
Base_selector = begin
_pipe@1 = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:select(_pipe@1, Subject)
end,
Selector = begin
_pipe@2 = gleam_erlang_ffi:new_selector(),
_pipe@3 = gleam@erlang@process:select_record(
_pipe@2,
erlang:binary_to_atom(<<"tcp"/utf8>>),
2,
fun(Record) ->
{receive_message, glisten_ffi:socket_data(Record)}
end
),
_pipe@4 = gleam@erlang@process:select_record(
_pipe@3,
erlang:binary_to_atom(<<"ssl"/utf8>>),
2,
fun(Record@1) ->
{receive_message, glisten_ffi:socket_data(Record@1)}
end
),
_pipe@5 = gleam@erlang@process:select_record(
_pipe@4,
erlang:binary_to_atom(<<"ssl_closed"/utf8>>),
1,
fun(_) -> closed end
),
_pipe@6 = gleam@erlang@process:select_record(
_pipe@5,
erlang:binary_to_atom(<<"tcp_closed"/utf8>>),
1,
fun(_) -> closed end
),
_pipe@7 = gleam@erlang@process:select_record(
_pipe@6,
erlang:binary_to_atom(<<"ssl_passive"/utf8>>),
1,
fun(_) -> passive end
),
_pipe@8 = gleam@erlang@process:select_record(
_pipe@7,
erlang:binary_to_atom(<<"tcp_passive"/utf8>>),
1,
fun(_) -> passive end
),
_pipe@9 = gleam@erlang@process:select_record(
_pipe@8,
erlang:binary_to_atom(<<"tcp_error"/utf8>>),
2,
fun(Record@2) ->
{socket_error, glisten_ffi:socket_data(Record@2)}
end
),
_pipe@10 = gleam@erlang@process:select_record(
_pipe@9,
erlang:binary_to_atom(<<"ssl_error"/utf8>>),
2,
fun(Record@3) ->
{socket_error, glisten_ffi:socket_data(Record@3)}
end
),
_pipe@11 = gleam_erlang_ffi:map_selector(
_pipe@10,
fun(Field@0) -> {internal, Field@0} end
),
gleam_erlang_ffi:merge_selector(_pipe@11, Base_selector)
end,
Selector@1 = case User_selector of
{some, Sel} ->
_pipe@12 = Sel,
_pipe@13 = gleam_erlang_ffi:map_selector(
_pipe@12,
fun(Field@0) -> {user, Field@0} end
),
gleam_erlang_ffi:merge_selector(Selector, _pipe@13);
_ ->
Selector
end,
_pipe@14 = {loop_state,
Client_ip,
erlang:element(2, Handler),
Subject,
erlang:element(6, Handler),
Initial_state},
_pipe@15 = gleam@otp@actor:initialised(_pipe@14),
_pipe@16 = gleam@otp@actor:selecting(_pipe@15, Selector@1),
_pipe@17 = gleam@otp@actor:returning(_pipe@16, Subject),
{ok, _pipe@17}
end
),
_pipe@19 = gleam@otp@actor:on_message(
_pipe@18,
fun(State, Msg) ->
Connection@1 = {connection,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(5, State),
erlang:element(4, State)},
case Msg of
{internal, closed} ->
case glisten@transport:close(
erlang:element(5, State),
erlang:element(3, State)
) of
{ok, nil} ->
_ = case erlang:element(5, Handler) of
{some, On_close} ->
On_close(erlang:element(6, State));
_ ->
nil
end,
gleam@otp@actor:stop();
{error, Err} ->
gleam@otp@actor:stop_abnormal(
glisten@socket:reason_to_string(Err)
)
end;
{internal, close} ->
case glisten@transport:close(
erlang:element(5, State),
erlang:element(3, State)
) of
{ok, nil} ->
_ = case erlang:element(5, Handler) of
{some, On_close} ->
On_close(erlang:element(6, State));
_ ->
nil
end,
gleam@otp@actor:stop();
{error, Err} ->
gleam@otp@actor:stop_abnormal(
glisten@socket:reason_to_string(Err)
)
end;
{internal, ready} ->
case glisten@transport:handshake(
erlang:element(5, State),
erlang:element(3, State)
) of
{error, _} ->
gleam@otp@actor:stop_abnormal(
<<"Failed to handshake socket"/utf8>>
);
{ok, _} ->
case glisten@transport:set_buffer_size(
erlang:element(5, State),
erlang:element(3, State)
) of
{ok, _} ->
nil;
{error, _} ->
logging:log(
warning,
<<"Failed to read `recbuf` size"/utf8>>
)
end,
Options = [{active_mode, erlang:element(7, Handler)}],
case glisten@transport:set_opts(
erlang:element(5, State),
erlang:element(3, State),
Options
) of
{ok, _} ->
gleam@otp@actor:continue(State);
{error, _} ->
gleam@otp@actor:stop_abnormal(
<<"Failed to set socket active"/utf8>>
)
end
end;
{user, Msg@1} ->
Msg@2 = {custom, Msg@1},
Res = glisten_ffi:rescue(
fun() ->
(erlang:element(3, Handler))(
erlang:element(6, State),
Msg@2,
Connection@1
)
end
),
case Res of
{ok, {continue, Next_state, _}} when erlang:element(
7,
Handler
) =:= once ->
case glisten@transport:set_opts(
erlang:element(5, State),
erlang:element(3, State),
[{active_mode, once}]
) of
{ok, nil} ->
gleam@otp@actor:continue(
{loop_state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
Next_state}
);
{error, _} ->
gleam@otp@actor:stop()
end;
{ok, {continue, Next_state@1, _}} ->
gleam@otp@actor:continue(
{loop_state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
Next_state@1}
);
{ok, normal_stop} ->
gleam@otp@actor:stop();
{ok, {abnormal_stop, Reason}} ->
gleam@otp@actor:stop_abnormal(Reason);
{error, Reason@1} ->
logging:log(
error,
<<"Caught error in user handler: "/utf8,
(gleam@string:inspect(Reason@1))/binary>>
),
gleam@otp@actor:continue(State)
end;
{internal, {receive_message, Msg@3}} ->
Msg@4 = {packet, Msg@3},
Res@1 = glisten_ffi:rescue(
fun() ->
(erlang:element(3, Handler))(
erlang:element(6, State),
Msg@4,
Connection@1
)
end
),
case Res@1 of
{ok, {continue, Next_state@2, _}} when erlang:element(
7,
Handler
) =:= once ->
case glisten@transport:set_opts(
erlang:element(5, State),
erlang:element(3, State),
[{active_mode, once}]
) of
{ok, nil} ->
gleam@otp@actor:continue(
{loop_state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
Next_state@2}
);
{error, _} ->
gleam@otp@actor:stop()
end;
{ok, {continue, Next_state@3, _}} ->
gleam@otp@actor:continue(
{loop_state,
erlang:element(2, State),
erlang:element(3, State),
erlang:element(4, State),
erlang:element(5, State),
Next_state@3}
);
{ok, normal_stop} ->
gleam@otp@actor:stop();
{ok, {abnormal_stop, Reason@2}} ->
gleam@otp@actor:stop_abnormal(Reason@2);
{error, Reason@3} ->
logging:log(
error,
<<"Caught error in user handler: "/utf8,
(gleam@string:inspect(Reason@3))/binary>>
),
gleam@otp@actor:continue(State)
end;
{internal, passive} ->
Options@1 = [{active_mode, erlang:element(7, Handler)}],
case glisten@transport:set_opts(
erlang:element(5, State),
erlang:element(3, State),
Options@1
) of
{ok, _} ->
gleam@otp@actor:continue(State);
{error, _} ->
gleam@otp@actor:stop_abnormal(
<<"Failed to set socket active"/utf8>>
)
end;
{internal, {socket_error, Reason@4}} ->
gleam@otp@actor:stop_abnormal(
<<"Received socket error "/utf8,
(glisten@socket:reason_to_string(Reason@4))/binary>>
)
end
end
),
gleam@otp@actor:start(_pipe@19).