-module(ewe). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/ewe.gleam"). -export([ip_address_to_string/1, get_client_info/1, get_server_info/1, file/3, new/1, bind/2, bind_all/1, listening/2, listening_random/1, enable_ipv6/1, enable_tls/3, with_name/2, on_start/2, quiet/1, on_crash/2, idle_timeout/2, start/1, supervised/1, read_body/2, stream_body/1, chunked_continue/1, chunked_stop/0, chunked_stop_abnormal/1, chunked_body/5, send_chunk/2, websocket_continue/1, websocket_continue_with_selector/2, websocket_stop/0, websocket_stop_abnormal/1, upgrade_websocket/4, send_binary_frame/2, send_text_frame/2, send_close_frame/2, sse_continue/1, sse_stop/0, sse_stop_abnormal/1, event_name/2, event_id/2, event_retry/2, sse/4, event/1, send_event/2]). -export_type([ip_address/0, socket_address/0, response_body/0, file_error/0, builder/0, body_error/0, stream/0, chunked_next/1, websocket_next/2, websocket_message/1, close_code/0, s_s_e_next/1]). -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( " \n" ). -type ip_address() :: {ip_v4, integer(), integer(), integer(), integer()} | {ip_v6, integer(), integer(), integer(), integer(), integer(), integer(), integer(), integer()}. -type socket_address() :: {socket_address, ip_address(), integer()}. -type response_body() :: {text_data, binary()} | {bytes_data, gleam@bytes_tree:bytes_tree()} | {bits_data, bitstring()} | {string_tree_data, gleam@string_tree:string_tree()} | empty | {file, ewe@internal@file:io_device(), integer(), integer()} | chunked | websocket | s_s_e. -type file_error() :: no_entry | no_access | is_directory | {unknown_file_error, gleam@dynamic:dynamic_()}. -opaque builder() :: {builder, fun((gleam@http@request:request(ewe@internal@http1:connection())) -> gleam@http@response:response(response_body())), integer(), binary(), boolean(), gleam@option:option({binary(), binary()}), fun((gleam@http:scheme(), socket_address()) -> nil), gleam@http@response:response(response_body()), gleam@erlang@process:name(glisten@internal@listener:message()), integer()}. -type body_error() :: body_too_large | invalid_body. -type stream() :: {consumed, bitstring(), fun((integer()) -> {ok, stream()} | {error, body_error()})} | done. -opaque chunked_next(NJR) :: {chunked_continue, NJR} | chunked_stop | {chunked_abnormal_stop, binary()}. -opaque websocket_next(NJS, NJT) :: {websocket_continue, NJS, gleam@option:option(gleam@erlang@process:selector(NJT))} | websocket_normal_stop | {websocket_abnormal_stop, binary()}. -type websocket_message(NJU) :: {text, binary()} | {binary, bitstring()} | {user, NJU}. -type close_code() :: {normal_closure, binary()} | {invalid_payload_data, binary()} | {policy_violation, binary()} | {message_too_big, binary()} | {internal_error, binary()} | {service_restart, binary()} | {try_again_later, binary()} | {bad_gateway, binary()} | {custom_close_code, integer(), binary()} | no_close_reason. -opaque s_s_e_next(NJV) :: {s_s_e_continue, NJV} | s_s_e_normal_stop | {s_s_e_abnormal_stop, binary()}. -file("src/ewe.gleam", 203). -spec glisten_to_ewe_ip(glisten:ip_address()) -> ip_address(). glisten_to_ewe_ip(Ip) -> case Ip of {ip_v4, N1, N2, N3, N4} -> {ip_v4, N1, N2, N3, N4}; {ip_v6, N1@1, N2@1, N3@1, N4@1, N5, N6, N7, N8} -> {ip_v6, N1@1, N2@1, N3@1, N4@1, N5, N6, N7, N8} end. -file("src/ewe.gleam", 211). -spec glisten_options_to_ewe_ip(glisten@socket@options:ip_address()) -> ip_address(). glisten_options_to_ewe_ip(Ip) -> case Ip of {ip_v4, N1, N2, N3, N4} -> {ip_v4, N1, N2, N3, N4}; {ip_v6, N1@1, N2@1, N3@1, N4@1, N5, N6, N7, N8} -> {ip_v6, N1@1, N2@1, N3@1, N4@1, N5, N6, N7, N8} end. -file("src/ewe.gleam", 219). -spec ewe_to_glisten_ip(ip_address()) -> glisten:ip_address(). ewe_to_glisten_ip(Ip) -> case Ip of {ip_v4, N1, N2, N3, N4} -> {ip_v4, N1, N2, N3, N4}; {ip_v6, N1@1, N2@1, N3@1, N4@1, N5, N6, N7, N8} -> {ip_v6, N1@1, N2@1, N3@1, N4@1, N5, N6, N7, N8} end. -file("src/ewe.gleam", 198). ?DOC(" Converts an `IpAddress` to a `String`.\n"). -spec ip_address_to_string(ip_address()) -> binary(). ip_address_to_string(Address) -> _pipe = ewe_to_glisten_ip(Address), glisten:ip_address_to_string(_pipe). -file("src/ewe.gleam", 241). ?DOC( " Attempts to get the client's socket address using request's\n" " connection.\n" ). -spec get_client_info(ewe@internal@http1:connection()) -> {ok, socket_address()} | {error, nil}. get_client_info(Connection) -> _pipe = glisten@transport:peername( erlang:element(2, Connection), erlang:element(3, Connection) ), gleam@result:map( _pipe, fun(Server_info) -> {socket_address, glisten_options_to_ewe_ip(erlang:element(1, Server_info)), erlang:element(2, Server_info)} end ). -file("src/ewe.gleam", 253). ?DOC( " Retrieves server's socket address. Requires the same name as the one used in\n" " `ewe.with_name` and server to be started.\n" ). -spec get_server_info( gleam@erlang@process:name(glisten@internal@listener:message()) ) -> socket_address(). get_server_info(Name) -> Server_info = glisten:get_server_info(Name, 10000), Ip_address = glisten_to_ewe_ip(erlang:element(3, Server_info)), {socket_address, Ip_address, erlang:element(2, Server_info)}. -file("src/ewe.gleam", 322). -spec transform_response_body(gleam@http@response:response(response_body())) -> gleam@http@response:response(ewe@internal@http1:response_body()). transform_response_body(Resp) -> gleam@http@response:set_body(Resp, case erlang:element(4, Resp) of {text_data, Text} -> {text_data, Text}; {bytes_data, Bytes} -> {bytes_data, Bytes}; {bits_data, Bits} -> {bits_data, Bits}; {string_tree_data, String_tree} -> {string_tree_data, String_tree}; chunked -> chunked; {file, Descriptor, Offset, Size} -> {file, Descriptor, Offset, Size}; websocket -> websocket; s_s_e -> s_s_e; empty -> empty end). -file("src/ewe.gleam", 359). -spec internal_to_file_error(ewe@internal@file:file_error()) -> file_error(). internal_to_file_error(Error) -> case Error of enoent -> no_entry; eacces -> no_access; eisdir -> is_directory; {eunknown, Error@1} -> {unknown_file_error, Error@1} end. -file("src/ewe.gleam", 370). ?DOC(" Sets response body from file, sets `content-length` header.\n"). -spec file( binary(), gleam@option:option(integer()), gleam@option:option(integer()) ) -> {ok, response_body()} | {error, file_error()}. file(Path, Offset, Limit) -> case ewe_ffi:open_file(Path) of {ok, File} -> {ok, {file, erlang:element(2, File), gleam@option:unwrap(Offset, 0), gleam@option:unwrap(Limit, erlang:element(3, File))}}; {error, Error} -> {error, internal_to_file_error(Error)} end. -file("src/ewe.gleam", 437). ?DOC( " Creates new server builder with handler provided.\n" "\n" " Default configuration:\n" " - port: `8080`\n" " - interface: `127.0.0.1`\n" " - No ipv6 support\n" " - No TLS support\n" " - Default listener name for server information retrieval\n" " - on_start: prints `Listening on ://:`\n" " - on_crash: empty 500 response\n" " - idle_timeout: connection is closed after 10_000ms of inactivity\n" ). -spec new( fun((gleam@http@request:request(ewe@internal@http1:connection())) -> gleam@http@response:response(response_body())) ) -> builder(). new(Handler) -> {builder, Handler, 8080, <<"127.0.0.1"/utf8>>, false, none, fun(Scheme, Server) -> Address = case erlang:element(2, Server) of {ip_v6, _, _, _, _, _, _, _, _} -> <<<<"["/utf8, (ip_address_to_string(erlang:element(2, Server)))/binary>>/binary, "]"/utf8>>; {ip_v4, _, _, _, _} -> ip_address_to_string(erlang:element(2, Server)) end, Url = <<<<<<<<(gleam@http:scheme_to_string(Scheme))/binary, "://"/utf8>>/binary, Address/binary>>/binary, ":"/utf8>>/binary, (erlang:integer_to_binary(erlang:element(3, Server)))/binary>>, logging:log(info, <<"Listening on "/utf8, Url/binary>>) end, begin _pipe = gleam@http@response:new(500), gleam@http@response:set_body(_pipe, empty) end, gleam_erlang_ffi:new_name(<<"glisten_listener"/utf8>>), 10000}. -file("src/ewe.gleam", 468). ?DOC( " Binds server to a specific interface. Crashes program if the interface is\n" " invalid.\n" ). -spec bind(builder(), binary()) -> builder(). bind(Builder, Interface) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), Interface, erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 474). ?DOC(" Binds server to all interfaces.\n"). -spec bind_all(builder()) -> builder(). bind_all(Builder) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), <<"0.0.0.0"/utf8>>, erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 480). ?DOC(" Sets listening port for server.\n"). -spec listening(builder(), integer()) -> builder(). listening(Builder, Port) -> {builder, erlang:element(2, Builder), Port, erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 486). ?DOC(" Sets listening port for server to a random port. Useful for testing.\n"). -spec listening_random(builder()) -> builder(). listening_random(Builder) -> {builder, erlang:element(2, Builder), 0, erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 492). ?DOC(" Enables IPv6 support.\n"). -spec enable_ipv6(builder()) -> builder(). enable_ipv6(Builder) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), true, erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 498). ?DOC(" Enables TLS support, requires certificate and key file.\n"). -spec enable_tls(builder(), binary(), binary()) -> builder(). enable_tls(Builder, Certificate_file, Key_file) -> Cert = case ewe_ffi:open_file(Certificate_file) of {ok, _} -> Certificate_file; {error, _} -> erlang:error(#{gleam_error => panic, message => <<"Failed to find cert file"/utf8>>, file => <>, module => <<"ewe"/utf8>>, function => <<"enable_tls"/utf8>>, line => 505}) end, Key = case ewe_ffi:open_file(Key_file) of {ok, _} -> Key_file; {error, _} -> erlang:error(#{gleam_error => panic, message => <<"Failed to find key file"/utf8>>, file => <>, module => <<"ewe"/utf8>>, function => <<"enable_tls"/utf8>>, line => 510}) end, {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), {some, {Cert, Key}}, erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 519). ?DOC( " Sets a custom process name for server information retrieval, allowing to\n" " use `ewe.get_server_info` after the server starts.\n" ). -spec with_name( builder(), gleam@erlang@process:name(glisten@internal@listener:message()) ) -> builder(). with_name(Builder, Name) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), Name, erlang:element(10, Builder)}. -file("src/ewe.gleam", 528). ?DOC(" Sets a custom handler that will be called after server starts.\n"). -spec on_start(builder(), fun((gleam@http:scheme(), socket_address()) -> nil)) -> builder(). on_start(Builder, On_start) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), On_start, erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 537). ?DOC(" Sets an empty `on_start` function.\n"). -spec quiet(builder()) -> builder(). quiet(Builder) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), fun(_, _) -> nil end, erlang:element(8, Builder), erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 543). ?DOC(" Sets a custom response that will be sent when server crashes.\n"). -spec on_crash(builder(), gleam@http@response:response(response_body())) -> builder(). on_crash(Builder, On_crash) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), On_crash, erlang:element(9, Builder), erlang:element(10, Builder)}. -file("src/ewe.gleam", 550). ?DOC( " Sets a custom idle timeout in milliseconds for connections. If\n" " provided timeout is less than 0, 10_000ms will be used instead.\n" ). -spec idle_timeout(builder(), integer()) -> builder(). idle_timeout(Builder, Idle_timeout) -> case Idle_timeout of Idle_timeout@1 when Idle_timeout@1 >= 0 -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), Idle_timeout@1}; _ -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder), erlang:element(9, Builder), 10000} end. -file("src/ewe.gleam", 563). ?DOC(" Starts the server with the provided configuration.\n"). -spec start(builder()) -> {ok, gleam@otp@actor:started(gleam@otp@static_supervisor:supervisor())} | {error, gleam@otp@actor:start_error()}. start(Builder) -> Handler = fun(Req) -> transform_response_body((erlang:element(2, Builder))(Req)) end, On_crash = transform_response_body(erlang:element(8, Builder)), Factory_name = gleam_erlang_ffi:new_name(<<"ewe_streams"/utf8>>), Factory_child = begin _pipe = gleam@otp@factory_supervisor:worker_child( fun(Start) -> Start() end ), _pipe@1 = gleam@otp@factory_supervisor:restart_strategy( _pipe, temporary ), _pipe@2 = gleam@otp@factory_supervisor:named(_pipe@1, Factory_name), gleam@otp@factory_supervisor:supervised(_pipe@2) end, Glisten_supervisor = begin _pipe@3 = glisten:new( fun ewe@internal@handler:init/1, ewe@internal@handler:loop( Handler, On_crash, Factory_name, erlang:element(10, Builder) ) ), _pipe@4 = glisten:bind(_pipe@3, erlang:element(4, Builder)), _pipe@5 = (fun(Glisten_builder) -> case erlang:element(5, Builder) of true -> glisten:with_ipv6(Glisten_builder); false -> Glisten_builder end end)(_pipe@4), _pipe@6 = (fun(Glisten_builder@1) -> case erlang:element(6, Builder) of {some, {Cert, Key}} -> glisten:with_tls(Glisten_builder@1, Cert, Key); none -> Glisten_builder@1 end end)(_pipe@5), _pipe@7 = glisten:start_with_listener_name( _pipe@6, erlang:element(3, Builder), erlang:element(9, Builder) ), gleam@result:map( _pipe@7, fun(Started) -> Scheme = case erlang:element(6, Builder) of {some, {_, _}} -> https; none -> http end, Server_info = glisten:get_server_info( erlang:element(9, Builder), 10000 ), Ip_address = glisten_to_ewe_ip(erlang:element(3, Server_info)), Server = {socket_address, Ip_address, erlang:element(2, Server_info)}, (erlang:element(7, Builder))(Scheme, Server), Started end ) end, Glisten_child = gleam@otp@supervision:supervisor( fun() -> Glisten_supervisor end ), _pipe@8 = gleam@otp@static_supervisor:new(one_for_all), _pipe@9 = gleam@otp@static_supervisor:add(_pipe@8, Glisten_child), _pipe@10 = gleam@otp@static_supervisor:add(_pipe@9, Factory_child), gleam@otp@static_supervisor:start(_pipe@10). -file("src/ewe.gleam", 623). ?DOC( " Creates a supervisor with the provided configuration that is a child of a\n" " supervision tree.\n" ). -spec supervised(builder()) -> gleam@otp@supervision:child_specification(gleam@otp@static_supervisor:supervisor()). supervised(Builder) -> gleam@otp@supervision:supervisor(fun() -> start(Builder) end). -file("src/ewe.gleam", 655). ?DOC( " Reads body from the request. If request body is malformed, `InvalidBody`\n" " error is returned. On success, returns a request with body converted to\n" " `BitArray`.\n" "\n" " - When `transfer-encoding` header set as `chunked`, `BodyTooLarge` error is\n" " returned if accumulated body is larger than `size_limit`.\n" " - Ensures that `content-length` is in `size_limit` scope.\n" ). -spec read_body( gleam@http@request:request(ewe@internal@http1:connection()), integer() ) -> {ok, gleam@http@request:request(bitstring())} | {error, body_error()}. read_body(Req, Bytes_limit) -> case ewe@internal@http1:read_body(Req, Bytes_limit) of {ok, Req@1} -> {ok, Req@1}; {error, body_too_large} -> {error, body_too_large}; {error, _} -> {error, invalid_body} end. -file("src/ewe.gleam", 693). -spec consumer_adapter( fun((integer()) -> {ok, ewe@internal@http1:stream()} | {error, ewe@internal@http1:parse_error()}) ) -> fun((integer()) -> {ok, stream()} | {error, body_error()}). consumer_adapter(Internal_consumer) -> fun(Size) -> case Internal_consumer(Size) of {ok, done} -> {ok, done}; {ok, {consumed, Data, Next}} -> {ok, {consumed, Data, consumer_adapter(Next)}}; {error, _} -> {error, invalid_body} end end. -file("src/ewe.gleam", 686). ?DOC( " Returns the consumer function that reads `N` amount of bytes from the\n" " request body stream.\n" ). -spec stream_body(gleam@http@request:request(ewe@internal@http1:connection())) -> {ok, fun((integer()) -> {ok, stream()} | {error, body_error()})} | {error, body_error()}. stream_body(Req) -> case ewe@internal@http1:stream_body(Req) of {ok, Consumer} -> {ok, consumer_adapter(Consumer)}; {error, _} -> {error, invalid_body} end. -file("src/ewe.gleam", 729). ?DOC(" Instructs chunked response to continue processing.\n"). -spec chunked_continue(NKU) -> chunked_next(NKU). chunked_continue(User_state) -> {chunked_continue, User_state}. -file("src/ewe.gleam", 735). ?DOC(" Instructs chunked response to stop normally.\n"). -spec chunked_stop() -> chunked_next(any()). chunked_stop() -> chunked_stop. -file("src/ewe.gleam", 741). ?DOC(" Instructs chunked response to stop with abnormal reason.\n"). -spec chunked_stop_abnormal(binary()) -> chunked_next(any()). chunked_stop_abnormal(Reason) -> {chunked_abnormal_stop, Reason}. -file("src/ewe.gleam", 745). -spec to_internal_chunked_next(chunked_next(NLA)) -> ewe@internal@stream@chunked:chunked_next(NLA). to_internal_chunked_next(Next) -> case Next of {chunked_continue, User_state} -> {continue, User_state}; chunked_stop -> normal_stop; {chunked_abnormal_stop, Reason} -> {abnormal_stop, Reason} end. -file("src/ewe.gleam", 766). ?DOC( " Sets up the connection for chunked response.\n" " \n" " `on_init` function is called once the chunked response process is \n" " initialized. The argument is subject that can be used to send chunks to the \n" " client. It must return initial state.\n" "\n" " `handler` function is called for every message received. It must return\n" " instruction on how chunked response should proceed.\n" "\n" " `on_close` function is called when the chunked response process is going to be stopped.\n" ). -spec chunked_body( gleam@http@request:request(ewe@internal@http1:connection()), gleam@http@response:response(any()), fun((gleam@erlang@process:subject(NLF)) -> NLH), fun((ewe@internal@stream@chunked:chunked_body(), NLH, NLF) -> chunked_next(NLH)), fun((ewe@internal@stream@chunked:chunked_body(), NLH) -> nil) ) -> gleam@http@response:response(response_body()). chunked_body(Req, Resp, On_init, Handler, On_close) -> Handler@1 = fun(Conn, State, Msg) -> _pipe = Handler(Conn, State, Msg), to_internal_chunked_next(_pipe) end, Transport = erlang:element(2, erlang:element(4, Req)), Socket = erlang:element(3, erlang:element(4, Req)), Factory_name = erlang:element(5, erlang:element(4, Req)), case ewe@internal@stream@chunked:send_response(Resp, Transport, Socket) of {ok, nil} -> Supervisor = gleam@otp@factory_supervisor:get_by_name(Factory_name), Start_result = gleam@otp@factory_supervisor:start_child( Supervisor, fun() -> ewe@internal@stream@chunked:start( Transport, Socket, On_init, Handler@1, On_close ) end ), case Start_result of {ok, Started} -> _ = glisten@transport:controlling_process( Transport, Socket, erlang:element(2, Started) ), _pipe@1 = gleam@http@response:new(200), gleam@http@response:set_body(_pipe@1, chunked); {error, _} -> _pipe@2 = gleam@http@response:new(400), gleam@http@response:set_body(_pipe@2, empty) end; {error, nil} -> _pipe@3 = gleam@http@response:new(400), gleam@http@response:set_body(_pipe@3, empty) end. -file("src/ewe.gleam", 806). ?DOC(" Sends a chunk to the client.\n"). -spec send_chunk(ewe@internal@stream@chunked:chunked_body(), bitstring()) -> {ok, nil} | {error, glisten@socket:socket_reason()}. send_chunk(Body, Chunk) -> ewe@internal@stream@chunked:send_chunk( erlang:element(2, Body), erlang:element(3, Body), Chunk ). -file("src/ewe.gleam", 838). ?DOC(" Instructs WebSocket connection to continue processing.\n"). -spec websocket_continue(NLL) -> websocket_next(NLL, any()). websocket_continue(User_state) -> {websocket_continue, User_state, none}. -file("src/ewe.gleam", 847). ?DOC( " Instructs WebSocket connection to continue processing, including selector\n" " for custom messages.\n" ). -spec websocket_continue_with_selector(NLP, gleam@erlang@process:selector(NLQ)) -> websocket_next(NLP, NLQ). websocket_continue_with_selector(User_state, Selector) -> {websocket_continue, User_state, {some, Selector}}. -file("src/ewe.gleam", 856). ?DOC(" Instructs WebSocket connection to stop.\n"). -spec websocket_stop() -> websocket_next(any(), any()). websocket_stop() -> websocket_normal_stop. -file("src/ewe.gleam", 862). ?DOC(" Instructs WebSocket connection to stop with abnormal reason.\n"). -spec websocket_stop_abnormal(binary()) -> websocket_next(any(), any()). websocket_stop_abnormal(Reason) -> {websocket_abnormal_stop, Reason}. -file("src/ewe.gleam", 868). -spec to_websocket_next(ewe@internal@stream@websocket:websocket_next(NMC, NMD)) -> websocket_next(NMC, NMD). to_websocket_next(Next) -> case Next of {continue, User_state, Selector} -> {websocket_continue, User_state, Selector}; normal_stop -> websocket_normal_stop; {abnormal_stop, Reason} -> {websocket_abnormal_stop, Reason} end. -file("src/ewe.gleam", 879). -spec to_internal_websocket_next(websocket_next(NMI, NMJ)) -> ewe@internal@stream@websocket:websocket_next(NMI, NMJ). to_internal_websocket_next(Next) -> case Next of {websocket_continue, User_state, Selector} -> {continue, User_state, Selector}; websocket_normal_stop -> normal_stop; {websocket_abnormal_stop, Reason} -> {abnormal_stop, Reason} end. -file("src/ewe.gleam", 904). -spec transform_websocket_message( ewe@internal@stream@websocket:websocket_message(NMO) ) -> {ok, websocket_message(NMO)} | {error, nil}. transform_websocket_message(Message) -> case Message of {frame, {text, Payload}} -> _pipe = gleam@bit_array:to_string(Payload), gleam@result:map(_pipe, fun(Field@0) -> {text, Field@0} end); {frame, {binary, Payload@1}} -> {ok, {binary, Payload@1}}; {user_message, User_message} -> {ok, {user, User_message}}; _ -> {error, nil} end. -file("src/ewe.gleam", 929). ?DOC( " Upgrade request to a WebSocket connection. If the initial request is not\n" " valid for WebSocket upgrade, 400 response is sent.\n" "\n" " `on_init` function is called once process that handles WebSocket connection\n" " is initialized. It must return a tuple with initial state and selector for\n" " custom messages. If there is no custom messages, user can pass the same\n" " selector from the argument\n" "\n" " `handler` function is called for every WebSocket message received. It must\n" " return instruction on how WebSocket connection should proceed.\n" "\n" " `on_close` function is called when WebSocket process is going to be stopped.\n" ). -spec upgrade_websocket( gleam@http@request:request(ewe@internal@http1:connection()), fun((ewe@internal@stream@websocket:websocket_connection(), gleam@erlang@process:selector(NMT)) -> {NMV, gleam@erlang@process:selector(NMT)}), fun((ewe@internal@stream@websocket:websocket_connection(), NMV, websocket_message(NMT)) -> websocket_next(NMV, NMT)), fun((ewe@internal@stream@websocket:websocket_connection(), NMV) -> nil) ) -> gleam@http@response:response(response_body()). upgrade_websocket(Req, On_init, Handler, On_close) -> Handler@1 = fun(Conn, State, Msg) -> _pipe = transform_websocket_message(Msg), _pipe@1 = gleam@result:map( _pipe, fun(_capture) -> Handler(Conn, State, _capture) end ), _pipe@2 = gleam@result:unwrap(_pipe@1, websocket_continue(State)), to_internal_websocket_next(_pipe@2) end, Transport = erlang:element(2, erlang:element(4, Req)), Socket = erlang:element(3, erlang:element(4, Req)), Factory_name = erlang:element(5, erlang:element(4, Req)), case ewe@internal@http1:upgrade_websocket(Req, Transport, Socket) of {ok, {Extensions, Per_message_deflate}} -> Supervisor = gleam@otp@factory_supervisor:get_by_name(Factory_name), Start_result = gleam@otp@factory_supervisor:start_child( Supervisor, fun() -> ewe@internal@stream@websocket:start( Transport, Socket, On_init, Handler@1, On_close, Extensions, Per_message_deflate ) end ), case Start_result of {ok, Started} -> _ = glisten@transport:controlling_process( Transport, Socket, erlang:element(2, Started) ), _pipe@3 = gleam@http@response:new(200), gleam@http@response:set_body(_pipe@3, websocket); {error, _} -> _pipe@4 = gleam@http@response:new(500), gleam@http@response:set_body(_pipe@4, empty) end; {error, _} -> _pipe@5 = gleam@http@response:new(400), gleam@http@response:set_body(_pipe@5, empty) end. -file("src/ewe.gleam", 983). ?DOC(" Sends a binary frame to the websocket client.\n"). -spec send_binary_frame( ewe@internal@stream@websocket:websocket_connection(), bitstring() ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. send_binary_frame(Conn, Bits) -> ewe@internal@stream@websocket:send_frame( fun websocks:encode_binary_frame/3, erlang:element(2, Conn), erlang:element(3, Conn), erlang:element(4, Conn), Bits ). -file("src/ewe.gleam", 998). ?DOC(" Sends a text frame to the websocket client.\n"). -spec send_text_frame( ewe@internal@stream@websocket:websocket_connection(), binary() ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. send_text_frame(Conn, Text) -> ewe@internal@stream@websocket:send_frame( fun websocks:encode_text_frame/3, erlang:element(2, Conn), erlang:element(3, Conn), erlang:element(4, Conn), gleam_stdlib:identity(Text) ). -file("src/ewe.gleam", 1055). -spec to_internal_close_code(close_code()) -> websocks:close_reason(). to_internal_close_code(Code) -> case Code of {normal_closure, Data} -> {normal_closure, gleam_stdlib:identity(Data)}; {invalid_payload_data, Data@1} -> {invalid_payload_data, gleam_stdlib:identity(Data@1)}; {policy_violation, Data@2} -> {policy_violation, gleam_stdlib:identity(Data@2)}; {message_too_big, Data@3} -> {message_too_big, gleam_stdlib:identity(Data@3)}; {internal_error, Data@4} -> {internal_error, gleam_stdlib:identity(Data@4)}; {service_restart, Data@5} -> {service_restart, gleam_stdlib:identity(Data@5)}; {try_again_later, Data@6} -> {try_again_later, gleam_stdlib:identity(Data@6)}; {bad_gateway, Data@7} -> {bad_gateway, gleam_stdlib:identity(Data@7)}; {custom_close_code, Code@1, Data@8} -> {custom_close_code, Code@1, gleam_stdlib:identity(Data@8)}; no_close_reason -> no_close_reason end. -file("src/ewe.gleam", 1077). ?DOC( " Sends a close frame to the websocket client. Once this function is called,\n" " no other frames can be sent on this connection. Returns how the WebSocket\n" " connection should proceed - make sure your handler returns this value.\n" ). -spec send_close_frame( ewe@internal@stream@websocket:websocket_connection(), close_code() ) -> websocket_next(any(), any()). send_close_frame(Conn, Code) -> _pipe = to_internal_close_code(Code), _pipe@1 = ewe@internal@stream@websocket:send_close_frame( erlang:element(2, Conn), erlang:element(3, Conn), _pipe ), to_websocket_next(_pipe@1). -file("src/ewe.gleam", 1110). ?DOC(" Instructs Server-Sent Events connection to continue processing.\n"). -spec sse_continue(NNI) -> s_s_e_next(NNI). sse_continue(User_state) -> {s_s_e_continue, User_state}. -file("src/ewe.gleam", 1116). ?DOC(" Instructs Server-Sent Events connection to stop.\n"). -spec sse_stop() -> s_s_e_next(any()). sse_stop() -> s_s_e_normal_stop. -file("src/ewe.gleam", 1122). ?DOC(" Instructs Server-Sent Events connection to stop with abnormal reason.\n"). -spec sse_stop_abnormal(binary()) -> s_s_e_next(any()). sse_stop_abnormal(Reason) -> {s_s_e_abnormal_stop, Reason}. -file("src/ewe.gleam", 1156). ?DOC(" Sets the name of the event.\n"). -spec event_name(ewe@internal@stream@sse:s_s_e_event(), binary()) -> ewe@internal@stream@sse:s_s_e_event(). event_name(Event, Name) -> {s_s_e_event, {some, Name}, erlang:element(3, Event), erlang:element(4, Event), erlang:element(5, Event)}. -file("src/ewe.gleam", 1162). ?DOC(" Sets the ID of the event.\n"). -spec event_id(ewe@internal@stream@sse:s_s_e_event(), binary()) -> ewe@internal@stream@sse:s_s_e_event(). event_id(Event, Id) -> {s_s_e_event, erlang:element(2, Event), erlang:element(3, Event), {some, Id}, erlang:element(5, Event)}. -file("src/ewe.gleam", 1168). ?DOC(" Sets the retry time of the event.\n"). -spec event_retry(ewe@internal@stream@sse:s_s_e_event(), integer()) -> ewe@internal@stream@sse:s_s_e_event(). event_retry(Event, Retry) -> {s_s_e_event, erlang:element(2, Event), erlang:element(3, Event), erlang:element(4, Event), {some, Retry}}. -file("src/ewe.gleam", 1183). ?DOC( " Sets up the connection for Server-Sent Events.\n" "\n" " `on_init` function is called once process that handles SSE connection\n" " is initialized. The argument is subject that can be used to send messages\n" " to the client. It must return initial state.\n" "\n" " `handler` function is called for every subject's message received. It must\n" " return instruction on how SSE connection should proceed.\n" " \n" " `on_close` function is called when SSE process is going to be stopped.\n" ). -spec sse( gleam@http@request:request(ewe@internal@http1:connection()), fun((gleam@erlang@process:subject(NNR)) -> NNT), fun((ewe@internal@stream@sse:s_s_e_connection(), NNT, NNR) -> s_s_e_next(NNT)), fun((ewe@internal@stream@sse:s_s_e_connection(), NNT) -> nil) ) -> gleam@http@response:response(response_body()). sse(Req, On_init, Handler, On_close) -> Handler@1 = fun(Conn, State, Msg) -> _pipe = Handler(Conn, State, Msg), to_internal_sse_next(_pipe) end, Transport = erlang:element(2, erlang:element(4, Req)), Socket = erlang:element(3, erlang:element(4, Req)), Factory_name = erlang:element(5, erlang:element(4, Req)), case ewe@internal@stream@sse:send_response(Transport, Socket) of {ok, nil} -> Supervisor = gleam@otp@factory_supervisor:get_by_name(Factory_name), Start_result = gleam@otp@factory_supervisor:start_child( Supervisor, fun() -> ewe@internal@stream@sse:start( Transport, Socket, On_init, Handler@1, On_close ) end ), case Start_result of {ok, Started} -> _ = glisten@transport:controlling_process( Transport, Socket, erlang:element(2, Started) ), _pipe@1 = gleam@http@response:new(200), gleam@http@response:set_body(_pipe@1, s_s_e); {error, _} -> _pipe@2 = gleam@http@response:new(400), gleam@http@response:set_body(_pipe@2, empty) end; {error, nil} -> _pipe@3 = gleam@http@response:new(400), gleam@http@response:set_body(_pipe@3, empty) end. -file("src/ewe.gleam", 1126). -spec to_internal_sse_next(s_s_e_next(NNO)) -> ewe@internal@stream@sse:s_s_e_next(NNO). to_internal_sse_next(Next) -> case Next of {s_s_e_continue, User_state} -> {continue, User_state}; s_s_e_normal_stop -> normal_stop; {s_s_e_abnormal_stop, Reason} -> {abnormal_stop, Reason} end. -file("src/ewe.gleam", 1150). ?DOC( " Creates a new SSE event with the given data. Use `ewe.event_name`,\n" " `ewe.event_id`, and `ewe.event_retry` to modify other fields of the event.\n" ). -spec event(binary()) -> ewe@internal@stream@sse:s_s_e_event(). event(Data) -> {s_s_e_event, none, Data, none, none}. -file("src/ewe.gleam", 1221). ?DOC(" Sends a Server-Sent Events event to the client.\n"). -spec send_event( ewe@internal@stream@sse:s_s_e_connection(), ewe@internal@stream@sse:s_s_e_event() ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. send_event(Conn, Event) -> ewe@internal@stream@sse:send_event( erlang:element(2, Conn), erlang:element(3, Conn), Event ).