Packages
thousand_island
0.1.2
1.5.0
1.4.3
1.4.2
1.4.1
1.4.0
1.3.14
1.3.13
1.3.12
1.3.11
1.3.10
1.3.9
1.3.8
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.0
1.0.0-pre.7
1.0.0-pre.6
1.0.0-pre.5
1.0.0-pre.4
1.0.0-pre.3
1.0.0-pre.2
1.0.0-pre.1
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
A simple & modern pure Elixir socket server
Current section
Files
Jump to
Current section
Files
lib/thousand_island/socket.ex
defmodule ThousandIsland.Socket do
@moduledoc """
Encapsulates a client connection's underlying socket, providing a facility to
read, write, and otherwise manipulate a connection from a client.
`ThousandIsland.Socket` instances are passed to the application layer of a server
via the `c:ThousandIsland.Handler.handle_connection/2` callback.
"""
defstruct socket: nil, transport_module: nil, connection_id: nil
alias ThousandIsland.{ServerConfig, Transport}
@typedoc "A reference to a socket along with metadata describing how to use it"
@opaque t :: %__MODULE__{
socket: Transport.socket(),
transport_module: module(),
connection_id: String.t()
}
@doc false
@spec new(Transport.socket(), String.t(), ServerConfig.t()) :: t()
def new(socket, connection_id, %ServerConfig{transport_module: transport_module}) do
%__MODULE__{socket: socket, transport_module: transport_module, connection_id: connection_id}
end
@doc """
Returns available bytes on the given socket. Up to `num_bytes` bytes will be
returned (0 can be passed in to get the next 'available' bytes, typically the
next packet). If insufficient bytes are available, the functino can wait `timeout`
milliseconds for data to arrive.
"""
@spec recv(t(), non_neg_integer(), timeout()) :: Transport.on_recv()
def recv(
%__MODULE__{
socket: socket,
transport_module: transport_module,
connection_id: connection_id
},
length \\ 0,
timeout \\ :infinity
) do
start = System.monotonic_time()
result = transport_module.recv(socket, length, timeout)
duration = System.monotonic_time() - start
:telemetry.execute([:socket, :recv, :complete], %{duration: duration, result: result}, %{
connection_id: connection_id
})
result
end
@doc """
Sends the given data (specified as a binary or an IO list) on the given socket.
"""
@spec send(t(), IO.iodata()) :: :ok | {:error, term()}
def send(
%__MODULE__{
socket: socket,
transport_module: transport_module,
connection_id: connection_id
},
data
) do
start = System.monotonic_time()
result = transport_module.send(socket, data)
duration = System.monotonic_time() - start
:telemetry.execute(
[:socket, :send, :complete],
%{duration: duration, result: result, data: data},
%{
connection_id: connection_id
}
)
result
end
@doc """
Sets the given flags on the socket
"""
@spec setopts(t(), Transport.socket_opts()) :: :ok | {:error, String.t()}
def setopts(%__MODULE__{socket: socket, transport_module: transport_module}, options) do
transport_module.setopts(socket, options)
end
@doc """
Shuts down the socket in the given direction.
"""
@spec shutdown(t(), Transport.way()) :: :ok
def shutdown(
%__MODULE__{
socket: socket,
transport_module: transport_module,
connection_id: connection_id
},
way
) do
result = transport_module.shutdown(socket, way)
:telemetry.execute([:socket, :shutdown, :complete], %{}, %{connection_id: connection_id})
result
end
@doc """
Closes the given socket.
"""
@spec close(t()) :: :ok
def close(%__MODULE__{
socket: socket,
transport_module: transport_module,
connection_id: connection_id
}) do
result = transport_module.close(socket)
:telemetry.execute([:socket, :close, :complete], %{}, %{connection_id: connection_id})
result
end
@doc """
Returns information in the form of `t:ThousandIsland.Transport.socket_info()` about the local end of the socket.
"""
@spec local_info(t()) :: Transport.socket_info()
def local_info(%__MODULE__{socket: socket, transport_module: transport_module}) do
transport_module.local_info(socket)
end
@doc """
Returns information in the form of `t:ThousandIsland.Transport.socket_info()` about the remote end of the socket.
"""
@spec peer_info(t()) :: Transport.socket_info()
def peer_info(%__MODULE__{socket: socket, transport_module: transport_module}) do
transport_module.peer_info(socket)
end
end