-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.