1.7 KiB · text History 9c0fc16
defmodule LambentExWeb.Layouts do
  use LambentExWeb, :html

  embed_templates "layouts/*"

  @doc """
  Base urls a phone on the same network could use to reach this box, best
  guess first. The browsed host is the honest answer unless it is loopback,
  in which case whoever is reading the qr is not the machine running it.
  """
  def pair_urls(socket) do
    port = pair_port(socket)

    browsed =
      case socket.host_uri do
        %URI{host: host} when is_binary(host) -> ["#{scheme(socket)}://#{host}:#{port}"]
        _otherwise -> []
      end

    lan =
      LambentEx.Scan.ESP8266x7777.get_valid_interfaces()
      |> Enum.map(fn {_iface, ifd} -> Keyword.get(ifd, :addr) end)
      |> Enum.reject(&is_nil/1)
      |> Enum.map(fn addr -> "http://#{addr |> Tuple.to_list() |> Enum.join(".")}:#{port}" end)

    (Enum.reject(browsed, &loopback?/1) ++ lan ++ browsed) |> Enum.uniq()
  end

  @doc """
  The url the qr encodes — a plain http url, so any camera app opens the web
  ui, and an android client can claim the same host with an app link.
  """
  def pair_url(socket), do: pair_urls(socket) |> List.first()

  def pair_qr(nil), do: nil

  def pair_qr(url) do
    url
    |> EQRCode.encode()
    |> EQRCode.svg(width: 240, background_color: "#ffffff", color: "#000000")
    |> Phoenix.HTML.raw()
  end

  defp pair_port(socket) do
    case socket.host_uri do
      %URI{port: port} when is_integer(port) -> port
      _otherwise -> LambentExWeb.Endpoint.config(:http)[:port] || 4000
    end
  end

  defp scheme(socket) do
    case socket.host_uri do
      %URI{scheme: scheme} when is_binary(scheme) -> scheme
      _otherwise -> "http"
    end
  end

  defp loopback?(url) do
    String.contains?(url, "//localhost:") or String.contains?(url, "//127.")
  end
end