-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, text/2, bytes/2, bits/2, string_tree/2, empty/1, json/2, chunked/2, file/2, new/1, bind/2, bind_all/1, listening/2, listening_random/1, enable_ipv6/1, enable_tls/3, set_information_name/2, on_start/2, quiet/1, on_crash/2, idle_timeout/2, start/1, supervised/1, read_body/2, stream_body/1, continue/1, continue_with_selector/2, stop/0, stop_abnormal/1, upgrade_websocket/4, send_binary_frame/2, send_text_frame/2, use_expression/1]). -export_type([ip_address/0, socket_address/0, response_body/0, file_error/0, builder/0, body_error/0, stream/0, next/2, websocket_message/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" " \n" " #### IP Address\n" " - [ip_address_to_string](#ip_address_to_string)\n" " #### Information\n" " - [get_client_info](#get_client_info)\n" " - [get_server_info](#get_server_info)\n" " #### Builder\n" " - [new](#new)\n" " - [bind](#bind)\n" " - [bind_all](#bind_all)\n" " - [listening](#listening)\n" " - [listening_random](#listening_random)\n" " - [enable_ipv6](#enable_ipv6)\n" " - [enable_tls](#enable_tls)\n" " - [set_information_name](#set_information_name)\n" " - [quiet](#quiet)\n" " - [idle_timeout](#idle_timeout)\n" " - [on_start](#on_start)\n" " - [on_crash](#on_crash)\n" " #### Server\n" " - [start](#start)\n" " - [supervised](#supervised)\n" " #### Request\n" " - [read_body](#read_body)\n" " - [stream_body](#stream_body)\n" " #### Response\n" " - [text](#text)\n" " - [bytes](#bytes)\n" " - [bits](#bits)\n" " - [string_tree](#string_tree)\n" " - [empty](#empty)\n" " - [json](#json)\n" " - [file](#file)\n" " - [chunked](#chunked)\n" " #### Websocket\n" " - [upgrade_websocket](#upgrade_websocket)\n" " - [send_binary_frame](#send_binary_frame)\n" " - [send_text_frame](#send_text_frame)\n" " - [continue](#continue)\n" " - [continue_with_selector](#continue_with_selector)\n" " - [stop](#stop)\n" " - [stop_abnormal](#stop_abnormal)\n" " #### Experimental\n" " - [use_expression](#use_expression)\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()}. -opaque response_body() :: {text_data, binary()} | {bytes_data, gleam@bytes_tree:bytes_tree()} | {bits_data, bitstring()} | {string_tree_data, gleam@string_tree:string_tree()} | {chunked_data, gleam@yielder:yielder(bitstring())} | {file, ewe@internal@file:io_device(), integer()} | {websocket_connection, gleam@erlang@process:selector(gleam@erlang@process:down())} | empty. -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@http: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(ewe@internal@information:message(socket_address())), integer()}. -type body_error() :: body_too_large | invalid_body. -type stream() :: {consumed, bitstring(), fun((integer()) -> {ok, stream()} | {error, body_error()})} | done. -opaque next(MVV, MVW) :: {continue, MVV, gleam@option:option(gleam@erlang@process:selector(MVW))} | normal_stop | {abnormal_stop, binary()}. -type websocket_message(MVX) :: {text, binary()} | {binary, bitstring()} | {user, MVX}. -file("src/ewe.gleam", 152). -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", 160). -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", 168). -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", 147). ?DOC(" Converts an `IpAddress` to a string for later printing.\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", 189). ?DOC(" Performs an attempt to get the client's socket address.\n"). -spec get_client_info(ewe@internal@http: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", 201). ?DOC( " Retrieves server's socket address. Requires the same name as the one used in\n" " `ewe.with_name` and server to be started. Otherwise, will crash the program.\n" ). -spec get_server_info( gleam@erlang@process:name(ewe@internal@information:message(socket_address())) ) -> {ok, socket_address()} | {error, nil}. get_server_info(Name) -> ewe@internal@information:get(gleam@erlang@process:named_subject(Name)). -file("src/ewe.gleam", 242). -spec transform_response_body(gleam@http@response:response(response_body())) -> gleam@http@response:response(ewe@internal@http: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_data, Yielder} -> {chunked_data, Yielder}; {file, Descriptor, Size} -> {file, Descriptor, Size}; {websocket_connection, Selector} -> {websocket_connection, Selector}; empty -> empty end). -file("src/ewe.gleam", 261). ?DOC( " Sets response body from string, sets `content-type` to\n" " `text/plain; charset=utf-8` and `content-length` headers.\n" ). -spec text(gleam@http@response:response(any()), binary()) -> gleam@http@response:response(response_body()). text(Response, Text) -> _pipe = gleam@http@response:set_body(Response, {text_data, Text}), _pipe@1 = gleam@http@response:set_header( _pipe, <<"content-type"/utf8>>, <<"text/plain; charset=utf-8"/utf8>> ), gleam@http@response:set_header( _pipe@1, <<"content-length"/utf8>>, erlang:integer_to_binary(erlang:byte_size(Text)) ). -file("src/ewe.gleam", 272). ?DOC(" Sets response body from bytes, sets `content-length` header.\n"). -spec bytes(gleam@http@response:response(any()), gleam@bytes_tree:bytes_tree()) -> gleam@http@response:response(response_body()). bytes(Response, Bytes) -> _pipe = gleam@http@response:set_body(Response, {bytes_data, Bytes}), gleam@http@response:set_header( _pipe, <<"content-length"/utf8>>, erlang:integer_to_binary(erlang:iolist_size(Bytes)) ). -file("src/ewe.gleam", 282). ?DOC(" Sets response body from bits, sets `content-length` header.\n"). -spec bits(gleam@http@response:response(any()), bitstring()) -> gleam@http@response:response(response_body()). bits(Response, Bits) -> _pipe = gleam@http@response:set_body(Response, {bits_data, Bits}), gleam@http@response:set_header( _pipe, <<"content-length"/utf8>>, erlang:integer_to_binary(erlang:byte_size(Bits)) ). -file("src/ewe.gleam", 292). ?DOC(" Sets response body from string tree, sets `content-length` header.\n"). -spec string_tree( gleam@http@response:response(any()), gleam@string_tree:string_tree() ) -> gleam@http@response:response(response_body()). string_tree(Response, String_tree) -> _pipe = gleam@http@response:set_body( Response, {string_tree_data, String_tree} ), gleam@http@response:set_header( _pipe, <<"content-length"/utf8>>, erlang:integer_to_binary(erlang:iolist_size(String_tree)) ). -file("src/ewe.gleam", 305). ?DOC(" Sets response body to empty, sets `content-length` header to `0`.\n"). -spec empty(gleam@http@response:response(any())) -> gleam@http@response:response(response_body()). empty(Response) -> _pipe = gleam@http@response:set_body(Response, empty), gleam@http@response:set_header( _pipe, <<"content-length"/utf8>>, <<"0"/utf8>> ). -file("src/ewe.gleam", 314). ?DOC( " Sets response body from string tree (use `gleam_json` package and encode\n" " using `json.to_string_tree`), sets `content-type` to `application/json;\n" " charset=utf-8` and `content-length` headers.\n" ). -spec json(gleam@http@response:response(any()), gleam@string_tree:string_tree()) -> gleam@http@response:response(response_body()). json(Response, Json) -> _pipe = string_tree(Response, Json), gleam@http@response:set_header( _pipe, <<"content-type"/utf8>>, <<"application/json; charset=utf-8"/utf8>> ). -file("src/ewe.gleam", 321). ?DOC(" Sets response body from yielder, sets `transfer-encoding` header to `chunked`.\n"). -spec chunked( gleam@http@response:response(any()), gleam@yielder:yielder(bitstring()) ) -> gleam@http@response:response(response_body()). chunked(Response, Yielder) -> _pipe = gleam@http@response:set_body(Response, {chunked_data, Yielder}), gleam@http@response:set_header( _pipe, <<"transfer-encoding"/utf8>>, <<"chunked"/utf8>> ). -file("src/ewe.gleam", 338). -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", 349). ?DOC(" Sets response body from file, sets `content-length` header.\n"). -spec file(gleam@http@response:response(any()), binary()) -> {ok, gleam@http@response:response(response_body())} | {error, file_error()}. file(Response, Path) -> _pipe = mist_ffi:open_file(Path), _pipe@1 = gleam@result:map_error(_pipe, fun internal_to_file_error/1), gleam@result:map( _pipe@1, fun(File) -> _pipe@2 = gleam@http@response:set_body( Response, {file, erlang:element(2, File), erlang:element(3, File)} ), gleam@http@response:set_header( _pipe@2, <<"content-length"/utf8>>, erlang:integer_to_binary(erlang:element(3, File)) ) end ). -file("src/ewe.gleam", 411). ?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 process 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@http: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>>, gleam_stdlib:println(<<"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(<<"ewe_server_info"/utf8>>), 10000}. -file("src/ewe.gleam", 441). ?DOC(" Binds server to a specific interface. Crashes program if interface is 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", 447). ?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", 453). ?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", 459). ?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", 465). ?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", 471). ?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 mist_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 => 478}) end, Key = case mist_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 => 483}) 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", 492). ?DOC( " Sets a custom process name for server information retrieval, allowing to\n" " use `ewe.get_server_info` after server starts.\n" ). -spec set_information_name( builder(), gleam@erlang@process:name(ewe@internal@information:message(socket_address())) ) -> builder(). set_information_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", 501). ?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", 510). ?DOC(" Sets 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", 516). ?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", 522). ?DOC(" Sets a custom idle timeout in milliseconds for connections. If 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", 535). ?DOC(" Starts the server.\n"). -spec start(builder()) -> {ok, gleam@otp@actor:started(gleam@otp@static_supervisor:supervisor())} | {error, gleam@otp@actor:start_error()}. start(Builder) -> Name = gleam_erlang_ffi:new_name(<<"ewe_glisten"/utf8>>), Handler = fun(Req) -> transform_response_body((erlang:element(2, Builder))(Req)) end, On_crash = transform_response_body(erlang:element(8, Builder)), Subject = gleam@erlang@process:named_subject(erlang:element(9, Builder)), Information = ewe@internal@information:worker(erlang:element(9, Builder)), Glisten_supervisor = begin _pipe = glisten:new( fun ewe@internal@handler:init/1, ewe@internal@handler:loop( Handler, On_crash, erlang:element(10, Builder) ) ), _pipe@1 = glisten:bind(_pipe, erlang:element(4, Builder)), _pipe@2 = (fun(Glisten_builder) -> case erlang:element(5, Builder) of true -> glisten:with_ipv6(Glisten_builder); false -> Glisten_builder end end)(_pipe@1), _pipe@3 = (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@2), _pipe@4 = glisten:start_with_listener_name( _pipe@3, erlang:element(3, Builder), Name ), gleam@result:map( _pipe@4, fun(Started) -> Scheme = case erlang:element(6, Builder) of {some, {_, _}} -> https; none -> http end, Server_info = glisten:get_server_info(Name, 10000), Ip_address = glisten_to_ewe_ip(erlang:element(3, Server_info)), Server = {socket_address, Ip_address, erlang:element(2, Server_info)}, ewe@internal@information:set(Subject, Server), (erlang:element(7, Builder))(Scheme, Server), Started end ) end, Glisten_child = gleam@otp@supervision:supervisor( fun() -> Glisten_supervisor end ), _pipe@5 = gleam@otp@static_supervisor:new(one_for_all), _pipe@6 = gleam@otp@static_supervisor:add(_pipe@5, Glisten_child), _pipe@7 = gleam@otp@static_supervisor:add(_pipe@6, Information), gleam@otp@static_supervisor:start(_pipe@7). -file("src/ewe.gleam", 593). ?DOC(" Creates a supervisor that can be appended to a 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", 622). ?DOC( " Reads body from a request. If request body is malformed, `InvalidBody`\n" " error is returned. On success, returns a request with body converted to\n" " `BitArray`.\n" " - When `transfer-encoding` header set as `chunked`, `BodyTooLarge` error is returned if\n" " 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@http:connection()), integer() ) -> {ok, gleam@http@request:request(bitstring())} | {error, body_error()}. read_body(Req, Bytes_limit) -> case ewe@internal@http: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", 654). -spec consumer_adapter( fun((integer()) -> {ok, ewe@internal@http:stream()} | {error, ewe@internal@http: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", 647). ?DOC(" Streams the request body.\n"). -spec stream_body(gleam@http@request:request(ewe@internal@http:connection())) -> {ok, fun((integer()) -> {ok, stream()} | {error, body_error()})} | {error, body_error()}. stream_body(Req) -> case ewe@internal@http:stream_body(Req) of {ok, Consumer} -> {ok, consumer_adapter(Consumer)}; {error, _} -> {error, invalid_body} end. -file("src/ewe.gleam", 693). ?DOC(" Instructs WebSocket connection to continue processing.\n"). -spec continue(MXP) -> next(MXP, any()). continue(User_state) -> {continue, User_state, none}. -file("src/ewe.gleam", 700). ?DOC( " Instructs WebSocket connection to continue processing, including selector\n" " for custom messages.\n" ). -spec continue_with_selector(MXT, gleam@erlang@process:selector(MXU)) -> next(MXT, MXU). continue_with_selector(User_state, Selector) -> {continue, User_state, {some, Selector}}. -file("src/ewe.gleam", 709). ?DOC(" Instructs WebSocket connection to stop.\n"). -spec stop() -> next(any(), any()). stop() -> normal_stop. -file("src/ewe.gleam", 715). ?DOC(" Instructs WebSocket connection to stop with abnormal reason.\n"). -spec stop_abnormal(binary()) -> next(any(), any()). stop_abnormal(Reason) -> {abnormal_stop, Reason}. -file("src/ewe.gleam", 719). -spec to_internal_next(next(MYG, MYH)) -> ewe@internal@websocket:websocket_next(MYG, MYH). to_internal_next(Next) -> case Next of {continue, User_state, Selector} -> {continue, User_state, Selector}; normal_stop -> normal_stop; {abnormal_stop, Reason} -> {abnormal_stop, Reason} end. -file("src/ewe.gleam", 737). -spec transform_websocket_message(ewe@internal@websocket:websocket_message(MYM)) -> {ok, websocket_message(MYM)} | {error, nil}. transform_websocket_message(Message) -> case Message of {websocket_frame, {data, Frame}} -> ewe@internal@gramps@websocket:match_data_frame( Frame, fun(Payload, _) -> _pipe = gleam@bit_array:to_string(Payload), gleam@result:map(_pipe, fun(Field@0) -> {text, Field@0} end) end, fun(Payload@1, _) -> {ok, {binary, Payload@1}} end ); {user_message, User_message} -> {ok, {user, User_message}}; _ -> {error, nil} end. -file("src/ewe.gleam", 760). ?DOC( " Upgrade request to a WebSocket connection. If the initial request is not\n" " valid for WebSocket upgrade, 400 response is sent. Handler must return\n" " instruction on how WebSocket connection should proceed.\n" ). -spec upgrade_websocket( gleam@http@request:request(ewe@internal@http:connection()), fun((ewe@internal@websocket:websocket_connection(), gleam@erlang@process:selector(MYR)) -> {MYT, gleam@erlang@process:selector(MYR)}), fun((ewe@internal@websocket:websocket_connection(), MYT, websocket_message(MYR)) -> next(MYT, MYR)), fun((ewe@internal@websocket:websocket_connection(), MYT) -> 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, continue(State)), to_internal_next(_pipe@2) end, Transport = erlang:element(2, erlang:element(4, Req)), Socket = erlang:element(3, erlang:element(4, Req)), Resp = begin gleam@result:'try'( begin _pipe@3 = ewe@internal@http:upgrade_websocket( Req, Transport, Socket ), gleam@result:replace_error( _pipe@3, begin _pipe@4 = gleam@http@response:new(400), gleam@http@response:set_body(_pipe@4, empty) end ) end, fun(_use0) -> {Extensions, Permessage_deflate} = _use0, gleam@result:'try'( begin _pipe@5 = ewe@internal@websocket:start( Transport, Socket, On_init, Handler@1, On_close, Extensions, Permessage_deflate ), gleam@result:replace_error( _pipe@5, begin _pipe@6 = gleam@http@response:new(500), gleam@http@response:set_body(_pipe@6, empty) end ) end, fun(Selector) -> _pipe@7 = gleam@http@response:new(500), _pipe@8 = gleam@http@response:set_body( _pipe@7, {websocket_connection, Selector} ), {ok, _pipe@8} end ) end ) end, gleam@result:unwrap_both(Resp). -file("src/ewe.gleam", 811). ?DOC(" Sends a binary frame to the websocket client.\n"). -spec send_binary_frame( ewe@internal@websocket:websocket_connection(), bitstring() ) -> {ok, nil} | {error, glisten@socket:socket_reason()}. send_binary_frame(Conn, Bits) -> ewe@internal@websocket:send_frame( fun ewe@internal@gramps@websocket:encode_binary_frame/3, erlang:element(2, Conn), erlang:element(3, Conn), erlang:element(4, Conn), Bits ). -file("src/ewe.gleam", 826). ?DOC(" Sends a text frame to the websocket client.\n"). -spec send_text_frame(ewe@internal@websocket:websocket_connection(), binary()) -> {ok, nil} | {error, glisten@socket:socket_reason()}. send_text_frame(Conn, Text) -> ewe@internal@websocket:send_frame( fun ewe@internal@gramps@websocket:encode_text_frame/3, erlang:element(2, Conn), erlang:element(3, Conn), erlang:element(4, Conn), Text ). -file("src/ewe.gleam", 876). ?DOC( " Experimental function that simplifies error handling in handlers when\n" " working with `Result` type.\n" " \n" " ## Example\n" " \n" " ```gleam\n" " pub fn handle_echo(\n" " req: Request,\n" " ) -> Response {\n" " let content_type =\n" " request.get_header(req, \"content-type\")\n" " |> result.unwrap(\"text/plain\")\n" "\n" " // Start the use_expression block\n" " use <- ewe.use_expression()\n" "\n" " // Now you can use result.try with use expressions\n" " // If any step fails, the error response is automatically returned\n" " use req <- result.try(\n" " ewe.read_body(req, 1024)\n" " |> result.replace_error(\n" " response.new(400)\n" " |> ewe.json(error_json(\"Invalid request body\")),\n" " ),\n" " )\n" "\n" " response.new(200)\n" " |> ewe.bits(req.body)\n" " |> response.set_header(\"content-type\", content_type)\n" " |> Ok \n" "}\n" " ```\n" ). -spec use_expression( fun(() -> {ok, gleam@http@response:response(response_body())} | {error, gleam@http@response:response(response_body())}) ) -> gleam@http@response:response(response_body()). use_expression(Handler) -> gleam@result:unwrap_both(Handler()).