defmodule Tortoise.Transport do @moduledoc """ Abstraction for working with network connections; this is done to normalize the `:ssl` and `:gen_tcp` modules, so they get a similar interface. This work has been heavily inspired by the Ranch project by NineNines. """ @opaque t :: %__MODULE__{ type: atom(), host: binary(), port: non_neg_integer(), opts: [term()] } @enforce_keys [:type, :host, :port] defstruct type: nil, host: nil, port: nil, opts: [] @doc """ Create a new Transport specification used by the Connection process to log on to the MQTT server. This allow us to filter the options passed to the connection type, and guide the user to connect to the individual transport type. """ @spec new({atom(), [term()]}) :: t() def new({transport, opts}) do %Tortoise.Transport{type: ^transport} = transport.new(opts) end @type socket() :: any() @type opts() :: any() @type stats() :: any() @callback new(opts()) :: Tortoise.Transport.t() @callback listen(opts()) :: {:ok, socket()} | {:error, atom()} @callback accept(socket(), timeout()) :: {:ok, socket()} | {:error, :closed | :timeout | atom()} @callback accept_ack(socket(), timeout()) :: :ok @callback connect(charlist(), :inet.port_number(), opts(), timeout()) :: {:ok, socket()} | {:error, atom()} @callback recv(socket(), non_neg_integer(), timeout()) :: {:ok, any()} | {:error, :closed | :timeout | atom()} @callback send(socket(), iodata()) :: :ok | {:error, atom()} @callback setopts(socket(), opts()) :: :ok | {:error, atom()} @callback getopts(socket(), [atom()]) :: {:ok, opts()} | {:error, atom()} @callback getstat(socket()) :: {:ok, stats()} | {:error, atom()} @callback getstat(socket(), [atom()]) :: {:ok, stats()} | {:error, atom()} @callback controlling_process(socket(), pid()) :: :ok | {:error, :closed | :now_owner | atom()} @callback peername(socket()) :: {:ok, {:inet.ip_address(), :inet.port_number()}} | {:error, atom()} @callback sockname(socket()) :: {:ok, {:inet.ip_address(), :inet.port_number()}} | {:error, atom()} @callback shutdown(socket(), :read | :write | :read_write) :: :ok | {:error, atom()} @callback close(socket()) :: :ok end