lib/openagents_web/plugs/status_probe_compat.ex

main at 58e6347eeb72 · 1 KB

defmodule OpenAgentsWeb.Plugs.StatusProbeCompat do
  @moduledoc """
  Deprecation shim for machine pollers of `GET /status`.

  `/status` is the public network-status page, but legacy pollers hit the old
  JSON contract on a ~15s cadence. Anything that does not ask for HTML —
  probes, curl, uptime monitors (`Accept: application/json`, `*/*`, or none),
  or an explicit `?format=json` — still gets the legacy DB-checked payload,
  byte-shaped like before: `{"status":"ok","revision":...}` (503 on DB
  failure). Browsers asking for `text/html` fall through to the LiveView.
  """

  import Plug.Conn

  @behaviour Plug

  @impl true
  def init(opts), do: opts

  @impl true
  def call(conn, _opts) do
    conn = fetch_query_params(conn)

    if status_path?(conn) and not wants_html?(conn) do
      conn
      |> legacy_health_response()
      |> halt()
    else
      conn
    end
  end

  defp status_path?(conn), do: conn.method == "GET" and conn.request_path == "/status"

  defp wants_html?(conn) do
    format = conn.query_params["format"] || conn.params["format"]
    accept = conn |> get_req_header("accept") |> Enum.join(",")

    cond do
      format == "json" -> false
      String.contains?(accept, "text/html") -> true
      true -> false
    end
  end

  defp legacy_health_response(conn) do
    case OpenAgents.Repo.query("SELECT 1") do
      {:ok, _result} ->
        json_response(conn, 200, %{status: "ok", revision: OpenAgents.BuildInfo.revision()})

      {:error, _reason} ->
        json_response(conn, 503, %{status: "unavailable"})
    end
  rescue
    _error -> json_response(conn, 503, %{status: "unavailable"})
  end

  defp json_response(conn, status, payload) do
    conn
    |> put_resp_content_type("application/json")
    |> send_resp(status, Phoenix.json_library().encode!(payload))
  end
end