defmodule SyntropyWeb.Api.RunController do use SyntropyWeb, :controller alias Syntropy.Persistence alias SyntropyWeb.Api.{ControllerHelpers, Listing, RunJSON, RunRequest} @memory_scan_limit 1_000 @spec index(Plug.Conn.t(), map()) :: Plug.Conn.t() def index(conn, params) do case Listing.parse_opts(params, [:status, :kind, :q]) do {:ok, opts} -> page = runs_page(opts) json(conn, %{ data: Enum.map(page.entries, &RunJSON.run/1), meta: Listing.meta(page) }) {:error, :invalid_cursor} -> ControllerHelpers.invalid_request(conn, "Invalid cursor.", []) end end @spec show(Plug.Conn.t(), map()) :: Plug.Conn.t() def show(conn, %{"id" => run_id}) do case Syntropy.run(run_id) || Persistence.get_run_envelope(run_id) do nil -> ControllerHelpers.not_found(conn, "Run", run_id) run -> json(conn, %{data: RunJSON.run(run)}) end end @spec create(Plug.Conn.t(), map()) :: Plug.Conn.t() def create(conn, params) do with {:ok, %{prompt: prompt, opts: opts}} <- RunRequest.parse(params), {:ok, run} <- Syntropy.start_run(prompt, opts) do conn |> put_status(:accepted) |> json(%{data: RunJSON.run(run)}) else {:error, errors} when is_list(errors) -> ControllerHelpers.invalid_request(conn, "Invalid run request.", errors) {:error, reason} -> ControllerHelpers.task_failure(conn, reason) end end @spec cancel(Plug.Conn.t(), map()) :: Plug.Conn.t() def cancel(conn, %{"id" => run_id}) do case Syntropy.cancel_run(run_id) do {:ok, run} -> json(conn, %{data: RunJSON.run(run)}) {:error, :not_found} -> ControllerHelpers.not_found(conn, "Run", run_id) {:error, :not_cancellable} -> ControllerHelpers.conflict( conn, "not_cancellable", "Run #{run_id} already reached a terminal state." ) end end defp runs_page(opts) do if Persistence.enabled?() do Persistence.list_run_envelopes(opts) else @memory_scan_limit |> Syntropy.recent_runs() |> Listing.filter_runs(opts) |> Listing.paginate(opts, :updated_at) end end end