defmodule ChronoscopeWeb.API.V1.Gemini.ConnectionController do use ChronoscopeWeb, :controller require Logger alias Chronoscope.Gemini @default_port 1965 @default_path "/" @max_parameter_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: String.trim(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: String.trim(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: String.trim(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: ""}) do bad_request_response(conn, "empty 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 host |> String.slice(0, @max_parameter_length) |> @gemini.connect(port, String.slice(path, 0, @max_parameter_length)) end defp format_response(response) do Map.take(response, [:status_code, :meta, :body, :cert_expiration]) end defp bad_request_response(conn, message) do conn |> put_status(:bad_request) |> json(%{error: message}) end end