-module(pgl@internal@socket). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pgl/internal/socket.gleam"). -export([host/2, port/2, timeout/2, ipv6/2, with_send/2, with_receive/2, with_shutdown/2, parameter/3, connect/1, to_ssl/2, send/2, 'receive'/2, shutdown/1, supervised/1, new/0, factory/1]). -export_type([tcp_socket/0, ssl_socket/0, internal_socket/0, builder/0, socket/0, msg/0, factory/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 tcp_socket() :: any(). -type ssl_socket() :: any(). -opaque internal_socket() :: {tcp, tcp_socket()} | {ssl, ssl_socket()}. -opaque builder() :: {builder, binary(), integer(), boolean(), integer(), fun((internal_socket(), bitstring()) -> {ok, nil} | {error, pgl@internal:posix_error()}), fun((internal_socket(), integer(), integer()) -> {ok, bitstring()} | {error, pgl@internal:posix_error()}), fun((internal_socket()) -> {ok, nil} | {error, pgl@internal:posix_error()})}. -opaque socket() :: {socket, gleam@erlang@process:subject(msg()), binary(), integer(), gleam@dict:dict(binary(), binary()), fun((internal_socket(), bitstring()) -> {ok, nil} | {error, pgl@internal:posix_error()}), fun((internal_socket(), integer(), integer()) -> {ok, bitstring()} | {error, pgl@internal:posix_error()}), fun((internal_socket()) -> {ok, nil} | {error, pgl@internal:posix_error()})}. -opaque msg() :: {ssl_upgrade, gleam@erlang@process:subject({ok, nil} | {error, pgl@internal:internal_error()}), binary(), boolean()} | {send, gleam@erlang@process:subject({ok, nil} | {error, pgl@internal:posix_error()}), fun((internal_socket(), bitstring()) -> {ok, nil} | {error, pgl@internal:posix_error()}), bitstring()} | {'receive', gleam@erlang@process:subject({ok, bitstring()} | {error, pgl@internal:posix_error()}), fun((internal_socket(), integer(), integer()) -> {ok, bitstring()} | {error, pgl@internal:posix_error()}), integer(), integer()} | {shutdown, gleam@erlang@process:subject({ok, nil} | {error, pgl@internal:posix_error()}), fun((internal_socket()) -> {ok, nil} | {error, pgl@internal:posix_error()})}. -opaque factory() :: {factory, gleam@erlang@process:name(gleam@otp@factory_supervisor:message(builder(), socket())), builder()}. -file("src/pgl/internal/socket.gleam", 78). ?DOC(false). -spec host(builder(), binary()) -> builder(). host(Builder, Host) -> {builder, Host, erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder)}. -file("src/pgl/internal/socket.gleam", 82). ?DOC(false). -spec port(builder(), integer()) -> builder(). port(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)}. -file("src/pgl/internal/socket.gleam", 86). ?DOC(false). -spec timeout(builder(), integer()) -> builder(). timeout(Builder, Timeout) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), Timeout, erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder)}. -file("src/pgl/internal/socket.gleam", 90). ?DOC(false). -spec ipv6(builder(), boolean()) -> builder(). ipv6(Builder, Ipv6) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), Ipv6, erlang:element(5, Builder), erlang:element(6, Builder), erlang:element(7, Builder), erlang:element(8, Builder)}. -file("src/pgl/internal/socket.gleam", 103). ?DOC(false). -spec with_send( builder(), fun((internal_socket(), bitstring()) -> {ok, nil} | {error, pgl@internal:posix_error()}) ) -> builder(). with_send(Builder, Send) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), Send, erlang:element(7, Builder), erlang:element(8, Builder)}. -file("src/pgl/internal/socket.gleam", 107). ?DOC(false). -spec with_receive( builder(), fun((internal_socket(), integer(), integer()) -> {ok, bitstring()} | {error, pgl@internal:posix_error()}) ) -> builder(). with_receive(Builder, Receive) -> {builder, erlang:element(2, Builder), erlang:element(3, Builder), erlang:element(4, Builder), erlang:element(5, Builder), erlang:element(6, Builder), Receive, erlang:element(8, Builder)}. -file("src/pgl/internal/socket.gleam", 111). ?DOC(false). -spec with_shutdown( builder(), fun((internal_socket()) -> {ok, nil} | {error, pgl@internal:posix_error()}) ) -> builder(). with_shutdown(Builder, Shutdown) -> {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), Shutdown}. -file("src/pgl/internal/socket.gleam", 131). ?DOC(false). -spec parameter(socket(), binary(), binary()) -> socket(). parameter(Sock, Key, Value) -> Parameters = begin _pipe = erlang:element(5, Sock), gleam@dict:insert(_pipe, Key, Value) end, {socket, erlang:element(2, Sock), erlang:element(3, Sock), erlang:element(4, Sock), Parameters, erlang:element(6, Sock), erlang:element(7, Sock), erlang:element(8, Sock)}. -file("src/pgl/internal/socket.gleam", 136). ?DOC(false). -spec connect(factory()) -> {ok, socket()} | {error, gleam@otp@actor:start_error()}. connect(Factory) -> _pipe = gleam@otp@factory_supervisor:get_by_name(erlang:element(2, Factory)), _pipe@1 = gleam@otp@factory_supervisor:start_child( _pipe, erlang:element(3, Factory) ), gleam@result:map(_pipe@1, fun(Started) -> erlang:element(3, Started) end). -file("src/pgl/internal/socket.gleam", 181). ?DOC(false). -spec to_ssl(socket(), boolean()) -> {ok, socket()} | {error, pgl@internal:internal_error()}. to_ssl(Socket, Verified) -> _pipe = gleam@otp@actor:call( erlang:element(2, Socket), 1000, fun(_capture) -> {ssl_upgrade, _capture, erlang:element(3, Socket), Verified} end ), gleam@result:replace(_pipe, Socket). -file("src/pgl/internal/socket.gleam", 189). ?DOC(false). -spec send(socket(), bitstring()) -> {ok, socket()} | {error, pgl@internal:internal_error()}. send(Socket, Payload) -> _pipe = gleam@otp@actor:call( erlang:element(2, Socket), 1000, fun(_capture) -> {send, _capture, erlang:element(6, Socket), Payload} end ), _pipe@1 = gleam@result:map_error( _pipe, fun(Code) -> {socket_error, Code, <<"Failed to send"/utf8>>} end ), gleam@result:replace(_pipe@1, Socket). -file("src/pgl/internal/socket.gleam", 200). ?DOC(false). -spec 'receive'(socket(), integer()) -> {ok, bitstring()} | {error, pgl@internal:internal_error()}. 'receive'(Conn, Length) -> _pipe = gleam@otp@actor:call( erlang:element(2, Conn), erlang:element(4, Conn), fun(_capture) -> {'receive', _capture, erlang:element(7, Conn), Length, erlang:element(4, Conn)} end ), gleam@result:map_error( _pipe, fun(Code) -> {socket_error, Code, <<"Failed to receive"/utf8>>} end ). -file("src/pgl/internal/socket.gleam", 215). ?DOC(false). -spec shutdown(socket()) -> {ok, nil} | {error, pgl@internal:internal_error()}. shutdown(Conn) -> _pipe = gleam@otp@actor:call( erlang:element(2, Conn), 1000, fun(_capture) -> {shutdown, _capture, erlang:element(8, Conn)} end ), gleam@result:map_error( _pipe, fun(Code) -> {socket_error, Code, <<"Failed to shutdown"/utf8>>} end ). -file("src/pgl/internal/socket.gleam", 282). ?DOC(false). -spec tcp_connect(binary(), integer(), boolean()) -> {ok, internal_socket()} | {error, pgl@internal:internal_error()}. tcp_connect(Host, Port, Ipv6) -> _pipe = Host, _pipe@1 = unicode:characters_to_list(_pipe), _pipe@2 = pgl_ffi:gen_tcp_connect(_pipe@1, Port, Ipv6), _pipe@3 = gleam@result:map(_pipe@2, fun(Field@0) -> {tcp, Field@0} end), gleam@result:map_error( _pipe@3, fun(Code) -> {socket_error, Code, <<"Failed to connect"/utf8>>} end ). -file("src/pgl/internal/socket.gleam", 264). ?DOC(false). -spec tcp_to_ssl(internal_socket(), binary(), boolean()) -> {ok, internal_socket()} | {error, pgl@internal:internal_error()}. tcp_to_ssl(Socket, Host, Verified) -> _pipe@2 = case Socket of {tcp, Sock} -> _pipe = Sock, _pipe@1 = pgl_ffi:ssl_connect(_pipe, Host, Verified), gleam@result:map(_pipe@1, fun(Field@0) -> {ssl, Field@0} end); _ -> {ok, Socket} end, gleam@result:map_error( _pipe@2, fun(Code) -> {socket_error, Code, <<"Failed to connect SSL"/utf8>>} end ). -file("src/pgl/internal/socket.gleam", 222). ?DOC(false). -spec handle_message(internal_socket(), msg()) -> gleam@otp@actor:next(internal_socket(), msg()). handle_message(Sock, Msg) -> case Msg of {ssl_upgrade, Client, Host, Verified} -> _pipe = case tcp_to_ssl(Sock, Host, Verified) of {ok, Ssl} -> gleam@otp@actor:send(Client, {ok, nil}), Ssl; {error, Err} -> gleam@otp@actor:send(Client, {error, Err}), Sock end, gleam@otp@actor:continue(_pipe); {send, Client@1, Send, Payload} -> _pipe@1 = Send(Sock, Payload), _pipe@2 = gleam@result:replace(_pipe@1, nil), gleam@otp@actor:send(Client@1, _pipe@2), gleam@otp@actor:continue(Sock); {'receive', Client@2, Receive, Length, Timeout} -> _pipe@3 = Receive(Sock, Length, Timeout), gleam@otp@actor:send(Client@2, _pipe@3), gleam@otp@actor:continue(Sock); {shutdown, Client@3, Shutdown} -> _pipe@4 = Shutdown(Sock), gleam@otp@actor:send(Client@3, _pipe@4), gleam@otp@actor:stop() end. -file("src/pgl/internal/socket.gleam", 150). ?DOC(false). -spec start_socket(builder()) -> {ok, gleam@otp@actor:started(socket())} | {error, gleam@otp@actor:start_error()}. start_socket(Builder) -> {builder, Host, Port, Ipv6, Timeout, Send, Receive, Shutdown} = Builder, _pipe@6 = gleam@otp@actor:new_with_initialiser( 1000, fun(Subject) -> _pipe = tcp_connect(Host, Port, Ipv6), _pipe@1 = gleam@result:map_error( _pipe, fun pgl@internal:error_to_string/1 ), gleam@result:map( _pipe@1, fun(Sock) -> Selector = begin _pipe@2 = gleam_erlang_ffi:new_selector(), gleam@erlang@process:select(_pipe@2, Subject) end, Socket = {socket, Subject, Host, Timeout, maps:new(), Send, Receive, Shutdown}, _pipe@3 = Sock, _pipe@4 = gleam@otp@actor:initialised(_pipe@3), _pipe@5 = gleam@otp@actor:selecting(_pipe@4, Selector), gleam@otp@actor:returning(_pipe@5, Socket) end ) end ), _pipe@7 = gleam@otp@actor:on_message(_pipe@6, fun handle_message/2), gleam@otp@actor:start(_pipe@7). -file("src/pgl/internal/socket.gleam", 142). ?DOC(false). -spec supervised(factory()) -> gleam@otp@supervision:child_specification(gleam@otp@factory_supervisor:supervisor(builder(), socket())). supervised(Factory) -> _pipe = gleam@otp@factory_supervisor:worker_child(fun start_socket/1), _pipe@1 = gleam@otp@factory_supervisor:named( _pipe, erlang:element(2, Factory) ), gleam@otp@factory_supervisor:supervised(_pipe@1). -file("src/pgl/internal/socket.gleam", 296). ?DOC(false). -spec socket_send(internal_socket(), bitstring()) -> {ok, nil} | {error, pgl@internal:posix_error()}. socket_send(Socket, Payload) -> case Socket of {tcp, Sock} -> pgl_ffi:gen_tcp_send(Sock, Payload); {ssl, Sock@1} -> pgl_ffi:ssl_send(Sock@1, Payload) end. -file("src/pgl/internal/socket.gleam", 306). ?DOC(false). -spec socket_receive(internal_socket(), integer(), integer()) -> {ok, bitstring()} | {error, pgl@internal:posix_error()}. socket_receive(Socket, Length, Timeout) -> case Socket of {tcp, Sock} -> pgl_ffi:gen_tcp_recv(Sock, Length, Timeout); {ssl, Sock@1} -> pgl_ffi:ssl_recv(Sock@1, Length) end. -file("src/pgl/internal/socket.gleam", 317). ?DOC(false). -spec socket_shutdown(internal_socket()) -> {ok, nil} | {error, pgl@internal:posix_error()}. socket_shutdown(Socket) -> case Socket of {tcp, Sock} -> pgl_ffi:gen_tcp_shutdown(Sock); {ssl, Sock@1} -> pgl_ffi:ssl_shutdown(Sock@1) end. -file("src/pgl/internal/socket.gleam", 66). ?DOC(false). -spec new() -> builder(). new() -> {builder, <<"127.0.0.1"/utf8>>, 5432, false, 1000, fun socket_send/2, fun socket_receive/3, fun socket_shutdown/1}. -file("src/pgl/internal/socket.gleam", 124). ?DOC(false). -spec factory(builder()) -> factory(). factory(Builder) -> _pipe = <<"pgl_sockets"/utf8>>, _pipe@1 = gleam_erlang_ffi:new_name(_pipe), {factory, _pipe@1, Builder}.