defmodule ExICE.URI do @moduledoc """ Module representing STUN URI. Implementation of RFC 7064. We could try to use URI module from Elixir but RFC 7064 states: While these two ABNF productions are defined in [RFC3986] as components of the generic hierarchical URI, this does not imply that the "stun" and "stuns" URI schemes are hierarchical URIs. Developers MUST NOT use a generic hierarchical URI parser to parse a "stun" or "stuns" URI. """ @type scheme :: :stun | :stuns @type t() :: %__MODULE__{ scheme: scheme(), host: String.t(), port: :inet.port_number() } @enforce_keys [:host] defstruct @enforce_keys ++ [scheme: :stun, port: 3478] @doc """ Parses URI string into `t:t/0`. """ @spec parse(String.t()) :: {:ok, t()} | :error def parse("stun" <> ":" <> host_and_port) do do_parse(:stun, host_and_port) end def parse("stuns" <> ":" <> host_and_port) do do_parse(:stuns, host_and_port) end def parse(_other), do: :error defp do_parse(scheme, host_and_port) do case String.split(host_and_port, ":") do [host, port] when host != "" -> case Integer.parse(port) do {port, ""} -> {:ok, %__MODULE__{scheme: scheme, host: host, port: port}} :error -> :error end [host] when host != "" -> {:ok, %__MODULE__{scheme: scheme, host: host}} _other -> :error end end end