61 lines
1.6 KiB
Elixir
61 lines
1.6 KiB
Elixir
defmodule Forum.PublicSiteRouter do
|
|
@moduledoc """
|
|
Serves one network's public website on its own port.
|
|
"""
|
|
import Plug.Conn
|
|
|
|
def init(opts), do: opts
|
|
|
|
def call(conn, opts) do
|
|
network = Keyword.fetch!(opts, :network)
|
|
started_at = System.monotonic_time(:microsecond)
|
|
|
|
response =
|
|
with {:ok, pid} <- Forum.PublicSiteSupervisor.get_or_start(network) do
|
|
Forum.PublicSite.serve(pid, %{
|
|
method: conn.method,
|
|
path: conn.request_path,
|
|
query_string: conn.query_string,
|
|
headers: conn.req_headers
|
|
})
|
|
else
|
|
{:error, reason} ->
|
|
%{
|
|
status: 500,
|
|
content_type: "text/plain",
|
|
body: "Unable to start public site: #{inspect(reason)}"
|
|
}
|
|
end
|
|
|
|
duration_us = System.monotonic_time(:microsecond) - started_at
|
|
|
|
Forum.LogStore.add(%{
|
|
"source_ip" => remote_ip(conn),
|
|
"host" => conn.host || "",
|
|
"network" => network,
|
|
"method" => conn.method,
|
|
"path" => conn.request_path,
|
|
"query_string" => conn.query_string,
|
|
"status" => response.status,
|
|
"duration_ms" => Float.round(duration_us / 1_000, 2)
|
|
})
|
|
|
|
conn
|
|
|> put_resp_content_type(response.content_type)
|
|
|> send_resp(response.status, response.body)
|
|
end
|
|
|
|
defp remote_ip(conn) do
|
|
case Plug.Conn.get_req_header(conn, "x-real-ip") do
|
|
[ip | _] -> ip
|
|
[] -> fallback_ip(conn)
|
|
end
|
|
end
|
|
|
|
defp fallback_ip(%{remote_ip: remote_ip}) when is_tuple(remote_ip) do
|
|
remote_ip |> :inet.ntoa() |> to_string()
|
|
end
|
|
|
|
defp fallback_ip(_), do: ""
|
|
end
|