defmodule ChronoscopeWeb.API.V1.Gemini.ConnectionController do use ChronoscopeWeb, :controller require Logger alias Chronoscope.Gemini @default_port 1965 @default_path "/" @max_host_length 255 @gemini Application.compile_env(:chronoscope, :gemini, Gemini) def get(conn, %{"host" => host, "port" => port, "path" => path}) do try do handle_get(conn, %{host: host, port: String.to_integer(port), path: path}) rescue ArgumentError -> bad_request_response(conn, "invalid port") end end def get(conn, %{"host" => host, "path" => path}) do handle_get(conn, %{host: host, port: @default_port, path: path}) end def get(conn, %{"host" => host, "port" => port}) do try do handle_get(conn, %{host: host, port: String.to_integer(port), path: @default_path}) rescue ArgumentError -> bad_request_response(conn, "invalid port") end end def get(conn, %{"host" => host}) do handle_get(conn, %{host: host, port: @default_port, path: @default_path}) end def get(conn, _params) do bad_request_response(conn, "missing host") end defp handle_get(conn, %{host: host, port: port, path: path}) when port > 0 and port < 65536 do case connect(host, port, path) do {:ok, response} -> json(conn, %{status: :ok, response: format_response(response)}) {:error, error} -> json(conn, %{status: :error, reason: to_string(error)}) end end defp handle_get(conn, _params) do bad_request_response(conn, "port out of range") end defp connect(host, port, path) do # TODO - max path length host |> String.slice(0, @max_host_length) |> @gemini.connect(port, path) end defp format_response(response) do Map.take(response, [:status, :mime_type, :body, :cert_expiration]) end defp bad_request_response(conn, message) do conn |> put_status(:bad_request) |> json(%{error: message}) end end