-module(ewe@internal@handler). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/ewe/internal/handler.gleam"). -export([init/1, loop/3]). -export_type([next/0, glisten_message/0, glisten_state/0]). -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 next() :: {continue, glisten_state()} | stop. -type glisten_message() :: idle_timeout. -type glisten_state() :: {glisten_state, gleam@option:option(gleam@erlang@process:timer()), gleam@erlang@process:subject(glisten_message())}. -file("src/ewe/internal/handler.gleam", 51). ?DOC(false). -spec init(any()) -> {glisten_state(), gleam@option:option(gleam@erlang@process:selector(glisten_message()))}. init(_) -> Subject = gleam@erlang@process:new_subject(), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:select(_pipe, Subject) end, {{glisten_state, none, Subject}, {some, Selector}}. -file("src/ewe/internal/handler.gleam", 160). ?DOC(false). -spec handle_resp_file( gleam@http@request:request(ewe@internal@http:connection()), gleam@http@response:response(ewe@internal@http:response_body()), ewe@internal@file:io_device(), integer() ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. handle_resp_file(Req, Resp, Descriptor, Size) -> Http_version@1 = case erlang:element(5, erlang:element(4, Req)) of {some, Http_version} -> Http_version; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"ewe/internal/handler"/utf8>>, function => <<"handle_resp_file"/utf8>>, line => 166, value => _assert_fail, start => 4945, 'end' => 5005, pattern_start => 4956, pattern_end => 4981}) end, Sent = begin _pipe = gleam@http@response:set_body(Resp, gleam@bytes_tree:new()), _pipe@1 = ewe@internal@http:append_default_headers( _pipe, Req, Http_version@1 ), _pipe@2 = ewe@internal@encoder:setup_encoded_response(_pipe@1), _pipe@3 = glisten@transport:send( erlang:element(2, erlang:element(4, Req)), erlang:element(3, erlang:element(4, Req)), _pipe@2 ), gleam@result:'try'( _pipe@3, fun(_) -> _pipe@4 = ewe@internal@file:send( erlang:element(2, erlang:element(4, Req)), erlang:element(3, erlang:element(4, Req)), Descriptor, Size ), gleam@result:replace_error(_pipe@4, badarg) end ) end, _ = mist_ffi:close_file(Descriptor), Sent. -file("src/ewe/internal/handler.gleam", 215). ?DOC(false). -spec handle_resp_body( gleam@http@request:request(ewe@internal@http:connection()), gleam@http@response:response(ewe@internal@http:response_body()), ewe@internal@http:response_body() ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. handle_resp_body(Req, Resp, Body) -> Http_version@1 = case erlang:element(5, erlang:element(4, Req)) of {some, Http_version} -> Http_version; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"ewe/internal/handler"/utf8>>, function => <<"handle_resp_body"/utf8>>, line => 220, value => _assert_fail, start => 6632, 'end' => 6692, pattern_start => 6643, pattern_end => 6668}) end, Bytes@1 = case Body of {text_data, Text} -> gleam_stdlib:wrap_list(Text); {string_tree_data, String_tree} -> gleam_stdlib:wrap_list(String_tree); {bits_data, Bits} -> gleam@bytes_tree:from_bit_array(Bits); {bytes_data, Bytes} -> Bytes; empty -> gleam@bytes_tree:new(); _ -> erlang:error(#{gleam_error => panic, message => <<"`panic` expression evaluated."/utf8>>, file => <>, module => <<"ewe/internal/handler"/utf8>>, function => <<"handle_resp_body"/utf8>>, line => 228}) end, _pipe = gleam@http@response:set_body(Resp, Bytes@1), _pipe@1 = ewe@internal@http:append_default_headers( _pipe, Req, Http_version@1 ), _pipe@2 = ewe@internal@encoder:encode_response(_pipe@1), glisten@transport:send( erlang:element(2, erlang:element(4, Req)), erlang:element(3, erlang:element(4, Req)), _pipe@2 ). -file("src/ewe/internal/handler.gleam", 237). ?DOC(false). -spec is_connection_close(gleam@http@response:response(any())) -> boolean(). is_connection_close(Resp) -> case gleam@http@response:get_header(Resp, <<"connection"/utf8>>) of {ok, <<"close"/utf8>>} -> true; _ -> false end. -file("src/ewe/internal/handler.gleam", 244). ?DOC(false). -spec to_hex_string(integer()) -> binary(). to_hex_string(Integer) -> erlang:integer_to_list(Integer, 16). -file("src/ewe/internal/handler.gleam", 184). ?DOC(false). -spec handle_resp_chunked( gleam@http@request:request(ewe@internal@http:connection()), gleam@http@response:response(ewe@internal@http:response_body()), gleam@yielder:yielder(bitstring()) ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. handle_resp_chunked(Req, Resp, Yielder) -> Http_version@1 = case erlang:element(5, erlang:element(4, Req)) of {some, Http_version} -> Http_version; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"ewe/internal/handler"/utf8>>, function => <<"handle_resp_chunked"/utf8>>, line => 189, value => _assert_fail, start => 5639, 'end' => 5699, pattern_start => 5650, pattern_end => 5675}) end, _pipe = gleam@http@response:set_body(Resp, gleam@bytes_tree:new()), _pipe@1 = ewe@internal@http:append_default_headers( _pipe, Req, Http_version@1 ), _pipe@2 = ewe@internal@encoder:setup_encoded_response(_pipe@1), _pipe@3 = glisten@transport:send( erlang:element(2, erlang:element(4, Req)), erlang:element(3, erlang:element(4, Req)), _pipe@2 ), gleam@result:'try'( _pipe@3, fun(_) -> _pipe@9 = gleam@yielder:try_fold( Yielder, nil, fun(_, Chunk) -> _pipe@4 = gleam@bytes_tree:new(), _pipe@5 = gleam@bytes_tree:append_string( _pipe@4, to_hex_string(erlang:byte_size(Chunk)) ), _pipe@6 = gleam@bytes_tree:append(_pipe@5, <<"\r\n"/utf8>>), _pipe@7 = gleam@bytes_tree:append(_pipe@6, Chunk), _pipe@8 = gleam@bytes_tree:append(_pipe@7, <<"\r\n"/utf8>>), glisten@transport:send( erlang:element(2, erlang:element(4, Req)), erlang:element(3, erlang:element(4, Req)), _pipe@8 ) end ), gleam@result:'try'( _pipe@9, fun(_) -> glisten@transport:send( erlang:element(2, erlang:element(4, Req)), erlang:element(3, erlang:element(4, Req)), gleam@bytes_tree:from_bit_array(<<"0\r\n\r\n"/utf8>>) ) end ) end ). -file("src/ewe/internal/handler.gleam", 118). ?DOC(false). -spec call_handler( gleam@http@request:request(ewe@internal@http:connection()), gleam@erlang@process:subject(glisten_message()), fun((gleam@http@request:request(ewe@internal@http:connection())) -> gleam@http@response:response(ewe@internal@http:response_body())), gleam@http@response:response(ewe@internal@http:response_body()), integer() ) -> next(). call_handler(Req, Subject, Handler, On_crash, Idle_timeout) -> Resp = begin _pipe = ewe_ffi:rescue(fun() -> Handler(Req) end), _pipe@2 = gleam@result:map_error(_pipe, fun(_) -> _pipe@1 = On_crash, gleam@http@response:set_header( _pipe@1, <<"connection"/utf8>>, <<"close"/utf8>> ) end), gleam@result:unwrap_both(_pipe@2) end, case Resp of {response, _, _, {websocket_connection, Selector}} -> _ = gleam_erlang_ffi:select(Selector), stop; {response, _, _, Body} -> Sent = case Body of {file, Descriptor, Size} -> handle_resp_file(Req, Resp, Descriptor, Size); {chunked_data, Yielder} -> handle_resp_chunked(Req, Resp, Yielder); _ -> handle_resp_body(Req, Resp, Body) end, case {Sent, is_connection_close(Resp)} of {{ok, nil}, false} -> Timer = gleam@erlang@process:send_after( Subject, Idle_timeout, idle_timeout ), {continue, {glisten_state, {some, Timer}, Subject}}; {_, _} -> stop end end. -file("src/ewe/internal/handler.gleam", 61). ?DOC(false). -spec loop( fun((gleam@http@request:request(ewe@internal@http:connection())) -> gleam@http@response:response(ewe@internal@http:response_body())), gleam@http@response:response(ewe@internal@http:response_body()), integer() ) -> fun((glisten_state(), glisten:message(glisten_message()), glisten:connection(glisten_message())) -> glisten:next(glisten_state(), glisten:message(glisten_message()))). loop(Handler, On_crash, Idle_timeout) -> fun(State, Msg, Conn) -> case Msg of {user, idle_timeout} -> glisten:stop(); {packet, Msg@1} -> case erlang:element(2, State) of {some, Timer} -> gleam@erlang@process:cancel_timer(Timer); none -> timer_not_found end, Http_conn = ewe@internal@http:transform_connection(Conn), Parsed = ewe@internal@http:parse_request( Http_conn, ewe@internal@buffer:new(Msg@1) ), case Parsed of {ok, Req} -> case call_handler( Req, erlang:element(3, State), Handler, On_crash, Idle_timeout ) of {continue, New_state} -> glisten:continue(New_state); stop -> glisten:stop() end; {error, Reason} -> Status = case Reason of invalid_version -> 505; _ -> 400 end, _ = begin _pipe = gleam@http@response:new(Status), _pipe@1 = gleam@http@response:set_body( _pipe, gleam@bytes_tree:new() ), _pipe@2 = gleam@http@response:set_header( _pipe@1, <<"connection"/utf8>>, <<"close"/utf8>> ), _pipe@3 = ewe@internal@encoder:encode_response( _pipe@2 ), glisten@transport:send( erlang:element(2, Http_conn), erlang:element(3, Http_conn), _pipe@3 ) end, glisten:stop() end end end.