chronoscope/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex

73 lines
1.9 KiB
Elixir

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])
end
defp bad_request_response(conn, message) do
conn
|> put_status(:bad_request)
|> json(%{error: message})
end
end