-module(gftp@stream). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/gftp/stream.gleam"). -export(['receive'/2, receive_exact/3, send/2, upgrade_to_ssl/2, downgrade_to_tcp/1, local_address/1, peer_address/1, set_line_mode/1, set_raw_mode/1, shutdown/1]). -export_type([data_stream/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( " The stream module provides an interface for working with a network stream, which can either be a TCP stream or a TLS stream.\n" " It abstracts away the differences between the two types of streams and provides a unified interface for reading and writing data.\n" ). -type data_stream() :: {ssl, kafein:ssl_socket(), mug:socket()} | {tcp, mug:socket()}. -file("src/gftp/stream.gleam", 45). ?DOC( " Receive a message from the peer.\n" "\n" " Errors if the socket is closed, if the timeout is reached, or if any other error occurs during the receive operation.\n" " The error is returned as a [`mug.Error`]. In case of success, it returns the received data as a `BitArray`.\n" ). -spec 'receive'(data_stream(), integer()) -> {ok, bitstring()} | {error, mug:error()}. 'receive'(Stream, Timeout) -> case Stream of {ssl, Ssl_socket, _} -> kafein:'receive'(Ssl_socket, Timeout); {tcp, Tcp_socket} -> mug:'receive'(Tcp_socket, Timeout) end. -file("src/gftp/stream.gleam", 56). ?DOC( " Receive an exact number of bytes from the peer.\n" "\n" " Errors if the socket is closed, if the timeout is reached, or if any other error occurs during the receive operation.\n" " The error is returned as a [`mug.Error`]. In case of success, it returns the received data as a `BitArray`.\n" ). -spec receive_exact(data_stream(), integer(), integer()) -> {ok, bitstring()} | {error, mug:error()}. receive_exact(Stream, Size, Timeout) -> case Stream of {ssl, Ssl_socket, _} -> kafein:receive_exact(Ssl_socket, Size, Timeout); {tcp, Tcp_socket} -> mug:receive_exact(Tcp_socket, Size, Timeout) end. -file("src/gftp/stream.gleam", 71). ?DOC( " Sends data over the provided stream.\n" " It handles both SSL and TCP streams, abstracting away the differences between them.\n" "\n" " Returns a Result indicating success (`Nil`) or an error ([`mug.Error`]) if the send operation fails.\n" ). -spec send(data_stream(), bitstring()) -> {ok, nil} | {error, mug:error()}. send(Stream, Data) -> case Stream of {ssl, Ssl_socket, _} -> kafein:send(Ssl_socket, Data); {tcp, Tcp_socket} -> mug:send(Tcp_socket, Data) end. -file("src/gftp/stream.gleam", 79). ?DOC(" Upgrades a TCP stream to an SSL stream using the provided options. If the stream is already an SSL stream, it returns it as is.\n"). -spec upgrade_to_ssl(data_stream(), kafein:wrap_options()) -> {ok, data_stream()} | {error, kafein:error()}. upgrade_to_ssl(Stream, Options) -> case Stream of {ssl, _, _} -> {ok, Stream}; {tcp, Tcp_socket} -> case kafein:wrap(stream_ffi:patch_wrap_options(Options), Tcp_socket) of {ok, Ssl_socket} -> {ok, {ssl, Ssl_socket, Tcp_socket}}; {error, E} -> {error, E} end end. -file("src/gftp/stream.gleam", 95). ?DOC(" Downgrades an SSL stream to a TCP stream. If the stream is already a TCP stream, it returns it as is.\n"). -spec downgrade_to_tcp(data_stream()) -> data_stream(). downgrade_to_tcp(Stream) -> case Stream of {ssl, _, Tcp_socket} -> {tcp, Tcp_socket}; {tcp, _} -> Stream end. -file("src/gftp/stream.gleam", 103). ?DOC(" Retrieves the local address (IP and port) of the underlying TCP socket.\n"). -spec local_address(data_stream()) -> {ok, {binary(), integer()}} | {error, mug:error()}. local_address(Stream) -> case Stream of {ssl, _, Tcp_socket} -> stream_ffi:local_address(Tcp_socket); {tcp, Tcp_socket@1} -> stream_ffi:local_address(Tcp_socket@1) end. -file("src/gftp/stream.gleam", 111). ?DOC(" Retrieves the peer address (IP and port) of the underlying TCP socket.\n"). -spec peer_address(data_stream()) -> {ok, {binary(), integer()}} | {error, mug:error()}. peer_address(Stream) -> case Stream of {ssl, _, Tcp_socket} -> stream_ffi:peer_address(Tcp_socket); {tcp, Tcp_socket@1} -> stream_ffi:peer_address(Tcp_socket@1) end. -file("src/gftp/stream.gleam", 120). ?DOC( " Set the socket to line-delimited packet mode ({packet, line}).\n" " In this mode, recv returns one complete line per call.\n" ). -spec set_line_mode(data_stream()) -> nil. set_line_mode(Stream) -> case Stream of {ssl, Ssl_socket, _} -> stream_ffi:set_ssl_packet_line(Ssl_socket); {tcp, Tcp_socket} -> stream_ffi:set_tcp_packet_line(Tcp_socket) end. -file("src/gftp/stream.gleam", 129). ?DOC( " Set the socket back to raw packet mode ({packet, raw}).\n" " In this mode, recv returns whatever data is available.\n" ). -spec set_raw_mode(data_stream()) -> nil. set_raw_mode(Stream) -> case Stream of {ssl, Ssl_socket, _} -> stream_ffi:set_ssl_packet_raw(Ssl_socket); {tcp, Tcp_socket} -> stream_ffi:set_tcp_packet_raw(Tcp_socket) end. -file("src/gftp/stream.gleam", 138). ?DOC( " Shuts down the provided stream, whether it's an SSL or TCP stream.\n" " It abstracts away the differences between the two types of streams and provides a unified interface for shutting them down.\n" ). -spec shutdown(data_stream()) -> {ok, nil} | {error, mug:error()}. shutdown(Stream) -> case Stream of {ssl, Ssl_socket, _} -> kafein_ffi:shutdown(Ssl_socket); {tcp, Tcp_socket} -> mug_ffi:shutdown(Tcp_socket) end.